/* Image Data Section * Len Description Value * 2 Compression Mode CompressionModes * n Image Data */ private static void ReadImageData(ref PsdInfo info, PSDReader reader) { info.CompressionMode = (CompressionModes)reader.ReadInt16(); int i; info.ImageData = new byte[info.Channels][]; switch (info.CompressionMode) { case CompressionModes.Raw: for (i = 0; i < info.Channels; ++i) { info.ImageData[i] = reader.ReadBytes(info.SizePerChannel); } break; case CompressionModes.RLE: reader.Position += info.Height * info.Channels * 2; for (i = 0; i < info.Channels; ++i) { info.ImageData[i] = new byte[info.SizePerChannel]; RLEDecompress(reader, info.ImageData[i], info.SizePerChannel); } break; case CompressionModes.ZipWithoutPrediction: case CompressionModes.ZipWithPrediction: throw new NotSupportedException(); } }
/* 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; }
public static Image Load(Stream stream) { if (stream.CanSeek) { stream.Position = 0; } var reader = new PSDReader(stream); PsdInfo info = new PsdInfo(); ReadHeader(ref info, reader); ReadColorData(ref info, reader); ReadImageResources(ref info, reader); ReadLayerAndMaskInfomation(ref info, reader); ReadImageData(ref info, reader); return(CreateBitmap(ref info)); }
private static int ReadColor(ref PsdInfo info, int c, int pos) { int v; pos *= info.ColorDepthBytes; if (info.ColorDepthBytes == 1) { v = PSDReader.ToInteger(info.ImageData[c], pos, info.ColorDepthBytes); } else if (info.ColorDepthBytes == 2) { v = (int)(PSDReader.ToInteger(info.ImageData[c], pos, info.ColorDepthBytes) / 257d); // (65536 - 1) * (256 - 1) = 257 } else { v = (int)(255 * Math.Pow(PSDReader.ToFloat(info.ImageData[c], pos), 0.45470693)); } return(v); }
// 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 Data Section * Len Description Value * 2 Compression Mode CompressionModes * n Image Data */ private static void ReadImageData(ref PsdInfo info, PSDReader reader) { info.CompressionMode = (CompressionModes)reader.ReadInt16(); int i; info.ImageData = new byte[info.Channels][]; switch (info.CompressionMode) { case CompressionModes.Raw: for (i = 0; i < info.Channels; ++i) info.ImageData[i] = reader.ReadBytes(info.SizePerChannel); break; case CompressionModes.RLE: reader.Position += info.Height * info.Channels * 2; for (i = 0; i < info.Channels; ++i) { info.ImageData[i] = new byte[info.SizePerChannel]; RLEDecompress(reader, info.ImageData[i], info.SizePerChannel); } break; case CompressionModes.ZipWithoutPrediction: case CompressionModes.ZipWithPrediction: throw new NotSupportedException(); } }
/* Layer and Mask Information Section * Len Description * 4 Section Length * v Layer info * v Global layer mask info * v Additional Layer Information */ private static void ReadLayerAndMaskInfomation(ref PsdInfo info, PSDReader reader) { var length = reader.ReadInt32(); reader.Position += length; }
/* 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; } } }
/* Color Mode Data Section * Len Description Value * 4 Length * n Color Data */ private static void ReadColorData(ref PsdInfo info, PSDReader reader) { var len = reader.ReadInt32(); info.ColorData = reader.ReadBytes(len); }
/* 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; }
public static Image Load(Stream stream) { if (stream.CanSeek) stream.Position = 0; var reader = new PSDReader(stream); PsdInfo info = new PsdInfo(); ReadHeader(ref info, reader); ReadColorData(ref info, reader); ReadImageResources(ref info, reader); ReadLayerAndMaskInfomation(ref info, reader); ReadImageData(ref info, reader); return CreateBitmap(ref info); }
/* 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; } } }