blob: d7e6b4a95a2449ecace6c1d5fceec89338f0f5a3 [file] [log] [blame]
The Android Open Source Project893912b2009-03-03 19:30:05 -08001
2/* pngrtran.c - transforms the data in a row for PNG readers
3 *
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004 * Last changed in libpng 1.2.38 [July 16, 2009]
The Android Open Source Project4215dd12009-03-09 11:52:12 -07005 * Copyright (c) 1998-2009 Glenn Randers-Pehrson
The Android Open Source Project893912b2009-03-03 19:30:05 -08006 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
8 *
Patrick Scotta0bb96c2009-07-22 11:50:02 -04009 * This code is released under the libpng license.
10 * For conditions of distribution and use, see the disclaimer
11 * and license in png.h
12 *
The Android Open Source Project893912b2009-03-03 19:30:05 -080013 * This file contains functions optionally called by an application
14 * in order to tell libpng how to handle data when reading a PNG.
15 * Transformations that are used in both reading and writing are
16 * in pngtrans.c.
17 */
18
19#define PNG_INTERNAL
20#include "png.h"
The Android Open Source Project893912b2009-03-03 19:30:05 -080021#if defined(PNG_READ_SUPPORTED)
22
23/* Set the action on getting a CRC error for an ancillary or critical chunk. */
24void PNGAPI
25png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
26{
The Android Open Source Project4215dd12009-03-09 11:52:12 -070027 png_debug(1, "in png_set_crc_action");
The Android Open Source Project893912b2009-03-03 19:30:05 -080028 /* Tell libpng how we react to CRC errors in critical chunks */
Patrick Scotta0bb96c2009-07-22 11:50:02 -040029 if (png_ptr == NULL)
30 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -080031 switch (crit_action)
32 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -040033 case PNG_CRC_NO_CHANGE: /* Leave setting as is */
The Android Open Source Project893912b2009-03-03 19:30:05 -080034 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040035
36 case PNG_CRC_WARN_USE: /* Warn/use data */
The Android Open Source Project893912b2009-03-03 19:30:05 -080037 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
38 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
39 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040040
41 case PNG_CRC_QUIET_USE: /* Quiet/use data */
The Android Open Source Project893912b2009-03-03 19:30:05 -080042 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
43 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
44 PNG_FLAG_CRC_CRITICAL_IGNORE;
45 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040046
47 case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */
The Android Open Source Project4215dd12009-03-09 11:52:12 -070048 png_warning(png_ptr,
49 "Can't discard critical data on CRC error.");
Patrick Scotta0bb96c2009-07-22 11:50:02 -040050 case PNG_CRC_ERROR_QUIT: /* Error/quit */
51
The Android Open Source Project893912b2009-03-03 19:30:05 -080052 case PNG_CRC_DEFAULT:
53 default:
54 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
55 break;
56 }
57
58 switch (ancil_action)
59 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -040060 case PNG_CRC_NO_CHANGE: /* Leave setting as is */
The Android Open Source Project893912b2009-03-03 19:30:05 -080061 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040062
63 case PNG_CRC_WARN_USE: /* Warn/use data */
The Android Open Source Project893912b2009-03-03 19:30:05 -080064 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
65 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
66 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040067
68 case PNG_CRC_QUIET_USE: /* Quiet/use data */
The Android Open Source Project893912b2009-03-03 19:30:05 -080069 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
70 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
71 PNG_FLAG_CRC_ANCILLARY_NOWARN;
72 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040073
74 case PNG_CRC_ERROR_QUIT: /* Error/quit */
The Android Open Source Project893912b2009-03-03 19:30:05 -080075 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
76 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
77 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040078
79 case PNG_CRC_WARN_DISCARD: /* Warn/discard data */
80
The Android Open Source Project893912b2009-03-03 19:30:05 -080081 case PNG_CRC_DEFAULT:
82 default:
83 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
84 break;
85 }
86}
87
88#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
89 defined(PNG_FLOATING_POINT_SUPPORTED)
Patrick Scotta0bb96c2009-07-22 11:50:02 -040090/* Handle alpha and tRNS via a background color */
The Android Open Source Project893912b2009-03-03 19:30:05 -080091void PNGAPI
92png_set_background(png_structp png_ptr,
93 png_color_16p background_color, int background_gamma_code,
94 int need_expand, double background_gamma)
95{
The Android Open Source Project4215dd12009-03-09 11:52:12 -070096 png_debug(1, "in png_set_background");
Patrick Scotta0bb96c2009-07-22 11:50:02 -040097 if (png_ptr == NULL)
98 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -080099 if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
100 {
101 png_warning(png_ptr, "Application must supply a known background gamma");
102 return;
103 }
104
105 png_ptr->transformations |= PNG_BACKGROUND;
106 png_memcpy(&(png_ptr->background), background_color,
107 png_sizeof(png_color_16));
108 png_ptr->background_gamma = (float)background_gamma;
109 png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
110 png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
111}
112#endif
113
114#if defined(PNG_READ_16_TO_8_SUPPORTED)
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400115/* Strip 16 bit depth files to 8 bit depth */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800116void PNGAPI
117png_set_strip_16(png_structp png_ptr)
118{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700119 png_debug(1, "in png_set_strip_16");
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400120 if (png_ptr == NULL)
121 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800122 png_ptr->transformations |= PNG_16_TO_8;
123}
124#endif
125
126#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
127void PNGAPI
128png_set_strip_alpha(png_structp png_ptr)
129{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700130 png_debug(1, "in png_set_strip_alpha");
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400131 if (png_ptr == NULL)
132 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800133 png_ptr->flags |= PNG_FLAG_STRIP_ALPHA;
134}
135#endif
136
137#if defined(PNG_READ_DITHER_SUPPORTED)
138/* Dither file to 8 bit. Supply a palette, the current number
139 * of elements in the palette, the maximum number of elements
140 * allowed, and a histogram if possible. If the current number
141 * of colors is greater then the maximum number, the palette will be
142 * modified to fit in the maximum number. "full_dither" indicates
143 * whether we need a dithering cube set up for RGB images, or if we
144 * simply are reducing the number of colors in a paletted image.
145 */
146
147typedef struct png_dsort_struct
148{
149 struct png_dsort_struct FAR * next;
150 png_byte left;
151 png_byte right;
152} png_dsort;
153typedef png_dsort FAR * png_dsortp;
154typedef png_dsort FAR * FAR * png_dsortpp;
155
156void PNGAPI
157png_set_dither(png_structp png_ptr, png_colorp palette,
158 int num_palette, int maximum_colors, png_uint_16p histogram,
159 int full_dither)
160{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700161 png_debug(1, "in png_set_dither");
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400162 if (png_ptr == NULL)
163 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800164 png_ptr->transformations |= PNG_DITHER;
165
166 if (!full_dither)
167 {
168 int i;
169
170 png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700171 (png_uint_32)(num_palette * png_sizeof(png_byte)));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800172 for (i = 0; i < num_palette; i++)
173 png_ptr->dither_index[i] = (png_byte)i;
174 }
175
176 if (num_palette > maximum_colors)
177 {
178 if (histogram != NULL)
179 {
180 /* This is easy enough, just throw out the least used colors.
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400181 * Perhaps not the best solution, but good enough.
182 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800183
184 int i;
185
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400186 /* Initialize an array to sort colors */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800187 png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700188 (png_uint_32)(num_palette * png_sizeof(png_byte)));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800189
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400190 /* Initialize the dither_sort array */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800191 for (i = 0; i < num_palette; i++)
192 png_ptr->dither_sort[i] = (png_byte)i;
193
194 /* Find the least used palette entries by starting a
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400195 * bubble sort, and running it until we have sorted
196 * out enough colors. Note that we don't care about
197 * sorting all the colors, just finding which are
198 * least used.
199 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800200
201 for (i = num_palette - 1; i >= maximum_colors; i--)
202 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400203 int done; /* To stop early if the list is pre-sorted */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800204 int j;
205
206 done = 1;
207 for (j = 0; j < i; j++)
208 {
209 if (histogram[png_ptr->dither_sort[j]]
210 < histogram[png_ptr->dither_sort[j + 1]])
211 {
212 png_byte t;
213
214 t = png_ptr->dither_sort[j];
215 png_ptr->dither_sort[j] = png_ptr->dither_sort[j + 1];
216 png_ptr->dither_sort[j + 1] = t;
217 done = 0;
218 }
219 }
220 if (done)
221 break;
222 }
223
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400224 /* Swap the palette around, and set up a table, if necessary */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800225 if (full_dither)
226 {
227 int j = num_palette;
228
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400229 /* Put all the useful colors within the max, but don't
230 * move the others.
231 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800232 for (i = 0; i < maximum_colors; i++)
233 {
234 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
235 {
236 do
237 j--;
238 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
239 palette[i] = palette[j];
240 }
241 }
242 }
243 else
244 {
245 int j = num_palette;
246
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400247 /* Move all the used colors inside the max limit, and
248 * develop a translation table.
249 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800250 for (i = 0; i < maximum_colors; i++)
251 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400252 /* Only move the colors we need to */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800253 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
254 {
255 png_color tmp_color;
256
257 do
258 j--;
259 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
260
261 tmp_color = palette[j];
262 palette[j] = palette[i];
263 palette[i] = tmp_color;
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400264 /* Indicate where the color went */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800265 png_ptr->dither_index[j] = (png_byte)i;
266 png_ptr->dither_index[i] = (png_byte)j;
267 }
268 }
269
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400270 /* Find closest color for those colors we are not using */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800271 for (i = 0; i < num_palette; i++)
272 {
273 if ((int)png_ptr->dither_index[i] >= maximum_colors)
274 {
275 int min_d, k, min_k, d_index;
276
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400277 /* Find the closest color to one we threw out */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800278 d_index = png_ptr->dither_index[i];
279 min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
280 for (k = 1, min_k = 0; k < maximum_colors; k++)
281 {
282 int d;
283
284 d = PNG_COLOR_DIST(palette[d_index], palette[k]);
285
286 if (d < min_d)
287 {
288 min_d = d;
289 min_k = k;
290 }
291 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400292 /* Point to closest color */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800293 png_ptr->dither_index[i] = (png_byte)min_k;
294 }
295 }
296 }
297 png_free(png_ptr, png_ptr->dither_sort);
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700298 png_ptr->dither_sort = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800299 }
300 else
301 {
302 /* This is much harder to do simply (and quickly). Perhaps
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400303 * we need to go through a median cut routine, but those
304 * don't always behave themselves with only a few colors
305 * as input. So we will just find the closest two colors,
306 * and throw out one of them (chosen somewhat randomly).
307 * [We don't understand this at all, so if someone wants to
308 * work on improving it, be our guest - AED, GRP]
309 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800310 int i;
311 int max_d;
312 int num_new_palette;
313 png_dsortp t;
314 png_dsortpp hash;
315
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700316 t = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800317
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400318 /* Initialize palette index arrays */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800319 png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700320 (png_uint_32)(num_palette * png_sizeof(png_byte)));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800321 png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700322 (png_uint_32)(num_palette * png_sizeof(png_byte)));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800323
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400324 /* Initialize the sort array */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800325 for (i = 0; i < num_palette; i++)
326 {
327 png_ptr->index_to_palette[i] = (png_byte)i;
328 png_ptr->palette_to_index[i] = (png_byte)i;
329 }
330
331 hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 *
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700332 png_sizeof(png_dsortp)));
333 png_memset(hash, 0, 769 * png_sizeof(png_dsortp));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800334
335 num_new_palette = num_palette;
336
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400337 /* Initial wild guess at how far apart the farthest pixel
338 * pair we will be eliminating will be. Larger
339 * numbers mean more areas will be allocated, Smaller
340 * numbers run the risk of not saving enough data, and
341 * having to do this all over again.
342 *
343 * I have not done extensive checking on this number.
344 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800345 max_d = 96;
346
347 while (num_new_palette > maximum_colors)
348 {
349 for (i = 0; i < num_new_palette - 1; i++)
350 {
351 int j;
352
353 for (j = i + 1; j < num_new_palette; j++)
354 {
355 int d;
356
357 d = PNG_COLOR_DIST(palette[i], palette[j]);
358
359 if (d <= max_d)
360 {
361
362 t = (png_dsortp)png_malloc_warn(png_ptr,
363 (png_uint_32)(png_sizeof(png_dsort)));
364 if (t == NULL)
365 break;
366 t->next = hash[d];
367 t->left = (png_byte)i;
368 t->right = (png_byte)j;
369 hash[d] = t;
370 }
371 }
372 if (t == NULL)
373 break;
374 }
375
376 if (t != NULL)
377 for (i = 0; i <= max_d; i++)
378 {
379 if (hash[i] != NULL)
380 {
381 png_dsortp p;
382
383 for (p = hash[i]; p; p = p->next)
384 {
385 if ((int)png_ptr->index_to_palette[p->left]
386 < num_new_palette &&
387 (int)png_ptr->index_to_palette[p->right]
388 < num_new_palette)
389 {
390 int j, next_j;
391
392 if (num_new_palette & 0x01)
393 {
394 j = p->left;
395 next_j = p->right;
396 }
397 else
398 {
399 j = p->right;
400 next_j = p->left;
401 }
402
403 num_new_palette--;
404 palette[png_ptr->index_to_palette[j]]
405 = palette[num_new_palette];
406 if (!full_dither)
407 {
408 int k;
409
410 for (k = 0; k < num_palette; k++)
411 {
412 if (png_ptr->dither_index[k] ==
413 png_ptr->index_to_palette[j])
414 png_ptr->dither_index[k] =
415 png_ptr->index_to_palette[next_j];
416 if ((int)png_ptr->dither_index[k] ==
417 num_new_palette)
418 png_ptr->dither_index[k] =
419 png_ptr->index_to_palette[j];
420 }
421 }
422
423 png_ptr->index_to_palette[png_ptr->palette_to_index
424 [num_new_palette]] = png_ptr->index_to_palette[j];
425 png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
426 = png_ptr->palette_to_index[num_new_palette];
427
428 png_ptr->index_to_palette[j] = (png_byte)num_new_palette;
429 png_ptr->palette_to_index[num_new_palette] = (png_byte)j;
430 }
431 if (num_new_palette <= maximum_colors)
432 break;
433 }
434 if (num_new_palette <= maximum_colors)
435 break;
436 }
437 }
438
439 for (i = 0; i < 769; i++)
440 {
441 if (hash[i] != NULL)
442 {
443 png_dsortp p = hash[i];
444 while (p)
445 {
446 t = p->next;
447 png_free(png_ptr, p);
448 p = t;
449 }
450 }
451 hash[i] = 0;
452 }
453 max_d += 96;
454 }
455 png_free(png_ptr, hash);
456 png_free(png_ptr, png_ptr->palette_to_index);
457 png_free(png_ptr, png_ptr->index_to_palette);
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700458 png_ptr->palette_to_index = NULL;
459 png_ptr->index_to_palette = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800460 }
461 num_palette = maximum_colors;
462 }
463 if (png_ptr->palette == NULL)
464 {
465 png_ptr->palette = palette;
466 }
467 png_ptr->num_palette = (png_uint_16)num_palette;
468
469 if (full_dither)
470 {
471 int i;
472 png_bytep distance;
473 int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
474 PNG_DITHER_BLUE_BITS;
475 int num_red = (1 << PNG_DITHER_RED_BITS);
476 int num_green = (1 << PNG_DITHER_GREEN_BITS);
477 int num_blue = (1 << PNG_DITHER_BLUE_BITS);
478 png_size_t num_entries = ((png_size_t)1 << total_bits);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800479 png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700480 (png_uint_32)(num_entries * png_sizeof(png_byte)));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800481 png_memset(png_ptr->palette_lookup, 0, num_entries *
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700482 png_sizeof(png_byte));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800483
484 distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
485 png_sizeof(png_byte)));
486
487 png_memset(distance, 0xff, num_entries * png_sizeof(png_byte));
488
489 for (i = 0; i < num_palette; i++)
490 {
491 int ir, ig, ib;
492 int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
493 int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
494 int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
495
496 for (ir = 0; ir < num_red; ir++)
497 {
498 /* int dr = abs(ir - r); */
499 int dr = ((ir > r) ? ir - r : r - ir);
500 int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
501
502 for (ig = 0; ig < num_green; ig++)
503 {
504 /* int dg = abs(ig - g); */
505 int dg = ((ig > g) ? ig - g : g - ig);
506 int dt = dr + dg;
507 int dm = ((dr > dg) ? dr : dg);
508 int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
509
510 for (ib = 0; ib < num_blue; ib++)
511 {
512 int d_index = index_g | ib;
513 /* int db = abs(ib - b); */
514 int db = ((ib > b) ? ib - b : b - ib);
515 int dmax = ((dm > db) ? dm : db);
516 int d = dmax + dt + db;
517
518 if (d < (int)distance[d_index])
519 {
520 distance[d_index] = (png_byte)d;
521 png_ptr->palette_lookup[d_index] = (png_byte)i;
522 }
523 }
524 }
525 }
526 }
527
528 png_free(png_ptr, distance);
529 }
530}
531#endif
532
533#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
534/* Transform the image from the file_gamma to the screen_gamma. We
535 * only do transformations on images where the file_gamma and screen_gamma
536 * are not close reciprocals, otherwise it slows things down slightly, and
537 * also needlessly introduces small errors.
538 *
539 * We will turn off gamma transformation later if no semitransparent entries
540 * are present in the tRNS array for palette images. We can't do it here
541 * because we don't necessarily have the tRNS chunk yet.
542 */
543void PNGAPI
544png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
545{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700546 png_debug(1, "in png_set_gamma");
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400547 if (png_ptr == NULL)
548 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800549 if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) ||
550 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) ||
551 (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
552 png_ptr->transformations |= PNG_GAMMA;
553 png_ptr->gamma = (float)file_gamma;
554 png_ptr->screen_gamma = (float)scrn_gamma;
555}
556#endif
557
558#if defined(PNG_READ_EXPAND_SUPPORTED)
559/* Expand paletted images to RGB, expand grayscale images of
560 * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
561 * to alpha channels.
562 */
563void PNGAPI
564png_set_expand(png_structp png_ptr)
565{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700566 png_debug(1, "in png_set_expand");
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400567 if (png_ptr == NULL)
568 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800569 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
570 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
571}
572
573/* GRR 19990627: the following three functions currently are identical
574 * to png_set_expand(). However, it is entirely reasonable that someone
575 * might wish to expand an indexed image to RGB but *not* expand a single,
576 * fully transparent palette entry to a full alpha channel--perhaps instead
577 * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
578 * the transparent color with a particular RGB value, or drop tRNS entirely.
579 * IOW, a future version of the library may make the transformations flag
580 * a bit more fine-grained, with separate bits for each of these three
581 * functions.
582 *
583 * More to the point, these functions make it obvious what libpng will be
584 * doing, whereas "expand" can (and does) mean any number of things.
585 *
586 * GRP 20060307: In libpng-1.4.0, png_set_gray_1_2_4_to_8() was modified
587 * to expand only the sample depth but not to expand the tRNS to alpha.
588 */
589
590/* Expand paletted images to RGB. */
591void PNGAPI
592png_set_palette_to_rgb(png_structp png_ptr)
593{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700594 png_debug(1, "in png_set_palette_to_rgb");
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400595 if (png_ptr == NULL)
596 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800597 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
598 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
599}
600
601#if !defined(PNG_1_0_X)
602/* Expand grayscale images of less than 8-bit depth to 8 bits. */
603void PNGAPI
604png_set_expand_gray_1_2_4_to_8(png_structp png_ptr)
605{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700606 png_debug(1, "in png_set_expand_gray_1_2_4_to_8");
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400607 if (png_ptr == NULL)
608 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800609 png_ptr->transformations |= PNG_EXPAND;
610 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
611}
612#endif
613
614#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
615/* Expand grayscale images of less than 8-bit depth to 8 bits. */
616/* Deprecated as of libpng-1.2.9 */
617void PNGAPI
618png_set_gray_1_2_4_to_8(png_structp png_ptr)
619{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700620 png_debug(1, "in png_set_gray_1_2_4_to_8");
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400621 if (png_ptr == NULL)
622 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800623 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
624}
625#endif
626
627
628/* Expand tRNS chunks to alpha channels. */
629void PNGAPI
630png_set_tRNS_to_alpha(png_structp png_ptr)
631{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700632 png_debug(1, "in png_set_tRNS_to_alpha");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800633 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
634 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
635}
636#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
637
638#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
639void PNGAPI
640png_set_gray_to_rgb(png_structp png_ptr)
641{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700642 png_debug(1, "in png_set_gray_to_rgb");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800643 png_ptr->transformations |= PNG_GRAY_TO_RGB;
644 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
645}
646#endif
647
648#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
649#if defined(PNG_FLOATING_POINT_SUPPORTED)
650/* Convert a RGB image to a grayscale of the same width. This allows us,
651 * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
652 */
653
654void PNGAPI
655png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red,
656 double green)
657{
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400658 int red_fixed = (int)((float)red*100000.0 + 0.5);
659 int green_fixed = (int)((float)green*100000.0 + 0.5);
660 if (png_ptr == NULL)
661 return;
662 png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800663}
664#endif
665
666void PNGAPI
667png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
668 png_fixed_point red, png_fixed_point green)
669{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700670 png_debug(1, "in png_set_rgb_to_gray");
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400671 if (png_ptr == NULL)
672 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800673 switch(error_action)
674 {
675 case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY;
676 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400677
The Android Open Source Project893912b2009-03-03 19:30:05 -0800678 case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
679 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400680
The Android Open Source Project893912b2009-03-03 19:30:05 -0800681 case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
682 }
683 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
684#if defined(PNG_READ_EXPAND_SUPPORTED)
685 png_ptr->transformations |= PNG_EXPAND;
686#else
687 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700688 png_warning(png_ptr,
689 "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED.");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800690 png_ptr->transformations &= ~PNG_RGB_TO_GRAY;
691 }
692#endif
693 {
694 png_uint_16 red_int, green_int;
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700695 if (red < 0 || green < 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800696 {
697 red_int = 6968; /* .212671 * 32768 + .5 */
698 green_int = 23434; /* .715160 * 32768 + .5 */
699 }
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700700 else if (red + green < 100000L)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800701 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400702 red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
703 green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800704 }
705 else
706 {
707 png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
708 red_int = 6968;
709 green_int = 23434;
710 }
711 png_ptr->rgb_to_gray_red_coeff = red_int;
712 png_ptr->rgb_to_gray_green_coeff = green_int;
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700713 png_ptr->rgb_to_gray_blue_coeff =
714 (png_uint_16)(32768 - red_int - green_int);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800715 }
716}
717#endif
718
719#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400720 defined(PNG_LEGACY_SUPPORTED) || \
721 defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800722void PNGAPI
723png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
724 read_user_transform_fn)
725{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700726 png_debug(1, "in png_set_read_user_transform_fn");
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400727 if (png_ptr == NULL)
728 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800729#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
730 png_ptr->transformations |= PNG_USER_TRANSFORM;
731 png_ptr->read_user_transform_fn = read_user_transform_fn;
732#endif
733#ifdef PNG_LEGACY_SUPPORTED
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700734 if (read_user_transform_fn)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800735 png_warning(png_ptr,
736 "This version of libpng does not support user transforms");
737#endif
738}
739#endif
740
741/* Initialize everything needed for the read. This includes modifying
742 * the palette.
743 */
744void /* PRIVATE */
745png_init_read_transformations(png_structp png_ptr)
746{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700747 png_debug(1, "in png_init_read_transformations");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800748#if defined(PNG_USELESS_TESTS_SUPPORTED)
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700749 if (png_ptr != NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800750#endif
751 {
752#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
753 || defined(PNG_READ_GAMMA_SUPPORTED)
754 int color_type = png_ptr->color_type;
755#endif
756
757#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
758
759#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
760 /* Detect gray background and attempt to enable optimization
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400761 * for gray --> RGB case
762 *
763 * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
The Android Open Source Project893912b2009-03-03 19:30:05 -0800764 * RGB_ALPHA (in which case need_expand is superfluous anyway), the
765 * background color might actually be gray yet not be flagged as such.
766 * This is not a problem for the current code, which uses
767 * PNG_BACKGROUND_IS_GRAY only to decide when to do the
768 * png_do_gray_to_rgb() transformation.
769 */
770 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
771 !(color_type & PNG_COLOR_MASK_COLOR))
772 {
773 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
774 } else if ((png_ptr->transformations & PNG_BACKGROUND) &&
775 !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
776 (png_ptr->transformations & PNG_GRAY_TO_RGB) &&
777 png_ptr->background.red == png_ptr->background.green &&
778 png_ptr->background.red == png_ptr->background.blue)
779 {
780 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
781 png_ptr->background.gray = png_ptr->background.red;
782 }
783#endif
784
785 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
786 (png_ptr->transformations & PNG_EXPAND))
787 {
788 if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
789 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400790 /* Expand background and tRNS chunks */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800791 switch (png_ptr->bit_depth)
792 {
793 case 1:
794 png_ptr->background.gray *= (png_uint_16)0xff;
795 png_ptr->background.red = png_ptr->background.green
796 = png_ptr->background.blue = png_ptr->background.gray;
797 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
798 {
799 png_ptr->trans_values.gray *= (png_uint_16)0xff;
800 png_ptr->trans_values.red = png_ptr->trans_values.green
801 = png_ptr->trans_values.blue = png_ptr->trans_values.gray;
802 }
803 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400804
The Android Open Source Project893912b2009-03-03 19:30:05 -0800805 case 2:
806 png_ptr->background.gray *= (png_uint_16)0x55;
807 png_ptr->background.red = png_ptr->background.green
808 = png_ptr->background.blue = png_ptr->background.gray;
809 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
810 {
811 png_ptr->trans_values.gray *= (png_uint_16)0x55;
812 png_ptr->trans_values.red = png_ptr->trans_values.green
813 = png_ptr->trans_values.blue = png_ptr->trans_values.gray;
814 }
815 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400816
The Android Open Source Project893912b2009-03-03 19:30:05 -0800817 case 4:
818 png_ptr->background.gray *= (png_uint_16)0x11;
819 png_ptr->background.red = png_ptr->background.green
820 = png_ptr->background.blue = png_ptr->background.gray;
821 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
822 {
823 png_ptr->trans_values.gray *= (png_uint_16)0x11;
824 png_ptr->trans_values.red = png_ptr->trans_values.green
825 = png_ptr->trans_values.blue = png_ptr->trans_values.gray;
826 }
827 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400828
The Android Open Source Project893912b2009-03-03 19:30:05 -0800829 case 8:
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400830
The Android Open Source Project893912b2009-03-03 19:30:05 -0800831 case 16:
832 png_ptr->background.red = png_ptr->background.green
833 = png_ptr->background.blue = png_ptr->background.gray;
834 break;
835 }
836 }
837 else if (color_type == PNG_COLOR_TYPE_PALETTE)
838 {
839 png_ptr->background.red =
840 png_ptr->palette[png_ptr->background.index].red;
841 png_ptr->background.green =
842 png_ptr->palette[png_ptr->background.index].green;
843 png_ptr->background.blue =
844 png_ptr->palette[png_ptr->background.index].blue;
845
846#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
847 if (png_ptr->transformations & PNG_INVERT_ALPHA)
848 {
849#if defined(PNG_READ_EXPAND_SUPPORTED)
850 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
851#endif
852 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400853 /* Invert the alpha channel (in tRNS) unless the pixels are
854 * going to be expanded, in which case leave it for later
855 */
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700856 int i, istop;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800857 istop=(int)png_ptr->num_trans;
858 for (i=0; i<istop; i++)
859 png_ptr->trans[i] = (png_byte)(255 - png_ptr->trans[i]);
860 }
861 }
862#endif
863
864 }
865 }
866#endif
867
868#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
869 png_ptr->background_1 = png_ptr->background;
870#endif
871#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
872
873 if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0)
874 && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0)
875 < PNG_GAMMA_THRESHOLD))
876 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700877 int i, k;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800878 k=0;
879 for (i=0; i<png_ptr->num_trans; i++)
880 {
881 if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff)
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400882 k=1; /* Partial transparency is present */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800883 }
884 if (k == 0)
885 png_ptr->transformations &= ~PNG_GAMMA;
886 }
887
888 if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) &&
889 png_ptr->gamma != 0.0)
890 {
891 png_build_gamma_table(png_ptr);
892#if defined(PNG_READ_BACKGROUND_SUPPORTED)
893 if (png_ptr->transformations & PNG_BACKGROUND)
894 {
895 if (color_type == PNG_COLOR_TYPE_PALETTE)
896 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400897 /* Could skip if no transparency */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800898 png_color back, back_1;
899 png_colorp palette = png_ptr->palette;
900 int num_palette = png_ptr->num_palette;
901 int i;
902 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
903 {
904 back.red = png_ptr->gamma_table[png_ptr->background.red];
905 back.green = png_ptr->gamma_table[png_ptr->background.green];
906 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
907
908 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
909 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
910 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
911 }
912 else
913 {
914 double g, gs;
915
916 switch (png_ptr->background_gamma_type)
917 {
918 case PNG_BACKGROUND_GAMMA_SCREEN:
919 g = (png_ptr->screen_gamma);
920 gs = 1.0;
921 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400922
The Android Open Source Project893912b2009-03-03 19:30:05 -0800923 case PNG_BACKGROUND_GAMMA_FILE:
924 g = 1.0 / (png_ptr->gamma);
925 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
926 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400927
The Android Open Source Project893912b2009-03-03 19:30:05 -0800928 case PNG_BACKGROUND_GAMMA_UNIQUE:
929 g = 1.0 / (png_ptr->background_gamma);
930 gs = 1.0 / (png_ptr->background_gamma *
931 png_ptr->screen_gamma);
932 break;
933 default:
934 g = 1.0; /* back_1 */
935 gs = 1.0; /* back */
936 }
937
938 if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD)
939 {
940 back.red = (png_byte)png_ptr->background.red;
941 back.green = (png_byte)png_ptr->background.green;
942 back.blue = (png_byte)png_ptr->background.blue;
943 }
944 else
945 {
946 back.red = (png_byte)(pow(
947 (double)png_ptr->background.red/255, gs) * 255.0 + .5);
948 back.green = (png_byte)(pow(
949 (double)png_ptr->background.green/255, gs) * 255.0 + .5);
950 back.blue = (png_byte)(pow(
951 (double)png_ptr->background.blue/255, gs) * 255.0 + .5);
952 }
953
954 back_1.red = (png_byte)(pow(
955 (double)png_ptr->background.red/255, g) * 255.0 + .5);
956 back_1.green = (png_byte)(pow(
957 (double)png_ptr->background.green/255, g) * 255.0 + .5);
958 back_1.blue = (png_byte)(pow(
959 (double)png_ptr->background.blue/255, g) * 255.0 + .5);
960 }
961 for (i = 0; i < num_palette; i++)
962 {
963 if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
964 {
965 if (png_ptr->trans[i] == 0)
966 {
967 palette[i] = back;
968 }
969 else /* if (png_ptr->trans[i] != 0xff) */
970 {
971 png_byte v, w;
972
973 v = png_ptr->gamma_to_1[palette[i].red];
974 png_composite(w, v, png_ptr->trans[i], back_1.red);
975 palette[i].red = png_ptr->gamma_from_1[w];
976
977 v = png_ptr->gamma_to_1[palette[i].green];
978 png_composite(w, v, png_ptr->trans[i], back_1.green);
979 palette[i].green = png_ptr->gamma_from_1[w];
980
981 v = png_ptr->gamma_to_1[palette[i].blue];
982 png_composite(w, v, png_ptr->trans[i], back_1.blue);
983 palette[i].blue = png_ptr->gamma_from_1[w];
984 }
985 }
986 else
987 {
988 palette[i].red = png_ptr->gamma_table[palette[i].red];
989 palette[i].green = png_ptr->gamma_table[palette[i].green];
990 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
991 }
992 }
993 /* Prevent the transformations being done again, and make sure
994 * that the now spurious alpha channel is stripped - the code
995 * has just reduced background composition and gamma correction
996 * to a simple alpha channel strip.
997 */
998 png_ptr->transformations &= ~PNG_BACKGROUND;
999 png_ptr->transformations &= ~PNG_GAMMA;
1000 png_ptr->transformations |= PNG_STRIP_ALPHA;
1001 }
1002 /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */
1003 else
1004 /* color_type != PNG_COLOR_TYPE_PALETTE */
1005 {
1006 double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
1007 double g = 1.0;
1008 double gs = 1.0;
1009
1010 switch (png_ptr->background_gamma_type)
1011 {
1012 case PNG_BACKGROUND_GAMMA_SCREEN:
1013 g = (png_ptr->screen_gamma);
1014 gs = 1.0;
1015 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001016
The Android Open Source Project893912b2009-03-03 19:30:05 -08001017 case PNG_BACKGROUND_GAMMA_FILE:
1018 g = 1.0 / (png_ptr->gamma);
1019 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
1020 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001021
The Android Open Source Project893912b2009-03-03 19:30:05 -08001022 case PNG_BACKGROUND_GAMMA_UNIQUE:
1023 g = 1.0 / (png_ptr->background_gamma);
1024 gs = 1.0 / (png_ptr->background_gamma *
1025 png_ptr->screen_gamma);
1026 break;
1027 }
1028
1029 png_ptr->background_1.gray = (png_uint_16)(pow(
1030 (double)png_ptr->background.gray / m, g) * m + .5);
1031 png_ptr->background.gray = (png_uint_16)(pow(
1032 (double)png_ptr->background.gray / m, gs) * m + .5);
1033
1034 if ((png_ptr->background.red != png_ptr->background.green) ||
1035 (png_ptr->background.red != png_ptr->background.blue) ||
1036 (png_ptr->background.red != png_ptr->background.gray))
1037 {
1038 /* RGB or RGBA with color background */
1039 png_ptr->background_1.red = (png_uint_16)(pow(
1040 (double)png_ptr->background.red / m, g) * m + .5);
1041 png_ptr->background_1.green = (png_uint_16)(pow(
1042 (double)png_ptr->background.green / m, g) * m + .5);
1043 png_ptr->background_1.blue = (png_uint_16)(pow(
1044 (double)png_ptr->background.blue / m, g) * m + .5);
1045 png_ptr->background.red = (png_uint_16)(pow(
1046 (double)png_ptr->background.red / m, gs) * m + .5);
1047 png_ptr->background.green = (png_uint_16)(pow(
1048 (double)png_ptr->background.green / m, gs) * m + .5);
1049 png_ptr->background.blue = (png_uint_16)(pow(
1050 (double)png_ptr->background.blue / m, gs) * m + .5);
1051 }
1052 else
1053 {
1054 /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */
1055 png_ptr->background_1.red = png_ptr->background_1.green
1056 = png_ptr->background_1.blue = png_ptr->background_1.gray;
1057 png_ptr->background.red = png_ptr->background.green
1058 = png_ptr->background.blue = png_ptr->background.gray;
1059 }
1060 }
1061 }
1062 else
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001063 /* Transformation does not include PNG_BACKGROUND */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001064#endif /* PNG_READ_BACKGROUND_SUPPORTED */
1065 if (color_type == PNG_COLOR_TYPE_PALETTE)
1066 {
1067 png_colorp palette = png_ptr->palette;
1068 int num_palette = png_ptr->num_palette;
1069 int i;
1070
1071 for (i = 0; i < num_palette; i++)
1072 {
1073 palette[i].red = png_ptr->gamma_table[palette[i].red];
1074 palette[i].green = png_ptr->gamma_table[palette[i].green];
1075 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
1076 }
1077
1078 /* Done the gamma correction. */
1079 png_ptr->transformations &= ~PNG_GAMMA;
1080 }
1081 }
1082#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1083 else
1084#endif
1085#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */
1086#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1087 /* No GAMMA transformation */
1088 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1089 (color_type == PNG_COLOR_TYPE_PALETTE))
1090 {
1091 int i;
1092 int istop = (int)png_ptr->num_trans;
1093 png_color back;
1094 png_colorp palette = png_ptr->palette;
1095
1096 back.red = (png_byte)png_ptr->background.red;
1097 back.green = (png_byte)png_ptr->background.green;
1098 back.blue = (png_byte)png_ptr->background.blue;
1099
1100 for (i = 0; i < istop; i++)
1101 {
1102 if (png_ptr->trans[i] == 0)
1103 {
1104 palette[i] = back;
1105 }
1106 else if (png_ptr->trans[i] != 0xff)
1107 {
1108 /* The png_composite() macro is defined in png.h */
1109 png_composite(palette[i].red, palette[i].red,
1110 png_ptr->trans[i], back.red);
1111 png_composite(palette[i].green, palette[i].green,
1112 png_ptr->trans[i], back.green);
1113 png_composite(palette[i].blue, palette[i].blue,
1114 png_ptr->trans[i], back.blue);
1115 }
1116 }
1117
1118 /* Handled alpha, still need to strip the channel. */
1119 png_ptr->transformations &= ~PNG_BACKGROUND;
1120 png_ptr->transformations |= PNG_STRIP_ALPHA;
1121 }
1122#endif /* PNG_READ_BACKGROUND_SUPPORTED */
1123
1124#if defined(PNG_READ_SHIFT_SUPPORTED)
1125 if ((png_ptr->transformations & PNG_SHIFT) &&
1126 (color_type == PNG_COLOR_TYPE_PALETTE))
1127 {
1128 png_uint_16 i;
1129 png_uint_16 istop = png_ptr->num_palette;
1130 int sr = 8 - png_ptr->sig_bit.red;
1131 int sg = 8 - png_ptr->sig_bit.green;
1132 int sb = 8 - png_ptr->sig_bit.blue;
1133
1134 if (sr < 0 || sr > 8)
1135 sr = 0;
1136 if (sg < 0 || sg > 8)
1137 sg = 0;
1138 if (sb < 0 || sb > 8)
1139 sb = 0;
1140 for (i = 0; i < istop; i++)
1141 {
1142 png_ptr->palette[i].red >>= sr;
1143 png_ptr->palette[i].green >>= sg;
1144 png_ptr->palette[i].blue >>= sb;
1145 }
1146 }
1147#endif /* PNG_READ_SHIFT_SUPPORTED */
1148 }
1149#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \
1150 && !defined(PNG_READ_BACKGROUND_SUPPORTED)
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001151 if (png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001152 return;
1153#endif
1154}
1155
1156/* Modify the info structure to reflect the transformations. The
1157 * info should be updated so a PNG file could be written with it,
1158 * assuming the transformations result in valid PNG data.
1159 */
1160void /* PRIVATE */
1161png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
1162{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001163 png_debug(1, "in png_read_transform_info");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001164#if defined(PNG_READ_EXPAND_SUPPORTED)
1165 if (png_ptr->transformations & PNG_EXPAND)
1166 {
1167 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1168 {
1169 if (png_ptr->num_trans &&
1170 (png_ptr->transformations & PNG_EXPAND_tRNS))
1171 info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1172 else
1173 info_ptr->color_type = PNG_COLOR_TYPE_RGB;
1174 info_ptr->bit_depth = 8;
1175 info_ptr->num_trans = 0;
1176 }
1177 else
1178 {
1179 if (png_ptr->num_trans)
1180 {
1181 if (png_ptr->transformations & PNG_EXPAND_tRNS)
1182 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001183 }
1184 if (info_ptr->bit_depth < 8)
1185 info_ptr->bit_depth = 8;
1186 info_ptr->num_trans = 0;
1187 }
1188 }
1189#endif
1190
1191#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1192 if (png_ptr->transformations & PNG_BACKGROUND)
1193 {
1194 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
1195 info_ptr->num_trans = 0;
1196 info_ptr->background = png_ptr->background;
1197 }
1198#endif
1199
1200#if defined(PNG_READ_GAMMA_SUPPORTED)
1201 if (png_ptr->transformations & PNG_GAMMA)
1202 {
1203#ifdef PNG_FLOATING_POINT_SUPPORTED
1204 info_ptr->gamma = png_ptr->gamma;
1205#endif
1206#ifdef PNG_FIXED_POINT_SUPPORTED
1207 info_ptr->int_gamma = png_ptr->int_gamma;
1208#endif
1209 }
1210#endif
1211
1212#if defined(PNG_READ_16_TO_8_SUPPORTED)
1213 if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16))
1214 info_ptr->bit_depth = 8;
1215#endif
1216
1217#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1218 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
1219 info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
1220#endif
1221
1222#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1223 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1224 info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
1225#endif
1226
1227#if defined(PNG_READ_DITHER_SUPPORTED)
1228 if (png_ptr->transformations & PNG_DITHER)
1229 {
1230 if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001231 (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
1232 png_ptr->palette_lookup && info_ptr->bit_depth == 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001233 {
1234 info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
1235 }
1236 }
1237#endif
1238
1239#if defined(PNG_READ_PACK_SUPPORTED)
1240 if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
1241 info_ptr->bit_depth = 8;
1242#endif
1243
1244 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1245 info_ptr->channels = 1;
1246 else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
1247 info_ptr->channels = 3;
1248 else
1249 info_ptr->channels = 1;
1250
1251#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
1252 if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
1253 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
1254#endif
1255
1256 if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
1257 info_ptr->channels++;
1258
1259#if defined(PNG_READ_FILLER_SUPPORTED)
1260 /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
1261 if ((png_ptr->transformations & PNG_FILLER) &&
1262 ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
1263 (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))
1264 {
1265 info_ptr->channels++;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001266 /* If adding a true alpha channel not just filler */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001267#if !defined(PNG_1_0_X)
1268 if (png_ptr->transformations & PNG_ADD_ALPHA)
1269 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
1270#endif
1271 }
1272#endif
1273
1274#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
1275defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001276 if (png_ptr->transformations & PNG_USER_TRANSFORM)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001277 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001278 if (info_ptr->bit_depth < png_ptr->user_transform_depth)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001279 info_ptr->bit_depth = png_ptr->user_transform_depth;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001280 if (info_ptr->channels < png_ptr->user_transform_channels)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001281 info_ptr->channels = png_ptr->user_transform_channels;
1282 }
1283#endif
1284
1285 info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
1286 info_ptr->bit_depth);
1287
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001288 info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001289
1290#if !defined(PNG_READ_EXPAND_SUPPORTED)
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001291 if (png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001292 return;
1293#endif
1294}
1295
1296/* Transform the row. The order of transformations is significant,
1297 * and is very touchy. If you add a transformation, take care to
1298 * decide how it fits in with the other transformations here.
1299 */
1300void /* PRIVATE */
1301png_do_read_transformations(png_structp png_ptr)
1302{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001303 png_debug(1, "in png_do_read_transformations");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001304 if (png_ptr->row_buf == NULL)
1305 {
1306#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
1307 char msg[50];
1308
1309 png_snprintf2(msg, 50,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001310 "NULL row buffer for row %ld, pass %d", (long)png_ptr->row_number,
The Android Open Source Project893912b2009-03-03 19:30:05 -08001311 png_ptr->pass);
1312 png_error(png_ptr, msg);
1313#else
1314 png_error(png_ptr, "NULL row buffer");
1315#endif
1316 }
1317#ifdef PNG_WARN_UNINITIALIZED_ROW
1318 if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
1319 /* Application has failed to call either png_read_start_image()
1320 * or png_read_update_info() after setting transforms that expand
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001321 * pixels. This check added to libpng-1.2.19
1322 */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001323#if (PNG_WARN_UNINITIALIZED_ROW==1)
1324 png_error(png_ptr, "Uninitialized row");
1325#else
1326 png_warning(png_ptr, "Uninitialized row");
1327#endif
1328#endif
1329
1330#if defined(PNG_READ_EXPAND_SUPPORTED)
1331 if (png_ptr->transformations & PNG_EXPAND)
1332 {
1333 if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
1334 {
1335 png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
1336 png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
1337 }
1338 else
1339 {
1340 if (png_ptr->num_trans &&
1341 (png_ptr->transformations & PNG_EXPAND_tRNS))
1342 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1343 &(png_ptr->trans_values));
1344 else
1345 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1346 NULL);
1347 }
1348 }
1349#endif
1350
1351#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
1352 if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
1353 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
1354 PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA));
1355#endif
1356
1357#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1358 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1359 {
1360 int rgb_error =
1361 png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001362 if (rgb_error)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001363 {
1364 png_ptr->rgb_to_gray_status=1;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001365 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
The Android Open Source Project893912b2009-03-03 19:30:05 -08001366 PNG_RGB_TO_GRAY_WARN)
1367 png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001368 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
The Android Open Source Project893912b2009-03-03 19:30:05 -08001369 PNG_RGB_TO_GRAY_ERR)
1370 png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1371 }
1372 }
1373#endif
1374
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001375/* From Andreas Dilger e-mail to png-implement, 26 March 1998:
1376 *
1377 * In most cases, the "simple transparency" should be done prior to doing
1378 * gray-to-RGB, or you will have to test 3x as many bytes to check if a
1379 * pixel is transparent. You would also need to make sure that the
1380 * transparency information is upgraded to RGB.
1381 *
1382 * To summarize, the current flow is:
1383 * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
1384 * with background "in place" if transparent,
1385 * convert to RGB if necessary
1386 * - Gray + alpha -> composite with gray background and remove alpha bytes,
1387 * convert to RGB if necessary
1388 *
1389 * To support RGB backgrounds for gray images we need:
1390 * - Gray + simple transparency -> convert to RGB + simple transparency,
1391 * compare 3 or 6 bytes and composite with
1392 * background "in place" if transparent
1393 * (3x compare/pixel compared to doing
1394 * composite with gray bkgrnd)
1395 * - Gray + alpha -> convert to RGB + alpha, composite with background and
1396 * remove alpha bytes (3x float
1397 * operations/pixel compared with composite
1398 * on gray background)
1399 *
1400 * Greg's change will do this. The reason it wasn't done before is for
1401 * performance, as this increases the per-pixel operations. If we would check
1402 * in advance if the background was gray or RGB, and position the gray-to-RGB
1403 * transform appropriately, then it would save a lot of work/time.
The Android Open Source Project893912b2009-03-03 19:30:05 -08001404 */
1405
1406#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001407 /* If gray -> RGB, do so now only if background is non-gray; else do later
1408 * for performance reasons
1409 */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001410 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
1411 !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
1412 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
1413#endif
1414
1415#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1416 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1417 ((png_ptr->num_trans != 0 ) ||
1418 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
1419 png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
1420 &(png_ptr->trans_values), &(png_ptr->background)
1421#if defined(PNG_READ_GAMMA_SUPPORTED)
1422 , &(png_ptr->background_1),
1423 png_ptr->gamma_table, png_ptr->gamma_from_1,
1424 png_ptr->gamma_to_1, png_ptr->gamma_16_table,
1425 png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
1426 png_ptr->gamma_shift
1427#endif
1428);
1429#endif
1430
1431#if defined(PNG_READ_GAMMA_SUPPORTED)
1432 if ((png_ptr->transformations & PNG_GAMMA) &&
1433#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001434 !((png_ptr->transformations & PNG_BACKGROUND) &&
1435 ((png_ptr->num_trans != 0) ||
1436 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
The Android Open Source Project893912b2009-03-03 19:30:05 -08001437#endif
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001438 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
The Android Open Source Project893912b2009-03-03 19:30:05 -08001439 png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001440 png_ptr->gamma_table, png_ptr->gamma_16_table,
1441 png_ptr->gamma_shift);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001442#endif
1443
1444#if defined(PNG_READ_16_TO_8_SUPPORTED)
1445 if (png_ptr->transformations & PNG_16_TO_8)
1446 png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
1447#endif
1448
1449#if defined(PNG_READ_DITHER_SUPPORTED)
1450 if (png_ptr->transformations & PNG_DITHER)
1451 {
1452 png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
1453 png_ptr->palette_lookup, png_ptr->dither_index);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001454 if (png_ptr->row_info.rowbytes == (png_uint_32)0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001455 png_error(png_ptr, "png_do_dither returned rowbytes=0");
1456 }
1457#endif
1458
1459#if defined(PNG_READ_INVERT_SUPPORTED)
1460 if (png_ptr->transformations & PNG_INVERT_MONO)
1461 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
1462#endif
1463
1464#if defined(PNG_READ_SHIFT_SUPPORTED)
1465 if (png_ptr->transformations & PNG_SHIFT)
1466 png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
1467 &(png_ptr->shift));
1468#endif
1469
1470#if defined(PNG_READ_PACK_SUPPORTED)
1471 if (png_ptr->transformations & PNG_PACK)
1472 png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
1473#endif
1474
1475#if defined(PNG_READ_BGR_SUPPORTED)
1476 if (png_ptr->transformations & PNG_BGR)
1477 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
1478#endif
1479
1480#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1481 if (png_ptr->transformations & PNG_PACKSWAP)
1482 png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1483#endif
1484
1485#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001486 /* If gray -> RGB, do so now only if we did not do so above */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001487 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
1488 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
1489 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
1490#endif
1491
1492#if defined(PNG_READ_FILLER_SUPPORTED)
1493 if (png_ptr->transformations & PNG_FILLER)
1494 png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
1495 (png_uint_32)png_ptr->filler, png_ptr->flags);
1496#endif
1497
1498#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
1499 if (png_ptr->transformations & PNG_INVERT_ALPHA)
1500 png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1501#endif
1502
1503#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
1504 if (png_ptr->transformations & PNG_SWAP_ALPHA)
1505 png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1506#endif
1507
1508#if defined(PNG_READ_SWAP_SUPPORTED)
1509 if (png_ptr->transformations & PNG_SWAP_BYTES)
1510 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1511#endif
1512
1513#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1514 if (png_ptr->transformations & PNG_USER_TRANSFORM)
1515 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001516 if (png_ptr->read_user_transform_fn != NULL)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001517 (*(png_ptr->read_user_transform_fn)) /* User read transform function */
1518 (png_ptr, /* png_ptr */
1519 &(png_ptr->row_info), /* row_info: */
1520 /* png_uint_32 width; width of row */
1521 /* png_uint_32 rowbytes; number of bytes in row */
1522 /* png_byte color_type; color type of pixels */
1523 /* png_byte bit_depth; bit depth of samples */
1524 /* png_byte channels; number of channels (1-4) */
1525 /* png_byte pixel_depth; bits per pixel (depth*channels) */
1526 png_ptr->row_buf + 1); /* start of pixel data for row */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001527#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001528 if (png_ptr->user_transform_depth)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001529 png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001530 if (png_ptr->user_transform_channels)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001531 png_ptr->row_info.channels = png_ptr->user_transform_channels;
1532#endif
1533 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
1534 png_ptr->row_info.channels);
1535 png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
1536 png_ptr->row_info.width);
1537 }
1538#endif
1539
1540}
1541
1542#if defined(PNG_READ_PACK_SUPPORTED)
1543/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
1544 * without changing the actual values. Thus, if you had a row with
1545 * a bit depth of 1, you would end up with bytes that only contained
1546 * the numbers 0 or 1. If you would rather they contain 0 and 255, use
1547 * png_do_shift() after this.
1548 */
1549void /* PRIVATE */
1550png_do_unpack(png_row_infop row_info, png_bytep row)
1551{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001552 png_debug(1, "in png_do_unpack");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001553#if defined(PNG_USELESS_TESTS_SUPPORTED)
1554 if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
1555#else
1556 if (row_info->bit_depth < 8)
1557#endif
1558 {
1559 png_uint_32 i;
1560 png_uint_32 row_width=row_info->width;
1561
1562 switch (row_info->bit_depth)
1563 {
1564 case 1:
1565 {
1566 png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
1567 png_bytep dp = row + (png_size_t)row_width - 1;
1568 png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
1569 for (i = 0; i < row_width; i++)
1570 {
1571 *dp = (png_byte)((*sp >> shift) & 0x01);
1572 if (shift == 7)
1573 {
1574 shift = 0;
1575 sp--;
1576 }
1577 else
1578 shift++;
1579
1580 dp--;
1581 }
1582 break;
1583 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001584
The Android Open Source Project893912b2009-03-03 19:30:05 -08001585 case 2:
1586 {
1587
1588 png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
1589 png_bytep dp = row + (png_size_t)row_width - 1;
1590 png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
1591 for (i = 0; i < row_width; i++)
1592 {
1593 *dp = (png_byte)((*sp >> shift) & 0x03);
1594 if (shift == 6)
1595 {
1596 shift = 0;
1597 sp--;
1598 }
1599 else
1600 shift += 2;
1601
1602 dp--;
1603 }
1604 break;
1605 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001606
The Android Open Source Project893912b2009-03-03 19:30:05 -08001607 case 4:
1608 {
1609 png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
1610 png_bytep dp = row + (png_size_t)row_width - 1;
1611 png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
1612 for (i = 0; i < row_width; i++)
1613 {
1614 *dp = (png_byte)((*sp >> shift) & 0x0f);
1615 if (shift == 4)
1616 {
1617 shift = 0;
1618 sp--;
1619 }
1620 else
1621 shift = 4;
1622
1623 dp--;
1624 }
1625 break;
1626 }
1627 }
1628 row_info->bit_depth = 8;
1629 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
1630 row_info->rowbytes = row_width * row_info->channels;
1631 }
1632}
1633#endif
1634
1635#if defined(PNG_READ_SHIFT_SUPPORTED)
1636/* Reverse the effects of png_do_shift. This routine merely shifts the
1637 * pixels back to their significant bits values. Thus, if you have
1638 * a row of bit depth 8, but only 5 are significant, this will shift
1639 * the values back to 0 through 31.
1640 */
1641void /* PRIVATE */
1642png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
1643{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001644 png_debug(1, "in png_do_unshift");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001645 if (
1646#if defined(PNG_USELESS_TESTS_SUPPORTED)
1647 row != NULL && row_info != NULL && sig_bits != NULL &&
1648#endif
1649 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
1650 {
1651 int shift[4];
1652 int channels = 0;
1653 int c;
1654 png_uint_16 value = 0;
1655 png_uint_32 row_width = row_info->width;
1656
1657 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
1658 {
1659 shift[channels++] = row_info->bit_depth - sig_bits->red;
1660 shift[channels++] = row_info->bit_depth - sig_bits->green;
1661 shift[channels++] = row_info->bit_depth - sig_bits->blue;
1662 }
1663 else
1664 {
1665 shift[channels++] = row_info->bit_depth - sig_bits->gray;
1666 }
1667 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
1668 {
1669 shift[channels++] = row_info->bit_depth - sig_bits->alpha;
1670 }
1671
1672 for (c = 0; c < channels; c++)
1673 {
1674 if (shift[c] <= 0)
1675 shift[c] = 0;
1676 else
1677 value = 1;
1678 }
1679
1680 if (!value)
1681 return;
1682
1683 switch (row_info->bit_depth)
1684 {
1685 case 2:
1686 {
1687 png_bytep bp;
1688 png_uint_32 i;
1689 png_uint_32 istop = row_info->rowbytes;
1690
1691 for (bp = row, i = 0; i < istop; i++)
1692 {
1693 *bp >>= 1;
1694 *bp++ &= 0x55;
1695 }
1696 break;
1697 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001698
The Android Open Source Project893912b2009-03-03 19:30:05 -08001699 case 4:
1700 {
1701 png_bytep bp = row;
1702 png_uint_32 i;
1703 png_uint_32 istop = row_info->rowbytes;
1704 png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
1705 (png_byte)((int)0xf >> shift[0]));
1706
1707 for (i = 0; i < istop; i++)
1708 {
1709 *bp >>= shift[0];
1710 *bp++ &= mask;
1711 }
1712 break;
1713 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001714
The Android Open Source Project893912b2009-03-03 19:30:05 -08001715 case 8:
1716 {
1717 png_bytep bp = row;
1718 png_uint_32 i;
1719 png_uint_32 istop = row_width * channels;
1720
1721 for (i = 0; i < istop; i++)
1722 {
1723 *bp++ >>= shift[i%channels];
1724 }
1725 break;
1726 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001727
The Android Open Source Project893912b2009-03-03 19:30:05 -08001728 case 16:
1729 {
1730 png_bytep bp = row;
1731 png_uint_32 i;
1732 png_uint_32 istop = channels * row_width;
1733
1734 for (i = 0; i < istop; i++)
1735 {
1736 value = (png_uint_16)((*bp << 8) + *(bp + 1));
1737 value >>= shift[i%channels];
1738 *bp++ = (png_byte)(value >> 8);
1739 *bp++ = (png_byte)(value & 0xff);
1740 }
1741 break;
1742 }
1743 }
1744 }
1745}
1746#endif
1747
1748#if defined(PNG_READ_16_TO_8_SUPPORTED)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001749/* Chop rows of bit depth 16 down to 8 */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001750void /* PRIVATE */
1751png_do_chop(png_row_infop row_info, png_bytep row)
1752{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001753 png_debug(1, "in png_do_chop");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001754#if defined(PNG_USELESS_TESTS_SUPPORTED)
1755 if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
1756#else
1757 if (row_info->bit_depth == 16)
1758#endif
1759 {
1760 png_bytep sp = row;
1761 png_bytep dp = row;
1762 png_uint_32 i;
1763 png_uint_32 istop = row_info->width * row_info->channels;
1764
1765 for (i = 0; i<istop; i++, sp += 2, dp++)
1766 {
1767#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
1768 /* This does a more accurate scaling of the 16-bit color
1769 * value, rather than a simple low-byte truncation.
1770 *
1771 * What the ideal calculation should be:
1772 * *dp = (((((png_uint_32)(*sp) << 8) |
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001773 * (png_uint_32)(*(sp + 1))) * 255 + 127)
1774 * / (png_uint_32)65535L;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001775 *
1776 * GRR: no, I think this is what it really should be:
1777 * *dp = (((((png_uint_32)(*sp) << 8) |
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001778 * (png_uint_32)(*(sp + 1))) + 128L)
1779 * / (png_uint_32)257L;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001780 *
1781 * GRR: here's the exact calculation with shifts:
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001782 * temp = (((png_uint_32)(*sp) << 8) |
1783 * (png_uint_32)(*(sp + 1))) + 128L;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001784 * *dp = (temp - (temp >> 8)) >> 8;
1785 *
1786 * Approximate calculation with shift/add instead of multiply/divide:
1787 * *dp = ((((png_uint_32)(*sp) << 8) |
1788 * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
1789 *
1790 * What we actually do to avoid extra shifting and conversion:
1791 */
1792
1793 *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
1794#else
1795 /* Simply discard the low order byte */
1796 *dp = *sp;
1797#endif
1798 }
1799 row_info->bit_depth = 8;
1800 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
1801 row_info->rowbytes = row_info->width * row_info->channels;
1802 }
1803}
1804#endif
1805
1806#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
1807void /* PRIVATE */
1808png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
1809{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001810 png_debug(1, "in png_do_read_swap_alpha");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001811#if defined(PNG_USELESS_TESTS_SUPPORTED)
1812 if (row != NULL && row_info != NULL)
1813#endif
1814 {
1815 png_uint_32 row_width = row_info->width;
1816 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1817 {
1818 /* This converts from RGBA to ARGB */
1819 if (row_info->bit_depth == 8)
1820 {
1821 png_bytep sp = row + row_info->rowbytes;
1822 png_bytep dp = sp;
1823 png_byte save;
1824 png_uint_32 i;
1825
1826 for (i = 0; i < row_width; i++)
1827 {
1828 save = *(--sp);
1829 *(--dp) = *(--sp);
1830 *(--dp) = *(--sp);
1831 *(--dp) = *(--sp);
1832 *(--dp) = save;
1833 }
1834 }
1835 /* This converts from RRGGBBAA to AARRGGBB */
1836 else
1837 {
1838 png_bytep sp = row + row_info->rowbytes;
1839 png_bytep dp = sp;
1840 png_byte save[2];
1841 png_uint_32 i;
1842
1843 for (i = 0; i < row_width; i++)
1844 {
1845 save[0] = *(--sp);
1846 save[1] = *(--sp);
1847 *(--dp) = *(--sp);
1848 *(--dp) = *(--sp);
1849 *(--dp) = *(--sp);
1850 *(--dp) = *(--sp);
1851 *(--dp) = *(--sp);
1852 *(--dp) = *(--sp);
1853 *(--dp) = save[0];
1854 *(--dp) = save[1];
1855 }
1856 }
1857 }
1858 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1859 {
1860 /* This converts from GA to AG */
1861 if (row_info->bit_depth == 8)
1862 {
1863 png_bytep sp = row + row_info->rowbytes;
1864 png_bytep dp = sp;
1865 png_byte save;
1866 png_uint_32 i;
1867
1868 for (i = 0; i < row_width; i++)
1869 {
1870 save = *(--sp);
1871 *(--dp) = *(--sp);
1872 *(--dp) = save;
1873 }
1874 }
1875 /* This converts from GGAA to AAGG */
1876 else
1877 {
1878 png_bytep sp = row + row_info->rowbytes;
1879 png_bytep dp = sp;
1880 png_byte save[2];
1881 png_uint_32 i;
1882
1883 for (i = 0; i < row_width; i++)
1884 {
1885 save[0] = *(--sp);
1886 save[1] = *(--sp);
1887 *(--dp) = *(--sp);
1888 *(--dp) = *(--sp);
1889 *(--dp) = save[0];
1890 *(--dp) = save[1];
1891 }
1892 }
1893 }
1894 }
1895}
1896#endif
1897
1898#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
1899void /* PRIVATE */
1900png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
1901{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001902 png_debug(1, "in png_do_read_invert_alpha");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001903#if defined(PNG_USELESS_TESTS_SUPPORTED)
1904 if (row != NULL && row_info != NULL)
1905#endif
1906 {
1907 png_uint_32 row_width = row_info->width;
1908 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1909 {
1910 /* This inverts the alpha channel in RGBA */
1911 if (row_info->bit_depth == 8)
1912 {
1913 png_bytep sp = row + row_info->rowbytes;
1914 png_bytep dp = sp;
1915 png_uint_32 i;
1916
1917 for (i = 0; i < row_width; i++)
1918 {
1919 *(--dp) = (png_byte)(255 - *(--sp));
1920
1921/* This does nothing:
1922 *(--dp) = *(--sp);
1923 *(--dp) = *(--sp);
1924 *(--dp) = *(--sp);
1925 We can replace it with:
1926*/
1927 sp-=3;
1928 dp=sp;
1929 }
1930 }
1931 /* This inverts the alpha channel in RRGGBBAA */
1932 else
1933 {
1934 png_bytep sp = row + row_info->rowbytes;
1935 png_bytep dp = sp;
1936 png_uint_32 i;
1937
1938 for (i = 0; i < row_width; i++)
1939 {
1940 *(--dp) = (png_byte)(255 - *(--sp));
1941 *(--dp) = (png_byte)(255 - *(--sp));
1942
1943/* This does nothing:
1944 *(--dp) = *(--sp);
1945 *(--dp) = *(--sp);
1946 *(--dp) = *(--sp);
1947 *(--dp) = *(--sp);
1948 *(--dp) = *(--sp);
1949 *(--dp) = *(--sp);
1950 We can replace it with:
1951*/
1952 sp-=6;
1953 dp=sp;
1954 }
1955 }
1956 }
1957 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1958 {
1959 /* This inverts the alpha channel in GA */
1960 if (row_info->bit_depth == 8)
1961 {
1962 png_bytep sp = row + row_info->rowbytes;
1963 png_bytep dp = sp;
1964 png_uint_32 i;
1965
1966 for (i = 0; i < row_width; i++)
1967 {
1968 *(--dp) = (png_byte)(255 - *(--sp));
1969 *(--dp) = *(--sp);
1970 }
1971 }
1972 /* This inverts the alpha channel in GGAA */
1973 else
1974 {
1975 png_bytep sp = row + row_info->rowbytes;
1976 png_bytep dp = sp;
1977 png_uint_32 i;
1978
1979 for (i = 0; i < row_width; i++)
1980 {
1981 *(--dp) = (png_byte)(255 - *(--sp));
1982 *(--dp) = (png_byte)(255 - *(--sp));
1983/*
1984 *(--dp) = *(--sp);
1985 *(--dp) = *(--sp);
1986*/
1987 sp-=2;
1988 dp=sp;
1989 }
1990 }
1991 }
1992 }
1993}
1994#endif
1995
1996#if defined(PNG_READ_FILLER_SUPPORTED)
1997/* Add filler channel if we have RGB color */
1998void /* PRIVATE */
1999png_do_read_filler(png_row_infop row_info, png_bytep row,
2000 png_uint_32 filler, png_uint_32 flags)
2001{
2002 png_uint_32 i;
2003 png_uint_32 row_width = row_info->width;
2004
2005 png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
2006 png_byte lo_filler = (png_byte)(filler & 0xff);
2007
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002008 png_debug(1, "in png_do_read_filler");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002009 if (
2010#if defined(PNG_USELESS_TESTS_SUPPORTED)
2011 row != NULL && row_info != NULL &&
2012#endif
2013 row_info->color_type == PNG_COLOR_TYPE_GRAY)
2014 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002015 if (row_info->bit_depth == 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002016 {
2017 /* This changes the data from G to GX */
2018 if (flags & PNG_FLAG_FILLER_AFTER)
2019 {
2020 png_bytep sp = row + (png_size_t)row_width;
2021 png_bytep dp = sp + (png_size_t)row_width;
2022 for (i = 1; i < row_width; i++)
2023 {
2024 *(--dp) = lo_filler;
2025 *(--dp) = *(--sp);
2026 }
2027 *(--dp) = lo_filler;
2028 row_info->channels = 2;
2029 row_info->pixel_depth = 16;
2030 row_info->rowbytes = row_width * 2;
2031 }
2032 /* This changes the data from G to XG */
2033 else
2034 {
2035 png_bytep sp = row + (png_size_t)row_width;
2036 png_bytep dp = sp + (png_size_t)row_width;
2037 for (i = 0; i < row_width; i++)
2038 {
2039 *(--dp) = *(--sp);
2040 *(--dp) = lo_filler;
2041 }
2042 row_info->channels = 2;
2043 row_info->pixel_depth = 16;
2044 row_info->rowbytes = row_width * 2;
2045 }
2046 }
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002047 else if (row_info->bit_depth == 16)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002048 {
2049 /* This changes the data from GG to GGXX */
2050 if (flags & PNG_FLAG_FILLER_AFTER)
2051 {
2052 png_bytep sp = row + (png_size_t)row_width * 2;
2053 png_bytep dp = sp + (png_size_t)row_width * 2;
2054 for (i = 1; i < row_width; i++)
2055 {
2056 *(--dp) = hi_filler;
2057 *(--dp) = lo_filler;
2058 *(--dp) = *(--sp);
2059 *(--dp) = *(--sp);
2060 }
2061 *(--dp) = hi_filler;
2062 *(--dp) = lo_filler;
2063 row_info->channels = 2;
2064 row_info->pixel_depth = 32;
2065 row_info->rowbytes = row_width * 4;
2066 }
2067 /* This changes the data from GG to XXGG */
2068 else
2069 {
2070 png_bytep sp = row + (png_size_t)row_width * 2;
2071 png_bytep dp = sp + (png_size_t)row_width * 2;
2072 for (i = 0; i < row_width; i++)
2073 {
2074 *(--dp) = *(--sp);
2075 *(--dp) = *(--sp);
2076 *(--dp) = hi_filler;
2077 *(--dp) = lo_filler;
2078 }
2079 row_info->channels = 2;
2080 row_info->pixel_depth = 32;
2081 row_info->rowbytes = row_width * 4;
2082 }
2083 }
2084 } /* COLOR_TYPE == GRAY */
2085 else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2086 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002087 if (row_info->bit_depth == 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002088 {
2089 /* This changes the data from RGB to RGBX */
2090 if (flags & PNG_FLAG_FILLER_AFTER)
2091 {
2092 png_bytep sp = row + (png_size_t)row_width * 3;
2093 png_bytep dp = sp + (png_size_t)row_width;
2094 for (i = 1; i < row_width; i++)
2095 {
2096 *(--dp) = lo_filler;
2097 *(--dp) = *(--sp);
2098 *(--dp) = *(--sp);
2099 *(--dp) = *(--sp);
2100 }
2101 *(--dp) = lo_filler;
2102 row_info->channels = 4;
2103 row_info->pixel_depth = 32;
2104 row_info->rowbytes = row_width * 4;
2105 }
2106 /* This changes the data from RGB to XRGB */
2107 else
2108 {
2109 png_bytep sp = row + (png_size_t)row_width * 3;
2110 png_bytep dp = sp + (png_size_t)row_width;
2111 for (i = 0; i < row_width; i++)
2112 {
2113 *(--dp) = *(--sp);
2114 *(--dp) = *(--sp);
2115 *(--dp) = *(--sp);
2116 *(--dp) = lo_filler;
2117 }
2118 row_info->channels = 4;
2119 row_info->pixel_depth = 32;
2120 row_info->rowbytes = row_width * 4;
2121 }
2122 }
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002123 else if (row_info->bit_depth == 16)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002124 {
2125 /* This changes the data from RRGGBB to RRGGBBXX */
2126 if (flags & PNG_FLAG_FILLER_AFTER)
2127 {
2128 png_bytep sp = row + (png_size_t)row_width * 6;
2129 png_bytep dp = sp + (png_size_t)row_width * 2;
2130 for (i = 1; i < row_width; i++)
2131 {
2132 *(--dp) = hi_filler;
2133 *(--dp) = lo_filler;
2134 *(--dp) = *(--sp);
2135 *(--dp) = *(--sp);
2136 *(--dp) = *(--sp);
2137 *(--dp) = *(--sp);
2138 *(--dp) = *(--sp);
2139 *(--dp) = *(--sp);
2140 }
2141 *(--dp) = hi_filler;
2142 *(--dp) = lo_filler;
2143 row_info->channels = 4;
2144 row_info->pixel_depth = 64;
2145 row_info->rowbytes = row_width * 8;
2146 }
2147 /* This changes the data from RRGGBB to XXRRGGBB */
2148 else
2149 {
2150 png_bytep sp = row + (png_size_t)row_width * 6;
2151 png_bytep dp = sp + (png_size_t)row_width * 2;
2152 for (i = 0; i < row_width; i++)
2153 {
2154 *(--dp) = *(--sp);
2155 *(--dp) = *(--sp);
2156 *(--dp) = *(--sp);
2157 *(--dp) = *(--sp);
2158 *(--dp) = *(--sp);
2159 *(--dp) = *(--sp);
2160 *(--dp) = hi_filler;
2161 *(--dp) = lo_filler;
2162 }
2163 row_info->channels = 4;
2164 row_info->pixel_depth = 64;
2165 row_info->rowbytes = row_width * 8;
2166 }
2167 }
2168 } /* COLOR_TYPE == RGB */
2169}
2170#endif
2171
2172#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002173/* Expand grayscale files to RGB, with or without alpha */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002174void /* PRIVATE */
2175png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
2176{
2177 png_uint_32 i;
2178 png_uint_32 row_width = row_info->width;
2179
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002180 png_debug(1, "in png_do_gray_to_rgb");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002181 if (row_info->bit_depth >= 8 &&
2182#if defined(PNG_USELESS_TESTS_SUPPORTED)
2183 row != NULL && row_info != NULL &&
2184#endif
2185 !(row_info->color_type & PNG_COLOR_MASK_COLOR))
2186 {
2187 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
2188 {
2189 if (row_info->bit_depth == 8)
2190 {
2191 png_bytep sp = row + (png_size_t)row_width - 1;
2192 png_bytep dp = sp + (png_size_t)row_width * 2;
2193 for (i = 0; i < row_width; i++)
2194 {
2195 *(dp--) = *sp;
2196 *(dp--) = *sp;
2197 *(dp--) = *(sp--);
2198 }
2199 }
2200 else
2201 {
2202 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2203 png_bytep dp = sp + (png_size_t)row_width * 4;
2204 for (i = 0; i < row_width; i++)
2205 {
2206 *(dp--) = *sp;
2207 *(dp--) = *(sp - 1);
2208 *(dp--) = *sp;
2209 *(dp--) = *(sp - 1);
2210 *(dp--) = *(sp--);
2211 *(dp--) = *(sp--);
2212 }
2213 }
2214 }
2215 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2216 {
2217 if (row_info->bit_depth == 8)
2218 {
2219 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2220 png_bytep dp = sp + (png_size_t)row_width * 2;
2221 for (i = 0; i < row_width; i++)
2222 {
2223 *(dp--) = *(sp--);
2224 *(dp--) = *sp;
2225 *(dp--) = *sp;
2226 *(dp--) = *(sp--);
2227 }
2228 }
2229 else
2230 {
2231 png_bytep sp = row + (png_size_t)row_width * 4 - 1;
2232 png_bytep dp = sp + (png_size_t)row_width * 4;
2233 for (i = 0; i < row_width; i++)
2234 {
2235 *(dp--) = *(sp--);
2236 *(dp--) = *(sp--);
2237 *(dp--) = *sp;
2238 *(dp--) = *(sp - 1);
2239 *(dp--) = *sp;
2240 *(dp--) = *(sp - 1);
2241 *(dp--) = *(sp--);
2242 *(dp--) = *(sp--);
2243 }
2244 }
2245 }
2246 row_info->channels += (png_byte)2;
2247 row_info->color_type |= PNG_COLOR_MASK_COLOR;
2248 row_info->pixel_depth = (png_byte)(row_info->channels *
2249 row_info->bit_depth);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002250 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002251 }
2252}
2253#endif
2254
2255#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002256/* Reduce RGB files to grayscale, with or without alpha
The Android Open Source Project893912b2009-03-03 19:30:05 -08002257 * using the equation given in Poynton's ColorFAQ at
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002258 * <http://www.inforamp.net/~poynton/> (THIS LINK IS DEAD June 2008)
2259 * New link:
2260 * <http://www.poynton.com/notes/colour_and_gamma/>
2261 * Charles Poynton poynton at poynton.com
The Android Open Source Project893912b2009-03-03 19:30:05 -08002262 *
2263 * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
2264 *
2265 * We approximate this with
2266 *
2267 * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
2268 *
2269 * which can be expressed with integers as
2270 *
2271 * Y = (6969 * R + 23434 * G + 2365 * B)/32768
2272 *
2273 * The calculation is to be done in a linear colorspace.
2274 *
2275 * Other integer coefficents can be used via png_set_rgb_to_gray().
2276 */
2277int /* PRIVATE */
2278png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
2279
2280{
2281 png_uint_32 i;
2282
2283 png_uint_32 row_width = row_info->width;
2284 int rgb_error = 0;
2285
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002286 png_debug(1, "in png_do_rgb_to_gray");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002287 if (
2288#if defined(PNG_USELESS_TESTS_SUPPORTED)
2289 row != NULL && row_info != NULL &&
2290#endif
2291 (row_info->color_type & PNG_COLOR_MASK_COLOR))
2292 {
2293 png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
2294 png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
2295 png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
2296
2297 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2298 {
2299 if (row_info->bit_depth == 8)
2300 {
2301#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2302 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2303 {
2304 png_bytep sp = row;
2305 png_bytep dp = row;
2306
2307 for (i = 0; i < row_width; i++)
2308 {
2309 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2310 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2311 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002312 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002313 {
2314 rgb_error |= 1;
2315 *(dp++) = png_ptr->gamma_from_1[
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002316 (rc*red + gc*green + bc*blue)>>15];
The Android Open Source Project893912b2009-03-03 19:30:05 -08002317 }
2318 else
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002319 *(dp++) = *(sp - 1);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002320 }
2321 }
2322 else
2323#endif
2324 {
2325 png_bytep sp = row;
2326 png_bytep dp = row;
2327 for (i = 0; i < row_width; i++)
2328 {
2329 png_byte red = *(sp++);
2330 png_byte green = *(sp++);
2331 png_byte blue = *(sp++);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002332 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002333 {
2334 rgb_error |= 1;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002335 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002336 }
2337 else
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002338 *(dp++) = *(sp - 1);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002339 }
2340 }
2341 }
2342
2343 else /* RGB bit_depth == 16 */
2344 {
2345#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2346 if (png_ptr->gamma_16_to_1 != NULL &&
2347 png_ptr->gamma_16_from_1 != NULL)
2348 {
2349 png_bytep sp = row;
2350 png_bytep dp = row;
2351 for (i = 0; i < row_width; i++)
2352 {
2353 png_uint_16 red, green, blue, w;
2354
2355 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2356 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2357 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2358
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002359 if (red == green && red == blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002360 w = red;
2361 else
2362 {
2363 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2364 png_ptr->gamma_shift][red>>8];
2365 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2366 png_ptr->gamma_shift][green>>8];
2367 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
2368 png_ptr->gamma_shift][blue>>8];
2369 png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
2370 + bc*blue_1)>>15);
2371 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2372 png_ptr->gamma_shift][gray16 >> 8];
2373 rgb_error |= 1;
2374 }
2375
2376 *(dp++) = (png_byte)((w>>8) & 0xff);
2377 *(dp++) = (png_byte)(w & 0xff);
2378 }
2379 }
2380 else
2381#endif
2382 {
2383 png_bytep sp = row;
2384 png_bytep dp = row;
2385 for (i = 0; i < row_width; i++)
2386 {
2387 png_uint_16 red, green, blue, gray16;
2388
2389 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2390 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2391 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2392
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002393 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002394 rgb_error |= 1;
2395 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
2396 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2397 *(dp++) = (png_byte)(gray16 & 0xff);
2398 }
2399 }
2400 }
2401 }
2402 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2403 {
2404 if (row_info->bit_depth == 8)
2405 {
2406#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2407 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2408 {
2409 png_bytep sp = row;
2410 png_bytep dp = row;
2411 for (i = 0; i < row_width; i++)
2412 {
2413 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2414 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2415 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002416 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002417 rgb_error |= 1;
2418 *(dp++) = png_ptr->gamma_from_1
2419 [(rc*red + gc*green + bc*blue)>>15];
2420 *(dp++) = *(sp++); /* alpha */
2421 }
2422 }
2423 else
2424#endif
2425 {
2426 png_bytep sp = row;
2427 png_bytep dp = row;
2428 for (i = 0; i < row_width; i++)
2429 {
2430 png_byte red = *(sp++);
2431 png_byte green = *(sp++);
2432 png_byte blue = *(sp++);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002433 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002434 rgb_error |= 1;
2435 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
2436 *(dp++) = *(sp++); /* alpha */
2437 }
2438 }
2439 }
2440 else /* RGBA bit_depth == 16 */
2441 {
2442#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2443 if (png_ptr->gamma_16_to_1 != NULL &&
2444 png_ptr->gamma_16_from_1 != NULL)
2445 {
2446 png_bytep sp = row;
2447 png_bytep dp = row;
2448 for (i = 0; i < row_width; i++)
2449 {
2450 png_uint_16 red, green, blue, w;
2451
2452 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2453 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2454 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2455
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002456 if (red == green && red == blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002457 w = red;
2458 else
2459 {
2460 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2461 png_ptr->gamma_shift][red>>8];
2462 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2463 png_ptr->gamma_shift][green>>8];
2464 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
2465 png_ptr->gamma_shift][blue>>8];
2466 png_uint_16 gray16 = (png_uint_16)((rc * red_1
2467 + gc * green_1 + bc * blue_1)>>15);
2468 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2469 png_ptr->gamma_shift][gray16 >> 8];
2470 rgb_error |= 1;
2471 }
2472
2473 *(dp++) = (png_byte)((w>>8) & 0xff);
2474 *(dp++) = (png_byte)(w & 0xff);
2475 *(dp++) = *(sp++); /* alpha */
2476 *(dp++) = *(sp++);
2477 }
2478 }
2479 else
2480#endif
2481 {
2482 png_bytep sp = row;
2483 png_bytep dp = row;
2484 for (i = 0; i < row_width; i++)
2485 {
2486 png_uint_16 red, green, blue, gray16;
2487 red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2488 green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2489 blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002490 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002491 rgb_error |= 1;
2492 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
2493 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2494 *(dp++) = (png_byte)(gray16 & 0xff);
2495 *(dp++) = *(sp++); /* alpha */
2496 *(dp++) = *(sp++);
2497 }
2498 }
2499 }
2500 }
2501 row_info->channels -= (png_byte)2;
2502 row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
2503 row_info->pixel_depth = (png_byte)(row_info->channels *
2504 row_info->bit_depth);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002505 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002506 }
2507 return rgb_error;
2508}
2509#endif
2510
2511/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
2512 * large of png_color. This lets grayscale images be treated as
2513 * paletted. Most useful for gamma correction and simplification
2514 * of code.
2515 */
2516void PNGAPI
2517png_build_grayscale_palette(int bit_depth, png_colorp palette)
2518{
2519 int num_palette;
2520 int color_inc;
2521 int i;
2522 int v;
2523
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002524 png_debug(1, "in png_do_build_grayscale_palette");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002525 if (palette == NULL)
2526 return;
2527
2528 switch (bit_depth)
2529 {
2530 case 1:
2531 num_palette = 2;
2532 color_inc = 0xff;
2533 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002534
The Android Open Source Project893912b2009-03-03 19:30:05 -08002535 case 2:
2536 num_palette = 4;
2537 color_inc = 0x55;
2538 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002539
The Android Open Source Project893912b2009-03-03 19:30:05 -08002540 case 4:
2541 num_palette = 16;
2542 color_inc = 0x11;
2543 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002544
The Android Open Source Project893912b2009-03-03 19:30:05 -08002545 case 8:
2546 num_palette = 256;
2547 color_inc = 1;
2548 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002549
The Android Open Source Project893912b2009-03-03 19:30:05 -08002550 default:
2551 num_palette = 0;
2552 color_inc = 0;
2553 break;
2554 }
2555
2556 for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
2557 {
2558 palette[i].red = (png_byte)v;
2559 palette[i].green = (png_byte)v;
2560 palette[i].blue = (png_byte)v;
2561 }
2562}
2563
2564/* This function is currently unused. Do we really need it? */
2565#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED)
2566void /* PRIVATE */
2567png_correct_palette(png_structp png_ptr, png_colorp palette,
2568 int num_palette)
2569{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002570 png_debug(1, "in png_correct_palette");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002571#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
2572 defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
2573 if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND))
2574 {
2575 png_color back, back_1;
2576
2577 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
2578 {
2579 back.red = png_ptr->gamma_table[png_ptr->background.red];
2580 back.green = png_ptr->gamma_table[png_ptr->background.green];
2581 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
2582
2583 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
2584 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
2585 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
2586 }
2587 else
2588 {
2589 double g;
2590
2591 g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma);
2592
2593 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
2594 fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
2595 {
2596 back.red = png_ptr->background.red;
2597 back.green = png_ptr->background.green;
2598 back.blue = png_ptr->background.blue;
2599 }
2600 else
2601 {
2602 back.red =
2603 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2604 255.0 + 0.5);
2605 back.green =
2606 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2607 255.0 + 0.5);
2608 back.blue =
2609 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2610 255.0 + 0.5);
2611 }
2612
2613 g = 1.0 / png_ptr->background_gamma;
2614
2615 back_1.red =
2616 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2617 255.0 + 0.5);
2618 back_1.green =
2619 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2620 255.0 + 0.5);
2621 back_1.blue =
2622 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2623 255.0 + 0.5);
2624 }
2625
2626 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2627 {
2628 png_uint_32 i;
2629
2630 for (i = 0; i < (png_uint_32)num_palette; i++)
2631 {
2632 if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
2633 {
2634 palette[i] = back;
2635 }
2636 else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
2637 {
2638 png_byte v, w;
2639
2640 v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
2641 png_composite(w, v, png_ptr->trans[i], back_1.red);
2642 palette[i].red = png_ptr->gamma_from_1[w];
2643
2644 v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
2645 png_composite(w, v, png_ptr->trans[i], back_1.green);
2646 palette[i].green = png_ptr->gamma_from_1[w];
2647
2648 v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
2649 png_composite(w, v, png_ptr->trans[i], back_1.blue);
2650 palette[i].blue = png_ptr->gamma_from_1[w];
2651 }
2652 else
2653 {
2654 palette[i].red = png_ptr->gamma_table[palette[i].red];
2655 palette[i].green = png_ptr->gamma_table[palette[i].green];
2656 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2657 }
2658 }
2659 }
2660 else
2661 {
2662 int i;
2663
2664 for (i = 0; i < num_palette; i++)
2665 {
2666 if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
2667 {
2668 palette[i] = back;
2669 }
2670 else
2671 {
2672 palette[i].red = png_ptr->gamma_table[palette[i].red];
2673 palette[i].green = png_ptr->gamma_table[palette[i].green];
2674 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2675 }
2676 }
2677 }
2678 }
2679 else
2680#endif
2681#if defined(PNG_READ_GAMMA_SUPPORTED)
2682 if (png_ptr->transformations & PNG_GAMMA)
2683 {
2684 int i;
2685
2686 for (i = 0; i < num_palette; i++)
2687 {
2688 palette[i].red = png_ptr->gamma_table[palette[i].red];
2689 palette[i].green = png_ptr->gamma_table[palette[i].green];
2690 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2691 }
2692 }
2693#if defined(PNG_READ_BACKGROUND_SUPPORTED)
2694 else
2695#endif
2696#endif
2697#if defined(PNG_READ_BACKGROUND_SUPPORTED)
2698 if (png_ptr->transformations & PNG_BACKGROUND)
2699 {
2700 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2701 {
2702 png_color back;
2703
2704 back.red = (png_byte)png_ptr->background.red;
2705 back.green = (png_byte)png_ptr->background.green;
2706 back.blue = (png_byte)png_ptr->background.blue;
2707
2708 for (i = 0; i < (int)png_ptr->num_trans; i++)
2709 {
2710 if (png_ptr->trans[i] == 0)
2711 {
2712 palette[i].red = back.red;
2713 palette[i].green = back.green;
2714 palette[i].blue = back.blue;
2715 }
2716 else if (png_ptr->trans[i] != 0xff)
2717 {
2718 png_composite(palette[i].red, png_ptr->palette[i].red,
2719 png_ptr->trans[i], back.red);
2720 png_composite(palette[i].green, png_ptr->palette[i].green,
2721 png_ptr->trans[i], back.green);
2722 png_composite(palette[i].blue, png_ptr->palette[i].blue,
2723 png_ptr->trans[i], back.blue);
2724 }
2725 }
2726 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002727 else /* Assume grayscale palette (what else could it be?) */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002728 {
2729 int i;
2730
2731 for (i = 0; i < num_palette; i++)
2732 {
2733 if (i == (png_byte)png_ptr->trans_values.gray)
2734 {
2735 palette[i].red = (png_byte)png_ptr->background.red;
2736 palette[i].green = (png_byte)png_ptr->background.green;
2737 palette[i].blue = (png_byte)png_ptr->background.blue;
2738 }
2739 }
2740 }
2741 }
2742#endif
2743}
2744#endif
2745
2746#if defined(PNG_READ_BACKGROUND_SUPPORTED)
2747/* Replace any alpha or transparency with the supplied background color.
2748 * "background" is already in the screen gamma, while "background_1" is
2749 * at a gamma of 1.0. Paletted files have already been taken care of.
2750 */
2751void /* PRIVATE */
2752png_do_background(png_row_infop row_info, png_bytep row,
2753 png_color_16p trans_values, png_color_16p background
2754#if defined(PNG_READ_GAMMA_SUPPORTED)
2755 , png_color_16p background_1,
2756 png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
2757 png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
2758 png_uint_16pp gamma_16_to_1, int gamma_shift
2759#endif
2760 )
2761{
2762 png_bytep sp, dp;
2763 png_uint_32 i;
2764 png_uint_32 row_width=row_info->width;
2765 int shift;
2766
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002767 png_debug(1, "in png_do_background");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002768 if (background != NULL &&
2769#if defined(PNG_USELESS_TESTS_SUPPORTED)
2770 row != NULL && row_info != NULL &&
2771#endif
2772 (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
2773 (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
2774 {
2775 switch (row_info->color_type)
2776 {
2777 case PNG_COLOR_TYPE_GRAY:
2778 {
2779 switch (row_info->bit_depth)
2780 {
2781 case 1:
2782 {
2783 sp = row;
2784 shift = 7;
2785 for (i = 0; i < row_width; i++)
2786 {
2787 if ((png_uint_16)((*sp >> shift) & 0x01)
2788 == trans_values->gray)
2789 {
2790 *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2791 *sp |= (png_byte)(background->gray << shift);
2792 }
2793 if (!shift)
2794 {
2795 shift = 7;
2796 sp++;
2797 }
2798 else
2799 shift--;
2800 }
2801 break;
2802 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002803
The Android Open Source Project893912b2009-03-03 19:30:05 -08002804 case 2:
2805 {
2806#if defined(PNG_READ_GAMMA_SUPPORTED)
2807 if (gamma_table != NULL)
2808 {
2809 sp = row;
2810 shift = 6;
2811 for (i = 0; i < row_width; i++)
2812 {
2813 if ((png_uint_16)((*sp >> shift) & 0x03)
2814 == trans_values->gray)
2815 {
2816 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2817 *sp |= (png_byte)(background->gray << shift);
2818 }
2819 else
2820 {
2821 png_byte p = (png_byte)((*sp >> shift) & 0x03);
2822 png_byte g = (png_byte)((gamma_table [p | (p << 2) |
2823 (p << 4) | (p << 6)] >> 6) & 0x03);
2824 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2825 *sp |= (png_byte)(g << shift);
2826 }
2827 if (!shift)
2828 {
2829 shift = 6;
2830 sp++;
2831 }
2832 else
2833 shift -= 2;
2834 }
2835 }
2836 else
2837#endif
2838 {
2839 sp = row;
2840 shift = 6;
2841 for (i = 0; i < row_width; i++)
2842 {
2843 if ((png_uint_16)((*sp >> shift) & 0x03)
2844 == trans_values->gray)
2845 {
2846 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2847 *sp |= (png_byte)(background->gray << shift);
2848 }
2849 if (!shift)
2850 {
2851 shift = 6;
2852 sp++;
2853 }
2854 else
2855 shift -= 2;
2856 }
2857 }
2858 break;
2859 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002860
The Android Open Source Project893912b2009-03-03 19:30:05 -08002861 case 4:
2862 {
2863#if defined(PNG_READ_GAMMA_SUPPORTED)
2864 if (gamma_table != NULL)
2865 {
2866 sp = row;
2867 shift = 4;
2868 for (i = 0; i < row_width; i++)
2869 {
2870 if ((png_uint_16)((*sp >> shift) & 0x0f)
2871 == trans_values->gray)
2872 {
2873 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2874 *sp |= (png_byte)(background->gray << shift);
2875 }
2876 else
2877 {
2878 png_byte p = (png_byte)((*sp >> shift) & 0x0f);
2879 png_byte g = (png_byte)((gamma_table[p |
2880 (p << 4)] >> 4) & 0x0f);
2881 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2882 *sp |= (png_byte)(g << shift);
2883 }
2884 if (!shift)
2885 {
2886 shift = 4;
2887 sp++;
2888 }
2889 else
2890 shift -= 4;
2891 }
2892 }
2893 else
2894#endif
2895 {
2896 sp = row;
2897 shift = 4;
2898 for (i = 0; i < row_width; i++)
2899 {
2900 if ((png_uint_16)((*sp >> shift) & 0x0f)
2901 == trans_values->gray)
2902 {
2903 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2904 *sp |= (png_byte)(background->gray << shift);
2905 }
2906 if (!shift)
2907 {
2908 shift = 4;
2909 sp++;
2910 }
2911 else
2912 shift -= 4;
2913 }
2914 }
2915 break;
2916 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002917
The Android Open Source Project893912b2009-03-03 19:30:05 -08002918 case 8:
2919 {
2920#if defined(PNG_READ_GAMMA_SUPPORTED)
2921 if (gamma_table != NULL)
2922 {
2923 sp = row;
2924 for (i = 0; i < row_width; i++, sp++)
2925 {
2926 if (*sp == trans_values->gray)
2927 {
2928 *sp = (png_byte)background->gray;
2929 }
2930 else
2931 {
2932 *sp = gamma_table[*sp];
2933 }
2934 }
2935 }
2936 else
2937#endif
2938 {
2939 sp = row;
2940 for (i = 0; i < row_width; i++, sp++)
2941 {
2942 if (*sp == trans_values->gray)
2943 {
2944 *sp = (png_byte)background->gray;
2945 }
2946 }
2947 }
2948 break;
2949 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002950
The Android Open Source Project893912b2009-03-03 19:30:05 -08002951 case 16:
2952 {
2953#if defined(PNG_READ_GAMMA_SUPPORTED)
2954 if (gamma_16 != NULL)
2955 {
2956 sp = row;
2957 for (i = 0; i < row_width; i++, sp += 2)
2958 {
2959 png_uint_16 v;
2960
2961 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2962 if (v == trans_values->gray)
2963 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002964 /* Background is already in screen gamma */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002965 *sp = (png_byte)((background->gray >> 8) & 0xff);
2966 *(sp + 1) = (png_byte)(background->gray & 0xff);
2967 }
2968 else
2969 {
2970 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
2971 *sp = (png_byte)((v >> 8) & 0xff);
2972 *(sp + 1) = (png_byte)(v & 0xff);
2973 }
2974 }
2975 }
2976 else
2977#endif
2978 {
2979 sp = row;
2980 for (i = 0; i < row_width; i++, sp += 2)
2981 {
2982 png_uint_16 v;
2983
2984 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2985 if (v == trans_values->gray)
2986 {
2987 *sp = (png_byte)((background->gray >> 8) & 0xff);
2988 *(sp + 1) = (png_byte)(background->gray & 0xff);
2989 }
2990 }
2991 }
2992 break;
2993 }
2994 }
2995 break;
2996 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002997
The Android Open Source Project893912b2009-03-03 19:30:05 -08002998 case PNG_COLOR_TYPE_RGB:
2999 {
3000 if (row_info->bit_depth == 8)
3001 {
3002#if defined(PNG_READ_GAMMA_SUPPORTED)
3003 if (gamma_table != NULL)
3004 {
3005 sp = row;
3006 for (i = 0; i < row_width; i++, sp += 3)
3007 {
3008 if (*sp == trans_values->red &&
3009 *(sp + 1) == trans_values->green &&
3010 *(sp + 2) == trans_values->blue)
3011 {
3012 *sp = (png_byte)background->red;
3013 *(sp + 1) = (png_byte)background->green;
3014 *(sp + 2) = (png_byte)background->blue;
3015 }
3016 else
3017 {
3018 *sp = gamma_table[*sp];
3019 *(sp + 1) = gamma_table[*(sp + 1)];
3020 *(sp + 2) = gamma_table[*(sp + 2)];
3021 }
3022 }
3023 }
3024 else
3025#endif
3026 {
3027 sp = row;
3028 for (i = 0; i < row_width; i++, sp += 3)
3029 {
3030 if (*sp == trans_values->red &&
3031 *(sp + 1) == trans_values->green &&
3032 *(sp + 2) == trans_values->blue)
3033 {
3034 *sp = (png_byte)background->red;
3035 *(sp + 1) = (png_byte)background->green;
3036 *(sp + 2) = (png_byte)background->blue;
3037 }
3038 }
3039 }
3040 }
3041 else /* if (row_info->bit_depth == 16) */
3042 {
3043#if defined(PNG_READ_GAMMA_SUPPORTED)
3044 if (gamma_16 != NULL)
3045 {
3046 sp = row;
3047 for (i = 0; i < row_width; i++, sp += 6)
3048 {
3049 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3050 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
3051 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
3052 if (r == trans_values->red && g == trans_values->green &&
3053 b == trans_values->blue)
3054 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003055 /* Background is already in screen gamma */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003056 *sp = (png_byte)((background->red >> 8) & 0xff);
3057 *(sp + 1) = (png_byte)(background->red & 0xff);
3058 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
3059 *(sp + 3) = (png_byte)(background->green & 0xff);
3060 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3061 *(sp + 5) = (png_byte)(background->blue & 0xff);
3062 }
3063 else
3064 {
3065 png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3066 *sp = (png_byte)((v >> 8) & 0xff);
3067 *(sp + 1) = (png_byte)(v & 0xff);
3068 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
3069 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
3070 *(sp + 3) = (png_byte)(v & 0xff);
3071 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
3072 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
3073 *(sp + 5) = (png_byte)(v & 0xff);
3074 }
3075 }
3076 }
3077 else
3078#endif
3079 {
3080 sp = row;
3081 for (i = 0; i < row_width; i++, sp += 6)
3082 {
3083 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
3084 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
3085 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
3086
3087 if (r == trans_values->red && g == trans_values->green &&
3088 b == trans_values->blue)
3089 {
3090 *sp = (png_byte)((background->red >> 8) & 0xff);
3091 *(sp + 1) = (png_byte)(background->red & 0xff);
3092 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
3093 *(sp + 3) = (png_byte)(background->green & 0xff);
3094 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3095 *(sp + 5) = (png_byte)(background->blue & 0xff);
3096 }
3097 }
3098 }
3099 }
3100 break;
3101 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003102
The Android Open Source Project893912b2009-03-03 19:30:05 -08003103 case PNG_COLOR_TYPE_GRAY_ALPHA:
3104 {
3105 if (row_info->bit_depth == 8)
3106 {
3107#if defined(PNG_READ_GAMMA_SUPPORTED)
3108 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3109 gamma_table != NULL)
3110 {
3111 sp = row;
3112 dp = row;
3113 for (i = 0; i < row_width; i++, sp += 2, dp++)
3114 {
3115 png_uint_16 a = *(sp + 1);
3116
3117 if (a == 0xff)
3118 {
3119 *dp = gamma_table[*sp];
3120 }
3121 else if (a == 0)
3122 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003123 /* Background is already in screen gamma */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003124 *dp = (png_byte)background->gray;
3125 }
3126 else
3127 {
3128 png_byte v, w;
3129
3130 v = gamma_to_1[*sp];
3131 png_composite(w, v, a, background_1->gray);
3132 *dp = gamma_from_1[w];
3133 }
3134 }
3135 }
3136 else
3137#endif
3138 {
3139 sp = row;
3140 dp = row;
3141 for (i = 0; i < row_width; i++, sp += 2, dp++)
3142 {
3143 png_byte a = *(sp + 1);
3144
3145 if (a == 0xff)
3146 {
3147 *dp = *sp;
3148 }
3149#if defined(PNG_READ_GAMMA_SUPPORTED)
3150 else if (a == 0)
3151 {
3152 *dp = (png_byte)background->gray;
3153 }
3154 else
3155 {
3156 png_composite(*dp, *sp, a, background_1->gray);
3157 }
3158#else
3159 *dp = (png_byte)background->gray;
3160#endif
3161 }
3162 }
3163 }
3164 else /* if (png_ptr->bit_depth == 16) */
3165 {
3166#if defined(PNG_READ_GAMMA_SUPPORTED)
3167 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3168 gamma_16_to_1 != NULL)
3169 {
3170 sp = row;
3171 dp = row;
3172 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
3173 {
3174 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
3175
3176 if (a == (png_uint_16)0xffff)
3177 {
3178 png_uint_16 v;
3179
3180 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3181 *dp = (png_byte)((v >> 8) & 0xff);
3182 *(dp + 1) = (png_byte)(v & 0xff);
3183 }
3184#if defined(PNG_READ_GAMMA_SUPPORTED)
3185 else if (a == 0)
3186#else
3187 else
3188#endif
3189 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003190 /* Background is already in screen gamma */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003191 *dp = (png_byte)((background->gray >> 8) & 0xff);
3192 *(dp + 1) = (png_byte)(background->gray & 0xff);
3193 }
3194#if defined(PNG_READ_GAMMA_SUPPORTED)
3195 else
3196 {
3197 png_uint_16 g, v, w;
3198
3199 g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3200 png_composite_16(v, g, a, background_1->gray);
3201 w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
3202 *dp = (png_byte)((w >> 8) & 0xff);
3203 *(dp + 1) = (png_byte)(w & 0xff);
3204 }
3205#endif
3206 }
3207 }
3208 else
3209#endif
3210 {
3211 sp = row;
3212 dp = row;
3213 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
3214 {
3215 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
3216 if (a == (png_uint_16)0xffff)
3217 {
3218 png_memcpy(dp, sp, 2);
3219 }
3220#if defined(PNG_READ_GAMMA_SUPPORTED)
3221 else if (a == 0)
3222#else
3223 else
3224#endif
3225 {
3226 *dp = (png_byte)((background->gray >> 8) & 0xff);
3227 *(dp + 1) = (png_byte)(background->gray & 0xff);
3228 }
3229#if defined(PNG_READ_GAMMA_SUPPORTED)
3230 else
3231 {
3232 png_uint_16 g, v;
3233
3234 g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3235 png_composite_16(v, g, a, background_1->gray);
3236 *dp = (png_byte)((v >> 8) & 0xff);
3237 *(dp + 1) = (png_byte)(v & 0xff);
3238 }
3239#endif
3240 }
3241 }
3242 }
3243 break;
3244 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003245
The Android Open Source Project893912b2009-03-03 19:30:05 -08003246 case PNG_COLOR_TYPE_RGB_ALPHA:
3247 {
3248 if (row_info->bit_depth == 8)
3249 {
3250#if defined(PNG_READ_GAMMA_SUPPORTED)
3251 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3252 gamma_table != NULL)
3253 {
3254 sp = row;
3255 dp = row;
3256 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
3257 {
3258 png_byte a = *(sp + 3);
3259
3260 if (a == 0xff)
3261 {
3262 *dp = gamma_table[*sp];
3263 *(dp + 1) = gamma_table[*(sp + 1)];
3264 *(dp + 2) = gamma_table[*(sp + 2)];
3265 }
3266 else if (a == 0)
3267 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003268 /* Background is already in screen gamma */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003269 *dp = (png_byte)background->red;
3270 *(dp + 1) = (png_byte)background->green;
3271 *(dp + 2) = (png_byte)background->blue;
3272 }
3273 else
3274 {
3275 png_byte v, w;
3276
3277 v = gamma_to_1[*sp];
3278 png_composite(w, v, a, background_1->red);
3279 *dp = gamma_from_1[w];
3280 v = gamma_to_1[*(sp + 1)];
3281 png_composite(w, v, a, background_1->green);
3282 *(dp + 1) = gamma_from_1[w];
3283 v = gamma_to_1[*(sp + 2)];
3284 png_composite(w, v, a, background_1->blue);
3285 *(dp + 2) = gamma_from_1[w];
3286 }
3287 }
3288 }
3289 else
3290#endif
3291 {
3292 sp = row;
3293 dp = row;
3294 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
3295 {
3296 png_byte a = *(sp + 3);
3297
3298 if (a == 0xff)
3299 {
3300 *dp = *sp;
3301 *(dp + 1) = *(sp + 1);
3302 *(dp + 2) = *(sp + 2);
3303 }
3304 else if (a == 0)
3305 {
3306 *dp = (png_byte)background->red;
3307 *(dp + 1) = (png_byte)background->green;
3308 *(dp + 2) = (png_byte)background->blue;
3309 }
3310 else
3311 {
3312 png_composite(*dp, *sp, a, background->red);
3313 png_composite(*(dp + 1), *(sp + 1), a,
3314 background->green);
3315 png_composite(*(dp + 2), *(sp + 2), a,
3316 background->blue);
3317 }
3318 }
3319 }
3320 }
3321 else /* if (row_info->bit_depth == 16) */
3322 {
3323#if defined(PNG_READ_GAMMA_SUPPORTED)
3324 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3325 gamma_16_to_1 != NULL)
3326 {
3327 sp = row;
3328 dp = row;
3329 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
3330 {
3331 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3332 << 8) + (png_uint_16)(*(sp + 7)));
3333 if (a == (png_uint_16)0xffff)
3334 {
3335 png_uint_16 v;
3336
3337 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3338 *dp = (png_byte)((v >> 8) & 0xff);
3339 *(dp + 1) = (png_byte)(v & 0xff);
3340 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
3341 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3342 *(dp + 3) = (png_byte)(v & 0xff);
3343 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
3344 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3345 *(dp + 5) = (png_byte)(v & 0xff);
3346 }
3347 else if (a == 0)
3348 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003349 /* Background is already in screen gamma */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003350 *dp = (png_byte)((background->red >> 8) & 0xff);
3351 *(dp + 1) = (png_byte)(background->red & 0xff);
3352 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3353 *(dp + 3) = (png_byte)(background->green & 0xff);
3354 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3355 *(dp + 5) = (png_byte)(background->blue & 0xff);
3356 }
3357 else
3358 {
3359 png_uint_16 v, w, x;
3360
3361 v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3362 png_composite_16(w, v, a, background_1->red);
3363 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3364 *dp = (png_byte)((x >> 8) & 0xff);
3365 *(dp + 1) = (png_byte)(x & 0xff);
3366 v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
3367 png_composite_16(w, v, a, background_1->green);
3368 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3369 *(dp + 2) = (png_byte)((x >> 8) & 0xff);
3370 *(dp + 3) = (png_byte)(x & 0xff);
3371 v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
3372 png_composite_16(w, v, a, background_1->blue);
3373 x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
3374 *(dp + 4) = (png_byte)((x >> 8) & 0xff);
3375 *(dp + 5) = (png_byte)(x & 0xff);
3376 }
3377 }
3378 }
3379 else
3380#endif
3381 {
3382 sp = row;
3383 dp = row;
3384 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
3385 {
3386 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3387 << 8) + (png_uint_16)(*(sp + 7)));
3388 if (a == (png_uint_16)0xffff)
3389 {
3390 png_memcpy(dp, sp, 6);
3391 }
3392 else if (a == 0)
3393 {
3394 *dp = (png_byte)((background->red >> 8) & 0xff);
3395 *(dp + 1) = (png_byte)(background->red & 0xff);
3396 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3397 *(dp + 3) = (png_byte)(background->green & 0xff);
3398 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3399 *(dp + 5) = (png_byte)(background->blue & 0xff);
3400 }
3401 else
3402 {
3403 png_uint_16 v;
3404
3405 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3406 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3407 + *(sp + 3));
3408 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3409 + *(sp + 5));
3410
3411 png_composite_16(v, r, a, background->red);
3412 *dp = (png_byte)((v >> 8) & 0xff);
3413 *(dp + 1) = (png_byte)(v & 0xff);
3414 png_composite_16(v, g, a, background->green);
3415 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3416 *(dp + 3) = (png_byte)(v & 0xff);
3417 png_composite_16(v, b, a, background->blue);
3418 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3419 *(dp + 5) = (png_byte)(v & 0xff);
3420 }
3421 }
3422 }
3423 }
3424 break;
3425 }
3426 }
3427
3428 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
3429 {
3430 row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
3431 row_info->channels--;
3432 row_info->pixel_depth = (png_byte)(row_info->channels *
3433 row_info->bit_depth);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003434 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003435 }
3436 }
3437}
3438#endif
3439
3440#if defined(PNG_READ_GAMMA_SUPPORTED)
3441/* Gamma correct the image, avoiding the alpha channel. Make sure
3442 * you do this after you deal with the transparency issue on grayscale
3443 * or RGB images. If your bit depth is 8, use gamma_table, if it
3444 * is 16, use gamma_16_table and gamma_shift. Build these with
3445 * build_gamma_table().
3446 */
3447void /* PRIVATE */
3448png_do_gamma(png_row_infop row_info, png_bytep row,
3449 png_bytep gamma_table, png_uint_16pp gamma_16_table,
3450 int gamma_shift)
3451{
3452 png_bytep sp;
3453 png_uint_32 i;
3454 png_uint_32 row_width=row_info->width;
3455
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003456 png_debug(1, "in png_do_gamma");
The Android Open Source Project893912b2009-03-03 19:30:05 -08003457 if (
3458#if defined(PNG_USELESS_TESTS_SUPPORTED)
3459 row != NULL && row_info != NULL &&
3460#endif
3461 ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
3462 (row_info->bit_depth == 16 && gamma_16_table != NULL)))
3463 {
3464 switch (row_info->color_type)
3465 {
3466 case PNG_COLOR_TYPE_RGB:
3467 {
3468 if (row_info->bit_depth == 8)
3469 {
3470 sp = row;
3471 for (i = 0; i < row_width; i++)
3472 {
3473 *sp = gamma_table[*sp];
3474 sp++;
3475 *sp = gamma_table[*sp];
3476 sp++;
3477 *sp = gamma_table[*sp];
3478 sp++;
3479 }
3480 }
3481 else /* if (row_info->bit_depth == 16) */
3482 {
3483 sp = row;
3484 for (i = 0; i < row_width; i++)
3485 {
3486 png_uint_16 v;
3487
3488 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3489 *sp = (png_byte)((v >> 8) & 0xff);
3490 *(sp + 1) = (png_byte)(v & 0xff);
3491 sp += 2;
3492 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3493 *sp = (png_byte)((v >> 8) & 0xff);
3494 *(sp + 1) = (png_byte)(v & 0xff);
3495 sp += 2;
3496 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3497 *sp = (png_byte)((v >> 8) & 0xff);
3498 *(sp + 1) = (png_byte)(v & 0xff);
3499 sp += 2;
3500 }
3501 }
3502 break;
3503 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003504
The Android Open Source Project893912b2009-03-03 19:30:05 -08003505 case PNG_COLOR_TYPE_RGB_ALPHA:
3506 {
3507 if (row_info->bit_depth == 8)
3508 {
3509 sp = row;
3510 for (i = 0; i < row_width; i++)
3511 {
3512 *sp = gamma_table[*sp];
3513 sp++;
3514 *sp = gamma_table[*sp];
3515 sp++;
3516 *sp = gamma_table[*sp];
3517 sp++;
3518 sp++;
3519 }
3520 }
3521 else /* if (row_info->bit_depth == 16) */
3522 {
3523 sp = row;
3524 for (i = 0; i < row_width; i++)
3525 {
3526 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3527 *sp = (png_byte)((v >> 8) & 0xff);
3528 *(sp + 1) = (png_byte)(v & 0xff);
3529 sp += 2;
3530 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3531 *sp = (png_byte)((v >> 8) & 0xff);
3532 *(sp + 1) = (png_byte)(v & 0xff);
3533 sp += 2;
3534 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3535 *sp = (png_byte)((v >> 8) & 0xff);
3536 *(sp + 1) = (png_byte)(v & 0xff);
3537 sp += 4;
3538 }
3539 }
3540 break;
3541 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003542
The Android Open Source Project893912b2009-03-03 19:30:05 -08003543 case PNG_COLOR_TYPE_GRAY_ALPHA:
3544 {
3545 if (row_info->bit_depth == 8)
3546 {
3547 sp = row;
3548 for (i = 0; i < row_width; i++)
3549 {
3550 *sp = gamma_table[*sp];
3551 sp += 2;
3552 }
3553 }
3554 else /* if (row_info->bit_depth == 16) */
3555 {
3556 sp = row;
3557 for (i = 0; i < row_width; i++)
3558 {
3559 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3560 *sp = (png_byte)((v >> 8) & 0xff);
3561 *(sp + 1) = (png_byte)(v & 0xff);
3562 sp += 4;
3563 }
3564 }
3565 break;
3566 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003567
The Android Open Source Project893912b2009-03-03 19:30:05 -08003568 case PNG_COLOR_TYPE_GRAY:
3569 {
3570 if (row_info->bit_depth == 2)
3571 {
3572 sp = row;
3573 for (i = 0; i < row_width; i += 4)
3574 {
3575 int a = *sp & 0xc0;
3576 int b = *sp & 0x30;
3577 int c = *sp & 0x0c;
3578 int d = *sp & 0x03;
3579
3580 *sp = (png_byte)(
3581 ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
3582 ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
3583 ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
3584 ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
3585 sp++;
3586 }
3587 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003588
The Android Open Source Project893912b2009-03-03 19:30:05 -08003589 if (row_info->bit_depth == 4)
3590 {
3591 sp = row;
3592 for (i = 0; i < row_width; i += 2)
3593 {
3594 int msb = *sp & 0xf0;
3595 int lsb = *sp & 0x0f;
3596
3597 *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
3598 | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
3599 sp++;
3600 }
3601 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003602
The Android Open Source Project893912b2009-03-03 19:30:05 -08003603 else if (row_info->bit_depth == 8)
3604 {
3605 sp = row;
3606 for (i = 0; i < row_width; i++)
3607 {
3608 *sp = gamma_table[*sp];
3609 sp++;
3610 }
3611 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003612
The Android Open Source Project893912b2009-03-03 19:30:05 -08003613 else if (row_info->bit_depth == 16)
3614 {
3615 sp = row;
3616 for (i = 0; i < row_width; i++)
3617 {
3618 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3619 *sp = (png_byte)((v >> 8) & 0xff);
3620 *(sp + 1) = (png_byte)(v & 0xff);
3621 sp += 2;
3622 }
3623 }
3624 break;
3625 }
3626 }
3627 }
3628}
3629#endif
3630
3631#if defined(PNG_READ_EXPAND_SUPPORTED)
3632/* Expands a palette row to an RGB or RGBA row depending
3633 * upon whether you supply trans and num_trans.
3634 */
3635void /* PRIVATE */
3636png_do_expand_palette(png_row_infop row_info, png_bytep row,
3637 png_colorp palette, png_bytep trans, int num_trans)
3638{
3639 int shift, value;
3640 png_bytep sp, dp;
3641 png_uint_32 i;
3642 png_uint_32 row_width=row_info->width;
3643
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003644 png_debug(1, "in png_do_expand_palette");
The Android Open Source Project893912b2009-03-03 19:30:05 -08003645 if (
3646#if defined(PNG_USELESS_TESTS_SUPPORTED)
3647 row != NULL && row_info != NULL &&
3648#endif
3649 row_info->color_type == PNG_COLOR_TYPE_PALETTE)
3650 {
3651 if (row_info->bit_depth < 8)
3652 {
3653 switch (row_info->bit_depth)
3654 {
3655 case 1:
3656 {
3657 sp = row + (png_size_t)((row_width - 1) >> 3);
3658 dp = row + (png_size_t)row_width - 1;
3659 shift = 7 - (int)((row_width + 7) & 0x07);
3660 for (i = 0; i < row_width; i++)
3661 {
3662 if ((*sp >> shift) & 0x01)
3663 *dp = 1;
3664 else
3665 *dp = 0;
3666 if (shift == 7)
3667 {
3668 shift = 0;
3669 sp--;
3670 }
3671 else
3672 shift++;
3673
3674 dp--;
3675 }
3676 break;
3677 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003678
The Android Open Source Project893912b2009-03-03 19:30:05 -08003679 case 2:
3680 {
3681 sp = row + (png_size_t)((row_width - 1) >> 2);
3682 dp = row + (png_size_t)row_width - 1;
3683 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
3684 for (i = 0; i < row_width; i++)
3685 {
3686 value = (*sp >> shift) & 0x03;
3687 *dp = (png_byte)value;
3688 if (shift == 6)
3689 {
3690 shift = 0;
3691 sp--;
3692 }
3693 else
3694 shift += 2;
3695
3696 dp--;
3697 }
3698 break;
3699 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003700
The Android Open Source Project893912b2009-03-03 19:30:05 -08003701 case 4:
3702 {
3703 sp = row + (png_size_t)((row_width - 1) >> 1);
3704 dp = row + (png_size_t)row_width - 1;
3705 shift = (int)((row_width & 0x01) << 2);
3706 for (i = 0; i < row_width; i++)
3707 {
3708 value = (*sp >> shift) & 0x0f;
3709 *dp = (png_byte)value;
3710 if (shift == 4)
3711 {
3712 shift = 0;
3713 sp--;
3714 }
3715 else
3716 shift += 4;
3717
3718 dp--;
3719 }
3720 break;
3721 }
3722 }
3723 row_info->bit_depth = 8;
3724 row_info->pixel_depth = 8;
3725 row_info->rowbytes = row_width;
3726 }
3727 switch (row_info->bit_depth)
3728 {
3729 case 8:
3730 {
3731 if (trans != NULL)
3732 {
3733 sp = row + (png_size_t)row_width - 1;
3734 dp = row + (png_size_t)(row_width << 2) - 1;
3735
3736 for (i = 0; i < row_width; i++)
3737 {
3738 if ((int)(*sp) >= num_trans)
3739 *dp-- = 0xff;
3740 else
3741 *dp-- = trans[*sp];
3742 *dp-- = palette[*sp].blue;
3743 *dp-- = palette[*sp].green;
3744 *dp-- = palette[*sp].red;
3745 sp--;
3746 }
3747 row_info->bit_depth = 8;
3748 row_info->pixel_depth = 32;
3749 row_info->rowbytes = row_width * 4;
3750 row_info->color_type = 6;
3751 row_info->channels = 4;
3752 }
3753 else
3754 {
3755 sp = row + (png_size_t)row_width - 1;
3756 dp = row + (png_size_t)(row_width * 3) - 1;
3757
3758 for (i = 0; i < row_width; i++)
3759 {
3760 *dp-- = palette[*sp].blue;
3761 *dp-- = palette[*sp].green;
3762 *dp-- = palette[*sp].red;
3763 sp--;
3764 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003765
The Android Open Source Project893912b2009-03-03 19:30:05 -08003766 row_info->bit_depth = 8;
3767 row_info->pixel_depth = 24;
3768 row_info->rowbytes = row_width * 3;
3769 row_info->color_type = 2;
3770 row_info->channels = 3;
3771 }
3772 break;
3773 }
3774 }
3775 }
3776}
3777
3778/* If the bit depth < 8, it is expanded to 8. Also, if the already
3779 * expanded transparency value is supplied, an alpha channel is built.
3780 */
3781void /* PRIVATE */
3782png_do_expand(png_row_infop row_info, png_bytep row,
3783 png_color_16p trans_value)
3784{
3785 int shift, value;
3786 png_bytep sp, dp;
3787 png_uint_32 i;
3788 png_uint_32 row_width=row_info->width;
3789
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003790 png_debug(1, "in png_do_expand");
The Android Open Source Project893912b2009-03-03 19:30:05 -08003791#if defined(PNG_USELESS_TESTS_SUPPORTED)
3792 if (row != NULL && row_info != NULL)
3793#endif
3794 {
3795 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
3796 {
3797 png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
3798
3799 if (row_info->bit_depth < 8)
3800 {
3801 switch (row_info->bit_depth)
3802 {
3803 case 1:
3804 {
3805 gray = (png_uint_16)((gray&0x01)*0xff);
3806 sp = row + (png_size_t)((row_width - 1) >> 3);
3807 dp = row + (png_size_t)row_width - 1;
3808 shift = 7 - (int)((row_width + 7) & 0x07);
3809 for (i = 0; i < row_width; i++)
3810 {
3811 if ((*sp >> shift) & 0x01)
3812 *dp = 0xff;
3813 else
3814 *dp = 0;
3815 if (shift == 7)
3816 {
3817 shift = 0;
3818 sp--;
3819 }
3820 else
3821 shift++;
3822
3823 dp--;
3824 }
3825 break;
3826 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003827
The Android Open Source Project893912b2009-03-03 19:30:05 -08003828 case 2:
3829 {
3830 gray = (png_uint_16)((gray&0x03)*0x55);
3831 sp = row + (png_size_t)((row_width - 1) >> 2);
3832 dp = row + (png_size_t)row_width - 1;
3833 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
3834 for (i = 0; i < row_width; i++)
3835 {
3836 value = (*sp >> shift) & 0x03;
3837 *dp = (png_byte)(value | (value << 2) | (value << 4) |
3838 (value << 6));
3839 if (shift == 6)
3840 {
3841 shift = 0;
3842 sp--;
3843 }
3844 else
3845 shift += 2;
3846
3847 dp--;
3848 }
3849 break;
3850 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003851
The Android Open Source Project893912b2009-03-03 19:30:05 -08003852 case 4:
3853 {
3854 gray = (png_uint_16)((gray&0x0f)*0x11);
3855 sp = row + (png_size_t)((row_width - 1) >> 1);
3856 dp = row + (png_size_t)row_width - 1;
3857 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
3858 for (i = 0; i < row_width; i++)
3859 {
3860 value = (*sp >> shift) & 0x0f;
3861 *dp = (png_byte)(value | (value << 4));
3862 if (shift == 4)
3863 {
3864 shift = 0;
3865 sp--;
3866 }
3867 else
3868 shift = 4;
3869
3870 dp--;
3871 }
3872 break;
3873 }
3874 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003875
The Android Open Source Project893912b2009-03-03 19:30:05 -08003876 row_info->bit_depth = 8;
3877 row_info->pixel_depth = 8;
3878 row_info->rowbytes = row_width;
3879 }
3880
3881 if (trans_value != NULL)
3882 {
3883 if (row_info->bit_depth == 8)
3884 {
3885 gray = gray & 0xff;
3886 sp = row + (png_size_t)row_width - 1;
3887 dp = row + (png_size_t)(row_width << 1) - 1;
3888 for (i = 0; i < row_width; i++)
3889 {
3890 if (*sp == gray)
3891 *dp-- = 0;
3892 else
3893 *dp-- = 0xff;
3894 *dp-- = *sp--;
3895 }
3896 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003897
The Android Open Source Project893912b2009-03-03 19:30:05 -08003898 else if (row_info->bit_depth == 16)
3899 {
3900 png_byte gray_high = (gray >> 8) & 0xff;
3901 png_byte gray_low = gray & 0xff;
3902 sp = row + row_info->rowbytes - 1;
3903 dp = row + (row_info->rowbytes << 1) - 1;
3904 for (i = 0; i < row_width; i++)
3905 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003906 if (*(sp - 1) == gray_high && *(sp) == gray_low)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003907 {
3908 *dp-- = 0;
3909 *dp-- = 0;
3910 }
3911 else
3912 {
3913 *dp-- = 0xff;
3914 *dp-- = 0xff;
3915 }
3916 *dp-- = *sp--;
3917 *dp-- = *sp--;
3918 }
3919 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003920
The Android Open Source Project893912b2009-03-03 19:30:05 -08003921 row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
3922 row_info->channels = 2;
3923 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
3924 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
3925 row_width);
3926 }
3927 }
3928 else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
3929 {
3930 if (row_info->bit_depth == 8)
3931 {
3932 png_byte red = trans_value->red & 0xff;
3933 png_byte green = trans_value->green & 0xff;
3934 png_byte blue = trans_value->blue & 0xff;
3935 sp = row + (png_size_t)row_info->rowbytes - 1;
3936 dp = row + (png_size_t)(row_width << 2) - 1;
3937 for (i = 0; i < row_width; i++)
3938 {
3939 if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)
3940 *dp-- = 0;
3941 else
3942 *dp-- = 0xff;
3943 *dp-- = *sp--;
3944 *dp-- = *sp--;
3945 *dp-- = *sp--;
3946 }
3947 }
3948 else if (row_info->bit_depth == 16)
3949 {
3950 png_byte red_high = (trans_value->red >> 8) & 0xff;
3951 png_byte green_high = (trans_value->green >> 8) & 0xff;
3952 png_byte blue_high = (trans_value->blue >> 8) & 0xff;
3953 png_byte red_low = trans_value->red & 0xff;
3954 png_byte green_low = trans_value->green & 0xff;
3955 png_byte blue_low = trans_value->blue & 0xff;
3956 sp = row + row_info->rowbytes - 1;
3957 dp = row + (png_size_t)(row_width << 3) - 1;
3958 for (i = 0; i < row_width; i++)
3959 {
3960 if (*(sp - 5) == red_high &&
3961 *(sp - 4) == red_low &&
3962 *(sp - 3) == green_high &&
3963 *(sp - 2) == green_low &&
3964 *(sp - 1) == blue_high &&
3965 *(sp ) == blue_low)
3966 {
3967 *dp-- = 0;
3968 *dp-- = 0;
3969 }
3970 else
3971 {
3972 *dp-- = 0xff;
3973 *dp-- = 0xff;
3974 }
3975 *dp-- = *sp--;
3976 *dp-- = *sp--;
3977 *dp-- = *sp--;
3978 *dp-- = *sp--;
3979 *dp-- = *sp--;
3980 *dp-- = *sp--;
3981 }
3982 }
3983 row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
3984 row_info->channels = 4;
3985 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003986 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003987 }
3988 }
3989}
3990#endif
3991
3992#if defined(PNG_READ_DITHER_SUPPORTED)
3993void /* PRIVATE */
3994png_do_dither(png_row_infop row_info, png_bytep row,
3995 png_bytep palette_lookup, png_bytep dither_lookup)
3996{
3997 png_bytep sp, dp;
3998 png_uint_32 i;
3999 png_uint_32 row_width=row_info->width;
4000
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004001 png_debug(1, "in png_do_dither");
The Android Open Source Project893912b2009-03-03 19:30:05 -08004002#if defined(PNG_USELESS_TESTS_SUPPORTED)
4003 if (row != NULL && row_info != NULL)
4004#endif
4005 {
4006 if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
4007 palette_lookup && row_info->bit_depth == 8)
4008 {
4009 int r, g, b, p;
4010 sp = row;
4011 dp = row;
4012 for (i = 0; i < row_width; i++)
4013 {
4014 r = *sp++;
4015 g = *sp++;
4016 b = *sp++;
4017
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004018 /* This looks real messy, but the compiler will reduce
4019 * it down to a reasonable formula. For example, with
4020 * 5 bits per color, we get:
4021 * p = (((r >> 3) & 0x1f) << 10) |
4022 * (((g >> 3) & 0x1f) << 5) |
4023 * ((b >> 3) & 0x1f);
4024 */
The Android Open Source Project893912b2009-03-03 19:30:05 -08004025 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
4026 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
4027 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
4028 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
4029 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
4030 (PNG_DITHER_BLUE_BITS)) |
4031 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
4032 ((1 << PNG_DITHER_BLUE_BITS) - 1));
4033
4034 *dp++ = palette_lookup[p];
4035 }
4036 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
4037 row_info->channels = 1;
4038 row_info->pixel_depth = row_info->bit_depth;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004039 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08004040 }
4041 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
4042 palette_lookup != NULL && row_info->bit_depth == 8)
4043 {
4044 int r, g, b, p;
4045 sp = row;
4046 dp = row;
4047 for (i = 0; i < row_width; i++)
4048 {
4049 r = *sp++;
4050 g = *sp++;
4051 b = *sp++;
4052 sp++;
4053
4054 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
4055 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
4056 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
4057 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
4058 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
4059 (PNG_DITHER_BLUE_BITS)) |
4060 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
4061 ((1 << PNG_DITHER_BLUE_BITS) - 1));
4062
4063 *dp++ = palette_lookup[p];
4064 }
4065 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
4066 row_info->channels = 1;
4067 row_info->pixel_depth = row_info->bit_depth;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004068 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08004069 }
4070 else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
4071 dither_lookup && row_info->bit_depth == 8)
4072 {
4073 sp = row;
4074 for (i = 0; i < row_width; i++, sp++)
4075 {
4076 *sp = dither_lookup[*sp];
4077 }
4078 }
4079 }
4080}
4081#endif
4082
4083#ifdef PNG_FLOATING_POINT_SUPPORTED
4084#if defined(PNG_READ_GAMMA_SUPPORTED)
4085static PNG_CONST int png_gamma_shift[] =
4086 {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0, 0x00};
4087
4088/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
4089 * tables, we don't make a full table if we are reducing to 8-bit in
4090 * the future. Note also how the gamma_16 tables are segmented so that
4091 * we don't need to allocate > 64K chunks for a full 16-bit table.
4092 */
4093void /* PRIVATE */
4094png_build_gamma_table(png_structp png_ptr)
4095{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004096 png_debug(1, "in png_build_gamma_table");
The Android Open Source Project893912b2009-03-03 19:30:05 -08004097
4098 if (png_ptr->bit_depth <= 8)
4099 {
4100 int i;
4101 double g;
4102
4103 if (png_ptr->screen_gamma > .000001)
4104 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004105
The Android Open Source Project893912b2009-03-03 19:30:05 -08004106 else
4107 g = 1.0;
4108
4109 png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
4110 (png_uint_32)256);
4111
4112 for (i = 0; i < 256; i++)
4113 {
4114 png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
4115 g) * 255.0 + .5);
4116 }
4117
4118#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
4119 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4120 if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
4121 {
4122
4123 g = 1.0 / (png_ptr->gamma);
4124
4125 png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
4126 (png_uint_32)256);
4127
4128 for (i = 0; i < 256; i++)
4129 {
4130 png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
4131 g) * 255.0 + .5);
4132 }
4133
4134
4135 png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
4136 (png_uint_32)256);
4137
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004138 if (png_ptr->screen_gamma > 0.000001)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004139 g = 1.0 / png_ptr->screen_gamma;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004140
The Android Open Source Project893912b2009-03-03 19:30:05 -08004141 else
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004142 g = png_ptr->gamma; /* Probably doing rgb_to_gray */
The Android Open Source Project893912b2009-03-03 19:30:05 -08004143
4144 for (i = 0; i < 256; i++)
4145 {
4146 png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
4147 g) * 255.0 + .5);
4148
4149 }
4150 }
4151#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
4152 }
4153 else
4154 {
4155 double g;
4156 int i, j, shift, num;
4157 int sig_bit;
4158 png_uint_32 ig;
4159
4160 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
4161 {
4162 sig_bit = (int)png_ptr->sig_bit.red;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004163
The Android Open Source Project893912b2009-03-03 19:30:05 -08004164 if ((int)png_ptr->sig_bit.green > sig_bit)
4165 sig_bit = png_ptr->sig_bit.green;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004166
The Android Open Source Project893912b2009-03-03 19:30:05 -08004167 if ((int)png_ptr->sig_bit.blue > sig_bit)
4168 sig_bit = png_ptr->sig_bit.blue;
4169 }
4170 else
4171 {
4172 sig_bit = (int)png_ptr->sig_bit.gray;
4173 }
4174
4175 if (sig_bit > 0)
4176 shift = 16 - sig_bit;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004177
The Android Open Source Project893912b2009-03-03 19:30:05 -08004178 else
4179 shift = 0;
4180
4181 if (png_ptr->transformations & PNG_16_TO_8)
4182 {
4183 if (shift < (16 - PNG_MAX_GAMMA_8))
4184 shift = (16 - PNG_MAX_GAMMA_8);
4185 }
4186
4187 if (shift > 8)
4188 shift = 8;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004189
The Android Open Source Project893912b2009-03-03 19:30:05 -08004190 if (shift < 0)
4191 shift = 0;
4192
4193 png_ptr->gamma_shift = (png_byte)shift;
4194
4195 num = (1 << (8 - shift));
4196
4197 if (png_ptr->screen_gamma > .000001)
4198 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
4199 else
4200 g = 1.0;
4201
4202 png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004203 (png_uint_32)(num * png_sizeof(png_uint_16p)));
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004204 png_memset(png_ptr->gamma_16_table, 0, num * png_sizeof(png_uint_16p));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004205
4206 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
4207 {
4208 double fin, fout;
4209 png_uint_32 last, max;
4210
4211 for (i = 0; i < num; i++)
4212 {
4213 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004214 (png_uint_32)(256 * png_sizeof(png_uint_16)));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004215 }
4216
4217 g = 1.0 / g;
4218 last = 0;
4219 for (i = 0; i < 256; i++)
4220 {
4221 fout = ((double)i + 0.5) / 256.0;
4222 fin = pow(fout, g);
4223 max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
4224 while (last <= max)
4225 {
4226 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4227 [(int)(last >> (8 - shift))] = (png_uint_16)(
4228 (png_uint_16)i | ((png_uint_16)i << 8));
4229 last++;
4230 }
4231 }
4232 while (last < ((png_uint_32)num << 8))
4233 {
4234 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4235 [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
4236 last++;
4237 }
4238 }
4239 else
4240 {
4241 for (i = 0; i < num; i++)
4242 {
4243 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004244 (png_uint_32)(256 * png_sizeof(png_uint_16)));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004245
4246 ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004247
The Android Open Source Project893912b2009-03-03 19:30:05 -08004248 for (j = 0; j < 256; j++)
4249 {
4250 png_ptr->gamma_16_table[i][j] =
4251 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4252 65535.0, g) * 65535.0 + .5);
4253 }
4254 }
4255 }
4256
4257#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
4258 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4259 if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
4260 {
4261
4262 g = 1.0 / (png_ptr->gamma);
4263
4264 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004265 (png_uint_32)(num * png_sizeof(png_uint_16p )));
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004266 png_memset(png_ptr->gamma_16_to_1, 0, num * png_sizeof(png_uint_16p));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004267
4268 for (i = 0; i < num; i++)
4269 {
4270 png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004271 (png_uint_32)(256 * png_sizeof(png_uint_16)));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004272
4273 ig = (((png_uint_32)i *
4274 (png_uint_32)png_gamma_shift[shift]) >> 4);
4275 for (j = 0; j < 256; j++)
4276 {
4277 png_ptr->gamma_16_to_1[i][j] =
4278 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4279 65535.0, g) * 65535.0 + .5);
4280 }
4281 }
4282
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004283 if (png_ptr->screen_gamma > 0.000001)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004284 g = 1.0 / png_ptr->screen_gamma;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004285
The Android Open Source Project893912b2009-03-03 19:30:05 -08004286 else
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004287 g = png_ptr->gamma; /* Probably doing rgb_to_gray */
The Android Open Source Project893912b2009-03-03 19:30:05 -08004288
4289 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004290 (png_uint_32)(num * png_sizeof(png_uint_16p)));
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004291 png_memset(png_ptr->gamma_16_from_1, 0,
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004292 num * png_sizeof(png_uint_16p));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004293
4294 for (i = 0; i < num; i++)
4295 {
4296 png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004297 (png_uint_32)(256 * png_sizeof(png_uint_16)));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004298
4299 ig = (((png_uint_32)i *
4300 (png_uint_32)png_gamma_shift[shift]) >> 4);
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004301
The Android Open Source Project893912b2009-03-03 19:30:05 -08004302 for (j = 0; j < 256; j++)
4303 {
4304 png_ptr->gamma_16_from_1[i][j] =
4305 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4306 65535.0, g) * 65535.0 + .5);
4307 }
4308 }
4309 }
4310#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
4311 }
4312}
4313#endif
4314/* To do: install integer version of png_build_gamma_table here */
4315#endif
4316
4317#if defined(PNG_MNG_FEATURES_SUPPORTED)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004318/* Undoes intrapixel differencing */
The Android Open Source Project893912b2009-03-03 19:30:05 -08004319void /* PRIVATE */
4320png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
4321{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004322 png_debug(1, "in png_do_read_intrapixel");
The Android Open Source Project893912b2009-03-03 19:30:05 -08004323 if (
4324#if defined(PNG_USELESS_TESTS_SUPPORTED)
4325 row != NULL && row_info != NULL &&
4326#endif
4327 (row_info->color_type & PNG_COLOR_MASK_COLOR))
4328 {
4329 int bytes_per_pixel;
4330 png_uint_32 row_width = row_info->width;
4331 if (row_info->bit_depth == 8)
4332 {
4333 png_bytep rp;
4334 png_uint_32 i;
4335
4336 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4337 bytes_per_pixel = 3;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004338
The Android Open Source Project893912b2009-03-03 19:30:05 -08004339 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4340 bytes_per_pixel = 4;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004341
The Android Open Source Project893912b2009-03-03 19:30:05 -08004342 else
4343 return;
4344
4345 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4346 {
4347 *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff);
4348 *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff);
4349 }
4350 }
4351 else if (row_info->bit_depth == 16)
4352 {
4353 png_bytep rp;
4354 png_uint_32 i;
4355
4356 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4357 bytes_per_pixel = 6;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004358
The Android Open Source Project893912b2009-03-03 19:30:05 -08004359 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4360 bytes_per_pixel = 8;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004361
The Android Open Source Project893912b2009-03-03 19:30:05 -08004362 else
4363 return;
4364
4365 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4366 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004367 png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1);
4368 png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3);
4369 png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5);
4370 png_uint_32 red = (png_uint_32)((s0 + s1 + 65536L) & 0xffffL);
4371 png_uint_32 blue = (png_uint_32)((s2 + s1 + 65536L) & 0xffffL);
The Android Open Source Project893912b2009-03-03 19:30:05 -08004372 *(rp ) = (png_byte)((red >> 8) & 0xff);
4373 *(rp+1) = (png_byte)(red & 0xff);
4374 *(rp+4) = (png_byte)((blue >> 8) & 0xff);
4375 *(rp+5) = (png_byte)(blue & 0xff);
4376 }
4377 }
4378 }
4379}
4380#endif /* PNG_MNG_FEATURES_SUPPORTED */
4381#endif /* PNG_READ_SUPPORTED */