Sign in to follow this  

Saving graphics with C#

This topic is 3416 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm creating a tileset maker and it works by selecting the tile and placing it into a picture box, the problem im having though is when i save that picturebox's image its just empty. Is there a specific way I should eb doing this? At the moment the paint event draws how you want your tileset to look but as I mentioned it doesnt keep that look when the image saves

Share this post


Link to post
Share on other sites
Hey im pretty much new to C# but maybe try this

//Load the Image Object into a BitMap
Bitmap bm = new Bitmap(Image);
Graphics g = Graphics.FromImage(bm);

//Keeps the quality of the image
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;

g.Dispose();
Image.Dispose();

//Save the image
bm.Save(c:\Temp\ImageName, System.Drawing.Imaging.ImageFormat.Jpeg);

Hope that helps :P

Share this post


Link to post
Share on other sites
Also, I'm not expert on graphics, but it sounds to me like rendering a tilemap with a picturebox isn't the best way to display said tilemap.

Here's some Microsoft code for rendering XNA within a form:

GraphicsDeviceService.cs
#region File Description
//-----------------------------------------------------------------------------
// GraphicsDeviceService.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Threading;
using Microsoft.Xna.Framework.Graphics;
#endregion

// The IGraphicsDeviceService interface requires a DeviceCreated event, but we
// always just create the device inside our constructor, so we have no place to
// raise that event. The C# compiler warns us that the event is never used, but
// we don't care so we just disable this warning.
#pragma warning disable 67

namespace MapEditor
{
/// <summary>
/// Helper class responsible for creating and managing the GraphicsDevice.
/// All GraphicsDeviceControl instances share the same GraphicsDeviceService,
/// so even though there can be many controls, there will only ever be a single
/// underlying GraphicsDevice. This implements the standard IGraphicsDeviceService
/// interface, which provides notification events for when the device is reset
/// or disposed.
/// </summary>
class GraphicsDeviceService : IGraphicsDeviceService
{
#region Fields


// Singleton device service instance.
static GraphicsDeviceService singletonInstance;


// Keep track of how many controls are sharing the singletonInstance.
static int referenceCount;


#endregion


/// <summary>
/// Constructor is private, because this is a singleton class:
/// client controls should use the public AddRef method instead.
/// </summary>
GraphicsDeviceService(IntPtr windowHandle, int width, int height)
{
parameters = new PresentationParameters();

parameters.BackBufferWidth = Math.Max(width, 1);
parameters.BackBufferHeight = Math.Max(height, 1);
parameters.BackBufferFormat = SurfaceFormat.Color;

parameters.EnableAutoDepthStencil = true;
parameters.AutoDepthStencilFormat = DepthFormat.Depth24;

graphicsDevice = new GraphicsDevice(GraphicsAdapter.DefaultAdapter,
DeviceType.Hardware,
windowHandle,
parameters);
}


/// <summary>
/// Gets a reference to the singleton instance.
/// </summary>
public static GraphicsDeviceService AddRef(IntPtr windowHandle,
int width, int height)
{
// Increment the "how many controls sharing the device" reference count.
if (Interlocked.Increment(ref referenceCount) == 1)
{
// If this is the first control to start using the
// device, we must create the singleton instance.
singletonInstance = new GraphicsDeviceService(windowHandle,
width, height);
}

return singletonInstance;
}


/// <summary>
/// Releases a reference to the singleton instance.
/// </summary>
public void Release(bool disposing)
{
// Decrement the "how many controls sharing the device" reference count.
if (Interlocked.Decrement(ref referenceCount) == 0)
{
// If this is the last control to finish using the
// device, we should dispose the singleton instance.
if (disposing)
{
if (DeviceDisposing != null)
DeviceDisposing(this, EventArgs.Empty);

graphicsDevice.Dispose();
}

graphicsDevice = null;
}
}


/// <summary>
/// Resets the graphics device to whichever is bigger out of the specified
/// resolution or its current size. This behavior means the device will
/// demand-grow to the largest of all its GraphicsDeviceControl clients.
/// </summary>
public void ResetDevice(int width, int height)
{
if (DeviceResetting != null)
DeviceResetting(this, EventArgs.Empty);

parameters.BackBufferWidth = Math.Max(parameters.BackBufferWidth, width);
parameters.BackBufferHeight = Math.Max(parameters.BackBufferHeight, height);

graphicsDevice.Reset(parameters);

if (DeviceReset != null)
DeviceReset(this, EventArgs.Empty);
}


/// <summary>
/// Gets the current graphics device.
/// </summary>
public GraphicsDevice GraphicsDevice
{
get { return graphicsDevice; }
}

GraphicsDevice graphicsDevice;


// Store the current device settings.
PresentationParameters parameters;


// IGraphicsDeviceService events.
public event EventHandler DeviceCreated;
public event EventHandler DeviceDisposing;
public event EventHandler DeviceReset;
public event EventHandler DeviceResetting;
}
}



GraphicsDeviceControl.cs
#region File Description
//-----------------------------------------------------------------------------
// GraphicsDeviceControl.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.Xna.Framework.Graphics;
#endregion

namespace MapEditor
{
// System.Drawing and the XNA Framework both define Color and Rectangle
// types. To avoid conflicts, we specify exactly which ones to use.
using Color = System.Drawing.Color;
using Rectangle = Microsoft.Xna.Framework.Rectangle;


/// <summary>
/// Custom control uses the XNA Framework GraphicsDevice to render onto
/// a Windows Form. Derived classes can override the Initialize and Draw
/// methods to add their own drawing code.
/// </summary>
abstract public class GraphicsDeviceControl : Control
{
#region Fields


// However many GraphicsDeviceControl instances you have, they all share
// the same underlying GraphicsDevice, managed by this helper service.
GraphicsDeviceService graphicsDeviceService;


#endregion

#region Properties


/// <summary>
/// Gets a GraphicsDevice that can be used to draw onto this control.
/// </summary>
public GraphicsDevice GraphicsDevice
{
get { return graphicsDeviceService.GraphicsDevice; }
}


/// <summary>
/// Gets an IServiceProvider containing our IGraphicsDeviceService.
/// This can be used with components such as the ContentManager,
/// which use this service to look up the GraphicsDevice.
/// </summary>
public ServiceContainer Services
{
get { return services; }
}

ServiceContainer services = new ServiceContainer();


#endregion

#region Initialization


/// <summary>
/// Initializes the control.
/// </summary>
protected override void OnCreateControl()
{
// Don't initialize the graphics device if we are running in the designer.
if (!DesignMode)
{
graphicsDeviceService = GraphicsDeviceService.AddRef(Handle,
ClientSize.Width,
ClientSize.Height);

// Register the service, so components like ContentManager can find it.
services.AddService<IGraphicsDeviceService>(graphicsDeviceService);

// Give derived classes a chance to initialize themselves.
Initialize();
}

base.OnCreateControl();
}


/// <summary>
/// Disposes the control.
/// </summary>
protected override void Dispose(bool disposing)
{
if (graphicsDeviceService != null)
{
graphicsDeviceService.Release(disposing);
graphicsDeviceService = null;
}

base.Dispose(disposing);
}


#endregion

#region Paint


/// <summary>
/// Redraws the control in response to a WinForms paint message.
/// </summary>
protected override void OnPaint(PaintEventArgs e)
{
string beginDrawError = BeginDraw();

if (string.IsNullOrEmpty(beginDrawError))
{
// Draw the control using the GraphicsDevice.
Draw();
EndDraw();
}
else
{
// If BeginDraw failed, show an error message using System.Drawing.
PaintUsingSystemDrawing(e.Graphics, beginDrawError);
}
}


/// <summary>
/// Attempts to begin drawing the control. Returns an error message string
/// if this was not possible, which can happen if the graphics device is
/// lost, or if we are running inside the Form designer.
/// </summary>
string BeginDraw()
{
// If we have no graphics device, we must be running in the designer.
if (graphicsDeviceService == null)
{
return Text + "\n\n" + GetType();
}

// Make sure the graphics device is big enough, and is not lost.
string deviceResetError = HandleDeviceReset();

if (!string.IsNullOrEmpty(deviceResetError))
{
return deviceResetError;
}

// Many GraphicsDeviceControl instances can be sharing the same
// GraphicsDevice. The device backbuffer will be resized to fit the
// largest of these controls. But what if we are currently drawing
// a smaller control? To avoid unwanted stretching, we set the
// viewport to only use the top left portion of the full backbuffer.
Viewport viewport = new Viewport();

viewport.X = 0;
viewport.Y = 0;

viewport.Width = ClientSize.Width;
viewport.Height = ClientSize.Height;

viewport.MinDepth = 0;
viewport.MaxDepth = 1;

GraphicsDevice.Viewport = viewport;

return null;
}


/// <summary>
/// Ends drawing the control. This is called after derived classes
/// have finished their Draw method, and is responsible for presenting
/// the finished image onto the screen, using the appropriate WinForms
/// control handle to make sure it shows up in the right place.
/// </summary>
void EndDraw()
{
try
{
Rectangle sourceRectangle = new Rectangle(0, 0, ClientSize.Width,
ClientSize.Height);

GraphicsDevice.Present(sourceRectangle, null, this.Handle);
}
catch
{
// Present might throw if the device became lost while we were
// drawing. The lost device will be handled by the next BeginDraw,
// so we just swallow the exception.
}
}


/// <summary>
/// Helper used by BeginDraw. This checks the graphics device status,
/// making sure it is big enough for drawing the current control, and
/// that the device is not lost. Returns an error string if the device
/// could not be reset.
/// </summary>
string HandleDeviceReset()
{
bool deviceNeedsReset = false;

switch (GraphicsDevice.GraphicsDeviceStatus)
{
case GraphicsDeviceStatus.Lost:
// If the graphics device is lost, we cannot use it at all.
return "Graphics device lost";

case GraphicsDeviceStatus.NotReset:
// If device is in the not-reset state, we should try to reset it.
deviceNeedsReset = true;
break;

default:
// If the device state is ok, check whether it is big enough.
PresentationParameters pp = GraphicsDevice.PresentationParameters;

deviceNeedsReset = (ClientSize.Width > pp.BackBufferWidth) ||
(ClientSize.Height > pp.BackBufferHeight);
break;
}

// Do we need to reset the device?
if (deviceNeedsReset)
{
try
{
graphicsDeviceService.ResetDevice(ClientSize.Width,
ClientSize.Height);
}
catch (Exception e)
{
return "Graphics device reset failed\n\n" + e;
}
}

return null;
}


/// <summary>
/// If we do not have a valid graphics device (for instance if the device
/// is lost, or if we are running inside the Form designer), we must use
/// regular System.Drawing method to display a status message.
/// </summary>
protected virtual void PaintUsingSystemDrawing(Graphics graphics, string text)
{
graphics.Clear(Color.CornflowerBlue);

using (Brush brush = new SolidBrush(Color.Black))
{
using (StringFormat format = new StringFormat())
{
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;

graphics.DrawString(text, Font, brush, ClientRectangle, format);
}
}
}


/// <summary>
/// Ignores WinForms paint-background messages. The default implementation
/// would clear the control to the current background color, causing
/// flickering when our OnPaint implementation then immediately draws some
/// other color over the top using the XNA Framework GraphicsDevice.
/// </summary>
protected override void OnPaintBackground(PaintEventArgs pevent)
{
}


#endregion

#region Abstract Methods


/// <summary>
/// Derived classes override this to initialize their drawing code.
/// </summary>
protected abstract void Initialize();


/// <summary>
/// Derived classes override this to draw themselves using the GraphicsDevice.
/// </summary>
protected abstract void Draw();


#endregion
}
}



TileDisplay.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace MapEditor
{
public class TileDisplay : GraphicsDeviceControl
{
public event EventHandler OnInitialize;
public event EventHandler OnDraw;

protected override void Initialize()
{
if (OnInitialize != null)
OnInitialize(this, null);
}

protected override void Draw()
{
if (OnDraw != null)
OnDraw(this, null);
}
}
}



Just drop TileDisplay onto yur form, and you're good to go!

Share this post


Link to post
Share on other sites
Im not trying to make a map editor but a tileset editor, its similiar in that you add tiles from a pallete to create your own tileset and I need that to save as a png file, its probably not saving anything because the data is just painted on with the paint event, ill post some code when i get a chance.

Share this post


Link to post
Share on other sites

This topic is 3416 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this