ReplaceColorOperation.cs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. using ChunkyImageLib.DataHolders;
  2. using Drawie.Backend.Core.ColorsImpl;
  3. using Drawie.Backend.Core.Numerics;
  4. using Drawie.Backend.Core.Surfaces;
  5. using Drawie.Backend.Core.Surfaces.ImageData;
  6. using Drawie.Numerics;
  7. namespace ChunkyImageLib.Operations;
  8. internal class ReplaceColorOperation : IDrawOperation
  9. {
  10. private readonly Color oldColor;
  11. private readonly Color newColor;
  12. private readonly ColorBounds oldColorBounds;
  13. private readonly ulong newColorBits;
  14. public bool IgnoreEmptyChunks => true;
  15. public ReplaceColorOperation(Color oldColor, Color newColor)
  16. {
  17. this.oldColor = oldColor;
  18. this.newColor = newColor;
  19. oldColorBounds = new ColorBounds(oldColor);
  20. newColorBits = newColor.ToULong();
  21. }
  22. public void DrawOnChunk(Chunk targetChunk, VecI chunkPos)
  23. {
  24. ulong targetColorBits = newColor.ToULong();
  25. ColorBounds colorBounds = new(oldColor);
  26. if (targetChunk.Surface.ImageInfo.ColorSpace is { IsSrgb: false })
  27. {
  28. var transform = ColorSpace.CreateSrgb().GetTransformFunction();
  29. targetColorBits = newColor.TransformColor(transform).ToULong();
  30. var transformOld = targetChunk.Surface.ImageInfo.ColorSpace.GetTransformFunction();
  31. colorBounds = new ColorBounds(oldColor.TransformColor(transform));
  32. }
  33. ReplaceColor(colorBounds, targetColorBits, targetChunk);
  34. }
  35. private static unsafe void ReplaceColor(ColorBounds oldColorBounds, ulong newColorBits, Chunk chunk)
  36. {
  37. int maxThreads = Environment.ProcessorCount;
  38. VecI imageSize = chunk.PixelSize;
  39. int rowsPerThread = imageSize.Y / maxThreads;
  40. using Pixmap pixmap = chunk.Surface.DrawingSurface.PeekPixels();
  41. IntPtr pixels = pixmap.GetPixels();
  42. Half* endOffset = (Half*)(pixels + pixmap.BytesSize);
  43. for (Half* i = (Half*)pixels; i < endOffset; i += 4)
  44. {
  45. if (oldColorBounds.IsWithinBounds(i))
  46. {
  47. *(ulong*)i = newColorBits;
  48. }
  49. }
  50. }
  51. public AffectedArea FindAffectedArea(VecI imageSize)
  52. {
  53. RectI rect = new(VecI.Zero, imageSize);
  54. return new AffectedArea(OperationHelper.FindChunksTouchingRectangle(rect, ChunkyImage.FullChunkSize), rect);
  55. }
  56. public void Dispose()
  57. {
  58. }
  59. }