Beispiel #1
0
        /// <summary>
        /// Store layer metadata and image data.
        /// </summary>
        public static void StoreLayer(BitmapLayer layer,
                                      PhotoshopFile.Layer psdLayer, PsdSaveConfigToken psdToken)
        {
            // Set layer metadata
            psdLayer.Name               = layer.Name;
            psdLayer.Rect               = FindImageRectangle(layer.Surface);
            psdLayer.BlendModeKey       = PsdBlendMode.Normal;
            psdLayer.Opacity            = layer.Opacity;
            psdLayer.Visible            = layer.Visible;
            psdLayer.Masks              = new MaskInfo();
            psdLayer.BlendingRangesData = new BlendingRanges(psdLayer);

            // Store channel metadata
            int layerSize = psdLayer.Rect.Width * psdLayer.Rect.Height;

            for (int i = -1; i < 3; i++)
            {
                var ch = new Channel((short)i, psdLayer);
                ch.ImageCompression = psdToken.RleCompress ? ImageCompression.Rle : ImageCompression.Raw;
                ch.ImageData        = new byte[layerSize];
                psdLayer.Channels.Add(ch);
            }

            // Store and compress channel image data
            var channelsArray = psdLayer.Channels.ToIdArray();

            StoreLayerImage(channelsArray, psdLayer.AlphaChannel, layer.Surface, psdLayer.Rect);
        }
Beispiel #2
0
 protected PsdSaveConfigToken(PsdSaveConfigToken copyMe)
 {
     this.RleCompress = copyMe.RleCompress;
 }
Beispiel #3
0
        public static void Save(Document input, Stream output, PsdSaveConfigToken psdToken,
                                Surface scratchSurface, ProgressEventHandler progressCallback)
        {
            var psdVersion = ((input.Height > 30000) || (input.Width > 30000))
        ? PsdFileVersion.PsbLargeDocument
        : PsdFileVersion.Psd;
            var psdFile = new PsdFile(psdVersion);

            psdFile.RowCount    = input.Height;
            psdFile.ColumnCount = input.Width;

            // We only save in RGBA format, 8 bits per channel, which corresponds to
            // Paint.NET's internal representation.

            psdFile.ChannelCount     = 4;
            psdFile.ColorMode        = PsdColorMode.RGB;
            psdFile.BitDepth         = 8;
            psdFile.ImageCompression = psdToken.RleCompress
        ? ImageCompression.Rle
        : ImageCompression.Raw;

            // Treat the composite image as another layer when reporting progress.
            var progress        = new ProgressNotifier(progressCallback);
            var percentPerLayer = percentStoreImages
                                  / (input.Layers.Count + 1);

            // Render the composite image.  This operation is parallelized within
            // Paint.NET using its own private thread pool.
            using (var ra = new RenderArgs(scratchSurface))
            {
                input.Flatten(scratchSurface);
                progress.Notify(percentRenderComposite);
            }

            // Delegate to store the composite
            Action storeCompositeAction = () =>
            {
                // Allocate space for the composite image data
                int imageSize = psdFile.RowCount * psdFile.ColumnCount;
                for (short i = 0; i < psdFile.ChannelCount; i++)
                {
                    var channel = new Channel(i, psdFile.BaseLayer);
                    channel.ImageData        = new byte[imageSize];
                    channel.ImageCompression = psdFile.ImageCompression;
                    psdFile.BaseLayer.Channels.Add(channel);
                }

                var channelsArray = psdFile.BaseLayer.Channels.ToIdArray();
                StoreLayerImage(channelsArray, channelsArray[3],
                                scratchSurface, psdFile.BaseLayer.Rect);

                progress.Notify(percentPerLayer);
            };

            // Delegate to store the layers
            Action storeLayersAction = () =>
            {
                // LayerList is an ArrayList, so we have to cast to get a generic
                // IEnumerable that works with LINQ.
                var pdnLayers = input.Layers.Cast <BitmapLayer>();
                var psdLayers = pdnLayers.AsParallel().AsOrdered().Select(pdnLayer =>
                {
                    var psdLayer = new PhotoshopFile.Layer(psdFile);
                    StoreLayer(pdnLayer, psdLayer, psdToken);

                    progress.Notify(percentPerLayer);
                    return(psdLayer);
                });
                psdFile.Layers.AddRange(psdLayers);
            };

            // Process composite and layers in parallel
            Parallel.Invoke(storeCompositeAction, storeLayersAction);

            psdFile.Save(output, Encoding.Default);
        }