blob: 94216b232389d6b580bf647511d416f164bcf22c [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
Andreas Dilger47a0c421997-05-16 02:46:07 -05002/* pngrtran.c - transforms the data in a row for PNG readers
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003 *
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06004 * libpng 1.2.2beta2 - February 24, 2002
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06006 * Copyright (c) 1998-2002 Glenn Randers-Pehrson
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05007 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06009 *
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -060010 * This file contains functions optionally called by an application
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060011 * in order to tell libpng how to handle data when reading a PNG.
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050012 * Transformations that are used in both reading and writing are
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060013 * in pngtrans.c.
14 */
Guy Schalnat0d580581995-07-20 02:43:20 -050015
16#define PNG_INTERNAL
17#include "png.h"
18
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060019/* Set the action on getting a CRC error for an ancillary or critical chunk. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050020void PNGAPI
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060021png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
22{
23 png_debug(1, "in png_set_crc_action\n");
24 /* Tell libpng how we react to CRC errors in critical chunks */
25 switch (crit_action)
26 {
27 case PNG_CRC_NO_CHANGE: /* leave setting as is */
28 break;
29 case PNG_CRC_WARN_USE: /* warn/use data */
30 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
31 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
32 break;
33 case PNG_CRC_QUIET_USE: /* quiet/use data */
34 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
35 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
36 PNG_FLAG_CRC_CRITICAL_IGNORE;
37 break;
38 case PNG_CRC_WARN_DISCARD: /* not a valid action for critical data */
39 png_warning(png_ptr, "Can't discard critical data on CRC error.");
40 case PNG_CRC_ERROR_QUIT: /* error/quit */
41 case PNG_CRC_DEFAULT:
42 default:
43 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
44 break;
45 }
46
47 switch (ancil_action)
48 {
49 case PNG_CRC_NO_CHANGE: /* leave setting as is */
50 break;
51 case PNG_CRC_WARN_USE: /* warn/use data */
52 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
53 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
54 break;
55 case PNG_CRC_QUIET_USE: /* quiet/use data */
56 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
57 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
58 PNG_FLAG_CRC_ANCILLARY_NOWARN;
59 break;
60 case PNG_CRC_ERROR_QUIT: /* error/quit */
61 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
62 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
63 break;
64 case PNG_CRC_WARN_DISCARD: /* warn/discard data */
65 case PNG_CRC_DEFAULT:
66 default:
67 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
68 break;
69 }
70}
71
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060072#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
73 defined(PNG_FLOATING_POINT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050074/* handle alpha and tRNS via a background color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050075void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060076png_set_background(png_structp png_ptr,
77 png_color_16p background_color, int background_gamma_code,
Guy Schalnat51f0eb41995-09-26 05:22:39 -050078 int need_expand, double background_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -050079{
Andreas Dilger47a0c421997-05-16 02:46:07 -050080 png_debug(1, "in png_set_background\n");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060081 if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
82 {
83 png_warning(png_ptr, "Application must supply a known background gamma");
84 return;
85 }
86
Guy Schalnat0d580581995-07-20 02:43:20 -050087 png_ptr->transformations |= PNG_BACKGROUND;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050088 png_memcpy(&(png_ptr->background), background_color, sizeof(png_color_16));
Guy Schalnat51f0eb41995-09-26 05:22:39 -050089 png_ptr->background_gamma = (float)background_gamma;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060090 png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
Guy Schalnate5a37791996-06-05 15:50:50 -050091 png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050092
93 /* Note: if need_expand is set and color_type is either RGB or RGB_ALPHA
94 * (in which case need_expand is superfluous anyway), the background color
95 * might actually be gray yet not be flagged as such. This is not a problem
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -060096 * for the current code, which uses PNG_BACKGROUND_IS_GRAY only to
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050097 * decide when to do the png_do_gray_to_rgb() transformation.
98 */
99 if ((need_expand && !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) ||
100 (!need_expand && background_color->red == background_color->green &&
101 background_color->red == background_color->blue))
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600102 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
Guy Schalnat0d580581995-07-20 02:43:20 -0500103}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500104#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500105
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500106#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500107/* strip 16 bit depth files to 8 bit depth */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500108void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600109png_set_strip_16(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500110{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500111 png_debug(1, "in png_set_strip_16\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500112 png_ptr->transformations |= PNG_16_TO_8;
113}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500114#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500115
Andreas Dilger47a0c421997-05-16 02:46:07 -0500116#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500117void PNGAPI
Andreas Dilger47a0c421997-05-16 02:46:07 -0500118png_set_strip_alpha(png_structp png_ptr)
119{
120 png_debug(1, "in png_set_strip_alpha\n");
121 png_ptr->transformations |= PNG_STRIP_ALPHA;
122}
123#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500124
Andreas Dilger47a0c421997-05-16 02:46:07 -0500125#if defined(PNG_READ_DITHER_SUPPORTED)
126/* Dither file to 8 bit. Supply a palette, the current number
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600127 * of elements in the palette, the maximum number of elements
128 * allowed, and a histogram if possible. If the current number
129 * of colors is greater then the maximum number, the palette will be
130 * modified to fit in the maximum number. "full_dither" indicates
131 * whether we need a dithering cube set up for RGB images, or if we
132 * simply are reducing the number of colors in a paletted image.
133 */
Guy Schalnat6d764711995-12-19 03:22:19 -0600134
135typedef struct png_dsort_struct
Guy Schalnat0d580581995-07-20 02:43:20 -0500136{
Guy Schalnat6d764711995-12-19 03:22:19 -0600137 struct png_dsort_struct FAR * next;
Guy Schalnat0d580581995-07-20 02:43:20 -0500138 png_byte left;
139 png_byte right;
Guy Schalnat6d764711995-12-19 03:22:19 -0600140} png_dsort;
141typedef png_dsort FAR * png_dsortp;
142typedef png_dsort FAR * FAR * png_dsortpp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500143
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500144void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600145png_set_dither(png_structp png_ptr, png_colorp palette,
146 int num_palette, int maximum_colors, png_uint_16p histogram,
Guy Schalnat0d580581995-07-20 02:43:20 -0500147 int full_dither)
148{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500149 png_debug(1, "in png_set_dither\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500150 png_ptr->transformations |= PNG_DITHER;
151
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600152 if (!full_dither)
Guy Schalnat0d580581995-07-20 02:43:20 -0500153 {
154 int i;
155
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600156 png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600157 (png_uint_32)(num_palette * sizeof (png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500158 for (i = 0; i < num_palette; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600159 png_ptr->dither_index[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500160 }
161
162 if (num_palette > maximum_colors)
163 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500164 if (histogram != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500165 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500166 /* This is easy enough, just throw out the least used colors.
167 Perhaps not the best solution, but good enough. */
Guy Schalnat0d580581995-07-20 02:43:20 -0500168
169 int i;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600170 png_bytep sort;
Guy Schalnat0d580581995-07-20 02:43:20 -0500171
172 /* initialize an array to sort colors */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600173 sort = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_palette
174 * sizeof (png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500175
176 /* initialize the sort array */
177 for (i = 0; i < num_palette; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600178 sort[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500179
Andreas Dilger47a0c421997-05-16 02:46:07 -0500180 /* Find the least used palette entries by starting a
Guy Schalnat0d580581995-07-20 02:43:20 -0500181 bubble sort, and running it until we have sorted
182 out enough colors. Note that we don't care about
183 sorting all the colors, just finding which are
184 least used. */
185
186 for (i = num_palette - 1; i >= maximum_colors; i--)
187 {
188 int done; /* to stop early if the list is pre-sorted */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600189 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500190
191 done = 1;
192 for (j = 0; j < i; j++)
193 {
194 if (histogram[sort[j]] < histogram[sort[j + 1]])
195 {
196 png_byte t;
197
198 t = sort[j];
199 sort[j] = sort[j + 1];
200 sort[j + 1] = t;
201 done = 0;
202 }
203 }
204 if (done)
205 break;
206 }
207
208 /* swap the palette around, and set up a table, if necessary */
209 if (full_dither)
210 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500211 int j = num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500212
213 /* put all the useful colors within the max, but don't
214 move the others */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500215 for (i = 0; i < maximum_colors; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500216 {
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600217 if ((int)sort[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500218 {
219 do
220 j--;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600221 while ((int)sort[j] >= maximum_colors);
Guy Schalnat0d580581995-07-20 02:43:20 -0500222 palette[i] = palette[j];
223 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600224 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500225 }
226 else
227 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500228 int j = num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500229
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600230 /* move all the used colors inside the max limit, and
Guy Schalnat0d580581995-07-20 02:43:20 -0500231 develop a translation table */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500232 for (i = 0; i < maximum_colors; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500233 {
234 /* only move the colors we need to */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600235 if ((int)sort[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500236 {
237 png_color tmp_color;
238
239 do
240 j--;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600241 while ((int)sort[j] >= maximum_colors);
Guy Schalnat0d580581995-07-20 02:43:20 -0500242
243 tmp_color = palette[j];
244 palette[j] = palette[i];
245 palette[i] = tmp_color;
246 /* indicate where the color went */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600247 png_ptr->dither_index[j] = (png_byte)i;
248 png_ptr->dither_index[i] = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500249 }
250 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500251
252 /* find closest color for those colors we are not using */
Guy Schalnat0d580581995-07-20 02:43:20 -0500253 for (i = 0; i < num_palette; i++)
254 {
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600255 if ((int)png_ptr->dither_index[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500256 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500257 int min_d, k, min_k, d_index;
Guy Schalnat0d580581995-07-20 02:43:20 -0500258
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600259 /* find the closest color to one we threw out */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500260 d_index = png_ptr->dither_index[i];
261 min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
262 for (k = 1, min_k = 0; k < maximum_colors; k++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500263 {
264 int d;
265
Andreas Dilger47a0c421997-05-16 02:46:07 -0500266 d = PNG_COLOR_DIST(palette[d_index], palette[k]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500267
268 if (d < min_d)
269 {
270 min_d = d;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500271 min_k = k;
Guy Schalnat0d580581995-07-20 02:43:20 -0500272 }
273 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600274 /* point to closest color */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500275 png_ptr->dither_index[i] = (png_byte)min_k;
Guy Schalnat0d580581995-07-20 02:43:20 -0500276 }
277 }
278 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600279 png_free(png_ptr, sort);
Guy Schalnat0d580581995-07-20 02:43:20 -0500280 }
281 else
282 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500283 /* This is much harder to do simply (and quickly). Perhaps
Guy Schalnat0d580581995-07-20 02:43:20 -0500284 we need to go through a median cut routine, but those
285 don't always behave themselves with only a few colors
286 as input. So we will just find the closest two colors,
287 and throw out one of them (chosen somewhat randomly).
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600288 [We don't understand this at all, so if someone wants to
289 work on improving it, be our guest - AED, GRP]
Guy Schalnat0d580581995-07-20 02:43:20 -0500290 */
291 int i;
292 int max_d;
293 int num_new_palette;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600294 png_dsortpp hash;
295 png_bytep index_to_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500296 /* where the original index currently is in the palette */
Guy Schalnat6d764711995-12-19 03:22:19 -0600297 png_bytep palette_to_index;
Guy Schalnat0d580581995-07-20 02:43:20 -0500298 /* which original index points to this palette color */
299
300 /* initialize palette index arrays */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600301 index_to_palette = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600302 (png_uint_32)(num_palette * sizeof (png_byte)));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600303 palette_to_index = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600304 (png_uint_32)(num_palette * sizeof (png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500305
306 /* initialize the sort array */
307 for (i = 0; i < num_palette; i++)
308 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600309 index_to_palette[i] = (png_byte)i;
310 palette_to_index[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500311 }
312
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600313 hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600314 sizeof (png_dsortp)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500315 for (i = 0; i < 769; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500316 hash[i] = NULL;
Guy Schalnat6d764711995-12-19 03:22:19 -0600317/* png_memset(hash, 0, 769 * sizeof (png_dsortp)); */
Guy Schalnat0d580581995-07-20 02:43:20 -0500318
319 num_new_palette = num_palette;
320
321 /* initial wild guess at how far apart the farthest pixel
322 pair we will be eliminating will be. Larger
323 numbers mean more areas will be allocated, Smaller
324 numbers run the risk of not saving enough data, and
325 having to do this all over again.
326
327 I have not done extensive checking on this number.
328 */
329 max_d = 96;
330
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600331 while (num_new_palette > maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500332 {
333 for (i = 0; i < num_new_palette - 1; i++)
334 {
335 int j;
336
337 for (j = i + 1; j < num_new_palette; j++)
338 {
339 int d;
340
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600341 d = PNG_COLOR_DIST(palette[i], palette[j]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500342
343 if (d <= max_d)
344 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600345 png_dsortp t;
Guy Schalnat0d580581995-07-20 02:43:20 -0500346
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600347 t = (png_dsortp)png_malloc(png_ptr, (png_uint_32)(sizeof
348 (png_dsort)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500349 t->next = hash[d];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600350 t->left = (png_byte)i;
351 t->right = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500352 hash[d] = t;
353 }
354 }
355 }
356
357 for (i = 0; i <= max_d; i++)
358 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500359 if (hash[i] != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500360 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600361 png_dsortp p;
Guy Schalnat0d580581995-07-20 02:43:20 -0500362
363 for (p = hash[i]; p; p = p->next)
364 {
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600365 if ((int)index_to_palette[p->left] < num_new_palette &&
366 (int)index_to_palette[p->right] < num_new_palette)
Guy Schalnat0d580581995-07-20 02:43:20 -0500367 {
368 int j, next_j;
369
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600370 if (num_new_palette & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -0500371 {
372 j = p->left;
373 next_j = p->right;
374 }
375 else
376 {
377 j = p->right;
378 next_j = p->left;
379 }
380
381 num_new_palette--;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500382 palette[index_to_palette[j]] = palette[num_new_palette];
Guy Schalnat0d580581995-07-20 02:43:20 -0500383 if (!full_dither)
384 {
385 int k;
386
387 for (k = 0; k < num_palette; k++)
388 {
389 if (png_ptr->dither_index[k] ==
390 index_to_palette[j])
391 png_ptr->dither_index[k] =
392 index_to_palette[next_j];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600393 if ((int)png_ptr->dither_index[k] ==
Guy Schalnat0d580581995-07-20 02:43:20 -0500394 num_new_palette)
395 png_ptr->dither_index[k] =
396 index_to_palette[j];
397 }
398 }
399
400 index_to_palette[palette_to_index[num_new_palette]] =
401 index_to_palette[j];
402 palette_to_index[index_to_palette[j]] =
403 palette_to_index[num_new_palette];
404
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600405 index_to_palette[j] = (png_byte)num_new_palette;
406 palette_to_index[num_new_palette] = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500407 }
408 if (num_new_palette <= maximum_colors)
409 break;
410 }
411 if (num_new_palette <= maximum_colors)
412 break;
413 }
414 }
415
416 for (i = 0; i < 769; i++)
417 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500418 if (hash[i] != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500419 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500420 png_dsortp p = hash[i];
Guy Schalnat0d580581995-07-20 02:43:20 -0500421 while (p)
422 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600423 png_dsortp t;
Guy Schalnat0d580581995-07-20 02:43:20 -0500424
425 t = p->next;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600426 png_free(png_ptr, p);
Guy Schalnat0d580581995-07-20 02:43:20 -0500427 p = t;
428 }
429 }
430 hash[i] = 0;
431 }
432 max_d += 96;
433 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600434 png_free(png_ptr, hash);
435 png_free(png_ptr, palette_to_index);
436 png_free(png_ptr, index_to_palette);
Guy Schalnat0d580581995-07-20 02:43:20 -0500437 }
438 num_palette = maximum_colors;
439 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500440 if (png_ptr->palette == NULL)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600441 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500442 png_ptr->palette = palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500443 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600444 png_ptr->num_palette = (png_uint_16)num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500445
446 if (full_dither)
447 {
448 int i;
Guy Schalnat6d764711995-12-19 03:22:19 -0600449 png_bytep distance;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500450 int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600451 PNG_DITHER_BLUE_BITS;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500452 int num_red = (1 << PNG_DITHER_RED_BITS);
453 int num_green = (1 << PNG_DITHER_GREEN_BITS);
454 int num_blue = (1 << PNG_DITHER_BLUE_BITS);
455 png_size_t num_entries = ((png_size_t)1 << total_bits);
Guy Schalnat0d580581995-07-20 02:43:20 -0500456
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600457 png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600458 (png_uint_32)(num_entries * sizeof (png_byte)));
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500459
460 png_memset(png_ptr->palette_lookup, 0, num_entries * sizeof (png_byte));
Guy Schalnat0d580581995-07-20 02:43:20 -0500461
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600462 distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
463 sizeof(png_byte)));
Glenn Randers-Pehrsone1eff582001-04-14 20:15:41 -0500464
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500465 png_memset(distance, 0xff, num_entries * sizeof(png_byte));
466
467 for (i = 0; i < num_palette; i++)
468 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500469 int ir, ig, ib;
470 int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
471 int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
472 int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
Guy Schalnat0d580581995-07-20 02:43:20 -0500473
474 for (ir = 0; ir < num_red; ir++)
475 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500476 int dr = abs(ir - r);
477 int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
Guy Schalnat0d580581995-07-20 02:43:20 -0500478
Guy Schalnat0d580581995-07-20 02:43:20 -0500479 for (ig = 0; ig < num_green; ig++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600480 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500481 int dg = abs(ig - g);
482 int dt = dr + dg;
483 int dm = ((dr > dg) ? dr : dg);
484 int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
Guy Schalnat0d580581995-07-20 02:43:20 -0500485
Guy Schalnat0d580581995-07-20 02:43:20 -0500486 for (ib = 0; ib < num_blue; ib++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600487 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500488 int d_index = index_g | ib;
489 int db = abs(ib - b);
490 int dmax = ((dm > db) ? dm : db);
491 int d = dmax + dt + db;
Guy Schalnat0d580581995-07-20 02:43:20 -0500492
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600493 if (d < (int)distance[d_index])
Guy Schalnat0d580581995-07-20 02:43:20 -0500494 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500495 distance[d_index] = (png_byte)d;
496 png_ptr->palette_lookup[d_index] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500497 }
498 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500499 }
500 }
501 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500502
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600503 png_free(png_ptr, distance);
Guy Schalnat0d580581995-07-20 02:43:20 -0500504 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500505}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500506#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500507
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600508#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600509/* Transform the image from the file_gamma to the screen_gamma. We
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600510 * only do transformations on images where the file_gamma and screen_gamma
511 * are not close reciprocals, otherwise it slows things down slightly, and
512 * also needlessly introduces small errors.
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600513 *
514 * We will turn off gamma transformation later if no semitransparent entries
515 * are present in the tRNS array for palette images. We can't do it here
516 * because we don't necessarily have the tRNS chunk yet.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600517 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500518void PNGAPI
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600519png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -0500520{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500521 png_debug(1, "in png_set_gamma\n");
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600522 if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) ||
523 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) ||
524 (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
525 png_ptr->transformations |= PNG_GAMMA;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500526 png_ptr->gamma = (float)file_gamma;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600527 png_ptr->screen_gamma = (float)scrn_gamma;
Guy Schalnat0d580581995-07-20 02:43:20 -0500528}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500529#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500530
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500531#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -0500532/* Expand paletted images to RGB, expand grayscale images of
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500533 * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600534 * to alpha channels.
535 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500536void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600537png_set_expand(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500538{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500539 png_debug(1, "in png_set_expand\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500540 png_ptr->transformations |= PNG_EXPAND;
541}
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500542
543/* GRR 19990627: the following three functions currently are identical
544 * to png_set_expand(). However, it is entirely reasonable that someone
545 * might wish to expand an indexed image to RGB but *not* expand a single,
546 * fully transparent palette entry to a full alpha channel--perhaps instead
547 * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
548 * the transparent color with a particular RGB value, or drop tRNS entirely.
549 * IOW, a future version of the library may make the transformations flag
550 * a bit more fine-grained, with separate bits for each of these three
551 * functions.
552 *
553 * More to the point, these functions make it obvious what libpng will be
554 * doing, whereas "expand" can (and does) mean any number of things.
555 */
556
557/* Expand paletted images to RGB. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500558void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500559png_set_palette_to_rgb(png_structp png_ptr)
560{
561 png_debug(1, "in png_set_expand\n");
562 png_ptr->transformations |= PNG_EXPAND;
563}
564
565/* Expand grayscale images of less than 8-bit depth to 8 bits. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500566void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500567png_set_gray_1_2_4_to_8(png_structp png_ptr)
568{
569 png_debug(1, "in png_set_expand\n");
570 png_ptr->transformations |= PNG_EXPAND;
571}
572
573/* Expand tRNS chunks to alpha channels. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500574void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500575png_set_tRNS_to_alpha(png_structp png_ptr)
576{
577 png_debug(1, "in png_set_expand\n");
578 png_ptr->transformations |= PNG_EXPAND;
579}
580#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500581
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500582#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500583void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600584png_set_gray_to_rgb(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500585{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500586 png_debug(1, "in png_set_gray_to_rgb\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500587 png_ptr->transformations |= PNG_GRAY_TO_RGB;
588}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500589#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500590
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600591#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
592#if defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600593/* Convert a RGB image to a grayscale of the same width. This allows us,
594 * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600595 */
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600596
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500597void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500598png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red,
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600599 double green)
600{
601 int red_fixed = (int)((float)red*100000.0 + 0.5);
602 int green_fixed = (int)((float)green*100000.0 + 0.5);
603 png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed);
604}
605#endif
606
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500607void PNGAPI
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600608png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
609 png_fixed_point red, png_fixed_point green)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600610{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500611 png_debug(1, "in png_set_rgb_to_gray\n");
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600612 switch(error_action)
613 {
614 case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY;
615 break;
616 case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
617 break;
618 case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
619 }
620 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
621#if defined(PNG_READ_EXPAND_SUPPORTED)
622 png_ptr->transformations |= PNG_EXPAND;
623#else
624 {
625 png_warning(png_ptr, "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED.");
626 png_ptr->transformations &= ~PNG_RGB_TO_GRAY;
627 }
628#endif
629 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600630 png_uint_16 red_int, green_int;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600631 if(red < 0 || green < 0)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600632 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600633 red_int = 6968; /* .212671 * 32768 + .5 */
634 green_int = 23434; /* .715160 * 32768 + .5 */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600635 }
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600636 else if(red + green < 100000L)
637 {
638 red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
639 green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
640 }
641 else
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600642 {
643 png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600644 red_int = 6968;
645 green_int = 23434;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600646 }
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600647 png_ptr->rgb_to_gray_red_coeff = red_int;
648 png_ptr->rgb_to_gray_green_coeff = green_int;
649 png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(32768-red_int-green_int);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600650 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600651}
652#endif
653
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500654#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
655 defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
656 defined(PNG_LEGACY_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500657void PNGAPI
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600658png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
659 read_user_transform_fn)
660{
661 png_debug(1, "in png_set_read_user_transform_fn\n");
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500662#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600663 png_ptr->transformations |= PNG_USER_TRANSFORM;
664 png_ptr->read_user_transform_fn = read_user_transform_fn;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500665#endif
666#ifdef PNG_LEGACY_SUPPORTED
667 if(read_user_transform_fn)
668 png_warning(png_ptr,
669 "This version of libpng does not support user transforms");
670#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600671}
672#endif
673
Andreas Dilger47a0c421997-05-16 02:46:07 -0500674/* Initialize everything needed for the read. This includes modifying
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600675 * the palette.
676 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500677void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -0600678png_init_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500679{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500680 png_debug(1, "in png_init_read_transformations\n");
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500681#if defined(PNG_USELESS_TESTS_SUPPORTED)
682 if(png_ptr != NULL)
683#endif
684 {
685#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
686 || defined(PNG_READ_GAMMA_SUPPORTED)
687 int color_type = png_ptr->color_type;
688#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500689
Guy Schalnate5a37791996-06-05 15:50:50 -0500690#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600691 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
692 (png_ptr->transformations & PNG_EXPAND))
Guy Schalnat0d580581995-07-20 02:43:20 -0500693 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500694 if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
Guy Schalnat0d580581995-07-20 02:43:20 -0500695 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500696 /* expand background chunk. */
Guy Schalnat0d580581995-07-20 02:43:20 -0500697 switch (png_ptr->bit_depth)
698 {
699 case 1:
Guy Schalnate5a37791996-06-05 15:50:50 -0500700 png_ptr->background.gray *= (png_uint_16)0xff;
701 png_ptr->background.red = png_ptr->background.green =
702 png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500703 break;
704 case 2:
Guy Schalnate5a37791996-06-05 15:50:50 -0500705 png_ptr->background.gray *= (png_uint_16)0x55;
706 png_ptr->background.red = png_ptr->background.green =
707 png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500708 break;
709 case 4:
Guy Schalnate5a37791996-06-05 15:50:50 -0500710 png_ptr->background.gray *= (png_uint_16)0x11;
711 png_ptr->background.red = png_ptr->background.green =
712 png_ptr->background.blue = png_ptr->background.gray;
713 break;
714 case 8:
715 case 16:
716 png_ptr->background.red = png_ptr->background.green =
717 png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500718 break;
719 }
720 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500721 else if (color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -0500722 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500723 png_ptr->background.red =
Guy Schalnat0d580581995-07-20 02:43:20 -0500724 png_ptr->palette[png_ptr->background.index].red;
725 png_ptr->background.green =
726 png_ptr->palette[png_ptr->background.index].green;
Guy Schalnate5a37791996-06-05 15:50:50 -0500727 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -0500728 png_ptr->palette[png_ptr->background.index].blue;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600729
730#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
731 if (png_ptr->transformations & PNG_INVERT_ALPHA)
732 {
733#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600734 if (!(png_ptr->transformations & PNG_EXPAND))
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600735#endif
736 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600737 /* invert the alpha channel (in tRNS) unless the pixels are
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600738 going to be expanded, in which case leave it for later */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500739 int i,istop;
740 istop=(int)png_ptr->num_trans;
741 for (i=0; i<istop; i++)
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -0500742 png_ptr->trans[i] = (png_byte)(255 - png_ptr->trans[i]);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600743 }
744 }
745#endif
746
Guy Schalnat0d580581995-07-20 02:43:20 -0500747 }
748 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500749#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500750
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500751#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500752 png_ptr->background_1 = png_ptr->background;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500753#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600754#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600755
756 if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0)
757 && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0)
758 < PNG_GAMMA_THRESHOLD))
759 {
760 int i,k;
761 k=0;
762 for (i=0; i<png_ptr->num_trans; i++)
763 {
764 if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff)
765 k=1; /* partial transparency is present */
766 }
767 if (k == 0)
768 png_ptr->transformations &= (~PNG_GAMMA);
769 }
770
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600771 if (png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -0500772 {
773 png_build_gamma_table(png_ptr);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500774#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Guy Schalnate5a37791996-06-05 15:50:50 -0500775 if (png_ptr->transformations & PNG_BACKGROUND)
Guy Schalnat0d580581995-07-20 02:43:20 -0500776 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500777 if (color_type == PNG_COLOR_TYPE_PALETTE)
778 {
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600779 /* could skip if no transparency and
780 */
Guy Schalnate5a37791996-06-05 15:50:50 -0500781 png_color back, back_1;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500782 png_colorp palette = png_ptr->palette;
783 int num_palette = png_ptr->num_palette;
784 int i;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500785 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
786 {
787 back.red = png_ptr->gamma_table[png_ptr->background.red];
788 back.green = png_ptr->gamma_table[png_ptr->background.green];
789 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
Guy Schalnate5a37791996-06-05 15:50:50 -0500790
Andreas Dilger47a0c421997-05-16 02:46:07 -0500791 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
792 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
793 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
794 }
795 else
796 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600797 double g, gs;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500798
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600799 switch (png_ptr->background_gamma_type)
Glenn Randers-Pehrson4922b1b1998-03-08 22:55:17 -0600800 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600801 case PNG_BACKGROUND_GAMMA_SCREEN:
802 g = (png_ptr->screen_gamma);
803 gs = 1.0;
804 break;
805 case PNG_BACKGROUND_GAMMA_FILE:
806 g = 1.0 / (png_ptr->gamma);
807 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
808 break;
809 case PNG_BACKGROUND_GAMMA_UNIQUE:
810 g = 1.0 / (png_ptr->background_gamma);
811 gs = 1.0 / (png_ptr->background_gamma *
812 png_ptr->screen_gamma);
813 break;
814 default:
815 g = 1.0; /* back_1 */
816 gs = 1.0; /* back */
817 }
818
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -0600819 if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD)
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600820 {
821 back.red = (png_byte)png_ptr->background.red;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500822 back.green = (png_byte)png_ptr->background.green;
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600823 back.blue = (png_byte)png_ptr->background.blue;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500824 }
825 else
826 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600827 back.red = (png_byte)(pow(
828 (double)png_ptr->background.red/255, gs) * 255.0 + .5);
829 back.green = (png_byte)(pow(
830 (double)png_ptr->background.green/255, gs) * 255.0 + .5);
831 back.blue = (png_byte)(pow(
832 (double)png_ptr->background.blue/255, gs) * 255.0 + .5);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500833 }
834
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600835 back_1.red = (png_byte)(pow(
836 (double)png_ptr->background.red/255, g) * 255.0 + .5);
837 back_1.green = (png_byte)(pow(
838 (double)png_ptr->background.green/255, g) * 255.0 + .5);
839 back_1.blue = (png_byte)(pow(
840 (double)png_ptr->background.blue/255, g) * 255.0 + .5);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500841 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500842 for (i = 0; i < num_palette; i++)
843 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500844 if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
Guy Schalnate5a37791996-06-05 15:50:50 -0500845 {
846 if (png_ptr->trans[i] == 0)
847 {
848 palette[i] = back;
849 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500850 else /* if (png_ptr->trans[i] != 0xff) */
Guy Schalnate5a37791996-06-05 15:50:50 -0500851 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500852 png_byte v, w;
Guy Schalnate5a37791996-06-05 15:50:50 -0500853
854 v = png_ptr->gamma_to_1[palette[i].red];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500855 png_composite(w, v, png_ptr->trans[i], back_1.red);
Guy Schalnate5a37791996-06-05 15:50:50 -0500856 palette[i].red = png_ptr->gamma_from_1[w];
857
858 v = png_ptr->gamma_to_1[palette[i].green];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500859 png_composite(w, v, png_ptr->trans[i], back_1.green);
Guy Schalnate5a37791996-06-05 15:50:50 -0500860 palette[i].green = png_ptr->gamma_from_1[w];
861
862 v = png_ptr->gamma_to_1[palette[i].blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500863 png_composite(w, v, png_ptr->trans[i], back_1.blue);
Guy Schalnate5a37791996-06-05 15:50:50 -0500864 palette[i].blue = png_ptr->gamma_from_1[w];
865 }
866 }
867 else
868 {
869 palette[i].red = png_ptr->gamma_table[palette[i].red];
870 palette[i].green = png_ptr->gamma_table[palette[i].green];
871 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
872 }
873 }
874 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500875 /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN)*/
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600876 else
877 /* color_type != PNG_COLOR_TYPE_PALETTE */
Guy Schalnat0d580581995-07-20 02:43:20 -0500878 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500879 double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
880 double g = 1.0;
881 double gs = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500882
883 switch (png_ptr->background_gamma_type)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600884 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500885 case PNG_BACKGROUND_GAMMA_SCREEN:
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600886 g = (png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500887 gs = 1.0;
888 break;
889 case PNG_BACKGROUND_GAMMA_FILE:
890 g = 1.0 / (png_ptr->gamma);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600891 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500892 break;
893 case PNG_BACKGROUND_GAMMA_UNIQUE:
894 g = 1.0 / (png_ptr->background_gamma);
895 gs = 1.0 / (png_ptr->background_gamma *
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600896 png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500897 break;
898 }
899
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600900 if (color_type & PNG_COLOR_MASK_COLOR)
Guy Schalnat0d580581995-07-20 02:43:20 -0500901 {
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600902 /* RGB or RGBA */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600903 png_ptr->background_1.red = (png_uint_16)(pow(
Guy Schalnat0d580581995-07-20 02:43:20 -0500904 (double)png_ptr->background.red / m, g) * m + .5);
905 png_ptr->background_1.green = (png_uint_16)(pow(
906 (double)png_ptr->background.green / m, g) * m + .5);
907 png_ptr->background_1.blue = (png_uint_16)(pow(
908 (double)png_ptr->background.blue / m, g) * m + .5);
909 png_ptr->background.red = (png_uint_16)(pow(
910 (double)png_ptr->background.red / m, gs) * m + .5);
911 png_ptr->background.green = (png_uint_16)(pow(
912 (double)png_ptr->background.green / m, gs) * m + .5);
913 png_ptr->background.blue = (png_uint_16)(pow(
914 (double)png_ptr->background.blue / m, gs) * m + .5);
915 }
916 else
917 {
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600918 /* GRAY or GRAY ALPHA */
Guy Schalnat0d580581995-07-20 02:43:20 -0500919 png_ptr->background_1.gray = (png_uint_16)(pow(
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600920 (double)png_ptr->background.gray / m, g) * m + .5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500921 png_ptr->background.gray = (png_uint_16)(pow(
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600922 (double)png_ptr->background.gray / m, gs) * m + .5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500923 }
924 }
925 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500926 else
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600927 /* transformation does not include PNG_BACKGROUND */
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500928#endif /* PNG_READ_BACKGROUND_SUPPORTED */
Guy Schalnate5a37791996-06-05 15:50:50 -0500929 if (color_type == PNG_COLOR_TYPE_PALETTE)
930 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500931 png_colorp palette = png_ptr->palette;
932 int num_palette = png_ptr->num_palette;
933 int i;
Guy Schalnate5a37791996-06-05 15:50:50 -0500934
935 for (i = 0; i < num_palette; i++)
936 {
937 palette[i].red = png_ptr->gamma_table[palette[i].red];
938 palette[i].green = png_ptr->gamma_table[palette[i].green];
939 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
940 }
941 }
942 }
943#if defined(PNG_READ_BACKGROUND_SUPPORTED)
944 else
945#endif
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500946#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */
Guy Schalnate5a37791996-06-05 15:50:50 -0500947#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600948 /* No GAMMA transformation */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600949 if ((png_ptr->transformations & PNG_BACKGROUND) &&
950 (color_type == PNG_COLOR_TYPE_PALETTE))
Guy Schalnate5a37791996-06-05 15:50:50 -0500951 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500952 int i;
953 int istop = (int)png_ptr->num_trans;
Guy Schalnate5a37791996-06-05 15:50:50 -0500954 png_color back;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500955 png_colorp palette = png_ptr->palette;
Guy Schalnate5a37791996-06-05 15:50:50 -0500956
Guy Schalnate5a37791996-06-05 15:50:50 -0500957 back.red = (png_byte)png_ptr->background.red;
958 back.green = (png_byte)png_ptr->background.green;
959 back.blue = (png_byte)png_ptr->background.blue;
960
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500961 for (i = 0; i < istop; i++)
Guy Schalnate5a37791996-06-05 15:50:50 -0500962 {
963 if (png_ptr->trans[i] == 0)
964 {
965 palette[i] = back;
966 }
967 else if (png_ptr->trans[i] != 0xff)
968 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500969 /* The png_composite() macro is defined in png.h */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500970 png_composite(palette[i].red, palette[i].red,
971 png_ptr->trans[i], back.red);
972 png_composite(palette[i].green, palette[i].green,
973 png_ptr->trans[i], back.green);
974 png_composite(palette[i].blue, palette[i].blue,
975 png_ptr->trans[i], back.blue);
Guy Schalnate5a37791996-06-05 15:50:50 -0500976 }
977 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500978 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500979#endif /* PNG_READ_BACKGROUND_SUPPORTED */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500980
Guy Schalnat6d764711995-12-19 03:22:19 -0600981#if defined(PNG_READ_SHIFT_SUPPORTED)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500982 if ((png_ptr->transformations & PNG_SHIFT) &&
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600983 (color_type == PNG_COLOR_TYPE_PALETTE))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500984 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500985 png_uint_16 i;
986 png_uint_16 istop = png_ptr->num_palette;
987 int sr = 8 - png_ptr->sig_bit.red;
988 int sg = 8 - png_ptr->sig_bit.green;
989 int sb = 8 - png_ptr->sig_bit.blue;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500990
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500991 if (sr < 0 || sr > 8)
992 sr = 0;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500993 if (sg < 0 || sg > 8)
994 sg = 0;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500995 if (sb < 0 || sb > 8)
996 sb = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500997 for (i = 0; i < istop; i++)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500998 {
999 png_ptr->palette[i].red >>= sr;
1000 png_ptr->palette[i].green >>= sg;
1001 png_ptr->palette[i].blue >>= sb;
1002 }
1003 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001004#endif /* PNG_READ_SHIFT_SUPPORTED */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001005 }
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001006#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \
1007 && !defined(PNG_READ_BACKGROUND_SUPPORTED)
1008 if(png_ptr)
1009 return;
1010#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001011}
1012
Andreas Dilger47a0c421997-05-16 02:46:07 -05001013/* Modify the info structure to reflect the transformations. The
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001014 * info should be updated so a PNG file could be written with it,
1015 * assuming the transformations result in valid PNG data.
1016 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001017void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001018png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001019{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001020 png_debug(1, "in png_read_transform_info\n");
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001021#if defined(PNG_READ_EXPAND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001022 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001023 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001024 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1025 {
1026 if (png_ptr->num_trans)
1027 info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1028 else
1029 info_ptr->color_type = PNG_COLOR_TYPE_RGB;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001030 info_ptr->bit_depth = 8;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001031 info_ptr->num_trans = 0;
1032 }
1033 else
1034 {
1035 if (png_ptr->num_trans)
1036 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
1037 if (info_ptr->bit_depth < 8)
1038 info_ptr->bit_depth = 8;
1039 info_ptr->num_trans = 0;
1040 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001041 }
1042#endif
1043
1044#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1045 if (png_ptr->transformations & PNG_BACKGROUND)
1046 {
1047 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
1048 info_ptr->num_trans = 0;
1049 info_ptr->background = png_ptr->background;
1050 }
1051#endif
1052
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001053#if defined(PNG_READ_GAMMA_SUPPORTED)
1054 if (png_ptr->transformations & PNG_GAMMA)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001055 {
1056#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001057 info_ptr->gamma = png_ptr->gamma;
1058#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001059#ifdef PNG_FIXED_POINT_SUPPORTED
1060 info_ptr->int_gamma = png_ptr->int_gamma;
1061#endif
1062 }
1063#endif
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001064
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001065#if defined(PNG_READ_16_TO_8_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001066 if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001067 info_ptr->bit_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001068#endif
1069
1070#if defined(PNG_READ_DITHER_SUPPORTED)
1071 if (png_ptr->transformations & PNG_DITHER)
1072 {
1073 if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
1074 (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
1075 png_ptr->palette_lookup && info_ptr->bit_depth == 8)
1076 {
1077 info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
1078 }
1079 }
1080#endif
1081
1082#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001083 if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001084 info_ptr->bit_depth = 8;
1085#endif
1086
1087#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001088 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001089 info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
1090#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001091
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001092#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1093 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1094 info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
1095#endif
1096
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001097 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001098 info_ptr->channels = 1;
1099 else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
1100 info_ptr->channels = 3;
1101 else
1102 info_ptr->channels = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001103
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001104#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001105 if (png_ptr->transformations & PNG_STRIP_ALPHA)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001106 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001107#endif
1108
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001109 if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
1110 info_ptr->channels++;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001111
1112#if defined(PNG_READ_FILLER_SUPPORTED)
1113 /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001114 if ((png_ptr->transformations & PNG_FILLER) &&
1115 ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
1116 (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001117 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001118 info_ptr->channels++;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001119#if 0 /* if adding a true alpha channel not just filler */
1120 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
1121#endif
1122 }
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001123#endif
1124
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001125#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
1126defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001127 if(png_ptr->transformations & PNG_USER_TRANSFORM)
1128 {
1129 if(info_ptr->bit_depth < png_ptr->user_transform_depth)
1130 info_ptr->bit_depth = png_ptr->user_transform_depth;
1131 if(info_ptr->channels < png_ptr->user_transform_channels)
1132 info_ptr->channels = png_ptr->user_transform_channels;
1133 }
1134#endif
1135
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001136 info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
1137 info_ptr->bit_depth);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001138 info_ptr->rowbytes = ((info_ptr->width * info_ptr->pixel_depth + 7) >> 3);
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05001139
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001140#if !defined(PNG_READ_EXPAND_SUPPORTED)
1141 if(png_ptr)
1142 return;
1143#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001144}
1145
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001146/* Transform the row. The order of transformations is significant,
1147 * and is very touchy. If you add a transformation, take care to
1148 * decide how it fits in with the other transformations here.
1149 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001150void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001151png_do_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05001152{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001153 png_debug(1, "in png_do_read_transformations\n");
1154#if !defined(PNG_USELESS_TESTS_SUPPORTED)
1155 if (png_ptr->row_buf == NULL)
1156 {
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -05001157#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001158 char msg[50];
1159
1160 sprintf(msg, "NULL row buffer for row %ld, pass %d", png_ptr->row_number,
1161 png_ptr->pass);
1162 png_error(png_ptr, msg);
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001163#else
1164 png_error(png_ptr, "NULL row buffer");
1165#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001166 }
1167#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001168
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001169#if defined(PNG_READ_EXPAND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001170 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05001171 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001172 if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
1173 {
1174 png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
1175 png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
1176 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001177 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001178 {
1179 if (png_ptr->num_trans)
1180 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1181 &(png_ptr->trans_values));
1182 else
1183 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1184 NULL);
1185 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001186 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001187#endif
1188
1189#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
1190 if (png_ptr->transformations & PNG_STRIP_ALPHA)
1191 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
1192 PNG_FLAG_FILLER_AFTER);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001193#endif
1194
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001195#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1196 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1197 {
1198 int rgb_error =
1199 png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1);
1200 if(rgb_error)
1201 {
1202 png_ptr->rgb_to_gray_status=1;
1203 if(png_ptr->transformations == PNG_RGB_TO_GRAY_WARN)
1204 png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1205 if(png_ptr->transformations == PNG_RGB_TO_GRAY_ERR)
1206 png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1207 }
1208 }
1209#endif
1210
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001211/*
1212From Andreas Dilger e-mail to png-implement, 26 March 1998:
1213
1214 In most cases, the "simple transparency" should be done prior to doing
1215 gray-to-RGB, or you will have to test 3x as many bytes to check if a
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001216 pixel is transparent. You would also need to make sure that the
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001217 transparency information is upgraded to RGB.
1218
1219 To summarize, the current flow is:
1220 - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
1221 with background "in place" if transparent,
1222 convert to RGB if necessary
1223 - Gray + alpha -> composite with gray background and remove alpha bytes,
1224 convert to RGB if necessary
1225
1226 To support RGB backgrounds for gray images we need:
1227 - Gray + simple transparency -> convert to RGB + simple transparency, compare
1228 3 or 6 bytes and composite with background
1229 "in place" if transparent (3x compare/pixel
1230 compared to doing composite with gray bkgrnd)
1231 - Gray + alpha -> convert to RGB + alpha, composite with background and
1232 remove alpha bytes (3x float operations/pixel
1233 compared with composite on gray background)
1234
1235 Greg's change will do this. The reason it wasn't done before is for
1236 performance, as this increases the per-pixel operations. If we would check
1237 in advance if the background was gray or RGB, and position the gray-to-RGB
1238 transform appropriately, then it would save a lot of work/time.
1239 */
1240
1241#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1242 /* if gray -> RGB, do so now only if background is non-gray; else do later
1243 * for performance reasons */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001244 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001245 !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001246 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
1247#endif
1248
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001249#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001250 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1251 ((png_ptr->num_trans != 0 ) ||
1252 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
Guy Schalnat0d580581995-07-20 02:43:20 -05001253 png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001254 &(png_ptr->trans_values), &(png_ptr->background)
1255#if defined(PNG_READ_GAMMA_SUPPORTED)
1256 , &(png_ptr->background_1),
Guy Schalnat0d580581995-07-20 02:43:20 -05001257 png_ptr->gamma_table, png_ptr->gamma_from_1,
1258 png_ptr->gamma_to_1, png_ptr->gamma_16_table,
1259 png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001260 png_ptr->gamma_shift
1261#endif
1262);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001263#endif
1264
1265#if defined(PNG_READ_GAMMA_SUPPORTED)
1266 if ((png_ptr->transformations & PNG_GAMMA) &&
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001267#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1268 !((png_ptr->transformations & PNG_BACKGROUND) &&
1269 ((png_ptr->num_trans != 0) ||
1270 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
1271#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001272 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
Guy Schalnat0d580581995-07-20 02:43:20 -05001273 png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
1274 png_ptr->gamma_table, png_ptr->gamma_16_table,
1275 png_ptr->gamma_shift);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001276#endif
1277
1278#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001279 if (png_ptr->transformations & PNG_16_TO_8)
1280 png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001281#endif
1282
1283#if defined(PNG_READ_DITHER_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001284 if (png_ptr->transformations & PNG_DITHER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001285 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001286 png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
1287 png_ptr->palette_lookup, png_ptr->dither_index);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001288 if(png_ptr->row_info.rowbytes == (png_uint_32)0)
1289 png_error(png_ptr, "png_do_dither returned rowbytes=0");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001290 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001291#endif
1292
1293#if defined(PNG_READ_INVERT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001294 if (png_ptr->transformations & PNG_INVERT_MONO)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001295 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001296#endif
1297
1298#if defined(PNG_READ_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001299 if (png_ptr->transformations & PNG_SHIFT)
1300 png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
1301 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001302#endif
1303
1304#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001305 if (png_ptr->transformations & PNG_PACK)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001306 png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001307#endif
1308
1309#if defined(PNG_READ_BGR_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001310 if (png_ptr->transformations & PNG_BGR)
1311 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001312#endif
1313
Andreas Dilger47a0c421997-05-16 02:46:07 -05001314#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1315 if (png_ptr->transformations & PNG_PACKSWAP)
1316 png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1317#endif
1318
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001319#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001320 /* if gray -> RGB, do so now only if we did not do so above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001321 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
1322 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05001323 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001324#endif
1325
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001326#if defined(PNG_READ_FILLER_SUPPORTED)
1327 if (png_ptr->transformations & PNG_FILLER)
1328 png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001329 (png_uint_32)png_ptr->filler, png_ptr->flags);
1330#endif
1331
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001332#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
1333 if (png_ptr->transformations & PNG_INVERT_ALPHA)
1334 png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1335#endif
1336
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001337#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
1338 if (png_ptr->transformations & PNG_SWAP_ALPHA)
1339 png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1340#endif
1341
Andreas Dilger47a0c421997-05-16 02:46:07 -05001342#if defined(PNG_READ_SWAP_SUPPORTED)
1343 if (png_ptr->transformations & PNG_SWAP_BYTES)
1344 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001345#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001346
1347#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1348 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001349 {
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001350 if(png_ptr->read_user_transform_fn != NULL)
1351 (*(png_ptr->read_user_transform_fn)) /* user read transform function */
1352 (png_ptr, /* png_ptr */
1353 &(png_ptr->row_info), /* row_info: */
1354 /* png_uint_32 width; width of row */
1355 /* png_uint_32 rowbytes; number of bytes in row */
1356 /* png_byte color_type; color type of pixels */
1357 /* png_byte bit_depth; bit depth of samples */
1358 /* png_byte channels; number of channels (1-4) */
1359 /* png_byte pixel_depth; bits per pixel (depth*channels) */
1360 png_ptr->row_buf + 1); /* start of pixel data for row */
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001361#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001362 if(png_ptr->user_transform_depth)
1363 png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
1364 if(png_ptr->user_transform_channels)
1365 png_ptr->row_info.channels = png_ptr->user_transform_channels;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001366#endif
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001367 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
1368 png_ptr->row_info.channels);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001369 png_ptr->row_info.rowbytes = (png_ptr->row_info.width *
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001370 png_ptr->row_info.pixel_depth+7)>>3;
1371 }
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001372#endif
1373
Guy Schalnat0d580581995-07-20 02:43:20 -05001374}
1375
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001376#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001377/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
1378 * without changing the actual values. Thus, if you had a row with
1379 * a bit depth of 1, you would end up with bytes that only contained
1380 * the numbers 0 or 1. If you would rather they contain 0 and 255, use
1381 * png_do_shift() after this.
1382 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001383void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001384png_do_unpack(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001385{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001386 png_debug(1, "in png_do_unpack\n");
1387#if defined(PNG_USELESS_TESTS_SUPPORTED)
1388 if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
1389#else
1390 if (row_info->bit_depth < 8)
1391#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001392 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001393 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001394 png_uint_32 row_width=row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001395
Guy Schalnat0d580581995-07-20 02:43:20 -05001396 switch (row_info->bit_depth)
1397 {
1398 case 1:
1399 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001400 png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
1401 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001402 png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001403 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001404 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001405 *dp = (png_byte)((*sp >> shift) & 0x01);
Guy Schalnat0d580581995-07-20 02:43:20 -05001406 if (shift == 7)
1407 {
1408 shift = 0;
1409 sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001410 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001411 else
1412 shift++;
1413
1414 dp--;
1415 }
1416 break;
1417 }
1418 case 2:
1419 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001420
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001421 png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
1422 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001423 png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001424 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001425 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001426 *dp = (png_byte)((*sp >> shift) & 0x03);
Guy Schalnat0d580581995-07-20 02:43:20 -05001427 if (shift == 6)
1428 {
1429 shift = 0;
1430 sp--;
1431 }
1432 else
1433 shift += 2;
1434
1435 dp--;
1436 }
1437 break;
1438 }
1439 case 4:
1440 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001441 png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
1442 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001443 png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001444 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001445 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001446 *dp = (png_byte)((*sp >> shift) & 0x0f);
Guy Schalnat0d580581995-07-20 02:43:20 -05001447 if (shift == 4)
1448 {
1449 shift = 0;
1450 sp--;
1451 }
1452 else
1453 shift = 4;
1454
1455 dp--;
1456 }
1457 break;
1458 }
1459 }
1460 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001461 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001462 row_info->rowbytes = row_width * row_info->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001463 }
1464}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001465#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001466
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001467#if defined(PNG_READ_SHIFT_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001468/* Reverse the effects of png_do_shift. This routine merely shifts the
1469 * pixels back to their significant bits values. Thus, if you have
1470 * a row of bit depth 8, but only 5 are significant, this will shift
1471 * the values back to 0 through 31.
1472 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001473void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001474png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
Guy Schalnat0d580581995-07-20 02:43:20 -05001475{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001476 png_debug(1, "in png_do_unshift\n");
1477 if (
1478#if defined(PNG_USELESS_TESTS_SUPPORTED)
1479 row != NULL && row_info != NULL && sig_bits != NULL &&
1480#endif
1481 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001482 {
1483 int shift[4];
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001484 int channels = 0;
1485 int c;
1486 png_uint_16 value = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001487 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001488
Guy Schalnat0d580581995-07-20 02:43:20 -05001489 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
1490 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001491 shift[channels++] = row_info->bit_depth - sig_bits->red;
1492 shift[channels++] = row_info->bit_depth - sig_bits->green;
1493 shift[channels++] = row_info->bit_depth - sig_bits->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05001494 }
1495 else
1496 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001497 shift[channels++] = row_info->bit_depth - sig_bits->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05001498 }
1499 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
1500 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001501 shift[channels++] = row_info->bit_depth - sig_bits->alpha;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001502 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001503
Andreas Dilger47a0c421997-05-16 02:46:07 -05001504 for (c = 0; c < channels; c++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001505 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001506 if (shift[c] <= 0)
1507 shift[c] = 0;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001508 else
1509 value = 1;
1510 }
Guy Schalnat0f716451995-11-28 11:22:13 -06001511
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001512 if (!value)
1513 return;
Guy Schalnat0f716451995-11-28 11:22:13 -06001514
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001515 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05001516 {
1517 case 2:
1518 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001519 png_bytep bp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001520 png_uint_32 i;
1521 png_uint_32 istop = row_info->rowbytes;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001522
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001523 for (bp = row, i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001524 {
1525 *bp >>= 1;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001526 *bp++ &= 0x55;
Guy Schalnat0d580581995-07-20 02:43:20 -05001527 }
1528 break;
1529 }
1530 case 4:
1531 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001532 png_bytep bp = row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001533 png_uint_32 i;
1534 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001535 png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
1536 (png_byte)((int)0xf >> shift[0]));
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001537
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001538 for (i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001539 {
1540 *bp >>= shift[0];
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001541 *bp++ &= mask;
Guy Schalnat0d580581995-07-20 02:43:20 -05001542 }
1543 break;
1544 }
1545 case 8:
1546 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001547 png_bytep bp = row;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001548 png_uint_32 i;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001549 png_uint_32 istop = row_width * channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001550
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001551 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001552 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001553 *bp++ >>= shift[i%channels];
Guy Schalnat0d580581995-07-20 02:43:20 -05001554 }
1555 break;
1556 }
1557 case 16:
1558 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001559 png_bytep bp = row;
1560 png_uint_32 i;
1561 png_uint_32 istop = channels * row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001562
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001563 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001564 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001565 value = (png_uint_16)((*bp << 8) + *(bp + 1));
1566 value >>= shift[i%channels];
1567 *bp++ = (png_byte)(value >> 8);
1568 *bp++ = (png_byte)(value & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05001569 }
1570 break;
1571 }
1572 }
1573 }
1574}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001575#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001576
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001577#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001578/* chop rows of bit depth 16 down to 8 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001579void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001580png_do_chop(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001581{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001582 png_debug(1, "in png_do_chop\n");
1583#if defined(PNG_USELESS_TESTS_SUPPORTED)
1584 if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
1585#else
1586 if (row_info->bit_depth == 16)
1587#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001588 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001589 png_bytep sp = row;
1590 png_bytep dp = row;
1591 png_uint_32 i;
1592 png_uint_32 istop = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001593
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001594 for (i = 0; i<istop; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001595 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001596#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001597 /* This does a more accurate scaling of the 16-bit color
1598 * value, rather than a simple low-byte truncation.
1599 *
1600 * What the ideal calculation should be:
1601 * *dp = (((((png_uint_32)(*sp) << 8) |
1602 * (png_uint_32)(*(sp + 1))) * 255 + 127) / (png_uint_32)65535L;
1603 *
1604 * GRR: no, I think this is what it really should be:
1605 * *dp = (((((png_uint_32)(*sp) << 8) |
1606 * (png_uint_32)(*(sp + 1))) + 128L) / (png_uint_32)257L;
1607 *
1608 * GRR: here's the exact calculation with shifts:
1609 * temp = (((png_uint_32)(*sp) << 8) | (png_uint_32)(*(sp + 1))) + 128L;
1610 * *dp = (temp - (temp >> 8)) >> 8;
1611 *
1612 * Approximate calculation with shift/add instead of multiply/divide:
1613 * *dp = ((((png_uint_32)(*sp) << 8) |
1614 * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
1615 *
1616 * What we actually do to avoid extra shifting and conversion:
1617 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001618
Andreas Dilger47a0c421997-05-16 02:46:07 -05001619 *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
1620#else
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001621 /* Simply discard the low order byte */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001622 *dp = *sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001623#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001624 }
1625 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001626 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001627 row_info->rowbytes = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001628 }
1629}
1630#endif
1631
1632#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001633void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001634png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
1635{
1636 png_debug(1, "in png_do_read_swap_alpha\n");
1637#if defined(PNG_USELESS_TESTS_SUPPORTED)
1638 if (row != NULL && row_info != NULL)
1639#endif
1640 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001641 png_uint_32 row_width = row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001642 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1643 {
1644 /* This converts from RGBA to ARGB */
1645 if (row_info->bit_depth == 8)
1646 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001647 png_bytep sp = row + row_info->rowbytes;
1648 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001649 png_byte save;
1650 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001651
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001652 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001653 {
1654 save = *(--sp);
1655 *(--dp) = *(--sp);
1656 *(--dp) = *(--sp);
1657 *(--dp) = *(--sp);
1658 *(--dp) = save;
1659 }
1660 }
1661 /* This converts from RRGGBBAA to AARRGGBB */
1662 else
1663 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001664 png_bytep sp = row + row_info->rowbytes;
1665 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001666 png_byte save[2];
1667 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001668
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001669 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001670 {
1671 save[0] = *(--sp);
1672 save[1] = *(--sp);
1673 *(--dp) = *(--sp);
1674 *(--dp) = *(--sp);
1675 *(--dp) = *(--sp);
1676 *(--dp) = *(--sp);
1677 *(--dp) = *(--sp);
1678 *(--dp) = *(--sp);
1679 *(--dp) = save[0];
1680 *(--dp) = save[1];
1681 }
1682 }
1683 }
1684 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1685 {
1686 /* This converts from GA to AG */
1687 if (row_info->bit_depth == 8)
1688 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001689 png_bytep sp = row + row_info->rowbytes;
1690 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001691 png_byte save;
1692 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001693
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001694 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001695 {
1696 save = *(--sp);
1697 *(--dp) = *(--sp);
1698 *(--dp) = save;
1699 }
1700 }
1701 /* This converts from GGAA to AAGG */
1702 else
1703 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001704 png_bytep sp = row + row_info->rowbytes;
1705 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001706 png_byte save[2];
1707 png_uint_32 i;
1708
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001709 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001710 {
1711 save[0] = *(--sp);
1712 save[1] = *(--sp);
1713 *(--dp) = *(--sp);
1714 *(--dp) = *(--sp);
1715 *(--dp) = save[0];
1716 *(--dp) = save[1];
1717 }
1718 }
1719 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001720 }
1721}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001722#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001723
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001724#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001725void /* PRIVATE */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001726png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
1727{
1728 png_debug(1, "in png_do_read_invert_alpha\n");
1729#if defined(PNG_USELESS_TESTS_SUPPORTED)
1730 if (row != NULL && row_info != NULL)
1731#endif
1732 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001733 png_uint_32 row_width = row_info->width;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001734 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1735 {
1736 /* This inverts the alpha channel in RGBA */
1737 if (row_info->bit_depth == 8)
1738 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001739 png_bytep sp = row + row_info->rowbytes;
1740 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001741 png_uint_32 i;
1742
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001743 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001744 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001745 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001746
1747/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001748 *(--dp) = *(--sp);
1749 *(--dp) = *(--sp);
1750 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001751 We can replace it with:
1752*/
1753 sp-=3;
1754 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001755 }
1756 }
1757 /* This inverts the alpha channel in RRGGBBAA */
1758 else
1759 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001760 png_bytep sp = row + row_info->rowbytes;
1761 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001762 png_uint_32 i;
1763
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001764 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001765 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001766 *(--dp) = (png_byte)(255 - *(--sp));
1767 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001768
1769/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001770 *(--dp) = *(--sp);
1771 *(--dp) = *(--sp);
1772 *(--dp) = *(--sp);
1773 *(--dp) = *(--sp);
1774 *(--dp) = *(--sp);
1775 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001776 We can replace it with:
1777*/
1778 sp-=6;
1779 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001780 }
1781 }
1782 }
1783 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1784 {
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001785 /* This inverts the alpha channel in GA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001786 if (row_info->bit_depth == 8)
1787 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001788 png_bytep sp = row + row_info->rowbytes;
1789 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001790 png_uint_32 i;
1791
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001792 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001793 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001794 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001795 *(--dp) = *(--sp);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001796 }
1797 }
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001798 /* This inverts the alpha channel in GGAA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001799 else
1800 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001801 png_bytep sp = row + row_info->rowbytes;
1802 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001803 png_uint_32 i;
1804
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001805 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001806 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001807 *(--dp) = (png_byte)(255 - *(--sp));
1808 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001809/*
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001810 *(--dp) = *(--sp);
1811 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001812*/
1813 sp-=2;
1814 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001815 }
1816 }
1817 }
1818 }
1819}
1820#endif
1821
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001822#if defined(PNG_READ_FILLER_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001823/* Add filler channel if we have RGB color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001824void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001825png_do_read_filler(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001826 png_uint_32 filler, png_uint_32 flags)
Guy Schalnat0d580581995-07-20 02:43:20 -05001827{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001828 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001829 png_uint_32 row_width = row_info->width;
1830
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001831 png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001832 png_byte lo_filler = (png_byte)(filler & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001833
1834 png_debug(1, "in png_do_read_filler\n");
1835 if (
1836#if defined(PNG_USELESS_TESTS_SUPPORTED)
1837 row != NULL && row_info != NULL &&
1838#endif
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001839 row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001840 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001841 if(row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05001842 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001843 /* This changes the data from G to GX */
1844 if (flags & PNG_FLAG_FILLER_AFTER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001845 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001846 png_bytep sp = row + (png_size_t)row_width;
1847 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001848 for (i = 1; i < row_width; i++)
1849 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001850 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001851 *(--dp) = *(--sp);
1852 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001853 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001854 row_info->channels = 2;
1855 row_info->pixel_depth = 16;
1856 row_info->rowbytes = row_width * 2;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001857 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001858 /* This changes the data from G to XG */
1859 else
1860 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001861 png_bytep sp = row + (png_size_t)row_width;
1862 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001863 for (i = 0; i < row_width; i++)
1864 {
1865 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001866 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001867 }
1868 row_info->channels = 2;
1869 row_info->pixel_depth = 16;
1870 row_info->rowbytes = row_width * 2;
1871 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001872 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001873 else if(row_info->bit_depth == 16)
1874 {
1875 /* This changes the data from GG to GGXX */
1876 if (flags & PNG_FLAG_FILLER_AFTER)
1877 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001878 png_bytep sp = row + (png_size_t)row_width;
1879 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001880 for (i = 1; i < row_width; i++)
1881 {
1882 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001883 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001884 *(--dp) = *(--sp);
1885 *(--dp) = *(--sp);
1886 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001887 *(--dp) = hi_filler;
1888 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001889 row_info->channels = 2;
1890 row_info->pixel_depth = 32;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001891 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001892 }
1893 /* This changes the data from GG to XXGG */
1894 else
1895 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001896 png_bytep sp = row + (png_size_t)row_width;
1897 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001898 for (i = 0; i < row_width; i++)
1899 {
1900 *(--dp) = *(--sp);
1901 *(--dp) = *(--sp);
1902 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001903 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001904 }
1905 row_info->channels = 2;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001906 row_info->pixel_depth = 32;
1907 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001908 }
1909 }
1910 } /* COLOR_TYPE == GRAY */
1911 else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
1912 {
1913 if(row_info->bit_depth == 8)
1914 {
1915 /* This changes the data from RGB to RGBX */
1916 if (flags & PNG_FLAG_FILLER_AFTER)
1917 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001918 png_bytep sp = row + (png_size_t)row_width * 3;
1919 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001920 for (i = 1; i < row_width; i++)
1921 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001922 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001923 *(--dp) = *(--sp);
1924 *(--dp) = *(--sp);
1925 *(--dp) = *(--sp);
1926 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001927 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001928 row_info->channels = 4;
1929 row_info->pixel_depth = 32;
1930 row_info->rowbytes = row_width * 4;
1931 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001932 /* This changes the data from RGB to XRGB */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001933 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001934 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001935 png_bytep sp = row + (png_size_t)row_width * 3;
1936 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001937 for (i = 0; i < row_width; i++)
1938 {
1939 *(--dp) = *(--sp);
1940 *(--dp) = *(--sp);
1941 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001942 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001943 }
1944 row_info->channels = 4;
1945 row_info->pixel_depth = 32;
1946 row_info->rowbytes = row_width * 4;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001947 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001948 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001949 else if(row_info->bit_depth == 16)
1950 {
1951 /* This changes the data from RRGGBB to RRGGBBXX */
1952 if (flags & PNG_FLAG_FILLER_AFTER)
1953 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001954 png_bytep sp = row + (png_size_t)row_width * 3;
1955 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001956 for (i = 1; i < row_width; i++)
1957 {
1958 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001959 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001960 *(--dp) = *(--sp);
1961 *(--dp) = *(--sp);
1962 *(--dp) = *(--sp);
1963 *(--dp) = *(--sp);
1964 *(--dp) = *(--sp);
1965 *(--dp) = *(--sp);
1966 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001967 *(--dp) = hi_filler;
1968 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001969 row_info->channels = 4;
1970 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001971 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001972 }
1973 /* This changes the data from RRGGBB to XXRRGGBB */
1974 else
1975 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001976 png_bytep sp = row + (png_size_t)row_width * 3;
1977 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001978 for (i = 0; i < row_width; i++)
1979 {
1980 *(--dp) = *(--sp);
1981 *(--dp) = *(--sp);
1982 *(--dp) = *(--sp);
1983 *(--dp) = *(--sp);
1984 *(--dp) = *(--sp);
1985 *(--dp) = *(--sp);
1986 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001987 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001988 }
1989 row_info->channels = 4;
1990 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001991 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001992 }
1993 }
1994 } /* COLOR_TYPE == RGB */
Guy Schalnat0d580581995-07-20 02:43:20 -05001995}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001996#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001997
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001998#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001999/* expand grayscale files to RGB, with or without alpha */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002000void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002001png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05002002{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002003 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002004 png_uint_32 row_width = row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06002005
Andreas Dilger47a0c421997-05-16 02:46:07 -05002006 png_debug(1, "in png_do_gray_to_rgb\n");
2007 if (row_info->bit_depth >= 8 &&
2008#if defined(PNG_USELESS_TESTS_SUPPORTED)
2009 row != NULL && row_info != NULL &&
2010#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002011 !(row_info->color_type & PNG_COLOR_MASK_COLOR))
2012 {
2013 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
2014 {
2015 if (row_info->bit_depth == 8)
2016 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002017 png_bytep sp = row + (png_size_t)row_width - 1;
2018 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002019 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002020 {
2021 *(dp--) = *sp;
2022 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002023 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002024 }
2025 }
2026 else
2027 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002028 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2029 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002030 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002031 {
2032 *(dp--) = *sp;
2033 *(dp--) = *(sp - 1);
2034 *(dp--) = *sp;
2035 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002036 *(dp--) = *(sp--);
2037 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002038 }
2039 }
2040 }
2041 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2042 {
2043 if (row_info->bit_depth == 8)
2044 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002045 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2046 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002047 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002048 {
2049 *(dp--) = *(sp--);
2050 *(dp--) = *sp;
2051 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002052 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002053 }
2054 }
2055 else
2056 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002057 png_bytep sp = row + (png_size_t)row_width * 4 - 1;
2058 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002059 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002060 {
2061 *(dp--) = *(sp--);
2062 *(dp--) = *(sp--);
2063 *(dp--) = *sp;
2064 *(dp--) = *(sp - 1);
2065 *(dp--) = *sp;
2066 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002067 *(dp--) = *(sp--);
2068 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002069 }
2070 }
2071 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002072 row_info->channels += (png_byte)2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002073 row_info->color_type |= PNG_COLOR_MASK_COLOR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002074 row_info->pixel_depth = (png_byte)(row_info->channels *
2075 row_info->bit_depth);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002076 row_info->rowbytes = ((row_width *
Guy Schalnat0d580581995-07-20 02:43:20 -05002077 row_info->pixel_depth + 7) >> 3);
2078 }
2079}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002080#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002081
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002082#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002083/* reduce RGB files to grayscale, with or without alpha
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002084 * using the equation given in Poynton's ColorFAQ at
2085 * <http://www.inforamp.net/~poynton/>
2086 * Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net
2087 *
2088 * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
2089 *
2090 * We approximate this with
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002091 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002092 * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002093 *
2094 * which can be expressed with integers as
2095 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002096 * Y = (6969 * R + 23434 * G + 2365 * B)/32768
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002097 *
2098 * The calculation is to be done in a linear colorspace.
2099 *
2100 * Other integer coefficents can be used via png_set_rgb_to_gray().
2101 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002102int /* PRIVATE */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002103png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
2104
2105{
2106 png_uint_32 i;
2107
2108 png_uint_32 row_width = row_info->width;
2109 int rgb_error = 0;
2110
2111 png_debug(1, "in png_do_rgb_to_gray\n");
2112 if (
2113#if defined(PNG_USELESS_TESTS_SUPPORTED)
2114 row != NULL && row_info != NULL &&
2115#endif
2116 (row_info->color_type & PNG_COLOR_MASK_COLOR))
2117 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002118 png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
2119 png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
2120 png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002121
2122 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2123 {
2124 if (row_info->bit_depth == 8)
2125 {
2126#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2127 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2128 {
2129 png_bytep sp = row;
2130 png_bytep dp = row;
2131
2132 for (i = 0; i < row_width; i++)
2133 {
2134 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2135 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2136 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
2137 if(red != green || red != blue)
2138 {
2139 rgb_error |= 1;
2140 *(dp++) = png_ptr->gamma_from_1[
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002141 (rc*red+gc*green+bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002142 }
2143 else
2144 *(dp++) = *(sp-1);
2145 }
2146 }
2147 else
2148#endif
2149 {
2150 png_bytep sp = row;
2151 png_bytep dp = row;
2152 for (i = 0; i < row_width; i++)
2153 {
2154 png_byte red = *(sp++);
2155 png_byte green = *(sp++);
2156 png_byte blue = *(sp++);
2157 if(red != green || red != blue)
2158 {
2159 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002160 *(dp++) = (png_byte)((rc*red+gc*green+bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002161 }
2162 else
2163 *(dp++) = *(sp-1);
2164 }
2165 }
2166 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002167
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002168 else /* RGB bit_depth == 16 */
2169 {
2170#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2171 if (png_ptr->gamma_16_to_1 != NULL &&
2172 png_ptr->gamma_16_from_1 != NULL)
2173 {
2174 png_bytep sp = row;
2175 png_bytep dp = row;
2176 for (i = 0; i < row_width; i++)
2177 {
2178 png_uint_16 red, green, blue, w;
2179
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002180 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2181 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2182 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002183
2184 if(red == green && red == blue)
2185 w = red;
2186 else
2187 {
2188 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2189 png_ptr->gamma_shift][red>>8];
2190 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2191 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002192 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002193 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002194 png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002195 + bc*blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002196 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2197 png_ptr->gamma_shift][gray16 >> 8];
2198 rgb_error |= 1;
2199 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002200
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002201 *(dp++) = (png_byte)((w>>8) & 0xff);
2202 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002203 }
2204 }
2205 else
2206#endif
2207 {
2208 png_bytep sp = row;
2209 png_bytep dp = row;
2210 for (i = 0; i < row_width; i++)
2211 {
2212 png_uint_16 red, green, blue, gray16;
2213
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002214 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2215 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2216 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002217
2218 if(red != green || red != blue)
2219 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002220 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002221 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2222 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002223 }
2224 }
2225 }
2226 }
2227 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2228 {
2229 if (row_info->bit_depth == 8)
2230 {
2231#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2232 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2233 {
2234 png_bytep sp = row;
2235 png_bytep dp = row;
2236 for (i = 0; i < row_width; i++)
2237 {
2238 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2239 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2240 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
2241 if(red != green || red != blue)
2242 rgb_error |= 1;
2243 *(dp++) = png_ptr->gamma_from_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002244 [(rc*red + gc*green + bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002245 *(dp++) = *(sp++); /* alpha */
2246 }
2247 }
2248 else
2249#endif
2250 {
2251 png_bytep sp = row;
2252 png_bytep dp = row;
2253 for (i = 0; i < row_width; i++)
2254 {
2255 png_byte red = *(sp++);
2256 png_byte green = *(sp++);
2257 png_byte blue = *(sp++);
2258 if(red != green || red != blue)
2259 rgb_error |= 1;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002260 *(dp++) = (png_byte)((gc*red + gc*green + bc*blue)>>8);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002261 *(dp++) = *(sp++); /* alpha */
2262 }
2263 }
2264 }
2265 else /* RGBA bit_depth == 16 */
2266 {
2267#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2268 if (png_ptr->gamma_16_to_1 != NULL &&
2269 png_ptr->gamma_16_from_1 != NULL)
2270 {
2271 png_bytep sp = row;
2272 png_bytep dp = row;
2273 for (i = 0; i < row_width; i++)
2274 {
2275 png_uint_16 red, green, blue, w;
2276
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002277 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2278 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2279 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002280
2281 if(red == green && red == blue)
2282 w = red;
2283 else
2284 {
2285 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2286 png_ptr->gamma_shift][red>>8];
2287 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2288 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002289 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002290 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002291 png_uint_16 gray16 = (png_uint_16)((rc * red_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002292 + gc * green_1 + bc * blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002293 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2294 png_ptr->gamma_shift][gray16 >> 8];
2295 rgb_error |= 1;
2296 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002297
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002298 *(dp++) = (png_byte)((w>>8) & 0xff);
2299 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002300 *(dp++) = *(sp++); /* alpha */
2301 *(dp++) = *(sp++);
2302 }
2303 }
2304 else
2305#endif
2306 {
2307 png_bytep sp = row;
2308 png_bytep dp = row;
2309 for (i = 0; i < row_width; i++)
2310 {
2311 png_uint_16 red, green, blue, gray16;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002312 red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2313 green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2314 blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002315 if(red != green || red != blue)
2316 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002317 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002318 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2319 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002320 *(dp++) = *(sp++); /* alpha */
2321 *(dp++) = *(sp++);
2322 }
2323 }
2324 }
2325 }
2326 row_info->channels -= (png_byte)2;
2327 row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
2328 row_info->pixel_depth = (png_byte)(row_info->channels *
2329 row_info->bit_depth);
2330 row_info->rowbytes = ((row_width *
2331 row_info->pixel_depth + 7) >> 3);
2332 }
2333 return rgb_error;
2334}
2335#endif
2336
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002337/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
2338 * large of png_color. This lets grayscale images be treated as
2339 * paletted. Most useful for gamma correction and simplification
2340 * of code.
2341 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002342void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002343png_build_grayscale_palette(int bit_depth, png_colorp palette)
Guy Schalnat0d580581995-07-20 02:43:20 -05002344{
2345 int num_palette;
2346 int color_inc;
2347 int i;
2348 int v;
2349
Andreas Dilger47a0c421997-05-16 02:46:07 -05002350 png_debug(1, "in png_do_build_grayscale_palette\n");
2351 if (palette == NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002352 return;
2353
2354 switch (bit_depth)
2355 {
2356 case 1:
2357 num_palette = 2;
2358 color_inc = 0xff;
2359 break;
2360 case 2:
2361 num_palette = 4;
2362 color_inc = 0x55;
2363 break;
2364 case 4:
2365 num_palette = 16;
2366 color_inc = 0x11;
2367 break;
2368 case 8:
2369 num_palette = 256;
2370 color_inc = 1;
2371 break;
2372 default:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002373 num_palette = 0;
Guy Schalnat69b14481996-01-10 02:56:49 -06002374 color_inc = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002375 break;
2376 }
2377
2378 for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
2379 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002380 palette[i].red = (png_byte)v;
2381 palette[i].green = (png_byte)v;
2382 palette[i].blue = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002383 }
2384}
2385
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002386/* This function is currently unused. Do we really need it? */
2387#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002388void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002389png_correct_palette(png_structp png_ptr, png_colorp palette,
Guy Schalnat0d580581995-07-20 02:43:20 -05002390 int num_palette)
2391{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002392 png_debug(1, "in png_correct_palette\n");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002393#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
2394 defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002395 if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND))
Guy Schalnat0d580581995-07-20 02:43:20 -05002396 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002397 png_color back, back_1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002398
Andreas Dilger47a0c421997-05-16 02:46:07 -05002399 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
2400 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002401 back.red = png_ptr->gamma_table[png_ptr->background.red];
2402 back.green = png_ptr->gamma_table[png_ptr->background.green];
2403 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
Guy Schalnat0d580581995-07-20 02:43:20 -05002404
Guy Schalnate5a37791996-06-05 15:50:50 -05002405 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
2406 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
2407 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002408 }
2409 else
2410 {
2411 double g;
Guy Schalnat0d580581995-07-20 02:43:20 -05002412
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06002413 g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002414
2415 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
2416 fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
Guy Schalnat0d580581995-07-20 02:43:20 -05002417 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002418 back.red = png_ptr->background.red;
2419 back.green = png_ptr->background.green;
2420 back.blue = png_ptr->background.blue;
2421 }
2422 else
2423 {
2424 back.red =
2425 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2426 255.0 + 0.5);
2427 back.green =
2428 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2429 255.0 + 0.5);
2430 back.blue =
2431 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2432 255.0 + 0.5);
2433 }
2434
2435 g = 1.0 / png_ptr->background_gamma;
2436
2437 back_1.red =
2438 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2439 255.0 + 0.5);
2440 back_1.green =
2441 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2442 255.0 + 0.5);
2443 back_1.blue =
2444 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2445 255.0 + 0.5);
2446 }
2447
2448 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2449 {
2450 png_uint_32 i;
2451
2452 for (i = 0; i < (png_uint_32)num_palette; i++)
2453 {
2454 if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -05002455 {
2456 palette[i] = back;
2457 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002458 else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002459 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002460 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05002461
2462 v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002463 png_composite(w, v, png_ptr->trans[i], back_1.red);
2464 palette[i].red = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002465
2466 v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002467 png_composite(w, v, png_ptr->trans[i], back_1.green);
2468 palette[i].green = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002469
2470 v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002471 png_composite(w, v, png_ptr->trans[i], back_1.blue);
2472 palette[i].blue = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002473 }
2474 else
2475 {
2476 palette[i].red = png_ptr->gamma_table[palette[i].red];
2477 palette[i].green = png_ptr->gamma_table[palette[i].green];
2478 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2479 }
2480 }
2481 }
2482 else
2483 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002484 int i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002485
2486 for (i = 0; i < num_palette; i++)
2487 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002488 if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002489 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002490 palette[i] = back;
Guy Schalnat0d580581995-07-20 02:43:20 -05002491 }
2492 else
2493 {
2494 palette[i].red = png_ptr->gamma_table[palette[i].red];
2495 palette[i].green = png_ptr->gamma_table[palette[i].green];
2496 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2497 }
2498 }
2499 }
2500 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002501 else
2502#endif
2503#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002504 if (png_ptr->transformations & PNG_GAMMA)
Guy Schalnat0d580581995-07-20 02:43:20 -05002505 {
2506 int i;
2507
2508 for (i = 0; i < num_palette; i++)
2509 {
2510 palette[i].red = png_ptr->gamma_table[palette[i].red];
2511 palette[i].green = png_ptr->gamma_table[palette[i].green];
2512 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2513 }
2514 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002515#if defined(PNG_READ_BACKGROUND_SUPPORTED)
2516 else
2517#endif
2518#endif
2519#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002520 if (png_ptr->transformations & PNG_BACKGROUND)
Guy Schalnat0d580581995-07-20 02:43:20 -05002521 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002522 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05002523 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002524 png_color back;
Guy Schalnat0d580581995-07-20 02:43:20 -05002525
Guy Schalnate5a37791996-06-05 15:50:50 -05002526 back.red = (png_byte)png_ptr->background.red;
2527 back.green = (png_byte)png_ptr->background.green;
2528 back.blue = (png_byte)png_ptr->background.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002529
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06002530 for (i = 0; i < (int)png_ptr->num_trans; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002531 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002532 if (png_ptr->trans[i] == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -05002533 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002534 palette[i].red = back.red;
2535 palette[i].green = back.green;
2536 palette[i].blue = back.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002537 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002538 else if (png_ptr->trans[i] != 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002539 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002540 png_composite(palette[i].red, png_ptr->palette[i].red,
2541 png_ptr->trans[i], back.red);
2542 png_composite(palette[i].green, png_ptr->palette[i].green,
2543 png_ptr->trans[i], back.green);
2544 png_composite(palette[i].blue, png_ptr->palette[i].blue,
2545 png_ptr->trans[i], back.blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05002546 }
2547 }
2548 }
2549 else /* assume grayscale palette (what else could it be?) */
2550 {
2551 int i;
2552
2553 for (i = 0; i < num_palette; i++)
2554 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002555 if (i == (png_byte)png_ptr->trans_values.gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002556 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002557 palette[i].red = (png_byte)png_ptr->background.red;
2558 palette[i].green = (png_byte)png_ptr->background.green;
2559 palette[i].blue = (png_byte)png_ptr->background.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002560 }
2561 }
2562 }
2563 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002564#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002565}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002566#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002567
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002568#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002569/* Replace any alpha or transparency with the supplied background color.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002570 * "background" is already in the screen gamma, while "background_1" is
2571 * at a gamma of 1.0. Paletted files have already been taken care of.
2572 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002573void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002574png_do_background(png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002575 png_color_16p trans_values, png_color_16p background
2576#if defined(PNG_READ_GAMMA_SUPPORTED)
2577 , png_color_16p background_1,
Guy Schalnat6d764711995-12-19 03:22:19 -06002578 png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002579 png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002580 png_uint_16pp gamma_16_to_1, int gamma_shift
2581#endif
2582 )
Guy Schalnat0d580581995-07-20 02:43:20 -05002583{
Guy Schalnat6d764711995-12-19 03:22:19 -06002584 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002585 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002586 png_uint_32 row_width=row_info->width;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002587 int shift;
Guy Schalnate5a37791996-06-05 15:50:50 -05002588
Andreas Dilger47a0c421997-05-16 02:46:07 -05002589 png_debug(1, "in png_do_background\n");
2590 if (background != NULL &&
2591#if defined(PNG_USELESS_TESTS_SUPPORTED)
2592 row != NULL && row_info != NULL &&
2593#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002594 (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
Andreas Dilger47a0c421997-05-16 02:46:07 -05002595 (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
Guy Schalnat0d580581995-07-20 02:43:20 -05002596 {
2597 switch (row_info->color_type)
2598 {
2599 case PNG_COLOR_TYPE_GRAY:
2600 {
2601 switch (row_info->bit_depth)
2602 {
2603 case 1:
2604 {
Guy Schalnat0d580581995-07-20 02:43:20 -05002605 sp = row;
2606 shift = 7;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002607 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002608 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002609 if ((png_uint_16)((*sp >> shift) & 0x01)
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002610 == trans_values->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002611 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002612 *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2613 *sp |= (png_byte)(background->gray << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002614 }
2615 if (!shift)
2616 {
2617 shift = 7;
2618 sp++;
2619 }
2620 else
2621 shift--;
2622 }
2623 break;
2624 }
2625 case 2:
2626 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002627#if defined(PNG_READ_GAMMA_SUPPORTED)
2628 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002629 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002630 sp = row;
2631 shift = 6;
2632 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002633 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002634 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002635 == trans_values->gray)
2636 {
2637 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2638 *sp |= (png_byte)(background->gray << shift);
2639 }
2640 else
2641 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002642 png_byte p = (png_byte)((*sp >> shift) & 0x03);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002643 png_byte g = (png_byte)((gamma_table [p | (p << 2) |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002644 (p << 4) | (p << 6)] >> 6) & 0x03);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002645 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2646 *sp |= (png_byte)(g << shift);
2647 }
2648 if (!shift)
2649 {
2650 shift = 6;
2651 sp++;
2652 }
2653 else
2654 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002655 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002656 }
2657 else
2658#endif
2659 {
2660 sp = row;
2661 shift = 6;
2662 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002663 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002664 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002665 == trans_values->gray)
2666 {
2667 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2668 *sp |= (png_byte)(background->gray << shift);
2669 }
2670 if (!shift)
2671 {
2672 shift = 6;
2673 sp++;
2674 }
2675 else
2676 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002677 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002678 }
2679 break;
2680 }
2681 case 4:
2682 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002683#if defined(PNG_READ_GAMMA_SUPPORTED)
2684 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002685 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002686 sp = row;
2687 shift = 4;
2688 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002689 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002690 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002691 == trans_values->gray)
2692 {
2693 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2694 *sp |= (png_byte)(background->gray << shift);
2695 }
2696 else
2697 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002698 png_byte p = (png_byte)((*sp >> shift) & 0x0f);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002699 png_byte g = (png_byte)((gamma_table[p |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002700 (p << 4)] >> 4) & 0x0f);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002701 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2702 *sp |= (png_byte)(g << shift);
2703 }
2704 if (!shift)
2705 {
2706 shift = 4;
2707 sp++;
2708 }
2709 else
2710 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002711 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002712 }
2713 else
2714#endif
2715 {
2716 sp = row;
2717 shift = 4;
2718 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002719 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002720 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002721 == trans_values->gray)
2722 {
2723 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2724 *sp |= (png_byte)(background->gray << shift);
2725 }
2726 if (!shift)
2727 {
2728 shift = 4;
2729 sp++;
2730 }
2731 else
2732 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002733 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002734 }
2735 break;
2736 }
2737 case 8:
2738 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002739#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002740 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002741 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002742 sp = row;
2743 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002744 {
2745 if (*sp == trans_values->gray)
2746 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002747 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002748 }
2749 else
2750 {
2751 *sp = gamma_table[*sp];
2752 }
2753 }
2754 }
2755 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002756#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002757 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002758 sp = row;
2759 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002760 {
2761 if (*sp == trans_values->gray)
2762 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002763 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002764 }
2765 }
2766 }
2767 break;
2768 }
2769 case 16:
2770 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002771#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002772 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002773 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002774 sp = row;
2775 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002776 {
2777 png_uint_16 v;
2778
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002779 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05002780 if (v == trans_values->gray)
2781 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002782 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002783 *sp = (png_byte)((background->gray >> 8) & 0xff);
2784 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002785 }
2786 else
2787 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002788 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002789 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002790 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002791 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002792 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002793 }
2794 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002795#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002796 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002797 sp = row;
2798 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002799 {
2800 png_uint_16 v;
2801
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002802 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05002803 if (v == trans_values->gray)
2804 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002805 *sp = (png_byte)((background->gray >> 8) & 0xff);
2806 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002807 }
2808 }
2809 }
2810 break;
2811 }
2812 }
2813 break;
2814 }
2815 case PNG_COLOR_TYPE_RGB:
2816 {
2817 if (row_info->bit_depth == 8)
2818 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002819#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002820 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002821 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002822 sp = row;
2823 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002824 {
2825 if (*sp == trans_values->red &&
2826 *(sp + 1) == trans_values->green &&
2827 *(sp + 2) == trans_values->blue)
2828 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002829 *sp = (png_byte)background->red;
2830 *(sp + 1) = (png_byte)background->green;
2831 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002832 }
2833 else
2834 {
2835 *sp = gamma_table[*sp];
2836 *(sp + 1) = gamma_table[*(sp + 1)];
2837 *(sp + 2) = gamma_table[*(sp + 2)];
2838 }
2839 }
2840 }
2841 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002842#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002843 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002844 sp = row;
2845 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002846 {
2847 if (*sp == trans_values->red &&
2848 *(sp + 1) == trans_values->green &&
2849 *(sp + 2) == trans_values->blue)
2850 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002851 *sp = (png_byte)background->red;
2852 *(sp + 1) = (png_byte)background->green;
2853 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002854 }
2855 }
2856 }
2857 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002858 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05002859 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002860#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002861 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002862 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002863 sp = row;
2864 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002865 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002866 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2867 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2868 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05002869 if (r == trans_values->red && g == trans_values->green &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002870 b == trans_values->blue)
2871 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002872 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002873 *sp = (png_byte)((background->red >> 8) & 0xff);
2874 *(sp + 1) = (png_byte)(background->red & 0xff);
2875 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2876 *(sp + 3) = (png_byte)(background->green & 0xff);
2877 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2878 *(sp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002879 }
2880 else
2881 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002882 png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002883 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002884 *(sp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002885 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002886 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
2887 *(sp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002888 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002889 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
2890 *(sp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002891 }
2892 }
2893 }
2894 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002895#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002896 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002897 sp = row;
2898 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05002899 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002900 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
2901 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2902 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Guy Schalnat0d580581995-07-20 02:43:20 -05002903
Andreas Dilger47a0c421997-05-16 02:46:07 -05002904 if (r == trans_values->red && g == trans_values->green &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002905 b == trans_values->blue)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002906 {
2907 *sp = (png_byte)((background->red >> 8) & 0xff);
2908 *(sp + 1) = (png_byte)(background->red & 0xff);
2909 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2910 *(sp + 3) = (png_byte)(background->green & 0xff);
2911 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2912 *(sp + 5) = (png_byte)(background->blue & 0xff);
2913 }
2914 }
2915 }
2916 }
2917 break;
2918 }
2919 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -05002920 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002921 if (row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002922 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002923#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002924 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
2925 gamma_table != NULL)
2926 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002927 sp = row;
2928 dp = row;
2929 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002930 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002931 png_uint_16 a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002932
Andreas Dilger47a0c421997-05-16 02:46:07 -05002933 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002934 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002935 *dp = gamma_table[*sp];
2936 }
2937 else if (a == 0)
2938 {
2939 /* background is already in screen gamma */
2940 *dp = (png_byte)background->gray;
2941 }
2942 else
2943 {
2944 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05002945
Andreas Dilger47a0c421997-05-16 02:46:07 -05002946 v = gamma_to_1[*sp];
2947 png_composite(w, v, a, background_1->gray);
2948 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002949 }
2950 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002951 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002952 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002953#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002954 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002955 sp = row;
2956 dp = row;
2957 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002958 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002959 png_byte a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002960
Andreas Dilger47a0c421997-05-16 02:46:07 -05002961 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002962 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002963 *dp = *sp;
2964 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002965#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002966 else if (a == 0)
2967 {
2968 *dp = (png_byte)background->gray;
2969 }
2970 else
2971 {
2972 png_composite(*dp, *sp, a, background_1->gray);
Guy Schalnat0d580581995-07-20 02:43:20 -05002973 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002974#else
2975 *dp = (png_byte)background->gray;
2976#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002977 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002978 }
2979 }
2980 else /* if (png_ptr->bit_depth == 16) */
2981 {
2982#if defined(PNG_READ_GAMMA_SUPPORTED)
2983 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
2984 gamma_16_to_1 != NULL)
2985 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002986 sp = row;
2987 dp = row;
2988 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002989 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002990 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05002991
Andreas Dilger47a0c421997-05-16 02:46:07 -05002992 if (a == (png_uint_16)0xffff)
2993 {
2994 png_uint_16 v;
2995
2996 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
2997 *dp = (png_byte)((v >> 8) & 0xff);
2998 *(dp + 1) = (png_byte)(v & 0xff);
2999 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003000#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003001 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003002#else
3003 else
3004#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003005 {
3006 /* background is already in screen gamma */
3007 *dp = (png_byte)((background->gray >> 8) & 0xff);
3008 *(dp + 1) = (png_byte)(background->gray & 0xff);
3009 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003010#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003011 else
3012 {
3013 png_uint_16 g, v, w;
3014
3015 g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3016 png_composite_16(v, g, a, background_1->gray);
3017 w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
3018 *dp = (png_byte)((w >> 8) & 0xff);
3019 *(dp + 1) = (png_byte)(w & 0xff);
3020 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003021#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003022 }
3023 }
3024 else
3025#endif
3026 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003027 sp = row;
3028 dp = row;
3029 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003030 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003031 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003032 if (a == (png_uint_16)0xffff)
3033 {
3034 png_memcpy(dp, sp, 2);
3035 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003036#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003037 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003038#else
3039 else
3040#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003041 {
3042 *dp = (png_byte)((background->gray >> 8) & 0xff);
3043 *(dp + 1) = (png_byte)(background->gray & 0xff);
3044 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003045#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003046 else
3047 {
3048 png_uint_16 g, v;
3049
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003050 g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003051 png_composite_16(v, g, a, background_1->gray);
3052 *dp = (png_byte)((v >> 8) & 0xff);
3053 *(dp + 1) = (png_byte)(v & 0xff);
3054 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003055#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003056 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003057 }
3058 }
3059 break;
3060 }
3061 case PNG_COLOR_TYPE_RGB_ALPHA:
3062 {
3063 if (row_info->bit_depth == 8)
3064 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003065#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003066 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3067 gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003068 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003069 sp = row;
3070 dp = row;
3071 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003072 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003073 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003074
Guy Schalnat0d580581995-07-20 02:43:20 -05003075 if (a == 0xff)
3076 {
3077 *dp = gamma_table[*sp];
3078 *(dp + 1) = gamma_table[*(sp + 1)];
3079 *(dp + 2) = gamma_table[*(sp + 2)];
3080 }
3081 else if (a == 0)
3082 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003083 /* background is already in screen gamma */
3084 *dp = (png_byte)background->red;
3085 *(dp + 1) = (png_byte)background->green;
3086 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003087 }
3088 else
3089 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003090 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05003091
3092 v = gamma_to_1[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003093 png_composite(w, v, a, background_1->red);
3094 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003095 v = gamma_to_1[*(sp + 1)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003096 png_composite(w, v, a, background_1->green);
3097 *(dp + 1) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003098 v = gamma_to_1[*(sp + 2)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003099 png_composite(w, v, a, background_1->blue);
3100 *(dp + 2) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003101 }
3102 }
3103 }
3104 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003105#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003106 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003107 sp = row;
3108 dp = row;
3109 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003110 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003111 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003112
Guy Schalnat0d580581995-07-20 02:43:20 -05003113 if (a == 0xff)
3114 {
3115 *dp = *sp;
3116 *(dp + 1) = *(sp + 1);
3117 *(dp + 2) = *(sp + 2);
3118 }
3119 else if (a == 0)
3120 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003121 *dp = (png_byte)background->red;
3122 *(dp + 1) = (png_byte)background->green;
3123 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003124 }
3125 else
3126 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003127 png_composite(*dp, *sp, a, background->red);
3128 png_composite(*(dp + 1), *(sp + 1), a,
3129 background->green);
3130 png_composite(*(dp + 2), *(sp + 2), a,
3131 background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003132 }
3133 }
3134 }
3135 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003136 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003137 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003138#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003139 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3140 gamma_16_to_1 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003141 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003142 sp = row;
3143 dp = row;
3144 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003145 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003146 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3147 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003148 if (a == (png_uint_16)0xffff)
3149 {
3150 png_uint_16 v;
3151
Andreas Dilger47a0c421997-05-16 02:46:07 -05003152 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003153 *dp = (png_byte)((v >> 8) & 0xff);
3154 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003155 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003156 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3157 *(dp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003158 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003159 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3160 *(dp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003161 }
3162 else if (a == 0)
3163 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003164 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003165 *dp = (png_byte)((background->red >> 8) & 0xff);
3166 *(dp + 1) = (png_byte)(background->red & 0xff);
3167 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3168 *(dp + 3) = (png_byte)(background->green & 0xff);
3169 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3170 *(dp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003171 }
3172 else
3173 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003174 png_uint_16 v, w, x;
Guy Schalnat0d580581995-07-20 02:43:20 -05003175
Andreas Dilger47a0c421997-05-16 02:46:07 -05003176 v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003177 png_composite_16(w, v, a, background_1->red);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003178 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3179 *dp = (png_byte)((x >> 8) & 0xff);
3180 *(dp + 1) = (png_byte)(x & 0xff);
3181 v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003182 png_composite_16(w, v, a, background_1->green);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003183 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3184 *(dp + 2) = (png_byte)((x >> 8) & 0xff);
3185 *(dp + 3) = (png_byte)(x & 0xff);
3186 v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003187 png_composite_16(w, v, a, background_1->blue);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003188 x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
3189 *(dp + 4) = (png_byte)((x >> 8) & 0xff);
3190 *(dp + 5) = (png_byte)(x & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003191 }
3192 }
3193 }
3194 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003195#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003196 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003197 sp = row;
3198 dp = row;
3199 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003200 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003201 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3202 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003203 if (a == (png_uint_16)0xffff)
3204 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003205 png_memcpy(dp, sp, 6);
Guy Schalnat0d580581995-07-20 02:43:20 -05003206 }
3207 else if (a == 0)
3208 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003209 *dp = (png_byte)((background->red >> 8) & 0xff);
3210 *(dp + 1) = (png_byte)(background->red & 0xff);
3211 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3212 *(dp + 3) = (png_byte)(background->green & 0xff);
3213 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3214 *(dp + 5) = (png_byte)(background->blue & 0xff);
3215 }
3216 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003217 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003218 png_uint_16 v;
Guy Schalnat0d580581995-07-20 02:43:20 -05003219
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003220 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3221 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3222 + *(sp + 3));
3223 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3224 + *(sp + 5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003225
3226 png_composite_16(v, r, a, background->red);
Guy Schalnat0d580581995-07-20 02:43:20 -05003227 *dp = (png_byte)((v >> 8) & 0xff);
3228 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003229 png_composite_16(v, g, a, background->green);
Guy Schalnat0d580581995-07-20 02:43:20 -05003230 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3231 *(dp + 3) = (png_byte)(v & 0xff);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003232 png_composite_16(v, b, a, background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003233 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3234 *(dp + 5) = (png_byte)(v & 0xff);
3235 }
3236 }
3237 }
3238 }
3239 break;
3240 }
3241 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003242
Guy Schalnat0d580581995-07-20 02:43:20 -05003243 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
3244 {
3245 row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
Guy Schalnate5a37791996-06-05 15:50:50 -05003246 row_info->channels--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003247 row_info->pixel_depth = (png_byte)(row_info->channels *
3248 row_info->bit_depth);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003249 row_info->rowbytes = ((row_width *
Guy Schalnat0d580581995-07-20 02:43:20 -05003250 row_info->pixel_depth + 7) >> 3);
3251 }
3252 }
3253}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003254#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003255
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003256#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003257/* Gamma correct the image, avoiding the alpha channel. Make sure
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003258 * you do this after you deal with the transparency issue on grayscale
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003259 * or RGB images. If your bit depth is 8, use gamma_table, if it
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003260 * is 16, use gamma_16_table and gamma_shift. Build these with
3261 * build_gamma_table().
3262 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003263void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003264png_do_gamma(png_row_infop row_info, png_bytep row,
3265 png_bytep gamma_table, png_uint_16pp gamma_16_table,
Guy Schalnat0d580581995-07-20 02:43:20 -05003266 int gamma_shift)
3267{
Guy Schalnat6d764711995-12-19 03:22:19 -06003268 png_bytep sp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003269 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003270 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003271
Andreas Dilger47a0c421997-05-16 02:46:07 -05003272 png_debug(1, "in png_do_gamma\n");
3273 if (
3274#if defined(PNG_USELESS_TESTS_SUPPORTED)
3275 row != NULL && row_info != NULL &&
3276#endif
3277 ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
3278 (row_info->bit_depth == 16 && gamma_16_table != NULL)))
Guy Schalnat0d580581995-07-20 02:43:20 -05003279 {
3280 switch (row_info->color_type)
3281 {
3282 case PNG_COLOR_TYPE_RGB:
3283 {
3284 if (row_info->bit_depth == 8)
3285 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003286 sp = row;
3287 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003288 {
3289 *sp = gamma_table[*sp];
3290 sp++;
3291 *sp = gamma_table[*sp];
3292 sp++;
3293 *sp = gamma_table[*sp];
3294 sp++;
3295 }
3296 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003297 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003298 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003299 sp = row;
3300 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003301 {
3302 png_uint_16 v;
3303
Andreas Dilger47a0c421997-05-16 02:46:07 -05003304 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003305 *sp = (png_byte)((v >> 8) & 0xff);
3306 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003307 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003308 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003309 *sp = (png_byte)((v >> 8) & 0xff);
3310 *(sp + 1) = (png_byte)(v & 0xff);
3311 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003312 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003313 *sp = (png_byte)((v >> 8) & 0xff);
3314 *(sp + 1) = (png_byte)(v & 0xff);
3315 sp += 2;
3316 }
3317 }
3318 break;
3319 }
3320 case PNG_COLOR_TYPE_RGB_ALPHA:
3321 {
3322 if (row_info->bit_depth == 8)
3323 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003324 sp = row;
3325 for (i = 0; i < row_width; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003326 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003327 *sp = gamma_table[*sp];
3328 sp++;
3329 *sp = gamma_table[*sp];
3330 sp++;
3331 *sp = gamma_table[*sp];
3332 sp++;
3333 sp++;
3334 }
3335 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003336 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003337 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003338 sp = row;
3339 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003340 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003341 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003342 *sp = (png_byte)((v >> 8) & 0xff);
3343 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003344 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003345 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003346 *sp = (png_byte)((v >> 8) & 0xff);
3347 *(sp + 1) = (png_byte)(v & 0xff);
3348 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003349 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003350 *sp = (png_byte)((v >> 8) & 0xff);
3351 *(sp + 1) = (png_byte)(v & 0xff);
3352 sp += 4;
3353 }
3354 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003355 break;
3356 }
3357 case PNG_COLOR_TYPE_GRAY_ALPHA:
3358 {
3359 if (row_info->bit_depth == 8)
3360 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003361 sp = row;
3362 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003363 {
3364 *sp = gamma_table[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003365 sp += 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05003366 }
3367 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003368 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003369 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003370 sp = row;
3371 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003372 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003373 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003374 *sp = (png_byte)((v >> 8) & 0xff);
3375 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003376 sp += 4;
3377 }
3378 }
3379 break;
3380 }
3381 case PNG_COLOR_TYPE_GRAY:
3382 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003383 if (row_info->bit_depth == 2)
3384 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003385 sp = row;
3386 for (i = 0; i < row_width; i += 4)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003387 {
3388 int a = *sp & 0xc0;
3389 int b = *sp & 0x30;
3390 int c = *sp & 0x0c;
3391 int d = *sp & 0x03;
3392
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003393 *sp = (png_byte)(
3394 ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003395 ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
3396 ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003397 ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003398 sp++;
3399 }
3400 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003401 if (row_info->bit_depth == 4)
Guy Schalnat0d580581995-07-20 02:43:20 -05003402 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003403 sp = row;
3404 for (i = 0; i < row_width; i += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003405 {
3406 int msb = *sp & 0xf0;
3407 int lsb = *sp & 0x0f;
3408
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003409 *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
3410 | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003411 sp++;
3412 }
3413 }
3414 else if (row_info->bit_depth == 8)
3415 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003416 sp = row;
3417 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003418 {
3419 *sp = gamma_table[*sp];
3420 sp++;
3421 }
3422 }
3423 else if (row_info->bit_depth == 16)
3424 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003425 sp = row;
3426 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003427 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003428 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003429 *sp = (png_byte)((v >> 8) & 0xff);
3430 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003431 sp += 2;
3432 }
3433 }
3434 break;
3435 }
3436 }
3437 }
3438}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003439#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003440
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003441#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003442/* Expands a palette row to an RGB or RGBA row depending
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003443 * upon whether you supply trans and num_trans.
3444 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003445void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003446png_do_expand_palette(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05003447 png_colorp palette, png_bytep trans, int num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003448{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003449 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003450 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003451 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003452 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003453
Andreas Dilger47a0c421997-05-16 02:46:07 -05003454 png_debug(1, "in png_do_expand_palette\n");
3455 if (
3456#if defined(PNG_USELESS_TESTS_SUPPORTED)
3457 row != NULL && row_info != NULL &&
3458#endif
3459 row_info->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05003460 {
3461 if (row_info->bit_depth < 8)
3462 {
3463 switch (row_info->bit_depth)
3464 {
3465 case 1:
3466 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003467 sp = row + (png_size_t)((row_width - 1) >> 3);
3468 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003469 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003470 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003471 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003472 if ((*sp >> shift) & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -05003473 *dp = 1;
3474 else
3475 *dp = 0;
3476 if (shift == 7)
3477 {
3478 shift = 0;
3479 sp--;
3480 }
3481 else
3482 shift++;
3483
3484 dp--;
3485 }
3486 break;
3487 }
3488 case 2:
3489 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003490 sp = row + (png_size_t)((row_width - 1) >> 2);
3491 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003492 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003493 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003494 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003495 value = (*sp >> shift) & 0x03;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003496 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003497 if (shift == 6)
3498 {
3499 shift = 0;
3500 sp--;
3501 }
3502 else
3503 shift += 2;
3504
3505 dp--;
3506 }
3507 break;
3508 }
3509 case 4:
3510 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003511 sp = row + (png_size_t)((row_width - 1) >> 1);
3512 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003513 shift = (int)((row_width & 0x01) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003514 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003515 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003516 value = (*sp >> shift) & 0x0f;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003517 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003518 if (shift == 4)
3519 {
3520 shift = 0;
3521 sp--;
3522 }
3523 else
3524 shift += 4;
3525
3526 dp--;
3527 }
3528 break;
3529 }
3530 }
3531 row_info->bit_depth = 8;
3532 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003533 row_info->rowbytes = row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003534 }
3535 switch (row_info->bit_depth)
3536 {
3537 case 8:
3538 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003539 if (trans != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003540 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003541 sp = row + (png_size_t)row_width - 1;
3542 dp = row + (png_size_t)(row_width << 2) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003543
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003544 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003545 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003546 if ((int)(*sp) >= num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003547 *dp-- = 0xff;
3548 else
3549 *dp-- = trans[*sp];
3550 *dp-- = palette[*sp].blue;
3551 *dp-- = palette[*sp].green;
3552 *dp-- = palette[*sp].red;
3553 sp--;
3554 }
3555 row_info->bit_depth = 8;
3556 row_info->pixel_depth = 32;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003557 row_info->rowbytes = row_width * 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05003558 row_info->color_type = 6;
3559 row_info->channels = 4;
3560 }
3561 else
3562 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003563 sp = row + (png_size_t)row_width - 1;
3564 dp = row + (png_size_t)(row_width * 3) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003565
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003566 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003567 {
3568 *dp-- = palette[*sp].blue;
3569 *dp-- = palette[*sp].green;
3570 *dp-- = palette[*sp].red;
3571 sp--;
3572 }
3573 row_info->bit_depth = 8;
3574 row_info->pixel_depth = 24;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003575 row_info->rowbytes = row_width * 3;
Guy Schalnat0d580581995-07-20 02:43:20 -05003576 row_info->color_type = 2;
3577 row_info->channels = 3;
3578 }
3579 break;
3580 }
3581 }
3582 }
3583}
3584
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003585/* If the bit depth < 8, it is expanded to 8. Also, if the
3586 * transparency value is supplied, an alpha channel is built.
3587 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003588void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003589png_do_expand(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003590 png_color_16p trans_value)
Guy Schalnat0d580581995-07-20 02:43:20 -05003591{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003592 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003593 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003594 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003595 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003596
Andreas Dilger47a0c421997-05-16 02:46:07 -05003597 png_debug(1, "in png_do_expand\n");
3598#if defined(PNG_USELESS_TESTS_SUPPORTED)
3599 if (row != NULL && row_info != NULL)
3600#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003601 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003602 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05003603 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003604 png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003605
3606 if (row_info->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003607 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003608 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05003609 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003610 case 1:
3611 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003612 gray = (png_uint_16)(gray*0xff);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003613 sp = row + (png_size_t)((row_width - 1) >> 3);
3614 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003615 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003616 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003617 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003618 if ((*sp >> shift) & 0x01)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003619 *dp = 0xff;
3620 else
3621 *dp = 0;
3622 if (shift == 7)
3623 {
3624 shift = 0;
3625 sp--;
3626 }
3627 else
3628 shift++;
3629
3630 dp--;
3631 }
3632 break;
3633 }
3634 case 2:
3635 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003636 gray = (png_uint_16)(gray*0x55);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003637 sp = row + (png_size_t)((row_width - 1) >> 2);
3638 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003639 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003640 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003641 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003642 value = (*sp >> shift) & 0x03;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003643 *dp = (png_byte)(value | (value << 2) | (value << 4) |
3644 (value << 6));
3645 if (shift == 6)
3646 {
3647 shift = 0;
3648 sp--;
3649 }
3650 else
3651 shift += 2;
3652
3653 dp--;
3654 }
3655 break;
3656 }
3657 case 4:
3658 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003659 gray = (png_uint_16)(gray*0x11);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003660 sp = row + (png_size_t)((row_width - 1) >> 1);
3661 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003662 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003663 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003664 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003665 value = (*sp >> shift) & 0x0f;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003666 *dp = (png_byte)(value | (value << 4));
3667 if (shift == 4)
3668 {
3669 shift = 0;
3670 sp--;
3671 }
3672 else
3673 shift = 4;
3674
3675 dp--;
3676 }
3677 break;
3678 }
3679 }
3680 row_info->bit_depth = 8;
3681 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003682 row_info->rowbytes = row_width;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003683 }
3684
Andreas Dilger47a0c421997-05-16 02:46:07 -05003685 if (trans_value != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003686 {
3687 if (row_info->bit_depth == 8)
3688 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003689 sp = row + (png_size_t)row_width - 1;
3690 dp = row + (png_size_t)(row_width << 1) - 1;
3691 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003692 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003693 if (*sp == gray)
3694 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003695 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003696 *dp-- = 0xff;
3697 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003698 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003699 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003700 else if (row_info->bit_depth == 16)
Guy Schalnat0d580581995-07-20 02:43:20 -05003701 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003702 sp = row + row_info->rowbytes - 1;
3703 dp = row + (row_info->rowbytes << 1) - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003704 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003705 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003706 if (((png_uint_16)*(sp) |
3707 ((png_uint_16)*(sp - 1) << 8)) == gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05003708 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003709 *dp-- = 0;
3710 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003711 }
3712 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003713 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003714 *dp-- = 0xff;
3715 *dp-- = 0xff;
Guy Schalnat0d580581995-07-20 02:43:20 -05003716 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003717 *dp-- = *sp--;
3718 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003719 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003720 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003721 row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
3722 row_info->channels = 2;
3723 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
3724 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003725 ((row_width * row_info->pixel_depth) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003726 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003727 }
3728 else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
3729 {
3730 if (row_info->bit_depth == 8)
3731 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003732 sp = row + (png_size_t)row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003733 dp = row + (png_size_t)(row_width << 2) - 1;
3734 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003735 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003736 if (*(sp - 2) == trans_value->red &&
Guy Schalnat0d580581995-07-20 02:43:20 -05003737 *(sp - 1) == trans_value->green &&
3738 *(sp - 0) == trans_value->blue)
3739 *dp-- = 0;
3740 else
3741 *dp-- = 0xff;
3742 *dp-- = *sp--;
3743 *dp-- = *sp--;
3744 *dp-- = *sp--;
3745 }
3746 }
3747 else if (row_info->bit_depth == 16)
3748 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003749 sp = row + row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003750 dp = row + (png_size_t)(row_width << 3) - 1;
3751 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003752 {
3753 if ((((png_uint_16)*(sp - 4) |
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003754 ((png_uint_16)*(sp - 5) << 8)) == trans_value->red) &&
Guy Schalnat0d580581995-07-20 02:43:20 -05003755 (((png_uint_16)*(sp - 2) |
3756 ((png_uint_16)*(sp - 3) << 8)) == trans_value->green) &&
3757 (((png_uint_16)*(sp - 0) |
3758 ((png_uint_16)*(sp - 1) << 8)) == trans_value->blue))
3759 {
3760 *dp-- = 0;
3761 *dp-- = 0;
3762 }
3763 else
3764 {
3765 *dp-- = 0xff;
3766 *dp-- = 0xff;
3767 }
3768 *dp-- = *sp--;
3769 *dp-- = *sp--;
3770 *dp-- = *sp--;
3771 *dp-- = *sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003772 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003773 *dp-- = *sp--;
3774 }
3775 }
3776 row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
3777 row_info->channels = 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003778 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
Guy Schalnat0d580581995-07-20 02:43:20 -05003779 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003780 ((row_width * row_info->pixel_depth) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003781 }
3782 }
3783}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003784#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003785
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003786#if defined(PNG_READ_DITHER_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003787void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003788png_do_dither(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003789 png_bytep palette_lookup, png_bytep dither_lookup)
Guy Schalnat0d580581995-07-20 02:43:20 -05003790{
Guy Schalnat6d764711995-12-19 03:22:19 -06003791 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003792 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003793 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003794
Andreas Dilger47a0c421997-05-16 02:46:07 -05003795 png_debug(1, "in png_do_dither\n");
3796#if defined(PNG_USELESS_TESTS_SUPPORTED)
3797 if (row != NULL && row_info != NULL)
3798#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003799 {
3800 if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
3801 palette_lookup && row_info->bit_depth == 8)
3802 {
3803 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003804 sp = row;
3805 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003806 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003807 {
3808 r = *sp++;
3809 g = *sp++;
3810 b = *sp++;
3811
3812 /* this looks real messy, but the compiler will reduce
3813 it down to a reasonable formula. For example, with
3814 5 bits per color, we get:
3815 p = (((r >> 3) & 0x1f) << 10) |
3816 (((g >> 3) & 0x1f) << 5) |
3817 ((b >> 3) & 0x1f);
3818 */
3819 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
3820 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
3821 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3822 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003823 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003824 (PNG_DITHER_BLUE_BITS)) |
3825 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3826 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3827
3828 *dp++ = palette_lookup[p];
3829 }
3830 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3831 row_info->channels = 1;
3832 row_info->pixel_depth = row_info->bit_depth;
3833 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003834 ((row_width * row_info->pixel_depth + 7) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003835 }
3836 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
Andreas Dilger47a0c421997-05-16 02:46:07 -05003837 palette_lookup != NULL && row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003838 {
3839 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003840 sp = row;
3841 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003842 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003843 {
3844 r = *sp++;
3845 g = *sp++;
3846 b = *sp++;
3847 sp++;
3848
3849 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003850 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003851 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3852 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
3853 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
3854 (PNG_DITHER_BLUE_BITS)) |
3855 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3856 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3857
3858 *dp++ = palette_lookup[p];
3859 }
3860 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3861 row_info->channels = 1;
3862 row_info->pixel_depth = row_info->bit_depth;
3863 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003864 ((row_width * row_info->pixel_depth + 7) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003865 }
3866 else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
3867 dither_lookup && row_info->bit_depth == 8)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003868 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003869 sp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003870 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003871 {
3872 *sp = dither_lookup[*sp];
3873 }
3874 }
3875 }
3876}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003877#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003878
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003879#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003880#if defined(PNG_READ_GAMMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05003881static int png_gamma_shift[] =
3882 {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0};
3883
Andreas Dilger47a0c421997-05-16 02:46:07 -05003884/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003885 * tables, we don't make a full table if we are reducing to 8-bit in
3886 * the future. Note also how the gamma_16 tables are segmented so that
3887 * we don't need to allocate > 64K chunks for a full 16-bit table.
3888 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003889void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003890png_build_gamma_table(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003891{
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003892 png_debug(1, "in png_build_gamma_table\n");
3893 if(png_ptr->gamma != 0.0)
3894 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003895 if (png_ptr->bit_depth <= 8)
3896 {
3897 int i;
3898 double g;
3899
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003900 if (png_ptr->screen_gamma > .000001)
3901 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
3902 else
3903 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003904
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003905 png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -05003906 (png_uint_32)256);
3907
3908 for (i = 0; i < 256; i++)
3909 {
3910 png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
3911 g) * 255.0 + .5);
3912 }
3913
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003914#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
3915 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003916 if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05003917 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003918
Guy Schalnat0d580581995-07-20 02:43:20 -05003919 g = 1.0 / (png_ptr->gamma);
3920
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003921 png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -05003922 (png_uint_32)256);
3923
3924 for (i = 0; i < 256; i++)
3925 {
3926 png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
3927 g) * 255.0 + .5);
3928 }
3929
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003930
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003931 png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -05003932 (png_uint_32)256);
3933
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003934 if(png_ptr->screen_gamma > 0.000001)
3935 g = 1.0 / png_ptr->screen_gamma;
3936 else
3937 g = png_ptr->gamma; /* probably doing rgb_to_gray */
3938
Guy Schalnat0d580581995-07-20 02:43:20 -05003939 for (i = 0; i < 256; i++)
3940 {
3941 png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
3942 g) * 255.0 + .5);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003943
Guy Schalnat0d580581995-07-20 02:43:20 -05003944 }
3945 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003946#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003947 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003948 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003949 {
3950 double g;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003951 int i, j, shift, num;
3952 int sig_bit;
3953 png_uint_32 ig;
Guy Schalnat0d580581995-07-20 02:43:20 -05003954
3955 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003956 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003957 sig_bit = (int)png_ptr->sig_bit.red;
3958 if ((int)png_ptr->sig_bit.green > sig_bit)
3959 sig_bit = png_ptr->sig_bit.green;
3960 if ((int)png_ptr->sig_bit.blue > sig_bit)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003961 sig_bit = png_ptr->sig_bit.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003962 }
3963 else
3964 {
3965 sig_bit = (int)png_ptr->sig_bit.gray;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003966 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003967
3968 if (sig_bit > 0)
3969 shift = 16 - sig_bit;
3970 else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003971 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003972
3973 if (png_ptr->transformations & PNG_16_TO_8)
3974 {
3975 if (shift < (16 - PNG_MAX_GAMMA_8))
3976 shift = (16 - PNG_MAX_GAMMA_8);
3977 }
3978
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003979 if (shift > 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003980 shift = 8;
3981 if (shift < 0)
3982 shift = 0;
3983
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003984 png_ptr->gamma_shift = (png_byte)shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05003985
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003986 num = (1 << (8 - shift));
Guy Schalnat0d580581995-07-20 02:43:20 -05003987
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003988 if (png_ptr->screen_gamma > .000001)
3989 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
3990 else
3991 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003992
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003993 png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06003994 (png_uint_32)(num * sizeof (png_uint_16p)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003995
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003996 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003997 {
3998 double fin, fout;
3999 png_uint_32 last, max;
Guy Schalnat0d580581995-07-20 02:43:20 -05004000
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06004001 for (i = 0; i < num; i++)
4002 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004003 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004004 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06004005 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004006
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06004007 g = 1.0 / g;
4008 last = 0;
4009 for (i = 0; i < 256; i++)
4010 {
4011 fout = ((double)i + 0.5) / 256.0;
4012 fin = pow(fout, g);
4013 max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
4014 while (last <= max)
4015 {
4016 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4017 [(int)(last >> (8 - shift))] = (png_uint_16)(
4018 (png_uint_16)i | ((png_uint_16)i << 8));
4019 last++;
4020 }
4021 }
4022 while (last < ((png_uint_32)num << 8))
4023 {
4024 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
Andreas Dilger47a0c421997-05-16 02:46:07 -05004025 [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06004026 last++;
Guy Schalnat6d764711995-12-19 03:22:19 -06004027 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004028 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06004029 else
4030 {
4031 for (i = 0; i < num; i++)
4032 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004033 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004034 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004035
Andreas Dilger47a0c421997-05-16 02:46:07 -05004036 ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06004037 for (j = 0; j < 256; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05004038 {
4039 png_ptr->gamma_16_table[i][j] =
4040 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4041 65535.0, g) * 65535.0 + .5);
4042 }
4043 }
4044 }
4045
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004046#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
4047 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4048 if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05004049 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004050
Guy Schalnat0d580581995-07-20 02:43:20 -05004051 g = 1.0 / (png_ptr->gamma);
4052
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004053 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004054 (png_uint_32)(num * sizeof (png_uint_16p )));
Guy Schalnat0d580581995-07-20 02:43:20 -05004055
4056 for (i = 0; i < num; i++)
4057 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004058 png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004059 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004060
4061 ig = (((png_uint_32)i *
4062 (png_uint_32)png_gamma_shift[shift]) >> 4);
4063 for (j = 0; j < 256; j++)
4064 {
4065 png_ptr->gamma_16_to_1[i][j] =
4066 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4067 65535.0, g) * 65535.0 + .5);
4068 }
4069 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004070
4071 if(png_ptr->screen_gamma > 0.000001)
4072 g = 1.0 / png_ptr->screen_gamma;
4073 else
4074 g = png_ptr->gamma; /* probably doing rgb_to_gray */
Guy Schalnat0d580581995-07-20 02:43:20 -05004075
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004076 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004077 (png_uint_32)(num * sizeof (png_uint_16p)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004078
4079 for (i = 0; i < num; i++)
4080 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004081 png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004082 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004083
4084 ig = (((png_uint_32)i *
4085 (png_uint_32)png_gamma_shift[shift]) >> 4);
4086 for (j = 0; j < 256; j++)
4087 {
4088 png_ptr->gamma_16_from_1[i][j] =
4089 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4090 65535.0, g) * 65535.0 + .5);
4091 }
4092 }
4093 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004094#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05004095 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004096 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004097}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004098#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06004099/* To do: install integer version of png_build_gamma_table here */
4100#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004101
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004102#if defined(PNG_MNG_FEATURES_SUPPORTED)
4103/* undoes intrapixel differencing */
4104void /* PRIVATE */
4105png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
4106{
4107 png_debug(1, "in png_do_read_intrapixel\n");
4108 if (
4109#if defined(PNG_USELESS_TESTS_SUPPORTED)
4110 row != NULL && row_info != NULL &&
4111#endif
4112 (row_info->color_type & PNG_COLOR_MASK_COLOR))
4113 {
4114 int bytes_per_pixel;
4115 png_uint_32 row_width = row_info->width;
4116 if (row_info->bit_depth == 8)
4117 {
4118 png_bytep rp;
4119 png_uint_32 i;
4120
4121 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4122 bytes_per_pixel = 3;
4123 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4124 bytes_per_pixel = 4;
4125 else
4126 return;
4127
4128 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4129 {
4130 *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff);
4131 *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff);
4132 }
4133 }
4134 else if (row_info->bit_depth == 16)
4135 {
4136 png_bytep rp;
4137 png_uint_32 i;
4138
4139 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4140 bytes_per_pixel = 6;
4141 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4142 bytes_per_pixel = 8;
4143 else
4144 return;
4145
4146 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4147 {
4148 png_uint_32 s0=*(rp )<<8 | *(rp+1);
4149 png_uint_32 s1=*(rp+2)<<8 | *(rp+3);
4150 png_uint_32 s2=*(rp+4)<<8 | *(rp+5);
4151 png_uint_32 red=(65536+s0+s1)&0xffff;
4152 png_uint_32 blue=(65536+s2+s1)&0xffff;
4153 *(rp ) = (png_byte)((red>>8)&0xff);
4154 *(rp+1) = (png_byte)(red&0xff);
4155 *(rp+4) = (png_byte)((blue>>8)&0xff);
4156 *(rp+5) = (png_byte)(blue&0xff);
4157 }
4158 }
4159 }
4160}
4161#endif /* PNG_MNG_FEATURES_SUPPORTED */