public RleRowLengths(PsdBinaryReader reader, int rowCount) : this(rowCount) { for (int i = 0; i < rowCount; i++) { Values[i] = reader.ReadUInt16(); } }
public RawImageResource(PsdBinaryReader reader, string signature, ResourceID resourceId, string name, int numBytes) : base(name) { this.Signature = signature; this.id = resourceId; Data = reader.ReadBytes(numBytes); }
public VersionInfo(PsdBinaryReader reader, string name) : base(name) { Version = reader.ReadUInt32(); HasRealMergedData = reader.ReadBoolean(); ReaderName = reader.ReadUnicodeString(); WriterName = reader.ReadUnicodeString(); FileVersion = reader.ReadUInt32(); }
/////////////////////////////////////////////////////////////////////////// private void Load(Stream stream, Encoding encoding) { var reader = new PsdBinaryReader(stream, encoding); LoadHeader(reader); LoadColorModeData(reader); LoadImageResources(reader); LoadLayerAndMaskInfo(reader); LoadImage(reader); DecompressImages(); }
public UnicodeAlphaNames(PsdBinaryReader reader, string name, int resourceDataLength) : base(name) { var endPosition = reader.BaseStream.Position + resourceDataLength; while (reader.BaseStream.Position < endPosition) { var channelName = reader.ReadUnicodeString(); ChannelNames.Add(channelName); } }
/////////////////////////////////////////////////////////////////////////// public BlendingRanges(PsdBinaryReader reader, Layer layer) { Debug.WriteLine("BlendingRanges started at " + reader.BaseStream.Position.ToString(CultureInfo.InvariantCulture)); Layer = layer; var dataLength = reader.ReadInt32(); if (dataLength <= 0) return; Data = reader.ReadBytes(dataLength); }
public ResolutionInfo(PsdBinaryReader reader, string name) : base(name) { this.HDpi = new UFixed16_16(reader.ReadUInt32()); this.HResDisplayUnit = (ResUnit)reader.ReadInt16(); this.WidthDisplayUnit = (Unit)reader.ReadInt16(); this.VDpi = new UFixed16_16(reader.ReadUInt32()); this.VResDisplayUnit = (ResUnit)reader.ReadInt16(); this.HeightDisplayUnit = (Unit)reader.ReadInt16(); }
public AlphaChannelNames(PsdBinaryReader reader, string name, int resourceDataLength) : base(name) { var endPosition = reader.BaseStream.Position + resourceDataLength; // Alpha channel names are Pascal strings, with no padding in-between. while (reader.BaseStream.Position < endPosition) { var channelName = reader.ReadPascalString(1); ChannelNames.Add(channelName); } }
public Thumbnail(PsdBinaryReader psdReader, ResourceID id, string name, int numBytes) : base(psdReader, "8BIM", id, name, numBytes) { using (var memoryStream = new MemoryStream(Data)) using (var reader = new PsdBinaryReader(memoryStream, psdReader)) { const int HEADER_LENGTH = 28; var format = reader.ReadUInt32(); var width = reader.ReadUInt32(); var height = reader.ReadUInt32(); var widthBytes = reader.ReadUInt32(); var size = reader.ReadUInt32(); var compressedSize = reader.ReadUInt32(); var bitPerPixel = reader.ReadUInt16(); var planes = reader.ReadUInt16(); // Raw RGB bitmap if (format == 0) { Image = new Bitmap((int)width, (int)height, PixelFormat.Format24bppRgb); } // JPEG bitmap else if (format == 1) { byte[] imgData = reader.ReadBytes(numBytes - HEADER_LENGTH); using (MemoryStream stream = new MemoryStream(imgData)) { var bitmap = new Bitmap(stream); Image = (Bitmap)bitmap.Clone(); } // Reverse BGR pixels from old thumbnail format if (id == ResourceID.ThumbnailBgr) { //for(int y=0;y<m_thumbnailImage.Height;y++) // for (int x = 0; x < m_thumbnailImage.Width; x++) // { // Color c=m_thumbnailImage.GetPixel(x,y); // Color c2=Color.FromArgb(c.B, c.G, c.R); // m_thumbnailImage.SetPixel(x, y, c); // } } } else { throw new PsdInvalidException("Unknown thumbnail format."); } } }
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 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(); } } }
private void Load(Stream stream, LoadContext loadContext, ELoadFlag loadFlag) { LoadContext = loadContext; var reader = new PsdBinaryReader(stream, loadContext.Encoding); if ((loadFlag & ELoadFlag.Header) == ELoadFlag.Header) { LoadHeader(reader); } if ((loadFlag & ELoadFlag.ColorMode) == ELoadFlag.ColorMode) { LoadColorModeData(reader); } if ((loadFlag & ELoadFlag.ImageData) == ELoadFlag.ImageData) { LoadImageResources(reader); LoadLayerAndMaskInfo(reader); LoadImage(reader); DecompressImages(); } }
/// <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(); }
/// <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); }
private void LoadColorModeData(PsdBinaryReader reader) { Debug.WriteLine("LoadColorModeData started at " + reader.BaseStream.Position.ToString(CultureInfo.InvariantCulture)); var paletteLength = reader.ReadUInt32(); if (paletteLength > 0) { ColorModeData = reader.ReadBytes((int)paletteLength); } }
public DoubleStructure(PsdBinaryReader reader) { Value = reader.ReadDouble(); }
public RawLayerInfo(PsdBinaryReader reader, string key, int dataLength) { this.key = key; Data = reader.ReadBytes((int)dataLength); }
public PsdBinaryReader(Stream stream, PsdBinaryReader reader) : this(stream, reader.encoding) { }
/////////////////////////////////////////////////////////////////////////// private void LoadImageResources(PsdBinaryReader reader) { var imageResourcesLength = reader.ReadUInt32(); if (imageResourcesLength <= 0) return; var startPosition = reader.BaseStream.Position; var endPosition = startPosition + imageResourcesLength; while (reader.BaseStream.Position < endPosition) { var imageResource = ImageResourceFactory.CreateImageResource(reader); ImageResources.Add(imageResource); } //----------------------------------------------------------------------- // make sure we are not on a wrong offset, so set the stream position // manually reader.BaseStream.Position = startPosition + imageResourcesLength; }
/////////////////////////////////////////////////////////////////////////// #endregion /////////////////////////////////////////////////////////////////////////// #region ImageData /////////////////////////////////////////////////////////////////////////// private void LoadImage(PsdBinaryReader reader) { ImageCompression = (ImageCompression)reader.ReadInt16(); // Create channels for (Int16 i = 0; i < ChannelCount; i++) { var channel = new Channel(i, this.BaseLayer); channel.ImageCompression = ImageCompression; channel.Length = this.RowCount * Util.BytesPerRow(BaseLayer.Rect, BitDepth); // The composite image stores all RLE headers up-front, rather than // with each channel. if (ImageCompression == ImageCompression.Rle) { channel.RleRowLengths = new RleRowLengths(reader, RowCount); channel.Length = channel.RleRowLengths.Total; } BaseLayer.Channels.Add(channel); } foreach (var channel in this.BaseLayer.Channels) { channel.ImageDataRaw = reader.ReadBytes(channel.Length); } // If there is exactly one more channel than we need, then it is the // alpha channel. if ((ColorMode != PsdColorMode.Multichannel) && (ChannelCount == ColorMode.MinChannelCount() + 1)) { var alphaChannel = BaseLayer.Channels.Last(); alphaChannel.ID = -1; } }
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; } } }
private void LoadGlobalLayerMask(PsdBinaryReader reader) { var maskLength = reader.ReadUInt32(); if (maskLength <= 0) return; GlobalLayerMaskData = reader.ReadBytes((int)maskLength); }
/////////////////////////////////////////////////////////////////////////// /// <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> private void LoadLayers(PsdBinaryReader reader, bool hasHeader) { UInt32 sectionLength = 0; if (hasHeader) { sectionLength = reader.ReadUInt32(); if (sectionLength <= 0) 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); } if (numLayers == 0) return; for (int i = 0; i < numLayers; i++) { var layer = new Layer(reader, this); Layers.Add(layer); } //----------------------------------------------------------------------- // Load image data for all channels. foreach (var layer in Layers) { foreach (var channel in layer.Channels) { channel.LoadPixelData(reader); } } // 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; if (reader.BaseStream.Position < endPosition) reader.BaseStream.Position = endPosition; } }
/////////////////////////////////////////////////////////////////////////// private void LoadLayerAndMaskInfo(PsdBinaryReader reader) { var layersAndMaskLength = 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); AdditionalInfo.Add(info); if (info is RawLayerInfo) { var layerInfo = (RawLayerInfo)info; switch (info.Key) { case "Layr": case "Lr16": case "Lr32": using (var memoryStream = new MemoryStream(layerInfo.Data)) using (var memoryReader = new PsdBinaryReader(memoryStream, reader)) { LoadLayers(memoryReader, false); } break; case "LMsk": GlobalLayerMaskData = layerInfo.Data; break; } } } //----------------------------------------------------------------------- // make sure we are not on a wrong offset, so set the stream position // manually reader.BaseStream.Position = startPosition + layersAndMaskLength; }
public RowData(PsdBinaryReader reader) { int length = reader.ReadInt32(); Data = reader.ReadBytes(length); }
public Integer(PsdBinaryReader reader, string key) { _key = key; Value = reader.ReadInt32(); }
internal Channel(PsdBinaryReader reader, Layer layer) { ID = reader.ReadInt16(); Length = reader.ReadInt32(); Layer = layer; }
private void LoadColorModeData(PsdBinaryReader reader) { var paletteLength = reader.ReadUInt32(); if (paletteLength > 0) { ColorModeData = reader.ReadBytes((int)paletteLength); } }
public LayerUnicodeName(PsdBinaryReader reader) { Name = reader.ReadUnicodeString(); }
public LayerTextType(PsdBinaryReader reader) { version = reader.ReadUInt16(); // 1 = Photoshop 5.0 transform = new Matrix2D(reader); //Font info: // fontVersion reader.ReadUInt16(); // 6 = Photoshop 5.0 ushort faceCount = reader.ReadUInt16(); fontInfos = new List <FontInfo>(); for (int i = 0; i < faceCount; i++) { fontInfos.Add(new FontInfo(reader)); } //TODO: make classes of styles as well... ushort styleCount = reader.ReadUInt16(); for (int i = 0; i < styleCount; i++) { // mark reader.ReadUInt16(); // faceMark reader.ReadUInt16(); // size reader.ReadUInt32(); // tracking reader.ReadUInt32(); // kerning reader.ReadUInt32(); // leading reader.ReadUInt32(); // baseShift reader.ReadUInt32(); // autoKern reader.ReadByte(); if (version <= 5) { // extra reader.ReadByte(); } // rotate reader.ReadByte(); } //Text information // type reader.ReadUInt16(); // scalingFactor reader.ReadUInt32(); // characterCount reader.ReadUInt32(); // horizontalPlacement reader.ReadUInt32(); // verticalPlacement reader.ReadUInt32(); // selectStart reader.ReadUInt32(); // selectEnd reader.ReadUInt32(); ushort lineCount = reader.ReadUInt16(); for (int i = 0; i < lineCount; i++) { // characterCountLine reader.ReadUInt32(); // orientation reader.ReadUInt16(); // alignment reader.ReadUInt16(); // doubleByteChar reader.ReadUInt16(); // style reader.ReadUInt16(); } // colorSpace reader.ReadUInt16(); for (int i = 0; i < 4; i++) { reader.ReadUInt16(); //Color compensation } // antiAlias reader.ReadByte(); }
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); }
/////////////////////////////////////////////////////////////////////////// private void LoadImageResources(PsdBinaryReader reader) { Debug.WriteLine("LoadImageResources started at " + reader.BaseStream.Position.ToString(CultureInfo.InvariantCulture)); ImageResources.Clear(); var imageResourcesLength = reader.ReadUInt32(); if (imageResourcesLength <= 0) return; var startPosition = reader.BaseStream.Position; var endPosition = startPosition + imageResourcesLength; while (reader.BaseStream.Position < endPosition) { var imageResource = ImageResourceFactory.CreateImageResource(reader); ImageResources.Add(imageResource); } //----------------------------------------------------------------------- // make sure we are not on a wrong offset, so set the stream position // manually reader.BaseStream.Position = startPosition + imageResourcesLength; }
public AliasStructure(PsdBinaryReader reader) { var length = reader.ReadInt32(); Path = reader.ReadAsciiChars(length); }
/////////////////////////////////////////////////////////////////////////// private void LoadImage(PsdBinaryReader reader) { Debug.WriteLine("LoadImage started at " + reader.BaseStream.Position.ToString(CultureInfo.InvariantCulture)); BaseLayer.Rect = new Rectangle(0, 0, ColumnCount, RowCount); ImageCompression = (ImageCompression)reader.ReadInt16(); switch (ImageCompression) { case ImageCompression.Raw: var length = this.RowCount * Util.BytesPerRow(BaseLayer.Rect, BitDepth); for (Int16 i = 0; i < ChannelCount; i++) { var channel = new Channel(i, this.BaseLayer); channel.ImageCompression = ImageCompression; channel.Length = length; channel.ImageData = reader.ReadBytes(length); BaseLayer.Channels.Add(channel); } break; case ImageCompression.Rle: // Store RLE data length for (Int16 i = 0; i < ChannelCount; i++) { var channel = new Channel(i, this.BaseLayer); channel.RleHeader = reader.ReadBytes(2 * RowCount); int totalRleLength = 0; using (var memoryStream = new MemoryStream(channel.RleHeader)) using (var memoryReader = new PsdBinaryReader(memoryStream, Encoding.ASCII)) { for (int j = 0; j < RowCount; j++) totalRleLength += memoryReader.ReadUInt16(); } channel.ImageCompression = this.ImageCompression; channel.Length = (int)totalRleLength; this.BaseLayer.Channels.Add(channel); } foreach (var channel in this.BaseLayer.Channels) { channel.Data = reader.ReadBytes(channel.Length); } break; } // If there is one more channel than we need, then it is the alpha channel if (ChannelCount == ColorMode.ChannelCount() + 1) { var alphaChannel = BaseLayer.Channels.Last(); alphaChannel.ID = -1; } }
public BooleanStructure(PsdBinaryReader reader) { Value = reader.ReadBoolean(); }
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(System.Text.Encoding.ASCII.GetString(r.ReadBytes(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.Descriptor: vt = 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 //TODO: need a specific type for this, with a double and a type (percent/pixel)? string tst = GetMeaningOfFourCC(System.Text.Encoding.ASCII.GetString(r.ReadBytes(4))); //#Prc #Pxl #Ang = percent / pixels / angle? double d = r.ReadDouble(); tst += ": " + d; vt.Value = tst; break; case OSType.Enumerated: string namesp = ReadSpecialString(r); string item = ReadSpecialString(r); //vt.Value = namesp + "." + item; //TODO: cast to real enum vt.Value = GetMeaningOfFourCC(namesp) + "." + GetMeaningOfFourCC(item); 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; default: throw new Exception("Unhandled type: " + vt.Type); } return(vt); }
private void LoadGlobalLayerMask(PsdBinaryReader reader) { Debug.WriteLine("LoadGlobalLayerMask started at " + reader.BaseStream.Position.ToString(CultureInfo.InvariantCulture)); var maskLength = reader.ReadUInt32(); if (maskLength <= 0) return; GlobalLayerMaskData = reader.ReadBytes((int)maskLength); }
/////////////////////////////////////////////////////////////////////////// //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"); }
public UnitFloatStructure(PsdBinaryReader reader) { Unit = reader.ReadAsciiChars(4); Value = reader.ReadDouble(); }
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 LayerText(PsdBinaryReader psdReader, int dataLength) { Data = psdReader.ReadBytes((int)dataLength); var reader = new PsdBinaryReader(new System.IO.MemoryStream(Data), psdReader); // PhotoShop version reader.ReadUInt16(); Transform = new Matrix2D(reader); // TextVersion reader.ReadUInt16(); //2 bytes, =50. For Photoshop 6.0. // DescriptorVersion reader.ReadUInt32(); //4 bytes,=16. For Photoshop 6.0. TxtDescriptor = DynVal.ReadDescriptor(reader); //Text descriptor // WarpVersion reader.ReadUInt16(); //2 bytes, =1. For Photoshop 6.0. engineData = (Dictionary <string, object>)TxtDescriptor.Children.Find(c => c.Name == "EngineData").Value; StylesheetReader = new TdTaStylesheetReader(engineData); Dictionary <string, object> d = StylesheetReader.GetStylesheetDataFromLongestRun(); Text = StylesheetReader.Text; FontName = TdTaParser.getString(StylesheetReader.getFontSet()[(int)TdTaParser.query(d, "Font")], "Name$"); FontSize = (double)TdTaParser.query(d, "FontSize"); try { FauxBold = TdTaParser.getBool(d, "FauxBold"); } catch (KeyNotFoundException) { FauxBold = false; } try { FauxItalic = TdTaParser.getBool(d, "FauxItalic"); } catch (KeyNotFoundException) { FauxItalic = false; } try { Underline = TdTaParser.getBool(d, "Underline"); } catch (KeyNotFoundException) { Underline = false; } FillColor = TdTaParser.getColor(d, "FillColor"); try { OutlineWidth = (double)TdTaParser.query(d, "OutlineWidth"); } catch (KeyNotFoundException) { OutlineWidth = 0f; } try { StrokeColor = TdTaParser.getColor(d, "StrokeColor"); } catch (KeyNotFoundException) { StrokeColor = 0; } }
public LayerText(PsdBinaryReader psdReader, int dataLength) { Data = psdReader.ReadBytes((int)dataLength); var reader = new PsdBinaryReader(new System.IO.MemoryStream(Data), psdReader); // PhotoShop version reader.ReadUInt16(); Transform = new Matrix2D(reader); // TextVersion reader.ReadUInt16(); //2 bytes, =50. For Photoshop 6.0. // DescriptorVersion reader.ReadUInt32(); //4 bytes,=16. For Photoshop 6.0. TxtDescriptor = DynVal.ReadDescriptor(reader); //Text descriptor // WarpVersion ushort wrapVersion = reader.ReadUInt16(); //2 bytes, =1. For Photoshop 6.0. // DescriptorVersion uint wrapDescriptorVersion = reader.ReadUInt32(); DynVal warpDescriptor = DynVal.ReadDescriptor(reader); // double left = reader.ReadDouble(); // double top = reader.ReadDouble(); // double right = reader.ReadDouble(); // double bottom = reader.ReadDouble(); byte[] datas = reader.ReadBytes(32); engineData = (Dictionary <string, object>)TxtDescriptor.Children.Find(c => c.Name == "EngineData").Value; StylesheetReader = new TdTaStylesheetReader(engineData); Dictionary <string, object> d = StylesheetReader.GetStylesheetDataFromLongestRun(); Text = StylesheetReader.Text; FontName = TdTaParser.getString(StylesheetReader.getFontSet()[(int)TdTaParser.query(d, "Font")], "Name$"); FontSize = (double)TdTaParser.query(d, "FontSize"); if (d.ContainsKey("FauxBold")) { FauxBold = TdTaParser.getBool(d, "FauxBold"); } if (d.ContainsKey("FauxItalic")) { FauxItalic = TdTaParser.getBool(d, "FauxItalic"); } if (d.ContainsKey("Underline")) { Underline = TdTaParser.getBool(d, "Underline"); } if (d.ContainsKey("StyleRunAlignment")) { int styleRunAlignment = (int)TdTaParser.query(d, "StyleRunAlignment");//No idea what this maps to. } FillColor = Color.black; if (d.ContainsKey("FillColor")) { FillColor = TdTaParser.getColor(d, "FillColor"); } if (d.ContainsKey("OutlineWidth")) { OutlineWidth = (double)TdTaParser.query(d, "OutlineWidth"); } if (d.ContainsKey("StrokeFlag")) { StrokeFlag = TdTaParser.getBool(d, "StrokeFlag"); } if (d.ContainsKey("StrokeColor")) { StrokeColor = TdTaParser.getColor(d, "StrokeColor"); } if (d.ContainsKey("Strikethrough")) { Strikethrough = TdTaParser.getBool(d, "Strikethrough"); } if (d.ContainsKey("FontBaseline")) { FontBaseline = TdTaParser.getIntger(d, "FontBaseline"); } //Fix newlines try { //Remove MT if (FontName.EndsWith("MT")) { FontName = FontName.Substring(0, FontName.Length - 2); } //Remove -Bold, -Italic, -BoldItalic if (FontName.EndsWith("-Bold", StringComparison.OrdinalIgnoreCase)) { Style |= FontStyle.Bold; } if (FontName.EndsWith("-Italic", StringComparison.OrdinalIgnoreCase)) { Style |= FontStyle.Italic; } if (FontName.EndsWith("-BoldItalic", StringComparison.OrdinalIgnoreCase)) { Style |= FontStyle.Bold | FontStyle.Italic; } //Remove from FontName FontName = new Regex("\\-(Bold|Italic|BoldItalic)$", RegexOptions.IgnoreCase | RegexOptions.IgnoreCase).Replace(FontName, ""); //Remove PS if (FontName.EndsWith("PS")) { FontName = FontName.Substring(0, FontName.Length - 2); } //Find font family if (FauxBold) { Style |= FontStyle.Bold; } if (FauxItalic) { Style |= FontStyle.Italic; } // if (underline) style |= FontStyle.Underline; // if (strikethrough) style |= FontStyle.Strikeout; } finally { } }
/////////////////////////////////////////////////////////////////////////// /// <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> private void LoadLayers(PsdBinaryReader reader, bool hasHeader) { Debug.WriteLine("LoadLayers started at " + reader.BaseStream.Position.ToString(CultureInfo.InvariantCulture)); UInt32 sectionLength = 0; if (hasHeader) { sectionLength = reader.ReadUInt32(); if (sectionLength <= 0) { 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); } Layers.Clear(); if (numLayers == 0) { return; } for (int i = 0; i < numLayers; i++) { var layer = new Layer(reader, this); Layers.Add(layer); } //----------------------------------------------------------------------- // Load image data for all channels. foreach (var layer in Layers) { foreach (var channel in layer.Channels) { channel.LoadPixelData(reader); } } // 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; } } }
public static ImageResource CreateImageResource(PsdBinaryReader reader) { Util.DebugMessage(reader.BaseStream, "Load, Begin, ImageResource"); 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; } Util.DebugMessage(reader.BaseStream, "Load, End, ImageResource, {0}", resourceId); // 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); }
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; case "lrFX": result = new EffectsLayer(reader, key); break; case "shmd": result = new MetadataSetting(reader); break; case "lfx2": result = new ObjectBasedEffect(reader, length); 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 StringStructure(PsdBinaryReader reader, string key) { _key = key; Text = reader.ReadUnicodeString(); }
public static Descriptor Load(PsdBinaryReader reader) { string key = reader.ReadAsciiChars(4); return(Load(key, reader)); }
public MaskInfo(PsdBinaryReader reader, Layer layer) { Debug.WriteLine("MaskInfo started at " + reader.BaseStream.Position.ToString(CultureInfo.InvariantCulture)); 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; }
public static Descriptor Load(string key, PsdBinaryReader reader) { Descriptor result = null; switch (key) { case Reference: result = new ReferenceStructure(reader); break; case Descriptor: case GlobalObject: result = new DescriptorStructure(reader, key); break; case List: result = new ListStructure(reader); break; case Double: result = new DoubleStructure(reader); break; case UnitFloat: result = new UnitFloatStructure(reader); break; case String: result = new StringStructure(reader, key); break; case Enumerated: result = new EnumeratedDescriptor(reader); break; case Integer: result = new Integer(reader, key); break; case LargeInteger: result = new LargeInteger(reader); break; case Booolean: result = new BooleanStructure(reader); break; case Class1: case Class2: result = new ClassStructure(reader, key); break; case Alias: result = new AliasStructure(reader); break; case RowData: result = new RowData(reader); break; } return(result); }
public LargeInteger(PsdBinaryReader reader) { Value = reader.ReadInt64(); }
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; } } }