public MaskInfo(PsdBinaryReader reader, Layer layer) { Util.DebugMessage(reader.BaseStream, "Load, Begin, MaskInfo"); var maskLength = reader.ReadUInt32(); if (maskLength <= 0) { return; } var startPosition = reader.BaseStream.Position; var endPosition = startPosition + maskLength; // Read layer mask var rectangle = reader.ReadRectangle(); var backgroundColor = reader.ReadByte(); var flagsByte = reader.ReadByte(); LayerMask = new Mask(layer, rectangle, backgroundColor, new BitVector32(flagsByte)); // User mask is supplied separately when there is also a vector mask. if (maskLength == 36) { var userFlagsByte = reader.ReadByte(); var userBackgroundColor = reader.ReadByte(); var userRectangle = reader.ReadRectangle(); UserMask = new Mask(layer, userRectangle, userBackgroundColor, new BitVector32(userFlagsByte)); } // 20-byte mask data will end with padding. reader.BaseStream.Position = endPosition; Util.DebugMessage(reader.BaseStream, "Load, End, MaskInfo"); }
/////////////////////////////////////////////////////////////////////////// /// <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"); }
public LayerUnicodeName(PsdBinaryReader reader) { Name = reader.ReadUnicodeString(); }
public PsdBinaryReader(Stream stream, PsdBinaryReader reader) : this(stream, reader._encoding) { }
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. Int32 numberOfChannels = reader.ReadUInt16(); for (Int32 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 Int64 adjustmentLayerEndPos = extraDataStartPosition + extraDataSize; while (reader.BaseStream.Position < adjustmentLayerEndPos) { var layerInfo = LayerInfoFactory.Load(reader, psdFile: 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); }
/// <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, Boolean globalLayerInfo) { 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( $"{nameof(LayerInfo)} signature invalid, must be 8BIM or 8B64."); } var key = reader.ReadAsciiChars(4); var hasLongLength = LayerInfoUtil.HasLongLength(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, (Int32)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, {0}, {1}", result.Signature, result.Key); return(result); }