RenderArgs.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. using System;
  2. using System.Drawing;
  3. namespace PaintDotNet
  4. {
  5. /// <summary>
  6. /// Encapsulates the arguments passed to a Render function.
  7. /// This way we can do on-demand and once-only creation of Bitmap and Graphics
  8. /// objects from a given Surface object.
  9. /// </summary>
  10. /// <remarks>
  11. /// Use of the Bitmap and Graphics objects is not thread safe because of how GDI+ works.
  12. /// You must wrap use of these objects with a critical section, like so:
  13. /// object lockObject = new object();
  14. /// lock (lockObject)
  15. /// {
  16. /// Graphics g = ra.Graphics;
  17. /// g.DrawRectangle(...);
  18. /// // etc.
  19. /// }
  20. /// </remarks>
  21. public sealed class RenderArgs
  22. : IDisposable
  23. {
  24. private Surface surface;
  25. private Bitmap bitmap;
  26. private Graphics graphics;
  27. private bool disposed = false;
  28. /// <summary>
  29. /// Gets the Surface that has been associated with this instance of RenderArgs.
  30. /// </summary>
  31. public Surface Surface
  32. {
  33. get
  34. {
  35. if (this.disposed)
  36. {
  37. throw new ObjectDisposedException("RenderArgs");
  38. }
  39. return this.surface;
  40. }
  41. }
  42. /// <summary>
  43. /// Gets a Bitmap reference that aliases the Surface.
  44. /// </summary>
  45. public Bitmap Bitmap
  46. {
  47. get
  48. {
  49. if (this.disposed)
  50. {
  51. throw new ObjectDisposedException("RenderArgs");
  52. }
  53. if (this.bitmap == null)
  54. {
  55. this.bitmap = surface.CreateAliasedBitmap();
  56. }
  57. return this.bitmap;
  58. }
  59. }
  60. /// <summary>
  61. /// Retrieves a Graphics instance that can be used to draw on to the Surface.
  62. /// </summary>
  63. /// <remarks>
  64. /// Use of this object is not thread-safe. You must wrap retrieval and consumption of this
  65. /// property with a critical section.
  66. /// </remarks>
  67. public Graphics Graphics
  68. {
  69. get
  70. {
  71. if (this.disposed)
  72. {
  73. throw new ObjectDisposedException("RenderArgs");
  74. }
  75. if (this.graphics == null)
  76. {
  77. this.graphics = Graphics.FromImage(Bitmap);
  78. }
  79. return this.graphics;
  80. }
  81. }
  82. /// <summary>
  83. /// Gets the size of the associated Surface object.
  84. /// </summary>
  85. /// <remarks>
  86. /// This is a convenience method equivalent to using RenderArgs.Surface.Bounds.
  87. /// </remarks>
  88. public Rectangle Bounds
  89. {
  90. get
  91. {
  92. if (this.disposed)
  93. {
  94. throw new ObjectDisposedException("RenderArgs");
  95. }
  96. return this.Surface.Bounds;
  97. }
  98. }
  99. /// <summary>
  100. /// Gets the size of the associated Surface object.
  101. /// </summary>
  102. /// <remarks>
  103. /// This is a convenient method equivalent to using RenderArgs.Surface.Size.
  104. /// </remarks>
  105. public Size Size
  106. {
  107. get
  108. {
  109. if (this.disposed)
  110. {
  111. throw new ObjectDisposedException("RenderArgs");
  112. }
  113. return this.Surface.Size;
  114. }
  115. }
  116. /// <summary>
  117. /// Gets the width of the associated Surface object.
  118. /// </summary>
  119. /// <remarks>
  120. /// This is a convenience method equivalent to using RenderArgs.Surface.Width.
  121. /// </remarks>
  122. public int Width
  123. {
  124. get
  125. {
  126. if (this.disposed)
  127. {
  128. throw new ObjectDisposedException("RenderArgs");
  129. }
  130. return this.surface.Width;
  131. }
  132. }
  133. /// <summary>
  134. /// Gets the height of the associated Surface object.
  135. /// </summary>
  136. /// <remarks>
  137. /// This is a convenience method equivalent to using RenderArgs.Surface.Height.
  138. /// </remarks>
  139. public int Height
  140. {
  141. get
  142. {
  143. if (this.disposed)
  144. {
  145. throw new ObjectDisposedException("RenderArgs");
  146. }
  147. return this.surface.Height;
  148. }
  149. }
  150. /// <summary>
  151. /// Creates an instance of the RenderArgs class.
  152. /// </summary>
  153. /// <param name="surface">
  154. /// The Surface to associate with this instance. This instance of RenderArgs does not
  155. /// take ownership of this Surface.
  156. /// </param>
  157. public RenderArgs(Surface surface)
  158. {
  159. this.surface = surface;
  160. this.bitmap = null;
  161. this.graphics = null;
  162. }
  163. ~RenderArgs()
  164. {
  165. Dispose(false);
  166. }
  167. /// <summary>
  168. /// Disposes of the contained Bitmap and Graphics instances, if necessary.
  169. /// </summary>
  170. /// <remarks>
  171. /// Note that since this class does not take ownership of the Surface, it
  172. /// is not disposed.
  173. /// </remarks>
  174. public void Dispose()
  175. {
  176. Dispose(true);
  177. GC.SuppressFinalize(this);
  178. }
  179. private void Dispose(bool disposing)
  180. {
  181. if (!this.disposed)
  182. {
  183. this.disposed = true;
  184. if (disposing)
  185. {
  186. if (this.graphics != null)
  187. {
  188. this.graphics.Dispose();
  189. this.graphics = null;
  190. }
  191. if (this.bitmap != null)
  192. {
  193. this.bitmap.Dispose();
  194. this.bitmap = null;
  195. }
  196. }
  197. }
  198. }
  199. }
  200. }