blob: 9064b4833e617c4204fd4c18b3487a1dd9bb7d67 [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-Pehrson2ad31ae2000-12-15 08:54:42 -06004 * libpng 1.0.9beta5 - December 15, 2000
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
Glenn Randers-Pehrsonf5ed0e12000-11-18 18:19:14 -06006 * Copyright (c) 1998, 1999, 2000 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)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500459
Andreas Dilger47a0c421997-05-16 02:46:07 -0500460 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)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500464
Andreas Dilger47a0c421997-05-16 02:46:07 -0500465 png_memset(distance, 0xff, num_entries * sizeof(png_byte));
Guy Schalnat0d580581995-07-20 02:43:20 -0500466
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 }
499 }
500 }
501 }
502
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
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500745#if defined(PNG_READ_BACKGROUND_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 */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500904#endif
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
922#endif
923#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 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500955#endif
956
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 }
980#endif
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,
1230 &(png_ptr->trans_values), &(png_ptr->background),
1231 &(png_ptr->background_1),
1232 png_ptr->gamma_table, png_ptr->gamma_from_1,
1233 png_ptr->gamma_to_1, png_ptr->gamma_16_table,
1234 png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
1235 png_ptr->gamma_shift);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001236#endif
1237
1238#if defined(PNG_READ_GAMMA_SUPPORTED)
1239 if ((png_ptr->transformations & PNG_GAMMA) &&
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001240#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1241 !((png_ptr->transformations & PNG_BACKGROUND) &&
1242 ((png_ptr->num_trans != 0) ||
1243 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
1244#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001245 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
Guy Schalnat0d580581995-07-20 02:43:20 -05001246 png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
1247 png_ptr->gamma_table, png_ptr->gamma_16_table,
1248 png_ptr->gamma_shift);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001249#endif
1250
1251#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001252 if (png_ptr->transformations & PNG_16_TO_8)
1253 png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001254#endif
1255
1256#if defined(PNG_READ_DITHER_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001257 if (png_ptr->transformations & PNG_DITHER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001258 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001259 png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
1260 png_ptr->palette_lookup, png_ptr->dither_index);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001261 if(png_ptr->row_info.rowbytes == (png_uint_32)0)
1262 png_error(png_ptr, "png_do_dither returned rowbytes=0");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001263 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001264#endif
1265
1266#if defined(PNG_READ_INVERT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001267 if (png_ptr->transformations & PNG_INVERT_MONO)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001268 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001269#endif
1270
1271#if defined(PNG_READ_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001272 if (png_ptr->transformations & PNG_SHIFT)
1273 png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
1274 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001275#endif
1276
1277#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001278 if (png_ptr->transformations & PNG_PACK)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001279 png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001280#endif
1281
1282#if defined(PNG_READ_BGR_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001283 if (png_ptr->transformations & PNG_BGR)
1284 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001285#endif
1286
Andreas Dilger47a0c421997-05-16 02:46:07 -05001287#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1288 if (png_ptr->transformations & PNG_PACKSWAP)
1289 png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1290#endif
1291
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001292#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001293 /* if gray -> RGB, do so now only if we did not do so above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001294 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
1295 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05001296 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001297#endif
1298
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001299#if defined(PNG_READ_FILLER_SUPPORTED)
1300 if (png_ptr->transformations & PNG_FILLER)
1301 png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001302 (png_uint_32)png_ptr->filler, png_ptr->flags);
1303#endif
1304
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001305#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
1306 if (png_ptr->transformations & PNG_INVERT_ALPHA)
1307 png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1308#endif
1309
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001310#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
1311 if (png_ptr->transformations & PNG_SWAP_ALPHA)
1312 png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1313#endif
1314
Andreas Dilger47a0c421997-05-16 02:46:07 -05001315#if defined(PNG_READ_SWAP_SUPPORTED)
1316 if (png_ptr->transformations & PNG_SWAP_BYTES)
1317 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001318#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001319
1320#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1321 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001322 {
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001323 if(png_ptr->read_user_transform_fn != NULL)
1324 (*(png_ptr->read_user_transform_fn)) /* user read transform function */
1325 (png_ptr, /* png_ptr */
1326 &(png_ptr->row_info), /* row_info: */
1327 /* png_uint_32 width; width of row */
1328 /* png_uint_32 rowbytes; number of bytes in row */
1329 /* png_byte color_type; color type of pixels */
1330 /* png_byte bit_depth; bit depth of samples */
1331 /* png_byte channels; number of channels (1-4) */
1332 /* png_byte pixel_depth; bits per pixel (depth*channels) */
1333 png_ptr->row_buf + 1); /* start of pixel data for row */
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001334#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001335 if(png_ptr->user_transform_depth)
1336 png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
1337 if(png_ptr->user_transform_channels)
1338 png_ptr->row_info.channels = png_ptr->user_transform_channels;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001339#endif
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001340 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
1341 png_ptr->row_info.channels);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001342 png_ptr->row_info.rowbytes = (png_ptr->row_info.width *
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001343 png_ptr->row_info.pixel_depth+7)>>3;
1344 }
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001345#endif
1346
Guy Schalnat0d580581995-07-20 02:43:20 -05001347}
1348
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001349#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001350/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
1351 * without changing the actual values. Thus, if you had a row with
1352 * a bit depth of 1, you would end up with bytes that only contained
1353 * the numbers 0 or 1. If you would rather they contain 0 and 255, use
1354 * png_do_shift() after this.
1355 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001356void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001357png_do_unpack(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001358{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001359 png_debug(1, "in png_do_unpack\n");
1360#if defined(PNG_USELESS_TESTS_SUPPORTED)
1361 if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
1362#else
1363 if (row_info->bit_depth < 8)
1364#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001365 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001366 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001367 png_uint_32 row_width=row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001368
Guy Schalnat0d580581995-07-20 02:43:20 -05001369 switch (row_info->bit_depth)
1370 {
1371 case 1:
1372 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001373 png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
1374 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001375 png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001376 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001377 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001378 *dp = (png_byte)((*sp >> shift) & 0x01);
Guy Schalnat0d580581995-07-20 02:43:20 -05001379 if (shift == 7)
1380 {
1381 shift = 0;
1382 sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001383 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001384 else
1385 shift++;
1386
1387 dp--;
1388 }
1389 break;
1390 }
1391 case 2:
1392 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001393
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001394 png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
1395 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001396 png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001397 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001398 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001399 *dp = (png_byte)((*sp >> shift) & 0x03);
Guy Schalnat0d580581995-07-20 02:43:20 -05001400 if (shift == 6)
1401 {
1402 shift = 0;
1403 sp--;
1404 }
1405 else
1406 shift += 2;
1407
1408 dp--;
1409 }
1410 break;
1411 }
1412 case 4:
1413 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001414 png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
1415 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001416 png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001417 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001418 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001419 *dp = (png_byte)((*sp >> shift) & 0x0f);
Guy Schalnat0d580581995-07-20 02:43:20 -05001420 if (shift == 4)
1421 {
1422 shift = 0;
1423 sp--;
1424 }
1425 else
1426 shift = 4;
1427
1428 dp--;
1429 }
1430 break;
1431 }
1432 }
1433 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001434 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001435 row_info->rowbytes = row_width * row_info->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001436 }
1437}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001438#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001439
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001440#if defined(PNG_READ_SHIFT_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001441/* Reverse the effects of png_do_shift. This routine merely shifts the
1442 * pixels back to their significant bits values. Thus, if you have
1443 * a row of bit depth 8, but only 5 are significant, this will shift
1444 * the values back to 0 through 31.
1445 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001446void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001447png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
Guy Schalnat0d580581995-07-20 02:43:20 -05001448{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001449 png_debug(1, "in png_do_unshift\n");
1450 if (
1451#if defined(PNG_USELESS_TESTS_SUPPORTED)
1452 row != NULL && row_info != NULL && sig_bits != NULL &&
1453#endif
1454 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001455 {
1456 int shift[4];
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001457 int channels = 0;
1458 int c;
1459 png_uint_16 value = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001460 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001461
Guy Schalnat0d580581995-07-20 02:43:20 -05001462 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
1463 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001464 shift[channels++] = row_info->bit_depth - sig_bits->red;
1465 shift[channels++] = row_info->bit_depth - sig_bits->green;
1466 shift[channels++] = row_info->bit_depth - sig_bits->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05001467 }
1468 else
1469 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001470 shift[channels++] = row_info->bit_depth - sig_bits->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05001471 }
1472 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
1473 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001474 shift[channels++] = row_info->bit_depth - sig_bits->alpha;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001475 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001476
Andreas Dilger47a0c421997-05-16 02:46:07 -05001477 for (c = 0; c < channels; c++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001478 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001479 if (shift[c] <= 0)
1480 shift[c] = 0;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001481 else
1482 value = 1;
1483 }
Guy Schalnat0f716451995-11-28 11:22:13 -06001484
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001485 if (!value)
1486 return;
Guy Schalnat0f716451995-11-28 11:22:13 -06001487
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001488 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05001489 {
1490 case 2:
1491 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001492 png_bytep bp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001493 png_uint_32 i;
1494 png_uint_32 istop = row_info->rowbytes;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001495
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001496 for (bp = row, i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001497 {
1498 *bp >>= 1;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001499 *bp++ &= 0x55;
Guy Schalnat0d580581995-07-20 02:43:20 -05001500 }
1501 break;
1502 }
1503 case 4:
1504 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001505 png_bytep bp = row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001506 png_uint_32 i;
1507 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001508 png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
1509 (png_byte)((int)0xf >> shift[0]));
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001510
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001511 for (i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001512 {
1513 *bp >>= shift[0];
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001514 *bp++ &= mask;
Guy Schalnat0d580581995-07-20 02:43:20 -05001515 }
1516 break;
1517 }
1518 case 8:
1519 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001520 png_bytep bp = row;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001521 png_uint_32 i;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001522 png_uint_32 istop = row_width * channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001523
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001524 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001525 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001526 *bp++ >>= shift[i%channels];
Guy Schalnat0d580581995-07-20 02:43:20 -05001527 }
1528 break;
1529 }
1530 case 16:
1531 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001532 png_bytep bp = row;
1533 png_uint_32 i;
1534 png_uint_32 istop = channels * row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001535
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001536 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001537 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001538 value = (png_uint_16)((*bp << 8) + *(bp + 1));
1539 value >>= shift[i%channels];
1540 *bp++ = (png_byte)(value >> 8);
1541 *bp++ = (png_byte)(value & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05001542 }
1543 break;
1544 }
1545 }
1546 }
1547}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001548#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001549
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001550#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001551/* chop rows of bit depth 16 down to 8 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001552void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001553png_do_chop(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001554{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001555 png_debug(1, "in png_do_chop\n");
1556#if defined(PNG_USELESS_TESTS_SUPPORTED)
1557 if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
1558#else
1559 if (row_info->bit_depth == 16)
1560#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001561 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001562 png_bytep sp = row;
1563 png_bytep dp = row;
1564 png_uint_32 i;
1565 png_uint_32 istop = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001566
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001567 for (i = 0; i<istop; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001568 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001569#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001570 /* This does a more accurate scaling of the 16-bit color
1571 * value, rather than a simple low-byte truncation.
1572 *
1573 * What the ideal calculation should be:
1574 * *dp = (((((png_uint_32)(*sp) << 8) |
1575 * (png_uint_32)(*(sp + 1))) * 255 + 127) / (png_uint_32)65535L;
1576 *
1577 * GRR: no, I think this is what it really should be:
1578 * *dp = (((((png_uint_32)(*sp) << 8) |
1579 * (png_uint_32)(*(sp + 1))) + 128L) / (png_uint_32)257L;
1580 *
1581 * GRR: here's the exact calculation with shifts:
1582 * temp = (((png_uint_32)(*sp) << 8) | (png_uint_32)(*(sp + 1))) + 128L;
1583 * *dp = (temp - (temp >> 8)) >> 8;
1584 *
1585 * Approximate calculation with shift/add instead of multiply/divide:
1586 * *dp = ((((png_uint_32)(*sp) << 8) |
1587 * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
1588 *
1589 * What we actually do to avoid extra shifting and conversion:
1590 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001591
Andreas Dilger47a0c421997-05-16 02:46:07 -05001592 *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
1593#else
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001594 /* Simply discard the low order byte */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001595 *dp = *sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001596#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001597 }
1598 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001599 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001600 row_info->rowbytes = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001601 }
1602}
1603#endif
1604
1605#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001606void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001607png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
1608{
1609 png_debug(1, "in png_do_read_swap_alpha\n");
1610#if defined(PNG_USELESS_TESTS_SUPPORTED)
1611 if (row != NULL && row_info != NULL)
1612#endif
1613 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001614 png_uint_32 row_width = row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001615 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1616 {
1617 /* This converts from RGBA to ARGB */
1618 if (row_info->bit_depth == 8)
1619 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001620 png_bytep sp = row + row_info->rowbytes;
1621 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001622 png_byte save;
1623 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001624
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001625 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001626 {
1627 save = *(--sp);
1628 *(--dp) = *(--sp);
1629 *(--dp) = *(--sp);
1630 *(--dp) = *(--sp);
1631 *(--dp) = save;
1632 }
1633 }
1634 /* This converts from RRGGBBAA to AARRGGBB */
1635 else
1636 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001637 png_bytep sp = row + row_info->rowbytes;
1638 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001639 png_byte save[2];
1640 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001641
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001642 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001643 {
1644 save[0] = *(--sp);
1645 save[1] = *(--sp);
1646 *(--dp) = *(--sp);
1647 *(--dp) = *(--sp);
1648 *(--dp) = *(--sp);
1649 *(--dp) = *(--sp);
1650 *(--dp) = *(--sp);
1651 *(--dp) = *(--sp);
1652 *(--dp) = save[0];
1653 *(--dp) = save[1];
1654 }
1655 }
1656 }
1657 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1658 {
1659 /* This converts from GA to AG */
1660 if (row_info->bit_depth == 8)
1661 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001662 png_bytep sp = row + row_info->rowbytes;
1663 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001664 png_byte save;
1665 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001666
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001667 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001668 {
1669 save = *(--sp);
1670 *(--dp) = *(--sp);
1671 *(--dp) = save;
1672 }
1673 }
1674 /* This converts from GGAA to AAGG */
1675 else
1676 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001677 png_bytep sp = row + row_info->rowbytes;
1678 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001679 png_byte save[2];
1680 png_uint_32 i;
1681
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001682 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001683 {
1684 save[0] = *(--sp);
1685 save[1] = *(--sp);
1686 *(--dp) = *(--sp);
1687 *(--dp) = *(--sp);
1688 *(--dp) = save[0];
1689 *(--dp) = save[1];
1690 }
1691 }
1692 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001693 }
1694}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001695#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001696
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001697#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001698void /* PRIVATE */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001699png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
1700{
1701 png_debug(1, "in png_do_read_invert_alpha\n");
1702#if defined(PNG_USELESS_TESTS_SUPPORTED)
1703 if (row != NULL && row_info != NULL)
1704#endif
1705 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001706 png_uint_32 row_width = row_info->width;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001707 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1708 {
1709 /* This inverts the alpha channel in RGBA */
1710 if (row_info->bit_depth == 8)
1711 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001712 png_bytep sp = row + row_info->rowbytes;
1713 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001714 png_uint_32 i;
1715
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001716 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001717 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001718 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001719
1720/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001721 *(--dp) = *(--sp);
1722 *(--dp) = *(--sp);
1723 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001724 We can replace it with:
1725*/
1726 sp-=3;
1727 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001728 }
1729 }
1730 /* This inverts the alpha channel in RRGGBBAA */
1731 else
1732 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001733 png_bytep sp = row + row_info->rowbytes;
1734 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001735 png_uint_32 i;
1736
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001737 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001738 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001739 *(--dp) = (png_byte)(255 - *(--sp));
1740 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001741
1742/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001743 *(--dp) = *(--sp);
1744 *(--dp) = *(--sp);
1745 *(--dp) = *(--sp);
1746 *(--dp) = *(--sp);
1747 *(--dp) = *(--sp);
1748 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001749 We can replace it with:
1750*/
1751 sp-=6;
1752 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001753 }
1754 }
1755 }
1756 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1757 {
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001758 /* This inverts the alpha channel in GA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001759 if (row_info->bit_depth == 8)
1760 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001761 png_bytep sp = row + row_info->rowbytes;
1762 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001763 png_uint_32 i;
1764
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001765 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001766 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001767 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001768 *(--dp) = *(--sp);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001769 }
1770 }
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001771 /* This inverts the alpha channel in GGAA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001772 else
1773 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001774 png_bytep sp = row + row_info->rowbytes;
1775 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001776 png_uint_32 i;
1777
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001778 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001779 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001780 *(--dp) = (png_byte)(255 - *(--sp));
1781 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001782/*
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001783 *(--dp) = *(--sp);
1784 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001785*/
1786 sp-=2;
1787 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001788 }
1789 }
1790 }
1791 }
1792}
1793#endif
1794
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001795#if defined(PNG_READ_FILLER_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001796/* Add filler channel if we have RGB color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001797void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001798png_do_read_filler(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001799 png_uint_32 filler, png_uint_32 flags)
Guy Schalnat0d580581995-07-20 02:43:20 -05001800{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001801 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001802 png_uint_32 row_width = row_info->width;
1803
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001804 png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001805 png_byte lo_filler = (png_byte)(filler & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001806
1807 png_debug(1, "in png_do_read_filler\n");
1808 if (
1809#if defined(PNG_USELESS_TESTS_SUPPORTED)
1810 row != NULL && row_info != NULL &&
1811#endif
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001812 row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001813 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001814 if(row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05001815 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001816 /* This changes the data from G to GX */
1817 if (flags & PNG_FLAG_FILLER_AFTER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001818 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001819 png_bytep sp = row + (png_size_t)row_width;
1820 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001821 for (i = 1; i < row_width; i++)
1822 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001823 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001824 *(--dp) = *(--sp);
1825 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001826 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001827 row_info->channels = 2;
1828 row_info->pixel_depth = 16;
1829 row_info->rowbytes = row_width * 2;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001830 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001831 /* This changes the data from G to XG */
1832 else
1833 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001834 png_bytep sp = row + (png_size_t)row_width;
1835 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001836 for (i = 0; i < row_width; i++)
1837 {
1838 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001839 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001840 }
1841 row_info->channels = 2;
1842 row_info->pixel_depth = 16;
1843 row_info->rowbytes = row_width * 2;
1844 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001845 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001846 else if(row_info->bit_depth == 16)
1847 {
1848 /* This changes the data from GG to GGXX */
1849 if (flags & PNG_FLAG_FILLER_AFTER)
1850 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001851 png_bytep sp = row + (png_size_t)row_width;
1852 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001853 for (i = 1; i < row_width; i++)
1854 {
1855 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001856 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001857 *(--dp) = *(--sp);
1858 *(--dp) = *(--sp);
1859 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001860 *(--dp) = hi_filler;
1861 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001862 row_info->channels = 2;
1863 row_info->pixel_depth = 32;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001864 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001865 }
1866 /* This changes the data from GG to XXGG */
1867 else
1868 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001869 png_bytep sp = row + (png_size_t)row_width;
1870 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001871 for (i = 0; i < row_width; i++)
1872 {
1873 *(--dp) = *(--sp);
1874 *(--dp) = *(--sp);
1875 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001876 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001877 }
1878 row_info->channels = 2;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001879 row_info->pixel_depth = 32;
1880 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001881 }
1882 }
1883 } /* COLOR_TYPE == GRAY */
1884 else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
1885 {
1886 if(row_info->bit_depth == 8)
1887 {
1888 /* This changes the data from RGB to RGBX */
1889 if (flags & PNG_FLAG_FILLER_AFTER)
1890 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001891 png_bytep sp = row + (png_size_t)row_width * 3;
1892 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001893 for (i = 1; i < row_width; i++)
1894 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001895 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001896 *(--dp) = *(--sp);
1897 *(--dp) = *(--sp);
1898 *(--dp) = *(--sp);
1899 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001900 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001901 row_info->channels = 4;
1902 row_info->pixel_depth = 32;
1903 row_info->rowbytes = row_width * 4;
1904 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001905 /* This changes the data from RGB to XRGB */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001906 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001907 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001908 png_bytep sp = row + (png_size_t)row_width * 3;
1909 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001910 for (i = 0; i < row_width; i++)
1911 {
1912 *(--dp) = *(--sp);
1913 *(--dp) = *(--sp);
1914 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001915 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001916 }
1917 row_info->channels = 4;
1918 row_info->pixel_depth = 32;
1919 row_info->rowbytes = row_width * 4;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001920 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001921 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001922 else if(row_info->bit_depth == 16)
1923 {
1924 /* This changes the data from RRGGBB to RRGGBBXX */
1925 if (flags & PNG_FLAG_FILLER_AFTER)
1926 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001927 png_bytep sp = row + (png_size_t)row_width * 3;
1928 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001929 for (i = 1; i < row_width; i++)
1930 {
1931 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001932 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001933 *(--dp) = *(--sp);
1934 *(--dp) = *(--sp);
1935 *(--dp) = *(--sp);
1936 *(--dp) = *(--sp);
1937 *(--dp) = *(--sp);
1938 *(--dp) = *(--sp);
1939 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001940 *(--dp) = hi_filler;
1941 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001942 row_info->channels = 4;
1943 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001944 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001945 }
1946 /* This changes the data from RRGGBB to XXRRGGBB */
1947 else
1948 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001949 png_bytep sp = row + (png_size_t)row_width * 3;
1950 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001951 for (i = 0; i < row_width; i++)
1952 {
1953 *(--dp) = *(--sp);
1954 *(--dp) = *(--sp);
1955 *(--dp) = *(--sp);
1956 *(--dp) = *(--sp);
1957 *(--dp) = *(--sp);
1958 *(--dp) = *(--sp);
1959 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001960 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001961 }
1962 row_info->channels = 4;
1963 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001964 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001965 }
1966 }
1967 } /* COLOR_TYPE == RGB */
Guy Schalnat0d580581995-07-20 02:43:20 -05001968}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001969#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001970
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001971#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001972/* expand grayscale files to RGB, with or without alpha */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001973void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001974png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001975{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001976 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001977 png_uint_32 row_width = row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06001978
Andreas Dilger47a0c421997-05-16 02:46:07 -05001979 png_debug(1, "in png_do_gray_to_rgb\n");
1980 if (row_info->bit_depth >= 8 &&
1981#if defined(PNG_USELESS_TESTS_SUPPORTED)
1982 row != NULL && row_info != NULL &&
1983#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001984 !(row_info->color_type & PNG_COLOR_MASK_COLOR))
1985 {
1986 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
1987 {
1988 if (row_info->bit_depth == 8)
1989 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001990 png_bytep sp = row + (png_size_t)row_width - 1;
1991 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001992 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001993 {
1994 *(dp--) = *sp;
1995 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001996 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05001997 }
1998 }
1999 else
2000 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002001 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2002 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002003 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002004 {
2005 *(dp--) = *sp;
2006 *(dp--) = *(sp - 1);
2007 *(dp--) = *sp;
2008 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002009 *(dp--) = *(sp--);
2010 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002011 }
2012 }
2013 }
2014 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2015 {
2016 if (row_info->bit_depth == 8)
2017 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002018 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2019 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002020 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002021 {
2022 *(dp--) = *(sp--);
2023 *(dp--) = *sp;
2024 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002025 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002026 }
2027 }
2028 else
2029 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002030 png_bytep sp = row + (png_size_t)row_width * 4 - 1;
2031 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002032 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002033 {
2034 *(dp--) = *(sp--);
2035 *(dp--) = *(sp--);
2036 *(dp--) = *sp;
2037 *(dp--) = *(sp - 1);
2038 *(dp--) = *sp;
2039 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002040 *(dp--) = *(sp--);
2041 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002042 }
2043 }
2044 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002045 row_info->channels += (png_byte)2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002046 row_info->color_type |= PNG_COLOR_MASK_COLOR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002047 row_info->pixel_depth = (png_byte)(row_info->channels *
2048 row_info->bit_depth);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002049 row_info->rowbytes = ((row_width *
Guy Schalnat0d580581995-07-20 02:43:20 -05002050 row_info->pixel_depth + 7) >> 3);
2051 }
2052}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002053#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002054
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002055#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002056/* reduce RGB files to grayscale, with or without alpha
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002057 * using the equation given in Poynton's ColorFAQ at
2058 * <http://www.inforamp.net/~poynton/>
2059 * Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net
2060 *
2061 * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
2062 *
2063 * We approximate this with
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002064 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002065 * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002066 *
2067 * which can be expressed with integers as
2068 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002069 * Y = (6969 * R + 23434 * G + 2365 * B)/32768
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002070 *
2071 * The calculation is to be done in a linear colorspace.
2072 *
2073 * Other integer coefficents can be used via png_set_rgb_to_gray().
2074 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002075int /* PRIVATE */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002076png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
2077
2078{
2079 png_uint_32 i;
2080
2081 png_uint_32 row_width = row_info->width;
2082 int rgb_error = 0;
2083
2084 png_debug(1, "in png_do_rgb_to_gray\n");
2085 if (
2086#if defined(PNG_USELESS_TESTS_SUPPORTED)
2087 row != NULL && row_info != NULL &&
2088#endif
2089 (row_info->color_type & PNG_COLOR_MASK_COLOR))
2090 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002091 png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
2092 png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
2093 png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002094
2095 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2096 {
2097 if (row_info->bit_depth == 8)
2098 {
2099#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2100 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2101 {
2102 png_bytep sp = row;
2103 png_bytep dp = row;
2104
2105 for (i = 0; i < row_width; i++)
2106 {
2107 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2108 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2109 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
2110 if(red != green || red != blue)
2111 {
2112 rgb_error |= 1;
2113 *(dp++) = png_ptr->gamma_from_1[
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002114 (rc*red+gc*green+bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002115 }
2116 else
2117 *(dp++) = *(sp-1);
2118 }
2119 }
2120 else
2121#endif
2122 {
2123 png_bytep sp = row;
2124 png_bytep dp = row;
2125 for (i = 0; i < row_width; i++)
2126 {
2127 png_byte red = *(sp++);
2128 png_byte green = *(sp++);
2129 png_byte blue = *(sp++);
2130 if(red != green || red != blue)
2131 {
2132 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002133 *(dp++) = (png_byte)((rc*red+gc*green+bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002134 }
2135 else
2136 *(dp++) = *(sp-1);
2137 }
2138 }
2139 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002140
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002141 else /* RGB bit_depth == 16 */
2142 {
2143#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2144 if (png_ptr->gamma_16_to_1 != NULL &&
2145 png_ptr->gamma_16_from_1 != NULL)
2146 {
2147 png_bytep sp = row;
2148 png_bytep dp = row;
2149 for (i = 0; i < row_width; i++)
2150 {
2151 png_uint_16 red, green, blue, w;
2152
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002153 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2154 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2155 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002156
2157 if(red == green && red == blue)
2158 w = red;
2159 else
2160 {
2161 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2162 png_ptr->gamma_shift][red>>8];
2163 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2164 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002165 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002166 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002167 png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002168 + bc*blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002169 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2170 png_ptr->gamma_shift][gray16 >> 8];
2171 rgb_error |= 1;
2172 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002173
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002174 *(dp++) = (png_byte)((w>>8) & 0xff);
2175 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002176 }
2177 }
2178 else
2179#endif
2180 {
2181 png_bytep sp = row;
2182 png_bytep dp = row;
2183 for (i = 0; i < row_width; i++)
2184 {
2185 png_uint_16 red, green, blue, gray16;
2186
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002187 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2188 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2189 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002190
2191 if(red != green || red != blue)
2192 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002193 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002194 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2195 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002196 }
2197 }
2198 }
2199 }
2200 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2201 {
2202 if (row_info->bit_depth == 8)
2203 {
2204#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2205 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2206 {
2207 png_bytep sp = row;
2208 png_bytep dp = row;
2209 for (i = 0; i < row_width; i++)
2210 {
2211 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2212 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2213 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
2214 if(red != green || red != blue)
2215 rgb_error |= 1;
2216 *(dp++) = png_ptr->gamma_from_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002217 [(rc*red + gc*green + bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002218 *(dp++) = *(sp++); /* alpha */
2219 }
2220 }
2221 else
2222#endif
2223 {
2224 png_bytep sp = row;
2225 png_bytep dp = row;
2226 for (i = 0; i < row_width; i++)
2227 {
2228 png_byte red = *(sp++);
2229 png_byte green = *(sp++);
2230 png_byte blue = *(sp++);
2231 if(red != green || red != blue)
2232 rgb_error |= 1;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002233 *(dp++) = (png_byte)((gc*red + gc*green + bc*blue)>>8);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002234 *(dp++) = *(sp++); /* alpha */
2235 }
2236 }
2237 }
2238 else /* RGBA bit_depth == 16 */
2239 {
2240#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2241 if (png_ptr->gamma_16_to_1 != NULL &&
2242 png_ptr->gamma_16_from_1 != NULL)
2243 {
2244 png_bytep sp = row;
2245 png_bytep dp = row;
2246 for (i = 0; i < row_width; i++)
2247 {
2248 png_uint_16 red, green, blue, w;
2249
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002250 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2251 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2252 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002253
2254 if(red == green && red == blue)
2255 w = red;
2256 else
2257 {
2258 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2259 png_ptr->gamma_shift][red>>8];
2260 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2261 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002262 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002263 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002264 png_uint_16 gray16 = (png_uint_16)((rc * red_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002265 + gc * green_1 + bc * blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002266 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2267 png_ptr->gamma_shift][gray16 >> 8];
2268 rgb_error |= 1;
2269 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002270
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002271 *(dp++) = (png_byte)((w>>8) & 0xff);
2272 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002273 *(dp++) = *(sp++); /* alpha */
2274 *(dp++) = *(sp++);
2275 }
2276 }
2277 else
2278#endif
2279 {
2280 png_bytep sp = row;
2281 png_bytep dp = row;
2282 for (i = 0; i < row_width; i++)
2283 {
2284 png_uint_16 red, green, blue, gray16;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002285 red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2286 green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2287 blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002288 if(red != green || red != blue)
2289 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002290 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002291 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2292 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002293 *(dp++) = *(sp++); /* alpha */
2294 *(dp++) = *(sp++);
2295 }
2296 }
2297 }
2298 }
2299 row_info->channels -= (png_byte)2;
2300 row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
2301 row_info->pixel_depth = (png_byte)(row_info->channels *
2302 row_info->bit_depth);
2303 row_info->rowbytes = ((row_width *
2304 row_info->pixel_depth + 7) >> 3);
2305 }
2306 return rgb_error;
2307}
2308#endif
2309
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002310/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
2311 * large of png_color. This lets grayscale images be treated as
2312 * paletted. Most useful for gamma correction and simplification
2313 * of code.
2314 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002315void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002316png_build_grayscale_palette(int bit_depth, png_colorp palette)
Guy Schalnat0d580581995-07-20 02:43:20 -05002317{
2318 int num_palette;
2319 int color_inc;
2320 int i;
2321 int v;
2322
Andreas Dilger47a0c421997-05-16 02:46:07 -05002323 png_debug(1, "in png_do_build_grayscale_palette\n");
2324 if (palette == NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002325 return;
2326
2327 switch (bit_depth)
2328 {
2329 case 1:
2330 num_palette = 2;
2331 color_inc = 0xff;
2332 break;
2333 case 2:
2334 num_palette = 4;
2335 color_inc = 0x55;
2336 break;
2337 case 4:
2338 num_palette = 16;
2339 color_inc = 0x11;
2340 break;
2341 case 8:
2342 num_palette = 256;
2343 color_inc = 1;
2344 break;
2345 default:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002346 num_palette = 0;
Guy Schalnat69b14481996-01-10 02:56:49 -06002347 color_inc = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002348 break;
2349 }
2350
2351 for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
2352 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002353 palette[i].red = (png_byte)v;
2354 palette[i].green = (png_byte)v;
2355 palette[i].blue = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002356 }
2357}
2358
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002359/* This function is currently unused. Do we really need it? */
2360#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002361void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002362png_correct_palette(png_structp png_ptr, png_colorp palette,
Guy Schalnat0d580581995-07-20 02:43:20 -05002363 int num_palette)
2364{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002365 png_debug(1, "in png_correct_palette\n");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002366#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
2367 defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002368 if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND))
Guy Schalnat0d580581995-07-20 02:43:20 -05002369 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002370 png_color back, back_1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002371
Andreas Dilger47a0c421997-05-16 02:46:07 -05002372 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
2373 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002374 back.red = png_ptr->gamma_table[png_ptr->background.red];
2375 back.green = png_ptr->gamma_table[png_ptr->background.green];
2376 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
Guy Schalnat0d580581995-07-20 02:43:20 -05002377
Guy Schalnate5a37791996-06-05 15:50:50 -05002378 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
2379 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
2380 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002381 }
2382 else
2383 {
2384 double g;
Guy Schalnat0d580581995-07-20 02:43:20 -05002385
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06002386 g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002387
2388 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
2389 fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
Guy Schalnat0d580581995-07-20 02:43:20 -05002390 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002391 back.red = png_ptr->background.red;
2392 back.green = png_ptr->background.green;
2393 back.blue = png_ptr->background.blue;
2394 }
2395 else
2396 {
2397 back.red =
2398 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2399 255.0 + 0.5);
2400 back.green =
2401 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2402 255.0 + 0.5);
2403 back.blue =
2404 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2405 255.0 + 0.5);
2406 }
2407
2408 g = 1.0 / png_ptr->background_gamma;
2409
2410 back_1.red =
2411 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2412 255.0 + 0.5);
2413 back_1.green =
2414 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2415 255.0 + 0.5);
2416 back_1.blue =
2417 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2418 255.0 + 0.5);
2419 }
2420
2421 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2422 {
2423 png_uint_32 i;
2424
2425 for (i = 0; i < (png_uint_32)num_palette; i++)
2426 {
2427 if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -05002428 {
2429 palette[i] = back;
2430 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002431 else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002432 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002433 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05002434
2435 v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002436 png_composite(w, v, png_ptr->trans[i], back_1.red);
2437 palette[i].red = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002438
2439 v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002440 png_composite(w, v, png_ptr->trans[i], back_1.green);
2441 palette[i].green = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002442
2443 v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002444 png_composite(w, v, png_ptr->trans[i], back_1.blue);
2445 palette[i].blue = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002446 }
2447 else
2448 {
2449 palette[i].red = png_ptr->gamma_table[palette[i].red];
2450 palette[i].green = png_ptr->gamma_table[palette[i].green];
2451 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2452 }
2453 }
2454 }
2455 else
2456 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002457 int i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002458
2459 for (i = 0; i < num_palette; i++)
2460 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002461 if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002462 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002463 palette[i] = back;
Guy Schalnat0d580581995-07-20 02:43:20 -05002464 }
2465 else
2466 {
2467 palette[i].red = png_ptr->gamma_table[palette[i].red];
2468 palette[i].green = png_ptr->gamma_table[palette[i].green];
2469 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2470 }
2471 }
2472 }
2473 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002474 else
2475#endif
2476#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002477 if (png_ptr->transformations & PNG_GAMMA)
Guy Schalnat0d580581995-07-20 02:43:20 -05002478 {
2479 int i;
2480
2481 for (i = 0; i < num_palette; i++)
2482 {
2483 palette[i].red = png_ptr->gamma_table[palette[i].red];
2484 palette[i].green = png_ptr->gamma_table[palette[i].green];
2485 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2486 }
2487 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002488#if defined(PNG_READ_BACKGROUND_SUPPORTED)
2489 else
2490#endif
2491#endif
2492#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002493 if (png_ptr->transformations & PNG_BACKGROUND)
Guy Schalnat0d580581995-07-20 02:43:20 -05002494 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002495 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05002496 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002497 png_color back;
Guy Schalnat0d580581995-07-20 02:43:20 -05002498
Guy Schalnate5a37791996-06-05 15:50:50 -05002499 back.red = (png_byte)png_ptr->background.red;
2500 back.green = (png_byte)png_ptr->background.green;
2501 back.blue = (png_byte)png_ptr->background.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002502
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06002503 for (i = 0; i < (int)png_ptr->num_trans; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002504 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002505 if (png_ptr->trans[i] == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -05002506 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002507 palette[i].red = back.red;
2508 palette[i].green = back.green;
2509 palette[i].blue = back.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002510 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002511 else if (png_ptr->trans[i] != 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002512 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002513 png_composite(palette[i].red, png_ptr->palette[i].red,
2514 png_ptr->trans[i], back.red);
2515 png_composite(palette[i].green, png_ptr->palette[i].green,
2516 png_ptr->trans[i], back.green);
2517 png_composite(palette[i].blue, png_ptr->palette[i].blue,
2518 png_ptr->trans[i], back.blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05002519 }
2520 }
2521 }
2522 else /* assume grayscale palette (what else could it be?) */
2523 {
2524 int i;
2525
2526 for (i = 0; i < num_palette; i++)
2527 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002528 if (i == (png_byte)png_ptr->trans_values.gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002529 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002530 palette[i].red = (png_byte)png_ptr->background.red;
2531 palette[i].green = (png_byte)png_ptr->background.green;
2532 palette[i].blue = (png_byte)png_ptr->background.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002533 }
2534 }
2535 }
2536 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002537#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002538}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002539#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002540
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002541#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002542/* Replace any alpha or transparency with the supplied background color.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002543 * "background" is already in the screen gamma, while "background_1" is
2544 * at a gamma of 1.0. Paletted files have already been taken care of.
2545 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002546void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002547png_do_background(png_row_infop row_info, png_bytep row,
2548 png_color_16p trans_values, png_color_16p background,
2549 png_color_16p background_1,
2550 png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002551 png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
2552 png_uint_16pp gamma_16_to_1, int gamma_shift)
Guy Schalnat0d580581995-07-20 02:43:20 -05002553{
Guy Schalnat6d764711995-12-19 03:22:19 -06002554 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002555 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002556 png_uint_32 row_width=row_info->width;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002557 int shift;
Guy Schalnate5a37791996-06-05 15:50:50 -05002558
Andreas Dilger47a0c421997-05-16 02:46:07 -05002559 png_debug(1, "in png_do_background\n");
2560 if (background != NULL &&
2561#if defined(PNG_USELESS_TESTS_SUPPORTED)
2562 row != NULL && row_info != NULL &&
2563#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002564 (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
Andreas Dilger47a0c421997-05-16 02:46:07 -05002565 (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
Guy Schalnat0d580581995-07-20 02:43:20 -05002566 {
2567 switch (row_info->color_type)
2568 {
2569 case PNG_COLOR_TYPE_GRAY:
2570 {
2571 switch (row_info->bit_depth)
2572 {
2573 case 1:
2574 {
Guy Schalnat0d580581995-07-20 02:43:20 -05002575 sp = row;
2576 shift = 7;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002577 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002578 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002579 if ((png_uint_16)((*sp >> shift) & 0x01)
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002580 == trans_values->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002581 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002582 *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2583 *sp |= (png_byte)(background->gray << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002584 }
2585 if (!shift)
2586 {
2587 shift = 7;
2588 sp++;
2589 }
2590 else
2591 shift--;
2592 }
2593 break;
2594 }
2595 case 2:
2596 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002597#if defined(PNG_READ_GAMMA_SUPPORTED)
2598 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002599 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002600 sp = row;
2601 shift = 6;
2602 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002603 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002604 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002605 == trans_values->gray)
2606 {
2607 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2608 *sp |= (png_byte)(background->gray << shift);
2609 }
2610 else
2611 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002612 png_byte p = (png_byte)((*sp >> shift) & 0x03);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002613 png_byte g = (png_byte)((gamma_table [p | (p << 2) |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002614 (p << 4) | (p << 6)] >> 6) & 0x03);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002615 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2616 *sp |= (png_byte)(g << shift);
2617 }
2618 if (!shift)
2619 {
2620 shift = 6;
2621 sp++;
2622 }
2623 else
2624 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002625 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002626 }
2627 else
2628#endif
2629 {
2630 sp = row;
2631 shift = 6;
2632 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002633 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002634 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002635 == trans_values->gray)
2636 {
2637 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2638 *sp |= (png_byte)(background->gray << shift);
2639 }
2640 if (!shift)
2641 {
2642 shift = 6;
2643 sp++;
2644 }
2645 else
2646 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002647 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002648 }
2649 break;
2650 }
2651 case 4:
2652 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002653#if defined(PNG_READ_GAMMA_SUPPORTED)
2654 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002655 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002656 sp = row;
2657 shift = 4;
2658 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002659 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002660 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002661 == trans_values->gray)
2662 {
2663 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2664 *sp |= (png_byte)(background->gray << shift);
2665 }
2666 else
2667 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002668 png_byte p = (png_byte)((*sp >> shift) & 0x0f);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002669 png_byte g = (png_byte)((gamma_table[p |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002670 (p << 4)] >> 4) & 0x0f);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002671 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2672 *sp |= (png_byte)(g << shift);
2673 }
2674 if (!shift)
2675 {
2676 shift = 4;
2677 sp++;
2678 }
2679 else
2680 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002681 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002682 }
2683 else
2684#endif
2685 {
2686 sp = row;
2687 shift = 4;
2688 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002689 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002690 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002691 == trans_values->gray)
2692 {
2693 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2694 *sp |= (png_byte)(background->gray << shift);
2695 }
2696 if (!shift)
2697 {
2698 shift = 4;
2699 sp++;
2700 }
2701 else
2702 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002703 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002704 }
2705 break;
2706 }
2707 case 8:
2708 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002709#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002710 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002711 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002712 sp = row;
2713 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002714 {
2715 if (*sp == trans_values->gray)
2716 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002717 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002718 }
2719 else
2720 {
2721 *sp = gamma_table[*sp];
2722 }
2723 }
2724 }
2725 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002726#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002727 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002728 sp = row;
2729 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002730 {
2731 if (*sp == trans_values->gray)
2732 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002733 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002734 }
2735 }
2736 }
2737 break;
2738 }
2739 case 16:
2740 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002741#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002742 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002743 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002744 sp = row;
2745 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002746 {
2747 png_uint_16 v;
2748
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002749 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05002750 if (v == trans_values->gray)
2751 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002752 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002753 *sp = (png_byte)((background->gray >> 8) & 0xff);
2754 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002755 }
2756 else
2757 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002758 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002759 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002760 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002761 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002762 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002763 }
2764 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002765#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002766 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002767 sp = row;
2768 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002769 {
2770 png_uint_16 v;
2771
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002772 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05002773 if (v == trans_values->gray)
2774 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002775 *sp = (png_byte)((background->gray >> 8) & 0xff);
2776 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002777 }
2778 }
2779 }
2780 break;
2781 }
2782 }
2783 break;
2784 }
2785 case PNG_COLOR_TYPE_RGB:
2786 {
2787 if (row_info->bit_depth == 8)
2788 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002789#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002790 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002791 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002792 sp = row;
2793 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002794 {
2795 if (*sp == trans_values->red &&
2796 *(sp + 1) == trans_values->green &&
2797 *(sp + 2) == trans_values->blue)
2798 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002799 *sp = (png_byte)background->red;
2800 *(sp + 1) = (png_byte)background->green;
2801 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002802 }
2803 else
2804 {
2805 *sp = gamma_table[*sp];
2806 *(sp + 1) = gamma_table[*(sp + 1)];
2807 *(sp + 2) = gamma_table[*(sp + 2)];
2808 }
2809 }
2810 }
2811 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002812#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002813 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002814 sp = row;
2815 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002816 {
2817 if (*sp == trans_values->red &&
2818 *(sp + 1) == trans_values->green &&
2819 *(sp + 2) == trans_values->blue)
2820 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002821 *sp = (png_byte)background->red;
2822 *(sp + 1) = (png_byte)background->green;
2823 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002824 }
2825 }
2826 }
2827 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002828 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05002829 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002830#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002831 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002832 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002833 sp = row;
2834 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002835 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002836 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2837 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2838 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05002839 if (r == trans_values->red && g == trans_values->green &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002840 b == trans_values->blue)
2841 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002842 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002843 *sp = (png_byte)((background->red >> 8) & 0xff);
2844 *(sp + 1) = (png_byte)(background->red & 0xff);
2845 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2846 *(sp + 3) = (png_byte)(background->green & 0xff);
2847 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2848 *(sp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002849 }
2850 else
2851 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002852 png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002853 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002854 *(sp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002855 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002856 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
2857 *(sp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002858 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002859 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
2860 *(sp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002861 }
2862 }
2863 }
2864 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002865#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002866 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002867 sp = row;
2868 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05002869 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002870 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
2871 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2872 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Guy Schalnat0d580581995-07-20 02:43:20 -05002873
Andreas Dilger47a0c421997-05-16 02:46:07 -05002874 if (r == trans_values->red && g == trans_values->green &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002875 b == trans_values->blue)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002876 {
2877 *sp = (png_byte)((background->red >> 8) & 0xff);
2878 *(sp + 1) = (png_byte)(background->red & 0xff);
2879 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2880 *(sp + 3) = (png_byte)(background->green & 0xff);
2881 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2882 *(sp + 5) = (png_byte)(background->blue & 0xff);
2883 }
2884 }
2885 }
2886 }
2887 break;
2888 }
2889 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -05002890 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002891 if (row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002892 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002893#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002894 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
2895 gamma_table != NULL)
2896 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002897 sp = row;
2898 dp = row;
2899 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002900 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002901 png_uint_16 a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002902
Andreas Dilger47a0c421997-05-16 02:46:07 -05002903 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002904 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002905 *dp = gamma_table[*sp];
2906 }
2907 else if (a == 0)
2908 {
2909 /* background is already in screen gamma */
2910 *dp = (png_byte)background->gray;
2911 }
2912 else
2913 {
2914 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05002915
Andreas Dilger47a0c421997-05-16 02:46:07 -05002916 v = gamma_to_1[*sp];
2917 png_composite(w, v, a, background_1->gray);
2918 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002919 }
2920 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002921 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002922 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002923#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002924 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002925 sp = row;
2926 dp = row;
2927 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002928 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002929 png_byte a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002930
Andreas Dilger47a0c421997-05-16 02:46:07 -05002931 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002932 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002933 *dp = *sp;
2934 }
2935 else if (a == 0)
2936 {
2937 *dp = (png_byte)background->gray;
2938 }
2939 else
2940 {
2941 png_composite(*dp, *sp, a, background_1->gray);
Guy Schalnat0d580581995-07-20 02:43:20 -05002942 }
2943 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002944 }
2945 }
2946 else /* if (png_ptr->bit_depth == 16) */
2947 {
2948#if defined(PNG_READ_GAMMA_SUPPORTED)
2949 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
2950 gamma_16_to_1 != NULL)
2951 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002952 sp = row;
2953 dp = row;
2954 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002955 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002956 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05002957
Andreas Dilger47a0c421997-05-16 02:46:07 -05002958 if (a == (png_uint_16)0xffff)
2959 {
2960 png_uint_16 v;
2961
2962 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
2963 *dp = (png_byte)((v >> 8) & 0xff);
2964 *(dp + 1) = (png_byte)(v & 0xff);
2965 }
2966 else if (a == 0)
2967 {
2968 /* background is already in screen gamma */
2969 *dp = (png_byte)((background->gray >> 8) & 0xff);
2970 *(dp + 1) = (png_byte)(background->gray & 0xff);
2971 }
2972 else
2973 {
2974 png_uint_16 g, v, w;
2975
2976 g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
2977 png_composite_16(v, g, a, background_1->gray);
2978 w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
2979 *dp = (png_byte)((w >> 8) & 0xff);
2980 *(dp + 1) = (png_byte)(w & 0xff);
2981 }
2982 }
2983 }
2984 else
2985#endif
2986 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002987 sp = row;
2988 dp = row;
2989 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002990 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002991 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05002992 if (a == (png_uint_16)0xffff)
2993 {
2994 png_memcpy(dp, sp, 2);
2995 }
2996 else if (a == 0)
2997 {
2998 *dp = (png_byte)((background->gray >> 8) & 0xff);
2999 *(dp + 1) = (png_byte)(background->gray & 0xff);
3000 }
3001 else
3002 {
3003 png_uint_16 g, v;
3004
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003005 g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003006 png_composite_16(v, g, a, background_1->gray);
3007 *dp = (png_byte)((v >> 8) & 0xff);
3008 *(dp + 1) = (png_byte)(v & 0xff);
3009 }
3010 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003011 }
3012 }
3013 break;
3014 }
3015 case PNG_COLOR_TYPE_RGB_ALPHA:
3016 {
3017 if (row_info->bit_depth == 8)
3018 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003019#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003020 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3021 gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003022 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003023 sp = row;
3024 dp = row;
3025 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003026 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003027 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003028
Guy Schalnat0d580581995-07-20 02:43:20 -05003029 if (a == 0xff)
3030 {
3031 *dp = gamma_table[*sp];
3032 *(dp + 1) = gamma_table[*(sp + 1)];
3033 *(dp + 2) = gamma_table[*(sp + 2)];
3034 }
3035 else if (a == 0)
3036 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003037 /* background is already in screen gamma */
3038 *dp = (png_byte)background->red;
3039 *(dp + 1) = (png_byte)background->green;
3040 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003041 }
3042 else
3043 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003044 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05003045
3046 v = gamma_to_1[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003047 png_composite(w, v, a, background_1->red);
3048 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003049 v = gamma_to_1[*(sp + 1)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003050 png_composite(w, v, a, background_1->green);
3051 *(dp + 1) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003052 v = gamma_to_1[*(sp + 2)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003053 png_composite(w, v, a, background_1->blue);
3054 *(dp + 2) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003055 }
3056 }
3057 }
3058 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003059#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003060 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003061 sp = row;
3062 dp = row;
3063 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003064 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003065 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003066
Guy Schalnat0d580581995-07-20 02:43:20 -05003067 if (a == 0xff)
3068 {
3069 *dp = *sp;
3070 *(dp + 1) = *(sp + 1);
3071 *(dp + 2) = *(sp + 2);
3072 }
3073 else if (a == 0)
3074 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003075 *dp = (png_byte)background->red;
3076 *(dp + 1) = (png_byte)background->green;
3077 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003078 }
3079 else
3080 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003081 png_composite(*dp, *sp, a, background->red);
3082 png_composite(*(dp + 1), *(sp + 1), a,
3083 background->green);
3084 png_composite(*(dp + 2), *(sp + 2), a,
3085 background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003086 }
3087 }
3088 }
3089 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003090 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003091 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003092#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003093 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3094 gamma_16_to_1 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003095 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003096 sp = row;
3097 dp = row;
3098 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003099 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003100 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3101 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003102 if (a == (png_uint_16)0xffff)
3103 {
3104 png_uint_16 v;
3105
Andreas Dilger47a0c421997-05-16 02:46:07 -05003106 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003107 *dp = (png_byte)((v >> 8) & 0xff);
3108 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003109 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003110 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3111 *(dp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003112 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003113 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3114 *(dp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003115 }
3116 else if (a == 0)
3117 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003118 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003119 *dp = (png_byte)((background->red >> 8) & 0xff);
3120 *(dp + 1) = (png_byte)(background->red & 0xff);
3121 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3122 *(dp + 3) = (png_byte)(background->green & 0xff);
3123 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3124 *(dp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003125 }
3126 else
3127 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003128 png_uint_16 v, w, x;
Guy Schalnat0d580581995-07-20 02:43:20 -05003129
Andreas Dilger47a0c421997-05-16 02:46:07 -05003130 v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3131 png_composite_16(w, v, a, background->red);
3132 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3133 *dp = (png_byte)((x >> 8) & 0xff);
3134 *(dp + 1) = (png_byte)(x & 0xff);
3135 v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
3136 png_composite_16(w, v, a, background->green);
3137 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3138 *(dp + 2) = (png_byte)((x >> 8) & 0xff);
3139 *(dp + 3) = (png_byte)(x & 0xff);
3140 v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
3141 png_composite_16(w, v, a, background->blue);
3142 x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
3143 *(dp + 4) = (png_byte)((x >> 8) & 0xff);
3144 *(dp + 5) = (png_byte)(x & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003145 }
3146 }
3147 }
3148 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003149#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003150 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003151 sp = row;
3152 dp = row;
3153 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003154 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003155 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3156 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003157 if (a == (png_uint_16)0xffff)
3158 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003159 png_memcpy(dp, sp, 6);
Guy Schalnat0d580581995-07-20 02:43:20 -05003160 }
3161 else if (a == 0)
3162 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003163 *dp = (png_byte)((background->red >> 8) & 0xff);
3164 *(dp + 1) = (png_byte)(background->red & 0xff);
3165 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3166 *(dp + 3) = (png_byte)(background->green & 0xff);
3167 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3168 *(dp + 5) = (png_byte)(background->blue & 0xff);
3169 }
3170 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003171 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003172 png_uint_16 v;
Guy Schalnat0d580581995-07-20 02:43:20 -05003173
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003174 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3175 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3176 + *(sp + 3));
3177 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3178 + *(sp + 5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003179
3180 png_composite_16(v, r, a, background->red);
Guy Schalnat0d580581995-07-20 02:43:20 -05003181 *dp = (png_byte)((v >> 8) & 0xff);
3182 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003183 png_composite_16(v, g, a, background->green);
Guy Schalnat0d580581995-07-20 02:43:20 -05003184 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3185 *(dp + 3) = (png_byte)(v & 0xff);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003186 png_composite_16(v, b, a, background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003187 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3188 *(dp + 5) = (png_byte)(v & 0xff);
3189 }
3190 }
3191 }
3192 }
3193 break;
3194 }
3195 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003196
Guy Schalnat0d580581995-07-20 02:43:20 -05003197 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
3198 {
3199 row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
Guy Schalnate5a37791996-06-05 15:50:50 -05003200 row_info->channels--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003201 row_info->pixel_depth = (png_byte)(row_info->channels *
3202 row_info->bit_depth);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003203 row_info->rowbytes = ((row_width *
Guy Schalnat0d580581995-07-20 02:43:20 -05003204 row_info->pixel_depth + 7) >> 3);
3205 }
3206 }
3207}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003208#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003209
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003210#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003211/* Gamma correct the image, avoiding the alpha channel. Make sure
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003212 * you do this after you deal with the transparency issue on grayscale
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003213 * or RGB images. If your bit depth is 8, use gamma_table, if it
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003214 * is 16, use gamma_16_table and gamma_shift. Build these with
3215 * build_gamma_table().
3216 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003217void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003218png_do_gamma(png_row_infop row_info, png_bytep row,
3219 png_bytep gamma_table, png_uint_16pp gamma_16_table,
Guy Schalnat0d580581995-07-20 02:43:20 -05003220 int gamma_shift)
3221{
Guy Schalnat6d764711995-12-19 03:22:19 -06003222 png_bytep sp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003223 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003224 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003225
Andreas Dilger47a0c421997-05-16 02:46:07 -05003226 png_debug(1, "in png_do_gamma\n");
3227 if (
3228#if defined(PNG_USELESS_TESTS_SUPPORTED)
3229 row != NULL && row_info != NULL &&
3230#endif
3231 ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
3232 (row_info->bit_depth == 16 && gamma_16_table != NULL)))
Guy Schalnat0d580581995-07-20 02:43:20 -05003233 {
3234 switch (row_info->color_type)
3235 {
3236 case PNG_COLOR_TYPE_RGB:
3237 {
3238 if (row_info->bit_depth == 8)
3239 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003240 sp = row;
3241 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003242 {
3243 *sp = gamma_table[*sp];
3244 sp++;
3245 *sp = gamma_table[*sp];
3246 sp++;
3247 *sp = gamma_table[*sp];
3248 sp++;
3249 }
3250 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003251 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003252 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003253 sp = row;
3254 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003255 {
3256 png_uint_16 v;
3257
Andreas Dilger47a0c421997-05-16 02:46:07 -05003258 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003259 *sp = (png_byte)((v >> 8) & 0xff);
3260 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003261 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003262 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003263 *sp = (png_byte)((v >> 8) & 0xff);
3264 *(sp + 1) = (png_byte)(v & 0xff);
3265 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003266 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003267 *sp = (png_byte)((v >> 8) & 0xff);
3268 *(sp + 1) = (png_byte)(v & 0xff);
3269 sp += 2;
3270 }
3271 }
3272 break;
3273 }
3274 case PNG_COLOR_TYPE_RGB_ALPHA:
3275 {
3276 if (row_info->bit_depth == 8)
3277 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003278 sp = row;
3279 for (i = 0; i < row_width; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003280 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003281 *sp = gamma_table[*sp];
3282 sp++;
3283 *sp = gamma_table[*sp];
3284 sp++;
3285 *sp = gamma_table[*sp];
3286 sp++;
3287 sp++;
3288 }
3289 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003290 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003291 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003292 sp = row;
3293 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003294 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003295 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003296 *sp = (png_byte)((v >> 8) & 0xff);
3297 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003298 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003299 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003300 *sp = (png_byte)((v >> 8) & 0xff);
3301 *(sp + 1) = (png_byte)(v & 0xff);
3302 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003303 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003304 *sp = (png_byte)((v >> 8) & 0xff);
3305 *(sp + 1) = (png_byte)(v & 0xff);
3306 sp += 4;
3307 }
3308 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003309 break;
3310 }
3311 case PNG_COLOR_TYPE_GRAY_ALPHA:
3312 {
3313 if (row_info->bit_depth == 8)
3314 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003315 sp = row;
3316 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003317 {
3318 *sp = gamma_table[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003319 sp += 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05003320 }
3321 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003322 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003323 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003324 sp = row;
3325 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003326 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003327 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003328 *sp = (png_byte)((v >> 8) & 0xff);
3329 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003330 sp += 4;
3331 }
3332 }
3333 break;
3334 }
3335 case PNG_COLOR_TYPE_GRAY:
3336 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003337 if (row_info->bit_depth == 2)
3338 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003339 sp = row;
3340 for (i = 0; i < row_width; i += 4)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003341 {
3342 int a = *sp & 0xc0;
3343 int b = *sp & 0x30;
3344 int c = *sp & 0x0c;
3345 int d = *sp & 0x03;
3346
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003347 *sp = (png_byte)(
3348 ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003349 ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
3350 ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003351 ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003352 sp++;
3353 }
3354 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003355 if (row_info->bit_depth == 4)
Guy Schalnat0d580581995-07-20 02:43:20 -05003356 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003357 sp = row;
3358 for (i = 0; i < row_width; i += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003359 {
3360 int msb = *sp & 0xf0;
3361 int lsb = *sp & 0x0f;
3362
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003363 *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
3364 | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003365 sp++;
3366 }
3367 }
3368 else if (row_info->bit_depth == 8)
3369 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003370 sp = row;
3371 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003372 {
3373 *sp = gamma_table[*sp];
3374 sp++;
3375 }
3376 }
3377 else if (row_info->bit_depth == 16)
3378 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003379 sp = row;
3380 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003381 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003382 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003383 *sp = (png_byte)((v >> 8) & 0xff);
3384 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003385 sp += 2;
3386 }
3387 }
3388 break;
3389 }
3390 }
3391 }
3392}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003393#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003394
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003395#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003396/* Expands a palette row to an RGB or RGBA row depending
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003397 * upon whether you supply trans and num_trans.
3398 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003399void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003400png_do_expand_palette(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05003401 png_colorp palette, png_bytep trans, int num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003402{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003403 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003404 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003405 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003406 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003407
Andreas Dilger47a0c421997-05-16 02:46:07 -05003408 png_debug(1, "in png_do_expand_palette\n");
3409 if (
3410#if defined(PNG_USELESS_TESTS_SUPPORTED)
3411 row != NULL && row_info != NULL &&
3412#endif
3413 row_info->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05003414 {
3415 if (row_info->bit_depth < 8)
3416 {
3417 switch (row_info->bit_depth)
3418 {
3419 case 1:
3420 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003421 sp = row + (png_size_t)((row_width - 1) >> 3);
3422 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003423 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003424 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003425 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003426 if ((*sp >> shift) & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -05003427 *dp = 1;
3428 else
3429 *dp = 0;
3430 if (shift == 7)
3431 {
3432 shift = 0;
3433 sp--;
3434 }
3435 else
3436 shift++;
3437
3438 dp--;
3439 }
3440 break;
3441 }
3442 case 2:
3443 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003444 sp = row + (png_size_t)((row_width - 1) >> 2);
3445 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003446 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003447 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003448 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003449 value = (*sp >> shift) & 0x03;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003450 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003451 if (shift == 6)
3452 {
3453 shift = 0;
3454 sp--;
3455 }
3456 else
3457 shift += 2;
3458
3459 dp--;
3460 }
3461 break;
3462 }
3463 case 4:
3464 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003465 sp = row + (png_size_t)((row_width - 1) >> 1);
3466 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003467 shift = (int)((row_width & 0x01) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003468 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003469 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003470 value = (*sp >> shift) & 0x0f;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003471 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003472 if (shift == 4)
3473 {
3474 shift = 0;
3475 sp--;
3476 }
3477 else
3478 shift += 4;
3479
3480 dp--;
3481 }
3482 break;
3483 }
3484 }
3485 row_info->bit_depth = 8;
3486 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003487 row_info->rowbytes = row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003488 }
3489 switch (row_info->bit_depth)
3490 {
3491 case 8:
3492 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003493 if (trans != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003494 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003495 sp = row + (png_size_t)row_width - 1;
3496 dp = row + (png_size_t)(row_width << 2) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003497
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003498 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003499 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003500 if ((int)(*sp) >= num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003501 *dp-- = 0xff;
3502 else
3503 *dp-- = trans[*sp];
3504 *dp-- = palette[*sp].blue;
3505 *dp-- = palette[*sp].green;
3506 *dp-- = palette[*sp].red;
3507 sp--;
3508 }
3509 row_info->bit_depth = 8;
3510 row_info->pixel_depth = 32;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003511 row_info->rowbytes = row_width * 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05003512 row_info->color_type = 6;
3513 row_info->channels = 4;
3514 }
3515 else
3516 {
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 * 3) - 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 {
3522 *dp-- = palette[*sp].blue;
3523 *dp-- = palette[*sp].green;
3524 *dp-- = palette[*sp].red;
3525 sp--;
3526 }
3527 row_info->bit_depth = 8;
3528 row_info->pixel_depth = 24;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003529 row_info->rowbytes = row_width * 3;
Guy Schalnat0d580581995-07-20 02:43:20 -05003530 row_info->color_type = 2;
3531 row_info->channels = 3;
3532 }
3533 break;
3534 }
3535 }
3536 }
3537}
3538
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003539/* If the bit depth < 8, it is expanded to 8. Also, if the
3540 * transparency value is supplied, an alpha channel is built.
3541 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003542void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003543png_do_expand(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003544 png_color_16p trans_value)
Guy Schalnat0d580581995-07-20 02:43:20 -05003545{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003546 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003547 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003548 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003549 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003550
Andreas Dilger47a0c421997-05-16 02:46:07 -05003551 png_debug(1, "in png_do_expand\n");
3552#if defined(PNG_USELESS_TESTS_SUPPORTED)
3553 if (row != NULL && row_info != NULL)
3554#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003555 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003556 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05003557 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003558 png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003559
3560 if (row_info->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003561 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003562 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05003563 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003564 case 1:
3565 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003566 gray = (png_uint_16)(gray*0xff);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003567 sp = row + (png_size_t)((row_width - 1) >> 3);
3568 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003569 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003570 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003571 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003572 if ((*sp >> shift) & 0x01)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003573 *dp = 0xff;
3574 else
3575 *dp = 0;
3576 if (shift == 7)
3577 {
3578 shift = 0;
3579 sp--;
3580 }
3581 else
3582 shift++;
3583
3584 dp--;
3585 }
3586 break;
3587 }
3588 case 2:
3589 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003590 gray = (png_uint_16)(gray*0x55);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003591 sp = row + (png_size_t)((row_width - 1) >> 2);
3592 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003593 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003594 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003595 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003596 value = (*sp >> shift) & 0x03;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003597 *dp = (png_byte)(value | (value << 2) | (value << 4) |
3598 (value << 6));
3599 if (shift == 6)
3600 {
3601 shift = 0;
3602 sp--;
3603 }
3604 else
3605 shift += 2;
3606
3607 dp--;
3608 }
3609 break;
3610 }
3611 case 4:
3612 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003613 gray = (png_uint_16)(gray*0x11);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003614 sp = row + (png_size_t)((row_width - 1) >> 1);
3615 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003616 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003617 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003618 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003619 value = (*sp >> shift) & 0x0f;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003620 *dp = (png_byte)(value | (value << 4));
3621 if (shift == 4)
3622 {
3623 shift = 0;
3624 sp--;
3625 }
3626 else
3627 shift = 4;
3628
3629 dp--;
3630 }
3631 break;
3632 }
3633 }
3634 row_info->bit_depth = 8;
3635 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003636 row_info->rowbytes = row_width;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003637 }
3638
Andreas Dilger47a0c421997-05-16 02:46:07 -05003639 if (trans_value != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003640 {
3641 if (row_info->bit_depth == 8)
3642 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003643 sp = row + (png_size_t)row_width - 1;
3644 dp = row + (png_size_t)(row_width << 1) - 1;
3645 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003646 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003647 if (*sp == gray)
3648 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003649 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003650 *dp-- = 0xff;
3651 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003652 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003653 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003654 else if (row_info->bit_depth == 16)
Guy Schalnat0d580581995-07-20 02:43:20 -05003655 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003656 sp = row + row_info->rowbytes - 1;
3657 dp = row + (row_info->rowbytes << 1) - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003658 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003659 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003660 if (((png_uint_16)*(sp) |
3661 ((png_uint_16)*(sp - 1) << 8)) == gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05003662 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003663 *dp-- = 0;
3664 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003665 }
3666 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003667 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003668 *dp-- = 0xff;
3669 *dp-- = 0xff;
Guy Schalnat0d580581995-07-20 02:43:20 -05003670 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003671 *dp-- = *sp--;
3672 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003673 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003674 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003675 row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
3676 row_info->channels = 2;
3677 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
3678 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003679 ((row_width * row_info->pixel_depth) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003680 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003681 }
3682 else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
3683 {
3684 if (row_info->bit_depth == 8)
3685 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003686 sp = row + (png_size_t)row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003687 dp = row + (png_size_t)(row_width << 2) - 1;
3688 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003689 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003690 if (*(sp - 2) == trans_value->red &&
Guy Schalnat0d580581995-07-20 02:43:20 -05003691 *(sp - 1) == trans_value->green &&
3692 *(sp - 0) == trans_value->blue)
3693 *dp-- = 0;
3694 else
3695 *dp-- = 0xff;
3696 *dp-- = *sp--;
3697 *dp-- = *sp--;
3698 *dp-- = *sp--;
3699 }
3700 }
3701 else if (row_info->bit_depth == 16)
3702 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003703 sp = row + row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003704 dp = row + (png_size_t)(row_width << 3) - 1;
3705 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003706 {
3707 if ((((png_uint_16)*(sp - 4) |
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003708 ((png_uint_16)*(sp - 5) << 8)) == trans_value->red) &&
Guy Schalnat0d580581995-07-20 02:43:20 -05003709 (((png_uint_16)*(sp - 2) |
3710 ((png_uint_16)*(sp - 3) << 8)) == trans_value->green) &&
3711 (((png_uint_16)*(sp - 0) |
3712 ((png_uint_16)*(sp - 1) << 8)) == trans_value->blue))
3713 {
3714 *dp-- = 0;
3715 *dp-- = 0;
3716 }
3717 else
3718 {
3719 *dp-- = 0xff;
3720 *dp-- = 0xff;
3721 }
3722 *dp-- = *sp--;
3723 *dp-- = *sp--;
3724 *dp-- = *sp--;
3725 *dp-- = *sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003726 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003727 *dp-- = *sp--;
3728 }
3729 }
3730 row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
3731 row_info->channels = 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003732 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
Guy Schalnat0d580581995-07-20 02:43:20 -05003733 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003734 ((row_width * row_info->pixel_depth) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003735 }
3736 }
3737}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003738#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003739
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003740#if defined(PNG_READ_DITHER_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003741void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003742png_do_dither(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003743 png_bytep palette_lookup, png_bytep dither_lookup)
Guy Schalnat0d580581995-07-20 02:43:20 -05003744{
Guy Schalnat6d764711995-12-19 03:22:19 -06003745 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003746 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003747 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003748
Andreas Dilger47a0c421997-05-16 02:46:07 -05003749 png_debug(1, "in png_do_dither\n");
3750#if defined(PNG_USELESS_TESTS_SUPPORTED)
3751 if (row != NULL && row_info != NULL)
3752#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003753 {
3754 if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
3755 palette_lookup && row_info->bit_depth == 8)
3756 {
3757 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003758 sp = row;
3759 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003760 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003761 {
3762 r = *sp++;
3763 g = *sp++;
3764 b = *sp++;
3765
3766 /* this looks real messy, but the compiler will reduce
3767 it down to a reasonable formula. For example, with
3768 5 bits per color, we get:
3769 p = (((r >> 3) & 0x1f) << 10) |
3770 (((g >> 3) & 0x1f) << 5) |
3771 ((b >> 3) & 0x1f);
3772 */
3773 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
3774 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
3775 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3776 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003777 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003778 (PNG_DITHER_BLUE_BITS)) |
3779 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3780 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3781
3782 *dp++ = palette_lookup[p];
3783 }
3784 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3785 row_info->channels = 1;
3786 row_info->pixel_depth = row_info->bit_depth;
3787 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003788 ((row_width * row_info->pixel_depth + 7) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003789 }
3790 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
Andreas Dilger47a0c421997-05-16 02:46:07 -05003791 palette_lookup != NULL && row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003792 {
3793 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003794 sp = row;
3795 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003796 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003797 {
3798 r = *sp++;
3799 g = *sp++;
3800 b = *sp++;
3801 sp++;
3802
3803 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003804 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003805 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3806 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
3807 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
3808 (PNG_DITHER_BLUE_BITS)) |
3809 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3810 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3811
3812 *dp++ = palette_lookup[p];
3813 }
3814 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3815 row_info->channels = 1;
3816 row_info->pixel_depth = row_info->bit_depth;
3817 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003818 ((row_width * row_info->pixel_depth + 7) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003819 }
3820 else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
3821 dither_lookup && row_info->bit_depth == 8)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003822 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003823 sp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003824 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003825 {
3826 *sp = dither_lookup[*sp];
3827 }
3828 }
3829 }
3830}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003831#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003832
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003833#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003834#if defined(PNG_READ_GAMMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05003835static int png_gamma_shift[] =
3836 {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0};
3837
Andreas Dilger47a0c421997-05-16 02:46:07 -05003838/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003839 * tables, we don't make a full table if we are reducing to 8-bit in
3840 * the future. Note also how the gamma_16 tables are segmented so that
3841 * we don't need to allocate > 64K chunks for a full 16-bit table.
3842 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003843void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003844png_build_gamma_table(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003845{
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003846 png_debug(1, "in png_build_gamma_table\n");
3847 if(png_ptr->gamma != 0.0)
3848 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003849 if (png_ptr->bit_depth <= 8)
3850 {
3851 int i;
3852 double g;
3853
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003854 if (png_ptr->screen_gamma > .000001)
3855 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
3856 else
3857 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003858
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003859 png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -05003860 (png_uint_32)256);
3861
3862 for (i = 0; i < 256; i++)
3863 {
3864 png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
3865 g) * 255.0 + .5);
3866 }
3867
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003868#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
3869 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003870 if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05003871 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003872
Guy Schalnat0d580581995-07-20 02:43:20 -05003873 g = 1.0 / (png_ptr->gamma);
3874
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003875 png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -05003876 (png_uint_32)256);
3877
3878 for (i = 0; i < 256; i++)
3879 {
3880 png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
3881 g) * 255.0 + .5);
3882 }
3883
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003884
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003885 png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -05003886 (png_uint_32)256);
3887
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003888 if(png_ptr->screen_gamma > 0.000001)
3889 g = 1.0 / png_ptr->screen_gamma;
3890 else
3891 g = png_ptr->gamma; /* probably doing rgb_to_gray */
3892
Guy Schalnat0d580581995-07-20 02:43:20 -05003893 for (i = 0; i < 256; i++)
3894 {
3895 png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
3896 g) * 255.0 + .5);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003897
Guy Schalnat0d580581995-07-20 02:43:20 -05003898 }
3899 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003900#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003901 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003902 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003903 {
3904 double g;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003905 int i, j, shift, num;
3906 int sig_bit;
3907 png_uint_32 ig;
Guy Schalnat0d580581995-07-20 02:43:20 -05003908
3909 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003910 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003911 sig_bit = (int)png_ptr->sig_bit.red;
3912 if ((int)png_ptr->sig_bit.green > sig_bit)
3913 sig_bit = png_ptr->sig_bit.green;
3914 if ((int)png_ptr->sig_bit.blue > sig_bit)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003915 sig_bit = png_ptr->sig_bit.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003916 }
3917 else
3918 {
3919 sig_bit = (int)png_ptr->sig_bit.gray;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003920 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003921
3922 if (sig_bit > 0)
3923 shift = 16 - sig_bit;
3924 else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003925 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003926
3927 if (png_ptr->transformations & PNG_16_TO_8)
3928 {
3929 if (shift < (16 - PNG_MAX_GAMMA_8))
3930 shift = (16 - PNG_MAX_GAMMA_8);
3931 }
3932
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003933 if (shift > 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003934 shift = 8;
3935 if (shift < 0)
3936 shift = 0;
3937
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003938 png_ptr->gamma_shift = (png_byte)shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05003939
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003940 num = (1 << (8 - shift));
Guy Schalnat0d580581995-07-20 02:43:20 -05003941
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003942 if (png_ptr->screen_gamma > .000001)
3943 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
3944 else
3945 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003946
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003947 png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06003948 (png_uint_32)(num * sizeof (png_uint_16p)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003949
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003950 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003951 {
3952 double fin, fout;
3953 png_uint_32 last, max;
Guy Schalnat0d580581995-07-20 02:43:20 -05003954
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003955 for (i = 0; i < num; i++)
3956 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003957 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06003958 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003959 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003960
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003961 g = 1.0 / g;
3962 last = 0;
3963 for (i = 0; i < 256; i++)
3964 {
3965 fout = ((double)i + 0.5) / 256.0;
3966 fin = pow(fout, g);
3967 max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
3968 while (last <= max)
3969 {
3970 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
3971 [(int)(last >> (8 - shift))] = (png_uint_16)(
3972 (png_uint_16)i | ((png_uint_16)i << 8));
3973 last++;
3974 }
3975 }
3976 while (last < ((png_uint_32)num << 8))
3977 {
3978 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
Andreas Dilger47a0c421997-05-16 02:46:07 -05003979 [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003980 last++;
Guy Schalnat6d764711995-12-19 03:22:19 -06003981 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003982 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003983 else
3984 {
3985 for (i = 0; i < num; i++)
3986 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003987 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06003988 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003989
Andreas Dilger47a0c421997-05-16 02:46:07 -05003990 ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003991 for (j = 0; j < 256; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003992 {
3993 png_ptr->gamma_16_table[i][j] =
3994 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
3995 65535.0, g) * 65535.0 + .5);
3996 }
3997 }
3998 }
3999
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004000#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
4001 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4002 if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05004003 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004004
Guy Schalnat0d580581995-07-20 02:43:20 -05004005 g = 1.0 / (png_ptr->gamma);
4006
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004007 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004008 (png_uint_32)(num * sizeof (png_uint_16p )));
Guy Schalnat0d580581995-07-20 02:43:20 -05004009
4010 for (i = 0; i < num; i++)
4011 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004012 png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004013 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004014
4015 ig = (((png_uint_32)i *
4016 (png_uint_32)png_gamma_shift[shift]) >> 4);
4017 for (j = 0; j < 256; j++)
4018 {
4019 png_ptr->gamma_16_to_1[i][j] =
4020 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4021 65535.0, g) * 65535.0 + .5);
4022 }
4023 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004024
4025 if(png_ptr->screen_gamma > 0.000001)
4026 g = 1.0 / png_ptr->screen_gamma;
4027 else
4028 g = png_ptr->gamma; /* probably doing rgb_to_gray */
Guy Schalnat0d580581995-07-20 02:43:20 -05004029
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004030 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004031 (png_uint_32)(num * sizeof (png_uint_16p)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004032
4033 for (i = 0; i < num; i++)
4034 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004035 png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004036 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004037
4038 ig = (((png_uint_32)i *
4039 (png_uint_32)png_gamma_shift[shift]) >> 4);
4040 for (j = 0; j < 256; j++)
4041 {
4042 png_ptr->gamma_16_from_1[i][j] =
4043 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4044 65535.0, g) * 65535.0 + .5);
4045 }
4046 }
4047 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004048#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05004049 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004050 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004051}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004052#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06004053/* To do: install integer version of png_build_gamma_table here */
4054#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004055
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004056#if defined(PNG_MNG_FEATURES_SUPPORTED)
4057/* undoes intrapixel differencing */
4058void /* PRIVATE */
4059png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
4060{
4061 png_debug(1, "in png_do_read_intrapixel\n");
4062 if (
4063#if defined(PNG_USELESS_TESTS_SUPPORTED)
4064 row != NULL && row_info != NULL &&
4065#endif
4066 (row_info->color_type & PNG_COLOR_MASK_COLOR))
4067 {
4068 int bytes_per_pixel;
4069 png_uint_32 row_width = row_info->width;
4070 if (row_info->bit_depth == 8)
4071 {
4072 png_bytep rp;
4073 png_uint_32 i;
4074
4075 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4076 bytes_per_pixel = 3;
4077 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4078 bytes_per_pixel = 4;
4079 else
4080 return;
4081
4082 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4083 {
4084 *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff);
4085 *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff);
4086 }
4087 }
4088 else if (row_info->bit_depth == 16)
4089 {
4090 png_bytep rp;
4091 png_uint_32 i;
4092
4093 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4094 bytes_per_pixel = 6;
4095 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4096 bytes_per_pixel = 8;
4097 else
4098 return;
4099
4100 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4101 {
4102 png_uint_32 s0=*(rp )<<8 | *(rp+1);
4103 png_uint_32 s1=*(rp+2)<<8 | *(rp+3);
4104 png_uint_32 s2=*(rp+4)<<8 | *(rp+5);
4105 png_uint_32 red=(65536+s0+s1)&0xffff;
4106 png_uint_32 blue=(65536+s2+s1)&0xffff;
4107 *(rp ) = (png_byte)((red>>8)&0xff);
4108 *(rp+1) = (png_byte)(red&0xff);
4109 *(rp+4) = (png_byte)((blue>>8)&0xff);
4110 *(rp+5) = (png_byte)(blue&0xff);
4111 }
4112 }
4113 }
4114}
4115#endif /* PNG_MNG_FEATURES_SUPPORTED */