Ejemplo n.º 1
0
        public static int stbi__png_info(stbi__context s, int *x, int *y, int *comp)
        {
            var p = new stbi__png();

            p.s = s;
            return(stbi__png_info_raw(p, x, y, comp));
        }
        public static int stbi__create_png_image(stbi__png a, byte *image_data, uint image_data_len, int out_n,
                                                 int depth, int color, int interlaced)
        {
            var   bytes     = depth == 16 ? 2 : 1;
            var   out_bytes = out_n * bytes;
            byte *final;
            var   p = 0;

            if (interlaced == 0)
            {
                return(stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a.s.img_x, a.s.img_y, depth,
                                                  color));
            }
            final = (byte *)stbi__malloc_mad3((int)a.s.img_x, (int)a.s.img_y, out_bytes, 0);
            if (final == null)
            {
                return(stbi__err("outofmem"));
            }
            for (p = 0; p < 7; ++p)
            {
                var xorig = stackalloc int[] { 0, 4, 0, 2, 0, 1, 0 };
                var yorig = stackalloc int[] { 0, 0, 4, 0, 2, 0, 1 };
                var xspc  = stackalloc int[] { 8, 8, 4, 4, 2, 2, 1 };
                var yspc  = stackalloc int[] { 8, 8, 8, 4, 4, 2, 2 };
                var i     = 0;
                var j     = 0;
                var x     = 0;
                var y     = 0;
                x = (int)((a.s.img_x - xorig[p] + xspc[p] - 1) / xspc[p]);
                y = (int)((a.s.img_y - yorig[p] + yspc[p] - 1) / yspc[p]);
                if (x != 0 && y != 0)
                {
                    var img_len = (uint)((((a.s.img_n * x * depth + 7) >> 3) + 1) * y);
                    if (stbi__create_png_image_raw(a, image_data, image_data_len, out_n, (uint)x, (uint)y, depth,
                                                   color) == 0)
                    {
                        CRuntime.free(final);
                        return(0);
                    }

                    for (j = 0; j < y; ++j)
                    {
                        for (i = 0; i < x; ++i)
                        {
                            var out_y = j * yspc[p] + yorig[p];
                            var out_x = i * xspc[p] + xorig[p];
                            CRuntime.memcpy(final + out_y * a.s.img_x * out_bytes + out_x * out_bytes,
                                            a._out_ + (j * x + i) * out_bytes, (ulong)out_bytes);
                        }
                    }

                    CRuntime.free(a._out_);
                    image_data     += img_len;
                    image_data_len -= img_len;
                }
            }

            a._out_ = final;
            return(1);
        }
Ejemplo n.º 3
0
        public static int stbi__compute_transparency16(stbi__png z, ushort *tc, int out_n)
        {
            var  s           = z.s;
            uint i           = 0;
            var  pixel_count = s.img_x * s.img_y;
            var  p           = (ushort *)z._out_;

            if (out_n == 2)
            {
                for (i = (uint)0; i < pixel_count; ++i)
                {
                    p[1] = (ushort)(p[0] == tc[0] ? 0 : 65535);
                    p   += 2;
                }
            }
            else
            {
                for (i = (uint)0; i < pixel_count; ++i)
                {
                    if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
                    {
                        p[3] = 0;
                    }
                    p += 4;
                }
            }

            return(1);
        }
Ejemplo n.º 4
0
        public static void *stbi__png_load(stbi__context s, int *x, int *y, int *comp, int req_comp,
                                           stbi__result_info *ri)
        {
            var p = new stbi__png();

            p.s = s;
            return(stbi__do_png(p, x, y, comp, req_comp, ri));
        }
        public static void *stbi__do_png(stbi__png p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)
        {
            void *result = null;

            if (req_comp < 0 || req_comp > 4)
            {
                return((byte *)(ulong)(stbi__err("bad req_comp") != 0 ? 0 : 0));
            }
            if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp) != 0)
            {
                if (p.depth <= 8)
                {
                    ri->bits_per_channel = 8;
                }
                else if (p.depth == 16)
                {
                    ri->bits_per_channel = 16;
                }
                else
                {
                    return((byte *)(ulong)(stbi__err("bad bits_per_channel") != 0 ? 0 : 0));
                }
                result  = p._out_;
                p._out_ = null;
                if (req_comp != 0 && req_comp != p.s.img_out_n)
                {
                    if (ri->bits_per_channel == 8)
                    {
                        result = stbi__convert_format((byte *)result, p.s.img_out_n, req_comp, p.s.img_x, p.s.img_y);
                    }
                    else
                    {
                        result = stbi__convert_format16((ushort *)result, p.s.img_out_n, req_comp, p.s.img_x,
                                                        p.s.img_y);
                    }
                    p.s.img_out_n = req_comp;
                    if (result == null)
                    {
                        return(result);
                    }
                }

                *x = (int)p.s.img_x;
                *y = (int)p.s.img_y;
                if (n != null)
                {
                    *n = p.s.img_n;
                }
            }

            CRuntime.free(p._out_);
            p._out_ = null;
            CRuntime.free(p.expanded);
            p.expanded = null;
            CRuntime.free(p.idata);
            p.idata = null;
            return(result);
        }
        public static void stbi__de_iphone(stbi__png z)
        {
            var  s           = z.s;
            uint i           = 0;
            var  pixel_count = s.img_x * s.img_y;
            var  p           = z._out_;

            if (s.img_out_n == 3)
            {
                for (i = 0; i < pixel_count; ++i)
                {
                    var t = p[0];
                    p[0] = p[2];
                    p[2] = t;
                    p   += 3;
                }
            }
            else
            {
                if ((stbi__unpremultiply_on_load_set != 0
                                        ? stbi__unpremultiply_on_load_local
                                        : stbi__unpremultiply_on_load_global) != 0)
                {
                    for (i = 0; i < pixel_count; ++i)
                    {
                        var a = p[3];
                        var t = p[0];
                        if (a != 0)
                        {
                            var half = (byte)(a / 2);
                            p[0] = (byte)((p[2] * 255 + half) / a);
                            p[1] = (byte)((p[1] * 255 + half) / a);
                            p[2] = (byte)((t * 255 + half) / a);
                        }
                        else
                        {
                            p[0] = p[2];
                            p[2] = t;
                        }

                        p += 4;
                    }
                }
                else
                {
                    for (i = 0; i < pixel_count; ++i)
                    {
                        var t = p[0];
                        p[0] = p[2];
                        p[2] = t;
                        p   += 4;
                    }
                }
            }
        }
Ejemplo n.º 7
0
        public static int stbi__png_is16(stbi__context s)
        {
            var p = new stbi__png();

            p.s = s;
            if (stbi__png_info_raw(p, null, null, null) == 0)
            {
                return(0);
            }
            if (p.depth != 16)
            {
                stbi__rewind(p.s);
                return(0);
            }

            return(1);
        }
Ejemplo n.º 8
0
        public static int stbi__expand_png_palette(stbi__png a, byte *palette, int len, int pal_img_n)
        {
            uint  i           = 0;
            var   pixel_count = a.s.img_x * a.s.img_y;
            byte *p;
            byte *temp_out;
            var   orig = a._out_;

            p = (byte *)stbi__malloc_mad2((int)pixel_count, pal_img_n, 0);
            if (p == null)
            {
                return(stbi__err("outofmem"));
            }
            temp_out = p;
            if (pal_img_n == 3)
            {
                for (i = (uint)0; i < pixel_count; ++i)
                {
                    var n = orig[i] * 4;
                    p[0] = palette[n];
                    p[1] = palette[n + 1];
                    p[2] = palette[n + 2];
                    p   += 3;
                }
            }
            else
            {
                for (i = (uint)0; i < pixel_count; ++i)
                {
                    var n = orig[i] * 4;
                    p[0] = palette[n];
                    p[1] = palette[n + 1];
                    p[2] = palette[n + 2];
                    p[3] = palette[n + 3];
                    p   += 4;
                }
            }

            CRuntime.free(a._out_);
            a._out_ = temp_out;
            return(1);
        }
Ejemplo n.º 9
0
        public static int stbi__png_info_raw(stbi__png p, int *x, int *y, int *comp)
        {
            if (stbi__parse_png_file(p, STBI__SCAN_header, 0) == 0)
            {
                stbi__rewind(p.s);
                return(0);
            }

            if (x != null)
            {
                *x = (int)p.s.img_x;
            }
            if (y != null)
            {
                *y = (int)p.s.img_y;
            }
            if (comp != null)
            {
                *comp = p.s.img_n;
            }
            return(1);
        }
Ejemplo n.º 10
0
        static int stbi__create_png_image(stbi__png* a, byte* image_data, uint image_data_len, int out_n, int depth, int color, int interlaced)
        {
            byte* final;
            int p;
            if (interlaced == 0)
                return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);

            // de-interlacing
            final = (byte*)CLib.CStdlib.malloc((int)(a->s->img_x * a->s->img_y * out_n));
            for (p = 0; p < 7; ++p)
            {
                int[] xorig = new int[] { 0, 4, 0, 2, 0, 1, 0 };
                int[] yorig = new int[] { 0, 0, 4, 0, 2, 0, 1 };
                int[] xspc = new int[] { 8, 8, 4, 4, 2, 2, 1 };
                int[] yspc = new int[] { 8, 8, 8, 4, 4, 2, 2 };
                int i, j, x, y;
                // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1
                x = (int)(a->s->img_x - xorig[p] + xspc[p] - 1) / xspc[p];
                y = (int)(a->s->img_y - yorig[p] + yspc[p] - 1) / yspc[p];
                if (x != 0 && y != 0)
                {
                    uint img_len = (uint)(((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y);
                    if (stbi__create_png_image_raw(a, image_data, image_data_len, out_n, (uint)x, (uint)y, depth, color) == 0)
                    {
                        CLib.CStdlib.free(final);
                        return 0;
                    }
                    for (j = 0; j < y; ++j)
                    {
                        for (i = 0; i < x; ++i)
                        {
                            int out_y = j * yspc[p] + yorig[p];
                            int out_x = i * xspc[p] + xorig[p];
                            CLib.CString.memcpy(final + out_y * a->s->img_x * out_n + out_x * out_n, a->Out + (j * x + i) * out_n, (uint)out_n);
                        }
                    }
                    CLib.CStdlib.free(a->Out);
                    image_data += img_len;
                    image_data_len -= img_len;
                }
            }
            a->Out = final;

            return 1;
        }
Ejemplo n.º 11
0
        static int stbi__compute_transparency(stbi__png* z, byte* tc, int out_n)
        {
            stbi__context* s = z->s;
            uint i, pixel_count = s->img_x * s->img_y;
            byte* p = z->Out;

            // compute color-based transparency, assuming we've
            // already got 255 as the alpha value in the output
            Debug.Assert(out_n == 2 || out_n == 4);

            if (out_n == 2)
            {
                for (i = 0; i < pixel_count; ++i)
                {
                    p[1] = (byte)(p[0] == tc[0] ? 0 : 255);
                    p += 2;
                }
            }
            else
            {
                for (i = 0; i < pixel_count; ++i)
                {
                    if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
                        p[3] = 0;
                    p += 4;
                }
            }
            return 1;
        }
Ejemplo n.º 12
0
 static int stbi__png_info_raw(stbi__png* p, int* x, int* y, int* comp)
 {
     if (stbi__parse_png_file(p, STBI__SCAN_header, 0) == 0)
     {
         stbi__rewind(p->s);
         return 0;
     }
     if (x != null) *x = (int)p->s->img_x;
     if (y != null) *y = (int)p->s->img_y;
     if (comp != null) *comp = p->s->img_n;
     return 1;
 }
Ejemplo n.º 13
0
        public static int stbi__parse_png_file(stbi__png* z, int scan, int req_comp)
        {
            byte* palette = stackalloc byte[1024]; byte pal_img_n = 0;
            byte has_trans = 0; byte* tc = stackalloc byte[3];
            uint ioff = 0, idata_limit = 0, i, pal_len = 0;
            int first = 1, k, interlace = 0, color = 0, depth = 0, is_iphone = 0;
            stbi__context* s = z->s;

            z->expanded = null;
            z->idata = null;
            z->Out = null;

            if (stbi__check_png_header(s) == 0) return 0;

            if (scan == STBI__SCAN_type) return 1;

            for (; ; )
            {
                stbi__pngchunk c = stbi__get_chunk_header(s);
                switch (c.type)
                {
                    case 0x43674249:    //STBI__PNG_TYPE('C', 'g', 'B', 'I'):
                        is_iphone = 1;
                        stbi__skip(s, (int)c.length);
                        break;
                    case 0x49484452:    //STBI__PNG_TYPE('I', 'H', 'D', 'R'):
                        {
                            int comp, filter;
                            if (first == 0) throw new Exception("multiple IHDR:Corrupt PNG");
                            first = 0;
                            if (c.length != 13) throw new Exception("bad IHDR len:Corrupt PNG");
                            s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) throw new Exception("too large:Very large image (corrupt?)");
                            s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) throw new Exception("too large:Very large image (corrupt?)");
                            depth = stbi__get8(s); if (depth != 1 && depth != 2 && depth != 4 && depth != 8) throw new Exception("1/2/4/8-bit only:PNG not supported: 1/2/4/8-bit only");
                            color = stbi__get8(s); if (color > 6) throw new Exception("bad ctype:Corrupt PNG");
                            if (color == 3) pal_img_n = 3; else if ((color & 1) != 0) throw new Exception("bad ctype:Corrupt PNG");
                            comp = stbi__get8(s); if (comp != 0) throw new Exception("bad comp method:Corrupt PNG");
                            filter = stbi__get8(s); if (filter != 0) throw new Exception("bad filter method:Corrupt PNG");
                            interlace = stbi__get8(s); if (interlace > 1) throw new Exception("bad interlace method:Corrupt PNG");
                            if (s->img_x == 0 || s->img_y == 0) throw new Exception("0-pixel image:Corrupt PNG");
                            if (pal_img_n == 0)
                            {
                                s->img_n = ((color & 2) != 0 ? 3 : 1) + ((color & 4) != 0 ? 1 : 0);
                                if ((1 << 30) / s->img_x / s->img_n < s->img_y) throw new Exception("too large:Image too large to decode");
                                if (scan == STBI__SCAN_header) return 1;
                            }
                            else
                            {
                                // if paletted, then pal_n is our final components, and
                                // img_n is # components to decompress/filter.
                                s->img_n = 1;
                                if ((1 << 30) / s->img_x / 4 < s->img_y) throw new Exception("too large:Corrupt PNG");
                                // if SCAN_header, have to scan to see if we have a tRNS
                            }
                            break;
                        }

                    case 0x504c5445:    //STBI__PNG_TYPE('P', 'L', 'T', 'E'):
                        {
                            if (first != 0) throw new Exception("first not IHDR:Corrupt PNG");
                            if (c.length > 256 * 3) throw new Exception("invalid PLTE:Corrupt PNG");
                            pal_len = c.length / 3;
                            if (pal_len * 3 != c.length) throw new Exception("invalid PLTE:Corrupt PNG");
                            for (i = 0; i < pal_len; ++i)
                            {
                                palette[i * 4 + 0] = stbi__get8(s);
                                palette[i * 4 + 1] = stbi__get8(s);
                                palette[i * 4 + 2] = stbi__get8(s);
                                palette[i * 4 + 3] = 255;
                            }
                            break;
                        }

                    case 0x74524e53:     //STBI__PNG_TYPE('t', 'R', 'N', 'S'):
                        {
                            if (first != 0) throw new Exception("first not IHDR:Corrupt PNG");
                            if (z->idata != null) throw new Exception("tRNS after IDAT:Corrupt PNG");
                            if (pal_img_n != 0)
                            {
                                if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }
                                if (pal_len == 0) throw new Exception("tRNS before PLTE:Corrupt PNG");
                                if (c.length > pal_len) throw new Exception("bad tRNS len:Corrupt PNG");
                                pal_img_n = 4;
                                for (i = 0; i < c.length; ++i)
                                    palette[i * 4 + 3] = stbi__get8(s);
                            }
                            else
                            {
                                if ((s->img_n & 1) == 0) throw new Exception("tRNS with alpha:Corrupt PNG");
                                if (c.length != (uint)s->img_n * 2) throw new Exception("bad tRNS len:Corrupt PNG");
                                has_trans = 1;
                                for (k = 0; k < s->img_n; ++k)
                                    tc[k] = (byte)((stbi__get16be(s) & 255) * stbi__depth_scale_table[depth]); // non 8-bit images will be larger
                            }
                            break;
                        }

                    case 0x49444154:    //STBI__PNG_TYPE('I', 'D', 'A', 'T'):
                        {
                            if (first != 0) throw new Exception("first not IHDR:Corrupt PNG");
                            if (pal_img_n != 0 && pal_len == 0) throw new Exception("no PLTE:Corrupt PNG");
                            if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
                            if ((int)(ioff + c.length) < (int)ioff) return 0;
                            if (ioff + c.length > idata_limit)
                            {
                                byte* p;
                                if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
                                while (ioff + c.length > idata_limit)
                                    idata_limit *= 2;
                                p = (byte*)CLib.CStdlib.realloc(z->idata, (int)idata_limit); if (p == null) throw new Exception("outofmem:Out of memory");
                                z->idata = p;
                            }
                            if (stbi__getn(s, z->idata + ioff, (int)c.length) == 0) throw new Exception("outofdata:Corrupt PNG");
                            ioff += c.length;
                            break;
                        }

                    case 0x49454e44:    //STBI__PNG_TYPE('I', 'E', 'N', 'D'):
                        {
                            uint raw_len, bpl;
                            if (first != 0) throw new Exception("first not IHDR:Corrupt PNG");
                            if (scan != STBI__SCAN_load) return 1;
                            if (z->idata == null) throw new Exception("no IDAT:Corrupt PNG");
                            // initial guess for decoded data size to avoid unnecessary reallocs
                            bpl = (s->img_x * (uint)depth + 7) / 8; // bytes per line, per component
                            raw_len = (uint)(bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */);
                            z->expanded = (byte*)stbi_zlib_decode_malloc_guesssize_headerflag((sbyte*)z->idata, (int)ioff, (int)raw_len, (int*)&raw_len, is_iphone);
                            if (z->expanded == null) return 0; // zlib should set error
                            CLib.CStdlib.free(z->idata); z->idata = null;
                            if ((req_comp == s->img_n + 1 && req_comp != 3 && pal_img_n == 0) || has_trans != 0)
                                s->img_out_n = s->img_n + 1;
                            else
                                s->img_out_n = s->img_n;
                            if (stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, color, interlace) == 0) return 0;
                            if (has_trans != 0)
                                if (stbi__compute_transparency(z, tc, s->img_out_n) == 0) return 0;
                            if (is_iphone != 0 && stbi__de_iphone_flag != 0 && s->img_out_n > 2)
                                stbi__de_iphone(z);
                            if (pal_img_n != 0)
                            {
                                // pal_img_n == 3 or 4
                                s->img_n = pal_img_n; // record the actual colors we had
                                s->img_out_n = pal_img_n;
                                if (req_comp >= 3) s->img_out_n = req_comp;
                                if (stbi__expand_png_palette(z, palette, (int)pal_len, (int)s->img_out_n) == 0)
                                    return 0;
                            }
                            CLib.CStdlib.free(z->expanded); z->expanded = null;
                            return 1;
                        }

                    default:
                        // if critical, fail
                        if (first != 0) throw new Exception("first not IHDR:Corrupt PNG");
                        if ((c.type & (1 << 29)) == 0)
                        {
                            // not threadsafe
                            char[] invalid_chunk = "XXXX PNG chunk not known".ToCharArray();
                            invalid_chunk[0] = (char)(c.type >> 24);
                            invalid_chunk[1] = (char)(c.type >> 16);
                            invalid_chunk[2] = (char)(c.type >> 8);
                            invalid_chunk[3] = (char)(c.type >> 0);
                            throw new Exception(new string(invalid_chunk) + ":PNG not supported: unknown PNG chunk type");
                        }
                        stbi__skip(s, (int)c.length);
                        break;
                }
                // end of PNG chunk, read and skip CRC
                stbi__get32be(s);
            }
        }
Ejemplo n.º 14
0
        static int stbi__expand_png_palette(stbi__png* a, byte* palette, int len, int pal_img_n)
        {
            uint i, pixel_count = a->s->img_x * a->s->img_y;
            byte* p;
            byte* temp_out;
            byte* orig = a->Out;

            p = (byte*)CLib.CStdlib.malloc((int)(pixel_count * pal_img_n));
            if (p == null) throw new Exception("outofmem:Out of memory");

            // between here and free(out) below, exitting would leak
            temp_out = p;

            if (pal_img_n == 3)
            {
                for (i = 0; i < pixel_count; ++i)
                {
                    int n = orig[i] * 4;
                    p[0] = palette[n];
                    p[1] = palette[n + 1];
                    p[2] = palette[n + 2];
                    p += 3;
                }
            }
            else
            {
                for (i = 0; i < pixel_count; ++i)
                {
                    int n = orig[i] * 4;
                    p[0] = palette[n];
                    p[1] = palette[n + 1];
                    p[2] = palette[n + 2];
                    p[3] = palette[n + 3];
                    p += 4;
                }
            }
            CLib.CStdlib.free(a->Out);
            a->Out = temp_out;

            //STBI_NOTUSED(len);

            return 1;
        }
Ejemplo n.º 15
0
        static byte* stbi__do_png(stbi__png* p, int* x, int* y, int* n, int req_comp)
        {
            byte* result = null;
            if (req_comp < 0 || req_comp > 4) throw new Exception("bad req_comp:Internal error");
            if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp) != 0)
            {
                result = p->Out;
                p->Out = null;
                if (req_comp != 0 && req_comp != p->s->img_out_n)
                {
                    result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
                    p->s->img_out_n = req_comp;
                    if (result == null) return result;
                }
                *x = (int)p->s->img_x;
                *y = (int)p->s->img_y;
                if (n != null) *n = p->s->img_out_n;
            }
            CLib.CStdlib.free(p->Out); p->Out = null;
            CLib.CStdlib.free(p->expanded); p->expanded = null;
            CLib.CStdlib.free(p->idata); p->idata = null;

            return result;
        }
Ejemplo n.º 16
0
        static void stbi__de_iphone(stbi__png* z)
        {
            stbi__context* s = z->s;
            uint i, pixel_count = s->img_x * s->img_y;
            byte* p = z->Out;

            if (s->img_out_n == 3)
            {  // convert bgr to rgb
                for (i = 0; i < pixel_count; ++i)
                {
                    byte t = p[0];
                    p[0] = p[2];
                    p[2] = t;
                    p += 3;
                }
            }
            else
            {
                Debug.Assert(s->img_out_n == 4);
                if (stbi__unpremultiply_on_load != 0)
                {
                    // convert bgr to rgb and unpremultiply
                    for (i = 0; i < pixel_count; ++i)
                    {
                        byte a = p[3];
                        byte t = p[0];
                        if (a != 0)
                        {
                            p[0] = (byte)(p[2] * 255 / a);
                            p[1] = (byte)(p[1] * 255 / a);
                            p[2] = (byte)(t * 255 / a);
                        }
                        else
                        {
                            p[0] = p[2];
                            p[2] = t;
                        }
                        p += 4;
                    }
                }
                else
                {
                    // convert bgr to rgb
                    for (i = 0; i < pixel_count; ++i)
                    {
                        byte t = p[0];
                        p[0] = p[2];
                        p[2] = t;
                        p += 4;
                    }
                }
            }
        }
Ejemplo n.º 17
0
        // create the png data from post-deflated data
        static int stbi__create_png_image_raw(stbi__png* a, byte* raw, uint raw_len, int out_n, uint x, uint y, int depth, int color)
        {
            stbi__context* s = a->s;
            uint i, j, stride = x * (uint)out_n;
            uint img_len, img_width_bytes;
            int k;
            int img_n = s->img_n; // copy it into a local for later

            Debug.Assert(out_n == s->img_n || out_n == s->img_n + 1);
            a->Out = (byte*)CLib.CStdlib.malloc((int)x * (int)y * out_n); // extra bytes to write off the end into
            if (a->Out == null) throw new Exception("outofmem:Out of memory");

            img_width_bytes = ((((uint)img_n * x * (uint)depth) + 7) >> 3);
            img_len = (img_width_bytes + 1) * y;
            if (s->img_x == x && s->img_y == y)
            {
                if (raw_len != img_len) throw new Exception("not enough pixels:Corrupt PNG");
            }
            else
            { // interlaced:
                if (raw_len < img_len) throw new Exception("not enough pixels:Corrupt PNG");
            }

            for (j = 0; j < y; ++j)
            {
                byte* cur = a->Out + stride * j;
                byte* prior = cur - stride;
                int filter = *raw++;
                int filter_bytes = img_n;
                int width = (int)x;
                if (filter > 4)
                    throw new Exception("invalid filter:Corrupt PNG");

                if (depth < 8)
                {
                    Debug.Assert(img_width_bytes <= x);
                    cur += x * out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
                    filter_bytes = 1;
                    width = (int)img_width_bytes;
                }

                // if first row, use special filter that doesn't sample previous row
                if (j == 0) filter = first_row_filter[filter];

                // handle first byte explicitly
                for (k = 0; k < filter_bytes; ++k)
                {
                    switch (filter)
                    {
                        case STBI__F_none: cur[k] = raw[k]; break;
                        case STBI__F_sub: cur[k] = raw[k]; break;
                        case STBI__F_up: cur[k] = (byte)(raw[k] + prior[k]); break;
                        case STBI__F_avg: cur[k] = (byte)(raw[k] + (prior[k] >> 1)); break;
                        case STBI__F_paeth: cur[k] = (byte)(raw[k] + stbi__paeth(0, prior[k], 0)); break;
                        case STBI__F_avg_first: cur[k] = raw[k]; break;
                        case STBI__F_paeth_first: cur[k] = raw[k]; break;
                    }
                }

                if (depth == 8)
                {
                    if (img_n != out_n)
                        cur[img_n] = 255; // first pixel
                    raw += img_n;
                    cur += out_n;
                    prior += out_n;
                }
                else
                {
                    raw += 1;
                    cur += 1;
                    prior += 1;
                }

                // this is a little gross, so that we don't switch per-pixel or per-component
                if (depth < 8 || img_n == out_n)
                {
                    int nk = (width - 1) * img_n;
                    switch (filter)
                    {
                        // "none" filter turns into a memcpy here; make that explicit.
                        case STBI__F_none: CLib.CString.memcpy(cur, raw, (uint)nk); break;
                        case STBI__F_sub: for (k = 0; k < nk; ++k) cur[k] = (byte)(raw[k] + cur[k - filter_bytes]); break;
                        case STBI__F_up: for (k = 0; k < nk; ++k) cur[k] = (byte)(raw[k] + prior[k]); break;
                        case STBI__F_avg: for (k = 0; k < nk; ++k) cur[k] = (byte)(raw[k] + ((prior[k] + cur[k - filter_bytes]) >> 1)); break;
                        case STBI__F_paeth: for (k = 0; k < nk; ++k) cur[k] = (byte)(raw[k] + stbi__paeth(cur[k - filter_bytes], prior[k], prior[k - filter_bytes])); break;
                        case STBI__F_avg_first: for (k = 0; k < nk; ++k) cur[k] = (byte)(raw[k] + (cur[k - filter_bytes] >> 1)); break;
                        case STBI__F_paeth_first: for (k = 0; k < nk; ++k) cur[k] = (byte)(raw[k] + stbi__paeth(cur[k - filter_bytes], 0, 0)); break;
                    }
                    raw += nk;
                }
                else
                {
                    switch (filter)
                    {
                        case STBI__F_none: for (i = x - 1; i >= 1; --i, cur[img_n] = 255, raw += img_n, cur += out_n, prior += out_n) for (k = 0; k < img_n; ++k) cur[k] = raw[k]; break;
                        case STBI__F_sub: for (i = x - 1; i >= 1; --i, cur[img_n] = 255, raw += img_n, cur += out_n, prior += out_n) for (k = 0; k < img_n; ++k) cur[k] = (byte)(raw[k] + cur[k - out_n]); break;
                        case STBI__F_up: for (i = x - 1; i >= 1; --i, cur[img_n] = 255, raw += img_n, cur += out_n, prior += out_n) for (k = 0; k < img_n; ++k) cur[k] = (byte)(raw[k] + prior[k]); break;
                        case STBI__F_avg: for (i = x - 1; i >= 1; --i, cur[img_n] = 255, raw += img_n, cur += out_n, prior += out_n) for (k = 0; k < img_n; ++k) cur[k] = (byte)(raw[k] + ((prior[k] + cur[k - out_n]) >> 1)); break;
                        case STBI__F_paeth: for (i = x - 1; i >= 1; --i, cur[img_n] = 255, raw += img_n, cur += out_n, prior += out_n) for (k = 0; k < img_n; ++k) cur[k] = (byte)(raw[k] + stbi__paeth(cur[k - out_n], prior[k], prior[k - out_n])); break;
                        case STBI__F_avg_first: for (i = x - 1; i >= 1; --i, cur[img_n] = 255, raw += img_n, cur += out_n, prior += out_n) for (k = 0; k < img_n; ++k) cur[k] = (byte)(raw[k] + (cur[k - out_n] >> 1)); break;
                        case STBI__F_paeth_first: for (i = x - 1; i >= 1; --i, cur[img_n] = 255, raw += img_n, cur += out_n, prior += out_n) for (k = 0; k < img_n; ++k) cur[k] = (byte)(raw[k] + stbi__paeth(cur[k - out_n], 0, 0)); break;
                    }
                }
            }

            // we make a separate pass to expand bits to pixels; for performance,
            // this could run two scanlines behind the above code, so it won't
            // intefere with filtering but will still be in the cache.
            if (depth < 8)
            {
                for (j = 0; j < y; ++j)
                {
                    byte* cur = a->Out + stride * j;
                    byte* In = a->Out + stride * j + x * out_n - img_width_bytes;
                    // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
                    // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
                    byte scale = (color == 0) ? (byte)stbi__depth_scale_table[depth] : (byte)1; // scale grayscale values to 0..255 range

                    // note that the final byte might overshoot and write more data than desired.
                    // we can allocate enough data that this never writes out of memory, but it
                    // could also overwrite the next scanline. can it overwrite non-empty data
                    // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
                    // so we need to explicitly clamp the final ones

                    if (depth == 4)
                    {
                        for (k = (int)x * img_n; k >= 2; k -= 2, ++In)
                        {
                            *cur++ = (byte)(scale * ((*In >> 4)));
                            *cur++ = (byte)(scale * ((*In) & 0x0f));
                        }
                        if (k > 0) *cur++ = (byte)(scale * ((*In >> 4)));
                    }
                    else if (depth == 2)
                    {
                        for (k = (int)x * img_n; k >= 4; k -= 4, ++In)
                        {
                            *cur++ = (byte)(scale * ((*In >> 6)));
                            *cur++ = (byte)(scale * ((*In >> 4) & 0x03));
                            *cur++ = (byte)(scale * ((*In >> 2) & 0x03));
                            *cur++ = (byte)(scale * ((*In) & 0x03));
                        }
                        if (k > 0) *cur++ = (byte)(scale * ((*In >> 6)));
                        if (k > 1) *cur++ = (byte)(scale * ((*In >> 4) & 0x03));
                        if (k > 2) *cur++ = (byte)(scale * ((*In >> 2) & 0x03));
                    }
                    else if (depth == 1)
                    {
                        for (k = (int)x * img_n; k >= 8; k -= 8, ++In)
                        {
                            *cur++ = (byte)(scale * ((*In >> 7)));
                            *cur++ = (byte)(scale * ((*In >> 6) & 0x01));
                            *cur++ = (byte)(scale * ((*In >> 5) & 0x01));
                            *cur++ = (byte)(scale * ((*In >> 4) & 0x01));
                            *cur++ = (byte)(scale * ((*In >> 3) & 0x01));
                            *cur++ = (byte)(scale * ((*In >> 2) & 0x01));
                            *cur++ = (byte)(scale * ((*In >> 1) & 0x01));
                            *cur++ = (byte)(scale * ((*In) & 0x01));
                        }
                        if (k > 0) *cur++ = (byte)(scale * ((*In >> 7)));
                        if (k > 1) *cur++ = (byte)(scale * ((*In >> 6) & 0x01));
                        if (k > 2) *cur++ = (byte)(scale * ((*In >> 5) & 0x01));
                        if (k > 3) *cur++ = (byte)(scale * ((*In >> 4) & 0x01));
                        if (k > 4) *cur++ = (byte)(scale * ((*In >> 3) & 0x01));
                        if (k > 5) *cur++ = (byte)(scale * ((*In >> 2) & 0x01));
                        if (k > 6) *cur++ = (byte)(scale * ((*In >> 1) & 0x01));
                    }
                    if (img_n != out_n)
                    {
                        // insert alpha = 255
                        byte* cur2 = a->Out + stride * j;
                        int ii;
                        if (img_n == 1)
                        {
                            for (ii = (int)x - 1; ii >= 0; --ii)
                            {
                                cur2[ii * 2 + 1] = 255;
                                cur2[ii * 2 + 0] = cur2[ii];
                            }
                        }
                        else
                        {
                            Debug.Assert(img_n == 3);
                            for (ii = (int)x - 1; ii >= 0; --ii)
                            {
                                cur2[ii * 4 + 3] = 255;
                                cur2[ii * 4 + 2] = cur2[ii * 3 + 2];
                                cur2[ii * 4 + 1] = cur2[ii * 3 + 1];
                                cur2[ii * 4 + 0] = cur2[ii * 3 + 0];
                            }
                        }
                    }
                }
            }

            return 1;
        }
Ejemplo n.º 18
0
        public static int stbi__parse_png_file(stbi__png z, int scan, int req_comp)
        {
            var palette   = stackalloc byte[1024];
            var pal_img_n = (byte)0;
            var has_trans = (byte)0;
            var tc        = stackalloc byte[3];

            tc[0] = 0;

            var  tc16        = stackalloc ushort[3];
            var  ioff        = (uint)0;
            var  idata_limit = (uint)0;
            uint i           = 0;
            var  pal_len     = (uint)0;
            var  first       = 1;
            var  k           = 0;
            var  interlace   = 0;
            var  color       = 0;
            var  is_iphone   = 0;
            var  s           = z.s;

            z.expanded = null;
            z.idata    = null;
            z._out_    = null;
            if (stbi__check_png_header(s) == 0)
            {
                return(0);
            }
            if (scan == STBI__SCAN_type)
            {
                return(1);
            }
            for (; ;)
            {
                var c = stbi__get_chunk_header(s);
                switch (c.type)
                {
                case ((uint)'C' << 24) + ((uint)'g' << 16) + ((uint)'B' << 8) + 'I':
                    is_iphone = 1;
                    stbi__skip(s, (int)c.length);
                    break;

                case ((uint)'I' << 24) + ((uint)'H' << 16) + ((uint)'D' << 8) + 'R':
                {
                    var comp   = 0;
                    var filter = 0;
                    if (first == 0)
                    {
                        return(stbi__err("multiple IHDR"));
                    }
                    first = 0;
                    if (c.length != 13)
                    {
                        return(stbi__err("bad IHDR len"));
                    }
                    s.img_x = stbi__get32be(s);
                    if (s.img_x > 1 << 24)
                    {
                        return(stbi__err("too large"));
                    }
                    s.img_y = stbi__get32be(s);
                    if (s.img_y > 1 << 24)
                    {
                        return(stbi__err("too large"));
                    }
                    z.depth = stbi__get8(s);
                    if (z.depth != 1 && z.depth != 2 && z.depth != 4 && z.depth != 8 && z.depth != 16)
                    {
                        return(stbi__err("1/2/4/8/16-bit only"));
                    }
                    color = stbi__get8(s);
                    if (color > 6)
                    {
                        return(stbi__err("bad ctype"));
                    }
                    if (color == 3 && z.depth == 16)
                    {
                        return(stbi__err("bad ctype"));
                    }
                    if (color == 3)
                    {
                        pal_img_n = 3;
                    }
                    else if ((color & 1) != 0)
                    {
                        return(stbi__err("bad ctype"));
                    }
                    comp = stbi__get8(s);
                    if (comp != 0)
                    {
                        return(stbi__err("bad comp method"));
                    }
                    filter = stbi__get8(s);
                    if (filter != 0)
                    {
                        return(stbi__err("bad filter method"));
                    }
                    interlace = stbi__get8(s);
                    if (interlace > 1)
                    {
                        return(stbi__err("bad interlace method"));
                    }
                    if (s.img_x == 0 || s.img_y == 0)
                    {
                        return(stbi__err("0-pixel image"));
                    }
                    if (pal_img_n == 0)
                    {
                        s.img_n = ((color & 2) != 0 ? 3 : 1) + ((color & 4) != 0 ? 1 : 0);
                        if ((1 << 30) / s.img_x / s.img_n < s.img_y)
                        {
                            return(stbi__err("too large"));
                        }
                        if (scan == STBI__SCAN_header)
                        {
                            return(1);
                        }
                    }
                    else
                    {
                        s.img_n = 1;
                        if ((1 << 30) / s.img_x / 4 < s.img_y)
                        {
                            return(stbi__err("too large"));
                        }
                    }

                    break;
                }

                case ((uint)'P' << 24) + ((uint)'L' << 16) + ((uint)'T' << 8) + 'E':
                {
                    if (first != 0)
                    {
                        return(stbi__err("first not IHDR"));
                    }
                    if (c.length > 256 * 3)
                    {
                        return(stbi__err("invalid PLTE"));
                    }
                    pal_len = c.length / 3;
                    if (pal_len * 3 != c.length)
                    {
                        return(stbi__err("invalid PLTE"));
                    }
                    for (i = (uint)0; i < pal_len; ++i)
                    {
                        palette[i * 4 + 0] = stbi__get8(s);
                        palette[i * 4 + 1] = stbi__get8(s);
                        palette[i * 4 + 2] = stbi__get8(s);
                        palette[i * 4 + 3] = 255;
                    }

                    break;
                }

                case ((uint)'t' << 24) + ((uint)'R' << 16) + ((uint)'N' << 8) + 'S':
                {
                    if (first != 0)
                    {
                        return(stbi__err("first not IHDR"));
                    }
                    if (z.idata != null)
                    {
                        return(stbi__err("tRNS after IDAT"));
                    }
                    if (pal_img_n != 0)
                    {
                        if (scan == STBI__SCAN_header)
                        {
                            s.img_n = 4;
                            return(1);
                        }

                        if (pal_len == 0)
                        {
                            return(stbi__err("tRNS before PLTE"));
                        }
                        if (c.length > pal_len)
                        {
                            return(stbi__err("bad tRNS len"));
                        }
                        pal_img_n = 4;
                        for (i = (uint)0; i < c.length; ++i)
                        {
                            palette[i * 4 + 3] = stbi__get8(s);
                        }
                    }
                    else
                    {
                        if ((s.img_n & 1) == 0)
                        {
                            return(stbi__err("tRNS with alpha"));
                        }
                        if (c.length != (uint)s.img_n * 2)
                        {
                            return(stbi__err("bad tRNS len"));
                        }
                        has_trans = 1;
                        if (z.depth == 16)
                        {
                            for (k = 0; k < s.img_n; ++k)
                            {
                                tc16[k] = (ushort)stbi__get16be(s);
                            }
                        }
                        else
                        {
                            for (k = 0; k < s.img_n; ++k)
                            {
                                tc[k] = (byte)((byte)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z.depth]);
                            }
                        }
                    }

                    break;
                }

                case ((uint)'I' << 24) + ((uint)'D' << 16) + ((uint)'A' << 8) + 'T':
                {
                    if (first != 0)
                    {
                        return(stbi__err("first not IHDR"));
                    }
                    if (pal_img_n != 0 && pal_len == 0)
                    {
                        return(stbi__err("no PLTE"));
                    }
                    if (scan == STBI__SCAN_header)
                    {
                        s.img_n = pal_img_n;
                        return(1);
                    }

                    if ((int)(ioff + c.length) < (int)ioff)
                    {
                        return(0);
                    }
                    if (ioff + c.length > idata_limit)
                    {
                        var   idata_limit_old = idata_limit;
                        byte *p;
                        if (idata_limit == 0)
                        {
                            idata_limit = c.length > 4096 ? c.length : 4096;
                        }
                        while (ioff + c.length > idata_limit)
                        {
                            idata_limit *= 2;
                        }
                        p = (byte *)CRuntime.realloc(z.idata, (ulong)idata_limit);
                        if (p == null)
                        {
                            return(stbi__err("outofmem"));
                        }
                        z.idata = p;
                    }

                    if (stbi__getn(s, z.idata + ioff, (int)c.length) == 0)
                    {
                        return(stbi__err("outofdata"));
                    }
                    ioff += c.length;
                    break;
                }

                case ((uint)'I' << 24) + ((uint)'E' << 16) + ((uint)'N' << 8) + 'D':
                {
                    uint raw_len = 0;
                    uint bpl     = 0;
                    if (first != 0)
                    {
                        return(stbi__err("first not IHDR"));
                    }
                    if (scan != STBI__SCAN_load)
                    {
                        return(1);
                    }
                    if (z.idata == null)
                    {
                        return(stbi__err("no IDAT"));
                    }
                    bpl        = (uint)((s.img_x * z.depth + 7) / 8);
                    raw_len    = (uint)(bpl * s.img_y * s.img_n + s.img_y);
                    z.expanded = (byte *)stbi_zlib_decode_malloc_guesssize_headerflag((sbyte *)z.idata, (int)ioff,
                                                                                      (int)raw_len, (int *)&raw_len, is_iphone != 0 ? 0 : 1);
                    if (z.expanded == null)
                    {
                        return(0);
                    }
                    CRuntime.free(z.idata);
                    z.idata = null;
                    if (req_comp == s.img_n + 1 && req_comp != 3 && pal_img_n == 0 || has_trans != 0)
                    {
                        s.img_out_n = s.img_n + 1;
                    }
                    else
                    {
                        s.img_out_n = s.img_n;
                    }
                    if (stbi__create_png_image(z, z.expanded, raw_len, s.img_out_n, z.depth, color, interlace) == 0)
                    {
                        return(0);
                    }
                    if (has_trans != 0)
                    {
                        if (z.depth == 16)
                        {
                            if (stbi__compute_transparency16(z, tc16, s.img_out_n) == 0)
                            {
                                return(0);
                            }
                        }
                        else
                        {
                            if (stbi__compute_transparency(z, tc, s.img_out_n) == 0)
                            {
                                return(0);
                            }
                        }
                    }

                    if (is_iphone != 0 && stbi__de_iphone_flag != 0 && s.img_out_n > 2)
                    {
                        stbi__de_iphone(z);
                    }
                    if (pal_img_n != 0)
                    {
                        s.img_n     = pal_img_n;
                        s.img_out_n = pal_img_n;
                        if (req_comp >= 3)
                        {
                            s.img_out_n = req_comp;
                        }
                        if (stbi__expand_png_palette(z, palette, (int)pal_len, s.img_out_n) == 0)
                        {
                            return(0);
                        }
                    }
                    else if (has_trans != 0)
                    {
                        ++s.img_n;
                    }

                    CRuntime.free(z.expanded);
                    z.expanded = null;
                    return(1);
                }

                default:
                    if (first != 0)
                    {
                        return(stbi__err("first not IHDR"));
                    }
                    if ((c.type & (1 << 29)) == 0)
                    {
                        var invalid_chunk = c.type + " PNG chunk not known";
                        return(stbi__err(invalid_chunk));
                    }

                    stbi__skip(s, (int)c.length);
                    break;
                }

                stbi__get32be(s);
            }
        }
Ejemplo n.º 19
0
        public static int stbi__create_png_image_raw(stbi__png a, byte *raw, uint raw_len, int out_n, uint x, uint y,
                                                     int depth, int color)
        {
            var  bytes           = depth == 16 ? 2 : 1;
            var  s               = a.s;
            uint i               = 0;
            uint j               = 0;
            var  stride          = (uint)(x * out_n * bytes);
            uint img_len         = 0;
            uint img_width_bytes = 0;
            var  k               = 0;
            var  img_n           = s.img_n;
            var  output_bytes    = out_n * bytes;
            var  filter_bytes    = img_n * bytes;
            var  width           = (int)x;

            a._out_ = (byte *)stbi__malloc_mad3((int)x, (int)y, output_bytes, 0);
            if (a._out_ == null)
            {
                return(stbi__err("outofmem"));
            }
            if (stbi__mad3sizes_valid(img_n, (int)x, depth, 7) == 0)
            {
                return(stbi__err("too large"));
            }
            img_width_bytes = (uint)((img_n * x * depth + 7) >> 3);
            img_len         = (img_width_bytes + 1) * y;
            if (raw_len < img_len)
            {
                return(stbi__err("not enough pixels"));
            }
            for (j = (uint)0; j < y; ++j)
            {
                var   cur = a._out_ + stride * j;
                byte *prior;
                var   filter = (int)*raw++;
                if (filter > 4)
                {
                    return(stbi__err("invalid filter"));
                }
                if (depth < 8)
                {
                    cur         += x * out_n - img_width_bytes;
                    filter_bytes = 1;
                    width        = (int)img_width_bytes;
                }

                prior = cur - stride;
                if (j == 0)
                {
                    filter = first_row_filter[filter];
                }
                for (k = 0; k < filter_bytes; ++k)
                {
                    switch (filter)
                    {
                    case STBI__F_none:
                        cur[k] = raw[k];
                        break;

                    case STBI__F_sub:
                        cur[k] = raw[k];
                        break;

                    case STBI__F_up:
                        cur[k] = (byte)((raw[k] + prior[k]) & 255);
                        break;

                    case STBI__F_avg:
                        cur[k] = (byte)((raw[k] + (prior[k] >> 1)) & 255);
                        break;

                    case STBI__F_paeth:
                        cur[k] = (byte)((raw[k] + stbi__paeth(0, prior[k], 0)) & 255);
                        break;

                    case STBI__F_avg_first:
                        cur[k] = raw[k];
                        break;

                    case STBI__F_paeth_first:
                        cur[k] = raw[k];
                        break;
                    }
                }

                if (depth == 8)
                {
                    if (img_n != out_n)
                    {
                        cur[img_n] = 255;
                    }
                    raw   += img_n;
                    cur   += out_n;
                    prior += out_n;
                }
                else if (depth == 16)
                {
                    if (img_n != out_n)
                    {
                        cur[filter_bytes]     = 255;
                        cur[filter_bytes + 1] = 255;
                    }

                    raw   += filter_bytes;
                    cur   += output_bytes;
                    prior += output_bytes;
                }
                else
                {
                    raw   += 1;
                    cur   += 1;
                    prior += 1;
                }

                if (depth < 8 || img_n == out_n)
                {
                    var nk = (width - 1) * filter_bytes;
                    switch (filter)
                    {
                    case STBI__F_none:
                        CRuntime.memcpy(cur, raw, (ulong)nk);
                        break;

                    case STBI__F_sub:
                        for (k = 0; k < nk; ++k)
                        {
                            cur[k] = (byte)((raw[k] + cur[k - filter_bytes]) & 255);
                        }
                        break;

                    case STBI__F_up:
                        for (k = 0; k < nk; ++k)
                        {
                            cur[k] = (byte)((raw[k] + prior[k]) & 255);
                        }
                        break;

                    case STBI__F_avg:
                        for (k = 0; k < nk; ++k)
                        {
                            cur[k] = (byte)((raw[k] + ((prior[k] + cur[k - filter_bytes]) >> 1)) & 255);
                        }
                        break;

                    case STBI__F_paeth:
                        for (k = 0; k < nk; ++k)
                        {
                            cur[k] = (byte)((raw[k] + stbi__paeth(cur[k - filter_bytes], prior[k],
                                                                  prior[k - filter_bytes])) & 255);
                        }
                        break;

                    case STBI__F_avg_first:
                        for (k = 0; k < nk; ++k)
                        {
                            cur[k] = (byte)((raw[k] + (cur[k - filter_bytes] >> 1)) & 255);
                        }
                        break;

                    case STBI__F_paeth_first:
                        for (k = 0; k < nk; ++k)
                        {
                            cur[k] = (byte)((raw[k] + stbi__paeth(cur[k - filter_bytes], 0, 0)) & 255);
                        }
                        break;
                    }

                    raw += nk;
                }
                else
                {
                    switch (filter)
                    {
                    case STBI__F_none:
                        for (i = x - 1;
                             i >= 1;
                             --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
                                 output_bytes)
                        {
                            for (k = 0; k < filter_bytes; ++k)
                            {
                                cur[k] = raw[k];
                            }
                        }
                        break;

                    case STBI__F_sub:
                        for (i = x - 1;
                             i >= 1;
                             --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
                                 output_bytes)
                        {
                            for (k = 0; k < filter_bytes; ++k)
                            {
                                cur[k] = (byte)((raw[k] + cur[k - output_bytes]) & 255);
                            }
                        }
                        break;

                    case STBI__F_up:
                        for (i = x - 1;
                             i >= 1;
                             --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
                                 output_bytes)
                        {
                            for (k = 0; k < filter_bytes; ++k)
                            {
                                cur[k] = (byte)((raw[k] + prior[k]) & 255);
                            }
                        }
                        break;

                    case STBI__F_avg:
                        for (i = x - 1;
                             i >= 1;
                             --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
                                 output_bytes)
                        {
                            for (k = 0; k < filter_bytes; ++k)
                            {
                                cur[k] = (byte)((raw[k] + ((prior[k] + cur[k - output_bytes]) >> 1)) & 255);
                            }
                        }
                        break;

                    case STBI__F_paeth:
                        for (i = x - 1;
                             i >= 1;
                             --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
                                 output_bytes)
                        {
                            for (k = 0; k < filter_bytes; ++k)
                            {
                                cur[k] = (byte)((raw[k] + stbi__paeth(cur[k - output_bytes], prior[k],
                                                                      prior[k - output_bytes])) & 255);
                            }
                        }
                        break;

                    case STBI__F_avg_first:
                        for (i = x - 1;
                             i >= 1;
                             --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
                                 output_bytes)
                        {
                            for (k = 0; k < filter_bytes; ++k)
                            {
                                cur[k] = (byte)((raw[k] + (cur[k - output_bytes] >> 1)) & 255);
                            }
                        }
                        break;

                    case STBI__F_paeth_first:
                        for (i = x - 1;
                             i >= 1;
                             --i, cur[filter_bytes] = (byte)255, raw += filter_bytes, cur += output_bytes, prior +=
                                 output_bytes)
                        {
                            for (k = 0; k < filter_bytes; ++k)
                            {
                                cur[k] = (byte)((raw[k] + stbi__paeth(cur[k - output_bytes], 0, 0)) & 255);
                            }
                        }
                        break;
                    }

                    if (depth == 16)
                    {
                        cur = a._out_ + stride * j;
                        for (i = (uint)0; i < x; ++i, cur += output_bytes)
                        {
                            cur[filter_bytes + 1] = 255;
                        }
                    }
                }
            }

            if (depth < 8)
            {
                for (j = (uint)0; j < y; ++j)
                {
                    var cur   = a._out_ + stride * j;
                    var _in_  = a._out_ + stride * j + x * out_n - img_width_bytes;
                    var scale = (byte)(color == 0 ? stbi__depth_scale_table[depth] : 1);
                    if (depth == 4)
                    {
                        for (k = (int)(x * img_n); k >= 2; k -= 2, ++_in_)
                        {
                            *cur++ = (byte)(scale * (*_in_ >> 4));
                            *cur++ = (byte)(scale * (*_in_ & 0x0f));
                        }

                        if (k > 0)
                        {
                            *cur++ = (byte)(scale * (*_in_ >> 4));
                        }
                    }
                    else if (depth == 2)
                    {
                        for (k = (int)(x * img_n); k >= 4; k -= 4, ++_in_)
                        {
                            *cur++ = (byte)(scale * (*_in_ >> 6));
                            *cur++ = (byte)(scale * ((*_in_ >> 4) & 0x03));
                            *cur++ = (byte)(scale * ((*_in_ >> 2) & 0x03));
                            *cur++ = (byte)(scale * (*_in_ & 0x03));
                        }

                        if (k > 0)
                        {
                            *cur++ = (byte)(scale * (*_in_ >> 6));
                        }
                        if (k > 1)
                        {
                            *cur++ = (byte)(scale * ((*_in_ >> 4) & 0x03));
                        }
                        if (k > 2)
                        {
                            *cur++ = (byte)(scale * ((*_in_ >> 2) & 0x03));
                        }
                    }
                    else if (depth == 1)
                    {
                        for (k = (int)(x * img_n); k >= 8; k -= 8, ++_in_)
                        {
                            *cur++ = (byte)(scale * (*_in_ >> 7));
                            *cur++ = (byte)(scale * ((*_in_ >> 6) & 0x01));
                            *cur++ = (byte)(scale * ((*_in_ >> 5) & 0x01));
                            *cur++ = (byte)(scale * ((*_in_ >> 4) & 0x01));
                            *cur++ = (byte)(scale * ((*_in_ >> 3) & 0x01));
                            *cur++ = (byte)(scale * ((*_in_ >> 2) & 0x01));
                            *cur++ = (byte)(scale * ((*_in_ >> 1) & 0x01));
                            *cur++ = (byte)(scale * (*_in_ & 0x01));
                        }

                        if (k > 0)
                        {
                            *cur++ = (byte)(scale * (*_in_ >> 7));
                        }
                        if (k > 1)
                        {
                            *cur++ = (byte)(scale * ((*_in_ >> 6) & 0x01));
                        }
                        if (k > 2)
                        {
                            *cur++ = (byte)(scale * ((*_in_ >> 5) & 0x01));
                        }
                        if (k > 3)
                        {
                            *cur++ = (byte)(scale * ((*_in_ >> 4) & 0x01));
                        }
                        if (k > 4)
                        {
                            *cur++ = (byte)(scale * ((*_in_ >> 3) & 0x01));
                        }
                        if (k > 5)
                        {
                            *cur++ = (byte)(scale * ((*_in_ >> 2) & 0x01));
                        }
                        if (k > 6)
                        {
                            *cur++ = (byte)(scale * ((*_in_ >> 1) & 0x01));
                        }
                    }

                    if (img_n != out_n)
                    {
                        var q = 0;
                        cur = a._out_ + stride * j;
                        if (img_n == 1)
                        {
                            for (q = (int)(x - 1); q >= 0; --q)
                            {
                                cur[q * 2 + 1] = 255;
                                cur[q * 2 + 0] = cur[q];
                            }
                        }
                        else
                        {
                            for (q = (int)(x - 1); q >= 0; --q)
                            {
                                cur[q * 4 + 3] = 255;
                                cur[q * 4 + 2] = cur[q * 3 + 2];
                                cur[q * 4 + 1] = cur[q * 3 + 1];
                                cur[q * 4 + 0] = cur[q * 3 + 0];
                            }
                        }
                    }
                }
            }
            else if (depth == 16)
            {
                var cur   = a._out_;
                var cur16 = (ushort *)cur;
                for (i = (uint)0; i < x * y * out_n; ++i, cur16++, cur += 2)
                {
                    *cur16 = (ushort)((cur[0] << 8) | cur[1]);
                }
            }

            return(1);
        }