Branch data Line data Source code
1 : : /*
2 : : Copyright (C) 2012-2014 Jeremiah Martell
3 : : All rights reserved.
4 : :
5 : : Redistribution and use in source and binary forms, with or without modification,
6 : : are permitted provided that the following conditions are met:
7 : :
8 : : - Redistributions of source code must retain the above copyright notice,
9 : : this list of conditions and the following disclaimer.
10 : : - Redistributions in binary form must reproduce the above copyright notice,
11 : : this list of conditions and the following disclaimer in the documentation
12 : : and/or other materials provided with the distribution.
13 : : - Neither the name of Jeremiah Martell nor the name of GeekHorse nor the
14 : : name of Pinto nor the names of its contributors may be used to endorse
15 : : or promote products derived from this software without specific prior
16 : : written permission.
17 : :
18 : : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 : : ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 : : WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 : : DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 : : ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 : : (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 : : LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 : : ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 : : (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 : : SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 : : */
29 : :
30 : : /******************************************************************************/
31 : : /*!
32 : : \file
33 : : Encoding and decoding functions.
34 : : */
35 : : #define PINTO_FILE_NUMBER 1
36 : :
37 : : /******************************************************************************/
38 : : #include "pinto.h"
39 : : #include "pintoInternal.h"
40 : :
41 : : /******************************************************************************/
42 : : extern const char valueToChar[];
43 : :
44 : : /******************************************************************************/
45 : : /*!
46 : : \brief Encodes an image into the Pinto format.
47 : : \param[in] image The image to be encoded.
48 : : \param[out] string_A On success, the string that contains the encoded image.
49 : : Will be allocated with the pintoHook memory functions. The caller is
50 : : responsible for freeing by passing to the pintoHook memory free
51 : : function, or its equivalent.
52 : : \return PINTO_RC
53 : : */
54 : 100853 : PINTO_RC pintoImageEncode( const PintoImage *image, char **string_A )
55 : : {
56 : : /* DATA */
57 : 100853 : PINTO_RC rc = PINTO_RC_SUCCESS;
58 : :
59 : 100853 : PintoText *newText = NULL;
60 : 100853 : PintoText *newTextDeflated = NULL;
61 : 100853 : u8 *palette = NULL;
62 : :
63 : : /* This is the indexed image data.
64 : : Instead of holding RGB, it holds an index into the palette.
65 : : The special value -1 is for transparent pixels. */
66 : 100853 : char *indexedData = NULL;
67 : :
68 : 100853 : s32 color = 0;
69 : 100853 : s32 pixel = 0;
70 : :
71 : 100853 : s32 colorAmount = 0;
72 : 100853 : s32 colorFound = 0;
73 : :
74 : 100853 : char needToAddStandardHeader = 1;
75 : :
76 : 100853 : u8 red = 0;
77 : 100853 : u8 green = 0;
78 : 100853 : u8 blue = 0;
79 : :
80 : 100853 : char rleState = 0;
81 : 100853 : s32 rleCount = 0;
82 : :
83 : 100853 : PintoImage *verifyImage = NULL;
84 : :
85 : 100853 : char *givebackString = NULL;
86 : :
87 : :
88 : : /* PRECOND */
89 [ + + ]: 100853 : ERR_IF( image == NULL, PINTO_RC_ERROR_PRECOND );
90 [ + + ]: 100852 : ERR_IF( string_A == NULL, PINTO_RC_ERROR_PRECOND );
91 [ + + ]: 100851 : ERR_IF( (*string_A) != NULL, PINTO_RC_ERROR_PRECOND );
92 : :
93 : :
94 : : /* CODE */
95 : :
96 : : /* check size */
97 [ + + ]: 100850 : ERR_IF_1( image->width <= 0, PINTO_RC_ERROR_IMAGE_BAD_SIZE, image->width );
98 [ + + ]: 100849 : ERR_IF_1( image->height <= 0, PINTO_RC_ERROR_IMAGE_BAD_SIZE, image->height );
99 : :
100 [ + + ]: 100848 : ERR_IF_1( image->width > PINTO_MAX_WIDTH, PINTO_RC_ERROR_IMAGE_BAD_SIZE, image->width );
101 [ + + ]: 100847 : ERR_IF_1( image->height > PINTO_MAX_HEIGHT, PINTO_RC_ERROR_IMAGE_BAD_SIZE, image->height );
102 : :
103 : : /* malloc data, which is the palette-ized version of the image.
104 : : instead of rgba, it'll hold the index of the color, with -1
105 : : being a special case of transparent. */
106 [ + + ]: 100846 : PINTO_MALLOC( indexedData, char, image->width * image->height );
107 : :
108 : : /* determine palette */
109 [ + + ]: 100832 : PINTO_CALLOC( palette, u8, PINTO_MAX_COLORS * 3 );
110 : :
111 : : /* foreach pixel */
112 [ + + ]: 1534579252 : for ( pixel = 0; pixel < ( image->width * image->height ); pixel += 1 )
113 : : {
114 : : /* if alpha is 0, fully transparent, ignore */
115 [ + + ]: 1534478437 : if ( image->rgba[ ( pixel * 4 ) + 3 ] == 0 )
116 : : {
117 : : /* mark pixel in data as transparent */
118 : 1395381800 : indexedData[ pixel ] = -1;
119 : :
120 : 1395381800 : continue;
121 : : }
122 : :
123 : : /* if alpha is not 255, fully opaque, then it's partially
124 : : transparent, and not allowed */
125 [ + + ]: 139096637 : ERR_IF( image->rgba[ ( pixel * 4 ) + 3 ] != 255, PINTO_RC_ERROR_IMAGE_PARTIAL_TRANSPARENCY );
126 : :
127 : : /* reset colorFound flag */
128 : 139096635 : colorFound = 0;
129 : :
130 : : /* get the red, green, and blue of the pixel */
131 : 139096635 : red = image->rgba[ ( pixel * 4 ) ];
132 : 139096635 : green = image->rgba[ ( pixel * 4 ) + 1 ];
133 : 139096635 : blue = image->rgba[ ( pixel * 4 ) + 2 ];
134 : :
135 : 139096635 : red = PINTO_8_BITS_TO_6_BITS( red );
136 : 139096635 : green = PINTO_8_BITS_TO_6_BITS( green );
137 : 139096635 : blue = PINTO_8_BITS_TO_6_BITS( blue );
138 : :
139 : : /* is this color already in our palette? */
140 : :
141 : : /* foreach color */
142 [ + + ]: 864222372 : for ( color = 0; color < colorAmount; color += 1 )
143 : : {
144 : : /* does the current pixel match this color? */
145 [ + + ]: 864028554 : if ( red == palette[ ( color * 3 ) ]
146 [ + + ]: 149958346 : && green == palette[ ( color * 3 ) + 1 ]
147 [ + + ]: 139158308 : && blue == palette[ ( color * 3 ) + 2 ]
148 : : )
149 : : {
150 : 138902817 : colorFound = 1;
151 : 138902817 : break;
152 : : }
153 : : }
154 : :
155 : : /* if color wasn't found, it's new, so add it to our palette */
156 [ + + ]: 139096635 : if ( colorFound == 0 )
157 : : {
158 : : /* make sure we dont go over PINTO_MAX_COLORS */
159 [ + + ]: 193818 : ERR_IF( colorAmount == PINTO_MAX_COLORS, PINTO_RC_ERROR_IMAGE_TOO_MANY_COLORS );
160 : :
161 : : /* add it to palette */
162 : 193817 : palette[ ( colorAmount * 3 ) ] = red;
163 : 193817 : palette[ ( colorAmount * 3 ) + 1 ] = green;
164 : 193817 : palette[ ( colorAmount * 3 ) + 2 ] = blue;
165 : :
166 : 193817 : colorAmount += 1;
167 : : }
168 : :
169 : : /* mark this pixel in data */
170 : 139096634 : indexedData[ pixel ] = color;
171 : : }
172 : :
173 : : /* we've created out palette, now lets start creating the pinto encoding */
174 : :
175 : : /* create text */
176 : 100815 : rc = pintoTextInit( &newText );
177 [ + + ]: 100815 : ERR_IF_PASSTHROUGH;
178 : :
179 : : /* See if it's a certain image, and we can use a shorter header */
180 [ + + ]: 100787 : if ( colorAmount == 1
181 [ + + ][ + + ]: 37711 : && palette[ 0 ] == 0 && palette[ 1 ] == 0 && palette[ 2 ] == 0
[ + + ]
182 [ + + ]: 606 : && image->width == image->height
183 : : )
184 : : {
185 [ + + ]: 515 : if ( image->width == 8 )
186 : : {
187 : 36 : rc = pintoTextAddChar( newText, '0' );
188 [ + + ]: 36 : ERR_IF_PASSTHROUGH;
189 : :
190 : 35 : needToAddStandardHeader = 0;
191 : : }
192 [ + + ]: 514 : if ( image->width == 16 )
193 : : {
194 : 41 : rc = pintoTextAddChar( newText, '1' );
195 [ + + ]: 41 : ERR_IF_PASSTHROUGH;
196 : :
197 : 40 : needToAddStandardHeader = 0;
198 : : }
199 [ + + ]: 473 : else if ( image->width == 32 )
200 : : {
201 : 39 : rc = pintoTextAddChar( newText, '2' );
202 [ + + ]: 39 : ERR_IF_PASSTHROUGH;
203 : :
204 : 38 : needToAddStandardHeader = 0;
205 : : }
206 [ + + ]: 434 : else if ( image->width == 64 )
207 : : {
208 : 35 : rc = pintoTextAddChar( newText, '3' );
209 [ + + ]: 35 : ERR_IF_PASSTHROUGH;
210 : :
211 : 34 : needToAddStandardHeader = 0;
212 : : }
213 [ + + ]: 399 : else if ( image->width == 128 )
214 : : {
215 : 37 : rc = pintoTextAddChar( newText, '4' );
216 [ + + ]: 37 : ERR_IF_PASSTHROUGH;
217 : :
218 : 36 : needToAddStandardHeader = 0;
219 : : }
220 [ + + ]: 362 : else if ( image->width == 256 )
221 : : {
222 : 39 : rc = pintoTextAddChar( newText, '5' );
223 [ + + ]: 39 : ERR_IF_PASSTHROUGH;
224 : :
225 : 38 : needToAddStandardHeader = 0;
226 : : }
227 [ + + ]: 323 : else if ( image->width == 512 )
228 : : {
229 : 35 : rc = pintoTextAddChar( newText, '6' );
230 [ + + ]: 35 : ERR_IF_PASSTHROUGH;
231 : :
232 : 34 : needToAddStandardHeader = 0;
233 : : }
234 [ + + ]: 288 : else if ( image->width == 1024 )
235 : : {
236 : 35 : rc = pintoTextAddChar( newText, '7' );
237 [ + + ]: 35 : ERR_IF_PASSTHROUGH;
238 : :
239 : 34 : needToAddStandardHeader = 0;
240 : : }
241 [ + + ]: 253 : else if ( image->width == 2048 )
242 : : {
243 : 34 : rc = pintoTextAddChar( newText, '8' );
244 [ + + ]: 34 : ERR_IF_PASSTHROUGH;
245 : :
246 : 33 : needToAddStandardHeader = 0;
247 : : }
248 [ + + ]: 219 : else if ( image->width == 4096 )
249 : : {
250 : 37 : rc = pintoTextAddChar( newText, '9' );
251 [ + + ]: 37 : ERR_IF_PASSTHROUGH;
252 : :
253 : 36 : needToAddStandardHeader = 0;
254 : : }
255 : : }
256 : :
257 [ + + ]: 100777 : if ( needToAddStandardHeader )
258 : : {
259 : : /* 'a' means standard header follows */
260 : 100419 : rc = pintoTextAddChar( newText, 'a' );
261 [ + + ]: 100419 : ERR_IF_PASSTHROUGH;
262 : :
263 : : /* add width */
264 : 100415 : rc = pintoTextAddValue( newText, image->width );
265 [ + + ]: 100415 : ERR_IF_PASSTHROUGH;
266 : :
267 : : /* add height */
268 : 100411 : rc = pintoTextAddValue( newText, image->height );
269 [ + + ]: 100411 : ERR_IF_PASSTHROUGH;
270 : :
271 : : /* add colorAmount */
272 : 100407 : rc = pintoTextAddValue( newText, colorAmount );
273 [ + + ]: 100407 : ERR_IF_PASSTHROUGH;
274 : :
275 : : /* add colors to palette */
276 [ + + ]: 680405 : for ( color = 0; color < ( colorAmount * 3 ); color += 1 )
277 : : {
278 : : /* divide by 4 because pinto's colors are 6-bit */
279 : 580014 : rc = pintoTextAddChar( newText, valueToChar[ palette[ color ] / 4 ] );
280 [ + + ]: 580014 : ERR_IF_PASSTHROUGH;
281 : : }
282 : : }
283 : :
284 : : /* add RLE data */
285 : :
286 : : /* foreach color */
287 [ + + ]: 294384 : for ( color = 0; color < colorAmount; color += 1 )
288 : : {
289 : 193688 : rleState = 0;
290 : 193688 : rleCount = 0;
291 : :
292 : : /* foreach pixel */
293 [ + + ]:17899321318 : for ( pixel = 0; pixel < ( image->width * image->height ); pixel += 1 )
294 : : {
295 : : /* if off */
296 [ + + ]:17899127669 : if ( rleState == 0 )
297 : : {
298 : : /* if same color */
299 [ + + ]:17735812039 : if ( color == indexedData[ pixel ] )
300 : : {
301 : : /* add rle count */
302 : 49865332 : rc = pintoTextAddValue( newText, rleCount );
303 [ + + ]: 49865332 : ERR_IF_PASSTHROUGH;
304 : :
305 : : /* reset rleState and rleCount */
306 : 49865312 : rleState = 1;
307 : 49865312 : rleCount = 1;
308 : : }
309 : : /* else if different color */
310 : : else
311 : : {
312 :17685946707 : rleCount += 1;
313 : : }
314 : : }
315 : : /* else, on */
316 : : else
317 : : {
318 : : PARANOID_ERR_IF( rleState != 1 );
319 : :
320 : : /* if same or higher color */
321 [ + + ]: 163315630 : if ( indexedData[ pixel ] >= color )
322 : : {
323 : 113473059 : rleCount += 1;
324 : : }
325 : : /* else if lower color */
326 : : else
327 : : {
328 : : /* add rle count */
329 : 49842571 : rc = pintoTextAddValue( newText, rleCount );
330 [ + + ]: 49842571 : ERR_IF_PASSTHROUGH;
331 : :
332 : 49842552 : rleState = 0;
333 : 49842552 : rleCount = 1;
334 : : }
335 : : }
336 : :
337 : : } /* end foreach pixel */
338 : :
339 : : /* add '^', which signals end of color */
340 : 193649 : rc = pintoTextAddChar( newText, '^' );
341 [ + + ]: 193649 : ERR_IF_PASSTHROUGH;
342 : :
343 : : } /* end foreach color */
344 : :
345 : : /* deflate */
346 : 100696 : rc = pintoSimpleDeflate( &newText, &newTextDeflated );
347 [ + + ]: 100696 : ERR_IF_PASSTHROUGH;
348 : :
349 : : /* get string */
350 : 100586 : pintoTextFreeAndGetString( &newTextDeflated, &givebackString );
351 : :
352 : : /* give back */
353 : 100586 : (*string_A) = givebackString;
354 : 100586 : givebackString = NULL;
355 : :
356 : :
357 : : /* CLEANUP */
358 : : cleanup:
359 : :
360 : 100853 : pintoHookFree( palette );
361 : 100853 : palette = NULL;
362 : :
363 : 100853 : pintoHookFree( indexedData );
364 : 100853 : indexedData = NULL;
365 : :
366 : 100853 : pintoTextFree( &newText );
367 : 100853 : pintoTextFree( &newTextDeflated );
368 : :
369 : 100853 : pintoImageFree( &verifyImage );
370 : :
371 : 100853 : pintoHookFree( givebackString );
372 : 100853 : givebackString = NULL;
373 : :
374 : 100853 : return rc;
375 : : }
376 : :
377 : : /******************************************************************************/
378 : : /*!
379 : : \brief Decodes a string into an image.
380 : : \param[in] string The string to be decoded.
381 : : \param[out] image_A On success, the decoded image.
382 : : Will be allocated with the pintoHook memory functions. The caller is
383 : : responsible for freeing by passing the image to the pintoImageFree()
384 : : function.
385 : : \return PINTO_RC
386 : : */
387 : 100643 : PINTO_RC pintoImageDecodeString( const char *string, PintoImage **image_A )
388 : : {
389 : : /* DATA */
390 : 100643 : PINTO_RC rc = PINTO_RC_SUCCESS;
391 : :
392 : 100643 : PintoText *text = NULL;
393 : :
394 : :
395 : : /* PRECOND */
396 [ + + ]: 100643 : ERR_IF( string == NULL, PINTO_RC_ERROR_PRECOND );
397 [ + + ]: 100642 : ERR_IF( image_A == NULL, PINTO_RC_ERROR_PRECOND );
398 [ + + ]: 100641 : ERR_IF( (*image_A) != NULL, PINTO_RC_ERROR_PRECOND );
399 : :
400 : :
401 : : /* CODE */
402 : : /* create our text */
403 : 100640 : rc = pintoTextInit( &text );
404 [ + + ]: 100640 : ERR_IF_PASSTHROUGH;
405 : :
406 : : /* add string to our pintoText */
407 [ + + ]: 10886090 : while ( (*string) != '\0' )
408 : : {
409 : 10785560 : rc = pintoTextAddChar( text, (*string) );
410 [ + + ]: 10785560 : ERR_IF_PASSTHROUGH;
411 : :
412 : 10785478 : string += 1;
413 : : }
414 : :
415 : : /* call the text version */
416 : 100530 : rc = pintoImageDecodeText( &text, image_A );
417 [ + + ]: 100530 : ERR_IF_PASSTHROUGH;
418 : :
419 : :
420 : : /* CLEANUP */
421 : : cleanup:
422 : :
423 : 100643 : pintoTextFree( &text );
424 : :
425 : 100643 : return rc;
426 : : }
427 : :
428 : : /******************************************************************************/
429 : : /*!
430 : : \brief Decodes a text into an image.
431 : : \param[in] text_F The text to be decoded. On success, this will be freed
432 : : with the pintoHook memory functions.
433 : : \param[out] image_A On success, the decoded image.
434 : : Will be allocated with the pintoHook memory functions. The caller is
435 : : responsible for freeing by passing the image to pintoImageFree().
436 : : \return PINTO_RC
437 : : */
438 : 100534 : PINTO_RC pintoImageDecodeText( PintoText **text_F, PintoImage **image_A )
439 : : {
440 : : /* DATA */
441 : 100534 : PINTO_RC rc = PINTO_RC_SUCCESS;
442 : :
443 : 100534 : PintoText *text = NULL;
444 : :
445 : 100534 : PintoImage *newImage = NULL;
446 : :
447 : 100534 : char header = 0;
448 : :
449 : 100534 : s32 colorIndex = 0;
450 : 100534 : s32 i = 0;
451 : 100534 : s32 pixelIndex = 0;
452 : :
453 : 100534 : char ch = 0;
454 : 100534 : s32 value = 0;
455 : :
456 : 100534 : s32 width = 0;
457 : 100534 : s32 height = 0;
458 : :
459 : 100534 : s32 colorAmount = 0;
460 : 100534 : u8 *palette = NULL;
461 : :
462 : 100534 : char flagOn = 0;
463 : :
464 : :
465 : : /* PRECOND */
466 [ + + ]: 100534 : ERR_IF( text_F == NULL, PINTO_RC_ERROR_PRECOND );
467 [ + + ]: 100533 : ERR_IF( (*text_F) == NULL, PINTO_RC_ERROR_PRECOND );
468 [ + + ]: 100532 : ERR_IF( image_A == NULL, PINTO_RC_ERROR_PRECOND );
469 [ + + ]: 100531 : ERR_IF( (*image_A) != NULL, PINTO_RC_ERROR_PRECOND );
470 : :
471 : :
472 : : /* CODE */
473 : :
474 : : /* inflate */
475 : 100530 : rc = pintoSimpleInflate( text_F, &text );
476 [ + + ]: 100530 : ERR_IF_PASSTHROUGH;
477 : :
478 : : /* get header */
479 : 100411 : rc = pintoTextGetChar( text, &header );
480 [ + + ]: 100411 : ERR_IF_PASSTHROUGH;
481 : :
482 : : /* standard header marker */
483 [ + + ]: 100410 : if ( header == 'a' )
484 : : {
485 : : /* get width */
486 : 100261 : rc = pintoTextGetValue( text, &width );
487 [ + + ]: 100261 : ERR_IF_PASSTHROUGH;
488 : :
489 [ + + ]: 100259 : ERR_IF_1( width <= 0, PINTO_RC_ERROR_FORMAT_INVALID, width );
490 [ + + ]: 100258 : ERR_IF_1( width > PINTO_MAX_WIDTH, PINTO_RC_ERROR_FORMAT_INVALID, width );
491 : :
492 : : /* get height */
493 : 100257 : rc = pintoTextGetValue( text, &height );
494 [ + + ]: 100257 : ERR_IF_PASSTHROUGH;
495 : :
496 [ + + ]: 100255 : ERR_IF_1( height <= 0, PINTO_RC_ERROR_FORMAT_INVALID, height );
497 [ + + ]: 100254 : ERR_IF_1( height > PINTO_MAX_HEIGHT, PINTO_RC_ERROR_FORMAT_INVALID, height );
498 : :
499 : : /* allocate new image */
500 : 100253 : rc = pintoImageInit( width, height, &newImage );
501 [ + + ]: 100253 : ERR_IF_PASSTHROUGH;
502 : :
503 : : /* get number of colors in palette */
504 : 100245 : rc = pintoTextGetValue( text, &colorAmount );
505 [ + + ]: 100245 : ERR_IF_PASSTHROUGH;
506 : :
507 [ + + ]: 100243 : ERR_IF_1( colorAmount > PINTO_MAX_COLORS, PINTO_RC_ERROR_FORMAT_INVALID, colorAmount );
508 : :
509 [ + + ]: 100242 : if ( colorAmount > 0 )
510 : : {
511 : : /* allocate palette */
512 [ + + ]: 99824 : PINTO_CALLOC( palette, u8, colorAmount * 3 );
513 : :
514 : : /* read in colors */
515 [ + + ]: 679339 : for ( colorIndex = 0; colorIndex < ( colorAmount * 3 ); colorIndex += 1 )
516 : : {
517 : 579525 : value = 0;
518 : :
519 : 579525 : rc = pintoTextUpdateValue( text, &value );
520 [ + + ]: 579525 : ERR_IF_PASSTHROUGH;
521 : :
522 : 579519 : palette[ colorIndex ] = PINTO_6_BITS_TO_8_BITS( value );
523 : : }
524 : :
525 : : }
526 : : }
527 : : /* smaller header */
528 : : else
529 : : {
530 [ + + ]: 149 : if ( header == '0' )
531 : : {
532 : 14 : width = height = 8;
533 : : }
534 [ + + ]: 135 : else if ( header == '1' )
535 : : {
536 : 19 : width = height = 16;
537 : : }
538 [ + + ]: 116 : else if ( header == '2' )
539 : : {
540 : 17 : width = height = 32;
541 : : }
542 [ + + ]: 99 : else if ( header == '3' )
543 : : {
544 : 13 : width = height = 64;
545 : : }
546 [ + + ]: 86 : else if ( header == '4' )
547 : : {
548 : 15 : width = height = 128;
549 : : }
550 [ + + ]: 71 : else if ( header == '5' )
551 : : {
552 : 17 : width = height = 256;
553 : : }
554 [ + + ]: 54 : else if ( header == '6' )
555 : : {
556 : 13 : width = height = 512;
557 : : }
558 [ + + ]: 41 : else if ( header == '7' )
559 : : {
560 : 13 : width = height = 1024;
561 : : }
562 [ + + ]: 28 : else if ( header == '8' )
563 : : {
564 : 12 : width = height = 2048;
565 : : }
566 [ + + ]: 16 : else if ( header == '9' )
567 : : {
568 : 15 : width = height = 4096;
569 : : }
570 : : else
571 : : {
572 : 1 : ERR_IF_1( 1, PINTO_RC_ERROR_FORMAT_INVALID, header );
573 : : }
574 : :
575 : : /* allocate new image */
576 : 148 : rc = pintoImageInit( width, height, &newImage );
577 [ + + ]: 148 : ERR_IF_PASSTHROUGH;
578 : :
579 : 128 : colorAmount = 1;
580 : :
581 : : /* allocate palette */
582 : : /* since this is calloc, our single color will be black, which is
583 : : what we want */
584 [ + + ]: 128 : PINTO_CALLOC( palette, u8, colorAmount * 3 );
585 : : }
586 : :
587 : : /* foreach color */
588 [ + + ]: 293618 : for ( colorIndex = 0; colorIndex < colorAmount; colorIndex += 1 )
589 : : {
590 : 193289 : pixelIndex = 0;
591 : 193289 : flagOn = 0;
592 : :
593 : : /* rle decoding */
594 : : while ( 1 )
595 : : {
596 : : /* peek at current character to see if it's a '^', which
597 : : signals end of current color */
598 : 99899817 : rc = pintoTextPeekChar( text, &ch );
599 [ + + ]: 99899817 : ERR_IF_PASSTHROUGH;
600 : :
601 [ + + ]: 99899809 : if ( ch == '^' )
602 : : {
603 : : /* we just peeked, now we must remove it to move
604 : : past it in the text */
605 : 193268 : rc = pintoTextGetChar( text, &ch );
606 : : PARANOID_ERR_IF( rc != PINTO_RC_SUCCESS );
607 : :
608 : 193268 : break;
609 : : }
610 : :
611 : : /* get the rle value */
612 : 99706541 : rc = pintoTextGetValue( text, &value );
613 [ + + ]: 99706541 : ERR_IF_PASSTHROUGH;
614 : :
615 : : /* make sure it doesn't go past end of rgba array */
616 [ + + ]: 99706530 : ERR_IF( pixelIndex + ( value * 4 ) >= ( width * height * 4 ), PINTO_RC_ERROR_FORMAT_INVALID );
617 : :
618 : : /* if we're in off state, just increment our pixelIndex */
619 [ + + ]: 99706528 : if ( flagOn == 0 )
620 : : {
621 : 49864619 : pixelIndex += ( value * 4 );
622 : : }
623 : : /* else we're in the on state, so draw our run */
624 : : else
625 : : {
626 [ + + ]: 129183993 : for ( i = 0; i < value; i += 1, pixelIndex += 4 )
627 : : {
628 : 79342084 : newImage->rgba[ pixelIndex ] = palette[ ( colorIndex * 3 ) ];
629 : 79342084 : newImage->rgba[ pixelIndex + 1 ] = palette[ ( colorIndex * 3 ) + 1 ];
630 : 79342084 : newImage->rgba[ pixelIndex + 2 ] = palette[ ( colorIndex * 3 ) + 2 ];
631 : 79342084 : newImage->rgba[ pixelIndex + 3 ] = 255;
632 : : }
633 : : }
634 : :
635 : : /* switch states */
636 : 99706528 : flagOn = ( ! flagOn );
637 : :
638 : 99706528 : } /* end rle decoding */
639 : :
640 : : /* the last rleValue is implicit,
641 : : if we're in on state */
642 [ + + ]: 193268 : if ( flagOn )
643 : : {
644 : : /* draw until end of image */
645 [ + + ]: 84017920 : for ( ; pixelIndex < ( width * height * 4 ); pixelIndex += 4 )
646 : : {
647 : 83995215 : newImage->rgba[ pixelIndex ] = palette[ ( colorIndex * 3 ) ];
648 : 83995215 : newImage->rgba[ pixelIndex + 1 ] = palette[ ( colorIndex * 3 ) + 1 ];
649 : 83995215 : newImage->rgba[ pixelIndex + 2 ] = palette[ ( colorIndex * 3 ) + 2 ];
650 : 83995215 : newImage->rgba[ pixelIndex + 3 ] = 255;
651 : : }
652 : : }
653 : :
654 : : } /* end foreach color */
655 : :
656 : : /* must be at end of text */
657 [ + + ]: 100329 : ERR_IF( pintoTextAtEnd( text ) == 0, PINTO_RC_ERROR_FORMAT_INVALID );
658 : :
659 : : /* give back */
660 : 100328 : (*image_A) = newImage;
661 : 100328 : newImage = NULL;
662 : :
663 : 100328 : pintoTextFree( text_F );
664 : :
665 : :
666 : : /* CLEANUP */
667 : : cleanup:
668 : :
669 : 100534 : pintoHookFree( palette );
670 : 100534 : palette = NULL;
671 : :
672 : 100534 : pintoTextFree( &text );
673 : :
674 : 100534 : pintoImageFree( &newImage );
675 : :
676 : 100534 : return rc;
677 : : }
678 : :
679 : : /******************************************************************************/
680 : : /*!
681 : : \brief Allocates a new image that's all transparent.
682 : : \param[in] width The width of the image.
683 : : \param[in] height The height of the image.
684 : : \param[out] image_A On success, the decoded image.
685 : : Will be allocated with the pintoHook memory functions. The caller is
686 : : responsible for freeing by passing the image to pintoImageFree().
687 : : \return PINTO_RC
688 : : */
689 : 295556 : PINTO_RC pintoImageInit( s32 width, s32 height, PintoImage **image_A )
690 : : {
691 : : /* DATA */
692 : 295556 : PINTO_RC rc = PINTO_RC_SUCCESS;
693 : :
694 : 295556 : PintoImage *newImage = NULL;
695 : :
696 : :
697 : : /* PRECOND */
698 [ + + ][ + + ]: 295556 : ERR_IF_1( width <= 0 || width > PINTO_MAX_WIDTH, PINTO_RC_ERROR_PRECOND, width );
699 [ + + ][ + + ]: 295553 : ERR_IF_1( height <= 0 || height > PINTO_MAX_HEIGHT, PINTO_RC_ERROR_PRECOND, height );
700 [ + + ]: 295550 : ERR_IF( image_A == NULL, PINTO_RC_ERROR_PRECOND );
701 [ + + ]: 295549 : ERR_IF( (*image_A) != NULL, PINTO_RC_ERROR_PRECOND );
702 : :
703 : :
704 : : /* CODE */
705 : : /* create our newImage */
706 [ + + ]: 295548 : PINTO_CALLOC( newImage, PintoImage, 1 );
707 : :
708 : : /* allocate rgba */
709 [ + + ]: 295519 : PINTO_CALLOC( newImage->rgba, u8, width * height * 4 );
710 : :
711 : 295490 : newImage->width = width;
712 : 295490 : newImage->height = height;
713 : :
714 : : /* give back */
715 : 295490 : (*image_A) = newImage;
716 : 295490 : newImage = NULL;
717 : :
718 : :
719 : : /* CLEANUP */
720 : : cleanup:
721 : :
722 : 295556 : pintoHookFree( newImage );
723 : 295556 : newImage = NULL;
724 : :
725 : 295556 : return rc;
726 : : }
727 : :
728 : : /******************************************************************************/
729 : : /*!
730 : : \brief Frees an image.
731 : : \param[in] image_F The image to be freed. Will be freed with
732 : : pintoHookFree(). On return, image_F will be NULL.
733 : : \return void.
734 : : */
735 : 597794 : void pintoImageFree( PintoImage **image_F )
736 : : {
737 : : /* CODE */
738 [ + + ][ + + ]: 597794 : if ( image_F == NULL || (*image_F) == NULL )
739 : : {
740 : 302304 : return;
741 : : }
742 : :
743 : 295490 : pintoHookFree( (*image_F)->rgba );
744 : 295490 : (*image_F)->rgba = NULL;
745 : :
746 : 295490 : pintoHookFree( (*image_F) );
747 : 295490 : (*image_F) = NULL;
748 : :
749 : 597794 : return;
750 : : }
751 : :
752 : : /******************************************************************************/
753 : : /*!
754 : : \brief Compresses text with a simple version of deflate.
755 : : \param[in] textToDeflate_F text to be compressed. On success, will be freed.
756 : : \param[out] text_A On success, will be compressed text.
757 : : Will be allocated with the pintoHook memory functions. The caller is
758 : : responsible for freeing with pintoTextFree().
759 : : \return PINTO_RC
760 : : */
761 : 100874 : PINTO_RC pintoSimpleDeflate( PintoText **textToDeflate_F, PintoText **text_A )
762 : : {
763 : : /* DATA */
764 : 100874 : PINTO_RC rc = PINTO_RC_SUCCESS;
765 : :
766 : 100874 : PintoText *newText = NULL;
767 : 100874 : char *string = NULL;
768 : 100874 : s32 stringLength = 0;
769 : :
770 : 100874 : s32 i = 0;
771 : :
772 : 100874 : s32 matchI = 0;
773 : 100874 : s32 matchLength = 0;
774 : :
775 : 100874 : s32 bestMatchLength = 0;
776 : 100874 : s32 bestMatchDistance = 0;
777 : :
778 : :
779 : : /* CODE */
780 : : PARANOID_ERR_IF( textToDeflate_F == NULL );
781 : : PARANOID_ERR_IF( (*textToDeflate_F) == NULL );
782 : : PARANOID_ERR_IF( text_A == NULL );
783 : : PARANOID_ERR_IF( (*text_A) != NULL );
784 : :
785 : : /* get string length */
786 : 100874 : stringLength = (*textToDeflate_F)->usedSize;
787 : :
788 : : /* get string */
789 : 100874 : pintoTextFreeAndGetString( textToDeflate_F, &string );
790 : :
791 : : /* create our new text */
792 : 100874 : rc = pintoTextInit( &newText );
793 [ + + ]: 100874 : ERR_IF_PASSTHROUGH;
794 : :
795 : : /* go through string */
796 : 100842 : i = 0;
797 : : /* we go until there's only 4 characters left, since we can only deflate
798 : : at least 4 characters */
799 [ + + ]: 7970921 : while ( i <= (stringLength - 4) )
800 : : {
801 : : /* reset our length variables */
802 : 7870193 : matchLength = 0;
803 : 7870193 : bestMatchLength = 0;
804 : :
805 : : /* set matchI */
806 : 7870193 : matchI = i - 1;
807 : :
808 : : /* go up to 64 * 64 characters back, finding the best match */
809 [ + + ][ + + ]: 3075444176 : while ( matchI >= 0 && ( i - matchI ) < (64 * 64) )
810 : : {
811 : : /* do at least 4 characters match? */
812 [ + + ]: 3067573983 : if ( string[ matchI ] == string[ i ]
813 [ + + ]: 426622182 : && string[ matchI + 1 ] == string[ i + 1 ]
814 [ + + ]: 70080506 : && string[ matchI + 2 ] == string[ i + 2 ]
815 [ + + ]: 27304267 : && string[ matchI + 3 ] == string[ i + 3 ]
816 : : )
817 : : {
818 : : /* see how long the match is */
819 : : /* we don't need to worry about going past the end of the string, because
820 : : before we go past the end of the string we won't match the terminating
821 : : '\0' and break out anyway */
822 : : /* we dont need to worry about matchLength becoming larger than we can
823 : : encode, because we only allow PINTO_MAX_WIDTH * PINTO_MAX_HEIGHT
824 : : characters in the string, so the max we'll have to encode is
825 : : ( PINTO_MAX_WIDTH * PINTO_MAX_HEIGHT ) - 1
826 : : which is exactly the max we can encode. (given than the max width
827 : : and height is 4096 and we use 4 64 values in encoding) */
828 : 19589857 : matchLength = 4;
829 [ + + ]: 4089485479 : while ( string[ matchI + matchLength ] == string[ i + matchLength ] )
830 : : {
831 : 4069895622 : matchLength += 1;
832 : : }
833 : :
834 : : /* is this our best match? */
835 [ + + ]: 19589857 : if ( matchLength > bestMatchLength )
836 : : {
837 : 3146209 : bestMatchLength = matchLength;
838 : 3146209 : bestMatchDistance = i - matchI;
839 : : }
840 : : }
841 : :
842 : : /* decrement matchI
843 : : try to find match at next spot */
844 : 3067573983 : matchI -= 1;
845 : : }
846 : :
847 : : /* if no match*/
848 : : /* or if best match length was 4 and the distance was farther than 64, then
849 : : the match is 4 characters and the encoding will be 4 characters, so there
850 : : is no point deflating. */
851 [ + + ]: 7870193 : if ( bestMatchLength == 0
852 [ + + ][ + + ]: 1274771 : || ( bestMatchLength == 4 && bestMatchDistance >= 64 )
853 : : )
854 : : {
855 : 6679521 : rc = pintoTextAddChar( newText, string[ i ] );
856 [ + + ]: 6679521 : ERR_IF_PASSTHROUGH;
857 : :
858 : : /* increment i */
859 : 6679417 : i += 1;
860 : : }
861 : : /* there was a match */
862 : : else
863 : : {
864 [ + + ]: 1190672 : if ( bestMatchDistance < 64 )
865 : : {
866 : 1079275 : rc = pintoTextAddChar( newText, '?' );
867 [ + + ]: 1079275 : ERR_IF_PASSTHROUGH;
868 : :
869 : 1079273 : rc = pintoTextAddValue( newText, bestMatchDistance );
870 [ + + ]: 1079273 : ERR_IF_PASSTHROUGH;
871 : :
872 : 1079271 : rc = pintoTextAddValue( newText, bestMatchLength );
873 [ + + ]: 1079271 : ERR_IF_PASSTHROUGH;
874 : : }
875 : : else
876 : : {
877 : : PARANOID_ERR_IF( bestMatchDistance >= ( 64 * 64 ) );
878 : :
879 : 111397 : rc = pintoTextAddChar( newText, '@' );
880 [ + + ]: 111397 : ERR_IF_PASSTHROUGH;
881 : :
882 : 111396 : rc = pintoTextAddChar( newText, valueToChar[ ( (bestMatchDistance) / 64 ) % 64 ] );
883 [ + + ]: 111396 : ERR_IF_PASSTHROUGH;
884 : :
885 : 111395 : rc = pintoTextAddChar( newText, valueToChar[ (bestMatchDistance) % 64 ] );
886 [ + + ]: 111395 : ERR_IF_PASSTHROUGH;
887 : :
888 : 111394 : rc = pintoTextAddValue( newText, bestMatchLength );
889 [ + + ]: 111394 : ERR_IF_PASSTHROUGH;
890 : : }
891 : :
892 : : /* increment i */
893 : 1190662 : i += bestMatchLength;
894 : : }
895 : : }
896 : :
897 : : /* add rest of string to newText */
898 [ + + ]: 373824 : while ( i < stringLength )
899 : : {
900 : 273136 : rc = pintoTextAddChar( newText, string[ i ] );
901 [ + + ]: 273136 : ERR_IF_PASSTHROUGH;
902 : :
903 : : /* *** */
904 : 273096 : i += 1;
905 : : }
906 : :
907 : : /* free textToDeflate */
908 : 100688 : pintoTextFree( textToDeflate_F );
909 : :
910 : : /* give back */
911 : 100688 : (*text_A) = newText;
912 : 100688 : newText = NULL;
913 : :
914 : :
915 : : /* CLEANUP */
916 : : cleanup:
917 : :
918 : 100874 : pintoTextFree( &newText );
919 : :
920 : 100874 : pintoHookFree( string );
921 : 100874 : string = NULL;
922 : :
923 : 100874 : return rc;
924 : : }
925 : :
926 : : /******************************************************************************/
927 : : /*!
928 : : \brief Uncompresses text with a simple version of deflate (inflate here).
929 : : \param[in] textToDeflate_F text to be uncompressed. On success, will be freed.
930 : : \param[out] text_A On success, will be uncompressed text.
931 : : Will be allocated with the pintoHook memory functions. The caller is
932 : : responsible for freeing with pintoTextFree().
933 : : \return PINTO_RC
934 : : */
935 : 100634 : PINTO_RC pintoSimpleInflate( PintoText **textToInflate_F, PintoText **text_A )
936 : : {
937 : : /* DATA */
938 : 100634 : PINTO_RC rc = PINTO_RC_SUCCESS;
939 : :
940 : 100634 : PintoText *newText = NULL;
941 : :
942 : 100634 : char ch = 0;
943 : :
944 : 100634 : s32 distance = 0;
945 : 100634 : s32 length = 0;
946 : :
947 : :
948 : : /* CODE */
949 : : PARANOID_ERR_IF( textToInflate_F == NULL );
950 : : PARANOID_ERR_IF( (*textToInflate_F) == NULL );
951 : : PARANOID_ERR_IF( text_A == NULL );
952 : : PARANOID_ERR_IF( (*text_A) != NULL );
953 : :
954 : : /* create our new text */
955 : 100634 : rc = pintoTextInit( &newText );
956 [ + + ]: 100634 : ERR_IF_PASSTHROUGH;
957 : :
958 : : /* go through string, inflating */
959 : : while ( 1 )
960 : : {
961 : : /* is there another char to get? */
962 [ + + ]: 8238288 : if ( pintoTextAtEnd( (*textToInflate_F) ) )
963 : : {
964 : 100443 : break;
965 : : }
966 : :
967 : : /* get next char */
968 : 8137845 : pintoTextGetChar( (*textToInflate_F), &ch );
969 : : /* since we just called pintoTextAtEnd there is guaranteed to be a char to get.
970 : : so no need to check for error
971 : : */
972 : :
973 : : /* '?' is used for distances 1-63 */
974 [ + + ]: 8137845 : if ( ch == '?' )
975 : : {
976 : : /* get distance */
977 : 1079248 : distance = 0;
978 : :
979 : 1079248 : rc = pintoTextUpdateValue( (*textToInflate_F), &distance );
980 [ + + ]: 1079248 : ERR_IF_PASSTHROUGH;
981 : :
982 : : /* get length */
983 : 1079247 : rc = pintoTextGetValue( (*textToInflate_F), &length );
984 [ + + ]: 1079247 : ERR_IF_PASSTHROUGH;
985 : :
986 : : /* inflate */
987 : 1079246 : rc = pintoTextInflateHelper( newText, distance, length );
988 [ + + ]: 1079246 : ERR_IF_PASSTHROUGH;
989 : : }
990 : : /* '@' is used for distances 64-4095 */
991 [ + + ]: 7058597 : else if ( ch == '@' )
992 : : {
993 : : /* get distance */
994 : 111333 : distance = 0;
995 : :
996 : 111333 : rc = pintoTextUpdateValue( (*textToInflate_F), &distance );
997 [ + + ]: 111333 : ERR_IF_PASSTHROUGH;
998 : 111332 : rc = pintoTextUpdateValue( (*textToInflate_F), &distance );
999 [ + + ]: 111332 : ERR_IF_PASSTHROUGH;
1000 : :
1001 : : /* get length */
1002 : 111331 : rc = pintoTextGetValue( (*textToInflate_F), &length );
1003 [ + + ]: 111331 : ERR_IF_PASSTHROUGH;
1004 : :
1005 : : /* inflate */
1006 : 111330 : rc = pintoTextInflateHelper( newText, distance, length );
1007 [ + + ]: 111330 : ERR_IF_PASSTHROUGH;
1008 : : }
1009 : : /* no inflate marker, just add char */
1010 : : else
1011 : : {
1012 : 6947264 : rc = pintoTextAddChar( newText, ch );
1013 [ + + ]: 6947264 : ERR_IF_PASSTHROUGH;
1014 : : }
1015 : 8137686 : }
1016 : :
1017 : 100443 : pintoTextFree( textToInflate_F );
1018 : :
1019 : : /* give back */
1020 : 100443 : (*text_A) = newText;
1021 : 100443 : newText = NULL;
1022 : :
1023 : :
1024 : : /* CLEANUP */
1025 : : cleanup:
1026 : :
1027 : 100634 : pintoTextFree( &newText );
1028 : :
1029 : 100634 : return rc;
1030 : : }
1031 : :
1032 : : /******************************************************************************/
1033 : : /*!
1034 : : \brief Creates a new image half the size.
1035 : : \param[in] imageIn The original image.
1036 : : \param[out] imageOut_A On success, a new image half the size of the original
1037 : : image.
1038 : : \return PINTO_RC
1039 : :
1040 : : Used to create anti-aliased images.
1041 : : */
1042 : 94274 : PINTO_RC pintoImageDownsize( PintoImage *imageIn, PintoImage **imageOut_A )
1043 : : {
1044 : : /* DATA */
1045 : 94274 : PINTO_RC rc = PINTO_RC_SUCCESS;
1046 : :
1047 : 94274 : PintoImage *newImage = NULL;
1048 : :
1049 : 94274 : s32 width = 0;
1050 : 94274 : s32 height = 0;
1051 : :
1052 : 94274 : s32 x = 0;
1053 : 94274 : s32 y = 0;
1054 : 94274 : s32 newX = 0;
1055 : 94274 : s32 newY = 0;
1056 : :
1057 : 94274 : s32 avg = 0;
1058 : :
1059 : :
1060 : : /* PRECOND */
1061 [ + + ]: 94274 : ERR_IF( imageIn == NULL, PINTO_RC_ERROR_PRECOND );
1062 [ + + ]: 94273 : ERR_IF( imageOut_A == NULL, PINTO_RC_ERROR_PRECOND );
1063 [ + + ]: 94272 : ERR_IF( (*imageOut_A) != NULL, PINTO_RC_ERROR_PRECOND );
1064 : :
1065 : :
1066 : : /* CODE */
1067 : 94271 : width = imageIn->width;
1068 : 94271 : height = imageIn->height;
1069 : :
1070 : : /* if odd, round down */
1071 : 94271 : width = width & (~((s32)1));
1072 : 94271 : height = height & (~((s32)1));
1073 : :
1074 [ + + ]: 94271 : ERR_IF( width == 0, PINTO_RC_ERROR_IMAGE_TOO_SMALL );
1075 [ + + ]: 94270 : ERR_IF( height == 0, PINTO_RC_ERROR_IMAGE_TOO_SMALL );
1076 : :
1077 : : /* create new image at half size */
1078 : 94269 : rc = pintoImageInit( width / 2, height / 2, &newImage );
1079 [ + + ]: 94269 : ERR_IF_PASSTHROUGH;
1080 : :
1081 : : /* do the downsize */
1082 : 94267 : x = 0;
1083 : 94267 : newX = 0;
1084 [ + + ]: 1072487 : while ( x < width )
1085 : : {
1086 : 978220 : y = 0;
1087 : 978220 : newY = 0;
1088 [ + + ]: 202385154 : while ( y < height )
1089 : : {
1090 : : /* red */
1091 : 201406934 : avg = 0;
1092 : 201406934 : avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 0 ) * 4 ) ];
1093 : 201406934 : avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 1 ) * 4 ) ];
1094 : 201406934 : avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 0 ) * 4 ) ];
1095 : 201406934 : avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 1 ) * 4 ) ];
1096 : 201406934 : avg /= 4;
1097 : 201406934 : newImage->rgba[ ( newY * (width / 2) * 4 ) + ( newX * 4 ) ] = avg;
1098 : :
1099 : : /* green */
1100 : 201406934 : avg = 0;
1101 : 201406934 : avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 0 ) * 4 ) + 1 ];
1102 : 201406934 : avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 1 ) * 4 ) + 1 ];
1103 : 201406934 : avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 0 ) * 4 ) + 1 ];
1104 : 201406934 : avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 1 ) * 4 ) + 1 ];
1105 : 201406934 : avg /= 4;
1106 : 201406934 : newImage->rgba[ ( newY * (width / 2) * 4 ) + ( newX * 4 ) + 1 ] = avg;
1107 : :
1108 : : /* blue */
1109 : 201406934 : avg = 0;
1110 : 201406934 : avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 0 ) * 4 ) + 2 ];
1111 : 201406934 : avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 1 ) * 4 ) + 2 ];
1112 : 201406934 : avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 0 ) * 4 ) + 2 ];
1113 : 201406934 : avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 1 ) * 4 ) + 2 ];
1114 : 201406934 : avg /= 4;
1115 : 201406934 : newImage->rgba[ ( newY * (width / 2) * 4 ) + ( newX * 4 ) + 2 ] = avg;
1116 : :
1117 : : /* alpha */
1118 : 201406934 : avg = 0;
1119 : 201406934 : avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 0 ) * 4 ) + 3 ];
1120 : 201406934 : avg += imageIn->rgba[ ( ( y + 0 ) * width * 4 ) + ( ( x + 1 ) * 4 ) + 3 ];
1121 : 201406934 : avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 0 ) * 4 ) + 3 ];
1122 : 201406934 : avg += imageIn->rgba[ ( ( y + 1 ) * width * 4 ) + ( ( x + 1 ) * 4 ) + 3 ];
1123 : 201406934 : avg /= 4;
1124 : 201406934 : newImage->rgba[ ( newY * (width / 2) * 4 ) + ( newX * 4 ) + 3 ] = avg;
1125 : :
1126 : : /* increment */
1127 : 201406934 : y += 2;
1128 : 201406934 : newY += 1;
1129 : : }
1130 : :
1131 : : /* increment */
1132 : 978220 : x += 2;
1133 : 978220 : newX += 1;
1134 : : }
1135 : :
1136 : :
1137 : : /* give back */
1138 : 94267 : (*imageOut_A) = newImage;
1139 : 94267 : newImage = NULL;
1140 : :
1141 : :
1142 : : /* CLEANUP */
1143 : : cleanup:
1144 : :
1145 : 94274 : pintoImageFree( &newImage );
1146 : :
1147 : 94274 : return rc;
1148 : : }
1149 : :
1150 : : /******************************************************************************/
1151 : : /*!
1152 : : \brief Provides a const char string representation for a PINTO_RC
1153 : : \param[in] rc A PINTO_RC value.
1154 : : \return A const char representation of the passed in PINTO_RC.
1155 : : */
1156 : 2942 : const char *pintoRCToString( PINTO_RC rc )
1157 : : {
1158 : : static const char *_rcStrings[] =
1159 : : {
1160 : : "Success",
1161 : :
1162 : : "Precondition Error",
1163 : : "Memory Allocation Error",
1164 : : "Standard Library Error",
1165 : :
1166 : : "Image Bad Size Error",
1167 : : "Image Too Many Colors Error",
1168 : : "Image Partial Transparency Error",
1169 : : "Image Too Small Error",
1170 : : "Format Invalid Error",
1171 : : "Format Too Long Error"
1172 : : };
1173 : :
1174 : : static const char *_rcUnknown = "Unknown Error";
1175 : :
1176 [ + + ][ + + ]: 2942 : if ( rc >= 0 && rc <= PINTO_RC_STANDARD_ERRORS_MAX )
1177 : : {
1178 : 2749 : return _rcStrings[ rc ];
1179 : : }
1180 [ + + ][ + + ]: 193 : else if ( rc >= PINTO_RC_PINTO_ERRORS_MIN && rc <= PINTO_RC_PINTO_ERRORS_MAX )
1181 : : {
1182 : 188 : return _rcStrings[ PINTO_RC_STANDARD_ERRORS_MAX + rc - PINTO_RC_PINTO_ERRORS_MIN + 1 ];
1183 : : }
1184 : :
1185 : 2942 : return _rcUnknown;
1186 : : }
1187 : :
|