PixelOp.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. using System;
  2. using System.Drawing;
  3. namespace PaintDotNet
  4. {
  5. [Serializable]
  6. public unsafe abstract class PixelOp
  7. : IPixelOp
  8. {
  9. public void Apply(Surface dst, Point dstOffset, Surface src, Point srcOffset, Size roiSize)
  10. {
  11. ApplyBase(dst, dstOffset, src, srcOffset, roiSize);
  12. }
  13. /// <summary>
  14. /// Provides a default implementation for performing dst = F(dst, src) or F(src) over some rectangle
  15. /// of interest. May be slightly faster than calling the other multi-parameter Apply method, as less
  16. /// variables are used in the implementation, thus inducing less register pressure.
  17. /// </summary>
  18. /// <param name="dst">The Surface to write pixels to, and from which pixels are read and used as the lhs parameter for calling the method <b>ColorBgra Apply(ColorBgra, ColorBgra)</b>.</param>
  19. /// <param name="dstOffset">The pixel offset that defines the upper-left of the rectangle-of-interest for the dst Surface.</param>
  20. /// <param name="src">The Surface to read pixels from for the rhs parameter given to the method <b>ColorBgra Apply(ColorBgra, ColorBgra)</b>b>.</param></param>
  21. /// <param name="srcOffset">The pixel offset that defines the upper-left of the rectangle-of-interest for the src Surface.</param>
  22. /// <param name="roiSize">The size of the rectangles-of-interest for all Surfaces.</param>
  23. public void ApplyBase(Surface dst, Point dstOffset, Surface src, Point srcOffset, Size roiSize)
  24. {
  25. // Create bounding rectangles for each Surface
  26. Rectangle dstRect = new Rectangle(dstOffset, roiSize);
  27. if (dstRect.Width == 0 || dstRect.Height == 0)
  28. {
  29. return;
  30. }
  31. Rectangle srcRect = new Rectangle(srcOffset, roiSize);
  32. if (srcRect.Width == 0 || srcRect.Height == 0)
  33. {
  34. return;
  35. }
  36. // Clip those rectangles to those Surface's bounding rectangles
  37. Rectangle dstClip = Rectangle.Intersect(dstRect, dst.Bounds);
  38. Rectangle srcClip = Rectangle.Intersect(srcRect, src.Bounds);
  39. // If any of those Rectangles actually got clipped, then throw an exception
  40. if (dstRect != dstClip)
  41. {
  42. throw new ArgumentOutOfRangeException
  43. (
  44. "roiSize",
  45. "Destination roi out of bounds" +
  46. ", dst.Size=" + dst.Size.ToString() +
  47. ", dst.Bounds=" + dst.Bounds.ToString() +
  48. ", dstOffset=" + dstOffset.ToString() +
  49. ", src.Size=" + src.Size.ToString() +
  50. ", srcOffset=" + srcOffset.ToString() +
  51. ", roiSize=" + roiSize.ToString() +
  52. ", dstRect=" + dstRect.ToString() +
  53. ", dstClip=" + dstClip.ToString() +
  54. ", srcRect=" + srcRect.ToString() +
  55. ", srcClip=" + srcClip.ToString()
  56. );
  57. }
  58. if (srcRect != srcClip)
  59. {
  60. throw new ArgumentOutOfRangeException("roiSize", "Source roi out of bounds");
  61. }
  62. // Cache the width and height properties
  63. int width = roiSize.Width;
  64. int height = roiSize.Height;
  65. // Do the work.
  66. unsafe
  67. {
  68. for (int row = 0; row < roiSize.Height; ++row)
  69. {
  70. ColorBgra* dstPtr = dst.GetPointAddress(dstOffset.X, dstOffset.Y + row);
  71. ColorBgra* srcPtr = src.GetPointAddress(srcOffset.X, srcOffset.Y + row);
  72. Apply(dstPtr, srcPtr, width);
  73. }
  74. }
  75. }
  76. public virtual void Apply(Surface dst, Point dstOffset, Surface src, Point srcOffset, int scanLength)
  77. {
  78. Apply(dst.GetPointAddress(dstOffset), src.GetPointAddress(srcOffset), scanLength);
  79. }
  80. public virtual void Apply(ColorBgra* dst, ColorBgra* src, int length)
  81. {
  82. throw new System.NotImplementedException("Derived class must implement Apply(ColorBgra*,ColorBgra*,int)");
  83. }
  84. public PixelOp()
  85. {
  86. }
  87. }
  88. }