blob: a916f54febec587b0d82d6583796b5f3def1782b [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 *
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004 * Last changed in libpng 1.2.35 [February 14, 2009]
The Android Open Source Project893912b2009-03-03 19:30:05 -08005 * For conditions of distribution and use, see copyright notice in png.h
The Android Open Source Project4215dd12009-03-09 11:52:12 -07006 * Copyright (c) 1998-2009 Glenn Randers-Pehrson
The Android Open Source Project893912b2009-03-03 19:30:05 -08007 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
9 *
10 * This file contains functions optionally called by an application
11 * in order to tell libpng how to handle data when reading a PNG.
12 * Transformations that are used in both reading and writing are
13 * in pngtrans.c.
14 */
15
16#define PNG_INTERNAL
17#include "png.h"
The Android Open Source Project893912b2009-03-03 19:30:05 -080018#if defined(PNG_READ_SUPPORTED)
19
20/* Set the action on getting a CRC error for an ancillary or critical chunk. */
21void PNGAPI
22png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
23{
The Android Open Source Project4215dd12009-03-09 11:52:12 -070024 png_debug(1, "in png_set_crc_action");
The Android Open Source Project893912b2009-03-03 19:30:05 -080025 /* Tell libpng how we react to CRC errors in critical chunks */
The Android Open Source Project4215dd12009-03-09 11:52:12 -070026 if (png_ptr == NULL) return;
The Android Open Source Project893912b2009-03-03 19:30:05 -080027 switch (crit_action)
28 {
29 case PNG_CRC_NO_CHANGE: /* leave setting as is */
30 break;
31 case PNG_CRC_WARN_USE: /* warn/use data */
32 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
33 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
34 break;
35 case PNG_CRC_QUIET_USE: /* quiet/use data */
36 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
37 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
38 PNG_FLAG_CRC_CRITICAL_IGNORE;
39 break;
40 case PNG_CRC_WARN_DISCARD: /* not a valid action for critical data */
The Android Open Source Project4215dd12009-03-09 11:52:12 -070041 png_warning(png_ptr,
42 "Can't discard critical data on CRC error.");
The Android Open Source Project893912b2009-03-03 19:30:05 -080043 case PNG_CRC_ERROR_QUIT: /* error/quit */
44 case PNG_CRC_DEFAULT:
45 default:
46 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
47 break;
48 }
49
50 switch (ancil_action)
51 {
52 case PNG_CRC_NO_CHANGE: /* leave setting as is */
53 break;
54 case PNG_CRC_WARN_USE: /* warn/use data */
55 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
56 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
57 break;
58 case PNG_CRC_QUIET_USE: /* quiet/use data */
59 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
60 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
61 PNG_FLAG_CRC_ANCILLARY_NOWARN;
62 break;
63 case PNG_CRC_ERROR_QUIT: /* error/quit */
64 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
65 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
66 break;
67 case PNG_CRC_WARN_DISCARD: /* warn/discard data */
68 case PNG_CRC_DEFAULT:
69 default:
70 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
71 break;
72 }
73}
74
75#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
76 defined(PNG_FLOATING_POINT_SUPPORTED)
77/* handle alpha and tRNS via a background color */
78void PNGAPI
79png_set_background(png_structp png_ptr,
80 png_color_16p background_color, int background_gamma_code,
81 int need_expand, double background_gamma)
82{
The Android Open Source Project4215dd12009-03-09 11:52:12 -070083 png_debug(1, "in png_set_background");
84 if (png_ptr == NULL) return;
The Android Open Source Project893912b2009-03-03 19:30:05 -080085 if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
86 {
87 png_warning(png_ptr, "Application must supply a known background gamma");
88 return;
89 }
90
91 png_ptr->transformations |= PNG_BACKGROUND;
92 png_memcpy(&(png_ptr->background), background_color,
93 png_sizeof(png_color_16));
94 png_ptr->background_gamma = (float)background_gamma;
95 png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
96 png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
97}
98#endif
99
100#if defined(PNG_READ_16_TO_8_SUPPORTED)
101/* strip 16 bit depth files to 8 bit depth */
102void PNGAPI
103png_set_strip_16(png_structp png_ptr)
104{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700105 png_debug(1, "in png_set_strip_16");
106 if (png_ptr == NULL) return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800107 png_ptr->transformations |= PNG_16_TO_8;
108}
109#endif
110
111#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
112void PNGAPI
113png_set_strip_alpha(png_structp png_ptr)
114{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700115 png_debug(1, "in png_set_strip_alpha");
116 if (png_ptr == NULL) return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800117 png_ptr->flags |= PNG_FLAG_STRIP_ALPHA;
118}
119#endif
120
121#if defined(PNG_READ_DITHER_SUPPORTED)
122/* Dither file to 8 bit. Supply a palette, the current number
123 * of elements in the palette, the maximum number of elements
124 * allowed, and a histogram if possible. If the current number
125 * of colors is greater then the maximum number, the palette will be
126 * modified to fit in the maximum number. "full_dither" indicates
127 * whether we need a dithering cube set up for RGB images, or if we
128 * simply are reducing the number of colors in a paletted image.
129 */
130
131typedef struct png_dsort_struct
132{
133 struct png_dsort_struct FAR * next;
134 png_byte left;
135 png_byte right;
136} png_dsort;
137typedef png_dsort FAR * png_dsortp;
138typedef png_dsort FAR * FAR * png_dsortpp;
139
140void PNGAPI
141png_set_dither(png_structp png_ptr, png_colorp palette,
142 int num_palette, int maximum_colors, png_uint_16p histogram,
143 int full_dither)
144{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700145 png_debug(1, "in png_set_dither");
146 if (png_ptr == NULL) return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800147 png_ptr->transformations |= PNG_DITHER;
148
149 if (!full_dither)
150 {
151 int i;
152
153 png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700154 (png_uint_32)(num_palette * png_sizeof(png_byte)));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800155 for (i = 0; i < num_palette; i++)
156 png_ptr->dither_index[i] = (png_byte)i;
157 }
158
159 if (num_palette > maximum_colors)
160 {
161 if (histogram != NULL)
162 {
163 /* This is easy enough, just throw out the least used colors.
164 Perhaps not the best solution, but good enough. */
165
166 int i;
167
168 /* initialize an array to sort colors */
169 png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700170 (png_uint_32)(num_palette * png_sizeof(png_byte)));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800171
172 /* initialize the dither_sort array */
173 for (i = 0; i < num_palette; i++)
174 png_ptr->dither_sort[i] = (png_byte)i;
175
176 /* Find the least used palette entries by starting a
177 bubble sort, and running it until we have sorted
178 out enough colors. Note that we don't care about
179 sorting all the colors, just finding which are
180 least used. */
181
182 for (i = num_palette - 1; i >= maximum_colors; i--)
183 {
184 int done; /* to stop early if the list is pre-sorted */
185 int j;
186
187 done = 1;
188 for (j = 0; j < i; j++)
189 {
190 if (histogram[png_ptr->dither_sort[j]]
191 < histogram[png_ptr->dither_sort[j + 1]])
192 {
193 png_byte t;
194
195 t = png_ptr->dither_sort[j];
196 png_ptr->dither_sort[j] = png_ptr->dither_sort[j + 1];
197 png_ptr->dither_sort[j + 1] = t;
198 done = 0;
199 }
200 }
201 if (done)
202 break;
203 }
204
205 /* swap the palette around, and set up a table, if necessary */
206 if (full_dither)
207 {
208 int j = num_palette;
209
210 /* put all the useful colors within the max, but don't
211 move the others */
212 for (i = 0; i < maximum_colors; i++)
213 {
214 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
215 {
216 do
217 j--;
218 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
219 palette[i] = palette[j];
220 }
221 }
222 }
223 else
224 {
225 int j = num_palette;
226
227 /* move all the used colors inside the max limit, and
228 develop a translation table */
229 for (i = 0; i < maximum_colors; i++)
230 {
231 /* only move the colors we need to */
232 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
233 {
234 png_color tmp_color;
235
236 do
237 j--;
238 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
239
240 tmp_color = palette[j];
241 palette[j] = palette[i];
242 palette[i] = tmp_color;
243 /* indicate where the color went */
244 png_ptr->dither_index[j] = (png_byte)i;
245 png_ptr->dither_index[i] = (png_byte)j;
246 }
247 }
248
249 /* find closest color for those colors we are not using */
250 for (i = 0; i < num_palette; i++)
251 {
252 if ((int)png_ptr->dither_index[i] >= maximum_colors)
253 {
254 int min_d, k, min_k, d_index;
255
256 /* find the closest color to one we threw out */
257 d_index = png_ptr->dither_index[i];
258 min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
259 for (k = 1, min_k = 0; k < maximum_colors; k++)
260 {
261 int d;
262
263 d = PNG_COLOR_DIST(palette[d_index], palette[k]);
264
265 if (d < min_d)
266 {
267 min_d = d;
268 min_k = k;
269 }
270 }
271 /* point to closest color */
272 png_ptr->dither_index[i] = (png_byte)min_k;
273 }
274 }
275 }
276 png_free(png_ptr, png_ptr->dither_sort);
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700277 png_ptr->dither_sort = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800278 }
279 else
280 {
281 /* This is much harder to do simply (and quickly). Perhaps
282 we need to go through a median cut routine, but those
283 don't always behave themselves with only a few colors
284 as input. So we will just find the closest two colors,
285 and throw out one of them (chosen somewhat randomly).
286 [We don't understand this at all, so if someone wants to
287 work on improving it, be our guest - AED, GRP]
288 */
289 int i;
290 int max_d;
291 int num_new_palette;
292 png_dsortp t;
293 png_dsortpp hash;
294
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700295 t = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800296
297 /* initialize palette index arrays */
298 png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700299 (png_uint_32)(num_palette * png_sizeof(png_byte)));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800300 png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700301 (png_uint_32)(num_palette * png_sizeof(png_byte)));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800302
303 /* initialize the sort array */
304 for (i = 0; i < num_palette; i++)
305 {
306 png_ptr->index_to_palette[i] = (png_byte)i;
307 png_ptr->palette_to_index[i] = (png_byte)i;
308 }
309
310 hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 *
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700311 png_sizeof(png_dsortp)));
312 png_memset(hash, 0, 769 * png_sizeof(png_dsortp));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800313
314 num_new_palette = num_palette;
315
316 /* initial wild guess at how far apart the farthest pixel
317 pair we will be eliminating will be. Larger
318 numbers mean more areas will be allocated, Smaller
319 numbers run the risk of not saving enough data, and
320 having to do this all over again.
321
322 I have not done extensive checking on this number.
323 */
324 max_d = 96;
325
326 while (num_new_palette > maximum_colors)
327 {
328 for (i = 0; i < num_new_palette - 1; i++)
329 {
330 int j;
331
332 for (j = i + 1; j < num_new_palette; j++)
333 {
334 int d;
335
336 d = PNG_COLOR_DIST(palette[i], palette[j]);
337
338 if (d <= max_d)
339 {
340
341 t = (png_dsortp)png_malloc_warn(png_ptr,
342 (png_uint_32)(png_sizeof(png_dsort)));
343 if (t == NULL)
344 break;
345 t->next = hash[d];
346 t->left = (png_byte)i;
347 t->right = (png_byte)j;
348 hash[d] = t;
349 }
350 }
351 if (t == NULL)
352 break;
353 }
354
355 if (t != NULL)
356 for (i = 0; i <= max_d; i++)
357 {
358 if (hash[i] != NULL)
359 {
360 png_dsortp p;
361
362 for (p = hash[i]; p; p = p->next)
363 {
364 if ((int)png_ptr->index_to_palette[p->left]
365 < num_new_palette &&
366 (int)png_ptr->index_to_palette[p->right]
367 < num_new_palette)
368 {
369 int j, next_j;
370
371 if (num_new_palette & 0x01)
372 {
373 j = p->left;
374 next_j = p->right;
375 }
376 else
377 {
378 j = p->right;
379 next_j = p->left;
380 }
381
382 num_new_palette--;
383 palette[png_ptr->index_to_palette[j]]
384 = palette[num_new_palette];
385 if (!full_dither)
386 {
387 int k;
388
389 for (k = 0; k < num_palette; k++)
390 {
391 if (png_ptr->dither_index[k] ==
392 png_ptr->index_to_palette[j])
393 png_ptr->dither_index[k] =
394 png_ptr->index_to_palette[next_j];
395 if ((int)png_ptr->dither_index[k] ==
396 num_new_palette)
397 png_ptr->dither_index[k] =
398 png_ptr->index_to_palette[j];
399 }
400 }
401
402 png_ptr->index_to_palette[png_ptr->palette_to_index
403 [num_new_palette]] = png_ptr->index_to_palette[j];
404 png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
405 = png_ptr->palette_to_index[num_new_palette];
406
407 png_ptr->index_to_palette[j] = (png_byte)num_new_palette;
408 png_ptr->palette_to_index[num_new_palette] = (png_byte)j;
409 }
410 if (num_new_palette <= maximum_colors)
411 break;
412 }
413 if (num_new_palette <= maximum_colors)
414 break;
415 }
416 }
417
418 for (i = 0; i < 769; i++)
419 {
420 if (hash[i] != NULL)
421 {
422 png_dsortp p = hash[i];
423 while (p)
424 {
425 t = p->next;
426 png_free(png_ptr, p);
427 p = t;
428 }
429 }
430 hash[i] = 0;
431 }
432 max_d += 96;
433 }
434 png_free(png_ptr, hash);
435 png_free(png_ptr, png_ptr->palette_to_index);
436 png_free(png_ptr, png_ptr->index_to_palette);
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700437 png_ptr->palette_to_index = NULL;
438 png_ptr->index_to_palette = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800439 }
440 num_palette = maximum_colors;
441 }
442 if (png_ptr->palette == NULL)
443 {
444 png_ptr->palette = palette;
445 }
446 png_ptr->num_palette = (png_uint_16)num_palette;
447
448 if (full_dither)
449 {
450 int i;
451 png_bytep distance;
452 int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
453 PNG_DITHER_BLUE_BITS;
454 int num_red = (1 << PNG_DITHER_RED_BITS);
455 int num_green = (1 << PNG_DITHER_GREEN_BITS);
456 int num_blue = (1 << PNG_DITHER_BLUE_BITS);
457 png_size_t num_entries = ((png_size_t)1 << total_bits);
458
459 png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700460 (png_uint_32)(num_entries * png_sizeof(png_byte)));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800461
462 png_memset(png_ptr->palette_lookup, 0, num_entries *
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700463 png_sizeof(png_byte));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800464
465 distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
466 png_sizeof(png_byte)));
467
468 png_memset(distance, 0xff, num_entries * png_sizeof(png_byte));
469
470 for (i = 0; i < num_palette; i++)
471 {
472 int ir, ig, ib;
473 int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
474 int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
475 int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
476
477 for (ir = 0; ir < num_red; ir++)
478 {
479 /* int dr = abs(ir - r); */
480 int dr = ((ir > r) ? ir - r : r - ir);
481 int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
482
483 for (ig = 0; ig < num_green; ig++)
484 {
485 /* int dg = abs(ig - g); */
486 int dg = ((ig > g) ? ig - g : g - ig);
487 int dt = dr + dg;
488 int dm = ((dr > dg) ? dr : dg);
489 int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
490
491 for (ib = 0; ib < num_blue; ib++)
492 {
493 int d_index = index_g | ib;
494 /* int db = abs(ib - b); */
495 int db = ((ib > b) ? ib - b : b - ib);
496 int dmax = ((dm > db) ? dm : db);
497 int d = dmax + dt + db;
498
499 if (d < (int)distance[d_index])
500 {
501 distance[d_index] = (png_byte)d;
502 png_ptr->palette_lookup[d_index] = (png_byte)i;
503 }
504 }
505 }
506 }
507 }
508
509 png_free(png_ptr, distance);
510 }
511}
512#endif
513
514#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
515/* Transform the image from the file_gamma to the screen_gamma. We
516 * only do transformations on images where the file_gamma and screen_gamma
517 * are not close reciprocals, otherwise it slows things down slightly, and
518 * also needlessly introduces small errors.
519 *
520 * We will turn off gamma transformation later if no semitransparent entries
521 * are present in the tRNS array for palette images. We can't do it here
522 * because we don't necessarily have the tRNS chunk yet.
523 */
524void PNGAPI
525png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
526{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700527 png_debug(1, "in png_set_gamma");
528 if (png_ptr == NULL) return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800529 if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) ||
530 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) ||
531 (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
532 png_ptr->transformations |= PNG_GAMMA;
533 png_ptr->gamma = (float)file_gamma;
534 png_ptr->screen_gamma = (float)scrn_gamma;
535}
536#endif
537
538#if defined(PNG_READ_EXPAND_SUPPORTED)
539/* Expand paletted images to RGB, expand grayscale images of
540 * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
541 * to alpha channels.
542 */
543void PNGAPI
544png_set_expand(png_structp png_ptr)
545{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700546 png_debug(1, "in png_set_expand");
547 if (png_ptr == NULL) return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800548 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
549 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
550}
551
552/* GRR 19990627: the following three functions currently are identical
553 * to png_set_expand(). However, it is entirely reasonable that someone
554 * might wish to expand an indexed image to RGB but *not* expand a single,
555 * fully transparent palette entry to a full alpha channel--perhaps instead
556 * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
557 * the transparent color with a particular RGB value, or drop tRNS entirely.
558 * IOW, a future version of the library may make the transformations flag
559 * a bit more fine-grained, with separate bits for each of these three
560 * functions.
561 *
562 * More to the point, these functions make it obvious what libpng will be
563 * doing, whereas "expand" can (and does) mean any number of things.
564 *
565 * GRP 20060307: In libpng-1.4.0, png_set_gray_1_2_4_to_8() was modified
566 * to expand only the sample depth but not to expand the tRNS to alpha.
567 */
568
569/* Expand paletted images to RGB. */
570void PNGAPI
571png_set_palette_to_rgb(png_structp png_ptr)
572{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700573 png_debug(1, "in png_set_palette_to_rgb");
574 if (png_ptr == NULL) return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800575 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
576 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
577}
578
579#if !defined(PNG_1_0_X)
580/* Expand grayscale images of less than 8-bit depth to 8 bits. */
581void PNGAPI
582png_set_expand_gray_1_2_4_to_8(png_structp png_ptr)
583{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700584 png_debug(1, "in png_set_expand_gray_1_2_4_to_8");
585 if (png_ptr == NULL) return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800586 png_ptr->transformations |= PNG_EXPAND;
587 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
588}
589#endif
590
591#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
592/* Expand grayscale images of less than 8-bit depth to 8 bits. */
593/* Deprecated as of libpng-1.2.9 */
594void PNGAPI
595png_set_gray_1_2_4_to_8(png_structp png_ptr)
596{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700597 png_debug(1, "in png_set_gray_1_2_4_to_8");
598 if (png_ptr == NULL) return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800599 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
600}
601#endif
602
603
604/* Expand tRNS chunks to alpha channels. */
605void PNGAPI
606png_set_tRNS_to_alpha(png_structp png_ptr)
607{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700608 png_debug(1, "in png_set_tRNS_to_alpha");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800609 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
610 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
611}
612#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
613
614#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
615void PNGAPI
616png_set_gray_to_rgb(png_structp png_ptr)
617{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700618 png_debug(1, "in png_set_gray_to_rgb");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800619 png_ptr->transformations |= PNG_GRAY_TO_RGB;
620 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
621}
622#endif
623
624#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
625#if defined(PNG_FLOATING_POINT_SUPPORTED)
626/* Convert a RGB image to a grayscale of the same width. This allows us,
627 * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
628 */
629
630void PNGAPI
631png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red,
632 double green)
633{
634 int red_fixed = (int)((float)red*100000.0 + 0.5);
635 int green_fixed = (int)((float)green*100000.0 + 0.5);
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700636 if (png_ptr == NULL) return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800637 png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed);
638}
639#endif
640
641void PNGAPI
642png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
643 png_fixed_point red, png_fixed_point green)
644{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700645 png_debug(1, "in png_set_rgb_to_gray");
646 if (png_ptr == NULL) return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800647 switch(error_action)
648 {
649 case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY;
650 break;
651 case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
652 break;
653 case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
654 }
655 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
656#if defined(PNG_READ_EXPAND_SUPPORTED)
657 png_ptr->transformations |= PNG_EXPAND;
658#else
659 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700660 png_warning(png_ptr,
661 "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED.");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800662 png_ptr->transformations &= ~PNG_RGB_TO_GRAY;
663 }
664#endif
665 {
666 png_uint_16 red_int, green_int;
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700667 if (red < 0 || green < 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800668 {
669 red_int = 6968; /* .212671 * 32768 + .5 */
670 green_int = 23434; /* .715160 * 32768 + .5 */
671 }
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700672 else if (red + green < 100000L)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800673 {
674 red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
675 green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
676 }
677 else
678 {
679 png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
680 red_int = 6968;
681 green_int = 23434;
682 }
683 png_ptr->rgb_to_gray_red_coeff = red_int;
684 png_ptr->rgb_to_gray_green_coeff = green_int;
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700685 png_ptr->rgb_to_gray_blue_coeff =
686 (png_uint_16)(32768 - red_int - green_int);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800687 }
688}
689#endif
690
691#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
692 defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
693 defined(PNG_LEGACY_SUPPORTED)
694void PNGAPI
695png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
696 read_user_transform_fn)
697{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700698 png_debug(1, "in png_set_read_user_transform_fn");
699 if (png_ptr == NULL) return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800700#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
701 png_ptr->transformations |= PNG_USER_TRANSFORM;
702 png_ptr->read_user_transform_fn = read_user_transform_fn;
703#endif
704#ifdef PNG_LEGACY_SUPPORTED
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700705 if (read_user_transform_fn)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800706 png_warning(png_ptr,
707 "This version of libpng does not support user transforms");
708#endif
709}
710#endif
711
712/* Initialize everything needed for the read. This includes modifying
713 * the palette.
714 */
715void /* PRIVATE */
716png_init_read_transformations(png_structp png_ptr)
717{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700718 png_debug(1, "in png_init_read_transformations");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800719#if defined(PNG_USELESS_TESTS_SUPPORTED)
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700720 if (png_ptr != NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800721#endif
722 {
723#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
724 || defined(PNG_READ_GAMMA_SUPPORTED)
725 int color_type = png_ptr->color_type;
726#endif
727
728#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
729
730#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
731 /* Detect gray background and attempt to enable optimization
732 * for gray --> RGB case */
733 /* Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
734 * RGB_ALPHA (in which case need_expand is superfluous anyway), the
735 * background color might actually be gray yet not be flagged as such.
736 * This is not a problem for the current code, which uses
737 * PNG_BACKGROUND_IS_GRAY only to decide when to do the
738 * png_do_gray_to_rgb() transformation.
739 */
740 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
741 !(color_type & PNG_COLOR_MASK_COLOR))
742 {
743 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
744 } else if ((png_ptr->transformations & PNG_BACKGROUND) &&
745 !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
746 (png_ptr->transformations & PNG_GRAY_TO_RGB) &&
747 png_ptr->background.red == png_ptr->background.green &&
748 png_ptr->background.red == png_ptr->background.blue)
749 {
750 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
751 png_ptr->background.gray = png_ptr->background.red;
752 }
753#endif
754
755 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
756 (png_ptr->transformations & PNG_EXPAND))
757 {
758 if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
759 {
760 /* expand background and tRNS chunks */
761 switch (png_ptr->bit_depth)
762 {
763 case 1:
764 png_ptr->background.gray *= (png_uint_16)0xff;
765 png_ptr->background.red = png_ptr->background.green
766 = png_ptr->background.blue = png_ptr->background.gray;
767 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
768 {
769 png_ptr->trans_values.gray *= (png_uint_16)0xff;
770 png_ptr->trans_values.red = png_ptr->trans_values.green
771 = png_ptr->trans_values.blue = png_ptr->trans_values.gray;
772 }
773 break;
774 case 2:
775 png_ptr->background.gray *= (png_uint_16)0x55;
776 png_ptr->background.red = png_ptr->background.green
777 = png_ptr->background.blue = png_ptr->background.gray;
778 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
779 {
780 png_ptr->trans_values.gray *= (png_uint_16)0x55;
781 png_ptr->trans_values.red = png_ptr->trans_values.green
782 = png_ptr->trans_values.blue = png_ptr->trans_values.gray;
783 }
784 break;
785 case 4:
786 png_ptr->background.gray *= (png_uint_16)0x11;
787 png_ptr->background.red = png_ptr->background.green
788 = png_ptr->background.blue = png_ptr->background.gray;
789 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
790 {
791 png_ptr->trans_values.gray *= (png_uint_16)0x11;
792 png_ptr->trans_values.red = png_ptr->trans_values.green
793 = png_ptr->trans_values.blue = png_ptr->trans_values.gray;
794 }
795 break;
796 case 8:
797 case 16:
798 png_ptr->background.red = png_ptr->background.green
799 = png_ptr->background.blue = png_ptr->background.gray;
800 break;
801 }
802 }
803 else if (color_type == PNG_COLOR_TYPE_PALETTE)
804 {
805 png_ptr->background.red =
806 png_ptr->palette[png_ptr->background.index].red;
807 png_ptr->background.green =
808 png_ptr->palette[png_ptr->background.index].green;
809 png_ptr->background.blue =
810 png_ptr->palette[png_ptr->background.index].blue;
811
812#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
813 if (png_ptr->transformations & PNG_INVERT_ALPHA)
814 {
815#if defined(PNG_READ_EXPAND_SUPPORTED)
816 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
817#endif
818 {
819 /* invert the alpha channel (in tRNS) unless the pixels are
820 going to be expanded, in which case leave it for later */
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700821 int i, istop;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800822 istop=(int)png_ptr->num_trans;
823 for (i=0; i<istop; i++)
824 png_ptr->trans[i] = (png_byte)(255 - png_ptr->trans[i]);
825 }
826 }
827#endif
828
829 }
830 }
831#endif
832
833#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
834 png_ptr->background_1 = png_ptr->background;
835#endif
836#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
837
838 if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0)
839 && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0)
840 < PNG_GAMMA_THRESHOLD))
841 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700842 int i, k;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800843 k=0;
844 for (i=0; i<png_ptr->num_trans; i++)
845 {
846 if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff)
847 k=1; /* partial transparency is present */
848 }
849 if (k == 0)
850 png_ptr->transformations &= ~PNG_GAMMA;
851 }
852
853 if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) &&
854 png_ptr->gamma != 0.0)
855 {
856 png_build_gamma_table(png_ptr);
857#if defined(PNG_READ_BACKGROUND_SUPPORTED)
858 if (png_ptr->transformations & PNG_BACKGROUND)
859 {
860 if (color_type == PNG_COLOR_TYPE_PALETTE)
861 {
862 /* could skip if no transparency and
863 */
864 png_color back, back_1;
865 png_colorp palette = png_ptr->palette;
866 int num_palette = png_ptr->num_palette;
867 int i;
868 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
869 {
870 back.red = png_ptr->gamma_table[png_ptr->background.red];
871 back.green = png_ptr->gamma_table[png_ptr->background.green];
872 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
873
874 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
875 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
876 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
877 }
878 else
879 {
880 double g, gs;
881
882 switch (png_ptr->background_gamma_type)
883 {
884 case PNG_BACKGROUND_GAMMA_SCREEN:
885 g = (png_ptr->screen_gamma);
886 gs = 1.0;
887 break;
888 case PNG_BACKGROUND_GAMMA_FILE:
889 g = 1.0 / (png_ptr->gamma);
890 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
891 break;
892 case PNG_BACKGROUND_GAMMA_UNIQUE:
893 g = 1.0 / (png_ptr->background_gamma);
894 gs = 1.0 / (png_ptr->background_gamma *
895 png_ptr->screen_gamma);
896 break;
897 default:
898 g = 1.0; /* back_1 */
899 gs = 1.0; /* back */
900 }
901
902 if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD)
903 {
904 back.red = (png_byte)png_ptr->background.red;
905 back.green = (png_byte)png_ptr->background.green;
906 back.blue = (png_byte)png_ptr->background.blue;
907 }
908 else
909 {
910 back.red = (png_byte)(pow(
911 (double)png_ptr->background.red/255, gs) * 255.0 + .5);
912 back.green = (png_byte)(pow(
913 (double)png_ptr->background.green/255, gs) * 255.0 + .5);
914 back.blue = (png_byte)(pow(
915 (double)png_ptr->background.blue/255, gs) * 255.0 + .5);
916 }
917
918 back_1.red = (png_byte)(pow(
919 (double)png_ptr->background.red/255, g) * 255.0 + .5);
920 back_1.green = (png_byte)(pow(
921 (double)png_ptr->background.green/255, g) * 255.0 + .5);
922 back_1.blue = (png_byte)(pow(
923 (double)png_ptr->background.blue/255, g) * 255.0 + .5);
924 }
925 for (i = 0; i < num_palette; i++)
926 {
927 if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
928 {
929 if (png_ptr->trans[i] == 0)
930 {
931 palette[i] = back;
932 }
933 else /* if (png_ptr->trans[i] != 0xff) */
934 {
935 png_byte v, w;
936
937 v = png_ptr->gamma_to_1[palette[i].red];
938 png_composite(w, v, png_ptr->trans[i], back_1.red);
939 palette[i].red = png_ptr->gamma_from_1[w];
940
941 v = png_ptr->gamma_to_1[palette[i].green];
942 png_composite(w, v, png_ptr->trans[i], back_1.green);
943 palette[i].green = png_ptr->gamma_from_1[w];
944
945 v = png_ptr->gamma_to_1[palette[i].blue];
946 png_composite(w, v, png_ptr->trans[i], back_1.blue);
947 palette[i].blue = png_ptr->gamma_from_1[w];
948 }
949 }
950 else
951 {
952 palette[i].red = png_ptr->gamma_table[palette[i].red];
953 palette[i].green = png_ptr->gamma_table[palette[i].green];
954 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
955 }
956 }
957 /* Prevent the transformations being done again, and make sure
958 * that the now spurious alpha channel is stripped - the code
959 * has just reduced background composition and gamma correction
960 * to a simple alpha channel strip.
961 */
962 png_ptr->transformations &= ~PNG_BACKGROUND;
963 png_ptr->transformations &= ~PNG_GAMMA;
964 png_ptr->transformations |= PNG_STRIP_ALPHA;
965 }
966 /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */
967 else
968 /* color_type != PNG_COLOR_TYPE_PALETTE */
969 {
970 double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
971 double g = 1.0;
972 double gs = 1.0;
973
974 switch (png_ptr->background_gamma_type)
975 {
976 case PNG_BACKGROUND_GAMMA_SCREEN:
977 g = (png_ptr->screen_gamma);
978 gs = 1.0;
979 break;
980 case PNG_BACKGROUND_GAMMA_FILE:
981 g = 1.0 / (png_ptr->gamma);
982 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
983 break;
984 case PNG_BACKGROUND_GAMMA_UNIQUE:
985 g = 1.0 / (png_ptr->background_gamma);
986 gs = 1.0 / (png_ptr->background_gamma *
987 png_ptr->screen_gamma);
988 break;
989 }
990
991 png_ptr->background_1.gray = (png_uint_16)(pow(
992 (double)png_ptr->background.gray / m, g) * m + .5);
993 png_ptr->background.gray = (png_uint_16)(pow(
994 (double)png_ptr->background.gray / m, gs) * m + .5);
995
996 if ((png_ptr->background.red != png_ptr->background.green) ||
997 (png_ptr->background.red != png_ptr->background.blue) ||
998 (png_ptr->background.red != png_ptr->background.gray))
999 {
1000 /* RGB or RGBA with color background */
1001 png_ptr->background_1.red = (png_uint_16)(pow(
1002 (double)png_ptr->background.red / m, g) * m + .5);
1003 png_ptr->background_1.green = (png_uint_16)(pow(
1004 (double)png_ptr->background.green / m, g) * m + .5);
1005 png_ptr->background_1.blue = (png_uint_16)(pow(
1006 (double)png_ptr->background.blue / m, g) * m + .5);
1007 png_ptr->background.red = (png_uint_16)(pow(
1008 (double)png_ptr->background.red / m, gs) * m + .5);
1009 png_ptr->background.green = (png_uint_16)(pow(
1010 (double)png_ptr->background.green / m, gs) * m + .5);
1011 png_ptr->background.blue = (png_uint_16)(pow(
1012 (double)png_ptr->background.blue / m, gs) * m + .5);
1013 }
1014 else
1015 {
1016 /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */
1017 png_ptr->background_1.red = png_ptr->background_1.green
1018 = png_ptr->background_1.blue = png_ptr->background_1.gray;
1019 png_ptr->background.red = png_ptr->background.green
1020 = png_ptr->background.blue = png_ptr->background.gray;
1021 }
1022 }
1023 }
1024 else
1025 /* transformation does not include PNG_BACKGROUND */
1026#endif /* PNG_READ_BACKGROUND_SUPPORTED */
1027 if (color_type == PNG_COLOR_TYPE_PALETTE)
1028 {
1029 png_colorp palette = png_ptr->palette;
1030 int num_palette = png_ptr->num_palette;
1031 int i;
1032
1033 for (i = 0; i < num_palette; i++)
1034 {
1035 palette[i].red = png_ptr->gamma_table[palette[i].red];
1036 palette[i].green = png_ptr->gamma_table[palette[i].green];
1037 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
1038 }
1039
1040 /* Done the gamma correction. */
1041 png_ptr->transformations &= ~PNG_GAMMA;
1042 }
1043 }
1044#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1045 else
1046#endif
1047#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */
1048#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1049 /* No GAMMA transformation */
1050 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1051 (color_type == PNG_COLOR_TYPE_PALETTE))
1052 {
1053 int i;
1054 int istop = (int)png_ptr->num_trans;
1055 png_color back;
1056 png_colorp palette = png_ptr->palette;
1057
1058 back.red = (png_byte)png_ptr->background.red;
1059 back.green = (png_byte)png_ptr->background.green;
1060 back.blue = (png_byte)png_ptr->background.blue;
1061
1062 for (i = 0; i < istop; i++)
1063 {
1064 if (png_ptr->trans[i] == 0)
1065 {
1066 palette[i] = back;
1067 }
1068 else if (png_ptr->trans[i] != 0xff)
1069 {
1070 /* The png_composite() macro is defined in png.h */
1071 png_composite(palette[i].red, palette[i].red,
1072 png_ptr->trans[i], back.red);
1073 png_composite(palette[i].green, palette[i].green,
1074 png_ptr->trans[i], back.green);
1075 png_composite(palette[i].blue, palette[i].blue,
1076 png_ptr->trans[i], back.blue);
1077 }
1078 }
1079
1080 /* Handled alpha, still need to strip the channel. */
1081 png_ptr->transformations &= ~PNG_BACKGROUND;
1082 png_ptr->transformations |= PNG_STRIP_ALPHA;
1083 }
1084#endif /* PNG_READ_BACKGROUND_SUPPORTED */
1085
1086#if defined(PNG_READ_SHIFT_SUPPORTED)
1087 if ((png_ptr->transformations & PNG_SHIFT) &&
1088 (color_type == PNG_COLOR_TYPE_PALETTE))
1089 {
1090 png_uint_16 i;
1091 png_uint_16 istop = png_ptr->num_palette;
1092 int sr = 8 - png_ptr->sig_bit.red;
1093 int sg = 8 - png_ptr->sig_bit.green;
1094 int sb = 8 - png_ptr->sig_bit.blue;
1095
1096 if (sr < 0 || sr > 8)
1097 sr = 0;
1098 if (sg < 0 || sg > 8)
1099 sg = 0;
1100 if (sb < 0 || sb > 8)
1101 sb = 0;
1102 for (i = 0; i < istop; i++)
1103 {
1104 png_ptr->palette[i].red >>= sr;
1105 png_ptr->palette[i].green >>= sg;
1106 png_ptr->palette[i].blue >>= sb;
1107 }
1108 }
1109#endif /* PNG_READ_SHIFT_SUPPORTED */
1110 }
1111#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \
1112 && !defined(PNG_READ_BACKGROUND_SUPPORTED)
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001113 if (png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001114 return;
1115#endif
1116}
1117
1118/* Modify the info structure to reflect the transformations. The
1119 * info should be updated so a PNG file could be written with it,
1120 * assuming the transformations result in valid PNG data.
1121 */
1122void /* PRIVATE */
1123png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
1124{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001125 png_debug(1, "in png_read_transform_info");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001126#if defined(PNG_READ_EXPAND_SUPPORTED)
1127 if (png_ptr->transformations & PNG_EXPAND)
1128 {
1129 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1130 {
1131 if (png_ptr->num_trans &&
1132 (png_ptr->transformations & PNG_EXPAND_tRNS))
1133 info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1134 else
1135 info_ptr->color_type = PNG_COLOR_TYPE_RGB;
1136 info_ptr->bit_depth = 8;
1137 info_ptr->num_trans = 0;
1138 }
1139 else
1140 {
1141 if (png_ptr->num_trans)
1142 {
1143 if (png_ptr->transformations & PNG_EXPAND_tRNS)
1144 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
1145#if 0 /* Removed from libpng-1.2.27 */
1146 else
1147 info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
1148#endif
1149 }
1150 if (info_ptr->bit_depth < 8)
1151 info_ptr->bit_depth = 8;
1152 info_ptr->num_trans = 0;
1153 }
1154 }
1155#endif
1156
1157#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1158 if (png_ptr->transformations & PNG_BACKGROUND)
1159 {
1160 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
1161 info_ptr->num_trans = 0;
1162 info_ptr->background = png_ptr->background;
1163 }
1164#endif
1165
1166#if defined(PNG_READ_GAMMA_SUPPORTED)
1167 if (png_ptr->transformations & PNG_GAMMA)
1168 {
1169#ifdef PNG_FLOATING_POINT_SUPPORTED
1170 info_ptr->gamma = png_ptr->gamma;
1171#endif
1172#ifdef PNG_FIXED_POINT_SUPPORTED
1173 info_ptr->int_gamma = png_ptr->int_gamma;
1174#endif
1175 }
1176#endif
1177
1178#if defined(PNG_READ_16_TO_8_SUPPORTED)
1179 if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16))
1180 info_ptr->bit_depth = 8;
1181#endif
1182
1183#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1184 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
1185 info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
1186#endif
1187
1188#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1189 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1190 info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
1191#endif
1192
1193#if defined(PNG_READ_DITHER_SUPPORTED)
1194 if (png_ptr->transformations & PNG_DITHER)
1195 {
1196 if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
1197 (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
1198 png_ptr->palette_lookup && info_ptr->bit_depth == 8)
1199 {
1200 info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
1201 }
1202 }
1203#endif
1204
1205#if defined(PNG_READ_PACK_SUPPORTED)
1206 if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
1207 info_ptr->bit_depth = 8;
1208#endif
1209
1210 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1211 info_ptr->channels = 1;
1212 else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
1213 info_ptr->channels = 3;
1214 else
1215 info_ptr->channels = 1;
1216
1217#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
1218 if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
1219 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
1220#endif
1221
1222 if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
1223 info_ptr->channels++;
1224
1225#if defined(PNG_READ_FILLER_SUPPORTED)
1226 /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
1227 if ((png_ptr->transformations & PNG_FILLER) &&
1228 ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
1229 (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))
1230 {
1231 info_ptr->channels++;
1232 /* if adding a true alpha channel not just filler */
1233#if !defined(PNG_1_0_X)
1234 if (png_ptr->transformations & PNG_ADD_ALPHA)
1235 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
1236#endif
1237 }
1238#endif
1239
1240#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
1241defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001242 if (png_ptr->transformations & PNG_USER_TRANSFORM)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001243 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001244 if (info_ptr->bit_depth < png_ptr->user_transform_depth)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001245 info_ptr->bit_depth = png_ptr->user_transform_depth;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001246 if (info_ptr->channels < png_ptr->user_transform_channels)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001247 info_ptr->channels = png_ptr->user_transform_channels;
1248 }
1249#endif
1250
1251 info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
1252 info_ptr->bit_depth);
1253
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001254 info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001255
1256#if !defined(PNG_READ_EXPAND_SUPPORTED)
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001257 if (png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001258 return;
1259#endif
1260}
1261
1262/* Transform the row. The order of transformations is significant,
1263 * and is very touchy. If you add a transformation, take care to
1264 * decide how it fits in with the other transformations here.
1265 */
1266void /* PRIVATE */
1267png_do_read_transformations(png_structp png_ptr)
1268{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001269 png_debug(1, "in png_do_read_transformations");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001270 if (png_ptr->row_buf == NULL)
1271 {
1272#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
1273 char msg[50];
1274
1275 png_snprintf2(msg, 50,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001276 "NULL row buffer for row %ld, pass %d", (long)png_ptr->row_number,
The Android Open Source Project893912b2009-03-03 19:30:05 -08001277 png_ptr->pass);
1278 png_error(png_ptr, msg);
1279#else
1280 png_error(png_ptr, "NULL row buffer");
1281#endif
1282 }
1283#ifdef PNG_WARN_UNINITIALIZED_ROW
1284 if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
1285 /* Application has failed to call either png_read_start_image()
1286 * or png_read_update_info() after setting transforms that expand
1287 * pixels. This check added to libpng-1.2.19 */
1288#if (PNG_WARN_UNINITIALIZED_ROW==1)
1289 png_error(png_ptr, "Uninitialized row");
1290#else
1291 png_warning(png_ptr, "Uninitialized row");
1292#endif
1293#endif
1294
1295#if defined(PNG_READ_EXPAND_SUPPORTED)
1296 if (png_ptr->transformations & PNG_EXPAND)
1297 {
1298 if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
1299 {
1300 png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
1301 png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
1302 }
1303 else
1304 {
1305 if (png_ptr->num_trans &&
1306 (png_ptr->transformations & PNG_EXPAND_tRNS))
1307 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1308 &(png_ptr->trans_values));
1309 else
1310 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1311 NULL);
1312 }
1313 }
1314#endif
1315
1316#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
1317 if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
1318 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
1319 PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA));
1320#endif
1321
1322#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1323 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1324 {
1325 int rgb_error =
1326 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 -07001327 if (rgb_error)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001328 {
1329 png_ptr->rgb_to_gray_status=1;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001330 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
The Android Open Source Project893912b2009-03-03 19:30:05 -08001331 PNG_RGB_TO_GRAY_WARN)
1332 png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001333 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
The Android Open Source Project893912b2009-03-03 19:30:05 -08001334 PNG_RGB_TO_GRAY_ERR)
1335 png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1336 }
1337 }
1338#endif
1339
1340/*
1341From Andreas Dilger e-mail to png-implement, 26 March 1998:
1342
1343 In most cases, the "simple transparency" should be done prior to doing
1344 gray-to-RGB, or you will have to test 3x as many bytes to check if a
1345 pixel is transparent. You would also need to make sure that the
1346 transparency information is upgraded to RGB.
1347
1348 To summarize, the current flow is:
1349 - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
1350 with background "in place" if transparent,
1351 convert to RGB if necessary
1352 - Gray + alpha -> composite with gray background and remove alpha bytes,
1353 convert to RGB if necessary
1354
1355 To support RGB backgrounds for gray images we need:
1356 - Gray + simple transparency -> convert to RGB + simple transparency, compare
1357 3 or 6 bytes and composite with background
1358 "in place" if transparent (3x compare/pixel
1359 compared to doing composite with gray bkgrnd)
1360 - Gray + alpha -> convert to RGB + alpha, composite with background and
1361 remove alpha bytes (3x float operations/pixel
1362 compared with composite on gray background)
1363
1364 Greg's change will do this. The reason it wasn't done before is for
1365 performance, as this increases the per-pixel operations. If we would check
1366 in advance if the background was gray or RGB, and position the gray-to-RGB
1367 transform appropriately, then it would save a lot of work/time.
1368 */
1369
1370#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1371 /* if gray -> RGB, do so now only if background is non-gray; else do later
1372 * for performance reasons */
1373 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
1374 !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
1375 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
1376#endif
1377
1378#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1379 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1380 ((png_ptr->num_trans != 0 ) ||
1381 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
1382 png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
1383 &(png_ptr->trans_values), &(png_ptr->background)
1384#if defined(PNG_READ_GAMMA_SUPPORTED)
1385 , &(png_ptr->background_1),
1386 png_ptr->gamma_table, png_ptr->gamma_from_1,
1387 png_ptr->gamma_to_1, png_ptr->gamma_16_table,
1388 png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
1389 png_ptr->gamma_shift
1390#endif
1391);
1392#endif
1393
1394#if defined(PNG_READ_GAMMA_SUPPORTED)
1395 if ((png_ptr->transformations & PNG_GAMMA) &&
1396#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1397 !((png_ptr->transformations & PNG_BACKGROUND) &&
1398 ((png_ptr->num_trans != 0) ||
1399 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
1400#endif
1401 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
1402 png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
1403 png_ptr->gamma_table, png_ptr->gamma_16_table,
1404 png_ptr->gamma_shift);
1405#endif
1406
1407#if defined(PNG_READ_16_TO_8_SUPPORTED)
1408 if (png_ptr->transformations & PNG_16_TO_8)
1409 png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
1410#endif
1411
1412#if defined(PNG_READ_DITHER_SUPPORTED)
1413 if (png_ptr->transformations & PNG_DITHER)
1414 {
1415 png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
1416 png_ptr->palette_lookup, png_ptr->dither_index);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001417 if (png_ptr->row_info.rowbytes == (png_uint_32)0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001418 png_error(png_ptr, "png_do_dither returned rowbytes=0");
1419 }
1420#endif
1421
1422#if defined(PNG_READ_INVERT_SUPPORTED)
1423 if (png_ptr->transformations & PNG_INVERT_MONO)
1424 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
1425#endif
1426
1427#if defined(PNG_READ_SHIFT_SUPPORTED)
1428 if (png_ptr->transformations & PNG_SHIFT)
1429 png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
1430 &(png_ptr->shift));
1431#endif
1432
1433#if defined(PNG_READ_PACK_SUPPORTED)
1434 if (png_ptr->transformations & PNG_PACK)
1435 png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
1436#endif
1437
1438#if defined(PNG_READ_BGR_SUPPORTED)
1439 if (png_ptr->transformations & PNG_BGR)
1440 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
1441#endif
1442
1443#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1444 if (png_ptr->transformations & PNG_PACKSWAP)
1445 png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1446#endif
1447
1448#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1449 /* if gray -> RGB, do so now only if we did not do so above */
1450 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
1451 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
1452 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
1453#endif
1454
1455#if defined(PNG_READ_FILLER_SUPPORTED)
1456 if (png_ptr->transformations & PNG_FILLER)
1457 png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
1458 (png_uint_32)png_ptr->filler, png_ptr->flags);
1459#endif
1460
1461#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
1462 if (png_ptr->transformations & PNG_INVERT_ALPHA)
1463 png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1464#endif
1465
1466#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
1467 if (png_ptr->transformations & PNG_SWAP_ALPHA)
1468 png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1469#endif
1470
1471#if defined(PNG_READ_SWAP_SUPPORTED)
1472 if (png_ptr->transformations & PNG_SWAP_BYTES)
1473 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1474#endif
1475
1476#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1477 if (png_ptr->transformations & PNG_USER_TRANSFORM)
1478 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001479 if (png_ptr->read_user_transform_fn != NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001480 (*(png_ptr->read_user_transform_fn)) /* user read transform function */
1481 (png_ptr, /* png_ptr */
1482 &(png_ptr->row_info), /* row_info: */
1483 /* png_uint_32 width; width of row */
1484 /* png_uint_32 rowbytes; number of bytes in row */
1485 /* png_byte color_type; color type of pixels */
1486 /* png_byte bit_depth; bit depth of samples */
1487 /* png_byte channels; number of channels (1-4) */
1488 /* png_byte pixel_depth; bits per pixel (depth*channels) */
1489 png_ptr->row_buf + 1); /* start of pixel data for row */
1490#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001491 if (png_ptr->user_transform_depth)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001492 png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001493 if (png_ptr->user_transform_channels)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001494 png_ptr->row_info.channels = png_ptr->user_transform_channels;
1495#endif
1496 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
1497 png_ptr->row_info.channels);
1498 png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
1499 png_ptr->row_info.width);
1500 }
1501#endif
1502
1503}
1504
1505#if defined(PNG_READ_PACK_SUPPORTED)
1506/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
1507 * without changing the actual values. Thus, if you had a row with
1508 * a bit depth of 1, you would end up with bytes that only contained
1509 * the numbers 0 or 1. If you would rather they contain 0 and 255, use
1510 * png_do_shift() after this.
1511 */
1512void /* PRIVATE */
1513png_do_unpack(png_row_infop row_info, png_bytep row)
1514{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001515 png_debug(1, "in png_do_unpack");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001516#if defined(PNG_USELESS_TESTS_SUPPORTED)
1517 if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
1518#else
1519 if (row_info->bit_depth < 8)
1520#endif
1521 {
1522 png_uint_32 i;
1523 png_uint_32 row_width=row_info->width;
1524
1525 switch (row_info->bit_depth)
1526 {
1527 case 1:
1528 {
1529 png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
1530 png_bytep dp = row + (png_size_t)row_width - 1;
1531 png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
1532 for (i = 0; i < row_width; i++)
1533 {
1534 *dp = (png_byte)((*sp >> shift) & 0x01);
1535 if (shift == 7)
1536 {
1537 shift = 0;
1538 sp--;
1539 }
1540 else
1541 shift++;
1542
1543 dp--;
1544 }
1545 break;
1546 }
1547 case 2:
1548 {
1549
1550 png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
1551 png_bytep dp = row + (png_size_t)row_width - 1;
1552 png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
1553 for (i = 0; i < row_width; i++)
1554 {
1555 *dp = (png_byte)((*sp >> shift) & 0x03);
1556 if (shift == 6)
1557 {
1558 shift = 0;
1559 sp--;
1560 }
1561 else
1562 shift += 2;
1563
1564 dp--;
1565 }
1566 break;
1567 }
1568 case 4:
1569 {
1570 png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
1571 png_bytep dp = row + (png_size_t)row_width - 1;
1572 png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
1573 for (i = 0; i < row_width; i++)
1574 {
1575 *dp = (png_byte)((*sp >> shift) & 0x0f);
1576 if (shift == 4)
1577 {
1578 shift = 0;
1579 sp--;
1580 }
1581 else
1582 shift = 4;
1583
1584 dp--;
1585 }
1586 break;
1587 }
1588 }
1589 row_info->bit_depth = 8;
1590 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
1591 row_info->rowbytes = row_width * row_info->channels;
1592 }
1593}
1594#endif
1595
1596#if defined(PNG_READ_SHIFT_SUPPORTED)
1597/* Reverse the effects of png_do_shift. This routine merely shifts the
1598 * pixels back to their significant bits values. Thus, if you have
1599 * a row of bit depth 8, but only 5 are significant, this will shift
1600 * the values back to 0 through 31.
1601 */
1602void /* PRIVATE */
1603png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
1604{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001605 png_debug(1, "in png_do_unshift");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001606 if (
1607#if defined(PNG_USELESS_TESTS_SUPPORTED)
1608 row != NULL && row_info != NULL && sig_bits != NULL &&
1609#endif
1610 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
1611 {
1612 int shift[4];
1613 int channels = 0;
1614 int c;
1615 png_uint_16 value = 0;
1616 png_uint_32 row_width = row_info->width;
1617
1618 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
1619 {
1620 shift[channels++] = row_info->bit_depth - sig_bits->red;
1621 shift[channels++] = row_info->bit_depth - sig_bits->green;
1622 shift[channels++] = row_info->bit_depth - sig_bits->blue;
1623 }
1624 else
1625 {
1626 shift[channels++] = row_info->bit_depth - sig_bits->gray;
1627 }
1628 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
1629 {
1630 shift[channels++] = row_info->bit_depth - sig_bits->alpha;
1631 }
1632
1633 for (c = 0; c < channels; c++)
1634 {
1635 if (shift[c] <= 0)
1636 shift[c] = 0;
1637 else
1638 value = 1;
1639 }
1640
1641 if (!value)
1642 return;
1643
1644 switch (row_info->bit_depth)
1645 {
1646 case 2:
1647 {
1648 png_bytep bp;
1649 png_uint_32 i;
1650 png_uint_32 istop = row_info->rowbytes;
1651
1652 for (bp = row, i = 0; i < istop; i++)
1653 {
1654 *bp >>= 1;
1655 *bp++ &= 0x55;
1656 }
1657 break;
1658 }
1659 case 4:
1660 {
1661 png_bytep bp = row;
1662 png_uint_32 i;
1663 png_uint_32 istop = row_info->rowbytes;
1664 png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
1665 (png_byte)((int)0xf >> shift[0]));
1666
1667 for (i = 0; i < istop; i++)
1668 {
1669 *bp >>= shift[0];
1670 *bp++ &= mask;
1671 }
1672 break;
1673 }
1674 case 8:
1675 {
1676 png_bytep bp = row;
1677 png_uint_32 i;
1678 png_uint_32 istop = row_width * channels;
1679
1680 for (i = 0; i < istop; i++)
1681 {
1682 *bp++ >>= shift[i%channels];
1683 }
1684 break;
1685 }
1686 case 16:
1687 {
1688 png_bytep bp = row;
1689 png_uint_32 i;
1690 png_uint_32 istop = channels * row_width;
1691
1692 for (i = 0; i < istop; i++)
1693 {
1694 value = (png_uint_16)((*bp << 8) + *(bp + 1));
1695 value >>= shift[i%channels];
1696 *bp++ = (png_byte)(value >> 8);
1697 *bp++ = (png_byte)(value & 0xff);
1698 }
1699 break;
1700 }
1701 }
1702 }
1703}
1704#endif
1705
1706#if defined(PNG_READ_16_TO_8_SUPPORTED)
1707/* chop rows of bit depth 16 down to 8 */
1708void /* PRIVATE */
1709png_do_chop(png_row_infop row_info, png_bytep row)
1710{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001711 png_debug(1, "in png_do_chop");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001712#if defined(PNG_USELESS_TESTS_SUPPORTED)
1713 if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
1714#else
1715 if (row_info->bit_depth == 16)
1716#endif
1717 {
1718 png_bytep sp = row;
1719 png_bytep dp = row;
1720 png_uint_32 i;
1721 png_uint_32 istop = row_info->width * row_info->channels;
1722
1723 for (i = 0; i<istop; i++, sp += 2, dp++)
1724 {
1725#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
1726 /* This does a more accurate scaling of the 16-bit color
1727 * value, rather than a simple low-byte truncation.
1728 *
1729 * What the ideal calculation should be:
1730 * *dp = (((((png_uint_32)(*sp) << 8) |
1731 * (png_uint_32)(*(sp + 1))) * 255 + 127) / (png_uint_32)65535L;
1732 *
1733 * GRR: no, I think this is what it really should be:
1734 * *dp = (((((png_uint_32)(*sp) << 8) |
1735 * (png_uint_32)(*(sp + 1))) + 128L) / (png_uint_32)257L;
1736 *
1737 * GRR: here's the exact calculation with shifts:
1738 * temp = (((png_uint_32)(*sp) << 8) | (png_uint_32)(*(sp + 1))) + 128L;
1739 * *dp = (temp - (temp >> 8)) >> 8;
1740 *
1741 * Approximate calculation with shift/add instead of multiply/divide:
1742 * *dp = ((((png_uint_32)(*sp) << 8) |
1743 * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
1744 *
1745 * What we actually do to avoid extra shifting and conversion:
1746 */
1747
1748 *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
1749#else
1750 /* Simply discard the low order byte */
1751 *dp = *sp;
1752#endif
1753 }
1754 row_info->bit_depth = 8;
1755 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
1756 row_info->rowbytes = row_info->width * row_info->channels;
1757 }
1758}
1759#endif
1760
1761#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
1762void /* PRIVATE */
1763png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
1764{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001765 png_debug(1, "in png_do_read_swap_alpha");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001766#if defined(PNG_USELESS_TESTS_SUPPORTED)
1767 if (row != NULL && row_info != NULL)
1768#endif
1769 {
1770 png_uint_32 row_width = row_info->width;
1771 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1772 {
1773 /* This converts from RGBA to ARGB */
1774 if (row_info->bit_depth == 8)
1775 {
1776 png_bytep sp = row + row_info->rowbytes;
1777 png_bytep dp = sp;
1778 png_byte save;
1779 png_uint_32 i;
1780
1781 for (i = 0; i < row_width; i++)
1782 {
1783 save = *(--sp);
1784 *(--dp) = *(--sp);
1785 *(--dp) = *(--sp);
1786 *(--dp) = *(--sp);
1787 *(--dp) = save;
1788 }
1789 }
1790 /* This converts from RRGGBBAA to AARRGGBB */
1791 else
1792 {
1793 png_bytep sp = row + row_info->rowbytes;
1794 png_bytep dp = sp;
1795 png_byte save[2];
1796 png_uint_32 i;
1797
1798 for (i = 0; i < row_width; i++)
1799 {
1800 save[0] = *(--sp);
1801 save[1] = *(--sp);
1802 *(--dp) = *(--sp);
1803 *(--dp) = *(--sp);
1804 *(--dp) = *(--sp);
1805 *(--dp) = *(--sp);
1806 *(--dp) = *(--sp);
1807 *(--dp) = *(--sp);
1808 *(--dp) = save[0];
1809 *(--dp) = save[1];
1810 }
1811 }
1812 }
1813 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1814 {
1815 /* This converts from GA to AG */
1816 if (row_info->bit_depth == 8)
1817 {
1818 png_bytep sp = row + row_info->rowbytes;
1819 png_bytep dp = sp;
1820 png_byte save;
1821 png_uint_32 i;
1822
1823 for (i = 0; i < row_width; i++)
1824 {
1825 save = *(--sp);
1826 *(--dp) = *(--sp);
1827 *(--dp) = save;
1828 }
1829 }
1830 /* This converts from GGAA to AAGG */
1831 else
1832 {
1833 png_bytep sp = row + row_info->rowbytes;
1834 png_bytep dp = sp;
1835 png_byte save[2];
1836 png_uint_32 i;
1837
1838 for (i = 0; i < row_width; i++)
1839 {
1840 save[0] = *(--sp);
1841 save[1] = *(--sp);
1842 *(--dp) = *(--sp);
1843 *(--dp) = *(--sp);
1844 *(--dp) = save[0];
1845 *(--dp) = save[1];
1846 }
1847 }
1848 }
1849 }
1850}
1851#endif
1852
1853#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
1854void /* PRIVATE */
1855png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
1856{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001857 png_debug(1, "in png_do_read_invert_alpha");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001858#if defined(PNG_USELESS_TESTS_SUPPORTED)
1859 if (row != NULL && row_info != NULL)
1860#endif
1861 {
1862 png_uint_32 row_width = row_info->width;
1863 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1864 {
1865 /* This inverts the alpha channel in RGBA */
1866 if (row_info->bit_depth == 8)
1867 {
1868 png_bytep sp = row + row_info->rowbytes;
1869 png_bytep dp = sp;
1870 png_uint_32 i;
1871
1872 for (i = 0; i < row_width; i++)
1873 {
1874 *(--dp) = (png_byte)(255 - *(--sp));
1875
1876/* This does nothing:
1877 *(--dp) = *(--sp);
1878 *(--dp) = *(--sp);
1879 *(--dp) = *(--sp);
1880 We can replace it with:
1881*/
1882 sp-=3;
1883 dp=sp;
1884 }
1885 }
1886 /* This inverts the alpha channel in RRGGBBAA */
1887 else
1888 {
1889 png_bytep sp = row + row_info->rowbytes;
1890 png_bytep dp = sp;
1891 png_uint_32 i;
1892
1893 for (i = 0; i < row_width; i++)
1894 {
1895 *(--dp) = (png_byte)(255 - *(--sp));
1896 *(--dp) = (png_byte)(255 - *(--sp));
1897
1898/* This does nothing:
1899 *(--dp) = *(--sp);
1900 *(--dp) = *(--sp);
1901 *(--dp) = *(--sp);
1902 *(--dp) = *(--sp);
1903 *(--dp) = *(--sp);
1904 *(--dp) = *(--sp);
1905 We can replace it with:
1906*/
1907 sp-=6;
1908 dp=sp;
1909 }
1910 }
1911 }
1912 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1913 {
1914 /* This inverts the alpha channel in GA */
1915 if (row_info->bit_depth == 8)
1916 {
1917 png_bytep sp = row + row_info->rowbytes;
1918 png_bytep dp = sp;
1919 png_uint_32 i;
1920
1921 for (i = 0; i < row_width; i++)
1922 {
1923 *(--dp) = (png_byte)(255 - *(--sp));
1924 *(--dp) = *(--sp);
1925 }
1926 }
1927 /* This inverts the alpha channel in GGAA */
1928 else
1929 {
1930 png_bytep sp = row + row_info->rowbytes;
1931 png_bytep dp = sp;
1932 png_uint_32 i;
1933
1934 for (i = 0; i < row_width; i++)
1935 {
1936 *(--dp) = (png_byte)(255 - *(--sp));
1937 *(--dp) = (png_byte)(255 - *(--sp));
1938/*
1939 *(--dp) = *(--sp);
1940 *(--dp) = *(--sp);
1941*/
1942 sp-=2;
1943 dp=sp;
1944 }
1945 }
1946 }
1947 }
1948}
1949#endif
1950
1951#if defined(PNG_READ_FILLER_SUPPORTED)
1952/* Add filler channel if we have RGB color */
1953void /* PRIVATE */
1954png_do_read_filler(png_row_infop row_info, png_bytep row,
1955 png_uint_32 filler, png_uint_32 flags)
1956{
1957 png_uint_32 i;
1958 png_uint_32 row_width = row_info->width;
1959
1960 png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
1961 png_byte lo_filler = (png_byte)(filler & 0xff);
1962
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001963 png_debug(1, "in png_do_read_filler");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001964 if (
1965#if defined(PNG_USELESS_TESTS_SUPPORTED)
1966 row != NULL && row_info != NULL &&
1967#endif
1968 row_info->color_type == PNG_COLOR_TYPE_GRAY)
1969 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001970 if (row_info->bit_depth == 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001971 {
1972 /* This changes the data from G to GX */
1973 if (flags & PNG_FLAG_FILLER_AFTER)
1974 {
1975 png_bytep sp = row + (png_size_t)row_width;
1976 png_bytep dp = sp + (png_size_t)row_width;
1977 for (i = 1; i < row_width; i++)
1978 {
1979 *(--dp) = lo_filler;
1980 *(--dp) = *(--sp);
1981 }
1982 *(--dp) = lo_filler;
1983 row_info->channels = 2;
1984 row_info->pixel_depth = 16;
1985 row_info->rowbytes = row_width * 2;
1986 }
1987 /* This changes the data from G to XG */
1988 else
1989 {
1990 png_bytep sp = row + (png_size_t)row_width;
1991 png_bytep dp = sp + (png_size_t)row_width;
1992 for (i = 0; i < row_width; i++)
1993 {
1994 *(--dp) = *(--sp);
1995 *(--dp) = lo_filler;
1996 }
1997 row_info->channels = 2;
1998 row_info->pixel_depth = 16;
1999 row_info->rowbytes = row_width * 2;
2000 }
2001 }
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002002 else if (row_info->bit_depth == 16)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002003 {
2004 /* This changes the data from GG to GGXX */
2005 if (flags & PNG_FLAG_FILLER_AFTER)
2006 {
2007 png_bytep sp = row + (png_size_t)row_width * 2;
2008 png_bytep dp = sp + (png_size_t)row_width * 2;
2009 for (i = 1; i < row_width; i++)
2010 {
2011 *(--dp) = hi_filler;
2012 *(--dp) = lo_filler;
2013 *(--dp) = *(--sp);
2014 *(--dp) = *(--sp);
2015 }
2016 *(--dp) = hi_filler;
2017 *(--dp) = lo_filler;
2018 row_info->channels = 2;
2019 row_info->pixel_depth = 32;
2020 row_info->rowbytes = row_width * 4;
2021 }
2022 /* This changes the data from GG to XXGG */
2023 else
2024 {
2025 png_bytep sp = row + (png_size_t)row_width * 2;
2026 png_bytep dp = sp + (png_size_t)row_width * 2;
2027 for (i = 0; i < row_width; i++)
2028 {
2029 *(--dp) = *(--sp);
2030 *(--dp) = *(--sp);
2031 *(--dp) = hi_filler;
2032 *(--dp) = lo_filler;
2033 }
2034 row_info->channels = 2;
2035 row_info->pixel_depth = 32;
2036 row_info->rowbytes = row_width * 4;
2037 }
2038 }
2039 } /* COLOR_TYPE == GRAY */
2040 else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2041 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002042 if (row_info->bit_depth == 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002043 {
2044 /* This changes the data from RGB to RGBX */
2045 if (flags & PNG_FLAG_FILLER_AFTER)
2046 {
2047 png_bytep sp = row + (png_size_t)row_width * 3;
2048 png_bytep dp = sp + (png_size_t)row_width;
2049 for (i = 1; i < row_width; i++)
2050 {
2051 *(--dp) = lo_filler;
2052 *(--dp) = *(--sp);
2053 *(--dp) = *(--sp);
2054 *(--dp) = *(--sp);
2055 }
2056 *(--dp) = lo_filler;
2057 row_info->channels = 4;
2058 row_info->pixel_depth = 32;
2059 row_info->rowbytes = row_width * 4;
2060 }
2061 /* This changes the data from RGB to XRGB */
2062 else
2063 {
2064 png_bytep sp = row + (png_size_t)row_width * 3;
2065 png_bytep dp = sp + (png_size_t)row_width;
2066 for (i = 0; i < row_width; i++)
2067 {
2068 *(--dp) = *(--sp);
2069 *(--dp) = *(--sp);
2070 *(--dp) = *(--sp);
2071 *(--dp) = lo_filler;
2072 }
2073 row_info->channels = 4;
2074 row_info->pixel_depth = 32;
2075 row_info->rowbytes = row_width * 4;
2076 }
2077 }
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002078 else if (row_info->bit_depth == 16)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002079 {
2080 /* This changes the data from RRGGBB to RRGGBBXX */
2081 if (flags & PNG_FLAG_FILLER_AFTER)
2082 {
2083 png_bytep sp = row + (png_size_t)row_width * 6;
2084 png_bytep dp = sp + (png_size_t)row_width * 2;
2085 for (i = 1; i < row_width; i++)
2086 {
2087 *(--dp) = hi_filler;
2088 *(--dp) = lo_filler;
2089 *(--dp) = *(--sp);
2090 *(--dp) = *(--sp);
2091 *(--dp) = *(--sp);
2092 *(--dp) = *(--sp);
2093 *(--dp) = *(--sp);
2094 *(--dp) = *(--sp);
2095 }
2096 *(--dp) = hi_filler;
2097 *(--dp) = lo_filler;
2098 row_info->channels = 4;
2099 row_info->pixel_depth = 64;
2100 row_info->rowbytes = row_width * 8;
2101 }
2102 /* This changes the data from RRGGBB to XXRRGGBB */
2103 else
2104 {
2105 png_bytep sp = row + (png_size_t)row_width * 6;
2106 png_bytep dp = sp + (png_size_t)row_width * 2;
2107 for (i = 0; i < row_width; i++)
2108 {
2109 *(--dp) = *(--sp);
2110 *(--dp) = *(--sp);
2111 *(--dp) = *(--sp);
2112 *(--dp) = *(--sp);
2113 *(--dp) = *(--sp);
2114 *(--dp) = *(--sp);
2115 *(--dp) = hi_filler;
2116 *(--dp) = lo_filler;
2117 }
2118 row_info->channels = 4;
2119 row_info->pixel_depth = 64;
2120 row_info->rowbytes = row_width * 8;
2121 }
2122 }
2123 } /* COLOR_TYPE == RGB */
2124}
2125#endif
2126
2127#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
2128/* expand grayscale files to RGB, with or without alpha */
2129void /* PRIVATE */
2130png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
2131{
2132 png_uint_32 i;
2133 png_uint_32 row_width = row_info->width;
2134
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002135 png_debug(1, "in png_do_gray_to_rgb");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002136 if (row_info->bit_depth >= 8 &&
2137#if defined(PNG_USELESS_TESTS_SUPPORTED)
2138 row != NULL && row_info != NULL &&
2139#endif
2140 !(row_info->color_type & PNG_COLOR_MASK_COLOR))
2141 {
2142 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
2143 {
2144 if (row_info->bit_depth == 8)
2145 {
2146 png_bytep sp = row + (png_size_t)row_width - 1;
2147 png_bytep dp = sp + (png_size_t)row_width * 2;
2148 for (i = 0; i < row_width; i++)
2149 {
2150 *(dp--) = *sp;
2151 *(dp--) = *sp;
2152 *(dp--) = *(sp--);
2153 }
2154 }
2155 else
2156 {
2157 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2158 png_bytep dp = sp + (png_size_t)row_width * 4;
2159 for (i = 0; i < row_width; i++)
2160 {
2161 *(dp--) = *sp;
2162 *(dp--) = *(sp - 1);
2163 *(dp--) = *sp;
2164 *(dp--) = *(sp - 1);
2165 *(dp--) = *(sp--);
2166 *(dp--) = *(sp--);
2167 }
2168 }
2169 }
2170 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2171 {
2172 if (row_info->bit_depth == 8)
2173 {
2174 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2175 png_bytep dp = sp + (png_size_t)row_width * 2;
2176 for (i = 0; i < row_width; i++)
2177 {
2178 *(dp--) = *(sp--);
2179 *(dp--) = *sp;
2180 *(dp--) = *sp;
2181 *(dp--) = *(sp--);
2182 }
2183 }
2184 else
2185 {
2186 png_bytep sp = row + (png_size_t)row_width * 4 - 1;
2187 png_bytep dp = sp + (png_size_t)row_width * 4;
2188 for (i = 0; i < row_width; i++)
2189 {
2190 *(dp--) = *(sp--);
2191 *(dp--) = *(sp--);
2192 *(dp--) = *sp;
2193 *(dp--) = *(sp - 1);
2194 *(dp--) = *sp;
2195 *(dp--) = *(sp - 1);
2196 *(dp--) = *(sp--);
2197 *(dp--) = *(sp--);
2198 }
2199 }
2200 }
2201 row_info->channels += (png_byte)2;
2202 row_info->color_type |= PNG_COLOR_MASK_COLOR;
2203 row_info->pixel_depth = (png_byte)(row_info->channels *
2204 row_info->bit_depth);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002205 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002206 }
2207}
2208#endif
2209
2210#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
2211/* reduce RGB files to grayscale, with or without alpha
2212 * using the equation given in Poynton's ColorFAQ at
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002213 * <http://www.inforamp.net/~poynton/> (THIS LINK IS DEAD June 2008)
2214 * New link:
2215 * <http://www.poynton.com/notes/colour_and_gamma/>
2216 * Charles Poynton poynton at poynton.com
The Android Open Source Project893912b2009-03-03 19:30:05 -08002217 *
2218 * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
2219 *
2220 * We approximate this with
2221 *
2222 * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
2223 *
2224 * which can be expressed with integers as
2225 *
2226 * Y = (6969 * R + 23434 * G + 2365 * B)/32768
2227 *
2228 * The calculation is to be done in a linear colorspace.
2229 *
2230 * Other integer coefficents can be used via png_set_rgb_to_gray().
2231 */
2232int /* PRIVATE */
2233png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
2234
2235{
2236 png_uint_32 i;
2237
2238 png_uint_32 row_width = row_info->width;
2239 int rgb_error = 0;
2240
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002241 png_debug(1, "in png_do_rgb_to_gray");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002242 if (
2243#if defined(PNG_USELESS_TESTS_SUPPORTED)
2244 row != NULL && row_info != NULL &&
2245#endif
2246 (row_info->color_type & PNG_COLOR_MASK_COLOR))
2247 {
2248 png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
2249 png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
2250 png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
2251
2252 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2253 {
2254 if (row_info->bit_depth == 8)
2255 {
2256#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2257 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2258 {
2259 png_bytep sp = row;
2260 png_bytep dp = row;
2261
2262 for (i = 0; i < row_width; i++)
2263 {
2264 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2265 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2266 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002267 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002268 {
2269 rgb_error |= 1;
2270 *(dp++) = png_ptr->gamma_from_1[
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002271 (rc*red + gc*green + bc*blue)>>15];
The Android Open Source Project893912b2009-03-03 19:30:05 -08002272 }
2273 else
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002274 *(dp++) = *(sp - 1);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002275 }
2276 }
2277 else
2278#endif
2279 {
2280 png_bytep sp = row;
2281 png_bytep dp = row;
2282 for (i = 0; i < row_width; i++)
2283 {
2284 png_byte red = *(sp++);
2285 png_byte green = *(sp++);
2286 png_byte blue = *(sp++);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002287 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002288 {
2289 rgb_error |= 1;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002290 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002291 }
2292 else
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002293 *(dp++) = *(sp - 1);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002294 }
2295 }
2296 }
2297
2298 else /* RGB bit_depth == 16 */
2299 {
2300#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2301 if (png_ptr->gamma_16_to_1 != NULL &&
2302 png_ptr->gamma_16_from_1 != NULL)
2303 {
2304 png_bytep sp = row;
2305 png_bytep dp = row;
2306 for (i = 0; i < row_width; i++)
2307 {
2308 png_uint_16 red, green, blue, w;
2309
2310 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2311 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2312 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2313
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002314 if (red == green && red == blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002315 w = red;
2316 else
2317 {
2318 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2319 png_ptr->gamma_shift][red>>8];
2320 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2321 png_ptr->gamma_shift][green>>8];
2322 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
2323 png_ptr->gamma_shift][blue>>8];
2324 png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
2325 + bc*blue_1)>>15);
2326 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2327 png_ptr->gamma_shift][gray16 >> 8];
2328 rgb_error |= 1;
2329 }
2330
2331 *(dp++) = (png_byte)((w>>8) & 0xff);
2332 *(dp++) = (png_byte)(w & 0xff);
2333 }
2334 }
2335 else
2336#endif
2337 {
2338 png_bytep sp = row;
2339 png_bytep dp = row;
2340 for (i = 0; i < row_width; i++)
2341 {
2342 png_uint_16 red, green, blue, gray16;
2343
2344 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2345 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2346 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2347
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002348 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002349 rgb_error |= 1;
2350 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
2351 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2352 *(dp++) = (png_byte)(gray16 & 0xff);
2353 }
2354 }
2355 }
2356 }
2357 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2358 {
2359 if (row_info->bit_depth == 8)
2360 {
2361#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2362 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2363 {
2364 png_bytep sp = row;
2365 png_bytep dp = row;
2366 for (i = 0; i < row_width; i++)
2367 {
2368 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2369 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2370 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002371 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002372 rgb_error |= 1;
2373 *(dp++) = png_ptr->gamma_from_1
2374 [(rc*red + gc*green + bc*blue)>>15];
2375 *(dp++) = *(sp++); /* alpha */
2376 }
2377 }
2378 else
2379#endif
2380 {
2381 png_bytep sp = row;
2382 png_bytep dp = row;
2383 for (i = 0; i < row_width; i++)
2384 {
2385 png_byte red = *(sp++);
2386 png_byte green = *(sp++);
2387 png_byte blue = *(sp++);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002388 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002389 rgb_error |= 1;
2390 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
2391 *(dp++) = *(sp++); /* alpha */
2392 }
2393 }
2394 }
2395 else /* RGBA bit_depth == 16 */
2396 {
2397#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2398 if (png_ptr->gamma_16_to_1 != NULL &&
2399 png_ptr->gamma_16_from_1 != NULL)
2400 {
2401 png_bytep sp = row;
2402 png_bytep dp = row;
2403 for (i = 0; i < row_width; i++)
2404 {
2405 png_uint_16 red, green, blue, w;
2406
2407 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2408 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2409 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2410
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002411 if (red == green && red == blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002412 w = red;
2413 else
2414 {
2415 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2416 png_ptr->gamma_shift][red>>8];
2417 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2418 png_ptr->gamma_shift][green>>8];
2419 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
2420 png_ptr->gamma_shift][blue>>8];
2421 png_uint_16 gray16 = (png_uint_16)((rc * red_1
2422 + gc * green_1 + bc * blue_1)>>15);
2423 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2424 png_ptr->gamma_shift][gray16 >> 8];
2425 rgb_error |= 1;
2426 }
2427
2428 *(dp++) = (png_byte)((w>>8) & 0xff);
2429 *(dp++) = (png_byte)(w & 0xff);
2430 *(dp++) = *(sp++); /* alpha */
2431 *(dp++) = *(sp++);
2432 }
2433 }
2434 else
2435#endif
2436 {
2437 png_bytep sp = row;
2438 png_bytep dp = row;
2439 for (i = 0; i < row_width; i++)
2440 {
2441 png_uint_16 red, green, blue, gray16;
2442 red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2443 green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2444 blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002445 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002446 rgb_error |= 1;
2447 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
2448 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2449 *(dp++) = (png_byte)(gray16 & 0xff);
2450 *(dp++) = *(sp++); /* alpha */
2451 *(dp++) = *(sp++);
2452 }
2453 }
2454 }
2455 }
2456 row_info->channels -= (png_byte)2;
2457 row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
2458 row_info->pixel_depth = (png_byte)(row_info->channels *
2459 row_info->bit_depth);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002460 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002461 }
2462 return rgb_error;
2463}
2464#endif
2465
2466/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
2467 * large of png_color. This lets grayscale images be treated as
2468 * paletted. Most useful for gamma correction and simplification
2469 * of code.
2470 */
2471void PNGAPI
2472png_build_grayscale_palette(int bit_depth, png_colorp palette)
2473{
2474 int num_palette;
2475 int color_inc;
2476 int i;
2477 int v;
2478
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002479 png_debug(1, "in png_do_build_grayscale_palette");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002480 if (palette == NULL)
2481 return;
2482
2483 switch (bit_depth)
2484 {
2485 case 1:
2486 num_palette = 2;
2487 color_inc = 0xff;
2488 break;
2489 case 2:
2490 num_palette = 4;
2491 color_inc = 0x55;
2492 break;
2493 case 4:
2494 num_palette = 16;
2495 color_inc = 0x11;
2496 break;
2497 case 8:
2498 num_palette = 256;
2499 color_inc = 1;
2500 break;
2501 default:
2502 num_palette = 0;
2503 color_inc = 0;
2504 break;
2505 }
2506
2507 for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
2508 {
2509 palette[i].red = (png_byte)v;
2510 palette[i].green = (png_byte)v;
2511 palette[i].blue = (png_byte)v;
2512 }
2513}
2514
2515/* This function is currently unused. Do we really need it? */
2516#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED)
2517void /* PRIVATE */
2518png_correct_palette(png_structp png_ptr, png_colorp palette,
2519 int num_palette)
2520{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002521 png_debug(1, "in png_correct_palette");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002522#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
2523 defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
2524 if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND))
2525 {
2526 png_color back, back_1;
2527
2528 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
2529 {
2530 back.red = png_ptr->gamma_table[png_ptr->background.red];
2531 back.green = png_ptr->gamma_table[png_ptr->background.green];
2532 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
2533
2534 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
2535 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
2536 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
2537 }
2538 else
2539 {
2540 double g;
2541
2542 g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma);
2543
2544 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
2545 fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
2546 {
2547 back.red = png_ptr->background.red;
2548 back.green = png_ptr->background.green;
2549 back.blue = png_ptr->background.blue;
2550 }
2551 else
2552 {
2553 back.red =
2554 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2555 255.0 + 0.5);
2556 back.green =
2557 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2558 255.0 + 0.5);
2559 back.blue =
2560 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2561 255.0 + 0.5);
2562 }
2563
2564 g = 1.0 / png_ptr->background_gamma;
2565
2566 back_1.red =
2567 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2568 255.0 + 0.5);
2569 back_1.green =
2570 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2571 255.0 + 0.5);
2572 back_1.blue =
2573 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2574 255.0 + 0.5);
2575 }
2576
2577 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2578 {
2579 png_uint_32 i;
2580
2581 for (i = 0; i < (png_uint_32)num_palette; i++)
2582 {
2583 if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
2584 {
2585 palette[i] = back;
2586 }
2587 else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
2588 {
2589 png_byte v, w;
2590
2591 v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
2592 png_composite(w, v, png_ptr->trans[i], back_1.red);
2593 palette[i].red = png_ptr->gamma_from_1[w];
2594
2595 v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
2596 png_composite(w, v, png_ptr->trans[i], back_1.green);
2597 palette[i].green = png_ptr->gamma_from_1[w];
2598
2599 v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
2600 png_composite(w, v, png_ptr->trans[i], back_1.blue);
2601 palette[i].blue = png_ptr->gamma_from_1[w];
2602 }
2603 else
2604 {
2605 palette[i].red = png_ptr->gamma_table[palette[i].red];
2606 palette[i].green = png_ptr->gamma_table[palette[i].green];
2607 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2608 }
2609 }
2610 }
2611 else
2612 {
2613 int i;
2614
2615 for (i = 0; i < num_palette; i++)
2616 {
2617 if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
2618 {
2619 palette[i] = back;
2620 }
2621 else
2622 {
2623 palette[i].red = png_ptr->gamma_table[palette[i].red];
2624 palette[i].green = png_ptr->gamma_table[palette[i].green];
2625 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2626 }
2627 }
2628 }
2629 }
2630 else
2631#endif
2632#if defined(PNG_READ_GAMMA_SUPPORTED)
2633 if (png_ptr->transformations & PNG_GAMMA)
2634 {
2635 int i;
2636
2637 for (i = 0; i < num_palette; i++)
2638 {
2639 palette[i].red = png_ptr->gamma_table[palette[i].red];
2640 palette[i].green = png_ptr->gamma_table[palette[i].green];
2641 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2642 }
2643 }
2644#if defined(PNG_READ_BACKGROUND_SUPPORTED)
2645 else
2646#endif
2647#endif
2648#if defined(PNG_READ_BACKGROUND_SUPPORTED)
2649 if (png_ptr->transformations & PNG_BACKGROUND)
2650 {
2651 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2652 {
2653 png_color back;
2654
2655 back.red = (png_byte)png_ptr->background.red;
2656 back.green = (png_byte)png_ptr->background.green;
2657 back.blue = (png_byte)png_ptr->background.blue;
2658
2659 for (i = 0; i < (int)png_ptr->num_trans; i++)
2660 {
2661 if (png_ptr->trans[i] == 0)
2662 {
2663 palette[i].red = back.red;
2664 palette[i].green = back.green;
2665 palette[i].blue = back.blue;
2666 }
2667 else if (png_ptr->trans[i] != 0xff)
2668 {
2669 png_composite(palette[i].red, png_ptr->palette[i].red,
2670 png_ptr->trans[i], back.red);
2671 png_composite(palette[i].green, png_ptr->palette[i].green,
2672 png_ptr->trans[i], back.green);
2673 png_composite(palette[i].blue, png_ptr->palette[i].blue,
2674 png_ptr->trans[i], back.blue);
2675 }
2676 }
2677 }
2678 else /* assume grayscale palette (what else could it be?) */
2679 {
2680 int i;
2681
2682 for (i = 0; i < num_palette; i++)
2683 {
2684 if (i == (png_byte)png_ptr->trans_values.gray)
2685 {
2686 palette[i].red = (png_byte)png_ptr->background.red;
2687 palette[i].green = (png_byte)png_ptr->background.green;
2688 palette[i].blue = (png_byte)png_ptr->background.blue;
2689 }
2690 }
2691 }
2692 }
2693#endif
2694}
2695#endif
2696
2697#if defined(PNG_READ_BACKGROUND_SUPPORTED)
2698/* Replace any alpha or transparency with the supplied background color.
2699 * "background" is already in the screen gamma, while "background_1" is
2700 * at a gamma of 1.0. Paletted files have already been taken care of.
2701 */
2702void /* PRIVATE */
2703png_do_background(png_row_infop row_info, png_bytep row,
2704 png_color_16p trans_values, png_color_16p background
2705#if defined(PNG_READ_GAMMA_SUPPORTED)
2706 , png_color_16p background_1,
2707 png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
2708 png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
2709 png_uint_16pp gamma_16_to_1, int gamma_shift
2710#endif
2711 )
2712{
2713 png_bytep sp, dp;
2714 png_uint_32 i;
2715 png_uint_32 row_width=row_info->width;
2716 int shift;
2717
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002718 png_debug(1, "in png_do_background");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002719 if (background != NULL &&
2720#if defined(PNG_USELESS_TESTS_SUPPORTED)
2721 row != NULL && row_info != NULL &&
2722#endif
2723 (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
2724 (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
2725 {
2726 switch (row_info->color_type)
2727 {
2728 case PNG_COLOR_TYPE_GRAY:
2729 {
2730 switch (row_info->bit_depth)
2731 {
2732 case 1:
2733 {
2734 sp = row;
2735 shift = 7;
2736 for (i = 0; i < row_width; i++)
2737 {
2738 if ((png_uint_16)((*sp >> shift) & 0x01)
2739 == trans_values->gray)
2740 {
2741 *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2742 *sp |= (png_byte)(background->gray << shift);
2743 }
2744 if (!shift)
2745 {
2746 shift = 7;
2747 sp++;
2748 }
2749 else
2750 shift--;
2751 }
2752 break;
2753 }
2754 case 2:
2755 {
2756#if defined(PNG_READ_GAMMA_SUPPORTED)
2757 if (gamma_table != NULL)
2758 {
2759 sp = row;
2760 shift = 6;
2761 for (i = 0; i < row_width; i++)
2762 {
2763 if ((png_uint_16)((*sp >> shift) & 0x03)
2764 == trans_values->gray)
2765 {
2766 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2767 *sp |= (png_byte)(background->gray << shift);
2768 }
2769 else
2770 {
2771 png_byte p = (png_byte)((*sp >> shift) & 0x03);
2772 png_byte g = (png_byte)((gamma_table [p | (p << 2) |
2773 (p << 4) | (p << 6)] >> 6) & 0x03);
2774 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2775 *sp |= (png_byte)(g << shift);
2776 }
2777 if (!shift)
2778 {
2779 shift = 6;
2780 sp++;
2781 }
2782 else
2783 shift -= 2;
2784 }
2785 }
2786 else
2787#endif
2788 {
2789 sp = row;
2790 shift = 6;
2791 for (i = 0; i < row_width; i++)
2792 {
2793 if ((png_uint_16)((*sp >> shift) & 0x03)
2794 == trans_values->gray)
2795 {
2796 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2797 *sp |= (png_byte)(background->gray << shift);
2798 }
2799 if (!shift)
2800 {
2801 shift = 6;
2802 sp++;
2803 }
2804 else
2805 shift -= 2;
2806 }
2807 }
2808 break;
2809 }
2810 case 4:
2811 {
2812#if defined(PNG_READ_GAMMA_SUPPORTED)
2813 if (gamma_table != NULL)
2814 {
2815 sp = row;
2816 shift = 4;
2817 for (i = 0; i < row_width; i++)
2818 {
2819 if ((png_uint_16)((*sp >> shift) & 0x0f)
2820 == trans_values->gray)
2821 {
2822 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2823 *sp |= (png_byte)(background->gray << shift);
2824 }
2825 else
2826 {
2827 png_byte p = (png_byte)((*sp >> shift) & 0x0f);
2828 png_byte g = (png_byte)((gamma_table[p |
2829 (p << 4)] >> 4) & 0x0f);
2830 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2831 *sp |= (png_byte)(g << shift);
2832 }
2833 if (!shift)
2834 {
2835 shift = 4;
2836 sp++;
2837 }
2838 else
2839 shift -= 4;
2840 }
2841 }
2842 else
2843#endif
2844 {
2845 sp = row;
2846 shift = 4;
2847 for (i = 0; i < row_width; i++)
2848 {
2849 if ((png_uint_16)((*sp >> shift) & 0x0f)
2850 == trans_values->gray)
2851 {
2852 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2853 *sp |= (png_byte)(background->gray << shift);
2854 }
2855 if (!shift)
2856 {
2857 shift = 4;
2858 sp++;
2859 }
2860 else
2861 shift -= 4;
2862 }
2863 }
2864 break;
2865 }
2866 case 8:
2867 {
2868#if defined(PNG_READ_GAMMA_SUPPORTED)
2869 if (gamma_table != NULL)
2870 {
2871 sp = row;
2872 for (i = 0; i < row_width; i++, sp++)
2873 {
2874 if (*sp == trans_values->gray)
2875 {
2876 *sp = (png_byte)background->gray;
2877 }
2878 else
2879 {
2880 *sp = gamma_table[*sp];
2881 }
2882 }
2883 }
2884 else
2885#endif
2886 {
2887 sp = row;
2888 for (i = 0; i < row_width; i++, sp++)
2889 {
2890 if (*sp == trans_values->gray)
2891 {
2892 *sp = (png_byte)background->gray;
2893 }
2894 }
2895 }
2896 break;
2897 }
2898 case 16:
2899 {
2900#if defined(PNG_READ_GAMMA_SUPPORTED)
2901 if (gamma_16 != NULL)
2902 {
2903 sp = row;
2904 for (i = 0; i < row_width; i++, sp += 2)
2905 {
2906 png_uint_16 v;
2907
2908 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2909 if (v == trans_values->gray)
2910 {
2911 /* background is already in screen gamma */
2912 *sp = (png_byte)((background->gray >> 8) & 0xff);
2913 *(sp + 1) = (png_byte)(background->gray & 0xff);
2914 }
2915 else
2916 {
2917 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
2918 *sp = (png_byte)((v >> 8) & 0xff);
2919 *(sp + 1) = (png_byte)(v & 0xff);
2920 }
2921 }
2922 }
2923 else
2924#endif
2925 {
2926 sp = row;
2927 for (i = 0; i < row_width; i++, sp += 2)
2928 {
2929 png_uint_16 v;
2930
2931 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2932 if (v == trans_values->gray)
2933 {
2934 *sp = (png_byte)((background->gray >> 8) & 0xff);
2935 *(sp + 1) = (png_byte)(background->gray & 0xff);
2936 }
2937 }
2938 }
2939 break;
2940 }
2941 }
2942 break;
2943 }
2944 case PNG_COLOR_TYPE_RGB:
2945 {
2946 if (row_info->bit_depth == 8)
2947 {
2948#if defined(PNG_READ_GAMMA_SUPPORTED)
2949 if (gamma_table != NULL)
2950 {
2951 sp = row;
2952 for (i = 0; i < row_width; i++, sp += 3)
2953 {
2954 if (*sp == trans_values->red &&
2955 *(sp + 1) == trans_values->green &&
2956 *(sp + 2) == trans_values->blue)
2957 {
2958 *sp = (png_byte)background->red;
2959 *(sp + 1) = (png_byte)background->green;
2960 *(sp + 2) = (png_byte)background->blue;
2961 }
2962 else
2963 {
2964 *sp = gamma_table[*sp];
2965 *(sp + 1) = gamma_table[*(sp + 1)];
2966 *(sp + 2) = gamma_table[*(sp + 2)];
2967 }
2968 }
2969 }
2970 else
2971#endif
2972 {
2973 sp = row;
2974 for (i = 0; i < row_width; i++, sp += 3)
2975 {
2976 if (*sp == trans_values->red &&
2977 *(sp + 1) == trans_values->green &&
2978 *(sp + 2) == trans_values->blue)
2979 {
2980 *sp = (png_byte)background->red;
2981 *(sp + 1) = (png_byte)background->green;
2982 *(sp + 2) = (png_byte)background->blue;
2983 }
2984 }
2985 }
2986 }
2987 else /* if (row_info->bit_depth == 16) */
2988 {
2989#if defined(PNG_READ_GAMMA_SUPPORTED)
2990 if (gamma_16 != NULL)
2991 {
2992 sp = row;
2993 for (i = 0; i < row_width; i++, sp += 6)
2994 {
2995 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2996 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2997 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
2998 if (r == trans_values->red && g == trans_values->green &&
2999 b == trans_values->blue)
3000 {
3001 /* background is already in screen gamma */
3002 *sp = (png_byte)((background->red >> 8) & 0xff);
3003 *(sp + 1) = (png_byte)(background->red & 0xff);
3004 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
3005 *(sp + 3) = (png_byte)(background->green & 0xff);
3006 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3007 *(sp + 5) = (png_byte)(background->blue & 0xff);
3008 }
3009 else
3010 {
3011 png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3012 *sp = (png_byte)((v >> 8) & 0xff);
3013 *(sp + 1) = (png_byte)(v & 0xff);
3014 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
3015 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
3016 *(sp + 3) = (png_byte)(v & 0xff);
3017 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
3018 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
3019 *(sp + 5) = (png_byte)(v & 0xff);
3020 }
3021 }
3022 }
3023 else
3024#endif
3025 {
3026 sp = row;
3027 for (i = 0; i < row_width; i++, sp += 6)
3028 {
3029 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
3030 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
3031 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
3032
3033 if (r == trans_values->red && g == trans_values->green &&
3034 b == trans_values->blue)
3035 {
3036 *sp = (png_byte)((background->red >> 8) & 0xff);
3037 *(sp + 1) = (png_byte)(background->red & 0xff);
3038 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
3039 *(sp + 3) = (png_byte)(background->green & 0xff);
3040 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3041 *(sp + 5) = (png_byte)(background->blue & 0xff);
3042 }
3043 }
3044 }
3045 }
3046 break;
3047 }
3048 case PNG_COLOR_TYPE_GRAY_ALPHA:
3049 {
3050 if (row_info->bit_depth == 8)
3051 {
3052#if defined(PNG_READ_GAMMA_SUPPORTED)
3053 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3054 gamma_table != NULL)
3055 {
3056 sp = row;
3057 dp = row;
3058 for (i = 0; i < row_width; i++, sp += 2, dp++)
3059 {
3060 png_uint_16 a = *(sp + 1);
3061
3062 if (a == 0xff)
3063 {
3064 *dp = gamma_table[*sp];
3065 }
3066 else if (a == 0)
3067 {
3068 /* background is already in screen gamma */
3069 *dp = (png_byte)background->gray;
3070 }
3071 else
3072 {
3073 png_byte v, w;
3074
3075 v = gamma_to_1[*sp];
3076 png_composite(w, v, a, background_1->gray);
3077 *dp = gamma_from_1[w];
3078 }
3079 }
3080 }
3081 else
3082#endif
3083 {
3084 sp = row;
3085 dp = row;
3086 for (i = 0; i < row_width; i++, sp += 2, dp++)
3087 {
3088 png_byte a = *(sp + 1);
3089
3090 if (a == 0xff)
3091 {
3092 *dp = *sp;
3093 }
3094#if defined(PNG_READ_GAMMA_SUPPORTED)
3095 else if (a == 0)
3096 {
3097 *dp = (png_byte)background->gray;
3098 }
3099 else
3100 {
3101 png_composite(*dp, *sp, a, background_1->gray);
3102 }
3103#else
3104 *dp = (png_byte)background->gray;
3105#endif
3106 }
3107 }
3108 }
3109 else /* if (png_ptr->bit_depth == 16) */
3110 {
3111#if defined(PNG_READ_GAMMA_SUPPORTED)
3112 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3113 gamma_16_to_1 != NULL)
3114 {
3115 sp = row;
3116 dp = row;
3117 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
3118 {
3119 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
3120
3121 if (a == (png_uint_16)0xffff)
3122 {
3123 png_uint_16 v;
3124
3125 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3126 *dp = (png_byte)((v >> 8) & 0xff);
3127 *(dp + 1) = (png_byte)(v & 0xff);
3128 }
3129#if defined(PNG_READ_GAMMA_SUPPORTED)
3130 else if (a == 0)
3131#else
3132 else
3133#endif
3134 {
3135 /* background is already in screen gamma */
3136 *dp = (png_byte)((background->gray >> 8) & 0xff);
3137 *(dp + 1) = (png_byte)(background->gray & 0xff);
3138 }
3139#if defined(PNG_READ_GAMMA_SUPPORTED)
3140 else
3141 {
3142 png_uint_16 g, v, w;
3143
3144 g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3145 png_composite_16(v, g, a, background_1->gray);
3146 w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
3147 *dp = (png_byte)((w >> 8) & 0xff);
3148 *(dp + 1) = (png_byte)(w & 0xff);
3149 }
3150#endif
3151 }
3152 }
3153 else
3154#endif
3155 {
3156 sp = row;
3157 dp = row;
3158 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
3159 {
3160 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
3161 if (a == (png_uint_16)0xffff)
3162 {
3163 png_memcpy(dp, sp, 2);
3164 }
3165#if defined(PNG_READ_GAMMA_SUPPORTED)
3166 else if (a == 0)
3167#else
3168 else
3169#endif
3170 {
3171 *dp = (png_byte)((background->gray >> 8) & 0xff);
3172 *(dp + 1) = (png_byte)(background->gray & 0xff);
3173 }
3174#if defined(PNG_READ_GAMMA_SUPPORTED)
3175 else
3176 {
3177 png_uint_16 g, v;
3178
3179 g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3180 png_composite_16(v, g, a, background_1->gray);
3181 *dp = (png_byte)((v >> 8) & 0xff);
3182 *(dp + 1) = (png_byte)(v & 0xff);
3183 }
3184#endif
3185 }
3186 }
3187 }
3188 break;
3189 }
3190 case PNG_COLOR_TYPE_RGB_ALPHA:
3191 {
3192 if (row_info->bit_depth == 8)
3193 {
3194#if defined(PNG_READ_GAMMA_SUPPORTED)
3195 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3196 gamma_table != NULL)
3197 {
3198 sp = row;
3199 dp = row;
3200 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
3201 {
3202 png_byte a = *(sp + 3);
3203
3204 if (a == 0xff)
3205 {
3206 *dp = gamma_table[*sp];
3207 *(dp + 1) = gamma_table[*(sp + 1)];
3208 *(dp + 2) = gamma_table[*(sp + 2)];
3209 }
3210 else if (a == 0)
3211 {
3212 /* background is already in screen gamma */
3213 *dp = (png_byte)background->red;
3214 *(dp + 1) = (png_byte)background->green;
3215 *(dp + 2) = (png_byte)background->blue;
3216 }
3217 else
3218 {
3219 png_byte v, w;
3220
3221 v = gamma_to_1[*sp];
3222 png_composite(w, v, a, background_1->red);
3223 *dp = gamma_from_1[w];
3224 v = gamma_to_1[*(sp + 1)];
3225 png_composite(w, v, a, background_1->green);
3226 *(dp + 1) = gamma_from_1[w];
3227 v = gamma_to_1[*(sp + 2)];
3228 png_composite(w, v, a, background_1->blue);
3229 *(dp + 2) = gamma_from_1[w];
3230 }
3231 }
3232 }
3233 else
3234#endif
3235 {
3236 sp = row;
3237 dp = row;
3238 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
3239 {
3240 png_byte a = *(sp + 3);
3241
3242 if (a == 0xff)
3243 {
3244 *dp = *sp;
3245 *(dp + 1) = *(sp + 1);
3246 *(dp + 2) = *(sp + 2);
3247 }
3248 else if (a == 0)
3249 {
3250 *dp = (png_byte)background->red;
3251 *(dp + 1) = (png_byte)background->green;
3252 *(dp + 2) = (png_byte)background->blue;
3253 }
3254 else
3255 {
3256 png_composite(*dp, *sp, a, background->red);
3257 png_composite(*(dp + 1), *(sp + 1), a,
3258 background->green);
3259 png_composite(*(dp + 2), *(sp + 2), a,
3260 background->blue);
3261 }
3262 }
3263 }
3264 }
3265 else /* if (row_info->bit_depth == 16) */
3266 {
3267#if defined(PNG_READ_GAMMA_SUPPORTED)
3268 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3269 gamma_16_to_1 != NULL)
3270 {
3271 sp = row;
3272 dp = row;
3273 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
3274 {
3275 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3276 << 8) + (png_uint_16)(*(sp + 7)));
3277 if (a == (png_uint_16)0xffff)
3278 {
3279 png_uint_16 v;
3280
3281 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3282 *dp = (png_byte)((v >> 8) & 0xff);
3283 *(dp + 1) = (png_byte)(v & 0xff);
3284 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
3285 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3286 *(dp + 3) = (png_byte)(v & 0xff);
3287 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
3288 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3289 *(dp + 5) = (png_byte)(v & 0xff);
3290 }
3291 else if (a == 0)
3292 {
3293 /* background is already in screen gamma */
3294 *dp = (png_byte)((background->red >> 8) & 0xff);
3295 *(dp + 1) = (png_byte)(background->red & 0xff);
3296 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3297 *(dp + 3) = (png_byte)(background->green & 0xff);
3298 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3299 *(dp + 5) = (png_byte)(background->blue & 0xff);
3300 }
3301 else
3302 {
3303 png_uint_16 v, w, x;
3304
3305 v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3306 png_composite_16(w, v, a, background_1->red);
3307 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3308 *dp = (png_byte)((x >> 8) & 0xff);
3309 *(dp + 1) = (png_byte)(x & 0xff);
3310 v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
3311 png_composite_16(w, v, a, background_1->green);
3312 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3313 *(dp + 2) = (png_byte)((x >> 8) & 0xff);
3314 *(dp + 3) = (png_byte)(x & 0xff);
3315 v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
3316 png_composite_16(w, v, a, background_1->blue);
3317 x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
3318 *(dp + 4) = (png_byte)((x >> 8) & 0xff);
3319 *(dp + 5) = (png_byte)(x & 0xff);
3320 }
3321 }
3322 }
3323 else
3324#endif
3325 {
3326 sp = row;
3327 dp = row;
3328 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
3329 {
3330 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3331 << 8) + (png_uint_16)(*(sp + 7)));
3332 if (a == (png_uint_16)0xffff)
3333 {
3334 png_memcpy(dp, sp, 6);
3335 }
3336 else if (a == 0)
3337 {
3338 *dp = (png_byte)((background->red >> 8) & 0xff);
3339 *(dp + 1) = (png_byte)(background->red & 0xff);
3340 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3341 *(dp + 3) = (png_byte)(background->green & 0xff);
3342 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3343 *(dp + 5) = (png_byte)(background->blue & 0xff);
3344 }
3345 else
3346 {
3347 png_uint_16 v;
3348
3349 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3350 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3351 + *(sp + 3));
3352 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3353 + *(sp + 5));
3354
3355 png_composite_16(v, r, a, background->red);
3356 *dp = (png_byte)((v >> 8) & 0xff);
3357 *(dp + 1) = (png_byte)(v & 0xff);
3358 png_composite_16(v, g, a, background->green);
3359 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3360 *(dp + 3) = (png_byte)(v & 0xff);
3361 png_composite_16(v, b, a, background->blue);
3362 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3363 *(dp + 5) = (png_byte)(v & 0xff);
3364 }
3365 }
3366 }
3367 }
3368 break;
3369 }
3370 }
3371
3372 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
3373 {
3374 row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
3375 row_info->channels--;
3376 row_info->pixel_depth = (png_byte)(row_info->channels *
3377 row_info->bit_depth);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003378 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003379 }
3380 }
3381}
3382#endif
3383
3384#if defined(PNG_READ_GAMMA_SUPPORTED)
3385/* Gamma correct the image, avoiding the alpha channel. Make sure
3386 * you do this after you deal with the transparency issue on grayscale
3387 * or RGB images. If your bit depth is 8, use gamma_table, if it
3388 * is 16, use gamma_16_table and gamma_shift. Build these with
3389 * build_gamma_table().
3390 */
3391void /* PRIVATE */
3392png_do_gamma(png_row_infop row_info, png_bytep row,
3393 png_bytep gamma_table, png_uint_16pp gamma_16_table,
3394 int gamma_shift)
3395{
3396 png_bytep sp;
3397 png_uint_32 i;
3398 png_uint_32 row_width=row_info->width;
3399
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003400 png_debug(1, "in png_do_gamma");
The Android Open Source Project893912b2009-03-03 19:30:05 -08003401 if (
3402#if defined(PNG_USELESS_TESTS_SUPPORTED)
3403 row != NULL && row_info != NULL &&
3404#endif
3405 ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
3406 (row_info->bit_depth == 16 && gamma_16_table != NULL)))
3407 {
3408 switch (row_info->color_type)
3409 {
3410 case PNG_COLOR_TYPE_RGB:
3411 {
3412 if (row_info->bit_depth == 8)
3413 {
3414 sp = row;
3415 for (i = 0; i < row_width; i++)
3416 {
3417 *sp = gamma_table[*sp];
3418 sp++;
3419 *sp = gamma_table[*sp];
3420 sp++;
3421 *sp = gamma_table[*sp];
3422 sp++;
3423 }
3424 }
3425 else /* if (row_info->bit_depth == 16) */
3426 {
3427 sp = row;
3428 for (i = 0; i < row_width; i++)
3429 {
3430 png_uint_16 v;
3431
3432 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3433 *sp = (png_byte)((v >> 8) & 0xff);
3434 *(sp + 1) = (png_byte)(v & 0xff);
3435 sp += 2;
3436 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3437 *sp = (png_byte)((v >> 8) & 0xff);
3438 *(sp + 1) = (png_byte)(v & 0xff);
3439 sp += 2;
3440 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3441 *sp = (png_byte)((v >> 8) & 0xff);
3442 *(sp + 1) = (png_byte)(v & 0xff);
3443 sp += 2;
3444 }
3445 }
3446 break;
3447 }
3448 case PNG_COLOR_TYPE_RGB_ALPHA:
3449 {
3450 if (row_info->bit_depth == 8)
3451 {
3452 sp = row;
3453 for (i = 0; i < row_width; i++)
3454 {
3455 *sp = gamma_table[*sp];
3456 sp++;
3457 *sp = gamma_table[*sp];
3458 sp++;
3459 *sp = gamma_table[*sp];
3460 sp++;
3461 sp++;
3462 }
3463 }
3464 else /* if (row_info->bit_depth == 16) */
3465 {
3466 sp = row;
3467 for (i = 0; i < row_width; i++)
3468 {
3469 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3470 *sp = (png_byte)((v >> 8) & 0xff);
3471 *(sp + 1) = (png_byte)(v & 0xff);
3472 sp += 2;
3473 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3474 *sp = (png_byte)((v >> 8) & 0xff);
3475 *(sp + 1) = (png_byte)(v & 0xff);
3476 sp += 2;
3477 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3478 *sp = (png_byte)((v >> 8) & 0xff);
3479 *(sp + 1) = (png_byte)(v & 0xff);
3480 sp += 4;
3481 }
3482 }
3483 break;
3484 }
3485 case PNG_COLOR_TYPE_GRAY_ALPHA:
3486 {
3487 if (row_info->bit_depth == 8)
3488 {
3489 sp = row;
3490 for (i = 0; i < row_width; i++)
3491 {
3492 *sp = gamma_table[*sp];
3493 sp += 2;
3494 }
3495 }
3496 else /* if (row_info->bit_depth == 16) */
3497 {
3498 sp = row;
3499 for (i = 0; i < row_width; i++)
3500 {
3501 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3502 *sp = (png_byte)((v >> 8) & 0xff);
3503 *(sp + 1) = (png_byte)(v & 0xff);
3504 sp += 4;
3505 }
3506 }
3507 break;
3508 }
3509 case PNG_COLOR_TYPE_GRAY:
3510 {
3511 if (row_info->bit_depth == 2)
3512 {
3513 sp = row;
3514 for (i = 0; i < row_width; i += 4)
3515 {
3516 int a = *sp & 0xc0;
3517 int b = *sp & 0x30;
3518 int c = *sp & 0x0c;
3519 int d = *sp & 0x03;
3520
3521 *sp = (png_byte)(
3522 ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
3523 ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
3524 ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
3525 ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
3526 sp++;
3527 }
3528 }
3529 if (row_info->bit_depth == 4)
3530 {
3531 sp = row;
3532 for (i = 0; i < row_width; i += 2)
3533 {
3534 int msb = *sp & 0xf0;
3535 int lsb = *sp & 0x0f;
3536
3537 *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
3538 | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
3539 sp++;
3540 }
3541 }
3542 else if (row_info->bit_depth == 8)
3543 {
3544 sp = row;
3545 for (i = 0; i < row_width; i++)
3546 {
3547 *sp = gamma_table[*sp];
3548 sp++;
3549 }
3550 }
3551 else if (row_info->bit_depth == 16)
3552 {
3553 sp = row;
3554 for (i = 0; i < row_width; i++)
3555 {
3556 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3557 *sp = (png_byte)((v >> 8) & 0xff);
3558 *(sp + 1) = (png_byte)(v & 0xff);
3559 sp += 2;
3560 }
3561 }
3562 break;
3563 }
3564 }
3565 }
3566}
3567#endif
3568
3569#if defined(PNG_READ_EXPAND_SUPPORTED)
3570/* Expands a palette row to an RGB or RGBA row depending
3571 * upon whether you supply trans and num_trans.
3572 */
3573void /* PRIVATE */
3574png_do_expand_palette(png_row_infop row_info, png_bytep row,
3575 png_colorp palette, png_bytep trans, int num_trans)
3576{
3577 int shift, value;
3578 png_bytep sp, dp;
3579 png_uint_32 i;
3580 png_uint_32 row_width=row_info->width;
3581
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003582 png_debug(1, "in png_do_expand_palette");
The Android Open Source Project893912b2009-03-03 19:30:05 -08003583 if (
3584#if defined(PNG_USELESS_TESTS_SUPPORTED)
3585 row != NULL && row_info != NULL &&
3586#endif
3587 row_info->color_type == PNG_COLOR_TYPE_PALETTE)
3588 {
3589 if (row_info->bit_depth < 8)
3590 {
3591 switch (row_info->bit_depth)
3592 {
3593 case 1:
3594 {
3595 sp = row + (png_size_t)((row_width - 1) >> 3);
3596 dp = row + (png_size_t)row_width - 1;
3597 shift = 7 - (int)((row_width + 7) & 0x07);
3598 for (i = 0; i < row_width; i++)
3599 {
3600 if ((*sp >> shift) & 0x01)
3601 *dp = 1;
3602 else
3603 *dp = 0;
3604 if (shift == 7)
3605 {
3606 shift = 0;
3607 sp--;
3608 }
3609 else
3610 shift++;
3611
3612 dp--;
3613 }
3614 break;
3615 }
3616 case 2:
3617 {
3618 sp = row + (png_size_t)((row_width - 1) >> 2);
3619 dp = row + (png_size_t)row_width - 1;
3620 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
3621 for (i = 0; i < row_width; i++)
3622 {
3623 value = (*sp >> shift) & 0x03;
3624 *dp = (png_byte)value;
3625 if (shift == 6)
3626 {
3627 shift = 0;
3628 sp--;
3629 }
3630 else
3631 shift += 2;
3632
3633 dp--;
3634 }
3635 break;
3636 }
3637 case 4:
3638 {
3639 sp = row + (png_size_t)((row_width - 1) >> 1);
3640 dp = row + (png_size_t)row_width - 1;
3641 shift = (int)((row_width & 0x01) << 2);
3642 for (i = 0; i < row_width; i++)
3643 {
3644 value = (*sp >> shift) & 0x0f;
3645 *dp = (png_byte)value;
3646 if (shift == 4)
3647 {
3648 shift = 0;
3649 sp--;
3650 }
3651 else
3652 shift += 4;
3653
3654 dp--;
3655 }
3656 break;
3657 }
3658 }
3659 row_info->bit_depth = 8;
3660 row_info->pixel_depth = 8;
3661 row_info->rowbytes = row_width;
3662 }
3663 switch (row_info->bit_depth)
3664 {
3665 case 8:
3666 {
3667 if (trans != NULL)
3668 {
3669 sp = row + (png_size_t)row_width - 1;
3670 dp = row + (png_size_t)(row_width << 2) - 1;
3671
3672 for (i = 0; i < row_width; i++)
3673 {
3674 if ((int)(*sp) >= num_trans)
3675 *dp-- = 0xff;
3676 else
3677 *dp-- = trans[*sp];
3678 *dp-- = palette[*sp].blue;
3679 *dp-- = palette[*sp].green;
3680 *dp-- = palette[*sp].red;
3681 sp--;
3682 }
3683 row_info->bit_depth = 8;
3684 row_info->pixel_depth = 32;
3685 row_info->rowbytes = row_width * 4;
3686 row_info->color_type = 6;
3687 row_info->channels = 4;
3688 }
3689 else
3690 {
3691 sp = row + (png_size_t)row_width - 1;
3692 dp = row + (png_size_t)(row_width * 3) - 1;
3693
3694 for (i = 0; i < row_width; i++)
3695 {
3696 *dp-- = palette[*sp].blue;
3697 *dp-- = palette[*sp].green;
3698 *dp-- = palette[*sp].red;
3699 sp--;
3700 }
3701 row_info->bit_depth = 8;
3702 row_info->pixel_depth = 24;
3703 row_info->rowbytes = row_width * 3;
3704 row_info->color_type = 2;
3705 row_info->channels = 3;
3706 }
3707 break;
3708 }
3709 }
3710 }
3711}
3712
3713/* If the bit depth < 8, it is expanded to 8. Also, if the already
3714 * expanded transparency value is supplied, an alpha channel is built.
3715 */
3716void /* PRIVATE */
3717png_do_expand(png_row_infop row_info, png_bytep row,
3718 png_color_16p trans_value)
3719{
3720 int shift, value;
3721 png_bytep sp, dp;
3722 png_uint_32 i;
3723 png_uint_32 row_width=row_info->width;
3724
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003725 png_debug(1, "in png_do_expand");
The Android Open Source Project893912b2009-03-03 19:30:05 -08003726#if defined(PNG_USELESS_TESTS_SUPPORTED)
3727 if (row != NULL && row_info != NULL)
3728#endif
3729 {
3730 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
3731 {
3732 png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
3733
3734 if (row_info->bit_depth < 8)
3735 {
3736 switch (row_info->bit_depth)
3737 {
3738 case 1:
3739 {
3740 gray = (png_uint_16)((gray&0x01)*0xff);
3741 sp = row + (png_size_t)((row_width - 1) >> 3);
3742 dp = row + (png_size_t)row_width - 1;
3743 shift = 7 - (int)((row_width + 7) & 0x07);
3744 for (i = 0; i < row_width; i++)
3745 {
3746 if ((*sp >> shift) & 0x01)
3747 *dp = 0xff;
3748 else
3749 *dp = 0;
3750 if (shift == 7)
3751 {
3752 shift = 0;
3753 sp--;
3754 }
3755 else
3756 shift++;
3757
3758 dp--;
3759 }
3760 break;
3761 }
3762 case 2:
3763 {
3764 gray = (png_uint_16)((gray&0x03)*0x55);
3765 sp = row + (png_size_t)((row_width - 1) >> 2);
3766 dp = row + (png_size_t)row_width - 1;
3767 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
3768 for (i = 0; i < row_width; i++)
3769 {
3770 value = (*sp >> shift) & 0x03;
3771 *dp = (png_byte)(value | (value << 2) | (value << 4) |
3772 (value << 6));
3773 if (shift == 6)
3774 {
3775 shift = 0;
3776 sp--;
3777 }
3778 else
3779 shift += 2;
3780
3781 dp--;
3782 }
3783 break;
3784 }
3785 case 4:
3786 {
3787 gray = (png_uint_16)((gray&0x0f)*0x11);
3788 sp = row + (png_size_t)((row_width - 1) >> 1);
3789 dp = row + (png_size_t)row_width - 1;
3790 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
3791 for (i = 0; i < row_width; i++)
3792 {
3793 value = (*sp >> shift) & 0x0f;
3794 *dp = (png_byte)(value | (value << 4));
3795 if (shift == 4)
3796 {
3797 shift = 0;
3798 sp--;
3799 }
3800 else
3801 shift = 4;
3802
3803 dp--;
3804 }
3805 break;
3806 }
3807 }
3808 row_info->bit_depth = 8;
3809 row_info->pixel_depth = 8;
3810 row_info->rowbytes = row_width;
3811 }
3812
3813 if (trans_value != NULL)
3814 {
3815 if (row_info->bit_depth == 8)
3816 {
3817 gray = gray & 0xff;
3818 sp = row + (png_size_t)row_width - 1;
3819 dp = row + (png_size_t)(row_width << 1) - 1;
3820 for (i = 0; i < row_width; i++)
3821 {
3822 if (*sp == gray)
3823 *dp-- = 0;
3824 else
3825 *dp-- = 0xff;
3826 *dp-- = *sp--;
3827 }
3828 }
3829 else if (row_info->bit_depth == 16)
3830 {
3831 png_byte gray_high = (gray >> 8) & 0xff;
3832 png_byte gray_low = gray & 0xff;
3833 sp = row + row_info->rowbytes - 1;
3834 dp = row + (row_info->rowbytes << 1) - 1;
3835 for (i = 0; i < row_width; i++)
3836 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003837 if (*(sp - 1) == gray_high && *(sp) == gray_low)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003838 {
3839 *dp-- = 0;
3840 *dp-- = 0;
3841 }
3842 else
3843 {
3844 *dp-- = 0xff;
3845 *dp-- = 0xff;
3846 }
3847 *dp-- = *sp--;
3848 *dp-- = *sp--;
3849 }
3850 }
3851 row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
3852 row_info->channels = 2;
3853 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
3854 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
3855 row_width);
3856 }
3857 }
3858 else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
3859 {
3860 if (row_info->bit_depth == 8)
3861 {
3862 png_byte red = trans_value->red & 0xff;
3863 png_byte green = trans_value->green & 0xff;
3864 png_byte blue = trans_value->blue & 0xff;
3865 sp = row + (png_size_t)row_info->rowbytes - 1;
3866 dp = row + (png_size_t)(row_width << 2) - 1;
3867 for (i = 0; i < row_width; i++)
3868 {
3869 if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)
3870 *dp-- = 0;
3871 else
3872 *dp-- = 0xff;
3873 *dp-- = *sp--;
3874 *dp-- = *sp--;
3875 *dp-- = *sp--;
3876 }
3877 }
3878 else if (row_info->bit_depth == 16)
3879 {
3880 png_byte red_high = (trans_value->red >> 8) & 0xff;
3881 png_byte green_high = (trans_value->green >> 8) & 0xff;
3882 png_byte blue_high = (trans_value->blue >> 8) & 0xff;
3883 png_byte red_low = trans_value->red & 0xff;
3884 png_byte green_low = trans_value->green & 0xff;
3885 png_byte blue_low = trans_value->blue & 0xff;
3886 sp = row + row_info->rowbytes - 1;
3887 dp = row + (png_size_t)(row_width << 3) - 1;
3888 for (i = 0; i < row_width; i++)
3889 {
3890 if (*(sp - 5) == red_high &&
3891 *(sp - 4) == red_low &&
3892 *(sp - 3) == green_high &&
3893 *(sp - 2) == green_low &&
3894 *(sp - 1) == blue_high &&
3895 *(sp ) == blue_low)
3896 {
3897 *dp-- = 0;
3898 *dp-- = 0;
3899 }
3900 else
3901 {
3902 *dp-- = 0xff;
3903 *dp-- = 0xff;
3904 }
3905 *dp-- = *sp--;
3906 *dp-- = *sp--;
3907 *dp-- = *sp--;
3908 *dp-- = *sp--;
3909 *dp-- = *sp--;
3910 *dp-- = *sp--;
3911 }
3912 }
3913 row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
3914 row_info->channels = 4;
3915 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003916 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003917 }
3918 }
3919}
3920#endif
3921
3922#if defined(PNG_READ_DITHER_SUPPORTED)
3923void /* PRIVATE */
3924png_do_dither(png_row_infop row_info, png_bytep row,
3925 png_bytep palette_lookup, png_bytep dither_lookup)
3926{
3927 png_bytep sp, dp;
3928 png_uint_32 i;
3929 png_uint_32 row_width=row_info->width;
3930
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003931 png_debug(1, "in png_do_dither");
The Android Open Source Project893912b2009-03-03 19:30:05 -08003932#if defined(PNG_USELESS_TESTS_SUPPORTED)
3933 if (row != NULL && row_info != NULL)
3934#endif
3935 {
3936 if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
3937 palette_lookup && row_info->bit_depth == 8)
3938 {
3939 int r, g, b, p;
3940 sp = row;
3941 dp = row;
3942 for (i = 0; i < row_width; i++)
3943 {
3944 r = *sp++;
3945 g = *sp++;
3946 b = *sp++;
3947
3948 /* this looks real messy, but the compiler will reduce
3949 it down to a reasonable formula. For example, with
3950 5 bits per color, we get:
3951 p = (((r >> 3) & 0x1f) << 10) |
3952 (((g >> 3) & 0x1f) << 5) |
3953 ((b >> 3) & 0x1f);
3954 */
3955 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
3956 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
3957 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3958 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
3959 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
3960 (PNG_DITHER_BLUE_BITS)) |
3961 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3962 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3963
3964 *dp++ = palette_lookup[p];
3965 }
3966 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3967 row_info->channels = 1;
3968 row_info->pixel_depth = row_info->bit_depth;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003969 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003970 }
3971 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
3972 palette_lookup != NULL && row_info->bit_depth == 8)
3973 {
3974 int r, g, b, p;
3975 sp = row;
3976 dp = row;
3977 for (i = 0; i < row_width; i++)
3978 {
3979 r = *sp++;
3980 g = *sp++;
3981 b = *sp++;
3982 sp++;
3983
3984 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
3985 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
3986 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3987 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
3988 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
3989 (PNG_DITHER_BLUE_BITS)) |
3990 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3991 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3992
3993 *dp++ = palette_lookup[p];
3994 }
3995 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3996 row_info->channels = 1;
3997 row_info->pixel_depth = row_info->bit_depth;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003998 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003999 }
4000 else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
4001 dither_lookup && row_info->bit_depth == 8)
4002 {
4003 sp = row;
4004 for (i = 0; i < row_width; i++, sp++)
4005 {
4006 *sp = dither_lookup[*sp];
4007 }
4008 }
4009 }
4010}
4011#endif
4012
4013#ifdef PNG_FLOATING_POINT_SUPPORTED
4014#if defined(PNG_READ_GAMMA_SUPPORTED)
4015static PNG_CONST int png_gamma_shift[] =
4016 {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0, 0x00};
4017
4018/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
4019 * tables, we don't make a full table if we are reducing to 8-bit in
4020 * the future. Note also how the gamma_16 tables are segmented so that
4021 * we don't need to allocate > 64K chunks for a full 16-bit table.
4022 */
4023void /* PRIVATE */
4024png_build_gamma_table(png_structp png_ptr)
4025{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004026 png_debug(1, "in png_build_gamma_table");
The Android Open Source Project893912b2009-03-03 19:30:05 -08004027
4028 if (png_ptr->bit_depth <= 8)
4029 {
4030 int i;
4031 double g;
4032
4033 if (png_ptr->screen_gamma > .000001)
4034 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
4035 else
4036 g = 1.0;
4037
4038 png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
4039 (png_uint_32)256);
4040
4041 for (i = 0; i < 256; i++)
4042 {
4043 png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
4044 g) * 255.0 + .5);
4045 }
4046
4047#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
4048 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4049 if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
4050 {
4051
4052 g = 1.0 / (png_ptr->gamma);
4053
4054 png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
4055 (png_uint_32)256);
4056
4057 for (i = 0; i < 256; i++)
4058 {
4059 png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
4060 g) * 255.0 + .5);
4061 }
4062
4063
4064 png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
4065 (png_uint_32)256);
4066
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004067 if (png_ptr->screen_gamma > 0.000001)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004068 g = 1.0 / png_ptr->screen_gamma;
4069 else
4070 g = png_ptr->gamma; /* probably doing rgb_to_gray */
4071
4072 for (i = 0; i < 256; i++)
4073 {
4074 png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
4075 g) * 255.0 + .5);
4076
4077 }
4078 }
4079#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
4080 }
4081 else
4082 {
4083 double g;
4084 int i, j, shift, num;
4085 int sig_bit;
4086 png_uint_32 ig;
4087
4088 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
4089 {
4090 sig_bit = (int)png_ptr->sig_bit.red;
4091 if ((int)png_ptr->sig_bit.green > sig_bit)
4092 sig_bit = png_ptr->sig_bit.green;
4093 if ((int)png_ptr->sig_bit.blue > sig_bit)
4094 sig_bit = png_ptr->sig_bit.blue;
4095 }
4096 else
4097 {
4098 sig_bit = (int)png_ptr->sig_bit.gray;
4099 }
4100
4101 if (sig_bit > 0)
4102 shift = 16 - sig_bit;
4103 else
4104 shift = 0;
4105
4106 if (png_ptr->transformations & PNG_16_TO_8)
4107 {
4108 if (shift < (16 - PNG_MAX_GAMMA_8))
4109 shift = (16 - PNG_MAX_GAMMA_8);
4110 }
4111
4112 if (shift > 8)
4113 shift = 8;
4114 if (shift < 0)
4115 shift = 0;
4116
4117 png_ptr->gamma_shift = (png_byte)shift;
4118
4119 num = (1 << (8 - shift));
4120
4121 if (png_ptr->screen_gamma > .000001)
4122 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
4123 else
4124 g = 1.0;
4125
4126 png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004127 (png_uint_32)(num * png_sizeof(png_uint_16p)));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004128
4129 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
4130 {
4131 double fin, fout;
4132 png_uint_32 last, max;
4133
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004134 png_memset(png_ptr->gamma_16_table, 0, num * png_sizeof(png_uint_16p));
4135
The Android Open Source Project893912b2009-03-03 19:30:05 -08004136 for (i = 0; i < num; i++)
4137 {
4138 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004139 (png_uint_32)(256 * png_sizeof(png_uint_16)));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004140 }
4141
4142 g = 1.0 / g;
4143 last = 0;
4144 for (i = 0; i < 256; i++)
4145 {
4146 fout = ((double)i + 0.5) / 256.0;
4147 fin = pow(fout, g);
4148 max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
4149 while (last <= max)
4150 {
4151 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4152 [(int)(last >> (8 - shift))] = (png_uint_16)(
4153 (png_uint_16)i | ((png_uint_16)i << 8));
4154 last++;
4155 }
4156 }
4157 while (last < ((png_uint_32)num << 8))
4158 {
4159 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4160 [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
4161 last++;
4162 }
4163 }
4164 else
4165 {
4166 for (i = 0; i < num; i++)
4167 {
4168 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004169 (png_uint_32)(256 * png_sizeof(png_uint_16)));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004170
4171 ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
4172 for (j = 0; j < 256; j++)
4173 {
4174 png_ptr->gamma_16_table[i][j] =
4175 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4176 65535.0, g) * 65535.0 + .5);
4177 }
4178 }
4179 }
4180
4181#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
4182 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4183 if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
4184 {
4185
4186 g = 1.0 / (png_ptr->gamma);
4187
4188 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004189 (png_uint_32)(num * png_sizeof(png_uint_16p )));
4190
4191 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 -08004192
4193 for (i = 0; i < num; i++)
4194 {
4195 png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004196 (png_uint_32)(256 * png_sizeof(png_uint_16)));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004197
4198 ig = (((png_uint_32)i *
4199 (png_uint_32)png_gamma_shift[shift]) >> 4);
4200 for (j = 0; j < 256; j++)
4201 {
4202 png_ptr->gamma_16_to_1[i][j] =
4203 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4204 65535.0, g) * 65535.0 + .5);
4205 }
4206 }
4207
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004208 if (png_ptr->screen_gamma > 0.000001)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004209 g = 1.0 / png_ptr->screen_gamma;
4210 else
4211 g = png_ptr->gamma; /* probably doing rgb_to_gray */
4212
4213 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004214 (png_uint_32)(num * png_sizeof(png_uint_16p)));
4215
4216 png_memset(png_ptr->gamma_16_from_1, 0,
4217 num * png_sizeof(png_uint_16p));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004218
4219 for (i = 0; i < num; i++)
4220 {
4221 png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004222 (png_uint_32)(256 * png_sizeof(png_uint_16)));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004223
4224 ig = (((png_uint_32)i *
4225 (png_uint_32)png_gamma_shift[shift]) >> 4);
4226 for (j = 0; j < 256; j++)
4227 {
4228 png_ptr->gamma_16_from_1[i][j] =
4229 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4230 65535.0, g) * 65535.0 + .5);
4231 }
4232 }
4233 }
4234#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
4235 }
4236}
4237#endif
4238/* To do: install integer version of png_build_gamma_table here */
4239#endif
4240
4241#if defined(PNG_MNG_FEATURES_SUPPORTED)
4242/* undoes intrapixel differencing */
4243void /* PRIVATE */
4244png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
4245{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004246 png_debug(1, "in png_do_read_intrapixel");
The Android Open Source Project893912b2009-03-03 19:30:05 -08004247 if (
4248#if defined(PNG_USELESS_TESTS_SUPPORTED)
4249 row != NULL && row_info != NULL &&
4250#endif
4251 (row_info->color_type & PNG_COLOR_MASK_COLOR))
4252 {
4253 int bytes_per_pixel;
4254 png_uint_32 row_width = row_info->width;
4255 if (row_info->bit_depth == 8)
4256 {
4257 png_bytep rp;
4258 png_uint_32 i;
4259
4260 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4261 bytes_per_pixel = 3;
4262 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4263 bytes_per_pixel = 4;
4264 else
4265 return;
4266
4267 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4268 {
4269 *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff);
4270 *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff);
4271 }
4272 }
4273 else if (row_info->bit_depth == 16)
4274 {
4275 png_bytep rp;
4276 png_uint_32 i;
4277
4278 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4279 bytes_per_pixel = 6;
4280 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4281 bytes_per_pixel = 8;
4282 else
4283 return;
4284
4285 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4286 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004287 png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1);
4288 png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3);
4289 png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5);
4290 png_uint_32 red = (png_uint_32)((s0 + s1 + 65536L) & 0xffffL);
4291 png_uint_32 blue = (png_uint_32)((s2 + s1 + 65536L) & 0xffffL);
The Android Open Source Project893912b2009-03-03 19:30:05 -08004292 *(rp ) = (png_byte)((red >> 8) & 0xff);
4293 *(rp+1) = (png_byte)(red & 0xff);
4294 *(rp+4) = (png_byte)((blue >> 8) & 0xff);
4295 *(rp+5) = (png_byte)(blue & 0xff);
4296 }
4297 }
4298 }
4299}
4300#endif /* PNG_MNG_FEATURES_SUPPORTED */
4301#endif /* PNG_READ_SUPPORTED */