public static bool Info(ImageBinReader s, out ReadState ri)
        {
            ri = new ReadState();
            var info = new PsdInfo();

            return(ParseHeader(s, ri, ref info));
        }
Example #2
0
        public static BmpInfo Info(ImageBinReader reader, out ReadState state)
        {
            state = new ReadState();
            var header = ParseHeader(reader, state);

            return(header ?? throw new StbImageReadException(ErrorCode.UnknownHeader));
        }
Example #3
0
        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);
        }
Example #5
0
        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);
        }
Example #7
0
        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..]);
Example #8
0
        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);
        }
Example #9
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 #10
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);
        }