using System; using System.Drawing; namespace PaintDotNet { /// /// Encapsulates the arguments passed to a Render function. /// This way we can do on-demand and once-only creation of Bitmap and Graphics /// objects from a given Surface object. /// /// /// Use of the Bitmap and Graphics objects is not thread safe because of how GDI+ works. /// You must wrap use of these objects with a critical section, like so: /// object lockObject = new object(); /// lock (lockObject) /// { /// Graphics g = ra.Graphics; /// g.DrawRectangle(...); /// // etc. /// } /// public sealed class RenderArgs : IDisposable { private Surface surface; private Bitmap bitmap; private Graphics graphics; private bool disposed = false; /// /// Gets the Surface that has been associated with this instance of RenderArgs. /// public Surface Surface { get { if (this.disposed) { throw new ObjectDisposedException("RenderArgs"); } return this.surface; } } /// /// Gets a Bitmap reference that aliases the Surface. /// public Bitmap Bitmap { get { if (this.disposed) { throw new ObjectDisposedException("RenderArgs"); } if (this.bitmap == null) { this.bitmap = surface.CreateAliasedBitmap(); } return this.bitmap; } } /// /// Retrieves a Graphics instance that can be used to draw on to the Surface. /// /// /// Use of this object is not thread-safe. You must wrap retrieval and consumption of this /// property with a critical section. /// public Graphics Graphics { get { if (this.disposed) { throw new ObjectDisposedException("RenderArgs"); } if (this.graphics == null) { this.graphics = Graphics.FromImage(Bitmap); } return this.graphics; } } /// /// Gets the size of the associated Surface object. /// /// /// This is a convenience method equivalent to using RenderArgs.Surface.Bounds. /// public Rectangle Bounds { get { if (this.disposed) { throw new ObjectDisposedException("RenderArgs"); } return this.Surface.Bounds; } } /// /// Gets the size of the associated Surface object. /// /// /// This is a convenient method equivalent to using RenderArgs.Surface.Size. /// public Size Size { get { if (this.disposed) { throw new ObjectDisposedException("RenderArgs"); } return this.Surface.Size; } } /// /// Gets the width of the associated Surface object. /// /// /// This is a convenience method equivalent to using RenderArgs.Surface.Width. /// public int Width { get { if (this.disposed) { throw new ObjectDisposedException("RenderArgs"); } return this.surface.Width; } } /// /// Gets the height of the associated Surface object. /// /// /// This is a convenience method equivalent to using RenderArgs.Surface.Height. /// public int Height { get { if (this.disposed) { throw new ObjectDisposedException("RenderArgs"); } return this.surface.Height; } } /// /// Creates an instance of the RenderArgs class. /// /// /// The Surface to associate with this instance. This instance of RenderArgs does not /// take ownership of this Surface. /// public RenderArgs(Surface surface) { this.surface = surface; this.bitmap = null; this.graphics = null; } ~RenderArgs() { //Dispose(false); } /// /// Disposes of the contained Bitmap and Graphics instances, if necessary. /// /// /// Note that since this class does not take ownership of the Surface, it /// is not disposed. /// public void Dispose() { //Dispose(true); //GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (!this.disposed) { this.disposed = true; if (disposing) { if (this.graphics != null) { this.graphics.Dispose(); this.graphics = null; } if (this.bitmap != null) { this.bitmap.Dispose(); this.bitmap = null; } } } } } }