source: trunk/src/image/png_loader.cc @ 486

Last change on this file since 486 was 486, checked in by epyon, 9 years ago
  • mass update once again...
File size: 31.0 KB
RevLine 
[484]1// Copyright (C) 2015-2015 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
6
7#include "nv/image/png_loader.hh"
8
9#include "nv/image/miniz.hh"
10
11using namespace nv;
12
13enum
14{
15        STBI_default = 0, // only used for req_comp
16
17        STBI_grey = 1,
18        STBI_grey_alpha = 2,
19        STBI_rgb = 3,
20        STBI_rgb_alpha = 4
21};
22
23typedef struct
24{
25        int( *read )  ( void *user, char *data, int size );   // fill 'data' with 'size' bytes.  return number of bytes actually read
26        void( *skip )  ( void *user, int n );                 // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
27        int( *eof )   ( void *user );                       // returns nonzero if we are at end of file/data
28} stbi_io_callbacks;
29
30#define STBI_MALLOC(sz)    nvmalloc(sz)
31#define STBI_REALLOC(p,sz) nvrealloc(p,sz)
32#define STBI_FREE(p)       nvfree(p)
33
34static void *stbi__malloc( size_t size )
35{
36        return STBI_MALLOC( size );
37}
38
39
40template < typename T >
41inline uchar8 byte_cast( T x )
42{
43        return uchar8( (x)& 255 );
44}
45
46#define stbi__err(x,y)  0
47#define stbi__errpuc(x,y)  ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))
48
49
50static uchar8 stbi__compute_y( int r, int g, int b )
51{
52        return (uchar8)( ( ( r * 77 ) + ( g * 150 ) + ( 29 * b ) ) >> 8 );
53}
54
55static unsigned char *stbi__convert_format( unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y )
56{
57        int i, j;
58        unsigned char *good;
59
60        if ( req_comp == img_n ) return data;
61        NV_ASSERT( req_comp >= 1 && req_comp <= 4, "!" );
62
63        good = (unsigned char *)stbi__malloc( req_comp * x * y );
64        if ( good == NULL )
65        {
66                STBI_FREE( data );
67                return stbi__errpuc( "outofmem", "Out of memory" );
68        }
69
70        for ( j = 0; j < (int)y; ++j )
71        {
72                unsigned char *src = data + j * x * img_n;
73                unsigned char *dest = good + j * x * req_comp;
74
75#define COMBO(a,b)  ((a)*8+(b))
76#define CASE(a,b)   case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
77                // convert source image with img_n components to one with req_comp components;
78                // avoid switch per pixel, so use switch per scanline and massive macros
79                switch ( COMBO( img_n, req_comp ) )
80                {
81                        CASE( 1, 2 ) dest[0] = src[0], dest[1] = 255; break;
82                        CASE( 1, 3 ) dest[0] = dest[1] = dest[2] = src[0]; break;
83                        CASE( 1, 4 ) dest[0] = dest[1] = dest[2] = src[0], dest[3] = 255; break;
84                        CASE( 2, 1 ) dest[0] = src[0]; break;
85                        CASE( 2, 3 ) dest[0] = dest[1] = dest[2] = src[0]; break;
86                        CASE( 2, 4 ) dest[0] = dest[1] = dest[2] = src[0], dest[3] = src[1]; break;
87                        CASE( 3, 4 ) dest[0] = src[0], dest[1] = src[1], dest[2] = src[2], dest[3] = 255; break;
88                        CASE( 3, 1 ) dest[0] = stbi__compute_y( src[0], src[1], src[2] ); break;
89                        CASE( 3, 2 ) dest[0] = stbi__compute_y( src[0], src[1], src[2] ), dest[1] = 255; break;
90                        CASE( 4, 1 ) dest[0] = stbi__compute_y( src[0], src[1], src[2] ); break;
91                        CASE( 4, 2 ) dest[0] = stbi__compute_y( src[0], src[1], src[2] ), dest[1] = src[3]; break;
92                        CASE( 4, 3 ) dest[0] = src[0], dest[1] = src[1], dest[2] = src[2]; break;
93                default: NV_ASSERT( 0, "!" );
94                }
95#undef CASE
96        }
97
98        STBI_FREE( data );
99        return good;
100}
101
102
103struct stbi__context
104{
105        uint32 img_x, img_y;
106        int img_n, img_out_n;
107
108        void rewind()
109        {
110                // conceptually rewind SHOULD rewind to the beginning of the stream,
111                // but we just rewind to the beginning of the initial buffer, because
112                // we only use it after doing 'test', which only ever looks at at most 92 bytes
113                m_img_buffer     = m_img_buffer_original;
114                m_img_buffer_end = m_img_buffer_original_end;
115        }
116
117        // initialize a memory-decode context
118        stbi__context( const uchar8* buffer, int len )
119        {
120                m_io.read = NULL;
121                m_read_from_callbacks = 0;
122                m_img_buffer          = m_img_buffer_original     = (uchar8 *)buffer;
123                m_img_buffer_end      = m_img_buffer_original_end = (uchar8 *)buffer + len;
124        }
125
126        // initialize a callback-based context
127        stbi__context( stbi_io_callbacks *c, void *user )
128        {
129                m_io = *c;
130                m_io_user_data = user;
131                m_buflen = sizeof( m_buffer_start );
132                m_read_from_callbacks = 1;
133                m_img_buffer_original = m_buffer_start;
134                refill_buffer();
135                m_img_buffer_original_end = m_img_buffer_end;
136        }
137
138        void refill_buffer()
139        {
140                int n = ( m_io.read )( m_io_user_data, (char*)m_buffer_start, m_buflen );
141                if ( n == 0 )
142                {
143                        // at end of file, treat same as if from memory, but need to handle case
144                        // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file
145                        m_read_from_callbacks = 0;
146                        m_img_buffer = m_buffer_start;
147                        m_img_buffer_end = m_buffer_start + 1;
148                        *m_img_buffer = 0;
149                }
150                else
151                {
152                        m_img_buffer = m_buffer_start;
153                        m_img_buffer_end = m_buffer_start + n;
154                }
155        }
156
157        uchar8 get8()
158        {
159                if ( m_img_buffer < m_img_buffer_end )
160                        return *m_img_buffer++;
161                if ( m_read_from_callbacks )
162                {
163                        refill_buffer();
164                        return *m_img_buffer++;
165                }
166                return 0;
167        }
168
169        inline int at_eof()
170        {
171                if ( m_io.read )
172                {
173                        if ( !( m_io.eof )( m_io_user_data ) ) return 0;
174                        // if feof() is true, check if buffer = end
175                        // special case: we've only got the special 0 character at the end
176                        if ( m_read_from_callbacks == 0 ) return 1;
177                }
178
179                return m_img_buffer >= m_img_buffer_end;
180        }
181
182        void skip( int n )
183        {
184                if ( n < 0 )
185                {
186                        m_img_buffer = m_img_buffer_end;
187                        return;
188                }
189                if ( m_io.read )
190                {
191                        int blen = (int)( m_img_buffer_end - m_img_buffer );
192                        if ( blen < n )
193                        {
194                                m_img_buffer = m_img_buffer_end;
195                                ( m_io.skip )( m_io_user_data, n - blen );
196                                return;
197                        }
198                }
199                m_img_buffer += n;
200        }
201
202        int getn( uchar8 *buffer, int n )
203        {
204                if ( m_io.read )
205                {
206                        int blen = (int)( m_img_buffer_end - m_img_buffer );
207                        if ( blen < n )
208                        {
209                                int res, count;
210
211                                nvmemcpy( buffer, m_img_buffer, blen );
212
213                                count = ( m_io.read )( m_io_user_data, (char*)buffer + blen, n - blen );
214                                res = ( count == ( n - blen ) );
215                                m_img_buffer = m_img_buffer_end;
216                                return res;
217                        }
218                }
219
220                if ( m_img_buffer + n <= m_img_buffer_end )
221                {
222                        nvmemcpy( buffer, m_img_buffer, n );
223                        m_img_buffer += n;
224                        return 1;
225                }
226                else
227                        return 0;
228        }
229
230        inline int get16be()
231        {
232                int z = get8();
233                return ( z << 8 ) + get8();
234        }
235
236        inline uint32 get32be()
237        {
238                uint32 z = get16be();
239                return ( z << 16 ) + get16be();
240        }
241
242        int remaining()
243        {
244                return m_img_buffer_end - m_img_buffer;
245        }
246
247private:
248        stbi_io_callbacks m_io;
249        void* m_io_user_data;
250
251        int m_read_from_callbacks;
252        int m_buflen;
253        uchar8 m_buffer_start[128];
254
255        uchar8 *m_img_buffer, *m_img_buffer_end;
256        uchar8 *m_img_buffer_original, *m_img_buffer_original_end;
257
258
259};
260
261
262enum
263{
264        STBI__SCAN_load = 0,
265        STBI__SCAN_type,
266        STBI__SCAN_header
267};
268
269static int      stbi__png_test( stbi__context *s );
270static uchar8 *stbi__png_load( stbi__context *s, int *x, int *y, int *comp, int req_comp );
271static int      stbi__png_info( stbi__context *s, int *x, int *y, int *comp );
272
273typedef struct
274{
275        uint32 length;
276        uint32 type;
277} stbi__pngchunk;
278
279static stbi__pngchunk stbi__get_chunk_header( stbi__context *s )
280{
281        stbi__pngchunk c;
282        c.length = s->get32be();
283        c.type = s->get32be();
284        return c;
285}
286
287static int stbi__check_png_header( stbi__context *s )
288{
289        static uchar8 png_sig[8] = { 137,80,78,71,13,10,26,10 };
290        int i;
291        for ( i = 0; i < 8; ++i )
292                if ( s->get8() != png_sig[i] ) return stbi__err( "bad png sig", "Not a PNG" );
293        return 1;
294}
295
296typedef struct
297{
298        stbi__context *s;
299        uchar8 *idata, *expanded, *out;
300} stbi__png;
301
302
303enum
304{
305        STBI__F_none = 0,
306        STBI__F_sub = 1,
307        STBI__F_up = 2,
308        STBI__F_avg = 3,
309        STBI__F_paeth = 4,
310        // synthetic filters used for first scanline to avoid needing a dummy row of 0s
311        STBI__F_avg_first,
312        STBI__F_paeth_first
313};
314
315static uchar8 first_row_filter[5] =
316{
317        STBI__F_none,
318        STBI__F_sub,
319        STBI__F_none,
320        STBI__F_avg_first,
321        STBI__F_paeth_first
322};
323
324static int stbi__paeth( int a, int b, int c )
325{
326        int p = a + b - c;
327        int pa = abs( p - a );
328        int pb = abs( p - b );
329        int pc = abs( p - c );
330        if ( pa <= pb && pa <= pc ) return a;
331        if ( pb <= pc ) return b;
332        return c;
333}
334
335static uchar8 stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
336
337// create the png data from post-deflated data
338static int stbi__create_png_image_raw( stbi__png *a, uchar8 *raw, uint32 raw_len, int out_n, uint32 x, uint32 y, int depth, int color )
339{
340        stbi__context *s = a->s;
341        uint32 i, j, stride = x*out_n;
342        uint32 img_len, img_width_bytes;
343        int k;
344        int img_n = s->img_n; // copy it into a local for later
345
346        NV_ASSERT( out_n == s->img_n || out_n == s->img_n + 1, "!" );
347        a->out = (uchar8 *)stbi__malloc( x * y * out_n ); // extra bytes to write off the end into
348        if ( !a->out ) return stbi__err( "outofmem", "Out of memory" );
349
350        img_width_bytes = ( ( ( img_n * x * depth ) + 7 ) >> 3 );
351        img_len = ( img_width_bytes + 1 ) * y;
352        if ( s->img_x == x && s->img_y == y )
353        {
354                if ( raw_len != img_len ) return stbi__err( "not enough pixels", "Corrupt PNG" );
355        }
356        else
357        { // interlaced:
358                if ( raw_len < img_len ) return stbi__err( "not enough pixels", "Corrupt PNG" );
359        }
360
361        for ( j = 0; j < y; ++j )
362        {
363                uchar8 *cur = a->out + stride*j;
364                uchar8 *prior = cur - stride;
365                int filter = *raw++;
366                int filter_bytes = img_n;
367                int width = x;
368                if ( filter > 4 )
369                        return stbi__err( "invalid filter", "Corrupt PNG" );
370
371                if ( depth < 8 )
372                {
373                        NV_ASSERT( img_width_bytes <= x, "!" );
374                        cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
375                        filter_bytes = 1;
376                        width = img_width_bytes;
377                }
378
379                // if first row, use special filter that doesn't sample previous row
380                if ( j == 0 ) filter = first_row_filter[filter];
381
382                // handle first byte explicitly
383                for ( k = 0; k < filter_bytes; ++k )
384                {
385                        switch ( filter )
386                        {
387                        case STBI__F_none: cur[k] = raw[k]; break;
388                        case STBI__F_sub: cur[k] = raw[k]; break;
389                        case STBI__F_up: cur[k] = byte_cast( raw[k] + prior[k] ); break;
390                        case STBI__F_avg: cur[k] = byte_cast( raw[k] + ( prior[k] >> 1 ) ); break;
391                        case STBI__F_paeth: cur[k] = byte_cast( raw[k] + stbi__paeth( 0, prior[k], 0 ) ); break;
392                        case STBI__F_avg_first: cur[k] = raw[k]; break;
393                        case STBI__F_paeth_first: cur[k] = raw[k]; break;
394                        }
395                }
396
397                if ( depth == 8 )
398                {
399                        if ( img_n != out_n )
400                                cur[img_n] = 255; // first pixel
401                        raw += img_n;
402                        cur += out_n;
403                        prior += out_n;
404                }
405                else
406                {
407                        raw += 1;
408                        cur += 1;
409                        prior += 1;
410                }
411
412                // this is a little gross, so that we don't switch per-pixel or per-component
413                if ( depth < 8 || img_n == out_n )
414                {
415                        int nk = ( width - 1 )*img_n;
416#define CASE(f) \
417             case f:     \
418                for (k=0; k < nk; ++k)
419                        switch ( filter )
420                        {
421                                // "none" filter turns into a memcpy here; make that explicit.
422                        case STBI__F_none:         nvmemcpy( cur, raw, nk ); break;
423                                CASE( STBI__F_sub )          cur[k] = byte_cast( raw[k] + cur[k - filter_bytes] ); break;
424                                CASE( STBI__F_up )           cur[k] = byte_cast( raw[k] + prior[k] ); break;
425                                CASE( STBI__F_avg )          cur[k] = byte_cast( raw[k] + ( ( prior[k] + cur[k - filter_bytes] ) >> 1 ) ); break;
426                                CASE( STBI__F_paeth )        cur[k] = byte_cast( raw[k] + stbi__paeth( cur[k - filter_bytes], prior[k], prior[k - filter_bytes] ) ); break;
427                                CASE( STBI__F_avg_first )    cur[k] = byte_cast( raw[k] + ( cur[k - filter_bytes] >> 1 ) ); break;
428                                CASE( STBI__F_paeth_first )  cur[k] = byte_cast( raw[k] + stbi__paeth( cur[k - filter_bytes], 0, 0 ) ); break;
429                        }
430#undef CASE
431                        raw += nk;
432                }
433                else
434                {
435                        NV_ASSERT( img_n + 1 == out_n, "!" );
436#define CASE(f) \
437             case f:     \
438                for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \
439                   for (k=0; k < img_n; ++k)
440                        switch ( filter )
441                        {
442                                CASE( STBI__F_none )         cur[k] = raw[k]; break;
443                                CASE( STBI__F_sub )          cur[k] = byte_cast( raw[k] + cur[k - out_n] ); break;
444                                CASE( STBI__F_up )           cur[k] = byte_cast( raw[k] + prior[k] ); break;
445                                CASE( STBI__F_avg )          cur[k] = byte_cast( raw[k] + ( ( prior[k] + cur[k - out_n] ) >> 1 ) ); break;
446                                CASE( STBI__F_paeth )        cur[k] = byte_cast( raw[k] + stbi__paeth( cur[k - out_n], prior[k], prior[k - out_n] ) ); break;
447                                CASE( STBI__F_avg_first )    cur[k] = byte_cast( raw[k] + ( cur[k - out_n] >> 1 ) ); break;
448                                CASE( STBI__F_paeth_first )  cur[k] = byte_cast( raw[k] + stbi__paeth( cur[k - out_n], 0, 0 ) ); break;
449                        }
450#undef CASE
451                }
452        }
453
454        // we make a separate pass to expand bits to pixels; for performance,
455        // this could run two scanlines behind the above code, so it won't
456        // intefere with filtering but will still be in the cache.
457        if ( depth < 8 )
458        {
459                for ( j = 0; j < y; ++j )
460                {
461                        uchar8 *cur = a->out + stride*j;
462                        uchar8 *in = a->out + stride*j + x*out_n - img_width_bytes;
463                        // 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
464                        // 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
465                        uchar8 scale = ( color == 0 ) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
466
467                                                                                                                                                                 // note that the final byte might overshoot and write more data than desired.
468                                                                                                                                                                 // we can allocate enough data that this never writes out of memory, but it
469                                                                                                                                                                 // could also overwrite the next scanline. can it overwrite non-empty data
470                                                                                                                                                                 // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
471                                                                                                                                                                 // so we need to explicitly clamp the final ones
472
473                        if ( depth == 4 )
474                        {
475                                for ( k = x*img_n; k >= 2; k -= 2, ++in )
476                                {
477                                        *cur++ = scale * ( ( *in >> 4 ) );
478                                        *cur++ = scale * ( ( *in ) & 0x0f );
479                                }
480                                if ( k > 0 ) *cur++ = scale * ( ( *in >> 4 ) );
481                        }
482                        else if ( depth == 2 )
483                        {
484                                for ( k = x*img_n; k >= 4; k -= 4, ++in )
485                                {
486                                        *cur++ = scale * ( ( *in >> 6 ) );
487                                        *cur++ = scale * ( ( *in >> 4 ) & 0x03 );
488                                        *cur++ = scale * ( ( *in >> 2 ) & 0x03 );
489                                        *cur++ = scale * ( ( *in ) & 0x03 );
490                                }
491                                if ( k > 0 ) *cur++ = scale * ( ( *in >> 6 ) );
492                                if ( k > 1 ) *cur++ = scale * ( ( *in >> 4 ) & 0x03 );
493                                if ( k > 2 ) *cur++ = scale * ( ( *in >> 2 ) & 0x03 );
494                        }
495                        else if ( depth == 1 )
496                        {
497                                for ( k = x*img_n; k >= 8; k -= 8, ++in )
498                                {
499                                        *cur++ = scale * ( ( *in >> 7 ) );
500                                        *cur++ = scale * ( ( *in >> 6 ) & 0x01 );
501                                        *cur++ = scale * ( ( *in >> 5 ) & 0x01 );
502                                        *cur++ = scale * ( ( *in >> 4 ) & 0x01 );
503                                        *cur++ = scale * ( ( *in >> 3 ) & 0x01 );
504                                        *cur++ = scale * ( ( *in >> 2 ) & 0x01 );
505                                        *cur++ = scale * ( ( *in >> 1 ) & 0x01 );
506                                        *cur++ = scale * ( ( *in ) & 0x01 );
507                                }
508                                if ( k > 0 ) *cur++ = scale * ( ( *in >> 7 ) );
509                                if ( k > 1 ) *cur++ = scale * ( ( *in >> 6 ) & 0x01 );
510                                if ( k > 2 ) *cur++ = scale * ( ( *in >> 5 ) & 0x01 );
511                                if ( k > 3 ) *cur++ = scale * ( ( *in >> 4 ) & 0x01 );
512                                if ( k > 4 ) *cur++ = scale * ( ( *in >> 3 ) & 0x01 );
513                                if ( k > 5 ) *cur++ = scale * ( ( *in >> 2 ) & 0x01 );
514                                if ( k > 6 ) *cur++ = scale * ( ( *in >> 1 ) & 0x01 );
515                        }
516                        if ( img_n != out_n )
517                        {
518                                int q;
519                                // insert alpha = 255
520                                cur = a->out + stride*j;
521                                if ( img_n == 1 )
522                                {
523                                        for ( q = x - 1; q >= 0; --q )
524                                        {
525                                                cur[q * 2 + 1] = 255;
526                                                cur[q * 2 + 0] = cur[q];
527                                        }
528                                }
529                                else
530                                {
531                                        NV_ASSERT( img_n == 3, "!" );
532                                        for ( q = x - 1; q >= 0; --q )
533                                        {
534                                                cur[q * 4 + 3] = 255;
535                                                cur[q * 4 + 2] = cur[q * 3 + 2];
536                                                cur[q * 4 + 1] = cur[q * 3 + 1];
537                                                cur[q * 4 + 0] = cur[q * 3 + 0];
538                                        }
539                                }
540                        }
541                }
542        }
543
544        return 1;
545}
546
547static int stbi__create_png_image( stbi__png *a, uchar8 *image_data, uint32 image_data_len, int out_n, int depth, int color, int interlaced )
548{
549        uchar8 *final;
550        int p;
551        if ( !interlaced )
552                return stbi__create_png_image_raw( a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color );
553
554        // de-interlacing
555        final = (uchar8 *)stbi__malloc( a->s->img_x * a->s->img_y * out_n );
556        for ( p = 0; p < 7; ++p )
557        {
558                int xorig[] = { 0,4,0,2,0,1,0 };
559                int yorig[] = { 0,0,4,0,2,0,1 };
560                int xspc[] = { 8,8,4,4,2,2,1 };
561                int yspc[] = { 8,8,8,4,4,2,2 };
562                int i, j, x, y;
563                // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1
564                x = ( a->s->img_x - xorig[p] + xspc[p] - 1 ) / xspc[p];
565                y = ( a->s->img_y - yorig[p] + yspc[p] - 1 ) / yspc[p];
566                if ( x && y )
567                {
568                        uint32 img_len = ( ( ( ( a->s->img_n * x * depth ) + 7 ) >> 3 ) + 1 ) * y;
569                        if ( !stbi__create_png_image_raw( a, image_data, image_data_len, out_n, x, y, depth, color ) )
570                        {
571                                STBI_FREE( final );
572                                return 0;
573                        }
574                        for ( j = 0; j < y; ++j )
575                        {
576                                for ( i = 0; i < x; ++i )
577                                {
578                                        int out_y = j*yspc[p] + yorig[p];
579                                        int out_x = i*xspc[p] + xorig[p];
580                                        nvmemcpy( final + out_y*a->s->img_x*out_n + out_x*out_n,
581                                                a->out + ( j*x + i )*out_n, out_n );
582                                }
583                        }
584                        STBI_FREE( a->out );
585                        image_data += img_len;
586                        image_data_len -= img_len;
587                }
588        }
589        a->out = final;
590
591        return 1;
592}
593
594static int stbi__compute_transparency( stbi__png *z, uchar8 tc[3], int out_n )
595{
596        stbi__context *s = z->s;
597        uint32 i, pixel_count = s->img_x * s->img_y;
598        uchar8 *p = z->out;
599
600        // compute color-based transparency, assuming we've
601        // already got 255 as the alpha value in the output
602        NV_ASSERT( out_n == 2 || out_n == 4, "!" );
603
604        if ( out_n == 2 )
605        {
606                for ( i = 0; i < pixel_count; ++i )
607                {
608                        p[1] = ( p[0] == tc[0] ? 0 : 255 );
609                        p += 2;
610                }
611        }
612        else
613        {
614                for ( i = 0; i < pixel_count; ++i )
615                {
616                        if ( p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2] )
617                                p[3] = 0;
618                        p += 4;
619                }
620        }
621        return 1;
622}
623
624static int stbi__expand_png_palette( stbi__png *a, uchar8 *palette, int len, int pal_img_n )
625{
626        uint32 i, pixel_count = a->s->img_x * a->s->img_y;
627        uchar8 *p, *temp_out, *orig = a->out;
628
629        p = (uchar8 *)stbi__malloc( pixel_count * pal_img_n );
630        if ( p == NULL ) return stbi__err( "outofmem", "Out of memory" );
631
632        // between here and free(out) below, exitting would leak
633        temp_out = p;
634
635        if ( pal_img_n == 3 )
636        {
637                for ( i = 0; i < pixel_count; ++i )
638                {
639                        int n = orig[i] * 4;
640                        p[0] = palette[n];
641                        p[1] = palette[n + 1];
642                        p[2] = palette[n + 2];
643                        p += 3;
644                }
645        }
646        else
647        {
648                for ( i = 0; i < pixel_count; ++i )
649                {
650                        int n = orig[i] * 4;
651                        p[0] = palette[n];
652                        p[1] = palette[n + 1];
653                        p[2] = palette[n + 2];
654                        p[3] = palette[n + 3];
655                        p += 4;
656                }
657        }
658        STBI_FREE( a->out );
659        a->out = temp_out;
660
661        NV_UNUSED( len );
662//      STBI_NOTUSED( len );
663
664        return 1;
665}
666
[486]667
[484]668static int stbi__unpremultiply_on_load = 0;
669static int stbi__de_iphone_flag = 0;
670
[486]671/*
[484]672static void stbi_set_unpremultiply_on_load( int flag_true_if_should_unpremultiply )
673{
674        stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;
675}
676
677static void stbi_convert_iphone_png_to_rgb( int flag_true_if_should_convert )
678{
679        stbi__de_iphone_flag = flag_true_if_should_convert;
680}
[486]681*/
[484]682
683static void stbi__de_iphone( stbi__png *z )
684{
685        stbi__context *s = z->s;
686        uint32 i, pixel_count = s->img_x * s->img_y;
687        uchar8 *p = z->out;
688
689        if ( s->img_out_n == 3 )
690        {  // convert bgr to rgb
691                for ( i = 0; i < pixel_count; ++i )
692                {
693                        uchar8 t = p[0];
694                        p[0] = p[2];
695                        p[2] = t;
696                        p += 3;
697                }
698        }
699        else
700        {
701                NV_ASSERT( s->img_out_n == 4, "!" );
702                if ( stbi__unpremultiply_on_load )
703                {
704                        // convert bgr to rgb and unpremultiply
705                        for ( i = 0; i < pixel_count; ++i )
706                        {
707                                uchar8 a = p[3];
708                                uchar8 t = p[0];
709                                if ( a )
710                                {
711                                        p[0] = p[2] * 255 / a;
712                                        p[1] = p[1] * 255 / a;
713                                        p[2] = t * 255 / a;
714                                }
715                                else
716                                {
717                                        p[0] = p[2];
718                                        p[2] = t;
719                                }
720                                p += 4;
721                        }
722                }
723                else
724                {
725                        // convert bgr to rgb
726                        for ( i = 0; i < pixel_count; ++i )
727                        {
728                                uchar8 t = p[0];
729                                p[0] = p[2];
730                                p[2] = t;
731                                p += 4;
732                        }
733                }
734        }
735}
736
737#define STBI__PNG_TYPE(a,b,c,d)  (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
738
739static int stbi__parse_png_file( stbi__png *z, int scan, int req_comp )
740{
741        uchar8 palette[1024], pal_img_n = 0;
742        uchar8 has_trans = 0, tc[3];
743        uint32 ioff = 0, idata_limit = 0, i, pal_len = 0;
744        int first = 1, k, interlace = 0, color = 0, depth = 0, is_iphone = 0;
745        stbi__context *s = z->s;
746
747        z->expanded = NULL;
748        z->idata = NULL;
749        z->out = NULL;
750
751        if ( !stbi__check_png_header( s ) ) return 0;
752
753        if ( scan == STBI__SCAN_type ) return 1;
754
755        for ( ;;)
756        {
757                stbi__pngchunk c = stbi__get_chunk_header( s );
758                switch ( c.type )
759                {
760                case STBI__PNG_TYPE( 'C', 'g', 'B', 'I' ):
761                        is_iphone = 1;
762                        s->skip( c.length );
763                        break;
764                case STBI__PNG_TYPE( 'I', 'H', 'D', 'R' ): {
765                        int comp, filter;
766                        if ( !first ) return stbi__err( "multiple IHDR", "Corrupt PNG" );
767                        first = 0;
768                        if ( c.length != 13 ) return stbi__err( "bad IHDR len", "Corrupt PNG" );
769                        s->img_x = s->get32be(); if ( s->img_x > ( 1 << 24 ) ) return stbi__err( "too large", "Very large image (corrupt?)" );
770                        s->img_y = s->get32be(); if ( s->img_y > ( 1 << 24 ) ) return stbi__err( "too large", "Very large image (corrupt?)" );
771                        depth = s->get8();  if ( depth != 1 && depth != 2 && depth != 4 && depth != 8 )  return stbi__err( "1/2/4/8-bit only", "PNG not supported: 1/2/4/8-bit only" );
772                        color = s->get8();  if ( color > 6 )         return stbi__err( "bad ctype", "Corrupt PNG" );
773                        if ( color == 3 ) pal_img_n = 3; else if ( color & 1 ) return stbi__err( "bad ctype", "Corrupt PNG" );
774                        comp = s->get8();  if ( comp ) return stbi__err( "bad comp method", "Corrupt PNG" );
775                        filter = s->get8();  if ( filter ) return stbi__err( "bad filter method", "Corrupt PNG" );
776                        interlace = s->get8(); if ( interlace > 1 ) return stbi__err( "bad interlace method", "Corrupt PNG" );
777                        if ( !s->img_x || !s->img_y ) return stbi__err( "0-pixel image", "Corrupt PNG" );
778                        if ( !pal_img_n )
779                        {
780                                s->img_n = ( color & 2 ? 3 : 1 ) + ( color & 4 ? 1 : 0 );
781                                if ( ( 1 << 30 ) / s->img_x / s->img_n < s->img_y ) return stbi__err( "too large", "Image too large to decode" );
782                                if ( scan == STBI__SCAN_header ) return 1;
783                        }
784                        else
785                        {
786                                // if paletted, then pal_n is our final components, and
787                                // img_n is # components to decompress/filter.
788                                s->img_n = 1;
789                                if ( ( 1 << 30 ) / s->img_x / 4 < s->img_y ) return stbi__err( "too large", "Corrupt PNG" );
790                                // if SCAN_header, have to scan to see if we have a tRNS
791                        }
792                        break;
793                }
794
795                case STBI__PNG_TYPE( 'P', 'L', 'T', 'E' ): {
796                        if ( first ) return stbi__err( "first not IHDR", "Corrupt PNG" );
797                        if ( c.length > 256 * 3 ) return stbi__err( "invalid PLTE", "Corrupt PNG" );
798                        pal_len = c.length / 3;
799                        if ( pal_len * 3 != c.length ) return stbi__err( "invalid PLTE", "Corrupt PNG" );
800                        for ( i = 0; i < pal_len; ++i )
801                        {
802                                palette[i * 4 + 0] = s->get8();
803                                palette[i * 4 + 1] = s->get8();
804                                palette[i * 4 + 2] = s->get8();
805                                palette[i * 4 + 3] = 255;
806                        }
807                        break;
808                }
809
810                case STBI__PNG_TYPE( 't', 'R', 'N', 'S' ): {
811                        if ( first ) return stbi__err( "first not IHDR", "Corrupt PNG" );
812                        if ( z->idata ) return stbi__err( "tRNS after IDAT", "Corrupt PNG" );
813                        if ( pal_img_n )
814                        {
815                                if ( scan == STBI__SCAN_header ) { s->img_n = 4; return 1; }
816                                if ( pal_len == 0 ) return stbi__err( "tRNS before PLTE", "Corrupt PNG" );
817                                if ( c.length > pal_len ) return stbi__err( "bad tRNS len", "Corrupt PNG" );
818                                pal_img_n = 4;
819                                for ( i = 0; i < c.length; ++i )
820                                        palette[i * 4 + 3] = s->get8();
821                        }
822                        else
823                        {
824                                if ( !( s->img_n & 1 ) ) return stbi__err( "tRNS with alpha", "Corrupt PNG" );
825                                if ( c.length != (uint32)s->img_n * 2 ) return stbi__err( "bad tRNS len", "Corrupt PNG" );
826                                has_trans = 1;
827                                for ( k = 0; k < s->img_n; ++k )
828                                        tc[k] = (uchar8)( s->get16be() & 255 ) * stbi__depth_scale_table[depth]; // non 8-bit images will be larger
829                        }
830                        break;
831                }
832
833                case STBI__PNG_TYPE( 'I', 'D', 'A', 'T' ): {
834                        if ( first ) return stbi__err( "first not IHDR", "Corrupt PNG" );
835                        if ( pal_img_n && !pal_len ) return stbi__err( "no PLTE", "Corrupt PNG" );
836                        if ( scan == STBI__SCAN_header ) { s->img_n = pal_img_n; return 1; }
837                        if ( (int)( ioff + c.length ) < (int)ioff ) return 0;
838                        if ( ioff + c.length > idata_limit )
839                        {
840                                uchar8 *p;
841                                if ( idata_limit == 0 ) idata_limit = c.length > 4096 ? c.length : 4096;
842                                while ( ioff + c.length > idata_limit )
843                                        idata_limit *= 2;
844                                p = (uchar8 *)STBI_REALLOC( z->idata, idata_limit ); if ( p == NULL ) return stbi__err( "outofmem", "Out of memory" );
845                                z->idata = p;
846                        }
847                        if ( !s->getn( z->idata + ioff, c.length ) ) return stbi__err( "outofdata", "Corrupt PNG" );
848                        ioff += c.length;
849                        break;
850                }
851
852                case STBI__PNG_TYPE( 'I', 'E', 'N', 'D' ): {
853                        uint32 raw_len, bpl;
854                        if ( first ) return stbi__err( "first not IHDR", "Corrupt PNG" );
855                        if ( scan != STBI__SCAN_load ) return 1;
856                        if ( z->idata == NULL ) return stbi__err( "no IDAT", "Corrupt PNG" );
857                        // initial guess for decoded data size to avoid unnecessary reallocs
858                        bpl = ( s->img_x * depth + 7 ) / 8; // bytes per line, per component
859                        raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;
860                        size_t result_len = raw_len;
861                        z->expanded = (uchar8 *)nv::miniz_decompress( (char *)z->idata, ioff, &result_len, !is_iphone );
862                        raw_len = result_len;
863
864                        if ( z->expanded == NULL ) return 0; // zlib should set error
865                        STBI_FREE( z->idata ); z->idata = NULL;
866                        if ( ( req_comp == s->img_n + 1 && req_comp != 3 && !pal_img_n ) || has_trans )
867                                s->img_out_n = s->img_n + 1;
868                        else
869                                s->img_out_n = s->img_n;
870                        if ( !stbi__create_png_image( z, z->expanded, raw_len, s->img_out_n, depth, color, interlace ) ) return 0;
871                        if ( has_trans )
872                                if ( !stbi__compute_transparency( z, tc, s->img_out_n ) ) return 0;
873                        if ( is_iphone && stbi__de_iphone_flag && s->img_out_n > 2 )
874                                stbi__de_iphone( z );
875                        if ( pal_img_n )
876                        {
877                                // pal_img_n == 3 or 4
878                                s->img_n = pal_img_n; // record the actual colors we had
879                                s->img_out_n = pal_img_n;
880                                if ( req_comp >= 3 ) s->img_out_n = req_comp;
881                                if ( !stbi__expand_png_palette( z, palette, pal_len, s->img_out_n ) )
882                                        return 0;
883                        }
884                        STBI_FREE( z->expanded ); z->expanded = NULL;
885                        return 1;
886                }
887
888                default:
889                        // if critical, fail
890                        if ( first ) return stbi__err( "first not IHDR", "Corrupt PNG" );
891                        if ( ( c.type & ( 1 << 29 ) ) == 0 )
892                        {
893                                return stbi__err( invalid_chunk, "PNG not supported: unknown PNG chunk type" );
894                        }
895                        s->skip( c.length );
896                        break;
897                }
898                // end of PNG chunk, read and skip CRC
899                s->get32be();
900        }
901}
902
903static unsigned char *stbi__do_png( stbi__png *p, int *x, int *y, int *n, int req_comp )
904{
905        unsigned char *result = NULL;
906        if ( req_comp < 0 || req_comp > 4 ) return stbi__errpuc( "bad req_comp", "Internal error" );
907        if ( stbi__parse_png_file( p, STBI__SCAN_load, req_comp ) )
908        {
909                result = p->out;
910                p->out = NULL;
911                if ( req_comp && req_comp != p->s->img_out_n )
912                {
913                        result = stbi__convert_format( result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y );
914                        p->s->img_out_n = req_comp;
915                        if ( result == NULL ) return result;
916                }
917                *x = p->s->img_x;
918                *y = p->s->img_y;
919                if ( n ) *n = p->s->img_out_n;
920        }
921        STBI_FREE( p->out );      p->out = NULL;
922        STBI_FREE( p->expanded ); p->expanded = NULL;
923        STBI_FREE( p->idata );    p->idata = NULL;
924
925        return result;
926}
927
928static unsigned char *stbi__png_load( stbi__context *s, int *x, int *y, int *comp, int req_comp )
929{
930        stbi__png p;
931        p.s = s;
932        return stbi__do_png( &p, x, y, comp, req_comp );
933}
934
935static int stbi__png_test( stbi__context *s )
936{
937        int r;
938        r = stbi__check_png_header( s );
939        s->rewind();
940        return r;
941}
942
943static int stbi__png_info_raw( stbi__png *p, int *x, int *y, int *comp )
944{
945        if ( !stbi__parse_png_file( p, STBI__SCAN_header, 0 ) )
946        {
947                p->s->rewind();
948                return 0;
949        }
950        if ( x ) *x = p->s->img_x;
951        if ( y ) *y = p->s->img_y;
952        if ( comp ) *comp = p->s->img_n;
953        return 1;
954}
955
956static int stbi__png_info( stbi__context *s, int *x, int *y, int *comp )
957{
958        stbi__png p;
959        p.s = s;
960        return stbi__png_info_raw( &p, x, y, comp );
961}
962
963static int stbi__stream_read( void *user, char *data, int size )
964{
965        return reinterpret_cast<stream*>( user )->read( data, 1, size );
966}
967
968static void stbi__stream_skip( void *user, int n )
969{
970        reinterpret_cast<stream*>( user )->seek( n, origin::CUR );
971}
972
973static int stbi__stream_eof( void *user )
974{
975        return reinterpret_cast<stream*>( user )->eof();
976}
977
978static stbi_io_callbacks stbi__callbacks =
979{
980        stbi__stream_read,
981        stbi__stream_skip,
982        stbi__stream_eof,
983};
984
985unsigned char * stbi_load( stream* f, int *x, int *y, int *comp, int req_comp )
986{
987        unsigned char *result;
988        stbi__context s( &stbi__callbacks, (void *)f );
989        result = stbi__png_load( &s, x, y, comp, req_comp );
990
991        if ( result )
992        {
993                // need to 'unget' all the characters in the IO buffer
994                f->seek( -s.remaining(), origin::CUR );
995        }
996        return result;
997}
998
999
1000png_loader::png_loader() {}
1001
1002bool nv::png_loader::get_info( stream& str, image_format& format, ivec2& size )
1003{
1004        size_t pos = str.tell();
1005        stbi__context s( &stbi__callbacks, (void *)&str );
1006        int x, y;
1007        int comp;
1008        if ( stbi__png_info( &s, &x, &y, &comp ) == 1 )
1009        {
1010                str.seek( pos, origin::SET );
1011                format.type = UBYTE;
1012                switch ( comp )
1013                {
1014                case 0: return false;
1015                case 1: format.format = RED; break;
1016                case 3: format.format = RGB; break;
1017                case 4: format.format = RGBA; break;
1018                default: return false;
1019                }
1020                size = ivec2( x, y );
1021                return true;
1022        }
1023        return false;
1024}
1025
[486]1026bool nv::png_loader::test( stream& str )
1027{
1028        stbi__context s( &stbi__callbacks, (void *)&str );
1029        return stbi__png_test( &s ) != 0;
1030}
1031
[484]1032image_data* nv::png_loader::load( stream& s )
1033{
1034        int x, y;
1035        int comp;
1036
1037        stbi__context ctx( &stbi__callbacks, (void *)&s );
1038        unsigned char *result;
1039        result = stbi__png_load( &ctx, &x, &y, &comp, 0 );
1040        if ( result )
1041        {
1042                // need to 'unget' all the characters in the IO buffer
1043                s.seek( -ctx.remaining(), origin::CUR );
1044                image_format format;
1045                ivec2 size;
1046                format.type = UBYTE;
1047                switch ( comp )
1048                {
1049                case 1: format.format = RED; break;
1050                case 3: format.format = RGB; break;
1051                case 4: format.format = RGBA; break;
1052                default: return false;
1053                }
1054                size = ivec2( x, y );
1055                return new image_data( format, size, result );
1056        }
1057        return nullptr;
1058}
1059
1060image_data* nv::png_loader::load( stream& s, image_format format )
1061{
1062        NV_ASSERT( format.type == UBYTE, "!" );
1063        int rcomp = 0;
1064        switch ( format.format )
1065        {
1066        case RED: rcomp = 1; break;
1067        case RGB: rcomp = 3; break;
1068        case RGBA: rcomp = 4; break;
1069        default: NV_ASSERT( false, "bad format requested!" ); return nullptr;
1070        }
1071        int x, y;
1072        int comp;
1073        stbi__context ctx( &stbi__callbacks, (void *)&s );
1074        unsigned char* result = stbi__png_load( &ctx, &x, &y, &comp, rcomp );
1075        if ( result )
1076        {
1077                s.seek( -ctx.remaining(), origin::CUR );
1078                image_format fmt;
1079                ivec2 sz;
1080                fmt.type = UBYTE;
1081                switch ( comp )
1082                {
1083                case 1: fmt.format = RED; break;
1084                case 3: fmt.format = RGB; break;
1085                case 4: fmt.format = RGBA; break;
1086                default: NV_ASSERT( false, "UNKNOWN RESULT!" );
1087                }
1088                sz = ivec2( x, y );
1089                return new image_data( fmt, sz, result );
1090        }
1091        return nullptr;
1092}
Note: See TracBrowser for help on using the repository browser.