BitmapOperationsUtility.cs 6.1 KB

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