Example #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       = layer.BlendMode.ToPsdBlendMode();
            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);
        }
Example #2
0
 public SaveLayerPixelsContext(BitmapLayer layer, PsdFile psdFile,
                               Document input, PhotoshopFile.Layer psdLayer, PsdSaveConfigToken psdToken)
 {
     this.layer    = layer;
     this.psdFile  = psdFile;
     this.input    = input;
     this.psdToken = psdToken;
     this.psdLayer = psdLayer;
 }
Example #3
0
        /// <summary>
        /// Store layer metadata and image data.
        /// </summary>
        public static void StoreLayer(
            BitmapLayerInfo layerInfo,
            PhotoshopFile.Layer psdLayer,
            PsdSaveConfigToken psdToken)
        {
            var layer = layerInfo.Layer;

            // Set layer metadata
            psdLayer.Name = layerInfo.Name;
            psdLayer.Rect = FindImageRectangle(layer.Surface);

            psdLayer.Opacity            = layer.Opacity;
            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);
            }

            psdLayer.BlendModeKey = layer.BlendMode.ToPsdBlendMode();
            psdLayer.Visible      = layer.Visible;

            // Create folders/groups before actual image data will be saved.
            if (psdToken.SaveLayers && !layerInfo.RenderAsRegularLayer)
            {
                if (layerInfo.IsGroupStart)
                {
                    var status = layer.Visible ? LayerSectionType.OpenFolder : LayerSectionType.ClosedFolder;
                    psdLayer.AdditionalInfo.Add(new LayerSectionInfo(status));
                    psdLayer.Name    = layerInfo.Name;
                    psdLayer.Visible = true;
                }
                else if (layerInfo.IsGroupEnd)
                {
                    // End of the group
                    psdLayer.Opacity      = 255;
                    psdLayer.BlendModeKey = PsdBlendMode.PassThrough;
                    psdLayer.Name         = "</Layer group>";
                    psdLayer.AdditionalInfo.Add(new LayerSectionInfo(LayerSectionType.SectionDivider));
                }

                return;
            }

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

            StoreLayerImage(channelsArray, psdLayer.AlphaChannel, layer.Surface, psdLayer.Rect);
        }
 protected override void InitWidgetFromToken(SaveConfigToken token)
 {
     if (token is PsdSaveConfigToken)
     {
         PsdSaveConfigToken psdToken = (PsdSaveConfigToken)token;
         this.m_rleCompressCheckBox.Checked = psdToken.RleCompress;
     }
     else
     {
         this.m_rleCompressCheckBox.Checked = true;
     }
 }
Example #5
0
 protected PsdSaveConfigToken(PsdSaveConfigToken copyMe)
 {
     this.RleCompress = copyMe.RleCompress;
     this.SaveLayers  = copyMe.SaveLayers;
 }
Example #6
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.Resolution       = GetResolutionInfo(input);
            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>();

                // Create folders/groups before actual image data will be saved.
                var layerInfos = PrepareLayers(pdnLayers, psdToken.SaveLayers);


                var psdLayers = layerInfos.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);
        }
Example #7
0
        protected override void OnSave(Document input, System.IO.Stream output,
                                       SaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback)
        {
            PsdSaveConfigToken psdToken = (PsdSaveConfigToken)token;
            PsdFile            psdFile  = new PsdFile();

            //-----------------------------------------------------------------------

            psdFile.Rows    = input.Height;
            psdFile.Columns = input.Width;

            // we have an Alpha channel which will be saved,
            // we have to add this to our image resources
            psdFile.Channels = 4;

            // for now we oly save the images as RGB
            psdFile.ColorMode = PsdFile.ColorModes.RGB;

            psdFile.Depth = 8;

            //-----------------------------------------------------------------------
            // no color mode Data

            //-----------------------------------------------------------------------

            ResolutionInfo resInfo = new ResolutionInfo();

            resInfo.HeightUnit = ResolutionInfo.Unit.In;
            resInfo.WidthUnit  = ResolutionInfo.Unit.In;

            if (input.DpuUnit == MeasurementUnit.Inch)
            {
                resInfo.HResUnit = ResolutionInfo.ResUnit.PxPerInch;
                resInfo.VResUnit = ResolutionInfo.ResUnit.PxPerInch;

                resInfo.HRes = (short)input.DpuX;
                resInfo.VRes = (short)input.DpuY;
            }
            else
            {
                resInfo.HResUnit = ResolutionInfo.ResUnit.PxPerCent;
                resInfo.VResUnit = ResolutionInfo.ResUnit.PxPerCent;


                resInfo.HRes = (short)(input.DpuX / 2.54);
                resInfo.VRes = (short)(input.DpuY / 2.54);
            }

            psdFile.Resolution = resInfo;
            //-----------------------------------------------------------------------

            psdFile.ImageCompression = psdToken.RleCompress ? ImageCompression.Rle : ImageCompression.Raw;

            int size = psdFile.Rows * psdFile.Columns;

            psdFile.ImageData = new byte[psdFile.Channels][];
            for (int i = 0; i < psdFile.Channels; i++)
            {
                psdFile.ImageData[i] = new byte[size];
            }

            using (RenderArgs ra = new RenderArgs(scratchSurface))
            {
                input.Flatten(scratchSurface);
            }

            unsafe
            {
                for (int y = 0; y < psdFile.Rows; y++)
                {
                    int        rowIndex = y * psdFile.Columns;
                    ColorBgra *srcRow   = scratchSurface.GetRowAddress(y);
                    ColorBgra *srcPixel = srcRow;

                    for (int x = 0; x < psdFile.Columns; x++)
                    {
                        int pos = rowIndex + x;

                        psdFile.ImageData[0][pos] = srcPixel->R;
                        psdFile.ImageData[1][pos] = srcPixel->G;
                        psdFile.ImageData[2][pos] = srcPixel->B;
                        psdFile.ImageData[3][pos] = srcPixel->A;
                        srcPixel++;
                    }
                }
            }

            PaintDotNet.Threading.PrivateThreadPool threadPool = new PaintDotNet.Threading.PrivateThreadPool();
            foreach (BitmapLayer layer in input.Layers)
            {
                PhotoshopFile.Layer psdLayer = new PhotoshopFile.Layer(psdFile);
                BlendOpToBlendModeKey(layer.BlendOp, psdLayer);

                SaveLayerPixelsContext slc          = new SaveLayerPixelsContext(layer, psdFile, input, psdLayer, psdToken);
                WaitCallback           waitCallback = new WaitCallback(slc.SaveLayer);
                threadPool.QueueUserWorkItem(waitCallback);
            }
            threadPool.Drain();

            psdFile.Save(output);
        }
Example #8
0
        public static void SaveLayerPixels(BitmapLayer layer, PsdFile psdFile,
                                           Document input, PhotoshopFile.Layer psdLayer, PsdSaveConfigToken psdToken)
        {
            Surface surface = layer.Surface;

            int rectLeft   = input.Width;
            int rectTop    = input.Height;
            int rectRight  = 0;
            int rectBottom = 0;

            // Determine the real size of this layer, i.e., the smallest rectangle
            // that includes all all non-invisible pixels
            unsafe
            {
                for (int y = 0; y < psdFile.Rows; y++)
                {
                    int        rowIndex = y * psdFile.Columns;
                    ColorBgra *srcRow   = surface.GetRowAddress(y);
                    ColorBgra *srcPixel = srcRow;

                    for (int x = 0; x < psdFile.Columns; x++)
                    {
                        int pos = rowIndex + x;

                        // Found a non-transparent pixel, potentially increase the size of the rectangle
                        if (srcPixel->A > 0)
                        {
                            // Expand the rectangle
                            if (x < rectLeft)
                            {
                                rectLeft = x;
                            }
                            if (x > rectRight)
                            {
                                rectRight = x;
                            }
                            if (y < rectTop)
                            {
                                rectTop = y;
                            }
                            if (y > rectBottom)
                            {
                                rectBottom = y;
                            }
                        }

                        srcPixel++;
                    }
                }
            }

            psdLayer.Rect               = new Rectangle(rectLeft, rectTop, rectRight - rectLeft + 1, rectBottom - rectTop + 1);
            psdLayer.Name               = layer.Name;
            psdLayer.Opacity            = layer.Opacity;
            psdLayer.Visible            = layer.Visible;
            psdLayer.MaskData           = new PhotoshopFile.Layer.Mask(psdLayer);
            psdLayer.BlendingRangesData = new PhotoshopFile.Layer.BlendingRanges(psdLayer);

            int layerSize = psdLayer.Rect.Width * psdLayer.Rect.Height;

            for (int i = -1; i < 3; i++)
            {
                PhotoshopFile.Layer.Channel ch = new PhotoshopFile.Layer.Channel((short)i, psdLayer);

                ch.ImageCompression = psdToken.RleCompress ? ImageCompression.Rle : ImageCompression.Raw;
                ch.ImageData        = new byte[layerSize];
            }

            var channels     = psdLayer.ChannelsArray;
            var alphaChannel = psdLayer.AlphaChannel;

            unsafe
            {
                int rowIndex = 0;
                for (int y = 0; y < psdLayer.Rect.Height; y++)
                {
                    ColorBgra *srcRow   = surface.GetRowAddress(y + psdLayer.Rect.Top);
                    ColorBgra *srcPixel = srcRow + psdLayer.Rect.Left;

                    for (int x = 0; x < psdLayer.Rect.Width; x++)
                    {
                        int pos = rowIndex + x;

                        channels[0].ImageData[pos]  = srcPixel->R;
                        channels[1].ImageData[pos]  = srcPixel->G;
                        channels[2].ImageData[pos]  = srcPixel->B;
                        alphaChannel.ImageData[pos] = srcPixel->A;
                        srcPixel++;
                    }
                    rowIndex += psdLayer.Rect.Width;
                }
            }
        }
 protected PsdSaveConfigToken(PsdSaveConfigToken copyMe)
 {
     this.m_rleCompress = copyMe.m_rleCompress;
 }