예제 #1
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);
        }