public static LayerInfo Load(PsdBinaryReader reader) { Debug.WriteLine("LayerInfoFactory.Load started at " + reader.BaseStream.Position); var signature = reader.ReadAsciiChars(4); if (signature != "8BIM") { throw new PsdInvalidException("Could not read LayerInfo due to signature mismatch."); } var key = reader.ReadAsciiChars(4); var length = reader.ReadInt32(); var startPosition = reader.BaseStream.Position; LayerInfo result; switch (key) { case "lsct": case "lsdk": result = new LayerSectionInfo(reader, key, length); break; case "luni": result = new LayerUnicodeName(reader); break; case "TySh": result = new LayerText(reader, length); break; case "tySH": result = new LayerTextType(reader); break; default: result = new RawLayerInfo(reader, 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. // // The data is always 4-padded, regardless of the stated length. reader.ReadPadding(startPosition, 4); return(result); }
public EnumeratedDescriptor(PsdBinaryReader reader) { int length = reader.ReadInt32(); Type = reader.ReadAsciiChars(length == 0 ? 4 : length); length = reader.ReadInt32(); Enum = reader.ReadAsciiChars(length == 0 ? 4 : length); }
public PropertyStructure(PsdBinaryReader reader) { NameFromClassID = reader.ReadUnicodeString(); int length = reader.ReadInt32(); ClassID = reader.ReadAsciiChars(length == 0 ? 4 : length); length = reader.ReadInt32(); KeyID = reader.ReadAsciiChars(length == 0 ? 4 : length); }
public EnumeratedReference(PsdBinaryReader reader) { NameFromClassID = reader.ReadUnicodeString(); var length = reader.ReadInt32(); ClassID = reader.ReadAsciiChars(length == 0 ? 4 : length); length = reader.ReadInt32(); TypeID = reader.ReadAsciiChars(length == 0 ? 4 : length); length = reader.ReadInt32(); Enum = reader.ReadAsciiChars(length == 0 ? 4 : length); }
public static ImageResource CreateImageResource(PsdBinaryReader reader) { Debug.Print("ImageResource started at {0}", reader.BaseStream.Position); var signature = reader.ReadAsciiChars(4); var resourceIdInt = reader.ReadUInt16(); var name = reader.ReadPascalString(2); var dataLength = (int)reader.ReadUInt32(); var dataPaddedLength = Util.RoundUp(dataLength, 2); var endPosition = reader.BaseStream.Position + dataPaddedLength; ImageResource resource = null; var resourceId = (ResourceID)resourceIdInt; switch (resourceId) { case ResourceID.ResolutionInfo: resource = new ResolutionInfo(reader, name); break; case ResourceID.ThumbnailRgb: case ResourceID.ThumbnailBgr: resource = new Thumbnail(reader, resourceId, name, dataLength); break; case ResourceID.AlphaChannelNames: resource = new AlphaChannelNames(reader, name, dataLength); break; case ResourceID.UnicodeAlphaNames: resource = new UnicodeAlphaNames(reader, name, dataLength); break; case ResourceID.VersionInfo: resource = new VersionInfo(reader, name); break; default: resource = new RawImageResource(reader, signature, resourceId, name, dataLength); break; } // Reposition the reader if we do not consume the full resource block. // This takes care of the even-padding, and also preserves forward- // compatibility in case a resource block is later extended with // additional properties. if (reader.BaseStream.Position < endPosition) { reader.BaseStream.Position = endPosition; } // However, overruns are definitely an error. if (reader.BaseStream.Position > endPosition) { throw new PsdInvalidException("Corruption detected in resource."); } return(resource); }
/////////////////////////////////////////////////////////////////////////// private void LoadHeader(PsdBinaryReader reader) { Util.DebugMessage(reader.BaseStream, "Load, Begin, File header"); var signature = reader.ReadAsciiChars(4); if (signature != "8BPS") { throw new PsdInvalidException("The given stream is not a valid PSD file"); } Version = (PsdFileVersion)reader.ReadInt16(); Util.DebugMessage(reader.BaseStream, "Load, Info, Version {0}", (int)Version); if ((Version != PsdFileVersion.Psd) && (Version != PsdFileVersion.PsbLargeDocument)) { throw new PsdInvalidException("The PSD file has an unknown version"); } //6 bytes reserved reader.BaseStream.Position += 6; this.ChannelCount = reader.ReadInt16(); this.RowCount = reader.ReadInt32(); this.ColumnCount = reader.ReadInt32(); BitDepth = reader.ReadInt16(); ColorMode = (PsdColorMode)reader.ReadInt16(); Util.DebugMessage(reader.BaseStream, "Load, End, File header"); }
/////////////////////////////////////////////////////////////////////////// private void LoadHeader(PsdBinaryReader reader) { Debug.WriteLine("LoadHeader started at " + reader.BaseStream.Position.ToString(CultureInfo.InvariantCulture)); var signature = reader.ReadAsciiChars(4); if (signature != "8BPS") { throw new PsdInvalidException("The given stream is not a valid PSD file"); } Version = reader.ReadInt16(); if (Version != 1) { throw new PsdInvalidException("The PSD file has an unknown version"); } //6 bytes reserved reader.BaseStream.Position += 6; this.ChannelCount = reader.ReadInt16(); this.RowCount = reader.ReadInt32(); this.ColumnCount = reader.ReadInt32(); BitDepth = reader.ReadInt16(); ColorMode = (PsdColorMode)reader.ReadInt16(); }
public Metadata(PsdBinaryReader reader) { string signature = reader.ReadAsciiChars(4); if (signature != "8BIM") { throw new PsdInvalidException("Could not read LayerInfo due to signature mismatch." + signature); } Key = reader.ReadAsciiChars(4); bool sheetCopy = reader.ReadBoolean(); byte[] padding = reader.ReadBytes(3); uint length = reader.ReadUInt32(); byte[] datas = reader.ReadBytes((int)length); }
public ClassStructure(PsdBinaryReader reader, string key) { _key = key; NameFromClassID = reader.ReadUnicodeString(); int length = reader.ReadInt32(); ClassID = reader.ReadAsciiChars(length == 0 ? 4 : length); }
/// <summary> /// A peculiar type of ascii string frequently used throughout the Descriptor data structure. /// First 4 bytes are length (in bytes), followed by string. If length is 0, length is assumed to be 4. No idea why they did this... RLE compression? /// </summary> /// <param name="r"></param> /// <returns></returns> public static string ReadSpecialString(PsdBinaryReader r) { uint length = r.ReadUInt32(); if (length == 0) { length = 4; } return(r.ReadAsciiChars((int)length)); }
public OffsetStructure(PsdBinaryReader reader) { NameFromClassID = reader.ReadUnicodeString(); var length = reader.ReadInt32(); ClassID = reader.ReadAsciiChars(length == 0 ? 4 : length); Offset = reader.ReadInt32(); }
public static LayerInfo Load(PsdBinaryReader reader) { Debug.WriteLine("LayerInfoFactory.Load started at " + reader.BaseStream.Position); var signature = reader.ReadAsciiChars(4); if (signature != "8BIM") throw new PsdInvalidException("Could not read LayerInfo due to signature mismatch."); var key = reader.ReadAsciiChars(4); var length = reader.ReadInt32(); var startPosition = reader.BaseStream.Position; LayerInfo result; switch (key) { case "lsct": case "lsdk": result = new LayerSectionInfo(reader, key, length); break; case "luni": result = new LayerUnicodeName(reader); break; default: result = new RawLayerInfo(reader, 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. // // The data is always 4-padded, regardless of the stated length. reader.ReadPadding(startPosition, 4); return result; }
public DescriptorStructure(PsdBinaryReader reader, string key = null) { _key = key; ClassIDName = reader.ReadUnicodeString(); var length = reader.ReadInt32(); ClassID = reader.ReadAsciiChars(length == 0 ? 4 : length); var itemCount = reader.ReadInt32(); Descriptor = new Dictionary <string, Descriptor> (); for (int i = 0; i < itemCount; i++) { length = reader.ReadInt32(); string itemName = reader.ReadAsciiChars(length == 0 ? 4 : length); Descriptor.Add(itemName, DescriptorFactory.Load(reader)); } }
public LayerSectionInfo(PsdBinaryReader reader, string key, int dataLength) { // The key for layer section info is documented to be "lsct". However, // some Photoshop files use the undocumented key "lsdk", with apparently // the same data format. this.key = key; SectionType = (LayerSectionType)reader.ReadInt32(); if (dataLength >= 12) { var signature = reader.ReadAsciiChars(4); if (signature != "8BIM") throw new PsdInvalidException("Invalid section divider signature."); BlendModeKey = reader.ReadAsciiChars(4); if (dataLength >= 16) { Subtype = (LayerSectionSubtype)reader.ReadInt32(); } } }
public LayerSectionInfo(PsdBinaryReader reader, string key, int dataLength) { // The key for layer section info is documented to be "lsct". However, // some Photoshop files use the undocumented key "lsdk", with apparently // the same data format. this.key = key; SectionType = (LayerSectionType)reader.ReadInt32(); if (dataLength >= 12) { var signature = reader.ReadAsciiChars(4); if (signature != "8BIM") { throw new PsdInvalidException("Invalid section divider signature."); } BlendModeKey = reader.ReadAsciiChars(4); if (dataLength >= 16) { Subtype = (LayerSectionSubtype)reader.ReadInt32(); } } }
public ReferenceStructure(PsdBinaryReader reader) { int itemCount = reader.ReadInt32(); References = new Descriptor[itemCount]; for (int i = 0; i < itemCount; ++i) { var key = reader.ReadAsciiChars(4); Descriptor item = null; switch (key) { case Property: item = new PropertyStructure(reader); break; case Class: item = new ClassStructure(reader, key); break; case EnumeratedReferebce: item = new EnumeratedReference(reader); break; case Offset: item = new OffsetStructure(reader); break; case Identifier: item = new Integer(reader, key); break; case Index: item = new Integer(reader, key); break; case Name: item = new StringStructure(reader, key); break; } References [i] = item; } }
public Layer(PsdBinaryReader reader, PsdFile psdFile) : this(psdFile) { Util.DebugMessage(reader.BaseStream, "Load, Begin, Layer"); Rect = reader.ReadRectangle(); //----------------------------------------------------------------------- // Read channel headers. Image data comes later, after the layer header. int numberOfChannels = reader.ReadUInt16(); for (int channel = 0; channel < numberOfChannels; channel++) { var ch = new Channel(reader, this); Channels.Add(ch); } //----------------------------------------------------------------------- // var signature = reader.ReadAsciiChars(4); if (signature != "8BIM") { throw (new PsdInvalidException("Invalid signature in layer header.")); } BlendModeKey = reader.ReadAsciiChars(4); Opacity = reader.ReadByte(); Clipping = reader.ReadBoolean(); var flagsByte = reader.ReadByte(); flags = new BitVector32(flagsByte); reader.ReadByte(); //padding //----------------------------------------------------------------------- // This is the total size of the MaskData, the BlendingRangesData, the // Name and the AdjustmentLayerInfo. var extraDataSize = reader.ReadUInt32(); var extraDataStartPosition = reader.BaseStream.Position; Masks = new MaskInfo(reader, this); BlendingRangesData = new BlendingRanges(reader, this); Name = reader.ReadPascalString(4); //----------------------------------------------------------------------- // Process Additional Layer Information long adjustmentLayerEndPos = extraDataStartPosition + extraDataSize; while (reader.BaseStream.Position < adjustmentLayerEndPos) { var layerInfo = LayerInfoFactory.Load(reader, psdFile: this.PsdFile, globalLayerInfo: false); AdditionalInfo.Add(layerInfo); } foreach (var adjustmentInfo in AdditionalInfo) { switch (adjustmentInfo.Key) { case "luni": Name = ((LayerUnicodeName)adjustmentInfo).Name; break; } } Util.DebugMessage(reader.BaseStream, "Load, End, Layer, {0}", Name); PsdFile.LoadContext.OnLoadLayerHeader(this); }
public Layer(PsdBinaryReader reader, PsdFile psdFile) : this(psdFile) { IsText = false; Rect = reader.ReadRectangle(); //----------------------------------------------------------------------- // Read channel headers. Image data comes later, after the layer header. int numberOfChannels = reader.ReadUInt16(); for (int channel = 0; channel < numberOfChannels; channel++) { var ch = new Channel(reader, this); Channels.Add(ch); } //----------------------------------------------------------------------- // var signature = reader.ReadAsciiChars(4); if (signature != "8BIM") { throw (new PsdInvalidException("Invalid signature in layer header.")); } BlendModeKey = reader.ReadAsciiChars(4); Opacity = reader.ReadByte(); Clipping = reader.ReadBoolean(); var flagsByte = reader.ReadByte(); flags = new BitVector32(flagsByte); reader.ReadByte(); //padding //----------------------------------------------------------------------- // This is the total size of the MaskData, the BlendingRangesData, the // Name and the AdjustmentLayerInfo. var extraDataSize = reader.ReadUInt32(); var extraDataStartPosition = reader.BaseStream.Position; Masks = new MaskInfo(reader, this); BlendingRangesData = new BlendingRanges(reader, this); Name = reader.ReadPascalString(4); //----------------------------------------------------------------------- // Process Additional Layer Information long adjustmentLayerEndPos = extraDataStartPosition + extraDataSize; while (reader.BaseStream.Position < adjustmentLayerEndPos) { var layerInfo = LayerInfoFactory.Load(reader); AdditionalInfo.Add(layerInfo); } foreach (var adjustmentInfo in AdditionalInfo) { switch (adjustmentInfo.Key) { case "luni": Name = ((LayerUnicodeName)adjustmentInfo).Name; break; case "TySh": IsText = true; LayerText = (LayerText)adjustmentInfo; break; case "lrFX": Effects = (EffectsLayer)adjustmentInfo; break; case "lfx2": BaseEffect = (ObjectBasedEffect)adjustmentInfo; break; } } }
public Layer(PsdBinaryReader reader, PsdFile psdFile) : this(psdFile) { Rect = reader.ReadRectangle(); //----------------------------------------------------------------------- // Read channel headers. Image data comes later, after the layer header. int numberOfChannels = reader.ReadUInt16(); for (int channel = 0; channel < numberOfChannels; channel++) { var ch = new Channel(reader, this); Channels.Add(ch); } //----------------------------------------------------------------------- // var signature = reader.ReadAsciiChars(4); if (signature != "8BIM") throw (new PsdInvalidException("Invalid signature in layer header.")); BlendModeKey = reader.ReadAsciiChars(4); Opacity = reader.ReadByte(); Clipping = reader.ReadBoolean(); var flagsByte = reader.ReadByte(); flags = new BitVector32(flagsByte); reader.ReadByte(); //padding //----------------------------------------------------------------------- // This is the total size of the MaskData, the BlendingRangesData, the // Name and the AdjustmentLayerInfo. var extraDataSize = reader.ReadUInt32(); var extraDataStartPosition = reader.BaseStream.Position; Masks = new MaskInfo(reader, this); BlendingRangesData = new BlendingRanges(reader, this); Name = reader.ReadPascalString(4); //----------------------------------------------------------------------- // Process Additional Layer Information long adjustmentLayerEndPos = extraDataStartPosition + extraDataSize; while (reader.BaseStream.Position < adjustmentLayerEndPos) { var layerInfo = LayerInfoFactory.Load(reader); AdditionalInfo.Add(layerInfo); } foreach (var adjustmentInfo in AdditionalInfo) { switch (adjustmentInfo.Key) { case "luni": Name = ((LayerUnicodeName)adjustmentInfo).Name; break; } } }
/// <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); }
/////////////////////////////////////////////////////////////////////////// private void LoadHeader(PsdBinaryReader reader) { var signature = reader.ReadAsciiChars(4); if (signature != "8BPS") throw new PsdInvalidException("The given stream is not a valid PSD file"); Version = reader.ReadInt16(); if (Version != 1) throw new PsdInvalidException("The PSD file has an unknown version"); //6 bytes reserved reader.BaseStream.Position += 6; this.ChannelCount = reader.ReadInt16(); this.RowCount = reader.ReadInt32(); this.ColumnCount = reader.ReadInt32(); BitDepth = reader.ReadInt16(); ColorMode = (PsdColorMode)reader.ReadInt16(); }
public UnitFloatStructure(PsdBinaryReader reader) { Unit = reader.ReadAsciiChars(4); Value = reader.ReadDouble(); }
public static Descriptor Load(PsdBinaryReader reader) { string key = reader.ReadAsciiChars(4); return(Load(key, reader)); }
/// <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); }
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); }
public AliasStructure(PsdBinaryReader reader) { var length = reader.ReadInt32(); Path = reader.ReadAsciiChars(length); }