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 |
|
---|
11 | using 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 |
|
---|
22 | enum
|
---|
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 |
|
---|
32 | typedef 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 |
|
---|
43 | static void *stbi__malloc( size_t size )
|
---|
44 | {
|
---|
45 | return STBI_MALLOC( size );
|
---|
46 | }
|
---|
47 |
|
---|
48 |
|
---|
49 | template < typename T >
|
---|
50 | inline 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 |
|
---|
59 | static uchar8 stbi__compute_y( int r, int g, int b )
|
---|
60 | {
|
---|
61 | return (uchar8)( ( ( r * 77 ) + ( g * 150 ) + ( 29 * b ) ) >> 8 );
|
---|
62 | }
|
---|
63 |
|
---|
64 | static 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 |
|
---|
112 | struct 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 |
|
---|
256 | private:
|
---|
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 |
|
---|
271 | enum
|
---|
272 | {
|
---|
273 | STBI__SCAN_load = 0,
|
---|
274 | STBI__SCAN_type,
|
---|
275 | STBI__SCAN_header
|
---|
276 | };
|
---|
277 |
|
---|
278 | static int stbi__png_test( stbi__context *s );
|
---|
279 | static uchar8 *stbi__png_load( stbi__context *s, int *x, int *y, int *comp, int req_comp );
|
---|
280 | static int stbi__png_info( stbi__context *s, int *x, int *y, int *comp );
|
---|
281 |
|
---|
282 | typedef struct
|
---|
283 | {
|
---|
284 | uint32 length;
|
---|
285 | uint32 type;
|
---|
286 | } stbi__pngchunk;
|
---|
287 |
|
---|
288 | static 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 |
|
---|
296 | static 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 |
|
---|
305 | typedef struct
|
---|
306 | {
|
---|
307 | stbi__context *s;
|
---|
308 | uchar8 *idata, *expanded, *out;
|
---|
309 | } stbi__png;
|
---|
310 |
|
---|
311 |
|
---|
312 | enum
|
---|
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 |
|
---|
324 | static 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 |
|
---|
333 | static int iabs( int a )
|
---|
334 | {
|
---|
335 | return a < 0 ? -a : a;
|
---|
336 | }
|
---|
337 |
|
---|
338 | static 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 |
|
---|
349 | static 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
|
---|
352 | static 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 |
|
---|
561 | static 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 |
|
---|
608 | static 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 |
|
---|
638 | static 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 |
|
---|
682 | static int stbi__unpremultiply_on_load = 0;
|
---|
683 | static int stbi__de_iphone_flag = 0;
|
---|
684 |
|
---|
685 | /*
|
---|
686 | static 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 |
|
---|
691 | static 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 |
|
---|
697 | static 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 |
|
---|
753 | static 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 |
|
---|
917 | static 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 |
|
---|
942 | static 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 |
|
---|
949 | static 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 |
|
---|
957 | static 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 |
|
---|
970 | static 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 |
|
---|
977 | static int stbi__stream_read( void *user, char *data, int size )
|
---|
978 | {
|
---|
979 | return reinterpret_cast<stream*>( user )->read( data, 1, size );
|
---|
980 | }
|
---|
981 |
|
---|
982 | static void stbi__stream_skip( void *user, int n )
|
---|
983 | {
|
---|
984 | reinterpret_cast<stream*>( user )->seek( n, origin::CUR );
|
---|
985 | }
|
---|
986 |
|
---|
987 | static int stbi__stream_eof( void *user )
|
---|
988 | {
|
---|
989 | return reinterpret_cast<stream*>( user )->eof();
|
---|
990 | }
|
---|
991 |
|
---|
992 | static stbi_io_callbacks stbi__callbacks =
|
---|
993 | {
|
---|
994 | stbi__stream_read,
|
---|
995 | stbi__stream_skip,
|
---|
996 | stbi__stream_eof,
|
---|
997 | };
|
---|
998 |
|
---|
999 | unsigned 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 |
|
---|
1014 | png_loader::png_loader() {}
|
---|
1015 |
|
---|
1016 | bool 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 |
|
---|
1040 | bool nv::png_loader::test( stream& str )
|
---|
1041 | {
|
---|
1042 | stbi__context s( &stbi__callbacks, (void *)&str );
|
---|
1043 | return stbi__png_test( &s ) != 0;
|
---|
1044 | }
|
---|
1045 |
|
---|
1046 | image_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 |
|
---|
1074 | image_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 | }
|
---|