123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- using System.Collections.Generic;
- using System.Drawing;
- using System.IO;
- using System.Linq;
- using ChunkyImageLib;
- using ChunkyImageLib.DataHolders;
- using PixiEditor.AvaloniaUI.Helpers;
- using PixiEditor.AvaloniaUI.Models.Handlers;
- using PixiEditor.AvaloniaUI.Models.IO.FileEncoders;
- using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
- using PixiEditor.ChangeableDocument.Changeables.Interfaces;
- using PixiEditor.DrawingApi.Core.Bridge;
- using PixiEditor.DrawingApi.Core.Numerics;
- using PixiEditor.DrawingApi.Core.Surface;
- using PixiEditor.DrawingApi.Core.Surface.ImageData;
- using PixiEditor.Extensions.CommonApi.Palettes;
- using PixiEditor.Numerics;
- using PixiEditor.Parser;
- using PixiEditor.Parser.Collections;
- using BlendMode = PixiEditor.Parser.BlendMode;
- using IKeyFrameChildrenContainer = PixiEditor.ChangeableDocument.Changeables.Interfaces.IKeyFrameChildrenContainer;
- using PixiDocument = PixiEditor.Parser.Document;
- namespace PixiEditor.AvaloniaUI.ViewModels.Document;
- internal partial class DocumentViewModel
- {
- public PixiDocument ToSerializable()
- {
- var root = new Folder();
-
- var doc = Internals.Tracker.Document;
- //AddMembers(doc.StructureRoot.Children, doc, root);
- var document = new PixiDocument
- {
- Width = Width, Height = Height,
- Swatches = ToCollection(Swatches), Palette = ToCollection(Palette),
- RootFolder = root, PreviewImage = (TryRenderWholeImage(0).Value as Surface)?.DrawingSurface.Snapshot().Encode().AsSpan().ToArray(),
- ReferenceLayer = GetReferenceLayer(doc),
- AnimationData = ToAnimationData(doc.AnimationData)
- };
- return document;
- }
- private static ReferenceLayer? GetReferenceLayer(IReadOnlyDocument document)
- {
- if (document.ReferenceLayer == null)
- {
- return null;
- }
- var layer = document.ReferenceLayer!;
- var surface = new Surface(new VecI(layer.ImageSize.X, layer.ImageSize.Y));
-
- surface.DrawBytes(surface.Size, layer.ImageBgra8888Bytes.ToArray(), ColorType.Bgra8888, AlphaType.Premul);
- var encoder = new UniversalFileEncoder(EncodedImageFormat.Png);
- using var stream = new MemoryStream();
-
- encoder.Save(stream, surface);
- stream.Position = 0;
- return new ReferenceLayer
- {
- Enabled = layer.IsVisible,
- Width = (float)layer.Shape.RectSize.X,
- Height = (float)layer.Shape.RectSize.Y,
- OffsetX = (float)layer.Shape.TopLeft.X,
- OffsetY = (float)layer.Shape.TopLeft.Y,
- Corners = new Corners
- {
- TopLeft = layer.Shape.TopLeft.ToVector2(),
- TopRight = layer.Shape.TopRight.ToVector2(),
- BottomLeft = layer.Shape.BottomLeft.ToVector2(),
- BottomRight = layer.Shape.BottomRight.ToVector2()
- },
- Opacity = 1,
- ImageBytes = stream.ToArray()
- };
- }
- private static void AddMembers(IEnumerable<IReadOnlyStructureNode> members, IReadOnlyDocument document, Folder parent)
- {
- foreach (var member in members)
- {
- if (member is IReadOnlyFolderNode readOnlyFolder)
- {
- var folder = ToSerializable(readOnlyFolder);
- //AddMembers(readOnlyFolder.Children, document, folder);
- parent.Children.Add(folder);
- }
- else if (member is IReadOnlyLayerNode readOnlyLayer)
- {
- parent.Children.Add(ToSerializable(readOnlyLayer, document));
- }
- }
- }
-
- private static Folder ToSerializable(IReadOnlyFolderNode folder)
- {
- return new Folder
- {
- Name = folder.MemberName,
- BlendMode = (BlendMode)(int)folder.BlendMode.Value,
- Enabled = folder.IsVisible.Value,
- Opacity = folder.Opacity.Value,
- ClipToMemberBelow = folder.ClipToPreviousMember.Value,
- Mask = GetMask(folder.Mask.Value, folder.MaskIsVisible.Value)
- };
- }
-
- private static ImageLayer ToSerializable(IReadOnlyLayerNode layer, IReadOnlyDocument document)
- {
- var result = document.GetLayerRasterizedImage(layer.Id, 0);
- var tightBounds = document.GetChunkAlignedLayerBounds(layer.Id, 0);
- using var data = result?.Encode();
- byte[] bytes = data?.AsSpan().ToArray();
- var serializable = new ImageLayer
- {
- Width = result?.Width ?? 0, Height = result?.Height ?? 0, OffsetX = tightBounds?.X ?? 0, OffsetY = tightBounds?.Y ?? 0,
- Enabled = layer.IsVisible.Value, BlendMode = (BlendMode)(int)layer.BlendMode.Value, ImageBytes = bytes,
- ClipToMemberBelow = layer.ClipToPreviousMember.Value, Name = layer.MemberName,
- Guid = layer.Id,
- LockAlpha = layer is ITransparencyLockable { LockTransparency: true },
- Opacity = layer.Opacity.Value, Mask = GetMask(layer.Mask.Value, layer.MaskIsVisible.Value)
- };
- return serializable;
- }
- private static Mask GetMask(IReadOnlyChunkyImage mask, bool maskVisible)
- {
- if (mask == null)
- return null;
-
- var maskBound = mask.FindChunkAlignedMostUpToDateBounds();
- if (maskBound == null)
- {
- return new Mask();
- }
-
- var surface = DrawingBackendApi.Current.SurfaceImplementation.Create(new ImageInfo(
- maskBound.Value.Width,
- maskBound.Value.Height));
-
- mask.DrawMostUpToDateRegionOn(new RectI(0, 0, maskBound.Value.Width, maskBound.Value.Height), ChunkResolution.Full, surface, new VecI(0, 0));
- return new Mask
- {
- Width = maskBound.Value.Width, Height = maskBound.Value.Height,
- OffsetX = maskBound.Value.X, OffsetY = maskBound.Value.Y,
- Enabled = maskVisible, ImageBytes = surface.Snapshot().Encode().AsSpan().ToArray()
- };
- }
- private ColorCollection ToCollection(IList<PaletteColor> collection) =>
- new(collection.Select(x => Color.FromArgb(255, x.R, x.G, x.B)));
- private AnimationData ToAnimationData(IReadOnlyAnimationData animationData)
- {
- var animData = new AnimationData();
- animData.KeyFrameGroups = new List<KeyFrameGroup>();
- BuildKeyFrames(animationData.KeyFrames, animData);
-
- return animData;
- }
- private static void BuildKeyFrames(IReadOnlyList<IReadOnlyKeyFrame> root, AnimationData animationData)
- {
- foreach (var keyFrame in root)
- {
- if(keyFrame is IKeyFrameChildrenContainer container)
- {
- KeyFrameGroup group = new();
- group.LayerGuid = keyFrame.LayerGuid;
- group.Enabled = keyFrame.IsVisible;
-
- foreach (var child in container.Children)
- {
- if (child is IKeyFrameChildrenContainer groupKeyFrame)
- {
- BuildKeyFrames(groupKeyFrame.Children, null);
- }
- else if (child is IReadOnlyRasterKeyFrame rasterKeyFrame)
- {
- BuildRasterKeyFrame(rasterKeyFrame, group);
- }
- }
-
- animationData?.KeyFrameGroups.Add(group);
- }
- }
- }
- private static void BuildRasterKeyFrame(IReadOnlyRasterKeyFrame rasterKeyFrame, KeyFrameGroup group)
- {
- var bounds = rasterKeyFrame.Image.FindChunkAlignedMostUpToDateBounds();
- DrawingSurface surface = null;
-
- if (bounds != null)
- {
- surface = DrawingBackendApi.Current.SurfaceImplementation.Create(
- new ImageInfo(bounds.Value.Width, bounds.Value.Height));
- rasterKeyFrame.Image.DrawMostUpToDateRegionOn(
- new RectI(0, 0, bounds.Value.Width, bounds.Value.Height), ChunkResolution.Full, surface,
- new VecI(0, 0));
- }
- group.Children.Add(new RasterKeyFrame()
- {
- LayerGuid = rasterKeyFrame.LayerGuid,
- StartFrame = rasterKeyFrame.StartFrame,
- Duration = rasterKeyFrame.Duration,
- ImageBytes = surface?.Snapshot().Encode().AsSpan().ToArray(),
- });
- }
- }
|