BitmapUtils.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. using PixiEditor.Models.DataHolders;
  2. using PixiEditor.Models.Layers;
  3. using PixiEditor.Models.Layers.Utils;
  4. using PixiEditor.Models.Position;
  5. using PixiEditor.Parser;
  6. using PixiEditor.Parser.Skia;
  7. using SkiaSharp;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Linq;
  11. using System.Windows;
  12. using System.Windows.Media.Imaging;
  13. namespace PixiEditor.Models.ImageManipulation
  14. {
  15. public static class BitmapUtils
  16. {
  17. public static Surface CombineLayers(Int32Rect portion, IEnumerable<Layer> layers, LayerStructure structure = null)
  18. {
  19. Surface finalSurface = new(portion.Width, portion.Height);
  20. using SKPaint paint = new();
  21. for (int i = 0; i < layers.Count(); i++)
  22. {
  23. Layer layer = layers.ElementAt(i);
  24. if (structure != null && !LayerStructureUtils.GetFinalLayerIsVisible(layer, structure))
  25. continue;
  26. float layerOpacity = structure == null ? layer.Opacity : LayerStructureUtils.GetFinalLayerOpacity(layer, structure);
  27. paint.Color = new(255, 255, 255, (byte)(layerOpacity * 255));
  28. if (layer.OffsetX < 0 || layer.OffsetY < 0 ||
  29. layer.Width + layer.OffsetX > layer.MaxWidth ||
  30. layer.Height + layer.OffsetY > layer.MaxHeight)
  31. {
  32. throw new InvalidOperationException("Layers must not extend beyond canvas borders");
  33. }
  34. using SKImage snapshot = layer.LayerBitmap.SkiaSurface.Snapshot();
  35. int x = portion.X - layer.OffsetX;
  36. int y = portion.Y - layer.OffsetY;
  37. finalSurface.SkiaSurface.Canvas.DrawImage(
  38. snapshot,
  39. new SKRect(x, y, portion.Width + x, portion.Height + y),
  40. new SKRect(0, 0, portion.Width, portion.Height),
  41. paint);
  42. }
  43. return finalSurface;
  44. }
  45. public static Surface[] ExtractSelectedPortions(Layer selLayer, Layer[] extractFrom, bool eraceFromLayers)
  46. {
  47. using var selSnap = selLayer.LayerBitmap.SkiaSurface.Snapshot();
  48. Surface[] output = new Surface[extractFrom.Length];
  49. int count = 0;
  50. foreach (Layer layer in extractFrom)
  51. {
  52. Surface portion = new Surface(selLayer.Width, selLayer.Height);
  53. SKRect selLayerRect = new SKRect(0, 0, selLayer.Width, selLayer.Height);
  54. int x = selLayer.OffsetX - layer.OffsetX;
  55. int y = selLayer.OffsetY - layer.OffsetY;
  56. using (var layerSnap = layer.LayerBitmap.SkiaSurface.Snapshot())
  57. portion.SkiaSurface.Canvas.DrawImage(layerSnap, new SKRect(x, y, x + selLayer.Width, y + selLayer.Height), selLayerRect, Surface.ReplacingPaint);
  58. portion.SkiaSurface.Canvas.DrawImage(selSnap, 0, 0, Surface.MaskingPaint);
  59. output[count] = portion;
  60. count++;
  61. if (eraceFromLayers)
  62. {
  63. layer.LayerBitmap.SkiaSurface.Canvas.DrawImage(selSnap, new SKRect(0, 0, selLayer.Width, selLayer.Height),
  64. new SKRect(selLayer.OffsetX - layer.OffsetX, selLayer.OffsetY - layer.OffsetY, selLayer.OffsetX - layer.OffsetX + selLayer.Width, selLayer.OffsetY - layer.OffsetY + selLayer.Height),
  65. Surface.InverseMaskingPaint);
  66. layer.InvokeLayerBitmapChange(new Int32Rect(selLayer.OffsetX, selLayer.OffsetY, selLayer.Width, selLayer.Height));
  67. }
  68. }
  69. return output;
  70. }
  71. /// <summary>
  72. /// Generates simplified preview from Document, very fast, great for creating small previews. Creates uniform streched image.
  73. /// </summary>
  74. /// <param name="document">Document which be used to generate preview.</param>
  75. /// <param name="maxPreviewWidth">Max width of preview.</param>
  76. /// <param name="maxPreviewHeight">Max height of preview.</param>
  77. /// <returns>WriteableBitmap image.</returns>
  78. public static WriteableBitmap GeneratePreviewBitmap(Document document, int maxPreviewWidth, int maxPreviewHeight)
  79. {
  80. var opacityLayers = document.Layers.Where(x => x.IsVisible && x.Opacity > 0.8f);
  81. return GeneratePreviewBitmap(
  82. opacityLayers.Select(x => x.LayerBitmap),
  83. opacityLayers.Select(x => x.OffsetX),
  84. opacityLayers.Select(x => x.OffsetY),
  85. document.Width,
  86. document.Height,
  87. maxPreviewWidth,
  88. maxPreviewHeight);
  89. }
  90. public static WriteableBitmap GeneratePreviewBitmap(IEnumerable<Layer> layers, int width, int height, int maxPreviewWidth, int maxPreviewHeight)
  91. {
  92. var opacityLayers = layers.Where(x => x.IsVisible && x.Opacity > 0.8f);
  93. return GeneratePreviewBitmap(
  94. opacityLayers.Select(x => x.LayerBitmap),
  95. opacityLayers.Select(x => x.OffsetX),
  96. opacityLayers.Select(x => x.OffsetY),
  97. width,
  98. height,
  99. maxPreviewWidth,
  100. maxPreviewHeight);
  101. }
  102. public static WriteableBitmap GeneratePreviewBitmap(IEnumerable<SerializableLayer> layers, int width, int height, int maxPreviewWidth, int maxPreviewHeight)
  103. {
  104. var opacityLayers = layers.Where(x => x.IsVisible && x.Opacity > 0.8f
  105. && x.Height > 0 && x.Width > 0);
  106. return GeneratePreviewBitmap(
  107. opacityLayers.Select(x => new Surface(x.ToSKImage())),
  108. opacityLayers.Select(x => x.OffsetX),
  109. opacityLayers.Select(x => x.OffsetY),
  110. width,
  111. height,
  112. maxPreviewWidth,
  113. maxPreviewHeight);
  114. }
  115. public static Dictionary<Guid, SKColor[]> GetPixelsForSelection(Layer[] layers, Coordinates[] selection)
  116. {
  117. Dictionary<Guid, SKColor[]> result = new();
  118. foreach (Layer layer in layers)
  119. {
  120. SKColor[] pixels = new SKColor[selection.Length];
  121. for (int j = 0; j < pixels.Length; j++)
  122. {
  123. Coordinates position = layer.GetRelativePosition(selection[j]);
  124. if (position.X < 0 || position.X > layer.Width - 1 || position.Y < 0 ||
  125. position.Y > layer.Height - 1)
  126. {
  127. continue;
  128. }
  129. var cl = layer.GetPixel(position.X, position.Y);
  130. pixels[j] = cl;
  131. }
  132. result[layer.GuidValue] = pixels;
  133. }
  134. return result;
  135. }
  136. public static SKColor BlendColors(SKColor bottomColor, SKColor topColor)
  137. {
  138. if ((topColor.Alpha < 255 && topColor.Alpha > 0))
  139. {
  140. byte r = (byte)((topColor.Red * topColor.Alpha / 255) + (bottomColor.Red * bottomColor.Alpha * (255 - topColor.Alpha) / (255 * 255)));
  141. byte g = (byte)((topColor.Green * topColor.Alpha / 255) + (bottomColor.Green * bottomColor.Alpha * (255 - topColor.Alpha) / (255 * 255)));
  142. byte b = (byte)((topColor.Blue * topColor.Alpha / 255) + (bottomColor.Blue * bottomColor.Alpha * (255 - topColor.Alpha) / (255 * 255)));
  143. byte a = (byte)(topColor.Alpha + (bottomColor.Alpha * (255 - topColor.Alpha) / 255));
  144. return new SKColor(r, g, b, a);
  145. }
  146. return topColor.Alpha == 255 ? topColor : bottomColor;
  147. }
  148. private static WriteableBitmap GeneratePreviewBitmap(
  149. IEnumerable<Surface> layerBitmaps,
  150. IEnumerable<int> offsetsX,
  151. IEnumerable<int> offsetsY,
  152. int width,
  153. int height,
  154. int maxPreviewWidth,
  155. int maxPreviewHeight)
  156. {
  157. int count = layerBitmaps.Count();
  158. if (count != offsetsX.Count() || count != offsetsY.Count())
  159. {
  160. throw new ArgumentException("There were not the same amount of bitmaps and offsets", nameof(layerBitmaps));
  161. }
  162. using Surface previewSurface = new Surface(maxPreviewWidth, maxPreviewHeight);
  163. return previewSurface.ToWriteableBitmap();
  164. /*
  165. WriteableBitmap previewBitmap = BitmapFactory.New(width, height);
  166. var layerBitmapsEnumerator = layerBitmaps.GetEnumerator();
  167. var offsetsXEnumerator = offsetsX.GetEnumerator();
  168. var offsetsYEnumerator = offsetsY.GetEnumerator();
  169. while (layerBitmapsEnumerator.MoveNext())
  170. {
  171. offsetsXEnumerator.MoveNext();
  172. offsetsYEnumerator.MoveNext();
  173. var bitmap = layerBitmapsEnumerator.Current;
  174. var offsetX = offsetsXEnumerator.Current;
  175. var offsetY = offsetsYEnumerator.Current;
  176. previewBitmap.Blit(
  177. new Rect(offsetX, offsetY, bitmap.Width, bitmap.Height),
  178. bitmap,
  179. new Rect(0, 0, bitmap.Width, bitmap.Height));
  180. }
  181. int newWidth = width >= height ? maxPreviewWidth : (int)Math.Ceiling(width / ((float)height / maxPreviewHeight));
  182. int newHeight = height > width ? maxPreviewHeight : (int)Math.Ceiling(height / ((float)width / maxPreviewWidth));
  183. return previewBitmap.Redesize(newWidth, newHeight, WriteableBitmapExtensions.Interpolation.NearestNeighbor);*/
  184. }
  185. }
  186. }