示例#1
0
        public void Save(Document input, Stream output, CompressionFormats format, Surface scratchSurface, ushort majorVersion, ProgressEventHandler callback)
        {
            if (majorVersion == PSPConstants.majorVersion5 && input.Layers.Count > 64)
            {
                throw new FormatException(string.Format(Properties.Resources.MaxLayersFormat, 64));
            }
            else if ((majorVersion == PSPConstants.majorVersion6 || majorVersion == PSPConstants.majorVersion7) && input.Layers.Count > 100)
            {
                throw new FormatException(string.Format(Properties.Resources.MaxLayersFormat, 100));
            }

            using (BinaryWriterEx writer = new BinaryWriterEx(output, false))
            {
                this.fileHeader      = new FileHeader(majorVersion);
                this.imageAttributes = new GeneralImageAttributes(
                    input.Width,
                    input.Height,
                    CompressionFromTokenFormat(format),
                    0,
                    input.Layers.Count,
                    majorVersion);
                switch (input.DpuUnit)
                {
                case MeasurementUnit.Centimeter:
                    this.imageAttributes.ResValue = input.DpuX;
                    this.imageAttributes.ResUnit  = ResolutionMetric.Centimeter;
                    break;

                case MeasurementUnit.Inch:
                    this.imageAttributes.ResValue = input.DpuX;
                    this.imageAttributes.ResUnit  = ResolutionMetric.Inch;
                    break;
                }

                this.totalProgress = 0;
                this.doneProgress  = 0;

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

                    Rectangle rect = PSPUtil.GetImageSaveRectangle(layer.Surface);

                    if (!rect.IsEmpty)
                    {
                        if (LayerHasTransparency(layer.Surface, rect))
                        {
                            this.totalProgress += 4;
                            flatImage           = false;
                        }
                        else
                        {
                            this.totalProgress += 3;
                        }
                    }
                }

                if (flatImage)
                {
                    this.imageAttributes.SetGraphicContentFlag(PSPGraphicContents.FlatImage);
                }

                if (majorVersion > PSPConstants.majorVersion5)
                {
                    CreateCompositeImageBlock(input, scratchSurface, callback, majorVersion);
                }
                else
                {
                    CreateThumbnailBlock(input, scratchSurface, callback, majorVersion);
                }

                int layerCount = input.Layers.Count;

                LayerInfoChunk[]       layerInfoChunks   = new LayerInfoChunk[layerCount];
                LayerBitmapInfoChunk[] layerBitmapChunks = new LayerBitmapInfoChunk[layerCount];

                for (int i = 0; i < layerCount; i++)
                {
                    BitmapLayer layer = (BitmapLayer)input.Layers[i];

                    Rectangle savedBounds = PSPUtil.GetImageSaveRectangle(layer.Surface);

                    LayerInfoChunk infoChunk = new LayerInfoChunk(layer, BlendOptoBlendMode(layer.BlendOp), savedBounds, majorVersion);

                    int channelCount = 3;
                    int bitmapCount  = 1;

                    if (LayerHasTransparency(layer.Surface, savedBounds))
                    {
                        channelCount = 4;
                        bitmapCount  = 2;
                    }

                    LayerBitmapInfoChunk biChunk = new LayerBitmapInfoChunk(bitmapCount, channelCount)
                    {
                        channels = SplitImageChannels(layer.Surface, savedBounds, channelCount, majorVersion, false, callback)
                    };

                    if (majorVersion <= PSPConstants.majorVersion5)
                    {
                        infoChunk.v5BitmapCount  = biChunk.bitmapCount;
                        infoChunk.v5ChannelCount = biChunk.channelCount;
                    }

                    layerInfoChunks[i]   = infoChunk;
                    layerBitmapChunks[i] = biChunk;
                }

                this.layerBlock = new LayerBlock(layerInfoChunks, layerBitmapChunks);

                string creatorData = input.Metadata.GetUserValue(PSPCreatorMetaData);
                if (!string.IsNullOrEmpty(creatorData))
                {
                    this.creator = DeserializeFromBase64 <CreatorBlock>(creatorData);
                }
                else
                {
                    this.creator = new CreatorBlock();
                }

                writer.Write(PSPFileSig);
                this.fileHeader.Save(writer);
                this.imageAttributes.Save(writer);
                this.creator.Save(writer);
                if (this.compImage != null)
                {
                    this.compImage.Save(writer);
                }
                else if (this.v5Thumbnail != null)
                {
                    this.v5Thumbnail.Save(writer);
                }
                this.layerBlock.Save(writer, majorVersion);
            }
        }
示例#2
0
        public Document Load(Stream input)
        {
            LoadPSPFile(input);

            if (this.imageAttributes == null || this.layerBlock == null)
            {
                throw new FormatException(Properties.Resources.InvalidPSPFile);
            }

            if (this.imageAttributes.BitDepth <= 8 && this.globalPalette == null)
            {
                throw new FormatException(Properties.Resources.ColorPaletteNotFound);
            }

            LayerInfoChunk[] infoChunks = this.layerBlock.LayerInfo;
            int layerCount = infoChunks.Length;

            // Some PSP files may have layers that are larger than the dimensions stored in the image attributes.
            int maxWidth  = this.imageAttributes.Width;
            int maxHeight = this.imageAttributes.Height;

            for (int i = 0; i < layerCount; i++)
            {
                Rectangle savedBounds = infoChunks[i].saveRect;
                if (savedBounds.Width > maxWidth)
                {
                    maxWidth = savedBounds.Width;
                }
                if (savedBounds.Height > maxHeight)
                {
                    maxHeight = savedBounds.Height;
                }
            }

            if (maxWidth <= 0 || maxHeight <= 0)
            {
                throw new FormatException(Properties.Resources.InvalidDocumentDimensions);
            }

            Document doc = new Document(maxWidth, maxHeight);

            if (this.imageAttributes.ResValue > 0.0)
            {
                switch (this.imageAttributes.ResUnit)
                {
                case ResolutionMetric.Inch:
                    doc.DpuUnit = MeasurementUnit.Inch;
                    doc.DpuX    = doc.DpuY = this.imageAttributes.ResValue;
                    break;

                case ResolutionMetric.Centimeter:
                    doc.DpuUnit = MeasurementUnit.Centimeter;
                    doc.DpuX    = doc.DpuY = this.imageAttributes.ResValue;
                    break;

                default:
                    break;
                }
            }

            short transIndex = -1;

            if (this.imageAttributes.BitDepth < 24 && this.extData != null)
            {
                byte[] data;
                if (this.extData.Values.TryGetValue(PSPExtendedDataID.TransparencyIndex, out data))
                {
                    transIndex = BitConverter.ToInt16(data, 0);
                }
            }

            LayerBitmapInfoChunk[] bitmapInfoChunks = this.layerBlock.LayerBitmapInfo;

            for (int i = 0; i < layerCount; i++)
            {
                LayerInfoChunk info = infoChunks[i];

                BitmapLayer layer = new BitmapLayer(doc.Width, doc.Height)
                {
                    Name = info.name, Opacity = info.opacity
                };
                UserBlendOp blendOp = BlendModetoBlendOp(info.blendMode);
                layer.SetBlendOp(blendOp);
                layer.Visible = (info.layerFlags & PSPLayerProperties.Visible) == PSPLayerProperties.Visible;

                Rectangle saveRect = info.saveRect;

                if (!saveRect.IsEmpty)
                {
                    LayerBitmapInfoChunk bitmapInfo = bitmapInfoChunks[i];

                    if (bitmapInfo.bitmapCount == 1)
                    {
                        new UnaryPixelOps.SetAlphaChannelTo255().Apply(layer.Surface, saveRect);
                    }

                    int alphaIndex = 0;

                    int bitDepth = this.imageAttributes.BitDepth;

                    int    bytesPerPixel   = 1;
                    int    stride          = saveRect.Width;
                    byte[] expandedPalette = null;

                    switch (bitDepth)
                    {
                    case 48:
                        bytesPerPixel = 2;
                        stride       *= 2;
                        break;

                    case 4:
                    case 1:
                        expandedPalette = ExpandPackedPalette(saveRect, bitmapInfo, bitDepth);
                        break;
                    }

                    unsafe
                    {
                        int palIdx = 0;
                        NativeStructs.RGBQUAD entry;

                        Surface surface = layer.Surface;
                        for (int y = saveRect.Top; y < saveRect.Bottom; y++)
                        {
                            ColorBgra *ptr    = surface.GetPointAddressUnchecked(saveRect.Left, y);
                            ColorBgra *endPtr = ptr + saveRect.Width;
                            int        index  = ((y - saveRect.Top) * stride);

                            while (ptr < endPtr)
                            {
                                switch (bitDepth)
                                {
                                case 48:

                                    for (int ci = 0; ci < bitmapInfo.channelCount; ci++)
                                    {
                                        ChannelSubBlock ch = bitmapInfo.channels[ci];

                                        if (ch.bitmapType == PSPDIBType.Image)
                                        {
                                            ushort col     = (ushort)(ch.channelData[index] | (ch.channelData[index + 1] << 8)); // PSP format is always little endian
                                            byte   clamped = (byte)((col * 255) / 65535);

                                            switch (ch.channelType)
                                            {
                                            case PSPChannelType.Red:
                                                ptr->R = clamped;
                                                break;

                                            case PSPChannelType.Green:
                                                ptr->G = clamped;
                                                break;

                                            case PSPChannelType.Blue:
                                                ptr->B = clamped;
                                                break;
                                            }
                                        }
                                        else if (ch.bitmapType == PSPDIBType.TransparencyMask)
                                        {
                                            ptr->A = ch.channelData[alphaIndex];
                                            alphaIndex++;
                                        }
                                    }

                                    break;

                                case 24:

                                    for (int ci = 0; ci < bitmapInfo.channelCount; ci++)
                                    {
                                        ChannelSubBlock ch = bitmapInfo.channels[ci];

                                        if (ch.bitmapType == PSPDIBType.Image)
                                        {
                                            switch (ch.channelType)
                                            {
                                            case PSPChannelType.Red:
                                                ptr->R = ch.channelData[index];
                                                break;

                                            case PSPChannelType.Green:
                                                ptr->G = ch.channelData[index];
                                                break;

                                            case PSPChannelType.Blue:
                                                ptr->B = ch.channelData[index];
                                                break;
                                            }
                                        }
                                        else if (ch.bitmapType == PSPDIBType.TransparencyMask)
                                        {
                                            ptr->A = ch.channelData[index];
                                        }
                                    }

                                    break;

                                case 8:
                                    for (int ci = 0; ci < bitmapInfo.channelCount; ci++)
                                    {
                                        ChannelSubBlock ch = bitmapInfo.channels[ci];
                                        palIdx = ch.channelData[index];
                                        entry  = this.globalPalette.entries[palIdx];

                                        switch (ch.bitmapType)
                                        {
                                        case PSPDIBType.Image:
                                            ptr->R = entry.rgbRed;
                                            ptr->G = entry.rgbGreen;
                                            ptr->B = entry.rgbBlue;

                                            if (palIdx == transIndex)
                                            {
                                                ptr->A = 0;
                                            }

                                            break;

                                        case PSPDIBType.TransparencyMask:
                                            ptr->A = entry.rgbRed;
                                            break;
                                        }
                                    }

                                    break;

                                case 4:
                                case 1:

                                    palIdx = expandedPalette[index];
                                    entry  = this.globalPalette.entries[palIdx];

                                    ptr->R = entry.rgbRed;
                                    ptr->G = entry.rgbGreen;
                                    ptr->B = entry.rgbBlue;

                                    if (palIdx == transIndex)
                                    {
                                        ptr->A = 0;
                                    }
                                    else if ((bitmapInfo.bitmapCount == 2) && bitmapInfo.channels[1].bitmapType == PSPDIBType.TransparencyMask)
                                    {
                                        ptr->A = bitmapInfo.channels[1].channelData[index];
                                    }

                                    break;

                                default:
                                    throw new FormatException(string.Format(Properties.Resources.UnsupportedBitDepth, bitDepth));
                                }

                                ptr++;
                                index += bytesPerPixel;
                            }
                        }
                    }
                }

#if DEBUG
                using (Bitmap temp = layer.Surface.CreateAliasedBitmap())
                {
                }
#endif
                doc.Layers.Add(layer);
            }

            string creatorData = SerializeToBase64(this.creator);
            doc.Metadata.SetUserValue(PSPCreatorMetaData, creatorData);

            return(doc);
        }