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

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