Example #1
0
        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)..]);
Example #2
0
        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);
        }