/* File Header Section * Len Description Value * 4 Signature "8BPS" * 2 Version 1 * 6 Reserved not used. * 2 Channels 1 ~ 56 * 4 Height 1 ~ 30,000 * 4 Width 1 ~ 30,000 * 2 Color Depth 1, 8, 16, 32 * 2 Color Mode 1 ~ 9 */ private static void ReadHeader(ref PsdInfo info, PSDReader reader) { // Signature if (reader.ReadByte() != 0x38 || reader.ReadByte() != 0x42 || reader.ReadByte() != 0x50 || reader.ReadByte() != 0x53) { throw new NotSupportedException(); } // Version var version = reader.ReadInt16(); if (version != 1) { throw new NotSupportedException(); } // Reserved reader.Position += 6; // Channels info.Channels = reader.ReadInt16(); // Height info.Height = reader.ReadInt32(); // Width info.Width = reader.ReadInt32(); // Color Depth info.ColorDepth = reader.ReadInt16(); info.ColorDepthBytes = info.ColorDepth / 8; if (info.ColorDepthBytes != 1 && info.ColorDepthBytes != 2 && info.ColorDepthBytes != 4) { throw new NotSupportedException(); } // Color Mode info.ColorMode = (ColorMods)reader.ReadInt16(); if (info.ColorMode == ColorMods.Bitmap) { throw new NotSupportedException(); } info.Pixcels = info.Width * info.Height; info.SizePerChannel = info.Pixcels * info.ColorDepthBytes; }
// By RyuaNerin private static void RLEDecompress(PSDReader reader, byte[] output, int count) { // https://en.wikipedia.org/wiki/PackBits int ind = 0; int len; byte val; while (ind < count) { len = reader.ReadByte(); // (1 + n) literal bytes of data // bin sb ub // 0000 0000 0 128 // 0111 1111 127 127 if (len < 128) // 0 ~ 127 { while (len-- >= 0) { output[ind++] = reader.ReadByte(); } } // One byte of data, repeated (1 – n) times in the decompressed output // bin sb ub not +2 1-n // 1111 1111 -1 256 0000 0000 0000 0010 2 // 1000 0001 -127 129 0111 1110 1000 0000 128 else if (128 < len) { val = reader.ReadByte(); len = (len ^ 0xFF) + 2; while (len-- > 0) { output[ind++] = val; } } } }
// By RyuaNerin private static void RLEDecompress(PSDReader reader, byte[] output, int count) { // https://en.wikipedia.org/wiki/PackBits int ind = 0; int len; byte val; while (ind < count) { len = reader.ReadByte(); // (1 + n) literal bytes of data // bin sb ub // 0000 0000 0 128 // 0111 1111 127 127 if (len < 128) // 0 ~ 127 { while (len-- >= 0) output[ind++] = reader.ReadByte(); } // One byte of data, repeated (1 – n) times in the decompressed output // bin sb ub not +2 1-n // 1111 1111 -1 256 0000 0000 0000 0010 2 // 1000 0001 -127 129 0111 1110 1000 0000 128 else if (128 < len) { val = reader.ReadByte(); len = (len ^ 0xFF) + 2; while (len-- > 0) output[ind++] = val; } } }
/* Image Resources Section * Len Description Value * 4 Length * n Resource Block Data */ /* Image Resource Blocks * Len Description Value * 4 Signature '8BIM' * 2 Resource Id * n Name * 4 Resource Data Length * n Resource Data */ private static void ReadImageResources(ref PsdInfo info, PSDReader reader) { var length = reader.ReadInt32(); short id; int len; info.TransparencyIndex = -1; long pos = reader.Position + length; while (reader.Position < pos) { // Signature if (reader.ReadByte() != 0x38 || reader.ReadByte() != 0x42 || reader.ReadByte() != 0x49 || reader.ReadByte() != 0x4D) throw new NotSupportedException(); // Resource Id id = reader.ReadInt16(); // Name len = reader.ReadByte(); if (len > 0) { if((len % 2) != 0) len = reader.ReadByte(); reader.Position += len; } reader.Position += 1; // Data Length len = reader.ReadInt32(); if (len % 2 != 0) len++; switch (id) { case 1005: // ResolutionInfo structure info.DpiX = reader.ReadInt16(); reader.Position += 6; info.DpiY = reader.ReadInt16(); reader.Position += 6; break; case 1047: // Transparency Index. 2 bytes for the index of transparent color, if any. info.TransparencyIndex = reader.ReadInt16(); break; default: reader.Position += len; break; } } }
/* File Header Section * Len Description Value * 4 Signature "8BPS" * 2 Version 1 * 6 Reserved not used. * 2 Channels 1 ~ 56 * 4 Height 1 ~ 30,000 * 4 Width 1 ~ 30,000 * 2 Color Depth 1, 8, 16, 32 * 2 Color Mode 1 ~ 9 */ private static void ReadHeader(ref PsdInfo info, PSDReader reader) { // Signature if (reader.ReadByte() != 0x38 || reader.ReadByte() != 0x42 || reader.ReadByte() != 0x50 || reader.ReadByte() != 0x53) throw new NotSupportedException(); // Version var version = reader.ReadInt16(); if (version != 1) throw new NotSupportedException(); // Reserved reader.Position += 6; // Channels info.Channels = reader.ReadInt16(); // Height info.Height = reader.ReadInt32(); // Width info.Width = reader.ReadInt32(); // Color Depth info.ColorDepth = reader.ReadInt16(); info.ColorDepthBytes = info.ColorDepth / 8; if (info.ColorDepthBytes != 1 && info.ColorDepthBytes != 2 && info.ColorDepthBytes != 4) throw new NotSupportedException(); // Color Mode info.ColorMode = (ColorMods)reader.ReadInt16(); if (info.ColorMode == ColorMods.Bitmap) throw new NotSupportedException(); info.Pixcels = info.Width * info.Height; info.SizePerChannel = info.Pixcels * info.ColorDepthBytes; }
/* Image Resources Section * Len Description Value * 4 Length * n Resource Block Data */ /* Image Resource Blocks * Len Description Value * 4 Signature '8BIM' * 2 Resource Id * n Name * 4 Resource Data Length * n Resource Data */ private static void ReadImageResources(ref PsdInfo info, PSDReader reader) { var length = reader.ReadInt32(); short id; int len; info.TransparencyIndex = -1; long pos = reader.Position + length; while (reader.Position < pos) { // Signature if (reader.ReadByte() != 0x38 || reader.ReadByte() != 0x42 || reader.ReadByte() != 0x49 || reader.ReadByte() != 0x4D) { throw new NotSupportedException(); } // Resource Id id = reader.ReadInt16(); // Name len = reader.ReadByte(); if (len > 0) { if ((len % 2) != 0) { len = reader.ReadByte(); } reader.Position += len; } reader.Position += 1; // Data Length len = reader.ReadInt32(); if (len % 2 != 0) { len++; } switch (id) { case 1005: // ResolutionInfo structure info.DpiX = reader.ReadInt16(); reader.Position += 6; info.DpiY = reader.ReadInt16(); reader.Position += 6; break; case 1047: // Transparency Index. 2 bytes for the index of transparent color, if any. info.TransparencyIndex = reader.ReadInt16(); break; default: reader.Position += len; break; } } }