blob: 7329ccf9d8e8f33c1f264d35670b4d33591784ce [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-Pehrson5a0be342001-10-18 20:55:13 -05004 * libpng 1.2.1beta1 - October 19, 2001
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
Glenn Randers-Pehrsonbe9de0f2001-01-22 08:52:16 -06006 * Copyright (c) 1998-2001 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.
513 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500514void PNGAPI
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600515png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -0500516{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500517 png_debug(1, "in png_set_gamma\n");
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600518 if (fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600519 png_ptr->transformations |= PNG_GAMMA;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500520 png_ptr->gamma = (float)file_gamma;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600521 png_ptr->screen_gamma = (float)scrn_gamma;
Guy Schalnat0d580581995-07-20 02:43:20 -0500522}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500523#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500524
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500525#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -0500526/* Expand paletted images to RGB, expand grayscale images of
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500527 * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600528 * to alpha channels.
529 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500530void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600531png_set_expand(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500532{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500533 png_debug(1, "in png_set_expand\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500534 png_ptr->transformations |= PNG_EXPAND;
535}
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500536
537/* GRR 19990627: the following three functions currently are identical
538 * to png_set_expand(). However, it is entirely reasonable that someone
539 * might wish to expand an indexed image to RGB but *not* expand a single,
540 * fully transparent palette entry to a full alpha channel--perhaps instead
541 * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
542 * the transparent color with a particular RGB value, or drop tRNS entirely.
543 * IOW, a future version of the library may make the transformations flag
544 * a bit more fine-grained, with separate bits for each of these three
545 * functions.
546 *
547 * More to the point, these functions make it obvious what libpng will be
548 * doing, whereas "expand" can (and does) mean any number of things.
549 */
550
551/* Expand paletted images to RGB. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500552void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500553png_set_palette_to_rgb(png_structp png_ptr)
554{
555 png_debug(1, "in png_set_expand\n");
556 png_ptr->transformations |= PNG_EXPAND;
557}
558
559/* Expand grayscale images of less than 8-bit depth to 8 bits. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500560void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500561png_set_gray_1_2_4_to_8(png_structp png_ptr)
562{
563 png_debug(1, "in png_set_expand\n");
564 png_ptr->transformations |= PNG_EXPAND;
565}
566
567/* Expand tRNS chunks to alpha channels. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500568void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500569png_set_tRNS_to_alpha(png_structp png_ptr)
570{
571 png_debug(1, "in png_set_expand\n");
572 png_ptr->transformations |= PNG_EXPAND;
573}
574#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500575
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500576#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500577void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600578png_set_gray_to_rgb(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500579{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500580 png_debug(1, "in png_set_gray_to_rgb\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500581 png_ptr->transformations |= PNG_GRAY_TO_RGB;
582}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500583#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500584
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600585#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
586#if defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600587/* Convert a RGB image to a grayscale of the same width. This allows us,
588 * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600589 */
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600590
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500591void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500592png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red,
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600593 double green)
594{
595 int red_fixed = (int)((float)red*100000.0 + 0.5);
596 int green_fixed = (int)((float)green*100000.0 + 0.5);
597 png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed);
598}
599#endif
600
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500601void PNGAPI
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600602png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
603 png_fixed_point red, png_fixed_point green)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600604{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500605 png_debug(1, "in png_set_rgb_to_gray\n");
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600606 switch(error_action)
607 {
608 case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY;
609 break;
610 case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
611 break;
612 case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
613 }
614 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
615#if defined(PNG_READ_EXPAND_SUPPORTED)
616 png_ptr->transformations |= PNG_EXPAND;
617#else
618 {
619 png_warning(png_ptr, "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED.");
620 png_ptr->transformations &= ~PNG_RGB_TO_GRAY;
621 }
622#endif
623 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600624 png_uint_16 red_int, green_int;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600625 if(red < 0 || green < 0)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600626 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600627 red_int = 6968; /* .212671 * 32768 + .5 */
628 green_int = 23434; /* .715160 * 32768 + .5 */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600629 }
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600630 else if(red + green < 100000L)
631 {
632 red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
633 green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
634 }
635 else
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600636 {
637 png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600638 red_int = 6968;
639 green_int = 23434;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600640 }
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600641 png_ptr->rgb_to_gray_red_coeff = red_int;
642 png_ptr->rgb_to_gray_green_coeff = green_int;
643 png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(32768-red_int-green_int);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600644 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600645}
646#endif
647
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500648#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
649 defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
650 defined(PNG_LEGACY_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500651void PNGAPI
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600652png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
653 read_user_transform_fn)
654{
655 png_debug(1, "in png_set_read_user_transform_fn\n");
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500656#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600657 png_ptr->transformations |= PNG_USER_TRANSFORM;
658 png_ptr->read_user_transform_fn = read_user_transform_fn;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500659#endif
660#ifdef PNG_LEGACY_SUPPORTED
661 if(read_user_transform_fn)
662 png_warning(png_ptr,
663 "This version of libpng does not support user transforms");
664#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600665}
666#endif
667
Andreas Dilger47a0c421997-05-16 02:46:07 -0500668/* Initialize everything needed for the read. This includes modifying
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600669 * the palette.
670 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500671void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -0600672png_init_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500673{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500674 png_debug(1, "in png_init_read_transformations\n");
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500675#if defined(PNG_USELESS_TESTS_SUPPORTED)
676 if(png_ptr != NULL)
677#endif
678 {
679#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
680 || defined(PNG_READ_GAMMA_SUPPORTED)
681 int color_type = png_ptr->color_type;
682#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500683
Guy Schalnate5a37791996-06-05 15:50:50 -0500684#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600685 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
686 (png_ptr->transformations & PNG_EXPAND))
Guy Schalnat0d580581995-07-20 02:43:20 -0500687 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500688 if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
Guy Schalnat0d580581995-07-20 02:43:20 -0500689 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500690 /* expand background chunk. */
Guy Schalnat0d580581995-07-20 02:43:20 -0500691 switch (png_ptr->bit_depth)
692 {
693 case 1:
Guy Schalnate5a37791996-06-05 15:50:50 -0500694 png_ptr->background.gray *= (png_uint_16)0xff;
695 png_ptr->background.red = png_ptr->background.green =
696 png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500697 break;
698 case 2:
Guy Schalnate5a37791996-06-05 15:50:50 -0500699 png_ptr->background.gray *= (png_uint_16)0x55;
700 png_ptr->background.red = png_ptr->background.green =
701 png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500702 break;
703 case 4:
Guy Schalnate5a37791996-06-05 15:50:50 -0500704 png_ptr->background.gray *= (png_uint_16)0x11;
705 png_ptr->background.red = png_ptr->background.green =
706 png_ptr->background.blue = png_ptr->background.gray;
707 break;
708 case 8:
709 case 16:
710 png_ptr->background.red = png_ptr->background.green =
711 png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500712 break;
713 }
714 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500715 else if (color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -0500716 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500717 png_ptr->background.red =
Guy Schalnat0d580581995-07-20 02:43:20 -0500718 png_ptr->palette[png_ptr->background.index].red;
719 png_ptr->background.green =
720 png_ptr->palette[png_ptr->background.index].green;
Guy Schalnate5a37791996-06-05 15:50:50 -0500721 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -0500722 png_ptr->palette[png_ptr->background.index].blue;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600723
724#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
725 if (png_ptr->transformations & PNG_INVERT_ALPHA)
726 {
727#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600728 if (!(png_ptr->transformations & PNG_EXPAND))
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600729#endif
730 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600731 /* invert the alpha channel (in tRNS) unless the pixels are
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600732 going to be expanded, in which case leave it for later */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500733 int i,istop;
734 istop=(int)png_ptr->num_trans;
735 for (i=0; i<istop; i++)
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -0500736 png_ptr->trans[i] = (png_byte)(255 - png_ptr->trans[i]);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600737 }
738 }
739#endif
740
Guy Schalnat0d580581995-07-20 02:43:20 -0500741 }
742 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500743#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500744
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500745#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500746 png_ptr->background_1 = png_ptr->background;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500747#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600748#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600749 if (png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -0500750 {
751 png_build_gamma_table(png_ptr);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500752#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Guy Schalnate5a37791996-06-05 15:50:50 -0500753 if (png_ptr->transformations & PNG_BACKGROUND)
Guy Schalnat0d580581995-07-20 02:43:20 -0500754 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500755 if (color_type == PNG_COLOR_TYPE_PALETTE)
756 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500757 png_color back, back_1;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500758 png_colorp palette = png_ptr->palette;
759 int num_palette = png_ptr->num_palette;
760 int i;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500761 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
762 {
763 back.red = png_ptr->gamma_table[png_ptr->background.red];
764 back.green = png_ptr->gamma_table[png_ptr->background.green];
765 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
Guy Schalnate5a37791996-06-05 15:50:50 -0500766
Andreas Dilger47a0c421997-05-16 02:46:07 -0500767 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
768 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
769 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
770 }
771 else
772 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600773 double g, gs;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500774
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600775 switch (png_ptr->background_gamma_type)
Glenn Randers-Pehrson4922b1b1998-03-08 22:55:17 -0600776 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600777 case PNG_BACKGROUND_GAMMA_SCREEN:
778 g = (png_ptr->screen_gamma);
779 gs = 1.0;
780 break;
781 case PNG_BACKGROUND_GAMMA_FILE:
782 g = 1.0 / (png_ptr->gamma);
783 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
784 break;
785 case PNG_BACKGROUND_GAMMA_UNIQUE:
786 g = 1.0 / (png_ptr->background_gamma);
787 gs = 1.0 / (png_ptr->background_gamma *
788 png_ptr->screen_gamma);
789 break;
790 default:
791 g = 1.0; /* back_1 */
792 gs = 1.0; /* back */
793 }
794
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -0600795 if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD)
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600796 {
797 back.red = (png_byte)png_ptr->background.red;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500798 back.green = (png_byte)png_ptr->background.green;
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600799 back.blue = (png_byte)png_ptr->background.blue;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500800 }
801 else
802 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600803 back.red = (png_byte)(pow(
804 (double)png_ptr->background.red/255, gs) * 255.0 + .5);
805 back.green = (png_byte)(pow(
806 (double)png_ptr->background.green/255, gs) * 255.0 + .5);
807 back.blue = (png_byte)(pow(
808 (double)png_ptr->background.blue/255, gs) * 255.0 + .5);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500809 }
810
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600811 back_1.red = (png_byte)(pow(
812 (double)png_ptr->background.red/255, g) * 255.0 + .5);
813 back_1.green = (png_byte)(pow(
814 (double)png_ptr->background.green/255, g) * 255.0 + .5);
815 back_1.blue = (png_byte)(pow(
816 (double)png_ptr->background.blue/255, g) * 255.0 + .5);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500817 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500818 for (i = 0; i < num_palette; i++)
819 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500820 if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
Guy Schalnate5a37791996-06-05 15:50:50 -0500821 {
822 if (png_ptr->trans[i] == 0)
823 {
824 palette[i] = back;
825 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500826 else /* if (png_ptr->trans[i] != 0xff) */
Guy Schalnate5a37791996-06-05 15:50:50 -0500827 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500828 png_byte v, w;
Guy Schalnate5a37791996-06-05 15:50:50 -0500829
830 v = png_ptr->gamma_to_1[palette[i].red];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500831 png_composite(w, v, png_ptr->trans[i], back_1.red);
Guy Schalnate5a37791996-06-05 15:50:50 -0500832 palette[i].red = png_ptr->gamma_from_1[w];
833
834 v = png_ptr->gamma_to_1[palette[i].green];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500835 png_composite(w, v, png_ptr->trans[i], back_1.green);
Guy Schalnate5a37791996-06-05 15:50:50 -0500836 palette[i].green = png_ptr->gamma_from_1[w];
837
838 v = png_ptr->gamma_to_1[palette[i].blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500839 png_composite(w, v, png_ptr->trans[i], back_1.blue);
Guy Schalnate5a37791996-06-05 15:50:50 -0500840 palette[i].blue = png_ptr->gamma_from_1[w];
841 }
842 }
843 else
844 {
845 palette[i].red = png_ptr->gamma_table[palette[i].red];
846 palette[i].green = png_ptr->gamma_table[palette[i].green];
847 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
848 }
849 }
850 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500851 /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN)*/
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600852 else
853 /* color_type != PNG_COLOR_TYPE_PALETTE */
Guy Schalnat0d580581995-07-20 02:43:20 -0500854 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500855 double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
856 double g = 1.0;
857 double gs = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500858
859 switch (png_ptr->background_gamma_type)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600860 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500861 case PNG_BACKGROUND_GAMMA_SCREEN:
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600862 g = (png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500863 gs = 1.0;
864 break;
865 case PNG_BACKGROUND_GAMMA_FILE:
866 g = 1.0 / (png_ptr->gamma);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600867 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500868 break;
869 case PNG_BACKGROUND_GAMMA_UNIQUE:
870 g = 1.0 / (png_ptr->background_gamma);
871 gs = 1.0 / (png_ptr->background_gamma *
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600872 png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500873 break;
874 }
875
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600876 if (color_type & PNG_COLOR_MASK_COLOR)
Guy Schalnat0d580581995-07-20 02:43:20 -0500877 {
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600878 /* RGB or RGBA */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600879 png_ptr->background_1.red = (png_uint_16)(pow(
Guy Schalnat0d580581995-07-20 02:43:20 -0500880 (double)png_ptr->background.red / m, g) * m + .5);
881 png_ptr->background_1.green = (png_uint_16)(pow(
882 (double)png_ptr->background.green / m, g) * m + .5);
883 png_ptr->background_1.blue = (png_uint_16)(pow(
884 (double)png_ptr->background.blue / m, g) * m + .5);
885 png_ptr->background.red = (png_uint_16)(pow(
886 (double)png_ptr->background.red / m, gs) * m + .5);
887 png_ptr->background.green = (png_uint_16)(pow(
888 (double)png_ptr->background.green / m, gs) * m + .5);
889 png_ptr->background.blue = (png_uint_16)(pow(
890 (double)png_ptr->background.blue / m, gs) * m + .5);
891 }
892 else
893 {
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600894 /* GRAY or GRAY ALPHA */
Guy Schalnat0d580581995-07-20 02:43:20 -0500895 png_ptr->background_1.gray = (png_uint_16)(pow(
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600896 (double)png_ptr->background.gray / m, g) * m + .5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500897 png_ptr->background.gray = (png_uint_16)(pow(
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600898 (double)png_ptr->background.gray / m, gs) * m + .5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500899 }
900 }
901 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500902 else
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600903 /* transformation does not include PNG_BACKGROUND */
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500904#endif /* PNG_READ_BACKGROUND_SUPPORTED */
Guy Schalnate5a37791996-06-05 15:50:50 -0500905 if (color_type == PNG_COLOR_TYPE_PALETTE)
906 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500907 png_colorp palette = png_ptr->palette;
908 int num_palette = png_ptr->num_palette;
909 int i;
Guy Schalnate5a37791996-06-05 15:50:50 -0500910
911 for (i = 0; i < num_palette; i++)
912 {
913 palette[i].red = png_ptr->gamma_table[palette[i].red];
914 palette[i].green = png_ptr->gamma_table[palette[i].green];
915 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
916 }
917 }
918 }
919#if defined(PNG_READ_BACKGROUND_SUPPORTED)
920 else
921#endif
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500922#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */
Guy Schalnate5a37791996-06-05 15:50:50 -0500923#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600924 /* No GAMMA transformation */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600925 if ((png_ptr->transformations & PNG_BACKGROUND) &&
926 (color_type == PNG_COLOR_TYPE_PALETTE))
Guy Schalnate5a37791996-06-05 15:50:50 -0500927 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500928 int i;
929 int istop = (int)png_ptr->num_trans;
Guy Schalnate5a37791996-06-05 15:50:50 -0500930 png_color back;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500931 png_colorp palette = png_ptr->palette;
Guy Schalnate5a37791996-06-05 15:50:50 -0500932
Guy Schalnate5a37791996-06-05 15:50:50 -0500933 back.red = (png_byte)png_ptr->background.red;
934 back.green = (png_byte)png_ptr->background.green;
935 back.blue = (png_byte)png_ptr->background.blue;
936
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500937 for (i = 0; i < istop; i++)
Guy Schalnate5a37791996-06-05 15:50:50 -0500938 {
939 if (png_ptr->trans[i] == 0)
940 {
941 palette[i] = back;
942 }
943 else if (png_ptr->trans[i] != 0xff)
944 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500945 /* The png_composite() macro is defined in png.h */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500946 png_composite(palette[i].red, palette[i].red,
947 png_ptr->trans[i], back.red);
948 png_composite(palette[i].green, palette[i].green,
949 png_ptr->trans[i], back.green);
950 png_composite(palette[i].blue, palette[i].blue,
951 png_ptr->trans[i], back.blue);
Guy Schalnate5a37791996-06-05 15:50:50 -0500952 }
953 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500954 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500955#endif /* PNG_READ_BACKGROUND_SUPPORTED */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500956
Guy Schalnat6d764711995-12-19 03:22:19 -0600957#if defined(PNG_READ_SHIFT_SUPPORTED)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500958 if ((png_ptr->transformations & PNG_SHIFT) &&
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600959 (color_type == PNG_COLOR_TYPE_PALETTE))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500960 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500961 png_uint_16 i;
962 png_uint_16 istop = png_ptr->num_palette;
963 int sr = 8 - png_ptr->sig_bit.red;
964 int sg = 8 - png_ptr->sig_bit.green;
965 int sb = 8 - png_ptr->sig_bit.blue;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500966
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500967 if (sr < 0 || sr > 8)
968 sr = 0;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500969 if (sg < 0 || sg > 8)
970 sg = 0;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500971 if (sb < 0 || sb > 8)
972 sb = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500973 for (i = 0; i < istop; i++)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500974 {
975 png_ptr->palette[i].red >>= sr;
976 png_ptr->palette[i].green >>= sg;
977 png_ptr->palette[i].blue >>= sb;
978 }
979 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500980#endif /* PNG_READ_SHIFT_SUPPORTED */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500981 }
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -0500982#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \
983 && !defined(PNG_READ_BACKGROUND_SUPPORTED)
984 if(png_ptr)
985 return;
986#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500987}
988
Andreas Dilger47a0c421997-05-16 02:46:07 -0500989/* Modify the info structure to reflect the transformations. The
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600990 * info should be updated so a PNG file could be written with it,
991 * assuming the transformations result in valid PNG data.
992 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500993void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -0600994png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500995{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500996 png_debug(1, "in png_read_transform_info\n");
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500997#if defined(PNG_READ_EXPAND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500998 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500999 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001000 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1001 {
1002 if (png_ptr->num_trans)
1003 info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1004 else
1005 info_ptr->color_type = PNG_COLOR_TYPE_RGB;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001006 info_ptr->bit_depth = 8;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001007 info_ptr->num_trans = 0;
1008 }
1009 else
1010 {
1011 if (png_ptr->num_trans)
1012 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
1013 if (info_ptr->bit_depth < 8)
1014 info_ptr->bit_depth = 8;
1015 info_ptr->num_trans = 0;
1016 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001017 }
1018#endif
1019
1020#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1021 if (png_ptr->transformations & PNG_BACKGROUND)
1022 {
1023 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
1024 info_ptr->num_trans = 0;
1025 info_ptr->background = png_ptr->background;
1026 }
1027#endif
1028
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001029#if defined(PNG_READ_GAMMA_SUPPORTED)
1030 if (png_ptr->transformations & PNG_GAMMA)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001031 {
1032#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001033 info_ptr->gamma = png_ptr->gamma;
1034#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001035#ifdef PNG_FIXED_POINT_SUPPORTED
1036 info_ptr->int_gamma = png_ptr->int_gamma;
1037#endif
1038 }
1039#endif
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001040
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001041#if defined(PNG_READ_16_TO_8_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001042 if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001043 info_ptr->bit_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001044#endif
1045
1046#if defined(PNG_READ_DITHER_SUPPORTED)
1047 if (png_ptr->transformations & PNG_DITHER)
1048 {
1049 if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
1050 (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
1051 png_ptr->palette_lookup && info_ptr->bit_depth == 8)
1052 {
1053 info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
1054 }
1055 }
1056#endif
1057
1058#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001059 if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001060 info_ptr->bit_depth = 8;
1061#endif
1062
1063#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001064 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001065 info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
1066#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001067
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001068#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1069 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1070 info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
1071#endif
1072
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001073 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001074 info_ptr->channels = 1;
1075 else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
1076 info_ptr->channels = 3;
1077 else
1078 info_ptr->channels = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001079
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001080#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001081 if (png_ptr->transformations & PNG_STRIP_ALPHA)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001082 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001083#endif
1084
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001085 if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
1086 info_ptr->channels++;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001087
1088#if defined(PNG_READ_FILLER_SUPPORTED)
1089 /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001090 if ((png_ptr->transformations & PNG_FILLER) &&
1091 ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
1092 (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001093 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001094 info_ptr->channels++;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001095#if 0 /* if adding a true alpha channel not just filler */
1096 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
1097#endif
1098 }
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001099#endif
1100
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001101#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
1102defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001103 if(png_ptr->transformations & PNG_USER_TRANSFORM)
1104 {
1105 if(info_ptr->bit_depth < png_ptr->user_transform_depth)
1106 info_ptr->bit_depth = png_ptr->user_transform_depth;
1107 if(info_ptr->channels < png_ptr->user_transform_channels)
1108 info_ptr->channels = png_ptr->user_transform_channels;
1109 }
1110#endif
1111
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001112 info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
1113 info_ptr->bit_depth);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001114 info_ptr->rowbytes = ((info_ptr->width * info_ptr->pixel_depth + 7) >> 3);
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05001115
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001116#if !defined(PNG_READ_EXPAND_SUPPORTED)
1117 if(png_ptr)
1118 return;
1119#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001120}
1121
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001122/* Transform the row. The order of transformations is significant,
1123 * and is very touchy. If you add a transformation, take care to
1124 * decide how it fits in with the other transformations here.
1125 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001126void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001127png_do_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05001128{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001129 png_debug(1, "in png_do_read_transformations\n");
1130#if !defined(PNG_USELESS_TESTS_SUPPORTED)
1131 if (png_ptr->row_buf == NULL)
1132 {
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -05001133#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001134 char msg[50];
1135
1136 sprintf(msg, "NULL row buffer for row %ld, pass %d", png_ptr->row_number,
1137 png_ptr->pass);
1138 png_error(png_ptr, msg);
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001139#else
1140 png_error(png_ptr, "NULL row buffer");
1141#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001142 }
1143#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001144
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001145#if defined(PNG_READ_EXPAND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001146 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05001147 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001148 if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
1149 {
1150 png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
1151 png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
1152 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001153 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001154 {
1155 if (png_ptr->num_trans)
1156 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1157 &(png_ptr->trans_values));
1158 else
1159 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1160 NULL);
1161 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001162 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001163#endif
1164
1165#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
1166 if (png_ptr->transformations & PNG_STRIP_ALPHA)
1167 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
1168 PNG_FLAG_FILLER_AFTER);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001169#endif
1170
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001171#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1172 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1173 {
1174 int rgb_error =
1175 png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1);
1176 if(rgb_error)
1177 {
1178 png_ptr->rgb_to_gray_status=1;
1179 if(png_ptr->transformations == PNG_RGB_TO_GRAY_WARN)
1180 png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1181 if(png_ptr->transformations == PNG_RGB_TO_GRAY_ERR)
1182 png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1183 }
1184 }
1185#endif
1186
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001187/*
1188From Andreas Dilger e-mail to png-implement, 26 March 1998:
1189
1190 In most cases, the "simple transparency" should be done prior to doing
1191 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 -06001192 pixel is transparent. You would also need to make sure that the
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001193 transparency information is upgraded to RGB.
1194
1195 To summarize, the current flow is:
1196 - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
1197 with background "in place" if transparent,
1198 convert to RGB if necessary
1199 - Gray + alpha -> composite with gray background and remove alpha bytes,
1200 convert to RGB if necessary
1201
1202 To support RGB backgrounds for gray images we need:
1203 - Gray + simple transparency -> convert to RGB + simple transparency, compare
1204 3 or 6 bytes and composite with background
1205 "in place" if transparent (3x compare/pixel
1206 compared to doing composite with gray bkgrnd)
1207 - Gray + alpha -> convert to RGB + alpha, composite with background and
1208 remove alpha bytes (3x float operations/pixel
1209 compared with composite on gray background)
1210
1211 Greg's change will do this. The reason it wasn't done before is for
1212 performance, as this increases the per-pixel operations. If we would check
1213 in advance if the background was gray or RGB, and position the gray-to-RGB
1214 transform appropriately, then it would save a lot of work/time.
1215 */
1216
1217#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1218 /* if gray -> RGB, do so now only if background is non-gray; else do later
1219 * for performance reasons */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001220 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001221 !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001222 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
1223#endif
1224
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001225#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001226 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1227 ((png_ptr->num_trans != 0 ) ||
1228 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
Guy Schalnat0d580581995-07-20 02:43:20 -05001229 png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001230 &(png_ptr->trans_values), &(png_ptr->background)
1231#if defined(PNG_READ_GAMMA_SUPPORTED)
1232 , &(png_ptr->background_1),
Guy Schalnat0d580581995-07-20 02:43:20 -05001233 png_ptr->gamma_table, png_ptr->gamma_from_1,
1234 png_ptr->gamma_to_1, png_ptr->gamma_16_table,
1235 png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001236 png_ptr->gamma_shift
1237#endif
1238);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001239#endif
1240
1241#if defined(PNG_READ_GAMMA_SUPPORTED)
1242 if ((png_ptr->transformations & PNG_GAMMA) &&
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001243#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1244 !((png_ptr->transformations & PNG_BACKGROUND) &&
1245 ((png_ptr->num_trans != 0) ||
1246 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
1247#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001248 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
Guy Schalnat0d580581995-07-20 02:43:20 -05001249 png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
1250 png_ptr->gamma_table, png_ptr->gamma_16_table,
1251 png_ptr->gamma_shift);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001252#endif
1253
1254#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001255 if (png_ptr->transformations & PNG_16_TO_8)
1256 png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001257#endif
1258
1259#if defined(PNG_READ_DITHER_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001260 if (png_ptr->transformations & PNG_DITHER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001261 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001262 png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
1263 png_ptr->palette_lookup, png_ptr->dither_index);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001264 if(png_ptr->row_info.rowbytes == (png_uint_32)0)
1265 png_error(png_ptr, "png_do_dither returned rowbytes=0");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001266 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001267#endif
1268
1269#if defined(PNG_READ_INVERT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001270 if (png_ptr->transformations & PNG_INVERT_MONO)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001271 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001272#endif
1273
1274#if defined(PNG_READ_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001275 if (png_ptr->transformations & PNG_SHIFT)
1276 png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
1277 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001278#endif
1279
1280#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001281 if (png_ptr->transformations & PNG_PACK)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001282 png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001283#endif
1284
1285#if defined(PNG_READ_BGR_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001286 if (png_ptr->transformations & PNG_BGR)
1287 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001288#endif
1289
Andreas Dilger47a0c421997-05-16 02:46:07 -05001290#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1291 if (png_ptr->transformations & PNG_PACKSWAP)
1292 png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1293#endif
1294
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001295#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001296 /* if gray -> RGB, do so now only if we did not do so above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001297 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
1298 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05001299 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001300#endif
1301
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001302#if defined(PNG_READ_FILLER_SUPPORTED)
1303 if (png_ptr->transformations & PNG_FILLER)
1304 png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001305 (png_uint_32)png_ptr->filler, png_ptr->flags);
1306#endif
1307
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001308#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
1309 if (png_ptr->transformations & PNG_INVERT_ALPHA)
1310 png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1311#endif
1312
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001313#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
1314 if (png_ptr->transformations & PNG_SWAP_ALPHA)
1315 png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1316#endif
1317
Andreas Dilger47a0c421997-05-16 02:46:07 -05001318#if defined(PNG_READ_SWAP_SUPPORTED)
1319 if (png_ptr->transformations & PNG_SWAP_BYTES)
1320 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001321#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001322
1323#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1324 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001325 {
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001326 if(png_ptr->read_user_transform_fn != NULL)
1327 (*(png_ptr->read_user_transform_fn)) /* user read transform function */
1328 (png_ptr, /* png_ptr */
1329 &(png_ptr->row_info), /* row_info: */
1330 /* png_uint_32 width; width of row */
1331 /* png_uint_32 rowbytes; number of bytes in row */
1332 /* png_byte color_type; color type of pixels */
1333 /* png_byte bit_depth; bit depth of samples */
1334 /* png_byte channels; number of channels (1-4) */
1335 /* png_byte pixel_depth; bits per pixel (depth*channels) */
1336 png_ptr->row_buf + 1); /* start of pixel data for row */
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001337#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001338 if(png_ptr->user_transform_depth)
1339 png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
1340 if(png_ptr->user_transform_channels)
1341 png_ptr->row_info.channels = png_ptr->user_transform_channels;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001342#endif
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001343 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
1344 png_ptr->row_info.channels);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001345 png_ptr->row_info.rowbytes = (png_ptr->row_info.width *
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001346 png_ptr->row_info.pixel_depth+7)>>3;
1347 }
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001348#endif
1349
Guy Schalnat0d580581995-07-20 02:43:20 -05001350}
1351
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001352#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001353/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
1354 * without changing the actual values. Thus, if you had a row with
1355 * a bit depth of 1, you would end up with bytes that only contained
1356 * the numbers 0 or 1. If you would rather they contain 0 and 255, use
1357 * png_do_shift() after this.
1358 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001359void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001360png_do_unpack(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001361{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001362 png_debug(1, "in png_do_unpack\n");
1363#if defined(PNG_USELESS_TESTS_SUPPORTED)
1364 if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
1365#else
1366 if (row_info->bit_depth < 8)
1367#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001368 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001369 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001370 png_uint_32 row_width=row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001371
Guy Schalnat0d580581995-07-20 02:43:20 -05001372 switch (row_info->bit_depth)
1373 {
1374 case 1:
1375 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001376 png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
1377 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001378 png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001379 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001380 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001381 *dp = (png_byte)((*sp >> shift) & 0x01);
Guy Schalnat0d580581995-07-20 02:43:20 -05001382 if (shift == 7)
1383 {
1384 shift = 0;
1385 sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001386 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001387 else
1388 shift++;
1389
1390 dp--;
1391 }
1392 break;
1393 }
1394 case 2:
1395 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001396
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001397 png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
1398 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001399 png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001400 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001401 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001402 *dp = (png_byte)((*sp >> shift) & 0x03);
Guy Schalnat0d580581995-07-20 02:43:20 -05001403 if (shift == 6)
1404 {
1405 shift = 0;
1406 sp--;
1407 }
1408 else
1409 shift += 2;
1410
1411 dp--;
1412 }
1413 break;
1414 }
1415 case 4:
1416 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001417 png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
1418 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001419 png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001420 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001421 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001422 *dp = (png_byte)((*sp >> shift) & 0x0f);
Guy Schalnat0d580581995-07-20 02:43:20 -05001423 if (shift == 4)
1424 {
1425 shift = 0;
1426 sp--;
1427 }
1428 else
1429 shift = 4;
1430
1431 dp--;
1432 }
1433 break;
1434 }
1435 }
1436 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001437 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001438 row_info->rowbytes = row_width * row_info->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001439 }
1440}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001441#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001442
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001443#if defined(PNG_READ_SHIFT_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001444/* Reverse the effects of png_do_shift. This routine merely shifts the
1445 * pixels back to their significant bits values. Thus, if you have
1446 * a row of bit depth 8, but only 5 are significant, this will shift
1447 * the values back to 0 through 31.
1448 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001449void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001450png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
Guy Schalnat0d580581995-07-20 02:43:20 -05001451{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001452 png_debug(1, "in png_do_unshift\n");
1453 if (
1454#if defined(PNG_USELESS_TESTS_SUPPORTED)
1455 row != NULL && row_info != NULL && sig_bits != NULL &&
1456#endif
1457 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001458 {
1459 int shift[4];
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001460 int channels = 0;
1461 int c;
1462 png_uint_16 value = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001463 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001464
Guy Schalnat0d580581995-07-20 02:43:20 -05001465 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
1466 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001467 shift[channels++] = row_info->bit_depth - sig_bits->red;
1468 shift[channels++] = row_info->bit_depth - sig_bits->green;
1469 shift[channels++] = row_info->bit_depth - sig_bits->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05001470 }
1471 else
1472 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001473 shift[channels++] = row_info->bit_depth - sig_bits->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05001474 }
1475 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
1476 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001477 shift[channels++] = row_info->bit_depth - sig_bits->alpha;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001478 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001479
Andreas Dilger47a0c421997-05-16 02:46:07 -05001480 for (c = 0; c < channels; c++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001481 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001482 if (shift[c] <= 0)
1483 shift[c] = 0;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001484 else
1485 value = 1;
1486 }
Guy Schalnat0f716451995-11-28 11:22:13 -06001487
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001488 if (!value)
1489 return;
Guy Schalnat0f716451995-11-28 11:22:13 -06001490
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001491 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05001492 {
1493 case 2:
1494 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001495 png_bytep bp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001496 png_uint_32 i;
1497 png_uint_32 istop = row_info->rowbytes;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001498
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001499 for (bp = row, i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001500 {
1501 *bp >>= 1;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001502 *bp++ &= 0x55;
Guy Schalnat0d580581995-07-20 02:43:20 -05001503 }
1504 break;
1505 }
1506 case 4:
1507 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001508 png_bytep bp = row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001509 png_uint_32 i;
1510 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001511 png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
1512 (png_byte)((int)0xf >> shift[0]));
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001513
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001514 for (i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001515 {
1516 *bp >>= shift[0];
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001517 *bp++ &= mask;
Guy Schalnat0d580581995-07-20 02:43:20 -05001518 }
1519 break;
1520 }
1521 case 8:
1522 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001523 png_bytep bp = row;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001524 png_uint_32 i;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001525 png_uint_32 istop = row_width * channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001526
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001527 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001528 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001529 *bp++ >>= shift[i%channels];
Guy Schalnat0d580581995-07-20 02:43:20 -05001530 }
1531 break;
1532 }
1533 case 16:
1534 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001535 png_bytep bp = row;
1536 png_uint_32 i;
1537 png_uint_32 istop = channels * row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001538
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001539 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001540 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001541 value = (png_uint_16)((*bp << 8) + *(bp + 1));
1542 value >>= shift[i%channels];
1543 *bp++ = (png_byte)(value >> 8);
1544 *bp++ = (png_byte)(value & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05001545 }
1546 break;
1547 }
1548 }
1549 }
1550}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001551#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001552
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001553#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001554/* chop rows of bit depth 16 down to 8 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001555void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001556png_do_chop(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001557{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001558 png_debug(1, "in png_do_chop\n");
1559#if defined(PNG_USELESS_TESTS_SUPPORTED)
1560 if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
1561#else
1562 if (row_info->bit_depth == 16)
1563#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001564 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001565 png_bytep sp = row;
1566 png_bytep dp = row;
1567 png_uint_32 i;
1568 png_uint_32 istop = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001569
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001570 for (i = 0; i<istop; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001571 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001572#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001573 /* This does a more accurate scaling of the 16-bit color
1574 * value, rather than a simple low-byte truncation.
1575 *
1576 * What the ideal calculation should be:
1577 * *dp = (((((png_uint_32)(*sp) << 8) |
1578 * (png_uint_32)(*(sp + 1))) * 255 + 127) / (png_uint_32)65535L;
1579 *
1580 * GRR: no, I think this is what it really should be:
1581 * *dp = (((((png_uint_32)(*sp) << 8) |
1582 * (png_uint_32)(*(sp + 1))) + 128L) / (png_uint_32)257L;
1583 *
1584 * GRR: here's the exact calculation with shifts:
1585 * temp = (((png_uint_32)(*sp) << 8) | (png_uint_32)(*(sp + 1))) + 128L;
1586 * *dp = (temp - (temp >> 8)) >> 8;
1587 *
1588 * Approximate calculation with shift/add instead of multiply/divide:
1589 * *dp = ((((png_uint_32)(*sp) << 8) |
1590 * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
1591 *
1592 * What we actually do to avoid extra shifting and conversion:
1593 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001594
Andreas Dilger47a0c421997-05-16 02:46:07 -05001595 *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
1596#else
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001597 /* Simply discard the low order byte */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001598 *dp = *sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001599#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001600 }
1601 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001602 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001603 row_info->rowbytes = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001604 }
1605}
1606#endif
1607
1608#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001609void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001610png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
1611{
1612 png_debug(1, "in png_do_read_swap_alpha\n");
1613#if defined(PNG_USELESS_TESTS_SUPPORTED)
1614 if (row != NULL && row_info != NULL)
1615#endif
1616 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001617 png_uint_32 row_width = row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001618 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1619 {
1620 /* This converts from RGBA to ARGB */
1621 if (row_info->bit_depth == 8)
1622 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001623 png_bytep sp = row + row_info->rowbytes;
1624 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001625 png_byte save;
1626 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001627
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001628 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001629 {
1630 save = *(--sp);
1631 *(--dp) = *(--sp);
1632 *(--dp) = *(--sp);
1633 *(--dp) = *(--sp);
1634 *(--dp) = save;
1635 }
1636 }
1637 /* This converts from RRGGBBAA to AARRGGBB */
1638 else
1639 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001640 png_bytep sp = row + row_info->rowbytes;
1641 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001642 png_byte save[2];
1643 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001644
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001645 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001646 {
1647 save[0] = *(--sp);
1648 save[1] = *(--sp);
1649 *(--dp) = *(--sp);
1650 *(--dp) = *(--sp);
1651 *(--dp) = *(--sp);
1652 *(--dp) = *(--sp);
1653 *(--dp) = *(--sp);
1654 *(--dp) = *(--sp);
1655 *(--dp) = save[0];
1656 *(--dp) = save[1];
1657 }
1658 }
1659 }
1660 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1661 {
1662 /* This converts from GA to AG */
1663 if (row_info->bit_depth == 8)
1664 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001665 png_bytep sp = row + row_info->rowbytes;
1666 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001667 png_byte save;
1668 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001669
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001670 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001671 {
1672 save = *(--sp);
1673 *(--dp) = *(--sp);
1674 *(--dp) = save;
1675 }
1676 }
1677 /* This converts from GGAA to AAGG */
1678 else
1679 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001680 png_bytep sp = row + row_info->rowbytes;
1681 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001682 png_byte save[2];
1683 png_uint_32 i;
1684
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001685 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001686 {
1687 save[0] = *(--sp);
1688 save[1] = *(--sp);
1689 *(--dp) = *(--sp);
1690 *(--dp) = *(--sp);
1691 *(--dp) = save[0];
1692 *(--dp) = save[1];
1693 }
1694 }
1695 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001696 }
1697}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001698#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001699
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001700#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001701void /* PRIVATE */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001702png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
1703{
1704 png_debug(1, "in png_do_read_invert_alpha\n");
1705#if defined(PNG_USELESS_TESTS_SUPPORTED)
1706 if (row != NULL && row_info != NULL)
1707#endif
1708 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001709 png_uint_32 row_width = row_info->width;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001710 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1711 {
1712 /* This inverts the alpha channel in RGBA */
1713 if (row_info->bit_depth == 8)
1714 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001715 png_bytep sp = row + row_info->rowbytes;
1716 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001717 png_uint_32 i;
1718
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001719 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001720 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001721 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001722
1723/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001724 *(--dp) = *(--sp);
1725 *(--dp) = *(--sp);
1726 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001727 We can replace it with:
1728*/
1729 sp-=3;
1730 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001731 }
1732 }
1733 /* This inverts the alpha channel in RRGGBBAA */
1734 else
1735 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001736 png_bytep sp = row + row_info->rowbytes;
1737 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001738 png_uint_32 i;
1739
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001740 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001741 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001742 *(--dp) = (png_byte)(255 - *(--sp));
1743 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001744
1745/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001746 *(--dp) = *(--sp);
1747 *(--dp) = *(--sp);
1748 *(--dp) = *(--sp);
1749 *(--dp) = *(--sp);
1750 *(--dp) = *(--sp);
1751 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001752 We can replace it with:
1753*/
1754 sp-=6;
1755 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001756 }
1757 }
1758 }
1759 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1760 {
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001761 /* This inverts the alpha channel in GA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001762 if (row_info->bit_depth == 8)
1763 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001764 png_bytep sp = row + row_info->rowbytes;
1765 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001766 png_uint_32 i;
1767
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001768 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001769 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001770 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001771 *(--dp) = *(--sp);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001772 }
1773 }
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001774 /* This inverts the alpha channel in GGAA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001775 else
1776 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001777 png_bytep sp = row + row_info->rowbytes;
1778 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001779 png_uint_32 i;
1780
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001781 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001782 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001783 *(--dp) = (png_byte)(255 - *(--sp));
1784 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001785/*
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001786 *(--dp) = *(--sp);
1787 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001788*/
1789 sp-=2;
1790 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001791 }
1792 }
1793 }
1794 }
1795}
1796#endif
1797
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001798#if defined(PNG_READ_FILLER_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001799/* Add filler channel if we have RGB color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001800void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001801png_do_read_filler(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001802 png_uint_32 filler, png_uint_32 flags)
Guy Schalnat0d580581995-07-20 02:43:20 -05001803{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001804 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001805 png_uint_32 row_width = row_info->width;
1806
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001807 png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001808 png_byte lo_filler = (png_byte)(filler & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001809
1810 png_debug(1, "in png_do_read_filler\n");
1811 if (
1812#if defined(PNG_USELESS_TESTS_SUPPORTED)
1813 row != NULL && row_info != NULL &&
1814#endif
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001815 row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001816 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001817 if(row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05001818 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001819 /* This changes the data from G to GX */
1820 if (flags & PNG_FLAG_FILLER_AFTER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001821 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001822 png_bytep sp = row + (png_size_t)row_width;
1823 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001824 for (i = 1; i < row_width; i++)
1825 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001826 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001827 *(--dp) = *(--sp);
1828 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001829 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001830 row_info->channels = 2;
1831 row_info->pixel_depth = 16;
1832 row_info->rowbytes = row_width * 2;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001833 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001834 /* This changes the data from G to XG */
1835 else
1836 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001837 png_bytep sp = row + (png_size_t)row_width;
1838 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001839 for (i = 0; i < row_width; i++)
1840 {
1841 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001842 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001843 }
1844 row_info->channels = 2;
1845 row_info->pixel_depth = 16;
1846 row_info->rowbytes = row_width * 2;
1847 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001848 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001849 else if(row_info->bit_depth == 16)
1850 {
1851 /* This changes the data from GG to GGXX */
1852 if (flags & PNG_FLAG_FILLER_AFTER)
1853 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001854 png_bytep sp = row + (png_size_t)row_width;
1855 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001856 for (i = 1; i < row_width; i++)
1857 {
1858 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001859 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001860 *(--dp) = *(--sp);
1861 *(--dp) = *(--sp);
1862 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001863 *(--dp) = hi_filler;
1864 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001865 row_info->channels = 2;
1866 row_info->pixel_depth = 32;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001867 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001868 }
1869 /* This changes the data from GG to XXGG */
1870 else
1871 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001872 png_bytep sp = row + (png_size_t)row_width;
1873 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001874 for (i = 0; i < row_width; i++)
1875 {
1876 *(--dp) = *(--sp);
1877 *(--dp) = *(--sp);
1878 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001879 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001880 }
1881 row_info->channels = 2;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001882 row_info->pixel_depth = 32;
1883 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001884 }
1885 }
1886 } /* COLOR_TYPE == GRAY */
1887 else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
1888 {
1889 if(row_info->bit_depth == 8)
1890 {
1891 /* This changes the data from RGB to RGBX */
1892 if (flags & PNG_FLAG_FILLER_AFTER)
1893 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001894 png_bytep sp = row + (png_size_t)row_width * 3;
1895 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001896 for (i = 1; i < row_width; i++)
1897 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001898 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001899 *(--dp) = *(--sp);
1900 *(--dp) = *(--sp);
1901 *(--dp) = *(--sp);
1902 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001903 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001904 row_info->channels = 4;
1905 row_info->pixel_depth = 32;
1906 row_info->rowbytes = row_width * 4;
1907 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001908 /* This changes the data from RGB to XRGB */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001909 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001910 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001911 png_bytep sp = row + (png_size_t)row_width * 3;
1912 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001913 for (i = 0; i < row_width; i++)
1914 {
1915 *(--dp) = *(--sp);
1916 *(--dp) = *(--sp);
1917 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001918 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001919 }
1920 row_info->channels = 4;
1921 row_info->pixel_depth = 32;
1922 row_info->rowbytes = row_width * 4;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001923 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001924 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001925 else if(row_info->bit_depth == 16)
1926 {
1927 /* This changes the data from RRGGBB to RRGGBBXX */
1928 if (flags & PNG_FLAG_FILLER_AFTER)
1929 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001930 png_bytep sp = row + (png_size_t)row_width * 3;
1931 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001932 for (i = 1; i < row_width; i++)
1933 {
1934 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001935 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001936 *(--dp) = *(--sp);
1937 *(--dp) = *(--sp);
1938 *(--dp) = *(--sp);
1939 *(--dp) = *(--sp);
1940 *(--dp) = *(--sp);
1941 *(--dp) = *(--sp);
1942 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001943 *(--dp) = hi_filler;
1944 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001945 row_info->channels = 4;
1946 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001947 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001948 }
1949 /* This changes the data from RRGGBB to XXRRGGBB */
1950 else
1951 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001952 png_bytep sp = row + (png_size_t)row_width * 3;
1953 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001954 for (i = 0; i < row_width; i++)
1955 {
1956 *(--dp) = *(--sp);
1957 *(--dp) = *(--sp);
1958 *(--dp) = *(--sp);
1959 *(--dp) = *(--sp);
1960 *(--dp) = *(--sp);
1961 *(--dp) = *(--sp);
1962 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001963 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001964 }
1965 row_info->channels = 4;
1966 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001967 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001968 }
1969 }
1970 } /* COLOR_TYPE == RGB */
Guy Schalnat0d580581995-07-20 02:43:20 -05001971}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001972#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001973
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001974#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001975/* expand grayscale files to RGB, with or without alpha */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001976void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001977png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001978{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001979 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001980 png_uint_32 row_width = row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06001981
Andreas Dilger47a0c421997-05-16 02:46:07 -05001982 png_debug(1, "in png_do_gray_to_rgb\n");
1983 if (row_info->bit_depth >= 8 &&
1984#if defined(PNG_USELESS_TESTS_SUPPORTED)
1985 row != NULL && row_info != NULL &&
1986#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001987 !(row_info->color_type & PNG_COLOR_MASK_COLOR))
1988 {
1989 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
1990 {
1991 if (row_info->bit_depth == 8)
1992 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001993 png_bytep sp = row + (png_size_t)row_width - 1;
1994 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001995 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001996 {
1997 *(dp--) = *sp;
1998 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001999 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002000 }
2001 }
2002 else
2003 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002004 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2005 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002006 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002007 {
2008 *(dp--) = *sp;
2009 *(dp--) = *(sp - 1);
2010 *(dp--) = *sp;
2011 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002012 *(dp--) = *(sp--);
2013 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002014 }
2015 }
2016 }
2017 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2018 {
2019 if (row_info->bit_depth == 8)
2020 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002021 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2022 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002023 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002024 {
2025 *(dp--) = *(sp--);
2026 *(dp--) = *sp;
2027 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002028 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002029 }
2030 }
2031 else
2032 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002033 png_bytep sp = row + (png_size_t)row_width * 4 - 1;
2034 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002035 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002036 {
2037 *(dp--) = *(sp--);
2038 *(dp--) = *(sp--);
2039 *(dp--) = *sp;
2040 *(dp--) = *(sp - 1);
2041 *(dp--) = *sp;
2042 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002043 *(dp--) = *(sp--);
2044 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002045 }
2046 }
2047 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002048 row_info->channels += (png_byte)2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002049 row_info->color_type |= PNG_COLOR_MASK_COLOR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002050 row_info->pixel_depth = (png_byte)(row_info->channels *
2051 row_info->bit_depth);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002052 row_info->rowbytes = ((row_width *
Guy Schalnat0d580581995-07-20 02:43:20 -05002053 row_info->pixel_depth + 7) >> 3);
2054 }
2055}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002056#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002057
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002058#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002059/* reduce RGB files to grayscale, with or without alpha
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002060 * using the equation given in Poynton's ColorFAQ at
2061 * <http://www.inforamp.net/~poynton/>
2062 * Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net
2063 *
2064 * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
2065 *
2066 * We approximate this with
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002067 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002068 * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002069 *
2070 * which can be expressed with integers as
2071 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002072 * Y = (6969 * R + 23434 * G + 2365 * B)/32768
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002073 *
2074 * The calculation is to be done in a linear colorspace.
2075 *
2076 * Other integer coefficents can be used via png_set_rgb_to_gray().
2077 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002078int /* PRIVATE */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002079png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
2080
2081{
2082 png_uint_32 i;
2083
2084 png_uint_32 row_width = row_info->width;
2085 int rgb_error = 0;
2086
2087 png_debug(1, "in png_do_rgb_to_gray\n");
2088 if (
2089#if defined(PNG_USELESS_TESTS_SUPPORTED)
2090 row != NULL && row_info != NULL &&
2091#endif
2092 (row_info->color_type & PNG_COLOR_MASK_COLOR))
2093 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002094 png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
2095 png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
2096 png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002097
2098 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2099 {
2100 if (row_info->bit_depth == 8)
2101 {
2102#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2103 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2104 {
2105 png_bytep sp = row;
2106 png_bytep dp = row;
2107
2108 for (i = 0; i < row_width; i++)
2109 {
2110 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2111 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2112 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
2113 if(red != green || red != blue)
2114 {
2115 rgb_error |= 1;
2116 *(dp++) = png_ptr->gamma_from_1[
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002117 (rc*red+gc*green+bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002118 }
2119 else
2120 *(dp++) = *(sp-1);
2121 }
2122 }
2123 else
2124#endif
2125 {
2126 png_bytep sp = row;
2127 png_bytep dp = row;
2128 for (i = 0; i < row_width; i++)
2129 {
2130 png_byte red = *(sp++);
2131 png_byte green = *(sp++);
2132 png_byte blue = *(sp++);
2133 if(red != green || red != blue)
2134 {
2135 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002136 *(dp++) = (png_byte)((rc*red+gc*green+bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002137 }
2138 else
2139 *(dp++) = *(sp-1);
2140 }
2141 }
2142 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002143
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002144 else /* RGB bit_depth == 16 */
2145 {
2146#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2147 if (png_ptr->gamma_16_to_1 != NULL &&
2148 png_ptr->gamma_16_from_1 != NULL)
2149 {
2150 png_bytep sp = row;
2151 png_bytep dp = row;
2152 for (i = 0; i < row_width; i++)
2153 {
2154 png_uint_16 red, green, blue, w;
2155
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002156 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2157 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2158 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002159
2160 if(red == green && red == blue)
2161 w = red;
2162 else
2163 {
2164 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2165 png_ptr->gamma_shift][red>>8];
2166 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2167 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002168 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002169 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002170 png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002171 + bc*blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002172 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2173 png_ptr->gamma_shift][gray16 >> 8];
2174 rgb_error |= 1;
2175 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002176
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002177 *(dp++) = (png_byte)((w>>8) & 0xff);
2178 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002179 }
2180 }
2181 else
2182#endif
2183 {
2184 png_bytep sp = row;
2185 png_bytep dp = row;
2186 for (i = 0; i < row_width; i++)
2187 {
2188 png_uint_16 red, green, blue, gray16;
2189
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002190 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2191 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2192 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002193
2194 if(red != green || red != blue)
2195 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002196 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002197 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2198 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002199 }
2200 }
2201 }
2202 }
2203 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2204 {
2205 if (row_info->bit_depth == 8)
2206 {
2207#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2208 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2209 {
2210 png_bytep sp = row;
2211 png_bytep dp = row;
2212 for (i = 0; i < row_width; i++)
2213 {
2214 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2215 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2216 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
2217 if(red != green || red != blue)
2218 rgb_error |= 1;
2219 *(dp++) = png_ptr->gamma_from_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002220 [(rc*red + gc*green + bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002221 *(dp++) = *(sp++); /* alpha */
2222 }
2223 }
2224 else
2225#endif
2226 {
2227 png_bytep sp = row;
2228 png_bytep dp = row;
2229 for (i = 0; i < row_width; i++)
2230 {
2231 png_byte red = *(sp++);
2232 png_byte green = *(sp++);
2233 png_byte blue = *(sp++);
2234 if(red != green || red != blue)
2235 rgb_error |= 1;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002236 *(dp++) = (png_byte)((gc*red + gc*green + bc*blue)>>8);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002237 *(dp++) = *(sp++); /* alpha */
2238 }
2239 }
2240 }
2241 else /* RGBA bit_depth == 16 */
2242 {
2243#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2244 if (png_ptr->gamma_16_to_1 != NULL &&
2245 png_ptr->gamma_16_from_1 != NULL)
2246 {
2247 png_bytep sp = row;
2248 png_bytep dp = row;
2249 for (i = 0; i < row_width; i++)
2250 {
2251 png_uint_16 red, green, blue, w;
2252
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002253 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2254 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2255 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002256
2257 if(red == green && red == blue)
2258 w = red;
2259 else
2260 {
2261 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2262 png_ptr->gamma_shift][red>>8];
2263 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2264 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002265 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002266 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002267 png_uint_16 gray16 = (png_uint_16)((rc * red_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002268 + gc * green_1 + bc * blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002269 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2270 png_ptr->gamma_shift][gray16 >> 8];
2271 rgb_error |= 1;
2272 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002273
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002274 *(dp++) = (png_byte)((w>>8) & 0xff);
2275 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002276 *(dp++) = *(sp++); /* alpha */
2277 *(dp++) = *(sp++);
2278 }
2279 }
2280 else
2281#endif
2282 {
2283 png_bytep sp = row;
2284 png_bytep dp = row;
2285 for (i = 0; i < row_width; i++)
2286 {
2287 png_uint_16 red, green, blue, gray16;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002288 red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2289 green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2290 blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002291 if(red != green || red != blue)
2292 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002293 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002294 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2295 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002296 *(dp++) = *(sp++); /* alpha */
2297 *(dp++) = *(sp++);
2298 }
2299 }
2300 }
2301 }
2302 row_info->channels -= (png_byte)2;
2303 row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
2304 row_info->pixel_depth = (png_byte)(row_info->channels *
2305 row_info->bit_depth);
2306 row_info->rowbytes = ((row_width *
2307 row_info->pixel_depth + 7) >> 3);
2308 }
2309 return rgb_error;
2310}
2311#endif
2312
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002313/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
2314 * large of png_color. This lets grayscale images be treated as
2315 * paletted. Most useful for gamma correction and simplification
2316 * of code.
2317 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002318void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002319png_build_grayscale_palette(int bit_depth, png_colorp palette)
Guy Schalnat0d580581995-07-20 02:43:20 -05002320{
2321 int num_palette;
2322 int color_inc;
2323 int i;
2324 int v;
2325
Andreas Dilger47a0c421997-05-16 02:46:07 -05002326 png_debug(1, "in png_do_build_grayscale_palette\n");
2327 if (palette == NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002328 return;
2329
2330 switch (bit_depth)
2331 {
2332 case 1:
2333 num_palette = 2;
2334 color_inc = 0xff;
2335 break;
2336 case 2:
2337 num_palette = 4;
2338 color_inc = 0x55;
2339 break;
2340 case 4:
2341 num_palette = 16;
2342 color_inc = 0x11;
2343 break;
2344 case 8:
2345 num_palette = 256;
2346 color_inc = 1;
2347 break;
2348 default:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002349 num_palette = 0;
Guy Schalnat69b14481996-01-10 02:56:49 -06002350 color_inc = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002351 break;
2352 }
2353
2354 for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
2355 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002356 palette[i].red = (png_byte)v;
2357 palette[i].green = (png_byte)v;
2358 palette[i].blue = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002359 }
2360}
2361
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002362/* This function is currently unused. Do we really need it? */
2363#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002364void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002365png_correct_palette(png_structp png_ptr, png_colorp palette,
Guy Schalnat0d580581995-07-20 02:43:20 -05002366 int num_palette)
2367{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002368 png_debug(1, "in png_correct_palette\n");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002369#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
2370 defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002371 if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND))
Guy Schalnat0d580581995-07-20 02:43:20 -05002372 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002373 png_color back, back_1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002374
Andreas Dilger47a0c421997-05-16 02:46:07 -05002375 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
2376 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002377 back.red = png_ptr->gamma_table[png_ptr->background.red];
2378 back.green = png_ptr->gamma_table[png_ptr->background.green];
2379 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
Guy Schalnat0d580581995-07-20 02:43:20 -05002380
Guy Schalnate5a37791996-06-05 15:50:50 -05002381 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
2382 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
2383 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002384 }
2385 else
2386 {
2387 double g;
Guy Schalnat0d580581995-07-20 02:43:20 -05002388
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06002389 g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002390
2391 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
2392 fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
Guy Schalnat0d580581995-07-20 02:43:20 -05002393 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002394 back.red = png_ptr->background.red;
2395 back.green = png_ptr->background.green;
2396 back.blue = png_ptr->background.blue;
2397 }
2398 else
2399 {
2400 back.red =
2401 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2402 255.0 + 0.5);
2403 back.green =
2404 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2405 255.0 + 0.5);
2406 back.blue =
2407 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2408 255.0 + 0.5);
2409 }
2410
2411 g = 1.0 / png_ptr->background_gamma;
2412
2413 back_1.red =
2414 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2415 255.0 + 0.5);
2416 back_1.green =
2417 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2418 255.0 + 0.5);
2419 back_1.blue =
2420 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2421 255.0 + 0.5);
2422 }
2423
2424 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2425 {
2426 png_uint_32 i;
2427
2428 for (i = 0; i < (png_uint_32)num_palette; i++)
2429 {
2430 if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -05002431 {
2432 palette[i] = back;
2433 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002434 else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002435 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002436 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05002437
2438 v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002439 png_composite(w, v, png_ptr->trans[i], back_1.red);
2440 palette[i].red = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002441
2442 v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002443 png_composite(w, v, png_ptr->trans[i], back_1.green);
2444 palette[i].green = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002445
2446 v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002447 png_composite(w, v, png_ptr->trans[i], back_1.blue);
2448 palette[i].blue = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002449 }
2450 else
2451 {
2452 palette[i].red = png_ptr->gamma_table[palette[i].red];
2453 palette[i].green = png_ptr->gamma_table[palette[i].green];
2454 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2455 }
2456 }
2457 }
2458 else
2459 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002460 int i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002461
2462 for (i = 0; i < num_palette; i++)
2463 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002464 if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002465 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002466 palette[i] = back;
Guy Schalnat0d580581995-07-20 02:43:20 -05002467 }
2468 else
2469 {
2470 palette[i].red = png_ptr->gamma_table[palette[i].red];
2471 palette[i].green = png_ptr->gamma_table[palette[i].green];
2472 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2473 }
2474 }
2475 }
2476 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002477 else
2478#endif
2479#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002480 if (png_ptr->transformations & PNG_GAMMA)
Guy Schalnat0d580581995-07-20 02:43:20 -05002481 {
2482 int i;
2483
2484 for (i = 0; i < num_palette; i++)
2485 {
2486 palette[i].red = png_ptr->gamma_table[palette[i].red];
2487 palette[i].green = png_ptr->gamma_table[palette[i].green];
2488 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2489 }
2490 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002491#if defined(PNG_READ_BACKGROUND_SUPPORTED)
2492 else
2493#endif
2494#endif
2495#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002496 if (png_ptr->transformations & PNG_BACKGROUND)
Guy Schalnat0d580581995-07-20 02:43:20 -05002497 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002498 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05002499 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002500 png_color back;
Guy Schalnat0d580581995-07-20 02:43:20 -05002501
Guy Schalnate5a37791996-06-05 15:50:50 -05002502 back.red = (png_byte)png_ptr->background.red;
2503 back.green = (png_byte)png_ptr->background.green;
2504 back.blue = (png_byte)png_ptr->background.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002505
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06002506 for (i = 0; i < (int)png_ptr->num_trans; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002507 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002508 if (png_ptr->trans[i] == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -05002509 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002510 palette[i].red = back.red;
2511 palette[i].green = back.green;
2512 palette[i].blue = back.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002513 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002514 else if (png_ptr->trans[i] != 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002515 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002516 png_composite(palette[i].red, png_ptr->palette[i].red,
2517 png_ptr->trans[i], back.red);
2518 png_composite(palette[i].green, png_ptr->palette[i].green,
2519 png_ptr->trans[i], back.green);
2520 png_composite(palette[i].blue, png_ptr->palette[i].blue,
2521 png_ptr->trans[i], back.blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05002522 }
2523 }
2524 }
2525 else /* assume grayscale palette (what else could it be?) */
2526 {
2527 int i;
2528
2529 for (i = 0; i < num_palette; i++)
2530 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002531 if (i == (png_byte)png_ptr->trans_values.gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002532 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002533 palette[i].red = (png_byte)png_ptr->background.red;
2534 palette[i].green = (png_byte)png_ptr->background.green;
2535 palette[i].blue = (png_byte)png_ptr->background.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002536 }
2537 }
2538 }
2539 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002540#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002541}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002542#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002543
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002544#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002545/* Replace any alpha or transparency with the supplied background color.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002546 * "background" is already in the screen gamma, while "background_1" is
2547 * at a gamma of 1.0. Paletted files have already been taken care of.
2548 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002549void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002550png_do_background(png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002551 png_color_16p trans_values, png_color_16p background
2552#if defined(PNG_READ_GAMMA_SUPPORTED)
2553 , png_color_16p background_1,
Guy Schalnat6d764711995-12-19 03:22:19 -06002554 png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002555 png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002556 png_uint_16pp gamma_16_to_1, int gamma_shift
2557#endif
2558 )
Guy Schalnat0d580581995-07-20 02:43:20 -05002559{
Guy Schalnat6d764711995-12-19 03:22:19 -06002560 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002561 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002562 png_uint_32 row_width=row_info->width;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002563 int shift;
Guy Schalnate5a37791996-06-05 15:50:50 -05002564
Andreas Dilger47a0c421997-05-16 02:46:07 -05002565 png_debug(1, "in png_do_background\n");
2566 if (background != NULL &&
2567#if defined(PNG_USELESS_TESTS_SUPPORTED)
2568 row != NULL && row_info != NULL &&
2569#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002570 (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
Andreas Dilger47a0c421997-05-16 02:46:07 -05002571 (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
Guy Schalnat0d580581995-07-20 02:43:20 -05002572 {
2573 switch (row_info->color_type)
2574 {
2575 case PNG_COLOR_TYPE_GRAY:
2576 {
2577 switch (row_info->bit_depth)
2578 {
2579 case 1:
2580 {
Guy Schalnat0d580581995-07-20 02:43:20 -05002581 sp = row;
2582 shift = 7;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002583 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002584 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002585 if ((png_uint_16)((*sp >> shift) & 0x01)
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002586 == trans_values->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002587 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002588 *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2589 *sp |= (png_byte)(background->gray << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002590 }
2591 if (!shift)
2592 {
2593 shift = 7;
2594 sp++;
2595 }
2596 else
2597 shift--;
2598 }
2599 break;
2600 }
2601 case 2:
2602 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002603#if defined(PNG_READ_GAMMA_SUPPORTED)
2604 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002605 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002606 sp = row;
2607 shift = 6;
2608 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002609 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002610 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002611 == trans_values->gray)
2612 {
2613 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2614 *sp |= (png_byte)(background->gray << shift);
2615 }
2616 else
2617 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002618 png_byte p = (png_byte)((*sp >> shift) & 0x03);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002619 png_byte g = (png_byte)((gamma_table [p | (p << 2) |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002620 (p << 4) | (p << 6)] >> 6) & 0x03);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002621 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2622 *sp |= (png_byte)(g << shift);
2623 }
2624 if (!shift)
2625 {
2626 shift = 6;
2627 sp++;
2628 }
2629 else
2630 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002631 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002632 }
2633 else
2634#endif
2635 {
2636 sp = row;
2637 shift = 6;
2638 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002639 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002640 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002641 == trans_values->gray)
2642 {
2643 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2644 *sp |= (png_byte)(background->gray << shift);
2645 }
2646 if (!shift)
2647 {
2648 shift = 6;
2649 sp++;
2650 }
2651 else
2652 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002653 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002654 }
2655 break;
2656 }
2657 case 4:
2658 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002659#if defined(PNG_READ_GAMMA_SUPPORTED)
2660 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002661 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002662 sp = row;
2663 shift = 4;
2664 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002665 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002666 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002667 == trans_values->gray)
2668 {
2669 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2670 *sp |= (png_byte)(background->gray << shift);
2671 }
2672 else
2673 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002674 png_byte p = (png_byte)((*sp >> shift) & 0x0f);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002675 png_byte g = (png_byte)((gamma_table[p |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002676 (p << 4)] >> 4) & 0x0f);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002677 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2678 *sp |= (png_byte)(g << shift);
2679 }
2680 if (!shift)
2681 {
2682 shift = 4;
2683 sp++;
2684 }
2685 else
2686 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002687 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002688 }
2689 else
2690#endif
2691 {
2692 sp = row;
2693 shift = 4;
2694 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002695 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002696 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002697 == trans_values->gray)
2698 {
2699 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2700 *sp |= (png_byte)(background->gray << shift);
2701 }
2702 if (!shift)
2703 {
2704 shift = 4;
2705 sp++;
2706 }
2707 else
2708 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002709 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002710 }
2711 break;
2712 }
2713 case 8:
2714 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002715#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002716 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002717 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002718 sp = row;
2719 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002720 {
2721 if (*sp == trans_values->gray)
2722 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002723 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002724 }
2725 else
2726 {
2727 *sp = gamma_table[*sp];
2728 }
2729 }
2730 }
2731 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002732#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002733 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002734 sp = row;
2735 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002736 {
2737 if (*sp == trans_values->gray)
2738 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002739 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002740 }
2741 }
2742 }
2743 break;
2744 }
2745 case 16:
2746 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002747#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002748 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002749 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002750 sp = row;
2751 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002752 {
2753 png_uint_16 v;
2754
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002755 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05002756 if (v == trans_values->gray)
2757 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002758 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002759 *sp = (png_byte)((background->gray >> 8) & 0xff);
2760 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002761 }
2762 else
2763 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002764 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002765 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002766 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002767 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002768 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002769 }
2770 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002771#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002772 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002773 sp = row;
2774 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002775 {
2776 png_uint_16 v;
2777
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002778 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05002779 if (v == trans_values->gray)
2780 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002781 *sp = (png_byte)((background->gray >> 8) & 0xff);
2782 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002783 }
2784 }
2785 }
2786 break;
2787 }
2788 }
2789 break;
2790 }
2791 case PNG_COLOR_TYPE_RGB:
2792 {
2793 if (row_info->bit_depth == 8)
2794 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002795#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002796 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002797 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002798 sp = row;
2799 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002800 {
2801 if (*sp == trans_values->red &&
2802 *(sp + 1) == trans_values->green &&
2803 *(sp + 2) == trans_values->blue)
2804 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002805 *sp = (png_byte)background->red;
2806 *(sp + 1) = (png_byte)background->green;
2807 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002808 }
2809 else
2810 {
2811 *sp = gamma_table[*sp];
2812 *(sp + 1) = gamma_table[*(sp + 1)];
2813 *(sp + 2) = gamma_table[*(sp + 2)];
2814 }
2815 }
2816 }
2817 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002818#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002819 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002820 sp = row;
2821 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002822 {
2823 if (*sp == trans_values->red &&
2824 *(sp + 1) == trans_values->green &&
2825 *(sp + 2) == trans_values->blue)
2826 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002827 *sp = (png_byte)background->red;
2828 *(sp + 1) = (png_byte)background->green;
2829 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002830 }
2831 }
2832 }
2833 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002834 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05002835 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002836#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002837 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002838 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002839 sp = row;
2840 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002841 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002842 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2843 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2844 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05002845 if (r == trans_values->red && g == trans_values->green &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002846 b == trans_values->blue)
2847 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002848 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002849 *sp = (png_byte)((background->red >> 8) & 0xff);
2850 *(sp + 1) = (png_byte)(background->red & 0xff);
2851 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2852 *(sp + 3) = (png_byte)(background->green & 0xff);
2853 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2854 *(sp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002855 }
2856 else
2857 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002858 png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002859 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002860 *(sp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002861 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002862 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
2863 *(sp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002864 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002865 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
2866 *(sp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002867 }
2868 }
2869 }
2870 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002871#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002872 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002873 sp = row;
2874 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05002875 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002876 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
2877 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2878 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Guy Schalnat0d580581995-07-20 02:43:20 -05002879
Andreas Dilger47a0c421997-05-16 02:46:07 -05002880 if (r == trans_values->red && g == trans_values->green &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002881 b == trans_values->blue)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002882 {
2883 *sp = (png_byte)((background->red >> 8) & 0xff);
2884 *(sp + 1) = (png_byte)(background->red & 0xff);
2885 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2886 *(sp + 3) = (png_byte)(background->green & 0xff);
2887 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2888 *(sp + 5) = (png_byte)(background->blue & 0xff);
2889 }
2890 }
2891 }
2892 }
2893 break;
2894 }
2895 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -05002896 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002897 if (row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002898 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002899#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002900 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
2901 gamma_table != NULL)
2902 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002903 sp = row;
2904 dp = row;
2905 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002906 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002907 png_uint_16 a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002908
Andreas Dilger47a0c421997-05-16 02:46:07 -05002909 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002910 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002911 *dp = gamma_table[*sp];
2912 }
2913 else if (a == 0)
2914 {
2915 /* background is already in screen gamma */
2916 *dp = (png_byte)background->gray;
2917 }
2918 else
2919 {
2920 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05002921
Andreas Dilger47a0c421997-05-16 02:46:07 -05002922 v = gamma_to_1[*sp];
2923 png_composite(w, v, a, background_1->gray);
2924 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002925 }
2926 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002927 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002928 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002929#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002930 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002931 sp = row;
2932 dp = row;
2933 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002934 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002935 png_byte a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002936
Andreas Dilger47a0c421997-05-16 02:46:07 -05002937 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002938 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002939 *dp = *sp;
2940 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002941#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002942 else if (a == 0)
2943 {
2944 *dp = (png_byte)background->gray;
2945 }
2946 else
2947 {
2948 png_composite(*dp, *sp, a, background_1->gray);
Guy Schalnat0d580581995-07-20 02:43:20 -05002949 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002950#else
2951 *dp = (png_byte)background->gray;
2952#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002953 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002954 }
2955 }
2956 else /* if (png_ptr->bit_depth == 16) */
2957 {
2958#if defined(PNG_READ_GAMMA_SUPPORTED)
2959 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
2960 gamma_16_to_1 != NULL)
2961 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002962 sp = row;
2963 dp = row;
2964 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002965 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002966 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05002967
Andreas Dilger47a0c421997-05-16 02:46:07 -05002968 if (a == (png_uint_16)0xffff)
2969 {
2970 png_uint_16 v;
2971
2972 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
2973 *dp = (png_byte)((v >> 8) & 0xff);
2974 *(dp + 1) = (png_byte)(v & 0xff);
2975 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002976#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002977 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002978#else
2979 else
2980#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002981 {
2982 /* background is already in screen gamma */
2983 *dp = (png_byte)((background->gray >> 8) & 0xff);
2984 *(dp + 1) = (png_byte)(background->gray & 0xff);
2985 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002986#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002987 else
2988 {
2989 png_uint_16 g, v, w;
2990
2991 g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
2992 png_composite_16(v, g, a, background_1->gray);
2993 w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
2994 *dp = (png_byte)((w >> 8) & 0xff);
2995 *(dp + 1) = (png_byte)(w & 0xff);
2996 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002997#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002998 }
2999 }
3000 else
3001#endif
3002 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003003 sp = row;
3004 dp = row;
3005 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003006 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003007 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003008 if (a == (png_uint_16)0xffff)
3009 {
3010 png_memcpy(dp, sp, 2);
3011 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003012#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003013 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003014#else
3015 else
3016#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003017 {
3018 *dp = (png_byte)((background->gray >> 8) & 0xff);
3019 *(dp + 1) = (png_byte)(background->gray & 0xff);
3020 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003021#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003022 else
3023 {
3024 png_uint_16 g, v;
3025
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003026 g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003027 png_composite_16(v, g, a, background_1->gray);
3028 *dp = (png_byte)((v >> 8) & 0xff);
3029 *(dp + 1) = (png_byte)(v & 0xff);
3030 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003031#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003032 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003033 }
3034 }
3035 break;
3036 }
3037 case PNG_COLOR_TYPE_RGB_ALPHA:
3038 {
3039 if (row_info->bit_depth == 8)
3040 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003041#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003042 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3043 gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003044 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003045 sp = row;
3046 dp = row;
3047 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003048 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003049 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003050
Guy Schalnat0d580581995-07-20 02:43:20 -05003051 if (a == 0xff)
3052 {
3053 *dp = gamma_table[*sp];
3054 *(dp + 1) = gamma_table[*(sp + 1)];
3055 *(dp + 2) = gamma_table[*(sp + 2)];
3056 }
3057 else if (a == 0)
3058 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003059 /* background is already in screen gamma */
3060 *dp = (png_byte)background->red;
3061 *(dp + 1) = (png_byte)background->green;
3062 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003063 }
3064 else
3065 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003066 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05003067
3068 v = gamma_to_1[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003069 png_composite(w, v, a, background_1->red);
3070 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003071 v = gamma_to_1[*(sp + 1)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003072 png_composite(w, v, a, background_1->green);
3073 *(dp + 1) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003074 v = gamma_to_1[*(sp + 2)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003075 png_composite(w, v, a, background_1->blue);
3076 *(dp + 2) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003077 }
3078 }
3079 }
3080 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003081#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003082 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003083 sp = row;
3084 dp = row;
3085 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003086 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003087 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003088
Guy Schalnat0d580581995-07-20 02:43:20 -05003089 if (a == 0xff)
3090 {
3091 *dp = *sp;
3092 *(dp + 1) = *(sp + 1);
3093 *(dp + 2) = *(sp + 2);
3094 }
3095 else if (a == 0)
3096 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003097 *dp = (png_byte)background->red;
3098 *(dp + 1) = (png_byte)background->green;
3099 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003100 }
3101 else
3102 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003103 png_composite(*dp, *sp, a, background->red);
3104 png_composite(*(dp + 1), *(sp + 1), a,
3105 background->green);
3106 png_composite(*(dp + 2), *(sp + 2), a,
3107 background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003108 }
3109 }
3110 }
3111 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003112 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003113 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003114#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003115 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3116 gamma_16_to_1 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003117 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003118 sp = row;
3119 dp = row;
3120 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003121 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003122 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3123 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003124 if (a == (png_uint_16)0xffff)
3125 {
3126 png_uint_16 v;
3127
Andreas Dilger47a0c421997-05-16 02:46:07 -05003128 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003129 *dp = (png_byte)((v >> 8) & 0xff);
3130 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003131 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003132 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3133 *(dp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003134 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003135 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3136 *(dp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003137 }
3138 else if (a == 0)
3139 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003140 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003141 *dp = (png_byte)((background->red >> 8) & 0xff);
3142 *(dp + 1) = (png_byte)(background->red & 0xff);
3143 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3144 *(dp + 3) = (png_byte)(background->green & 0xff);
3145 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3146 *(dp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003147 }
3148 else
3149 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003150 png_uint_16 v, w, x;
Guy Schalnat0d580581995-07-20 02:43:20 -05003151
Andreas Dilger47a0c421997-05-16 02:46:07 -05003152 v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3153 png_composite_16(w, v, a, background->red);
3154 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3155 *dp = (png_byte)((x >> 8) & 0xff);
3156 *(dp + 1) = (png_byte)(x & 0xff);
3157 v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
3158 png_composite_16(w, v, a, background->green);
3159 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3160 *(dp + 2) = (png_byte)((x >> 8) & 0xff);
3161 *(dp + 3) = (png_byte)(x & 0xff);
3162 v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
3163 png_composite_16(w, v, a, background->blue);
3164 x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
3165 *(dp + 4) = (png_byte)((x >> 8) & 0xff);
3166 *(dp + 5) = (png_byte)(x & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003167 }
3168 }
3169 }
3170 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003171#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003172 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003173 sp = row;
3174 dp = row;
3175 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003176 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003177 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3178 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003179 if (a == (png_uint_16)0xffff)
3180 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003181 png_memcpy(dp, sp, 6);
Guy Schalnat0d580581995-07-20 02:43:20 -05003182 }
3183 else if (a == 0)
3184 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003185 *dp = (png_byte)((background->red >> 8) & 0xff);
3186 *(dp + 1) = (png_byte)(background->red & 0xff);
3187 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3188 *(dp + 3) = (png_byte)(background->green & 0xff);
3189 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3190 *(dp + 5) = (png_byte)(background->blue & 0xff);
3191 }
3192 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003193 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003194 png_uint_16 v;
Guy Schalnat0d580581995-07-20 02:43:20 -05003195
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003196 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3197 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3198 + *(sp + 3));
3199 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3200 + *(sp + 5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003201
3202 png_composite_16(v, r, a, background->red);
Guy Schalnat0d580581995-07-20 02:43:20 -05003203 *dp = (png_byte)((v >> 8) & 0xff);
3204 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003205 png_composite_16(v, g, a, background->green);
Guy Schalnat0d580581995-07-20 02:43:20 -05003206 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3207 *(dp + 3) = (png_byte)(v & 0xff);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003208 png_composite_16(v, b, a, background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003209 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3210 *(dp + 5) = (png_byte)(v & 0xff);
3211 }
3212 }
3213 }
3214 }
3215 break;
3216 }
3217 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003218
Guy Schalnat0d580581995-07-20 02:43:20 -05003219 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
3220 {
3221 row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
Guy Schalnate5a37791996-06-05 15:50:50 -05003222 row_info->channels--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003223 row_info->pixel_depth = (png_byte)(row_info->channels *
3224 row_info->bit_depth);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003225 row_info->rowbytes = ((row_width *
Guy Schalnat0d580581995-07-20 02:43:20 -05003226 row_info->pixel_depth + 7) >> 3);
3227 }
3228 }
3229}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003230#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003231
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003232#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003233/* Gamma correct the image, avoiding the alpha channel. Make sure
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003234 * you do this after you deal with the transparency issue on grayscale
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003235 * or RGB images. If your bit depth is 8, use gamma_table, if it
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003236 * is 16, use gamma_16_table and gamma_shift. Build these with
3237 * build_gamma_table().
3238 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003239void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003240png_do_gamma(png_row_infop row_info, png_bytep row,
3241 png_bytep gamma_table, png_uint_16pp gamma_16_table,
Guy Schalnat0d580581995-07-20 02:43:20 -05003242 int gamma_shift)
3243{
Guy Schalnat6d764711995-12-19 03:22:19 -06003244 png_bytep sp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003245 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003246 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003247
Andreas Dilger47a0c421997-05-16 02:46:07 -05003248 png_debug(1, "in png_do_gamma\n");
3249 if (
3250#if defined(PNG_USELESS_TESTS_SUPPORTED)
3251 row != NULL && row_info != NULL &&
3252#endif
3253 ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
3254 (row_info->bit_depth == 16 && gamma_16_table != NULL)))
Guy Schalnat0d580581995-07-20 02:43:20 -05003255 {
3256 switch (row_info->color_type)
3257 {
3258 case PNG_COLOR_TYPE_RGB:
3259 {
3260 if (row_info->bit_depth == 8)
3261 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003262 sp = row;
3263 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003264 {
3265 *sp = gamma_table[*sp];
3266 sp++;
3267 *sp = gamma_table[*sp];
3268 sp++;
3269 *sp = gamma_table[*sp];
3270 sp++;
3271 }
3272 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003273 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003274 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003275 sp = row;
3276 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003277 {
3278 png_uint_16 v;
3279
Andreas Dilger47a0c421997-05-16 02:46:07 -05003280 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003281 *sp = (png_byte)((v >> 8) & 0xff);
3282 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003283 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003284 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003285 *sp = (png_byte)((v >> 8) & 0xff);
3286 *(sp + 1) = (png_byte)(v & 0xff);
3287 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003288 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003289 *sp = (png_byte)((v >> 8) & 0xff);
3290 *(sp + 1) = (png_byte)(v & 0xff);
3291 sp += 2;
3292 }
3293 }
3294 break;
3295 }
3296 case PNG_COLOR_TYPE_RGB_ALPHA:
3297 {
3298 if (row_info->bit_depth == 8)
3299 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003300 sp = row;
3301 for (i = 0; i < row_width; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003302 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003303 *sp = gamma_table[*sp];
3304 sp++;
3305 *sp = gamma_table[*sp];
3306 sp++;
3307 *sp = gamma_table[*sp];
3308 sp++;
3309 sp++;
3310 }
3311 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003312 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003313 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003314 sp = row;
3315 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003316 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003317 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003318 *sp = (png_byte)((v >> 8) & 0xff);
3319 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003320 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003321 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003322 *sp = (png_byte)((v >> 8) & 0xff);
3323 *(sp + 1) = (png_byte)(v & 0xff);
3324 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003325 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003326 *sp = (png_byte)((v >> 8) & 0xff);
3327 *(sp + 1) = (png_byte)(v & 0xff);
3328 sp += 4;
3329 }
3330 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003331 break;
3332 }
3333 case PNG_COLOR_TYPE_GRAY_ALPHA:
3334 {
3335 if (row_info->bit_depth == 8)
3336 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003337 sp = row;
3338 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003339 {
3340 *sp = gamma_table[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003341 sp += 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05003342 }
3343 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003344 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003345 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003346 sp = row;
3347 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003348 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003349 png_uint_16 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);
Guy Schalnat0d580581995-07-20 02:43:20 -05003352 sp += 4;
3353 }
3354 }
3355 break;
3356 }
3357 case PNG_COLOR_TYPE_GRAY:
3358 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003359 if (row_info->bit_depth == 2)
3360 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003361 sp = row;
3362 for (i = 0; i < row_width; i += 4)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003363 {
3364 int a = *sp & 0xc0;
3365 int b = *sp & 0x30;
3366 int c = *sp & 0x0c;
3367 int d = *sp & 0x03;
3368
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003369 *sp = (png_byte)(
3370 ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003371 ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
3372 ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003373 ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003374 sp++;
3375 }
3376 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003377 if (row_info->bit_depth == 4)
Guy Schalnat0d580581995-07-20 02:43:20 -05003378 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003379 sp = row;
3380 for (i = 0; i < row_width; i += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003381 {
3382 int msb = *sp & 0xf0;
3383 int lsb = *sp & 0x0f;
3384
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003385 *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
3386 | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003387 sp++;
3388 }
3389 }
3390 else if (row_info->bit_depth == 8)
3391 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003392 sp = row;
3393 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003394 {
3395 *sp = gamma_table[*sp];
3396 sp++;
3397 }
3398 }
3399 else if (row_info->bit_depth == 16)
3400 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003401 sp = row;
3402 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003403 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003404 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003405 *sp = (png_byte)((v >> 8) & 0xff);
3406 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003407 sp += 2;
3408 }
3409 }
3410 break;
3411 }
3412 }
3413 }
3414}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003415#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003416
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003417#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003418/* Expands a palette row to an RGB or RGBA row depending
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003419 * upon whether you supply trans and num_trans.
3420 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003421void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003422png_do_expand_palette(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05003423 png_colorp palette, png_bytep trans, int num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003424{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003425 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003426 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003427 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003428 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003429
Andreas Dilger47a0c421997-05-16 02:46:07 -05003430 png_debug(1, "in png_do_expand_palette\n");
3431 if (
3432#if defined(PNG_USELESS_TESTS_SUPPORTED)
3433 row != NULL && row_info != NULL &&
3434#endif
3435 row_info->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05003436 {
3437 if (row_info->bit_depth < 8)
3438 {
3439 switch (row_info->bit_depth)
3440 {
3441 case 1:
3442 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003443 sp = row + (png_size_t)((row_width - 1) >> 3);
3444 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003445 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003446 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003447 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003448 if ((*sp >> shift) & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -05003449 *dp = 1;
3450 else
3451 *dp = 0;
3452 if (shift == 7)
3453 {
3454 shift = 0;
3455 sp--;
3456 }
3457 else
3458 shift++;
3459
3460 dp--;
3461 }
3462 break;
3463 }
3464 case 2:
3465 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003466 sp = row + (png_size_t)((row_width - 1) >> 2);
3467 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003468 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003469 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003470 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003471 value = (*sp >> shift) & 0x03;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003472 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003473 if (shift == 6)
3474 {
3475 shift = 0;
3476 sp--;
3477 }
3478 else
3479 shift += 2;
3480
3481 dp--;
3482 }
3483 break;
3484 }
3485 case 4:
3486 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003487 sp = row + (png_size_t)((row_width - 1) >> 1);
3488 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003489 shift = (int)((row_width & 0x01) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003490 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003491 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003492 value = (*sp >> shift) & 0x0f;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003493 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003494 if (shift == 4)
3495 {
3496 shift = 0;
3497 sp--;
3498 }
3499 else
3500 shift += 4;
3501
3502 dp--;
3503 }
3504 break;
3505 }
3506 }
3507 row_info->bit_depth = 8;
3508 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003509 row_info->rowbytes = row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003510 }
3511 switch (row_info->bit_depth)
3512 {
3513 case 8:
3514 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003515 if (trans != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003516 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003517 sp = row + (png_size_t)row_width - 1;
3518 dp = row + (png_size_t)(row_width << 2) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003519
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003520 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003521 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003522 if ((int)(*sp) >= num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003523 *dp-- = 0xff;
3524 else
3525 *dp-- = trans[*sp];
3526 *dp-- = palette[*sp].blue;
3527 *dp-- = palette[*sp].green;
3528 *dp-- = palette[*sp].red;
3529 sp--;
3530 }
3531 row_info->bit_depth = 8;
3532 row_info->pixel_depth = 32;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003533 row_info->rowbytes = row_width * 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05003534 row_info->color_type = 6;
3535 row_info->channels = 4;
3536 }
3537 else
3538 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003539 sp = row + (png_size_t)row_width - 1;
3540 dp = row + (png_size_t)(row_width * 3) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003541
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003542 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003543 {
3544 *dp-- = palette[*sp].blue;
3545 *dp-- = palette[*sp].green;
3546 *dp-- = palette[*sp].red;
3547 sp--;
3548 }
3549 row_info->bit_depth = 8;
3550 row_info->pixel_depth = 24;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003551 row_info->rowbytes = row_width * 3;
Guy Schalnat0d580581995-07-20 02:43:20 -05003552 row_info->color_type = 2;
3553 row_info->channels = 3;
3554 }
3555 break;
3556 }
3557 }
3558 }
3559}
3560
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003561/* If the bit depth < 8, it is expanded to 8. Also, if the
3562 * transparency value is supplied, an alpha channel is built.
3563 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003564void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003565png_do_expand(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003566 png_color_16p trans_value)
Guy Schalnat0d580581995-07-20 02:43:20 -05003567{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003568 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003569 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003570 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003571 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003572
Andreas Dilger47a0c421997-05-16 02:46:07 -05003573 png_debug(1, "in png_do_expand\n");
3574#if defined(PNG_USELESS_TESTS_SUPPORTED)
3575 if (row != NULL && row_info != NULL)
3576#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003577 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003578 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05003579 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003580 png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003581
3582 if (row_info->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003583 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003584 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05003585 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003586 case 1:
3587 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003588 gray = (png_uint_16)(gray*0xff);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003589 sp = row + (png_size_t)((row_width - 1) >> 3);
3590 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003591 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003592 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003593 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003594 if ((*sp >> shift) & 0x01)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003595 *dp = 0xff;
3596 else
3597 *dp = 0;
3598 if (shift == 7)
3599 {
3600 shift = 0;
3601 sp--;
3602 }
3603 else
3604 shift++;
3605
3606 dp--;
3607 }
3608 break;
3609 }
3610 case 2:
3611 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003612 gray = (png_uint_16)(gray*0x55);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003613 sp = row + (png_size_t)((row_width - 1) >> 2);
3614 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003615 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
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 value = (*sp >> shift) & 0x03;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003619 *dp = (png_byte)(value | (value << 2) | (value << 4) |
3620 (value << 6));
3621 if (shift == 6)
3622 {
3623 shift = 0;
3624 sp--;
3625 }
3626 else
3627 shift += 2;
3628
3629 dp--;
3630 }
3631 break;
3632 }
3633 case 4:
3634 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003635 gray = (png_uint_16)(gray*0x11);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003636 sp = row + (png_size_t)((row_width - 1) >> 1);
3637 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003638 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003639 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003640 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003641 value = (*sp >> shift) & 0x0f;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003642 *dp = (png_byte)(value | (value << 4));
3643 if (shift == 4)
3644 {
3645 shift = 0;
3646 sp--;
3647 }
3648 else
3649 shift = 4;
3650
3651 dp--;
3652 }
3653 break;
3654 }
3655 }
3656 row_info->bit_depth = 8;
3657 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003658 row_info->rowbytes = row_width;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003659 }
3660
Andreas Dilger47a0c421997-05-16 02:46:07 -05003661 if (trans_value != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003662 {
3663 if (row_info->bit_depth == 8)
3664 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003665 sp = row + (png_size_t)row_width - 1;
3666 dp = row + (png_size_t)(row_width << 1) - 1;
3667 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003668 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003669 if (*sp == gray)
3670 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003671 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003672 *dp-- = 0xff;
3673 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003674 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003675 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003676 else if (row_info->bit_depth == 16)
Guy Schalnat0d580581995-07-20 02:43:20 -05003677 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003678 sp = row + row_info->rowbytes - 1;
3679 dp = row + (row_info->rowbytes << 1) - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003680 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003681 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003682 if (((png_uint_16)*(sp) |
3683 ((png_uint_16)*(sp - 1) << 8)) == gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05003684 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003685 *dp-- = 0;
3686 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003687 }
3688 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003689 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003690 *dp-- = 0xff;
3691 *dp-- = 0xff;
Guy Schalnat0d580581995-07-20 02:43:20 -05003692 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003693 *dp-- = *sp--;
3694 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003695 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003696 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003697 row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
3698 row_info->channels = 2;
3699 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
3700 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003701 ((row_width * row_info->pixel_depth) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003702 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003703 }
3704 else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
3705 {
3706 if (row_info->bit_depth == 8)
3707 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003708 sp = row + (png_size_t)row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003709 dp = row + (png_size_t)(row_width << 2) - 1;
3710 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003711 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003712 if (*(sp - 2) == trans_value->red &&
Guy Schalnat0d580581995-07-20 02:43:20 -05003713 *(sp - 1) == trans_value->green &&
3714 *(sp - 0) == trans_value->blue)
3715 *dp-- = 0;
3716 else
3717 *dp-- = 0xff;
3718 *dp-- = *sp--;
3719 *dp-- = *sp--;
3720 *dp-- = *sp--;
3721 }
3722 }
3723 else if (row_info->bit_depth == 16)
3724 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003725 sp = row + row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003726 dp = row + (png_size_t)(row_width << 3) - 1;
3727 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003728 {
3729 if ((((png_uint_16)*(sp - 4) |
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003730 ((png_uint_16)*(sp - 5) << 8)) == trans_value->red) &&
Guy Schalnat0d580581995-07-20 02:43:20 -05003731 (((png_uint_16)*(sp - 2) |
3732 ((png_uint_16)*(sp - 3) << 8)) == trans_value->green) &&
3733 (((png_uint_16)*(sp - 0) |
3734 ((png_uint_16)*(sp - 1) << 8)) == trans_value->blue))
3735 {
3736 *dp-- = 0;
3737 *dp-- = 0;
3738 }
3739 else
3740 {
3741 *dp-- = 0xff;
3742 *dp-- = 0xff;
3743 }
3744 *dp-- = *sp--;
3745 *dp-- = *sp--;
3746 *dp-- = *sp--;
3747 *dp-- = *sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003748 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003749 *dp-- = *sp--;
3750 }
3751 }
3752 row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
3753 row_info->channels = 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003754 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
Guy Schalnat0d580581995-07-20 02:43:20 -05003755 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003756 ((row_width * row_info->pixel_depth) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003757 }
3758 }
3759}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003760#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003761
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003762#if defined(PNG_READ_DITHER_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003763void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003764png_do_dither(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003765 png_bytep palette_lookup, png_bytep dither_lookup)
Guy Schalnat0d580581995-07-20 02:43:20 -05003766{
Guy Schalnat6d764711995-12-19 03:22:19 -06003767 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003768 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003769 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003770
Andreas Dilger47a0c421997-05-16 02:46:07 -05003771 png_debug(1, "in png_do_dither\n");
3772#if defined(PNG_USELESS_TESTS_SUPPORTED)
3773 if (row != NULL && row_info != NULL)
3774#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003775 {
3776 if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
3777 palette_lookup && row_info->bit_depth == 8)
3778 {
3779 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003780 sp = row;
3781 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003782 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003783 {
3784 r = *sp++;
3785 g = *sp++;
3786 b = *sp++;
3787
3788 /* this looks real messy, but the compiler will reduce
3789 it down to a reasonable formula. For example, with
3790 5 bits per color, we get:
3791 p = (((r >> 3) & 0x1f) << 10) |
3792 (((g >> 3) & 0x1f) << 5) |
3793 ((b >> 3) & 0x1f);
3794 */
3795 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
3796 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
3797 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3798 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003799 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003800 (PNG_DITHER_BLUE_BITS)) |
3801 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3802 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3803
3804 *dp++ = palette_lookup[p];
3805 }
3806 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3807 row_info->channels = 1;
3808 row_info->pixel_depth = row_info->bit_depth;
3809 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003810 ((row_width * row_info->pixel_depth + 7) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003811 }
3812 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
Andreas Dilger47a0c421997-05-16 02:46:07 -05003813 palette_lookup != NULL && row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003814 {
3815 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003816 sp = row;
3817 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003818 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003819 {
3820 r = *sp++;
3821 g = *sp++;
3822 b = *sp++;
3823 sp++;
3824
3825 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003826 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003827 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3828 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
3829 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
3830 (PNG_DITHER_BLUE_BITS)) |
3831 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3832 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3833
3834 *dp++ = palette_lookup[p];
3835 }
3836 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3837 row_info->channels = 1;
3838 row_info->pixel_depth = row_info->bit_depth;
3839 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003840 ((row_width * row_info->pixel_depth + 7) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003841 }
3842 else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
3843 dither_lookup && row_info->bit_depth == 8)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003844 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003845 sp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003846 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003847 {
3848 *sp = dither_lookup[*sp];
3849 }
3850 }
3851 }
3852}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003853#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003854
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003855#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003856#if defined(PNG_READ_GAMMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05003857static int png_gamma_shift[] =
3858 {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0};
3859
Andreas Dilger47a0c421997-05-16 02:46:07 -05003860/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003861 * tables, we don't make a full table if we are reducing to 8-bit in
3862 * the future. Note also how the gamma_16 tables are segmented so that
3863 * we don't need to allocate > 64K chunks for a full 16-bit table.
3864 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003865void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003866png_build_gamma_table(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003867{
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003868 png_debug(1, "in png_build_gamma_table\n");
3869 if(png_ptr->gamma != 0.0)
3870 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003871 if (png_ptr->bit_depth <= 8)
3872 {
3873 int i;
3874 double g;
3875
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003876 if (png_ptr->screen_gamma > .000001)
3877 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
3878 else
3879 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003880
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003881 png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -05003882 (png_uint_32)256);
3883
3884 for (i = 0; i < 256; i++)
3885 {
3886 png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
3887 g) * 255.0 + .5);
3888 }
3889
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003890#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
3891 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003892 if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05003893 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003894
Guy Schalnat0d580581995-07-20 02:43:20 -05003895 g = 1.0 / (png_ptr->gamma);
3896
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003897 png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -05003898 (png_uint_32)256);
3899
3900 for (i = 0; i < 256; i++)
3901 {
3902 png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
3903 g) * 255.0 + .5);
3904 }
3905
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003906
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003907 png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -05003908 (png_uint_32)256);
3909
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003910 if(png_ptr->screen_gamma > 0.000001)
3911 g = 1.0 / png_ptr->screen_gamma;
3912 else
3913 g = png_ptr->gamma; /* probably doing rgb_to_gray */
3914
Guy Schalnat0d580581995-07-20 02:43:20 -05003915 for (i = 0; i < 256; i++)
3916 {
3917 png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
3918 g) * 255.0 + .5);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003919
Guy Schalnat0d580581995-07-20 02:43:20 -05003920 }
3921 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003922#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003923 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003924 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003925 {
3926 double g;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003927 int i, j, shift, num;
3928 int sig_bit;
3929 png_uint_32 ig;
Guy Schalnat0d580581995-07-20 02:43:20 -05003930
3931 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003932 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003933 sig_bit = (int)png_ptr->sig_bit.red;
3934 if ((int)png_ptr->sig_bit.green > sig_bit)
3935 sig_bit = png_ptr->sig_bit.green;
3936 if ((int)png_ptr->sig_bit.blue > sig_bit)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003937 sig_bit = png_ptr->sig_bit.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003938 }
3939 else
3940 {
3941 sig_bit = (int)png_ptr->sig_bit.gray;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003942 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003943
3944 if (sig_bit > 0)
3945 shift = 16 - sig_bit;
3946 else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003947 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003948
3949 if (png_ptr->transformations & PNG_16_TO_8)
3950 {
3951 if (shift < (16 - PNG_MAX_GAMMA_8))
3952 shift = (16 - PNG_MAX_GAMMA_8);
3953 }
3954
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003955 if (shift > 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003956 shift = 8;
3957 if (shift < 0)
3958 shift = 0;
3959
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003960 png_ptr->gamma_shift = (png_byte)shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05003961
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003962 num = (1 << (8 - shift));
Guy Schalnat0d580581995-07-20 02:43:20 -05003963
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003964 if (png_ptr->screen_gamma > .000001)
3965 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
3966 else
3967 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003968
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003969 png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06003970 (png_uint_32)(num * sizeof (png_uint_16p)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003971
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003972 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003973 {
3974 double fin, fout;
3975 png_uint_32 last, max;
Guy Schalnat0d580581995-07-20 02:43:20 -05003976
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003977 for (i = 0; i < num; i++)
3978 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003979 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06003980 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003981 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003982
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003983 g = 1.0 / g;
3984 last = 0;
3985 for (i = 0; i < 256; i++)
3986 {
3987 fout = ((double)i + 0.5) / 256.0;
3988 fin = pow(fout, g);
3989 max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
3990 while (last <= max)
3991 {
3992 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
3993 [(int)(last >> (8 - shift))] = (png_uint_16)(
3994 (png_uint_16)i | ((png_uint_16)i << 8));
3995 last++;
3996 }
3997 }
3998 while (last < ((png_uint_32)num << 8))
3999 {
4000 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
Andreas Dilger47a0c421997-05-16 02:46:07 -05004001 [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06004002 last++;
Guy Schalnat6d764711995-12-19 03:22:19 -06004003 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004004 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06004005 else
4006 {
4007 for (i = 0; i < num; i++)
4008 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004009 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004010 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004011
Andreas Dilger47a0c421997-05-16 02:46:07 -05004012 ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06004013 for (j = 0; j < 256; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05004014 {
4015 png_ptr->gamma_16_table[i][j] =
4016 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4017 65535.0, g) * 65535.0 + .5);
4018 }
4019 }
4020 }
4021
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004022#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
4023 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4024 if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05004025 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004026
Guy Schalnat0d580581995-07-20 02:43:20 -05004027 g = 1.0 / (png_ptr->gamma);
4028
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004029 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004030 (png_uint_32)(num * sizeof (png_uint_16p )));
Guy Schalnat0d580581995-07-20 02:43:20 -05004031
4032 for (i = 0; i < num; i++)
4033 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004034 png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004035 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004036
4037 ig = (((png_uint_32)i *
4038 (png_uint_32)png_gamma_shift[shift]) >> 4);
4039 for (j = 0; j < 256; j++)
4040 {
4041 png_ptr->gamma_16_to_1[i][j] =
4042 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4043 65535.0, g) * 65535.0 + .5);
4044 }
4045 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004046
4047 if(png_ptr->screen_gamma > 0.000001)
4048 g = 1.0 / png_ptr->screen_gamma;
4049 else
4050 g = png_ptr->gamma; /* probably doing rgb_to_gray */
Guy Schalnat0d580581995-07-20 02:43:20 -05004051
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004052 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004053 (png_uint_32)(num * sizeof (png_uint_16p)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004054
4055 for (i = 0; i < num; i++)
4056 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004057 png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004058 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004059
4060 ig = (((png_uint_32)i *
4061 (png_uint_32)png_gamma_shift[shift]) >> 4);
4062 for (j = 0; j < 256; j++)
4063 {
4064 png_ptr->gamma_16_from_1[i][j] =
4065 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4066 65535.0, g) * 65535.0 + .5);
4067 }
4068 }
4069 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004070#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05004071 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004072 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004073}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004074#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06004075/* To do: install integer version of png_build_gamma_table here */
4076#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004077
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004078#if defined(PNG_MNG_FEATURES_SUPPORTED)
4079/* undoes intrapixel differencing */
4080void /* PRIVATE */
4081png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
4082{
4083 png_debug(1, "in png_do_read_intrapixel\n");
4084 if (
4085#if defined(PNG_USELESS_TESTS_SUPPORTED)
4086 row != NULL && row_info != NULL &&
4087#endif
4088 (row_info->color_type & PNG_COLOR_MASK_COLOR))
4089 {
4090 int bytes_per_pixel;
4091 png_uint_32 row_width = row_info->width;
4092 if (row_info->bit_depth == 8)
4093 {
4094 png_bytep rp;
4095 png_uint_32 i;
4096
4097 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4098 bytes_per_pixel = 3;
4099 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4100 bytes_per_pixel = 4;
4101 else
4102 return;
4103
4104 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4105 {
4106 *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff);
4107 *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff);
4108 }
4109 }
4110 else if (row_info->bit_depth == 16)
4111 {
4112 png_bytep rp;
4113 png_uint_32 i;
4114
4115 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4116 bytes_per_pixel = 6;
4117 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4118 bytes_per_pixel = 8;
4119 else
4120 return;
4121
4122 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4123 {
4124 png_uint_32 s0=*(rp )<<8 | *(rp+1);
4125 png_uint_32 s1=*(rp+2)<<8 | *(rp+3);
4126 png_uint_32 s2=*(rp+4)<<8 | *(rp+5);
4127 png_uint_32 red=(65536+s0+s1)&0xffff;
4128 png_uint_32 blue=(65536+s2+s1)&0xffff;
4129 *(rp ) = (png_byte)((red>>8)&0xff);
4130 *(rp+1) = (png_byte)(red&0xff);
4131 *(rp+4) = (png_byte)((blue>>8)&0xff);
4132 *(rp+5) = (png_byte)(blue&0xff);
4133 }
4134 }
4135 }
4136}
4137#endif /* PNG_MNG_FEATURES_SUPPORTED */