BitmapUtils.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Windows;
  5. using System.Windows.Media.Imaging;
  6. using PixiEditor.Models.DataHolders;
  7. using PixiEditor.Models.Layers;
  8. using PixiEditor.Models.Position;
  9. using Color = System.Windows.Media.Color;
  10. namespace PixiEditor.Models.ImageManipulation
  11. {
  12. public static class BitmapUtils
  13. {
  14. /// <summary>
  15. /// Converts pixel bytes to WriteableBitmap.
  16. /// </summary>
  17. /// <param name="currentBitmapWidth">Width of bitmap.</param>
  18. /// <param name="currentBitmapHeight">Height of bitmap.</param>
  19. /// <param name="byteArray">Bitmap byte array.</param>
  20. /// <returns>WriteableBitmap.</returns>
  21. public static WriteableBitmap BytesToWriteableBitmap(int currentBitmapWidth, int currentBitmapHeight, byte[] byteArray)
  22. {
  23. WriteableBitmap bitmap = BitmapFactory.New(currentBitmapWidth, currentBitmapHeight);
  24. if (byteArray != null)
  25. {
  26. bitmap.FromByteArray(byteArray);
  27. }
  28. return bitmap;
  29. }
  30. /// <summary>
  31. /// Converts layers bitmaps into one bitmap.
  32. /// </summary>
  33. /// <param name="layers">Layers to combine.</param>
  34. /// <param name="width">Width of final bitmap.</param>
  35. /// <param name="height">Height of final bitmap.</param>
  36. /// <returns>WriteableBitmap of layered bitmaps.</returns>
  37. public static WriteableBitmap CombineLayers(Layer[] layers, int width, int height)
  38. {
  39. WriteableBitmap finalBitmap = BitmapFactory.New(width, height);
  40. using (finalBitmap.GetBitmapContext())
  41. {
  42. for (int i = 0; i < layers.Length; i++)
  43. {
  44. float layerOpacity = layers[i].Opacity;
  45. Layer layer = layers[i];
  46. for (int y = 0; y < layers[i].Height; y++)
  47. {
  48. for (int x = 0; x < layers[i].Width; x++)
  49. {
  50. Color color = layer.GetPixel(x, y);
  51. if (i > 0 && ((color.A < 255 && color.A > 0) || (layerOpacity < 1f && layerOpacity > 0 && color.A > 0)))
  52. {
  53. var lastLayerPixel = finalBitmap.GetPixel(x + layer.OffsetX, y + layer.OffsetY);
  54. byte pixelA = (byte)(color.A * layerOpacity);
  55. byte r = (byte)((color.R * pixelA / 255) + (lastLayerPixel.R * lastLayerPixel.A * (255 - pixelA) / (255 * 255)));
  56. byte g = (byte)((color.G * pixelA / 255) + (lastLayerPixel.G * lastLayerPixel.A * (255 - pixelA) / (255 * 255)));
  57. byte b = (byte)((color.B * pixelA / 255) + (lastLayerPixel.B * lastLayerPixel.A * (255 - pixelA) / (255 * 255)));
  58. byte a = (byte)(pixelA + (lastLayerPixel.A * (255 - pixelA) / 255));
  59. color = Color.FromArgb(a, r, g, b);
  60. }
  61. else
  62. {
  63. color = Color.FromArgb(color.A, color.R, color.G, color.B);
  64. }
  65. if (color.A > 0)
  66. {
  67. finalBitmap.SetPixel(x + layer.OffsetX, y + layer.OffsetY, color);
  68. }
  69. }
  70. }
  71. }
  72. }
  73. return finalBitmap;
  74. }
  75. /// <summary>
  76. /// Generates simplified preview from Document, very fast, great for creating small previews. Creates uniform streched image.
  77. /// </summary>
  78. /// <param name="document">Document which be used to generate preview.</param>
  79. /// <param name="maxPreviewWidth">Max width of preview.</param>
  80. /// <param name="maxPreviewHeight">Max height of preview.</param>
  81. /// <returns>WriteableBitmap image.</returns>
  82. public static WriteableBitmap GeneratePreviewBitmap(Document document, int maxPreviewWidth, int maxPreviewHeight)
  83. {
  84. WriteableBitmap previewBitmap = BitmapFactory.New(document.Width, document.Height);
  85. // 0.8 because blit doesn't take into consideration layer opacity. Small images with opacity > 80% are simillar enough.
  86. foreach (var layer in document.Layers.Where(x => x.IsVisible && x.Opacity > 0.8f))
  87. {
  88. previewBitmap.Blit(
  89. new Rect(layer.OffsetX, layer.OffsetY, layer.Width, layer.Height),
  90. layer.LayerBitmap,
  91. new Rect(0, 0, layer.Width, layer.Height));
  92. }
  93. int width = document.Width >= document.Height ? maxPreviewWidth : (int)Math.Ceiling(document.Width / ((float)document.Height / maxPreviewHeight));
  94. int height = document.Height > document.Width ? maxPreviewHeight : (int)Math.Ceiling(document.Height / ((float)document.Width / maxPreviewWidth));
  95. return previewBitmap.Resize(width, height, WriteableBitmapExtensions.Interpolation.NearestNeighbor);
  96. }
  97. public static Dictionary<Layer, Color[]> GetPixelsForSelection(Layer[] layers, Coordinates[] selection)
  98. {
  99. Dictionary<Layer, Color[]> result = new Dictionary<Layer, Color[]>();
  100. for (int i = 0; i < layers.Length; i++)
  101. {
  102. Color[] pixels = new Color[selection.Length];
  103. using (layers[i].LayerBitmap.GetBitmapContext())
  104. {
  105. for (int j = 0; j < pixels.Length; j++)
  106. {
  107. Coordinates position = layers[i].GetRelativePosition(selection[j]);
  108. if (position.X < 0 || position.X > layers[i].Width - 1 || position.Y < 0 ||
  109. position.Y > layers[i].Height - 1)
  110. {
  111. continue;
  112. }
  113. pixels[j] = layers[i].GetPixel(position.X, position.Y);
  114. }
  115. }
  116. result[layers[i]] = pixels;
  117. }
  118. return result;
  119. }
  120. }
  121. }