Ejemplo n.º 1
0
            /// <summary>
            /// Reads an item of additional layer information within the additional layer information subsection of a
            /// PSD layer and mask information section from a stream and either returns a
            /// <see cref="PSDAdditionalLayerInformation"/> object containing the additional information, or (if this
            /// is an "out-of-band" layer information block) populates a <see cref="PSDFile"/> with the layer
            /// information within.
            /// </summary>
            /// <param name="psd">
            /// The PSD file object to populate if this is an "out-of-band" layer information block.
            /// </param>
            /// <param name="stream">The stream from which to read the layer information subsection.</param>
            /// <returns>
            /// The additional layer information, or <c>null</c> if the encountered block is an "out-of-band" layer
            /// information block.
            /// </returns>
            public static PSDAdditionalLayerInformation ReadAdditionalLayerInformation(PSDFile psd, Stream stream)
            {
                var ali = new PSDAdditionalLayerInformation();

                string signature = stream.ReadUsAsciiString(4);

                if (signature != AdditionalLayerInfoSignature && signature != AdditionalLayerInfoSignature2)
                {
                    throw new PSDFormatException($"unknown additional layer information signature \"{signature}\", expected \"{AdditionalLayerInfoSignature}\" or \"{AdditionalLayerInfoSignature2}\"");
                }

                string key         = stream.ReadUsAsciiString(4);
                bool   length64Bit = false;

                if (key == "Layr" || key == "Lr16" || key == "Lr32")
                {
                    // layer info has been shunted in here instead of where it belongs
                    ReadLayerInformation(psd, stream, roundToFourBytes: true);
                    return(null);
                }

                if (psd.Version == 2)
                {
                    // some keys have 64-bit lengths
                    length64Bit =
                        (key == "LMsk") ||
                        (key == "Mt16") ||
                        (key == "Mt32") ||
                        (key == "Mtrn") ||
                        (key == "Alph") ||
                        (key == "FMsk") ||
                        (key == "Ink2") ||
                        (key == "FEid") ||
                        (key == "FXid") ||
                        (key == "PxSD")
                    ;
                }

                long length = length64Bit
                    ? stream.ReadBigEndianInt64()
                    : stream.ReadBigEndianInt32();

                byte[] data = stream.ReadBytes((int)length);

                ali.Key  = key;
                ali.Data = data;

                // round up to 4 bytes
                // WARNING: spec is a liar; says "rounded up to an even byte count"
                if (length % 4 != 0)
                {
                    var skipCount = (int)(4 - (length % 4));
                    stream.ReadBytes(skipCount);
                }

                return(ali);
            }
Ejemplo n.º 2
0
            /// <summary>
            /// Reads a layer record from a stream and populates a PSD layer object with the information.
            /// </summary>
            /// <param name="psd">
            /// The PSD file being read. Used to obtain the file format version and to populate the
            /// <see cref="PSDFile.Layers"/> array if general layer information has been "outsourced" to an additional
            /// layer information block.
            /// </param>
            /// <param name="layer">The layer to populate with information read from the stream.</param>
            /// <param name="stream">The stream from which to read layer information.</param>
            public static void ReadLayerRecord(PSDFile psd, PSDLayer layer, Stream stream)
            {
                layer.Top    = stream.ReadBigEndianInt32();
                layer.Left   = stream.ReadBigEndianInt32();
                layer.Bottom = stream.ReadBigEndianInt32();
                layer.Right  = stream.ReadBigEndianInt32();

                short numberChannels = stream.ReadBigEndianInt16();

                layer.Channels = new PSDLayerChannel[numberChannels];
                for (int i = 0; i < numberChannels; ++i)
                {
                    var channel = new PSDLayerChannel();
                    channel.ID         = stream.ReadBigEndianInt16();
                    channel.DataLength = (psd.Version == 2)
                        ? stream.ReadBigEndianInt64()
                        : stream.ReadBigEndianInt32();
                    layer.Channels[i] = channel;
                }

                string blendModeSignature = stream.ReadUsAsciiString(4);

                if (blendModeSignature != BlendModeSignature)
                {
                    throw new PSDFormatException($"expected blend mode signature \"{BlendModeSignature}\", got \"{blendModeSignature}\"");
                }

                int blendModeValue = stream.ReadBigEndianInt32();

                if (!Enum.IsDefined(typeof(BlendMode), blendModeValue))
                {
                    char[] blendModeChars =
                    {
                        (char)((blendModeValue >> 24) & 0xFF),
                        (char)((blendModeValue >> 16) & 0xFF),
                        (char)((blendModeValue >> 8) & 0xFF),
                        (char)((blendModeValue >> 0) & 0xFF)
                    };
                    string blendModeString = new string(blendModeChars);
                    throw new PSDFormatException($"invalid blend mode {blendModeValue} (\"{blendModeString}\")");
                }
                layer.BlendMode = (BlendMode)blendModeValue;

                byte opacity = stream.ReadByteOrThrow();

                layer.Opacity = opacity;

                byte clipping = stream.ReadByteOrThrow();

                if (clipping > 1)
                {
                    throw new PSDFormatException($"invalid clipping value {clipping}; expected 0 (base) or 1 (non-base)");
                }
                layer.NonBaseClipping = (clipping == 1);

                byte flags = stream.ReadByteOrThrow();

                if ((flags & 0x01) != 0)
                {
                    layer.TransparencyProtected = true;
                }
                if ((flags & 0x02) != 0)
                {
                    layer.Visible = true;
                }
                if ((flags & 0x04) != 0)
                {
                    layer.Obsolete = true;
                }
                if ((flags & 0x18) == 0x18)
                {
                    // (both bits 3 and 4 must be set)
                    layer.PixelDataIrrelevantToDocumentAppearance = true;
                }

                // filler
                stream.ReadByteOrThrow();

                int  extraDataLength = stream.ReadBigEndianInt32();
                long extraDataStart  = stream.Position;

                ReadLayerMask(layer, stream);
                ReadLayerBlendingRanges(layer, stream);

                byte layerNameLength = stream.ReadByteOrThrow();

                layer.Name = stream.ReadWindows1252String(layerNameLength);
                int padTo4Bytes = 4 - ((layerNameLength + 1) % 4);

                if (padTo4Bytes != 4)  // there is zero padding if == 4
                {
                    stream.ReadBytes(padTo4Bytes);
                }

                layer.AdditionalInformation = new List <PSDAdditionalLayerInformation>();
                while (stream.Position < extraDataStart + extraDataLength)
                {
                    PSDAdditionalLayerInformation pali = PSDFile.Reading.ReadAdditionalLayerInformation(psd, stream);
                    layer.AdditionalInformation.Add(pali);
                }
            }