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 | enum
|
---|
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 |
|
---|
23 | typedef 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 |
|
---|
34 | static void *stbi__malloc( size_t size )
|
---|
35 | {
|
---|
36 | return STBI_MALLOC( size );
|
---|
37 | }
|
---|
38 |
|
---|
39 |
|
---|
40 | template < typename T >
|
---|
41 | inline 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 |
|
---|
50 | static uchar8 stbi__compute_y( int r, int g, int b )
|
---|
51 | {
|
---|
52 | return (uchar8)( ( ( r * 77 ) + ( g * 150 ) + ( 29 * b ) ) >> 8 );
|
---|
53 | }
|
---|
54 |
|
---|
55 | static 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 |
|
---|
103 | struct 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 |
|
---|
247 | private:
|
---|
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 |
|
---|
262 | enum
|
---|
263 | {
|
---|
264 | STBI__SCAN_load = 0,
|
---|
265 | STBI__SCAN_type,
|
---|
266 | STBI__SCAN_header
|
---|
267 | };
|
---|
268 |
|
---|
269 | static int stbi__png_test( stbi__context *s );
|
---|
270 | static uchar8 *stbi__png_load( stbi__context *s, int *x, int *y, int *comp, int req_comp );
|
---|
271 | static int stbi__png_info( stbi__context *s, int *x, int *y, int *comp );
|
---|
272 |
|
---|
273 | typedef struct
|
---|
274 | {
|
---|
275 | uint32 length;
|
---|
276 | uint32 type;
|
---|
277 | } stbi__pngchunk;
|
---|
278 |
|
---|
279 | static 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 |
|
---|
287 | static 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 |
|
---|
296 | typedef struct
|
---|
297 | {
|
---|
298 | stbi__context *s;
|
---|
299 | uchar8 *idata, *expanded, *out;
|
---|
300 | } stbi__png;
|
---|
301 |
|
---|
302 |
|
---|
303 | enum
|
---|
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 |
|
---|
315 | static 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 |
|
---|
324 | static 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 |
|
---|
335 | static 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
|
---|
338 | 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 )
|
---|
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 |
|
---|
547 | 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 )
|
---|
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 |
|
---|
594 | static 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 |
|
---|
624 | static 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 |
|
---|
667 | static int stbi__unpremultiply_on_load = 0;
|
---|
668 | static int stbi__de_iphone_flag = 0;
|
---|
669 |
|
---|
670 | static void stbi_set_unpremultiply_on_load( int flag_true_if_should_unpremultiply )
|
---|
671 | {
|
---|
672 | stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;
|
---|
673 | }
|
---|
674 |
|
---|
675 | static void stbi_convert_iphone_png_to_rgb( int flag_true_if_should_convert )
|
---|
676 | {
|
---|
677 | stbi__de_iphone_flag = flag_true_if_should_convert;
|
---|
678 | }
|
---|
679 |
|
---|
680 | static void stbi__de_iphone( stbi__png *z )
|
---|
681 | {
|
---|
682 | stbi__context *s = z->s;
|
---|
683 | uint32 i, pixel_count = s->img_x * s->img_y;
|
---|
684 | uchar8 *p = z->out;
|
---|
685 |
|
---|
686 | if ( s->img_out_n == 3 )
|
---|
687 | { // convert bgr to rgb
|
---|
688 | for ( i = 0; i < pixel_count; ++i )
|
---|
689 | {
|
---|
690 | uchar8 t = p[0];
|
---|
691 | p[0] = p[2];
|
---|
692 | p[2] = t;
|
---|
693 | p += 3;
|
---|
694 | }
|
---|
695 | }
|
---|
696 | else
|
---|
697 | {
|
---|
698 | NV_ASSERT( s->img_out_n == 4, "!" );
|
---|
699 | if ( stbi__unpremultiply_on_load )
|
---|
700 | {
|
---|
701 | // convert bgr to rgb and unpremultiply
|
---|
702 | for ( i = 0; i < pixel_count; ++i )
|
---|
703 | {
|
---|
704 | uchar8 a = p[3];
|
---|
705 | uchar8 t = p[0];
|
---|
706 | if ( a )
|
---|
707 | {
|
---|
708 | p[0] = p[2] * 255 / a;
|
---|
709 | p[1] = p[1] * 255 / a;
|
---|
710 | p[2] = t * 255 / a;
|
---|
711 | }
|
---|
712 | else
|
---|
713 | {
|
---|
714 | p[0] = p[2];
|
---|
715 | p[2] = t;
|
---|
716 | }
|
---|
717 | p += 4;
|
---|
718 | }
|
---|
719 | }
|
---|
720 | else
|
---|
721 | {
|
---|
722 | // convert bgr to rgb
|
---|
723 | for ( i = 0; i < pixel_count; ++i )
|
---|
724 | {
|
---|
725 | uchar8 t = p[0];
|
---|
726 | p[0] = p[2];
|
---|
727 | p[2] = t;
|
---|
728 | p += 4;
|
---|
729 | }
|
---|
730 | }
|
---|
731 | }
|
---|
732 | }
|
---|
733 |
|
---|
734 | #define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
|
---|
735 |
|
---|
736 | static int stbi__parse_png_file( stbi__png *z, int scan, int req_comp )
|
---|
737 | {
|
---|
738 | uchar8 palette[1024], pal_img_n = 0;
|
---|
739 | uchar8 has_trans = 0, tc[3];
|
---|
740 | uint32 ioff = 0, idata_limit = 0, i, pal_len = 0;
|
---|
741 | int first = 1, k, interlace = 0, color = 0, depth = 0, is_iphone = 0;
|
---|
742 | stbi__context *s = z->s;
|
---|
743 |
|
---|
744 | z->expanded = NULL;
|
---|
745 | z->idata = NULL;
|
---|
746 | z->out = NULL;
|
---|
747 |
|
---|
748 | if ( !stbi__check_png_header( s ) ) return 0;
|
---|
749 |
|
---|
750 | if ( scan == STBI__SCAN_type ) return 1;
|
---|
751 |
|
---|
752 | for ( ;;)
|
---|
753 | {
|
---|
754 | stbi__pngchunk c = stbi__get_chunk_header( s );
|
---|
755 | switch ( c.type )
|
---|
756 | {
|
---|
757 | case STBI__PNG_TYPE( 'C', 'g', 'B', 'I' ):
|
---|
758 | is_iphone = 1;
|
---|
759 | s->skip( c.length );
|
---|
760 | break;
|
---|
761 | case STBI__PNG_TYPE( 'I', 'H', 'D', 'R' ): {
|
---|
762 | int comp, filter;
|
---|
763 | if ( !first ) return stbi__err( "multiple IHDR", "Corrupt PNG" );
|
---|
764 | first = 0;
|
---|
765 | if ( c.length != 13 ) return stbi__err( "bad IHDR len", "Corrupt PNG" );
|
---|
766 | s->img_x = s->get32be(); if ( s->img_x > ( 1 << 24 ) ) return stbi__err( "too large", "Very large image (corrupt?)" );
|
---|
767 | s->img_y = s->get32be(); if ( s->img_y > ( 1 << 24 ) ) return stbi__err( "too large", "Very large image (corrupt?)" );
|
---|
768 | 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" );
|
---|
769 | color = s->get8(); if ( color > 6 ) return stbi__err( "bad ctype", "Corrupt PNG" );
|
---|
770 | if ( color == 3 ) pal_img_n = 3; else if ( color & 1 ) return stbi__err( "bad ctype", "Corrupt PNG" );
|
---|
771 | comp = s->get8(); if ( comp ) return stbi__err( "bad comp method", "Corrupt PNG" );
|
---|
772 | filter = s->get8(); if ( filter ) return stbi__err( "bad filter method", "Corrupt PNG" );
|
---|
773 | interlace = s->get8(); if ( interlace > 1 ) return stbi__err( "bad interlace method", "Corrupt PNG" );
|
---|
774 | if ( !s->img_x || !s->img_y ) return stbi__err( "0-pixel image", "Corrupt PNG" );
|
---|
775 | if ( !pal_img_n )
|
---|
776 | {
|
---|
777 | s->img_n = ( color & 2 ? 3 : 1 ) + ( color & 4 ? 1 : 0 );
|
---|
778 | if ( ( 1 << 30 ) / s->img_x / s->img_n < s->img_y ) return stbi__err( "too large", "Image too large to decode" );
|
---|
779 | if ( scan == STBI__SCAN_header ) return 1;
|
---|
780 | }
|
---|
781 | else
|
---|
782 | {
|
---|
783 | // if paletted, then pal_n is our final components, and
|
---|
784 | // img_n is # components to decompress/filter.
|
---|
785 | s->img_n = 1;
|
---|
786 | if ( ( 1 << 30 ) / s->img_x / 4 < s->img_y ) return stbi__err( "too large", "Corrupt PNG" );
|
---|
787 | // if SCAN_header, have to scan to see if we have a tRNS
|
---|
788 | }
|
---|
789 | break;
|
---|
790 | }
|
---|
791 |
|
---|
792 | case STBI__PNG_TYPE( 'P', 'L', 'T', 'E' ): {
|
---|
793 | if ( first ) return stbi__err( "first not IHDR", "Corrupt PNG" );
|
---|
794 | if ( c.length > 256 * 3 ) return stbi__err( "invalid PLTE", "Corrupt PNG" );
|
---|
795 | pal_len = c.length / 3;
|
---|
796 | if ( pal_len * 3 != c.length ) return stbi__err( "invalid PLTE", "Corrupt PNG" );
|
---|
797 | for ( i = 0; i < pal_len; ++i )
|
---|
798 | {
|
---|
799 | palette[i * 4 + 0] = s->get8();
|
---|
800 | palette[i * 4 + 1] = s->get8();
|
---|
801 | palette[i * 4 + 2] = s->get8();
|
---|
802 | palette[i * 4 + 3] = 255;
|
---|
803 | }
|
---|
804 | break;
|
---|
805 | }
|
---|
806 |
|
---|
807 | case STBI__PNG_TYPE( 't', 'R', 'N', 'S' ): {
|
---|
808 | if ( first ) return stbi__err( "first not IHDR", "Corrupt PNG" );
|
---|
809 | if ( z->idata ) return stbi__err( "tRNS after IDAT", "Corrupt PNG" );
|
---|
810 | if ( pal_img_n )
|
---|
811 | {
|
---|
812 | if ( scan == STBI__SCAN_header ) { s->img_n = 4; return 1; }
|
---|
813 | if ( pal_len == 0 ) return stbi__err( "tRNS before PLTE", "Corrupt PNG" );
|
---|
814 | if ( c.length > pal_len ) return stbi__err( "bad tRNS len", "Corrupt PNG" );
|
---|
815 | pal_img_n = 4;
|
---|
816 | for ( i = 0; i < c.length; ++i )
|
---|
817 | palette[i * 4 + 3] = s->get8();
|
---|
818 | }
|
---|
819 | else
|
---|
820 | {
|
---|
821 | if ( !( s->img_n & 1 ) ) return stbi__err( "tRNS with alpha", "Corrupt PNG" );
|
---|
822 | if ( c.length != (uint32)s->img_n * 2 ) return stbi__err( "bad tRNS len", "Corrupt PNG" );
|
---|
823 | has_trans = 1;
|
---|
824 | for ( k = 0; k < s->img_n; ++k )
|
---|
825 | tc[k] = (uchar8)( s->get16be() & 255 ) * stbi__depth_scale_table[depth]; // non 8-bit images will be larger
|
---|
826 | }
|
---|
827 | break;
|
---|
828 | }
|
---|
829 |
|
---|
830 | case STBI__PNG_TYPE( 'I', 'D', 'A', 'T' ): {
|
---|
831 | if ( first ) return stbi__err( "first not IHDR", "Corrupt PNG" );
|
---|
832 | if ( pal_img_n && !pal_len ) return stbi__err( "no PLTE", "Corrupt PNG" );
|
---|
833 | if ( scan == STBI__SCAN_header ) { s->img_n = pal_img_n; return 1; }
|
---|
834 | if ( (int)( ioff + c.length ) < (int)ioff ) return 0;
|
---|
835 | if ( ioff + c.length > idata_limit )
|
---|
836 | {
|
---|
837 | uchar8 *p;
|
---|
838 | if ( idata_limit == 0 ) idata_limit = c.length > 4096 ? c.length : 4096;
|
---|
839 | while ( ioff + c.length > idata_limit )
|
---|
840 | idata_limit *= 2;
|
---|
841 | p = (uchar8 *)STBI_REALLOC( z->idata, idata_limit ); if ( p == NULL ) return stbi__err( "outofmem", "Out of memory" );
|
---|
842 | z->idata = p;
|
---|
843 | }
|
---|
844 | if ( !s->getn( z->idata + ioff, c.length ) ) return stbi__err( "outofdata", "Corrupt PNG" );
|
---|
845 | ioff += c.length;
|
---|
846 | break;
|
---|
847 | }
|
---|
848 |
|
---|
849 | case STBI__PNG_TYPE( 'I', 'E', 'N', 'D' ): {
|
---|
850 | uint32 raw_len, bpl;
|
---|
851 | if ( first ) return stbi__err( "first not IHDR", "Corrupt PNG" );
|
---|
852 | if ( scan != STBI__SCAN_load ) return 1;
|
---|
853 | if ( z->idata == NULL ) return stbi__err( "no IDAT", "Corrupt PNG" );
|
---|
854 | // initial guess for decoded data size to avoid unnecessary reallocs
|
---|
855 | bpl = ( s->img_x * depth + 7 ) / 8; // bytes per line, per component
|
---|
856 | raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;
|
---|
857 | size_t result_len = raw_len;
|
---|
858 | z->expanded = (uchar8 *)nv::miniz_decompress( (char *)z->idata, ioff, &result_len, !is_iphone );
|
---|
859 | raw_len = result_len;
|
---|
860 |
|
---|
861 | if ( z->expanded == NULL ) return 0; // zlib should set error
|
---|
862 | STBI_FREE( z->idata ); z->idata = NULL;
|
---|
863 | if ( ( req_comp == s->img_n + 1 && req_comp != 3 && !pal_img_n ) || has_trans )
|
---|
864 | s->img_out_n = s->img_n + 1;
|
---|
865 | else
|
---|
866 | s->img_out_n = s->img_n;
|
---|
867 | if ( !stbi__create_png_image( z, z->expanded, raw_len, s->img_out_n, depth, color, interlace ) ) return 0;
|
---|
868 | if ( has_trans )
|
---|
869 | if ( !stbi__compute_transparency( z, tc, s->img_out_n ) ) return 0;
|
---|
870 | if ( is_iphone && stbi__de_iphone_flag && s->img_out_n > 2 )
|
---|
871 | stbi__de_iphone( z );
|
---|
872 | if ( pal_img_n )
|
---|
873 | {
|
---|
874 | // pal_img_n == 3 or 4
|
---|
875 | s->img_n = pal_img_n; // record the actual colors we had
|
---|
876 | s->img_out_n = pal_img_n;
|
---|
877 | if ( req_comp >= 3 ) s->img_out_n = req_comp;
|
---|
878 | if ( !stbi__expand_png_palette( z, palette, pal_len, s->img_out_n ) )
|
---|
879 | return 0;
|
---|
880 | }
|
---|
881 | STBI_FREE( z->expanded ); z->expanded = NULL;
|
---|
882 | return 1;
|
---|
883 | }
|
---|
884 |
|
---|
885 | default:
|
---|
886 | // if critical, fail
|
---|
887 | if ( first ) return stbi__err( "first not IHDR", "Corrupt PNG" );
|
---|
888 | if ( ( c.type & ( 1 << 29 ) ) == 0 )
|
---|
889 | {
|
---|
890 | return stbi__err( invalid_chunk, "PNG not supported: unknown PNG chunk type" );
|
---|
891 | }
|
---|
892 | s->skip( c.length );
|
---|
893 | break;
|
---|
894 | }
|
---|
895 | // end of PNG chunk, read and skip CRC
|
---|
896 | s->get32be();
|
---|
897 | }
|
---|
898 | }
|
---|
899 |
|
---|
900 | static unsigned char *stbi__do_png( stbi__png *p, int *x, int *y, int *n, int req_comp )
|
---|
901 | {
|
---|
902 | unsigned char *result = NULL;
|
---|
903 | if ( req_comp < 0 || req_comp > 4 ) return stbi__errpuc( "bad req_comp", "Internal error" );
|
---|
904 | if ( stbi__parse_png_file( p, STBI__SCAN_load, req_comp ) )
|
---|
905 | {
|
---|
906 | result = p->out;
|
---|
907 | p->out = NULL;
|
---|
908 | if ( req_comp && req_comp != p->s->img_out_n )
|
---|
909 | {
|
---|
910 | result = stbi__convert_format( result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y );
|
---|
911 | p->s->img_out_n = req_comp;
|
---|
912 | if ( result == NULL ) return result;
|
---|
913 | }
|
---|
914 | *x = p->s->img_x;
|
---|
915 | *y = p->s->img_y;
|
---|
916 | if ( n ) *n = p->s->img_out_n;
|
---|
917 | }
|
---|
918 | STBI_FREE( p->out ); p->out = NULL;
|
---|
919 | STBI_FREE( p->expanded ); p->expanded = NULL;
|
---|
920 | STBI_FREE( p->idata ); p->idata = NULL;
|
---|
921 |
|
---|
922 | return result;
|
---|
923 | }
|
---|
924 |
|
---|
925 | static unsigned char *stbi__png_load( stbi__context *s, int *x, int *y, int *comp, int req_comp )
|
---|
926 | {
|
---|
927 | stbi__png p;
|
---|
928 | p.s = s;
|
---|
929 | return stbi__do_png( &p, x, y, comp, req_comp );
|
---|
930 | }
|
---|
931 |
|
---|
932 | static int stbi__png_test( stbi__context *s )
|
---|
933 | {
|
---|
934 | int r;
|
---|
935 | r = stbi__check_png_header( s );
|
---|
936 | s->rewind();
|
---|
937 | return r;
|
---|
938 | }
|
---|
939 |
|
---|
940 | static int stbi__png_info_raw( stbi__png *p, int *x, int *y, int *comp )
|
---|
941 | {
|
---|
942 | if ( !stbi__parse_png_file( p, STBI__SCAN_header, 0 ) )
|
---|
943 | {
|
---|
944 | p->s->rewind();
|
---|
945 | return 0;
|
---|
946 | }
|
---|
947 | if ( x ) *x = p->s->img_x;
|
---|
948 | if ( y ) *y = p->s->img_y;
|
---|
949 | if ( comp ) *comp = p->s->img_n;
|
---|
950 | return 1;
|
---|
951 | }
|
---|
952 |
|
---|
953 | static int stbi__png_info( stbi__context *s, int *x, int *y, int *comp )
|
---|
954 | {
|
---|
955 | stbi__png p;
|
---|
956 | p.s = s;
|
---|
957 | return stbi__png_info_raw( &p, x, y, comp );
|
---|
958 | }
|
---|
959 |
|
---|
960 | static int stbi__stream_read( void *user, char *data, int size )
|
---|
961 | {
|
---|
962 | return reinterpret_cast<stream*>( user )->read( data, 1, size );
|
---|
963 | }
|
---|
964 |
|
---|
965 | static void stbi__stream_skip( void *user, int n )
|
---|
966 | {
|
---|
967 | reinterpret_cast<stream*>( user )->seek( n, origin::CUR );
|
---|
968 | }
|
---|
969 |
|
---|
970 | static int stbi__stream_eof( void *user )
|
---|
971 | {
|
---|
972 | return reinterpret_cast<stream*>( user )->eof();
|
---|
973 | }
|
---|
974 |
|
---|
975 | static stbi_io_callbacks stbi__callbacks =
|
---|
976 | {
|
---|
977 | stbi__stream_read,
|
---|
978 | stbi__stream_skip,
|
---|
979 | stbi__stream_eof,
|
---|
980 | };
|
---|
981 |
|
---|
982 | unsigned char * stbi_load( stream* f, int *x, int *y, int *comp, int req_comp )
|
---|
983 | {
|
---|
984 | unsigned char *result;
|
---|
985 | stbi__context s( &stbi__callbacks, (void *)f );
|
---|
986 | result = stbi__png_load( &s, x, y, comp, req_comp );
|
---|
987 |
|
---|
988 | if ( result )
|
---|
989 | {
|
---|
990 | // need to 'unget' all the characters in the IO buffer
|
---|
991 | f->seek( -s.remaining(), origin::CUR );
|
---|
992 | }
|
---|
993 | return result;
|
---|
994 | }
|
---|
995 |
|
---|
996 |
|
---|
997 | png_loader::png_loader() {}
|
---|
998 |
|
---|
999 | bool nv::png_loader::get_info( stream& str, image_format& format, ivec2& size )
|
---|
1000 | {
|
---|
1001 | size_t pos = str.tell();
|
---|
1002 | stbi__context s( &stbi__callbacks, (void *)&str );
|
---|
1003 | int x, y;
|
---|
1004 | int comp;
|
---|
1005 | if ( stbi__png_info( &s, &x, &y, &comp ) == 1 )
|
---|
1006 | {
|
---|
1007 | str.seek( pos, origin::SET );
|
---|
1008 | format.type = UBYTE;
|
---|
1009 | switch ( comp )
|
---|
1010 | {
|
---|
1011 | case 0: return false;
|
---|
1012 | case 1: format.format = RED; break;
|
---|
1013 | case 3: format.format = RGB; break;
|
---|
1014 | case 4: format.format = RGBA; break;
|
---|
1015 | default: return false;
|
---|
1016 | }
|
---|
1017 | size = ivec2( x, y );
|
---|
1018 | return true;
|
---|
1019 | }
|
---|
1020 | return false;
|
---|
1021 | }
|
---|
1022 |
|
---|
1023 | image_data* nv::png_loader::load( stream& s )
|
---|
1024 | {
|
---|
1025 | int x, y;
|
---|
1026 | int comp;
|
---|
1027 |
|
---|
1028 | stbi__context ctx( &stbi__callbacks, (void *)&s );
|
---|
1029 | unsigned char *result;
|
---|
1030 | result = stbi__png_load( &ctx, &x, &y, &comp, 0 );
|
---|
1031 | if ( result )
|
---|
1032 | {
|
---|
1033 | // need to 'unget' all the characters in the IO buffer
|
---|
1034 | s.seek( -ctx.remaining(), origin::CUR );
|
---|
1035 | image_format format;
|
---|
1036 | ivec2 size;
|
---|
1037 | format.type = UBYTE;
|
---|
1038 | switch ( comp )
|
---|
1039 | {
|
---|
1040 | case 1: format.format = RED; break;
|
---|
1041 | case 3: format.format = RGB; break;
|
---|
1042 | case 4: format.format = RGBA; break;
|
---|
1043 | default: return false;
|
---|
1044 | }
|
---|
1045 | size = ivec2( x, y );
|
---|
1046 | return new image_data( format, size, result );
|
---|
1047 | }
|
---|
1048 | return nullptr;
|
---|
1049 | }
|
---|
1050 |
|
---|
1051 | image_data* nv::png_loader::load( stream& s, image_format format )
|
---|
1052 | {
|
---|
1053 | NV_ASSERT( format.type == UBYTE, "!" );
|
---|
1054 | int rcomp = 0;
|
---|
1055 | switch ( format.format )
|
---|
1056 | {
|
---|
1057 | case RED: rcomp = 1; break;
|
---|
1058 | case RGB: rcomp = 3; break;
|
---|
1059 | case RGBA: rcomp = 4; break;
|
---|
1060 | default: NV_ASSERT( false, "bad format requested!" ); return nullptr;
|
---|
1061 | }
|
---|
1062 | int x, y;
|
---|
1063 | int comp;
|
---|
1064 | stbi__context ctx( &stbi__callbacks, (void *)&s );
|
---|
1065 | unsigned char* result = stbi__png_load( &ctx, &x, &y, &comp, rcomp );
|
---|
1066 | if ( result )
|
---|
1067 | {
|
---|
1068 | s.seek( -ctx.remaining(), origin::CUR );
|
---|
1069 | image_format fmt;
|
---|
1070 | ivec2 sz;
|
---|
1071 | fmt.type = UBYTE;
|
---|
1072 | switch ( comp )
|
---|
1073 | {
|
---|
1074 | case 1: fmt.format = RED; break;
|
---|
1075 | case 3: fmt.format = RGB; break;
|
---|
1076 | case 4: fmt.format = RGBA; break;
|
---|
1077 | default: NV_ASSERT( false, "UNKNOWN RESULT!" );
|
---|
1078 | }
|
---|
1079 | sz = ivec2( x, y );
|
---|
1080 | return new image_data( fmt, sz, result );
|
---|
1081 | }
|
---|
1082 | return nullptr;
|
---|
1083 | }
|
---|