BitmapOperationsUtility.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. using PixiEditor.Models.DataHolders;
  2. using PixiEditor.Models.Images;
  3. using PixiEditor.Models.Layers;
  4. using PixiEditor.Models.Position;
  5. using PixiEditor.Models.Tools;
  6. using PixiEditor.Models.Tools.Tools;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using System.Windows.Input;
  11. using System.Windows.Media;
  12. using System.Windows.Media.Imaging;
  13. namespace PixiEditor.Models.Controllers
  14. {
  15. public class BitmapOperationsUtility
  16. {
  17. private Coordinates _lastMousePos;
  18. private LayerChange[] _lastModifiedLayers;
  19. public event EventHandler<BitmapChangedEventArgs> BitmapChanged;
  20. public BitmapManager Manager { get; set; }
  21. public BitmapOperationsUtility(BitmapManager manager)
  22. {
  23. Manager = manager;
  24. }
  25. public void DeletePixels(Layer[] layers, Coordinates[] pixels)
  26. {
  27. var changes = BitmapPixelChanges.FromSingleColoredArray(pixels, Color.FromArgb(0,0,0,0));
  28. var oldValues = BitmapUtils.GetPixelsForSelection(layers, pixels);
  29. LayerChange[] old = new LayerChange[layers.Length];
  30. LayerChange[] newChange = new LayerChange[layers.Length];
  31. for (int i = 0; i < layers.Length; i++)
  32. {
  33. old[i] = new LayerChange(
  34. BitmapPixelChanges.FromArrays(pixels, oldValues[layers[i]]), i);
  35. newChange[i] = new LayerChange(changes, i);
  36. layers[i].ApplyPixels(changes);
  37. }
  38. UndoManager.AddUndoChange(new Change("UndoChanges", old, newChange, "Deleted pixels"));
  39. }
  40. public void ExecuteTool(Coordinates newPos, List<Coordinates> mouseMove, BitmapOperationTool tool)
  41. {
  42. if (Manager.ActiveDocument != null && tool != null && tool.ToolType != ToolType.None)
  43. {
  44. if (Manager.ActiveDocument.Layers.Count == 0 || mouseMove.Count == 0) return;
  45. mouseMove.Reverse();
  46. UseTool(mouseMove, tool, Manager.PrimaryColor);
  47. _lastMousePos = newPos;
  48. }
  49. }
  50. public void StopAction()
  51. {
  52. for (int i = 0; i < _lastModifiedLayers.Length; i++)
  53. {
  54. BitmapPixelChanges oldValues = GetOldPixelsValues(_lastModifiedLayers[i].PixelChanges.ChangedPixels.Keys.ToArray());
  55. Manager.ActiveDocument.Layers[_lastModifiedLayers[i].LayerIndex].ApplyPixels(_lastModifiedLayers[i].PixelChanges);
  56. BitmapChanged?.Invoke(this, new BitmapChangedEventArgs(_lastModifiedLayers[i].PixelChanges,
  57. oldValues, _lastModifiedLayers[i].LayerIndex));
  58. Manager.PreviewLayer.Clear();
  59. }
  60. }
  61. private void UseTool(List<Coordinates> mouseMoveCords, BitmapOperationTool tool, Color color)
  62. {
  63. if (Keyboard.IsKeyDown(Key.LeftShift) && !MouseCordsNotInLine(mouseMoveCords))
  64. {
  65. mouseMoveCords = GetSquareCoordiantes(mouseMoveCords);
  66. };
  67. if (!tool.RequiresPreviewLayer)
  68. {
  69. LayerChange[] modifiedLayers = tool.Use(Manager.ActiveLayer, mouseMoveCords.ToArray(), color);
  70. LayerChange[] oldPixelsValues = new LayerChange[modifiedLayers.Length];
  71. for (int i = 0; i < modifiedLayers.Length; i++)
  72. {
  73. oldPixelsValues[i] = new LayerChange(GetOldPixelsValues(modifiedLayers[i].PixelChanges.ChangedPixels.Keys.ToArray()),
  74. modifiedLayers[i].LayerIndex);
  75. Manager.ActiveDocument.Layers[modifiedLayers[i].LayerIndex].ApplyPixels(modifiedLayers[i].PixelChanges);
  76. BitmapChanged?.Invoke(this, new BitmapChangedEventArgs(modifiedLayers[i].PixelChanges,
  77. oldPixelsValues[i].PixelChanges, modifiedLayers[i].LayerIndex));
  78. }
  79. }
  80. else
  81. {
  82. UseToolOnPreviewLayer(mouseMoveCords);
  83. }
  84. }
  85. private bool MouseCordsNotInLine(List<Coordinates> cords)
  86. {
  87. return cords[0].X == cords[^1].X || cords[0].Y == cords[^1].Y;
  88. }
  89. /// <summary>
  90. /// Extracts square from rectangle mouse drag, used to draw symmetric shapes.
  91. /// </summary>
  92. /// <param name="mouseMoveCords"></param>
  93. /// <returns></returns>
  94. private List<Coordinates> GetSquareCoordiantes(List<Coordinates> mouseMoveCords)
  95. {
  96. int xLength = mouseMoveCords[0].Y - mouseMoveCords[^1].Y;
  97. int yLength = mouseMoveCords[0].Y - mouseMoveCords[^1].Y;
  98. if (mouseMoveCords[^1].Y > mouseMoveCords[0].Y)
  99. {
  100. xLength *= -1;
  101. }
  102. if (mouseMoveCords[^1].X > mouseMoveCords[0].X)
  103. {
  104. xLength *= -1;
  105. }
  106. mouseMoveCords[0] = new Coordinates(mouseMoveCords[^1].X + xLength, mouseMoveCords[^1].Y + yLength);
  107. return mouseMoveCords;
  108. }
  109. private BitmapPixelChanges GetOldPixelsValues(Coordinates[] coordinates)
  110. {
  111. Dictionary<Coordinates, Color> values = new Dictionary<Coordinates, Color>();
  112. Manager.ActiveLayer.LayerBitmap.Lock();
  113. for (int i = 0; i < coordinates.Length; i++)
  114. {
  115. if (coordinates[i].X < 0 || coordinates[i].X > Manager.ActiveDocument.Width - 1 || coordinates[i].Y < 0 || coordinates[i].Y > Manager.ActiveDocument.Height - 1)
  116. continue;
  117. values.Add(coordinates[i], Manager.ActiveLayer.LayerBitmap.GetPixel(coordinates[i].X, coordinates[i].Y));
  118. }
  119. Manager.ActiveLayer.LayerBitmap.Unlock();
  120. return new BitmapPixelChanges(values);
  121. }
  122. private void UseToolOnPreviewLayer(List<Coordinates> mouseMove)
  123. {
  124. LayerChange[] modifiedLayers = null;
  125. if (mouseMove.Count > 0 && mouseMove[0] != _lastMousePos)
  126. {
  127. Manager.GeneratePreviewLayer();
  128. Manager.PreviewLayer.Clear();
  129. modifiedLayers = ((BitmapOperationTool)Manager.SelectedTool).Use(Manager.ActiveDocument.ActiveLayer, mouseMove.ToArray(), Manager.PrimaryColor);
  130. BitmapPixelChanges[] changes = modifiedLayers.Select(x => x.PixelChanges).ToArray();
  131. Manager.PreviewLayer.ApplyPixels(BitmapPixelChanges.CombineOverride(changes));
  132. _lastModifiedLayers = modifiedLayers;
  133. }
  134. }
  135. }
  136. }
  137. public class BitmapChangedEventArgs : EventArgs
  138. {
  139. public BitmapPixelChanges PixelsChanged { get; set; }
  140. public BitmapPixelChanges OldPixelsValues { get; set; }
  141. public int ChangedLayerIndex { get; set; }
  142. public BitmapChangedEventArgs(BitmapPixelChanges pixelsChanged, BitmapPixelChanges oldPixelsValues, int changedLayerIndex)
  143. {
  144. PixelsChanged = pixelsChanged;
  145. OldPixelsValues = oldPixelsValues;
  146. ChangedLayerIndex = changedLayerIndex;
  147. }
  148. }