Example #1
0
        public static unsafe void Save(Document input, Stream output, PropertyBasedSaveConfigToken token, ProgressEventHandler progressCallback)
        {
            bool           rle         = token.GetProperty <PaintDotNet.PropertySystem.BooleanProperty>(PropertyNames.RLE).Value;
            AbrFileVersion fileVersion = (AbrFileVersion)token.GetProperty(PropertyNames.FileVersion).Value;

            double progressPercentage = 0.0;
            double progressDelta      = (1.0 / input.Layers.Count) * 100.0;

            using (BinaryReverseWriter writer = new BinaryReverseWriter(output, true))
            {
                writer.Write((short)fileVersion);
                writer.Write((short)input.Layers.Count);

                foreach (Layer item in input.Layers)
                {
                    BitmapLayer layer = (BitmapLayer)item;

                    SaveLayer(writer, layer, fileVersion, rle);

                    progressPercentage += progressDelta;

                    progressCallback(null, new ProgressEventArgs(progressPercentage));
                }
            }
        }
Example #2
0
        private static void SaveLayer(BinaryReverseWriter writer, BitmapLayer layer, AbrFileVersion fileVersion, bool rle)
        {
            writer.Write((short)AbrBrushType.Sampled);

            using (new LengthWriter(writer))
            {
                // Write the miscellaneous data, unused.
                writer.Write(0);

                // Write the spacing.
                string spacingMetaData = layer.Metadata.GetUserValue(AbrMetadataNames.BrushSpacing);

                if (spacingMetaData != null &&
                    int.TryParse(spacingMetaData, NumberStyles.Number, CultureInfo.InvariantCulture, out int spacing))
                {
                    writer.Write((short)spacing);
                }
                else
                {
                    writer.Write((short)DefaultSpacingPercent);
                }

                // Write the brush name, if applicable.
                if (fileVersion == AbrFileVersion.Version2)
                {
                    writer.WriteUnicodeString(layer.Name);
                }

                Rectangle imageBounds = GetImageRectangle(layer.Surface);

                // Write the anti-aliasing.
                if (imageBounds.Width < 32 && imageBounds.Height < 32)
                {
                    // Only brushes less than 32x32 pixels are anti-aliased by Photoshop.
                    writer.Write((byte)1);
                }
                else
                {
                    writer.Write((byte)0);
                }

                // Write the Int16 bounds.
                writer.WriteInt16Rectangle(imageBounds);
                // Write the Int32 bounds.
                writer.WriteInt32Rectangle(imageBounds);
                // Write the depth.
                writer.Write((short)8);

                byte[] alpha = GetBrushAlphaData(layer.Surface, imageBounds);

                int rowsRemaining = imageBounds.Height;
                int rowsRead      = 0;
                do
                {
                    // Brushes taller than 16384 pixels are split into 16384 line chunks.
                    int chunkHeight = Math.Min(rowsRemaining, 16384);

                    if (rle)
                    {
                        // Write the RLE compressed header.
                        writer.Write((byte)AbrImageCompression.RLE);

                        long rowCountOffset = writer.BaseStream.Position;

                        for (int i = 0; i < chunkHeight; i++)
                        {
                            // Placeholder for the row byte count.
                            writer.Write(short.MaxValue);
                        }

                        short[] rowByteCount = new short[chunkHeight];

                        for (int y = 0; y < chunkHeight; y++)
                        {
                            int row = rowsRead + y;
                            rowByteCount[y] = (short)RLEHelper.EncodedRow(writer.BaseStream, alpha, row * imageBounds.Width, imageBounds.Width);
                        }

                        long current = writer.BaseStream.Position;

                        writer.BaseStream.Position = rowCountOffset;
                        for (int i = 0; i < chunkHeight; i++)
                        {
                            writer.Write(rowByteCount[i]);
                        }

                        writer.BaseStream.Position = current;
                    }
                    else
                    {
                        // Write the uncompressed header.
                        writer.Write((byte)AbrImageCompression.Raw);

                        for (int y = 0; y < chunkHeight; y++)
                        {
                            int row = rowsRead + y;
                            writer.Write(alpha, row * imageBounds.Width, imageBounds.Width);
                        }
                    }

                    rowsRemaining -= 16384;
                    rowsRead      += 16384;
                } while (rowsRemaining > 0);
            }
        }