Example #1
0
        internal Channel(PsdBinaryReader reader, Layer layer)
        {
            Util.DebugMessage(reader.BaseStream, "Load, Begin, Channel");

            ID     = reader.ReadInt16();
            Length = (layer.PsdFile.IsLargeDocument)
        ? reader.ReadInt64()
        : reader.ReadInt32();
            Layer = layer;

            Util.DebugMessage(reader.BaseStream, $"Load, End, Channel, {ID}");
        }
Example #2
0
        ///////////////////////////////////////////////////////////////////////////

        private void LoadLayerAndMaskInfo(PsdBinaryReader reader)
        {
            Util.DebugMessage(reader.BaseStream, "Load, Begin, Layer and mask info");

            var layersAndMaskLength = IsLargeDocument
                ? reader.ReadInt64()
                : reader.ReadUInt32();

            if (layersAndMaskLength <= 0)
            {
                return;
            }

            var startPosition = reader.BaseStream.Position;
            var endPosition   = startPosition + layersAndMaskLength;

            LoadLayers(reader, true);
            LoadGlobalLayerMask(reader);

            //-----------------------------------------------------------------------
            // Load Additional Layer Information

            while (reader.BaseStream.Position < endPosition)
            {
                var info = LayerInfoFactory.Load(reader,
                                                 psdFile: this,
                                                 globalLayerInfo: true, endPosition);
                AdditionalInfo.Add(info);

                if (info is RawLayerInfo)
                {
                    var layerInfo = (RawLayerInfo)info;
                    switch (info.Key)
                    {
                    case "LMsk":
                        m_GlobalLayerMaskData = layerInfo.Data;
                        break;
                    }
                }
            }

            Util.DebugMessage(reader.BaseStream, "Load, End, Layer and mask info");

            //-----------------------------------------------------------------------
            // make sure we are not on a wrong offset, so set the stream position
            // manually
            reader.BaseStream.Position = startPosition + layersAndMaskLength;
        }
Example #3
0
 public LargeInteger(PsdBinaryReader reader)
 {
     Value = reader.ReadInt64();
 }
Example #4
0
        ///////////////////////////////////////////////////////////////////////////

        //private void SaveLayerAndMaskInfo(PsdBinaryWriter writer)
        //{
        //  Util.DebugMessage(writer.BaseStream, "Save, Begin, Layer and mask info");

        //  using (new PsdBlockLengthWriter(writer, IsLargeDocument))
        //  {
        //    var startPosition = writer.BaseStream.Position;

        //    SaveLayers(writer);
        //    SaveGlobalLayerMask(writer);

        //    foreach (var info in AdditionalInfo)
        //    {
        //      info.Save(writer,
        //        globalLayerInfo: true,
        //        isLargeDocument: IsLargeDocument);
        //    }

        //    writer.WritePadding(startPosition, 2);
        //  }

        //  Util.DebugMessage(writer.BaseStream, "Save, End, Layer and mask info");
        //}

        ///////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Load Layers Info section, including image data.
        /// </summary>
        /// <param name="reader">PSD reader.</param>
        /// <param name="hasHeader">Whether the Layers Info section has a length header.</param>
        internal void LoadLayers(PsdBinaryReader reader, bool hasHeader)
        {
            Util.DebugMessage(reader.BaseStream, "Load, Begin, Layers Info section");

            long sectionLength = 0;

            if (hasHeader)
            {
                sectionLength = IsLargeDocument
                    ? reader.ReadInt64()
                    : reader.ReadUInt32();

                if (sectionLength <= 0)
                {
                    // The callback may take action when there are 0 layers, so it must
                    // be called even though the Layers Info section is empty.
                    LoadContext.OnLoadLayersHeader(this);
                    Util.DebugMessage(reader.BaseStream, "Load, End, Layers Info section");
                    return;
                }
            }

            var startPosition = reader.BaseStream.Position;
            var numLayers     = reader.ReadInt16();

            // If numLayers < 0, then number of layers is absolute value,
            // and the first alpha channel contains the transparency data for
            // the merged result.
            if (numLayers < 0)
            {
                AbsoluteAlpha = true;
                numLayers     = Math.Abs(numLayers);
            }

            for (int i = 0; i < numLayers; i++)
            {
                var layer = new Layer(reader, this);
                Layers.Add(layer);
            }

            // Header is complete just before loading pixel data
            LoadContext.OnLoadLayersHeader(this);

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

            // Load image data for all channels.
            foreach (var layer in Layers)
            {
                Util.DebugMessage(reader.BaseStream,
                                  "Load, Begin, Layer image, layer.Name");
                foreach (var channel in layer.Channels)
                {
                    channel.LoadPixelData(reader);
                }
                Util.DebugMessage(reader.BaseStream,
                                  "Load, End, Layer image, layer.Name");
            }

            // Length is set to 0 when called on higher bitdepth layers.
            if (sectionLength > 0)
            {
                // Layers Info section is documented to be even-padded, but Photoshop
                // actually pads to 4 bytes.
                var endPosition    = startPosition + sectionLength;
                var positionOffset = reader.BaseStream.Position - endPosition;
                Debug.Assert(positionOffset > -4,
                             "LoadLayers did not read the full length of the Layers Info section.");
                Debug.Assert(positionOffset <= 0,
                             "LoadLayers read past the end of the Layers Info section.");


                if (reader.BaseStream.Position < endPosition)
                {
                    reader.BaseStream.Position = endPosition;
                }
            }

            Util.DebugMessage(reader.BaseStream, "Load, End, Layers");
        }
Example #5
0
        /// <summary>
        /// Loads the next LayerInfo record.
        /// </summary>
        /// <param name="reader">The file reader</param>
        /// <param name="psdFile">The PSD file.</param>
        /// <param name="globalLayerInfo">True if the LayerInfo record is being
        ///   loaded from the end of the Layer and Mask Information section;
        ///   false if it is being loaded from the end of a Layer record.</param>
        public static LayerInfo Load(PsdBinaryReader reader, PsdFile psdFile,
                                     bool globalLayerInfo, long fileEndPos)
        {
            Util.DebugMessage(reader.BaseStream, "Load, Begin, LayerInfo");

            // Some keys use a signature of 8B64, but the identity of these keys
            // is undocumented.  We will therefore accept either signature.
            var signature = reader.ReadAsciiChars(4);

            if ((signature != "8BIM") && (signature != "8B64"))
            {
                throw new PsdInvalidException(
                          "LayerInfo signature invalid, must be 8BIM or 8B64.");
            }

            var       key           = reader.ReadAsciiChars(4);
            var       hasLongLength = LayerInfoUtil.HasLongLength(key, psdFile.IsLargeDocument);
            LayerInfo result        = new RawLayerInfo("dummy");
            bool      breakFromLoop = false;

            while (!breakFromLoop)
            {
                var baseStartPosition = reader.BaseStream.Position;
                var length            = hasLongLength
                    ? reader.ReadInt64()
                    : reader.ReadInt32();
                var startPosition = reader.BaseStream.Position;


                switch (key)
                {
                case "Layr":
                case "Lr16":
                case "Lr32":
                    result = new InfoLayers(reader, psdFile, key, length);
                    break;

                case "lsct":
                case "lsdk":
                    result = new LayerSectionInfo(reader, key, (int)length);
                    break;

                case "luni":
                    result = new LayerUnicodeName(reader);
                    break;

                case "lyid":
                    result = new LayerId(reader, key, length);
                    break;

                default:
                    result = new RawLayerInfo(reader, signature, key, length);
                    break;
                }

                // May have additional padding applied.
                var endPosition = startPosition + length;
                if (reader.BaseStream.Position < endPosition)
                {
                    reader.BaseStream.Position = endPosition;
                }

                // Documentation states that the length is even-padded.  Actually:
                //   1. Most keys have 4-padded lengths.
                //   2. However, some keys (LMsk) have even-padded lengths.
                //   3. Other keys (Txt2, Lr16, Lr32) have unpadded lengths.
                //
                // Photoshop writes data that is always 4-padded, even when the stated
                // length is not a multiple of 4.  The length mismatch seems to occur
                // only on global layer info.  We do not read extra padding in other
                // cases because third-party programs are likely to follow the spec.

                if (globalLayerInfo)
                {
                    reader.ReadPadding(startPosition, 4);
                }

                //try if we can read the next signature
                if (reader.BaseStream.Position < fileEndPos)
                {
                    var nowPosition = reader.BaseStream.Position;
                    signature = reader.ReadAsciiChars(4);
                    if ((signature != "8BIM") && (signature != "8B64"))
                    {
                        hasLongLength = true;
                        reader.BaseStream.Position = baseStartPosition;
                    }
                    else
                    {
                        reader.BaseStream.Position = nowPosition;
                        breakFromLoop = true;
                    }
                }
                else
                {
                    breakFromLoop = true;
                }
            }


            Util.DebugMessage(reader.BaseStream, "Load, End, LayerInfo, {0}, {1}",
                              result.Signature, result.Key);
            return(result);
        }
Example #6
0
        /// <summary>
        /// Loads the next LayerInfo record.
        /// </summary>
        /// <param name="reader">The file reader</param>
        /// <param name="psdFile">The PSD file.</param>
        /// <param name="globalLayerInfo">True if the LayerInfo record is being
        ///   loaded from the end of the Layer and Mask Information section;
        ///   false if it is being loaded from the end of a Layer record.</param>
        /// <returns>LayerInfo object if it was successfully read, or null if
        ///   padding was found.</returns>
        private static LayerInfo Load(PsdBinaryReader reader, PsdFile psdFile,
                                      bool globalLayerInfo)
        {
            Util.DebugMessage(reader.BaseStream, "Load, Begin, LayerInfo");

            // Most keys have undocumented signatures, so we always accept either one.
            var signature = reader.ReadAsciiChars(4);

            if ((signature != "8BIM") && (signature != "8B64"))
            {
                throw new PsdInvalidException(
                          $"{nameof(LayerInfo)} signature invalid, must be 8BIM or 8B64.");
            }

            var key           = reader.ReadAsciiChars(4);
            var hasLongLength = LayerInfoUtil.HasLongLength(signature, key, psdFile.IsLargeDocument);
            var length        = hasLongLength
        ? reader.ReadInt64()
        : reader.ReadInt32();
            var startPosition = reader.BaseStream.Position;

            LayerInfo result;

            switch (key)
            {
            case "Layr":
            case "Lr16":
            case "Lr32":
                result = new InfoLayers(reader, psdFile, key, length);
                break;

            case "lsct":
            case "lsdk":
                result = new LayerSectionInfo(reader, key, (int)length);
                break;

            case "luni":
                result = new LayerUnicodeName(reader);
                break;

            default:
                result = new RawLayerInfo(reader, signature, key, length);
                break;
            }

            // May have additional padding applied.
            var endPosition = startPosition + length;

            if (reader.BaseStream.Position < endPosition)
            {
                reader.BaseStream.Position = endPosition;
            }

            // Documentation states that the length is even-padded.  Actually:
            //   1. Most keys have 4-padded lengths.
            //   2. However, some keys (LMsk) have even-padded lengths.
            //   3. Other keys (Txt2, Lr16, Lr32) have unpadded lengths.
            //
            // Photoshop writes data that is always 4-padded, even when the stated
            // length is not a multiple of 4.  The length mismatch seems to occur
            // only on global layer info.  We do not read extra padding in other
            // cases because third-party programs are likely to follow the spec.

            if (globalLayerInfo)
            {
                reader.ReadPadding(startPosition, 4);
            }

            Util.DebugMessage(reader.BaseStream,
                              $"Load, End, LayerInfo, {result.Signature}, {result.Key}");
            return(result);
        }
Example #7
0
        public static DynVal ReadValue(PsdBinaryReader r, bool skipKey)
        {
            DynVal vt = new DynVal();

            if (!skipKey)
            {
                vt.Name = GetMeaningOfFourCC(ReadSpecialString(r));
            }

            //TODO: should be assigned a sequential number?
            vt.Type = parseTypeString(r.ReadAsciiChars(4));
            switch (vt.Type)
            {
            case OSType.tdta:
                // unknown
                r.ReadUInt32();
                TdTaParser p = new TdTaParser(r);
                object     o = p.ParseOneTree();
                vt.Value = o;

                break;

            case OSType.Reference:
                vt.References = ReadValues(r, true);
                break;

            case OSType.Descriptor:
                vt.Value = DynVal.ReadDescriptor(r);
                break;

            case OSType.List:
                vt.Children = ReadValues(r, true);
                break;

            case OSType.Double:
                vt.Value = r.ReadDouble();
                break;

            case OSType.UnitFloat:                                    //Unif float
                string tst = GetMeaningOfFourCC(r.ReadAsciiChars(4)); //#Prc #Pxl #Ang = percent / pixels / angle?
                double d   = r.ReadDouble();
                tst     += ": " + d;
                vt.Value = tst;
                break;

            case OSType.Enumerated:
                string typeID  = ReadSpecialString(r);
                string enumVal = ReadSpecialString(r);
                vt.Value = GetMeaningOfFourCC(typeID) + "." + GetMeaningOfFourCC(enumVal);
                break;

            case OSType.Integer:
                vt.Value = r.ReadInt32();     //4 byte integer
                break;

            case OSType.Boolean:
                vt.Value = r.ReadBoolean();
                break;

            case OSType.String:
                vt.Value = r.ReadUnicodeString();    //r.ReadPSDUnicodeString();
                break;

            case OSType.LargeInteger:
                vt.Value = r.ReadInt64();
                break;

            case OSType.Class:
                vt.Value = ReadClass(r);
                break;

            case OSType.Alias:
                vt.Value = ReadAlias(r);
                break;

            case OSType.PropertyRef:
                vt.Value = ReadProperty(r);
                break;

            case OSType.EnumeratedRef:
                vt.Value = ReadEnumeratedRef(r);
                break;

            case OSType.OffestRef:
                vt.Value = ReadOffset(r);
                break;

            case OSType.IdentifierRef:
                vt.Value = r.ReadAsciiChars(4);
                break;

            case OSType.IndexRef:
                vt.Value = r.ReadUInt16();
                break;

            case OSType.NameRef:
                vt.Value = r.ReadAsciiChars(4);
                break;

            default:
                throw new Exception("Unhandled type: " + vt.Type);
            }
            return(vt);
        }