public static bool Info(ImageBinReader s, out ReadState ri) { ri = new ReadState(); var info = new PsdInfo(); return(ParseHeader(s, ri, ref info)); }
public static BmpInfo Info(ImageBinReader reader, out ReadState state) { state = new ReadState(); var header = ParseHeader(reader, state); return(header ?? throw new StbImageReadException(ErrorCode.UnknownHeader)); }
public static TgaInfo Info(ImageBinReader reader, out ReadState state) { state = new ReadState(); var header = ParseHeader(reader, state); return(header); }
public static bool ParseHeader(ImageBinReader s, ReadState ri, ref PsdInfo info) { Span <byte> tmp = stackalloc byte[HeaderSize]; if (!s.TryReadBytes(tmp)) { return(false); } if (!Test(tmp)) { throw new StbImageReadException(ErrorCode.UnknownFormat); } // TODO: figure out what this skips s.Skip(6); info.channelCount = s.ReadInt16BE(); if ((info.channelCount < 0) || (info.channelCount > 16)) { throw new StbImageReadException(ErrorCode.BadChannelCount); } ri.Height = s.ReadInt32BE(); ri.Width = s.ReadInt32BE(); ri.Depth = s.ReadInt16BE(); if (ri.Depth != 8 && ri.Depth != 16) { throw new StbImageReadException(ErrorCode.UnsupportedBitDepth); } if (s.ReadInt16BE() != 3) { throw new StbImageReadException(ErrorCode.BadColorType); } s.Skip(s.ReadInt32BE()); s.Skip(s.ReadInt32BE()); s.Skip(s.ReadInt32BE()); info.compression = s.ReadInt16BE(); if (info.compression > 1) { throw new StbImageReadException(ErrorCode.BadCompression); } ri.OutDepth = ri.Depth; if (info.compression == 0) { ri.OutDepth = ri.Depth; } else { ri.OutDepth = 8; } return(true); }
public static void ReadRgb16(ImageBinReader reader, Span <byte> destination) { Debug.Assert(reader != null); const ushort fiveBitMask = 31; var px = (ushort)reader.ReadInt16LE(); int b = px & fiveBitMask; int g = (px >> 5) & fiveBitMask; int r = (px >> 10) & fiveBitMask; destination[2] = (byte)(b * 255 / 31); destination[1] = (byte)(g * 255 / 31); destination[0] = (byte)(r * 255 / 31); }
public static bool DecodeRLE(ImageBinReader s, byte *destination, int pixelCount) { int count = 0; int nleft; while ((nleft = pixelCount - count) > 0) { int len = s.ReadByte(); if (len == 128) { } else if (len < 128) { len++; if (len > nleft) { return(false); } count += len; while (len != 0) { *destination = s.ReadByte(); destination += 4; len--; } } else if (len > 128) { len = 257 - len; if (len > nleft) { return(false); } int val = s.ReadByte(); count += len; while (len != 0) { *destination = (byte)val; destination += 4; len--; } } } return(true); }
public static TgaInfo Load( ImageBinReader reader, ReadState state, ArrayPool <byte>?bytePool = null) { var info = ParseHeader(reader, state); reader.Skip(info.offset); bytePool ??= ArrayPool <byte> .Shared; int lineBufferLength = (state.Width * state.Components * state.Depth + 7) / 8; byte[] lineBuffer = bytePool.Rent(lineBufferLength); try { Span <byte> line = lineBuffer.AsSpan(0, lineBufferLength); if (info.colormap_type == 0 && !info.is_RLE && state.Depth == 8) { for (int y = 0; y < state.Height; ++y) { reader.ReadBytes(line); SwapComponentOrder(line, state.Components, state.Depth); int row = info.inverted != 0 ? state.Height - y - 1 : y; state.OutputPixelLine(AddressingMajor.Row, row, 0, line); } } else { Memory <byte> paletteBuffer = default; Span <byte> palette = default; if (info.colormap_type != 0) { reader.Skip(info.palette_start); paletteBuffer = new byte[info.palette_len * state.Components]; palette = paletteBuffer.Span; if (state.Depth == 16) { for (int i = 0; i < palette.Length; i += state.Components) { ReadRgb16(reader, palette[i..]);
public static BmpInfo?ParseHeader(ImageBinReader s, ReadState ri) { if (s == null) { throw new ArgumentNullException(nameof(s)); } if (ri == null) { throw new ArgumentNullException(nameof(ri)); } Span <byte> tmp = stackalloc byte[HeaderSize]; if (!s.TryReadBytes(tmp)) { return(null); } if (!Test(tmp)) { throw new StbImageReadException(ErrorCode.UnknownFormat); } var info = new BmpInfo(); s.ReadInt32LE(); s.ReadInt16LE(); s.ReadInt16LE(); info.offset = s.ReadInt32LE(); info.headerSize = s.ReadInt32LE(); info.mr = info.mg = info.mb = info.ma = 0; if (info.headerSize != 12 && info.headerSize != 40 && info.headerSize != 56 && info.headerSize != 108 && info.headerSize != 124) { throw new StbImageReadException(ErrorCode.UnknownHeader); } if (info.headerSize == 12) { ri.Width = s.ReadInt16LE(); ri.Height = s.ReadInt16LE(); } else { ri.Width = s.ReadInt32LE(); ri.Height = s.ReadInt32LE(); } ri.Orientation = ri.Height > 0 ? ImageOrientation.BottomLeftOrigin : ImageOrientation.TopLeftOrigin; ri.Height = Math.Abs(ri.Height); if (s.ReadInt16LE() != 1) { throw new StbImageReadException(ErrorCode.BadColorPlane); } info.bitsPerPixel = s.ReadInt16LE(); if (info.bitsPerPixel == 1) { throw new StbImageReadException(ErrorCode.MonochromeNotSupported); } if (info.headerSize != 12) { int compress = s.ReadInt32LE(); if ((compress == 1) || (compress == 2)) { throw new StbImageReadException(ErrorCode.RLENotSupported); } s.ReadInt32LE(); s.ReadInt32LE(); s.ReadInt32LE(); s.ReadInt32LE(); s.ReadInt32LE(); if (info.headerSize == 40 || info.headerSize == 56) { if (info.headerSize == 56) { s.ReadInt32LE(); s.ReadInt32LE(); s.ReadInt32LE(); s.ReadInt32LE(); } if ((info.bitsPerPixel == 16) || (info.bitsPerPixel == 32)) { if (compress == 0) { if (info.bitsPerPixel == 32) { info.mr = 0xffu << 16; info.mg = 0xffu << 8; info.mb = 0xffu << 0; info.ma = 0xffu << 24; } else { info.mr = 31 << 10; info.mg = 31 << 5; info.mb = 31 << 0; } } else if (compress == 3) { info.mr = s.ReadUInt32LE(); info.mg = s.ReadUInt32LE(); info.mb = s.ReadUInt32LE(); if ((info.mr == info.mg) && (info.mg == info.mb)) { throw new StbImageReadException(ErrorCode.BadMasks); } } else { throw new StbImageReadException(ErrorCode.BadCompression); } } } else { if (info.headerSize != 108 && info.headerSize != 124) { throw new StbImageReadException(ErrorCode.UnknownHeader); } info.mr = s.ReadUInt32LE(); info.mg = s.ReadUInt32LE(); info.mb = s.ReadUInt32LE(); info.ma = s.ReadUInt32LE(); s.ReadInt32LE(); for (int i = 0; i < 12; ++i) { s.ReadInt32LE(); } if (info.headerSize == 124) { for (int i = 0; i < 4; ++i) { s.ReadInt32LE(); } } } } if (info.bitsPerPixel == 24 && info.ma == 0xffu << 24) { ri.Components = 3; } else { ri.Components = info.ma != 0 ? 4 : 3; } ri.Depth = info.bitsPerPixel / ri.Components; return(info); }
public static BmpInfo Load( ImageBinReader s, ReadState ri, ArrayPool <byte>?bytePool = null) { // TODO: optimize by pulling out some branching from loops bytePool ??= ArrayPool <byte> .Shared; var info = ParseHeader(s, ri) ?? throw new StbImageReadException(ErrorCode.UnknownHeader); ri.OutComponents = ri.Components; ri.OutDepth = Math.Max(ri.Depth, 8); ri.StateReady(); int psize = 0; if (info.headerSize == 12) { if (info.bitsPerPixel < 24) { psize = (info.offset - 14 - 24) / 3; } } else { if (info.bitsPerPixel < 16) { psize = (info.offset - 14 - info.headerSize) >> 2; } } int easy = 0; if (info.bitsPerPixel == 32) { if (info.mb == 0xffu << 0 && info.mg == 0xffu << 8 && info.mr == 0xffu << 16 && info.ma == 0xffu << 24) { easy = 2; } } else if (info.bitsPerPixel == 24) { easy = 1; } bool flipRows = (ri.Orientation & ImageOrientation.BottomToTop) == ImageOrientation.BottomToTop; int rowByteSize = ri.Width * ri.OutComponents; var rowBuffer = bytePool.Rent(rowByteSize); try { if (info.bitsPerPixel < 16) { if ((psize == 0) || (psize > 256)) { throw new StbImageReadException(ErrorCode.InvalidPLTE); } // TODO: output palette Span <byte> palette = stackalloc byte[256 * 4]; for (int x = 0; x < psize; ++x) { palette[x * 4 + 2] = s.ReadByte(); palette[x * 4 + 1] = s.ReadByte(); palette[x * 4 + 0] = s.ReadByte(); palette[x * 4 + 3] = info.headerSize == 12 ? (byte)255 : s.ReadByte(); } s.Skip( info.offset - 14 - info.headerSize - psize * (info.headerSize == 12 ? 3 : 4)); int width; if (info.bitsPerPixel == 4) { width = (ri.Width + 1) / 2; } else if (info.bitsPerPixel == 8) { width = ri.Width; } else { throw new StbImageReadException(ErrorCode.BadBitsPerPixel); } int pad = (-width) & 3; for (int y = 0; y < ri.Height; ++y) { for (int x = 0, z = 0; x < ri.Width; x += 2) { void WriteFromPalette(int comp, Span <byte> palette) { rowBuffer[z + 0] = palette[0]; rowBuffer[z + 1] = palette[1]; rowBuffer[z + 2] = palette[2]; if (comp == 4) { rowBuffer[z + 3] = palette[3]; } z += comp; } int v2 = 0; int v1 = s.ReadByte(); if (info.bitsPerPixel == 4) { v2 = v1 & 15; v1 >>= 4; } WriteFromPalette(ri.OutComponents, palette[(v1 * 4)..]);
public static TgaInfo ParseHeader(ImageBinReader reader, ReadState state) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (state == null) { throw new ArgumentNullException(nameof(state)); } Span <byte> tmp = stackalloc byte[HeaderSize]; if (!reader.TryReadBytes(tmp)) { throw new EndOfStreamException(); } bool test = TestCore(tmp, out var info); if (info.colormap_type == 1) { if (info.image_type != 1 && info.image_type != 9) { throw new StbImageReadException(ErrorCode.BadImageType); } info.palette_start = reader.ReadInt16LE(); info.palette_len = reader.ReadInt16LE(); info.palette_bpp = reader.ReadByte(); if (info.palette_bpp != 8 && info.palette_bpp != 15 && info.palette_bpp != 16 && info.palette_bpp != 24 && info.palette_bpp != 32) { throw new StbImageReadException(ErrorCode.BadPalette); } } else { if (info.image_type != 2 && info.image_type != 3 && info.image_type != 10 && info.image_type != 11) { throw new StbImageReadException(ErrorCode.BadImageType); } reader.Skip(5); // 16bit: Color Map Origin // 16bit: Color Map Length // 8bit: Color Map Entry Size } Debug.Assert(test); // Prior checks should throw if test was unsucessful. info.x_origin = reader.ReadInt16LE(); info.y_origin = reader.ReadInt16LE(); state.Width = reader.ReadUInt16LE(); if (state.Width < 1) { throw new StbImageReadException(ErrorCode.ZeroWidth); } state.Height = reader.ReadUInt16LE(); if (state.Height < 1) { throw new StbImageReadException(ErrorCode.ZeroHeight); } info.bits_per_pixel = reader.ReadByte(); info.inverted = reader.ReadByte(); info.inverted = 1 - ((info.inverted >> 5) & 1); // use the number of bits from the palette if paletted if (info.palette_bpp != 0) { if (info.bits_per_pixel != 8 && info.bits_per_pixel != 16) { throw new StbImageReadException(ErrorCode.BadBitsPerPixel); } state.Components = GetComponentCount( info.palette_bpp, false, out state.Depth); } else { state.Components = GetComponentCount( info.bits_per_pixel, info.image_type == 3, out state.Depth); } if (state.Components == 0) { throw new StbImageReadException(ErrorCode.BadComponentCount); } state.OutComponents = state.Components; state.OutDepth = state.Depth; state.Orientation = ImageOrientation.LeftToRight | (info.inverted != 0 ? ImageOrientation.BottomToTop : ImageOrientation.TopToBottom); state.StateReady(); return(info); }