private void ParseBrushPreset(BinaryReverseReader reader, uint count) { string presetName = null; BrushData brushData = null; for (uint i = 0; i < count; i++) { string key = ParseKey(reader); DescriptorTypes type = (DescriptorTypes)reader.ReadUInt32(); #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format( CultureInfo.CurrentCulture, "brushPreset item {0}: {1} ({2}) at 0x{3:X8}", new object[] { i, key, type, reader.BaseStream.Position })); #endif if (key.Equals("Nm ", StringComparison.Ordinal)) { presetName = ParseString(reader); } else if (key.Equals("Brsh", StringComparison.Ordinal) && type == DescriptorTypes.Descriptor) { brushData = ParseBrushDescriptor(reader); } else { ParseType(reader, type); } } if (brushData != null && !string.IsNullOrEmpty(brushData.sampledDataTag)) { this.sampledBrushes.Add(new SampledBrush(presetName, brushData.sampledDataTag, brushData.diameter, brushData.spacing)); } }
private void ParseDescriptor(BinaryReverseReader reader) { string name = ParseString(reader); string classId = ParseClassId(reader); uint count = reader.ReadUInt32(); #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Parsing descriptor '{0}' ({1} items)", classId, count)); #endif if (classId.Equals("brushPreset", StringComparison.Ordinal)) { ParseBrushPreset(reader, count); } else { for (uint i = 0; i < count; i++) { string key = ParseKey(reader); DescriptorTypes type = (DescriptorTypes)reader.ReadUInt32(); #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format( CultureInfo.CurrentCulture, "Item {0}: {1} ({2}) at 0x{3:X8}", new object[] { i, key, type, reader.BaseStream.Position })); #endif ParseType(reader, type); } } }
private static EnumeratedValue ParseEnumerated(BinaryReverseReader reader) { EnumeratedValue value = new EnumeratedValue() { type = ParseKey(reader), value = ParseKey(reader) }; return(value); }
private static UnitFloat ParseUnitFloat(BinaryReverseReader reader) { UnitFloat value = new UnitFloat() { type = (UnitTypes)reader.ReadUInt32(), value = reader.ReadDouble() }; return(value); }
private void ParseList(BinaryReverseReader reader) { uint count = reader.ReadUInt32(); for (int i = 0; i < count; i++) { DescriptorTypes type = (DescriptorTypes)reader.ReadUInt32(); ParseType(reader, type); } }
private static string ParseClassId(BinaryReverseReader reader) { int length = reader.ReadInt32(); if (length == 0) { length = 4; } return(Encoding.ASCII.GetString(reader.ReadBytes(length)).TrimEnd('\0')); }
private const uint DescriptorSectionId = 0x64657363; // desc /// <summary> /// Initializes a new instance of the <see cref="BrushSectionParser"/> class. /// </summary> /// <param name="reader">The reader.</param> public BrushSectionParser(BinaryReverseReader reader) { this.sectionOffsets = GetBrushSectionOffsets(reader); this.sampledBrushes = new SampledBrushCollection(); if (this.sectionOffsets != null && this.sectionOffsets.descriptorSectionOffset >= 0) { reader.BaseStream.Position = this.sectionOffsets.descriptorSectionOffset; ParseBrushDescriptorSection(reader); } }
private static string ParseKey(BinaryReverseReader reader) { int length = reader.ReadInt32(); if (length == 0) { length = 4; } byte[] bytes = reader.ReadBytes(length); return(Encoding.ASCII.GetString(bytes)); }
private BrushData ParseSampledBrush(BinaryReverseReader reader, uint count) { BrushData data = new BrushData(); for (uint i = 0; i < count; i++) { string key = ParseKey(reader); DescriptorTypes type = (DescriptorTypes)reader.ReadUInt32(); #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format( CultureInfo.CurrentCulture, "sampledBrush item {0}: {1} ({2}) at 0x{3:X8}", new object[] { i, key, type, reader.BaseStream.Position })); #endif UnitFloat unitFloat; switch (key) { case "Dmtr": unitFloat = ParseUnitFloat(reader); if (unitFloat.type == UnitTypes.Pixel) { data.diameter = (int)unitFloat.value; } break; case "Spcn": unitFloat = ParseUnitFloat(reader); if (unitFloat.type == UnitTypes.Percent) { data.spacing = (int)unitFloat.value; } break; case "sampledData": data.sampledDataTag = ParseString(reader); break; default: ParseType(reader, type); break; } } return(data); }
private void ParseType(BinaryReverseReader reader, DescriptorTypes type) { switch (type) { case DescriptorTypes.List: ParseList(reader); break; case DescriptorTypes.Descriptor: ParseDescriptor(reader); break; case DescriptorTypes.String: ParseString(reader); break; case DescriptorTypes.UnitFloat: ParseUnitFloat(reader); break; case DescriptorTypes.Boolean: ParseBoolean(reader); break; case DescriptorTypes.Integer: ParseInteger(reader); break; case DescriptorTypes.Float: ParseFloat(reader); break; case DescriptorTypes.Enumerated: ParseEnumerated(reader); break; default: throw new FormatException(string.Format(CultureInfo.CurrentCulture, "Unsupported brush descriptor type: '{0}'", DescriptorTypeToString(type))); } }
//////////////////////////////////////////////////////////////////////// public static void DecodedRow(BinaryReverseReader reader, byte[] imgData, int startIdx, int columns) { int count = 0; while (count < columns) { byte byteValue = reader.ReadByte(); int len = byteValue; if (len < 128) { len++; while (len != 0 && (startIdx + count) < imgData.Length) { byteValue = reader.ReadByte(); imgData[startIdx + count] = byteValue; count++; len--; } } else if (len > 128) { // Next -len+1 bytes in the dest are replicated from next source byte. // (Interpret len as a negative 8-bit int.) len ^= 0x0FF; len += 2; byteValue = reader.ReadByte(); while (len != 0 && (startIdx + count) < imgData.Length) { imgData[startIdx + count] = byteValue; count++; len--; } } } }
private BrushData ParseBrushDescriptor(BinaryReverseReader reader) { string name = ParseString(reader); string classId = ParseClassId(reader); uint count = reader.ReadUInt32(); #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Parsing {0} ({1} items)", classId, count)); #endif BrushData data = null; if (classId.Equals("sampledBrush", StringComparison.Ordinal)) { data = ParseSampledBrush(reader, count); } else { for (uint i = 0; i < count; i++) { string key = ParseKey(reader); DescriptorTypes type = (DescriptorTypes)reader.ReadUInt32(); #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format( CultureInfo.CurrentCulture, "{0} item {1}: {2} ({3}) at 0x{4:X8}", new object[] { classId, i, key, type, reader.BaseStream.Position })); #endif ParseType(reader, type); } } return(data); }
private static BrushSectionOffsets GetBrushSectionOffsets(BinaryReverseReader reader) { long sampleSectionOffset = -1; long descriptorSectionOffset = -1; while (reader.BaseStream.Position < reader.BaseStream.Length) { uint sig = reader.ReadUInt32(); if (sig != PhotoshopSignature) { return(null); } uint sectionId = reader.ReadUInt32(); switch (sectionId) { case SampleSectionId: sampleSectionOffset = reader.BaseStream.Position; break; case DescriptorSectionId: descriptorSectionOffset = reader.BaseStream.Position; break; default: break; } uint size = reader.ReadUInt32(); reader.BaseStream.Position += size; } return(new BrushSectionOffsets(sampleSectionOffset, descriptorSectionOffset)); }
private void ParseBrushDescriptorSection(BinaryReverseReader reader) { uint sectionSize = reader.ReadUInt32(); long sectionEnd = reader.BaseStream.Position + sectionSize; // Skip the unknown data. reader.BaseStream.Position += 22L; if (reader.BaseStream.Position < sectionEnd) { string key = ParseKey(reader); DescriptorTypes type = (DescriptorTypes)reader.ReadUInt32(); #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format( CultureInfo.CurrentCulture, "Item: {0} ({1}) at {2:X8}", new object[] { key, type, reader.BaseStream.Position })); #endif ParseType(reader, type); } }
public static Document Load(Stream stream) { using (BinaryReverseReader reader = new BinaryReverseReader(stream)) { ReadOnlyCollection <Brush> brushes; short version = reader.ReadInt16(); switch (version) { case 1: case 2: brushes = DecodeVersion1(reader, version); break; case 6: case 7: // Used by Photoshop CS and later for brushes containing 16-bit data. case 10: // Used by Photoshop CS6 and/or CC? brushes = DecodeVersion6(reader, version); break; default: throw new FormatException(string.Format(CultureInfo.CurrentCulture, Resources.UnsupportedABRVersion, version)); } if (brushes.Count == 0) { throw new FormatException(Resources.NoSampledBrushes); } int maxWidth = 0; int maxHeight = 0; foreach (var item in brushes) { if (item.Surface.Width > maxWidth) { maxWidth = item.Surface.Width; } if (item.Surface.Height > maxHeight) { maxHeight = item.Surface.Height; } } Document doc = null; Document tempDoc = null; try { tempDoc = new Document(maxWidth, maxHeight); for (int i = 0; i < brushes.Count; i++) { Brush abr = brushes[i]; BitmapLayer layer = null; BitmapLayer tempLayer = null; try { tempLayer = new BitmapLayer(maxWidth, maxHeight); tempLayer.IsBackground = i == 0; tempLayer.Name = !string.IsNullOrEmpty(abr.Name) ? abr.Name : string.Format(CultureInfo.CurrentCulture, Resources.BrushNameFormat, i); tempLayer.Metadata.SetUserValue(AbrMetadataNames.BrushSpacing, abr.Spacing.ToString(CultureInfo.InvariantCulture)); tempLayer.Surface.CopySurface(abr.Surface); layer = tempLayer; tempLayer = null; } finally { if (tempLayer != null) { tempLayer.Dispose(); tempLayer = null; } abr.Dispose(); } tempDoc.Layers.Add(layer); } doc = tempDoc; tempDoc = null; } finally { if (tempDoc != null) { tempDoc.Dispose(); tempDoc = null; } } return(doc); } }
private static ReadOnlyCollection <Brush> DecodeVersion6(BinaryReverseReader reader, short majorVersion) { short minorVersion = reader.ReadInt16(); long unusedDataLength; switch (minorVersion) { case 1: // Skip the Int16 bounds rectangle and the unknown Int16. unusedDataLength = 10L; break; case 2: // Skip the unknown bytes. unusedDataLength = 264L; break; default: throw new FormatException(string.Format(CultureInfo.CurrentCulture, Resources.UnsupportedABRSubVersion, majorVersion, minorVersion)); } BrushSectionParser parser = new BrushSectionParser(reader); List <Brush> brushes = new List <Brush>(parser.SampledBrushes.Count); long sampleSectionOffset = parser.SampleSectionOffset; if (parser.SampledBrushes.Count > 0 && sampleSectionOffset >= 0) { reader.BaseStream.Position = sampleSectionOffset; uint sectionLength = reader.ReadUInt32(); long sectionEnd = reader.BaseStream.Position + sectionLength; while (reader.BaseStream.Position < sectionEnd) { uint brushLength = reader.ReadUInt32(); // The brush data is padded to 4 byte alignment. long paddedBrushLength = ((long)brushLength + 3) & ~3; long endOffset = reader.BaseStream.Position + paddedBrushLength; string tag = reader.ReadPascalString(); // Skip the unneeded data that comes before the Int32 bounds rectangle. reader.BaseStream.Position += unusedDataLength; Rectangle bounds = reader.ReadInt32Rectangle(); if (bounds.Width <= 0 || bounds.Height <= 0) { // Skip any brushes that have invalid dimensions. reader.BaseStream.Position += (endOffset - reader.BaseStream.Position); continue; } short depth = reader.ReadInt16(); if (depth != 8 && depth != 16) { // Skip any brushes with an unknown bit depth. reader.BaseStream.Position += (endOffset - reader.BaseStream.Position); continue; } SampledBrush sampledBrush = parser.SampledBrushes.FindBrush(tag); if (sampledBrush != null) { AbrImageCompression compression = (AbrImageCompression)reader.ReadByte(); int height = bounds.Height; int width = bounds.Width; byte[] alphaData = null; if (compression == AbrImageCompression.RLE) { short[] compressedRowLengths = new short[height]; for (int y = 0; y < height; y++) { compressedRowLengths[y] = reader.ReadInt16(); } int alphaDataSize = width * height; int bytesPerRow = width; if (depth == 16) { alphaDataSize *= 2; bytesPerRow *= 2; } alphaData = new byte[alphaDataSize]; for (int y = 0; y < height; y++) { RLEHelper.DecodedRow(reader, alphaData, y * width, bytesPerRow); } } else { int alphaDataSize = width * height; if (depth == 16) { alphaDataSize *= 2; } alphaData = reader.ReadBytes(alphaDataSize); } var brush = CreateSampledBrush(width, height, depth, alphaData, sampledBrush.Name, sampledBrush.Spacing); brushes.Add(brush); // Some brushes only store the largest item and scale it down. var scaledBrushes = parser.SampledBrushes.Where(i => i.Tag.Equals(tag, StringComparison.Ordinal) && i.Diameter < sampledBrush.Diameter); if (scaledBrushes.Any()) { int originalWidth = brush.Surface.Width; int originalHeight = brush.Surface.Height; foreach (var item in scaledBrushes.OrderByDescending(p => p.Diameter)) { Size size = ComputeBrushSize(originalWidth, originalHeight, item.Diameter); Brush scaledBrush = new Brush(size.Width, size.Height, item.Name, item.Spacing); scaledBrush.Surface.FitSurface(ResamplingAlgorithm.SuperSampling, brush.Surface); brushes.Add(scaledBrush); } } } long remaining = endOffset - reader.BaseStream.Position; // Skip any remaining bytes until the next sampled brush. if (remaining > 0) { reader.BaseStream.Position += remaining; } } } return(brushes.AsReadOnly()); }
private static ReadOnlyCollection <Brush> DecodeVersion1(BinaryReverseReader reader, short version) { short count = reader.ReadInt16(); List <Brush> brushes = new List <Brush>(count); for (int i = 0; i < count; i++) { AbrBrushType type = (AbrBrushType)reader.ReadInt16(); int size = reader.ReadInt32(); long endOffset = reader.BaseStream.Position + size; #if DEBUG System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Brush: {0}, type: {1}, size: {2} bytes", i, type, size)); #endif if (type == AbrBrushType.Computed) { #if DEBUG int misc = reader.ReadInt32(); short spacing = reader.ReadInt16(); string name = string.Empty; if (version == 2) { name = reader.ReadUnicodeString(); } short diameter = reader.ReadInt16(); short roundness = reader.ReadInt16(); short angle = reader.ReadInt16(); short hardness = reader.ReadInt16(); #else reader.BaseStream.Position += size; #endif } else if (type == AbrBrushType.Sampled) { int misc = reader.ReadInt32(); short spacing = reader.ReadInt16(); string name = string.Empty; if (version == 2) { name = reader.ReadUnicodeString(); } bool antiAlias = reader.ReadByte() != 0; // Skip the Int16 bounds. reader.BaseStream.Position += 8L; Rectangle bounds = reader.ReadInt32Rectangle(); if (bounds.Width <= 0 || bounds.Height <= 0) { // Skip any brushes that have invalid dimensions. reader.BaseStream.Position += (endOffset - reader.BaseStream.Position); continue; } short depth = reader.ReadInt16(); if (depth != 8) { // The format specs state that brushes must be 8-bit, skip any that are not. reader.BaseStream.Position += (endOffset - reader.BaseStream.Position); continue; } int height = bounds.Height; int width = bounds.Width; int rowsRemaining = height; int rowsRead = 0; byte[] alphaData = new byte[width * height]; do { // Sampled brush data is broken into repeating chunks for brushes taller that 16384 pixels. int chunkHeight = Math.Min(rowsRemaining, 16384); // The format specs state that compression is stored as a 2-byte field, but it is written as a 1-byte field in actual files. AbrImageCompression compression = (AbrImageCompression)reader.ReadByte(); if (compression == AbrImageCompression.RLE) { short[] compressedRowLengths = new short[height]; for (int y = 0; y < height; y++) { compressedRowLengths[y] = reader.ReadInt16(); } for (int y = 0; y < chunkHeight; y++) { int row = rowsRead + y; RLEHelper.DecodedRow(reader, alphaData, row * width, width); } } else { int rowByteOffset = rowsRead * width; int numBytesToRead = chunkHeight * width; int numBytesRead = 0; while (numBytesToRead > 0) { // Read may return anything from 0 to numBytesToRead. int n = reader.Read(alphaData, rowByteOffset + numBytesRead, numBytesToRead); // The end of the file is reached. if (n == 0) { break; } numBytesRead += n; numBytesToRead -= n; } } rowsRemaining -= 16384; rowsRead += 16384; } while (rowsRemaining > 0); brushes.Add(CreateSampledBrush(width, height, depth, alphaData, name, spacing)); } else { // Skip any unknown brush types. reader.BaseStream.Position += size; } } return(brushes.AsReadOnly()); }
private static double ParseFloat(BinaryReverseReader reader) { double value = reader.ReadDouble(); return(value); }
private static uint ParseInteger(BinaryReverseReader reader) { uint value = reader.ReadUInt32(); return(value); }
private static bool ParseBoolean(BinaryReverseReader reader) { bool value = reader.ReadByte() != 0; return(value); }
private static string ParseString(BinaryReverseReader reader) { return(reader.ReadUnicodeString()); }