DocumentViewModel.Serialization.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. using System.Collections.Generic;
  2. using System.Drawing;
  3. using System.IO;
  4. using System.Linq;
  5. using ChunkyImageLib;
  6. using ChunkyImageLib.DataHolders;
  7. using PixiEditor.AvaloniaUI.Helpers;
  8. using PixiEditor.AvaloniaUI.Models.Handlers;
  9. using PixiEditor.AvaloniaUI.Models.IO.FileEncoders;
  10. using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
  11. using PixiEditor.ChangeableDocument.Changeables.Interfaces;
  12. using PixiEditor.DrawingApi.Core.Bridge;
  13. using PixiEditor.DrawingApi.Core.Numerics;
  14. using PixiEditor.DrawingApi.Core.Surface;
  15. using PixiEditor.DrawingApi.Core.Surface.ImageData;
  16. using PixiEditor.Extensions.CommonApi.Palettes;
  17. using PixiEditor.Numerics;
  18. using PixiEditor.Parser;
  19. using PixiEditor.Parser.Collections;
  20. using BlendMode = PixiEditor.Parser.BlendMode;
  21. using IKeyFrameChildrenContainer = PixiEditor.ChangeableDocument.Changeables.Interfaces.IKeyFrameChildrenContainer;
  22. using PixiDocument = PixiEditor.Parser.Document;
  23. namespace PixiEditor.AvaloniaUI.ViewModels.Document;
  24. internal partial class DocumentViewModel
  25. {
  26. public PixiDocument ToSerializable()
  27. {
  28. var root = new Folder();
  29. var doc = Internals.Tracker.Document;
  30. //AddMembers(doc.StructureRoot.Children, doc, root);
  31. var document = new PixiDocument
  32. {
  33. Width = Width, Height = Height,
  34. Swatches = ToCollection(Swatches), Palette = ToCollection(Palette),
  35. RootFolder = root, PreviewImage = (TryRenderWholeImage(0).Value as Surface)?.DrawingSurface.Snapshot().Encode().AsSpan().ToArray(),
  36. ReferenceLayer = GetReferenceLayer(doc),
  37. AnimationData = ToAnimationData(doc.AnimationData)
  38. };
  39. return document;
  40. }
  41. private static ReferenceLayer? GetReferenceLayer(IReadOnlyDocument document)
  42. {
  43. if (document.ReferenceLayer == null)
  44. {
  45. return null;
  46. }
  47. var layer = document.ReferenceLayer!;
  48. var surface = new Surface(new VecI(layer.ImageSize.X, layer.ImageSize.Y));
  49. surface.DrawBytes(surface.Size, layer.ImageBgra8888Bytes.ToArray(), ColorType.Bgra8888, AlphaType.Premul);
  50. var encoder = new UniversalFileEncoder(EncodedImageFormat.Png);
  51. using var stream = new MemoryStream();
  52. encoder.Save(stream, surface);
  53. stream.Position = 0;
  54. return new ReferenceLayer
  55. {
  56. Enabled = layer.IsVisible,
  57. Width = (float)layer.Shape.RectSize.X,
  58. Height = (float)layer.Shape.RectSize.Y,
  59. OffsetX = (float)layer.Shape.TopLeft.X,
  60. OffsetY = (float)layer.Shape.TopLeft.Y,
  61. Corners = new Corners
  62. {
  63. TopLeft = layer.Shape.TopLeft.ToVector2(),
  64. TopRight = layer.Shape.TopRight.ToVector2(),
  65. BottomLeft = layer.Shape.BottomLeft.ToVector2(),
  66. BottomRight = layer.Shape.BottomRight.ToVector2()
  67. },
  68. Opacity = 1,
  69. ImageBytes = stream.ToArray()
  70. };
  71. }
  72. private static void AddMembers(IEnumerable<IReadOnlyStructureNode> members, IReadOnlyDocument document, Folder parent)
  73. {
  74. foreach (var member in members)
  75. {
  76. if (member is IReadOnlyFolderNode readOnlyFolder)
  77. {
  78. var folder = ToSerializable(readOnlyFolder);
  79. //AddMembers(readOnlyFolder.Children, document, folder);
  80. parent.Children.Add(folder);
  81. }
  82. else if (member is IReadOnlyLayerNode readOnlyLayer)
  83. {
  84. parent.Children.Add(ToSerializable(readOnlyLayer, document));
  85. }
  86. }
  87. }
  88. private static Folder ToSerializable(IReadOnlyFolderNode folder)
  89. {
  90. return new Folder
  91. {
  92. Name = folder.MemberName,
  93. BlendMode = (BlendMode)(int)folder.BlendMode.Value,
  94. Enabled = folder.IsVisible.Value,
  95. Opacity = folder.Opacity.Value,
  96. ClipToMemberBelow = folder.ClipToPreviousMember.Value,
  97. Mask = GetMask(folder.Mask.Value, folder.MaskIsVisible.Value)
  98. };
  99. }
  100. private static ImageLayer ToSerializable(IReadOnlyLayerNode layer, IReadOnlyDocument document)
  101. {
  102. var result = document.GetLayerRasterizedImage(layer.Id, 0);
  103. var tightBounds = document.GetChunkAlignedLayerBounds(layer.Id, 0);
  104. using var data = result?.Encode();
  105. byte[] bytes = data?.AsSpan().ToArray();
  106. var serializable = new ImageLayer
  107. {
  108. Width = result?.Width ?? 0, Height = result?.Height ?? 0, OffsetX = tightBounds?.X ?? 0, OffsetY = tightBounds?.Y ?? 0,
  109. Enabled = layer.IsVisible.Value, BlendMode = (BlendMode)(int)layer.BlendMode.Value, ImageBytes = bytes,
  110. ClipToMemberBelow = layer.ClipToPreviousMember.Value, Name = layer.MemberName,
  111. Guid = layer.Id,
  112. LockAlpha = layer is ITransparencyLockable { LockTransparency: true },
  113. Opacity = layer.Opacity.Value, Mask = GetMask(layer.Mask.Value, layer.MaskIsVisible.Value)
  114. };
  115. return serializable;
  116. }
  117. private static Mask GetMask(IReadOnlyChunkyImage mask, bool maskVisible)
  118. {
  119. if (mask == null)
  120. return null;
  121. var maskBound = mask.FindChunkAlignedMostUpToDateBounds();
  122. if (maskBound == null)
  123. {
  124. return new Mask();
  125. }
  126. var surface = DrawingBackendApi.Current.SurfaceImplementation.Create(new ImageInfo(
  127. maskBound.Value.Width,
  128. maskBound.Value.Height));
  129. mask.DrawMostUpToDateRegionOn(new RectI(0, 0, maskBound.Value.Width, maskBound.Value.Height), ChunkResolution.Full, surface, new VecI(0, 0));
  130. return new Mask
  131. {
  132. Width = maskBound.Value.Width, Height = maskBound.Value.Height,
  133. OffsetX = maskBound.Value.X, OffsetY = maskBound.Value.Y,
  134. Enabled = maskVisible, ImageBytes = surface.Snapshot().Encode().AsSpan().ToArray()
  135. };
  136. }
  137. private ColorCollection ToCollection(IList<PaletteColor> collection) =>
  138. new(collection.Select(x => Color.FromArgb(255, x.R, x.G, x.B)));
  139. private AnimationData ToAnimationData(IReadOnlyAnimationData animationData)
  140. {
  141. var animData = new AnimationData();
  142. animData.KeyFrameGroups = new List<KeyFrameGroup>();
  143. BuildKeyFrames(animationData.KeyFrames, animData);
  144. return animData;
  145. }
  146. private static void BuildKeyFrames(IReadOnlyList<IReadOnlyKeyFrame> root, AnimationData animationData)
  147. {
  148. foreach (var keyFrame in root)
  149. {
  150. if(keyFrame is IKeyFrameChildrenContainer container)
  151. {
  152. KeyFrameGroup group = new();
  153. group.LayerGuid = keyFrame.LayerGuid;
  154. group.Enabled = keyFrame.IsVisible;
  155. foreach (var child in container.Children)
  156. {
  157. if (child is IKeyFrameChildrenContainer groupKeyFrame)
  158. {
  159. BuildKeyFrames(groupKeyFrame.Children, null);
  160. }
  161. else if (child is IReadOnlyRasterKeyFrame rasterKeyFrame)
  162. {
  163. BuildRasterKeyFrame(rasterKeyFrame, group);
  164. }
  165. }
  166. animationData?.KeyFrameGroups.Add(group);
  167. }
  168. }
  169. }
  170. private static void BuildRasterKeyFrame(IReadOnlyRasterKeyFrame rasterKeyFrame, KeyFrameGroup group)
  171. {
  172. var bounds = rasterKeyFrame.Image.FindChunkAlignedMostUpToDateBounds();
  173. DrawingSurface surface = null;
  174. if (bounds != null)
  175. {
  176. surface = DrawingBackendApi.Current.SurfaceImplementation.Create(
  177. new ImageInfo(bounds.Value.Width, bounds.Value.Height));
  178. rasterKeyFrame.Image.DrawMostUpToDateRegionOn(
  179. new RectI(0, 0, bounds.Value.Width, bounds.Value.Height), ChunkResolution.Full, surface,
  180. new VecI(0, 0));
  181. }
  182. group.Children.Add(new RasterKeyFrame()
  183. {
  184. LayerGuid = rasterKeyFrame.LayerGuid,
  185. StartFrame = rasterKeyFrame.StartFrame,
  186. Duration = rasterKeyFrame.Duration,
  187. ImageBytes = surface?.Snapshot().Encode().AsSpan().ToArray(),
  188. });
  189. }
  190. }