blob: 9d9a2bdb6f22fa2b6f53d50bf2f814d2058c081c [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-Pehrson316f97a2000-07-08 13:19:41 -05004 * libpng 1.0.8beta1 - July 8, 2000
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -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-Pehrson860ab2b1999-10-14 07:43:10 -05001093 info_ptr->channels++;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001094#endif
1095
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001096#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
1097defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001098 if(png_ptr->transformations & PNG_USER_TRANSFORM)
1099 {
1100 if(info_ptr->bit_depth < png_ptr->user_transform_depth)
1101 info_ptr->bit_depth = png_ptr->user_transform_depth;
1102 if(info_ptr->channels < png_ptr->user_transform_channels)
1103 info_ptr->channels = png_ptr->user_transform_channels;
1104 }
1105#endif
1106
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001107 info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
1108 info_ptr->bit_depth);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001109 info_ptr->rowbytes = ((info_ptr->width * info_ptr->pixel_depth + 7) >> 3);
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05001110
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001111#if !defined(PNG_READ_EXPAND_SUPPORTED)
1112 if(png_ptr)
1113 return;
1114#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001115}
1116
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001117/* Transform the row. The order of transformations is significant,
1118 * and is very touchy. If you add a transformation, take care to
1119 * decide how it fits in with the other transformations here.
1120 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001121void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001122png_do_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05001123{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001124 png_debug(1, "in png_do_read_transformations\n");
1125#if !defined(PNG_USELESS_TESTS_SUPPORTED)
1126 if (png_ptr->row_buf == NULL)
1127 {
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -05001128#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001129 char msg[50];
1130
1131 sprintf(msg, "NULL row buffer for row %ld, pass %d", png_ptr->row_number,
1132 png_ptr->pass);
1133 png_error(png_ptr, msg);
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001134#else
1135 png_error(png_ptr, "NULL row buffer");
1136#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001137 }
1138#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001139
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001140#if defined(PNG_READ_EXPAND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001141 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05001142 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001143 if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
1144 {
1145 png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
1146 png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
1147 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001148 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001149 {
1150 if (png_ptr->num_trans)
1151 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1152 &(png_ptr->trans_values));
1153 else
1154 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1155 NULL);
1156 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001157 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001158#endif
1159
1160#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
1161 if (png_ptr->transformations & PNG_STRIP_ALPHA)
1162 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
1163 PNG_FLAG_FILLER_AFTER);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001164#endif
1165
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001166#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1167 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1168 {
1169 int rgb_error =
1170 png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1);
1171 if(rgb_error)
1172 {
1173 png_ptr->rgb_to_gray_status=1;
1174 if(png_ptr->transformations == PNG_RGB_TO_GRAY_WARN)
1175 png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1176 if(png_ptr->transformations == PNG_RGB_TO_GRAY_ERR)
1177 png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1178 }
1179 }
1180#endif
1181
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001182/*
1183From Andreas Dilger e-mail to png-implement, 26 March 1998:
1184
1185 In most cases, the "simple transparency" should be done prior to doing
1186 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 -06001187 pixel is transparent. You would also need to make sure that the
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001188 transparency information is upgraded to RGB.
1189
1190 To summarize, the current flow is:
1191 - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
1192 with background "in place" if transparent,
1193 convert to RGB if necessary
1194 - Gray + alpha -> composite with gray background and remove alpha bytes,
1195 convert to RGB if necessary
1196
1197 To support RGB backgrounds for gray images we need:
1198 - Gray + simple transparency -> convert to RGB + simple transparency, compare
1199 3 or 6 bytes and composite with background
1200 "in place" if transparent (3x compare/pixel
1201 compared to doing composite with gray bkgrnd)
1202 - Gray + alpha -> convert to RGB + alpha, composite with background and
1203 remove alpha bytes (3x float operations/pixel
1204 compared with composite on gray background)
1205
1206 Greg's change will do this. The reason it wasn't done before is for
1207 performance, as this increases the per-pixel operations. If we would check
1208 in advance if the background was gray or RGB, and position the gray-to-RGB
1209 transform appropriately, then it would save a lot of work/time.
1210 */
1211
1212#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1213 /* if gray -> RGB, do so now only if background is non-gray; else do later
1214 * for performance reasons */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001215 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001216 !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001217 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
1218#endif
1219
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001220#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001221 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1222 ((png_ptr->num_trans != 0 ) ||
1223 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
Guy Schalnat0d580581995-07-20 02:43:20 -05001224 png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
1225 &(png_ptr->trans_values), &(png_ptr->background),
1226 &(png_ptr->background_1),
1227 png_ptr->gamma_table, png_ptr->gamma_from_1,
1228 png_ptr->gamma_to_1, png_ptr->gamma_16_table,
1229 png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
1230 png_ptr->gamma_shift);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001231#endif
1232
1233#if defined(PNG_READ_GAMMA_SUPPORTED)
1234 if ((png_ptr->transformations & PNG_GAMMA) &&
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001235#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1236 !((png_ptr->transformations & PNG_BACKGROUND) &&
1237 ((png_ptr->num_trans != 0) ||
1238 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
1239#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001240 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
Guy Schalnat0d580581995-07-20 02:43:20 -05001241 png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
1242 png_ptr->gamma_table, png_ptr->gamma_16_table,
1243 png_ptr->gamma_shift);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001244#endif
1245
1246#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001247 if (png_ptr->transformations & PNG_16_TO_8)
1248 png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001249#endif
1250
1251#if defined(PNG_READ_DITHER_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001252 if (png_ptr->transformations & PNG_DITHER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001253 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001254 png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
1255 png_ptr->palette_lookup, png_ptr->dither_index);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001256 if(png_ptr->row_info.rowbytes == (png_uint_32)0)
1257 png_error(png_ptr, "png_do_dither returned rowbytes=0");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001258 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001259#endif
1260
1261#if defined(PNG_READ_INVERT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001262 if (png_ptr->transformations & PNG_INVERT_MONO)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001263 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001264#endif
1265
1266#if defined(PNG_READ_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001267 if (png_ptr->transformations & PNG_SHIFT)
1268 png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
1269 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001270#endif
1271
1272#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001273 if (png_ptr->transformations & PNG_PACK)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001274 png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001275#endif
1276
1277#if defined(PNG_READ_BGR_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001278 if (png_ptr->transformations & PNG_BGR)
1279 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001280#endif
1281
Andreas Dilger47a0c421997-05-16 02:46:07 -05001282#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1283 if (png_ptr->transformations & PNG_PACKSWAP)
1284 png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1285#endif
1286
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001287#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001288 /* if gray -> RGB, do so now only if we did not do so above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001289 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
1290 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05001291 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001292#endif
1293
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001294#if defined(PNG_READ_FILLER_SUPPORTED)
1295 if (png_ptr->transformations & PNG_FILLER)
1296 png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001297 (png_uint_32)png_ptr->filler, png_ptr->flags);
1298#endif
1299
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001300#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
1301 if (png_ptr->transformations & PNG_INVERT_ALPHA)
1302 png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1303#endif
1304
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001305#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
1306 if (png_ptr->transformations & PNG_SWAP_ALPHA)
1307 png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1308#endif
1309
Andreas Dilger47a0c421997-05-16 02:46:07 -05001310#if defined(PNG_READ_SWAP_SUPPORTED)
1311 if (png_ptr->transformations & PNG_SWAP_BYTES)
1312 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001313#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001314
1315#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1316 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001317 {
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001318 if(png_ptr->read_user_transform_fn != NULL)
1319 (*(png_ptr->read_user_transform_fn)) /* user read transform function */
1320 (png_ptr, /* png_ptr */
1321 &(png_ptr->row_info), /* row_info: */
1322 /* png_uint_32 width; width of row */
1323 /* png_uint_32 rowbytes; number of bytes in row */
1324 /* png_byte color_type; color type of pixels */
1325 /* png_byte bit_depth; bit depth of samples */
1326 /* png_byte channels; number of channels (1-4) */
1327 /* png_byte pixel_depth; bits per pixel (depth*channels) */
1328 png_ptr->row_buf + 1); /* start of pixel data for row */
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001329#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001330 if(png_ptr->user_transform_depth)
1331 png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
1332 if(png_ptr->user_transform_channels)
1333 png_ptr->row_info.channels = png_ptr->user_transform_channels;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001334#endif
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001335 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
1336 png_ptr->row_info.channels);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001337 png_ptr->row_info.rowbytes = (png_ptr->row_info.width *
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001338 png_ptr->row_info.pixel_depth+7)>>3;
1339 }
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001340#endif
1341
Guy Schalnat0d580581995-07-20 02:43:20 -05001342}
1343
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001344#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001345/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
1346 * without changing the actual values. Thus, if you had a row with
1347 * a bit depth of 1, you would end up with bytes that only contained
1348 * the numbers 0 or 1. If you would rather they contain 0 and 255, use
1349 * png_do_shift() after this.
1350 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001351void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001352png_do_unpack(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001353{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001354 png_debug(1, "in png_do_unpack\n");
1355#if defined(PNG_USELESS_TESTS_SUPPORTED)
1356 if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
1357#else
1358 if (row_info->bit_depth < 8)
1359#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001360 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001361 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001362 png_uint_32 row_width=row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001363
Guy Schalnat0d580581995-07-20 02:43:20 -05001364 switch (row_info->bit_depth)
1365 {
1366 case 1:
1367 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001368 png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
1369 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001370 png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001371 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001372 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001373 *dp = (png_byte)((*sp >> shift) & 0x01);
Guy Schalnat0d580581995-07-20 02:43:20 -05001374 if (shift == 7)
1375 {
1376 shift = 0;
1377 sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001378 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001379 else
1380 shift++;
1381
1382 dp--;
1383 }
1384 break;
1385 }
1386 case 2:
1387 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001388
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001389 png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
1390 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001391 png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001392 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001393 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001394 *dp = (png_byte)((*sp >> shift) & 0x03);
Guy Schalnat0d580581995-07-20 02:43:20 -05001395 if (shift == 6)
1396 {
1397 shift = 0;
1398 sp--;
1399 }
1400 else
1401 shift += 2;
1402
1403 dp--;
1404 }
1405 break;
1406 }
1407 case 4:
1408 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001409 png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
1410 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001411 png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001412 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001413 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001414 *dp = (png_byte)((*sp >> shift) & 0x0f);
Guy Schalnat0d580581995-07-20 02:43:20 -05001415 if (shift == 4)
1416 {
1417 shift = 0;
1418 sp--;
1419 }
1420 else
1421 shift = 4;
1422
1423 dp--;
1424 }
1425 break;
1426 }
1427 }
1428 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001429 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001430 row_info->rowbytes = row_width * row_info->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001431 }
1432}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001433#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001434
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001435#if defined(PNG_READ_SHIFT_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001436/* Reverse the effects of png_do_shift. This routine merely shifts the
1437 * pixels back to their significant bits values. Thus, if you have
1438 * a row of bit depth 8, but only 5 are significant, this will shift
1439 * the values back to 0 through 31.
1440 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001441void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001442png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
Guy Schalnat0d580581995-07-20 02:43:20 -05001443{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001444 png_debug(1, "in png_do_unshift\n");
1445 if (
1446#if defined(PNG_USELESS_TESTS_SUPPORTED)
1447 row != NULL && row_info != NULL && sig_bits != NULL &&
1448#endif
1449 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001450 {
1451 int shift[4];
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001452 int channels = 0;
1453 int c;
1454 png_uint_16 value = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001455 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001456
Guy Schalnat0d580581995-07-20 02:43:20 -05001457 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
1458 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001459 shift[channels++] = row_info->bit_depth - sig_bits->red;
1460 shift[channels++] = row_info->bit_depth - sig_bits->green;
1461 shift[channels++] = row_info->bit_depth - sig_bits->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05001462 }
1463 else
1464 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001465 shift[channels++] = row_info->bit_depth - sig_bits->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05001466 }
1467 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
1468 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001469 shift[channels++] = row_info->bit_depth - sig_bits->alpha;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001470 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001471
Andreas Dilger47a0c421997-05-16 02:46:07 -05001472 for (c = 0; c < channels; c++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001473 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001474 if (shift[c] <= 0)
1475 shift[c] = 0;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001476 else
1477 value = 1;
1478 }
Guy Schalnat0f716451995-11-28 11:22:13 -06001479
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001480 if (!value)
1481 return;
Guy Schalnat0f716451995-11-28 11:22:13 -06001482
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001483 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05001484 {
1485 case 2:
1486 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001487 png_bytep bp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001488 png_uint_32 i;
1489 png_uint_32 istop = row_info->rowbytes;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001490
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001491 for (bp = row, i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001492 {
1493 *bp >>= 1;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001494 *bp++ &= 0x55;
Guy Schalnat0d580581995-07-20 02:43:20 -05001495 }
1496 break;
1497 }
1498 case 4:
1499 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001500 png_bytep bp = row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001501 png_uint_32 i;
1502 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001503 png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
1504 (png_byte)((int)0xf >> shift[0]));
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001505
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001506 for (i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001507 {
1508 *bp >>= shift[0];
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001509 *bp++ &= mask;
Guy Schalnat0d580581995-07-20 02:43:20 -05001510 }
1511 break;
1512 }
1513 case 8:
1514 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001515 png_bytep bp = row;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001516 png_uint_32 i;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001517 png_uint_32 istop = row_width * channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001518
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001519 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001520 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001521 *bp++ >>= shift[i%channels];
Guy Schalnat0d580581995-07-20 02:43:20 -05001522 }
1523 break;
1524 }
1525 case 16:
1526 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001527 png_bytep bp = row;
1528 png_uint_32 i;
1529 png_uint_32 istop = channels * row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001530
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001531 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001532 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001533 value = (png_uint_16)((*bp << 8) + *(bp + 1));
1534 value >>= shift[i%channels];
1535 *bp++ = (png_byte)(value >> 8);
1536 *bp++ = (png_byte)(value & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05001537 }
1538 break;
1539 }
1540 }
1541 }
1542}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001543#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001544
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001545#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001546/* chop rows of bit depth 16 down to 8 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001547void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001548png_do_chop(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001549{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001550 png_debug(1, "in png_do_chop\n");
1551#if defined(PNG_USELESS_TESTS_SUPPORTED)
1552 if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
1553#else
1554 if (row_info->bit_depth == 16)
1555#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001556 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001557 png_bytep sp = row;
1558 png_bytep dp = row;
1559 png_uint_32 i;
1560 png_uint_32 istop = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001561
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001562 for (i = 0; i<istop; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001563 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001564#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001565 /* This does a more accurate scaling of the 16-bit color
1566 * value, rather than a simple low-byte truncation.
1567 *
1568 * What the ideal calculation should be:
1569 * *dp = (((((png_uint_32)(*sp) << 8) |
1570 * (png_uint_32)(*(sp + 1))) * 255 + 127) / (png_uint_32)65535L;
1571 *
1572 * GRR: no, I think this is what it really should be:
1573 * *dp = (((((png_uint_32)(*sp) << 8) |
1574 * (png_uint_32)(*(sp + 1))) + 128L) / (png_uint_32)257L;
1575 *
1576 * GRR: here's the exact calculation with shifts:
1577 * temp = (((png_uint_32)(*sp) << 8) | (png_uint_32)(*(sp + 1))) + 128L;
1578 * *dp = (temp - (temp >> 8)) >> 8;
1579 *
1580 * Approximate calculation with shift/add instead of multiply/divide:
1581 * *dp = ((((png_uint_32)(*sp) << 8) |
1582 * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
1583 *
1584 * What we actually do to avoid extra shifting and conversion:
1585 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001586
Andreas Dilger47a0c421997-05-16 02:46:07 -05001587 *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
1588#else
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001589 /* Simply discard the low order byte */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001590 *dp = *sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001591#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001592 }
1593 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001594 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001595 row_info->rowbytes = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001596 }
1597}
1598#endif
1599
1600#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001601void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001602png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
1603{
1604 png_debug(1, "in png_do_read_swap_alpha\n");
1605#if defined(PNG_USELESS_TESTS_SUPPORTED)
1606 if (row != NULL && row_info != NULL)
1607#endif
1608 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001609 png_uint_32 row_width = row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001610 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1611 {
1612 /* This converts from RGBA to ARGB */
1613 if (row_info->bit_depth == 8)
1614 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001615 png_bytep sp = row + row_info->rowbytes;
1616 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001617 png_byte save;
1618 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001619
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001620 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001621 {
1622 save = *(--sp);
1623 *(--dp) = *(--sp);
1624 *(--dp) = *(--sp);
1625 *(--dp) = *(--sp);
1626 *(--dp) = save;
1627 }
1628 }
1629 /* This converts from RRGGBBAA to AARRGGBB */
1630 else
1631 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001632 png_bytep sp = row + row_info->rowbytes;
1633 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001634 png_byte save[2];
1635 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001636
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001637 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001638 {
1639 save[0] = *(--sp);
1640 save[1] = *(--sp);
1641 *(--dp) = *(--sp);
1642 *(--dp) = *(--sp);
1643 *(--dp) = *(--sp);
1644 *(--dp) = *(--sp);
1645 *(--dp) = *(--sp);
1646 *(--dp) = *(--sp);
1647 *(--dp) = save[0];
1648 *(--dp) = save[1];
1649 }
1650 }
1651 }
1652 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1653 {
1654 /* This converts from GA to AG */
1655 if (row_info->bit_depth == 8)
1656 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001657 png_bytep sp = row + row_info->rowbytes;
1658 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001659 png_byte save;
1660 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001661
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001662 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001663 {
1664 save = *(--sp);
1665 *(--dp) = *(--sp);
1666 *(--dp) = save;
1667 }
1668 }
1669 /* This converts from GGAA to AAGG */
1670 else
1671 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001672 png_bytep sp = row + row_info->rowbytes;
1673 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001674 png_byte save[2];
1675 png_uint_32 i;
1676
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001677 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001678 {
1679 save[0] = *(--sp);
1680 save[1] = *(--sp);
1681 *(--dp) = *(--sp);
1682 *(--dp) = *(--sp);
1683 *(--dp) = save[0];
1684 *(--dp) = save[1];
1685 }
1686 }
1687 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001688 }
1689}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001690#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001691
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001692#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001693void /* PRIVATE */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001694png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
1695{
1696 png_debug(1, "in png_do_read_invert_alpha\n");
1697#if defined(PNG_USELESS_TESTS_SUPPORTED)
1698 if (row != NULL && row_info != NULL)
1699#endif
1700 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001701 png_uint_32 row_width = row_info->width;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001702 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1703 {
1704 /* This inverts the alpha channel in RGBA */
1705 if (row_info->bit_depth == 8)
1706 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001707 png_bytep sp = row + row_info->rowbytes;
1708 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001709 png_uint_32 i;
1710
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001711 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001712 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001713 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001714
1715/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001716 *(--dp) = *(--sp);
1717 *(--dp) = *(--sp);
1718 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001719 We can replace it with:
1720*/
1721 sp-=3;
1722 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001723 }
1724 }
1725 /* This inverts the alpha channel in RRGGBBAA */
1726 else
1727 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001728 png_bytep sp = row + row_info->rowbytes;
1729 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001730 png_uint_32 i;
1731
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001732 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001733 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001734 *(--dp) = (png_byte)(255 - *(--sp));
1735 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001736
1737/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001738 *(--dp) = *(--sp);
1739 *(--dp) = *(--sp);
1740 *(--dp) = *(--sp);
1741 *(--dp) = *(--sp);
1742 *(--dp) = *(--sp);
1743 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001744 We can replace it with:
1745*/
1746 sp-=6;
1747 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001748 }
1749 }
1750 }
1751 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1752 {
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001753 /* This inverts the alpha channel in GA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001754 if (row_info->bit_depth == 8)
1755 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001756 png_bytep sp = row + row_info->rowbytes;
1757 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001758 png_uint_32 i;
1759
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001760 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001761 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001762 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001763 *(--dp) = *(--sp);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001764 }
1765 }
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001766 /* This inverts the alpha channel in GGAA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001767 else
1768 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001769 png_bytep sp = row + row_info->rowbytes;
1770 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001771 png_uint_32 i;
1772
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001773 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001774 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001775 *(--dp) = (png_byte)(255 - *(--sp));
1776 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001777/*
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001778 *(--dp) = *(--sp);
1779 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001780*/
1781 sp-=2;
1782 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001783 }
1784 }
1785 }
1786 }
1787}
1788#endif
1789
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001790#if defined(PNG_READ_FILLER_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001791/* Add filler channel if we have RGB color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001792void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001793png_do_read_filler(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001794 png_uint_32 filler, png_uint_32 flags)
Guy Schalnat0d580581995-07-20 02:43:20 -05001795{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001796 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001797 png_uint_32 row_width = row_info->width;
1798
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001799 png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001800 png_byte lo_filler = (png_byte)(filler & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001801
1802 png_debug(1, "in png_do_read_filler\n");
1803 if (
1804#if defined(PNG_USELESS_TESTS_SUPPORTED)
1805 row != NULL && row_info != NULL &&
1806#endif
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001807 row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001808 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001809 if(row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05001810 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001811 /* This changes the data from G to GX */
1812 if (flags & PNG_FLAG_FILLER_AFTER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001813 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001814 png_bytep sp = row + (png_size_t)row_width;
1815 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001816 for (i = 1; i < row_width; i++)
1817 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001818 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001819 *(--dp) = *(--sp);
1820 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001821 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001822 row_info->channels = 2;
1823 row_info->pixel_depth = 16;
1824 row_info->rowbytes = row_width * 2;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001825 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001826 /* This changes the data from G to XG */
1827 else
1828 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001829 png_bytep sp = row + (png_size_t)row_width;
1830 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001831 for (i = 0; i < row_width; i++)
1832 {
1833 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001834 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001835 }
1836 row_info->channels = 2;
1837 row_info->pixel_depth = 16;
1838 row_info->rowbytes = row_width * 2;
1839 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001840 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001841 else if(row_info->bit_depth == 16)
1842 {
1843 /* This changes the data from GG to GGXX */
1844 if (flags & PNG_FLAG_FILLER_AFTER)
1845 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001846 png_bytep sp = row + (png_size_t)row_width;
1847 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001848 for (i = 1; i < row_width; i++)
1849 {
1850 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001851 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001852 *(--dp) = *(--sp);
1853 *(--dp) = *(--sp);
1854 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001855 *(--dp) = hi_filler;
1856 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001857 row_info->channels = 2;
1858 row_info->pixel_depth = 32;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001859 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001860 }
1861 /* This changes the data from GG to XXGG */
1862 else
1863 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001864 png_bytep sp = row + (png_size_t)row_width;
1865 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001866 for (i = 0; i < row_width; i++)
1867 {
1868 *(--dp) = *(--sp);
1869 *(--dp) = *(--sp);
1870 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001871 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001872 }
1873 row_info->channels = 2;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001874 row_info->pixel_depth = 32;
1875 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001876 }
1877 }
1878 } /* COLOR_TYPE == GRAY */
1879 else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
1880 {
1881 if(row_info->bit_depth == 8)
1882 {
1883 /* This changes the data from RGB to RGBX */
1884 if (flags & PNG_FLAG_FILLER_AFTER)
1885 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001886 png_bytep sp = row + (png_size_t)row_width * 3;
1887 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001888 for (i = 1; i < row_width; i++)
1889 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001890 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001891 *(--dp) = *(--sp);
1892 *(--dp) = *(--sp);
1893 *(--dp) = *(--sp);
1894 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001895 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001896 row_info->channels = 4;
1897 row_info->pixel_depth = 32;
1898 row_info->rowbytes = row_width * 4;
1899 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001900 /* This changes the data from RGB to XRGB */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001901 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001902 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001903 png_bytep sp = row + (png_size_t)row_width * 3;
1904 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001905 for (i = 0; i < row_width; i++)
1906 {
1907 *(--dp) = *(--sp);
1908 *(--dp) = *(--sp);
1909 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001910 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001911 }
1912 row_info->channels = 4;
1913 row_info->pixel_depth = 32;
1914 row_info->rowbytes = row_width * 4;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001915 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001916 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001917 else if(row_info->bit_depth == 16)
1918 {
1919 /* This changes the data from RRGGBB to RRGGBBXX */
1920 if (flags & PNG_FLAG_FILLER_AFTER)
1921 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001922 png_bytep sp = row + (png_size_t)row_width * 3;
1923 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001924 for (i = 1; i < row_width; i++)
1925 {
1926 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001927 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001928 *(--dp) = *(--sp);
1929 *(--dp) = *(--sp);
1930 *(--dp) = *(--sp);
1931 *(--dp) = *(--sp);
1932 *(--dp) = *(--sp);
1933 *(--dp) = *(--sp);
1934 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001935 *(--dp) = hi_filler;
1936 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001937 row_info->channels = 4;
1938 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001939 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001940 }
1941 /* This changes the data from RRGGBB to XXRRGGBB */
1942 else
1943 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001944 png_bytep sp = row + (png_size_t)row_width * 3;
1945 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001946 for (i = 0; i < row_width; i++)
1947 {
1948 *(--dp) = *(--sp);
1949 *(--dp) = *(--sp);
1950 *(--dp) = *(--sp);
1951 *(--dp) = *(--sp);
1952 *(--dp) = *(--sp);
1953 *(--dp) = *(--sp);
1954 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001955 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001956 }
1957 row_info->channels = 4;
1958 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001959 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001960 }
1961 }
1962 } /* COLOR_TYPE == RGB */
Guy Schalnat0d580581995-07-20 02:43:20 -05001963}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001964#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001965
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001966#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001967/* expand grayscale files to RGB, with or without alpha */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001968void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001969png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001970{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001971 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001972 png_uint_32 row_width = row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06001973
Andreas Dilger47a0c421997-05-16 02:46:07 -05001974 png_debug(1, "in png_do_gray_to_rgb\n");
1975 if (row_info->bit_depth >= 8 &&
1976#if defined(PNG_USELESS_TESTS_SUPPORTED)
1977 row != NULL && row_info != NULL &&
1978#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001979 !(row_info->color_type & PNG_COLOR_MASK_COLOR))
1980 {
1981 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
1982 {
1983 if (row_info->bit_depth == 8)
1984 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001985 png_bytep sp = row + (png_size_t)row_width - 1;
1986 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001987 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001988 {
1989 *(dp--) = *sp;
1990 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001991 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05001992 }
1993 }
1994 else
1995 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001996 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
1997 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001998 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001999 {
2000 *(dp--) = *sp;
2001 *(dp--) = *(sp - 1);
2002 *(dp--) = *sp;
2003 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002004 *(dp--) = *(sp--);
2005 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002006 }
2007 }
2008 }
2009 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2010 {
2011 if (row_info->bit_depth == 8)
2012 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002013 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2014 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002015 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002016 {
2017 *(dp--) = *(sp--);
2018 *(dp--) = *sp;
2019 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002020 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002021 }
2022 }
2023 else
2024 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002025 png_bytep sp = row + (png_size_t)row_width * 4 - 1;
2026 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002027 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002028 {
2029 *(dp--) = *(sp--);
2030 *(dp--) = *(sp--);
2031 *(dp--) = *sp;
2032 *(dp--) = *(sp - 1);
2033 *(dp--) = *sp;
2034 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002035 *(dp--) = *(sp--);
2036 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002037 }
2038 }
2039 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002040 row_info->channels += (png_byte)2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002041 row_info->color_type |= PNG_COLOR_MASK_COLOR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002042 row_info->pixel_depth = (png_byte)(row_info->channels *
2043 row_info->bit_depth);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002044 row_info->rowbytes = ((row_width *
Guy Schalnat0d580581995-07-20 02:43:20 -05002045 row_info->pixel_depth + 7) >> 3);
2046 }
2047}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002048#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002049
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002050#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002051/* reduce RGB files to grayscale, with or without alpha
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002052 * using the equation given in Poynton's ColorFAQ at
2053 * <http://www.inforamp.net/~poynton/>
2054 * Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net
2055 *
2056 * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
2057 *
2058 * We approximate this with
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002059 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002060 * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002061 *
2062 * which can be expressed with integers as
2063 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002064 * Y = (6969 * R + 23434 * G + 2365 * B)/32768
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002065 *
2066 * The calculation is to be done in a linear colorspace.
2067 *
2068 * Other integer coefficents can be used via png_set_rgb_to_gray().
2069 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002070int /* PRIVATE */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002071png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
2072
2073{
2074 png_uint_32 i;
2075
2076 png_uint_32 row_width = row_info->width;
2077 int rgb_error = 0;
2078
2079 png_debug(1, "in png_do_rgb_to_gray\n");
2080 if (
2081#if defined(PNG_USELESS_TESTS_SUPPORTED)
2082 row != NULL && row_info != NULL &&
2083#endif
2084 (row_info->color_type & PNG_COLOR_MASK_COLOR))
2085 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002086 png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
2087 png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
2088 png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002089
2090 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2091 {
2092 if (row_info->bit_depth == 8)
2093 {
2094#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2095 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2096 {
2097 png_bytep sp = row;
2098 png_bytep dp = row;
2099
2100 for (i = 0; i < row_width; i++)
2101 {
2102 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2103 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2104 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
2105 if(red != green || red != blue)
2106 {
2107 rgb_error |= 1;
2108 *(dp++) = png_ptr->gamma_from_1[
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002109 (rc*red+gc*green+bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002110 }
2111 else
2112 *(dp++) = *(sp-1);
2113 }
2114 }
2115 else
2116#endif
2117 {
2118 png_bytep sp = row;
2119 png_bytep dp = row;
2120 for (i = 0; i < row_width; i++)
2121 {
2122 png_byte red = *(sp++);
2123 png_byte green = *(sp++);
2124 png_byte blue = *(sp++);
2125 if(red != green || red != blue)
2126 {
2127 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002128 *(dp++) = (png_byte)((rc*red+gc*green+bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002129 }
2130 else
2131 *(dp++) = *(sp-1);
2132 }
2133 }
2134 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002135
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002136 else /* RGB bit_depth == 16 */
2137 {
2138#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2139 if (png_ptr->gamma_16_to_1 != NULL &&
2140 png_ptr->gamma_16_from_1 != NULL)
2141 {
2142 png_bytep sp = row;
2143 png_bytep dp = row;
2144 for (i = 0; i < row_width; i++)
2145 {
2146 png_uint_16 red, green, blue, w;
2147
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002148 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2149 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2150 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002151
2152 if(red == green && red == blue)
2153 w = red;
2154 else
2155 {
2156 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2157 png_ptr->gamma_shift][red>>8];
2158 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2159 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002160 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002161 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002162 png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002163 + bc*blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002164 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2165 png_ptr->gamma_shift][gray16 >> 8];
2166 rgb_error |= 1;
2167 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002168
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002169 *(dp++) = (png_byte)((w>>8) & 0xff);
2170 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002171 }
2172 }
2173 else
2174#endif
2175 {
2176 png_bytep sp = row;
2177 png_bytep dp = row;
2178 for (i = 0; i < row_width; i++)
2179 {
2180 png_uint_16 red, green, blue, gray16;
2181
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002182 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2183 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2184 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002185
2186 if(red != green || red != blue)
2187 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002188 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002189 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2190 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002191 }
2192 }
2193 }
2194 }
2195 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2196 {
2197 if (row_info->bit_depth == 8)
2198 {
2199#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2200 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2201 {
2202 png_bytep sp = row;
2203 png_bytep dp = row;
2204 for (i = 0; i < row_width; i++)
2205 {
2206 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2207 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2208 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
2209 if(red != green || red != blue)
2210 rgb_error |= 1;
2211 *(dp++) = png_ptr->gamma_from_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002212 [(rc*red + gc*green + bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002213 *(dp++) = *(sp++); /* alpha */
2214 }
2215 }
2216 else
2217#endif
2218 {
2219 png_bytep sp = row;
2220 png_bytep dp = row;
2221 for (i = 0; i < row_width; i++)
2222 {
2223 png_byte red = *(sp++);
2224 png_byte green = *(sp++);
2225 png_byte blue = *(sp++);
2226 if(red != green || red != blue)
2227 rgb_error |= 1;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002228 *(dp++) = (png_byte)((gc*red + gc*green + bc*blue)>>8);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002229 *(dp++) = *(sp++); /* alpha */
2230 }
2231 }
2232 }
2233 else /* RGBA bit_depth == 16 */
2234 {
2235#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2236 if (png_ptr->gamma_16_to_1 != NULL &&
2237 png_ptr->gamma_16_from_1 != NULL)
2238 {
2239 png_bytep sp = row;
2240 png_bytep dp = row;
2241 for (i = 0; i < row_width; i++)
2242 {
2243 png_uint_16 red, green, blue, w;
2244
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002245 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2246 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2247 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002248
2249 if(red == green && red == blue)
2250 w = red;
2251 else
2252 {
2253 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2254 png_ptr->gamma_shift][red>>8];
2255 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2256 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002257 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002258 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002259 png_uint_16 gray16 = (png_uint_16)((rc * red_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002260 + gc * green_1 + bc * blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002261 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2262 png_ptr->gamma_shift][gray16 >> 8];
2263 rgb_error |= 1;
2264 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002265
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002266 *(dp++) = (png_byte)((w>>8) & 0xff);
2267 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002268 *(dp++) = *(sp++); /* alpha */
2269 *(dp++) = *(sp++);
2270 }
2271 }
2272 else
2273#endif
2274 {
2275 png_bytep sp = row;
2276 png_bytep dp = row;
2277 for (i = 0; i < row_width; i++)
2278 {
2279 png_uint_16 red, green, blue, gray16;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002280 red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2281 green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2282 blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002283 if(red != green || red != blue)
2284 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002285 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002286 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2287 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002288 *(dp++) = *(sp++); /* alpha */
2289 *(dp++) = *(sp++);
2290 }
2291 }
2292 }
2293 }
2294 row_info->channels -= (png_byte)2;
2295 row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
2296 row_info->pixel_depth = (png_byte)(row_info->channels *
2297 row_info->bit_depth);
2298 row_info->rowbytes = ((row_width *
2299 row_info->pixel_depth + 7) >> 3);
2300 }
2301 return rgb_error;
2302}
2303#endif
2304
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002305/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
2306 * large of png_color. This lets grayscale images be treated as
2307 * paletted. Most useful for gamma correction and simplification
2308 * of code.
2309 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002310void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002311png_build_grayscale_palette(int bit_depth, png_colorp palette)
Guy Schalnat0d580581995-07-20 02:43:20 -05002312{
2313 int num_palette;
2314 int color_inc;
2315 int i;
2316 int v;
2317
Andreas Dilger47a0c421997-05-16 02:46:07 -05002318 png_debug(1, "in png_do_build_grayscale_palette\n");
2319 if (palette == NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002320 return;
2321
2322 switch (bit_depth)
2323 {
2324 case 1:
2325 num_palette = 2;
2326 color_inc = 0xff;
2327 break;
2328 case 2:
2329 num_palette = 4;
2330 color_inc = 0x55;
2331 break;
2332 case 4:
2333 num_palette = 16;
2334 color_inc = 0x11;
2335 break;
2336 case 8:
2337 num_palette = 256;
2338 color_inc = 1;
2339 break;
2340 default:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002341 num_palette = 0;
Guy Schalnat69b14481996-01-10 02:56:49 -06002342 color_inc = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002343 break;
2344 }
2345
2346 for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
2347 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002348 palette[i].red = (png_byte)v;
2349 palette[i].green = (png_byte)v;
2350 palette[i].blue = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002351 }
2352}
2353
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002354/* This function is currently unused. Do we really need it? */
2355#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002356void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002357png_correct_palette(png_structp png_ptr, png_colorp palette,
Guy Schalnat0d580581995-07-20 02:43:20 -05002358 int num_palette)
2359{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002360 png_debug(1, "in png_correct_palette\n");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002361#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
2362 defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002363 if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND))
Guy Schalnat0d580581995-07-20 02:43:20 -05002364 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002365 png_color back, back_1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002366
Andreas Dilger47a0c421997-05-16 02:46:07 -05002367 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
2368 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002369 back.red = png_ptr->gamma_table[png_ptr->background.red];
2370 back.green = png_ptr->gamma_table[png_ptr->background.green];
2371 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
Guy Schalnat0d580581995-07-20 02:43:20 -05002372
Guy Schalnate5a37791996-06-05 15:50:50 -05002373 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
2374 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
2375 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002376 }
2377 else
2378 {
2379 double g;
Guy Schalnat0d580581995-07-20 02:43:20 -05002380
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06002381 g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002382
2383 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
2384 fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
Guy Schalnat0d580581995-07-20 02:43:20 -05002385 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002386 back.red = png_ptr->background.red;
2387 back.green = png_ptr->background.green;
2388 back.blue = png_ptr->background.blue;
2389 }
2390 else
2391 {
2392 back.red =
2393 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2394 255.0 + 0.5);
2395 back.green =
2396 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2397 255.0 + 0.5);
2398 back.blue =
2399 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2400 255.0 + 0.5);
2401 }
2402
2403 g = 1.0 / png_ptr->background_gamma;
2404
2405 back_1.red =
2406 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2407 255.0 + 0.5);
2408 back_1.green =
2409 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2410 255.0 + 0.5);
2411 back_1.blue =
2412 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2413 255.0 + 0.5);
2414 }
2415
2416 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2417 {
2418 png_uint_32 i;
2419
2420 for (i = 0; i < (png_uint_32)num_palette; i++)
2421 {
2422 if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -05002423 {
2424 palette[i] = back;
2425 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002426 else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002427 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002428 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05002429
2430 v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002431 png_composite(w, v, png_ptr->trans[i], back_1.red);
2432 palette[i].red = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002433
2434 v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002435 png_composite(w, v, png_ptr->trans[i], back_1.green);
2436 palette[i].green = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002437
2438 v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002439 png_composite(w, v, png_ptr->trans[i], back_1.blue);
2440 palette[i].blue = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002441 }
2442 else
2443 {
2444 palette[i].red = png_ptr->gamma_table[palette[i].red];
2445 palette[i].green = png_ptr->gamma_table[palette[i].green];
2446 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2447 }
2448 }
2449 }
2450 else
2451 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002452 int i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002453
2454 for (i = 0; i < num_palette; i++)
2455 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002456 if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002457 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002458 palette[i] = back;
Guy Schalnat0d580581995-07-20 02:43:20 -05002459 }
2460 else
2461 {
2462 palette[i].red = png_ptr->gamma_table[palette[i].red];
2463 palette[i].green = png_ptr->gamma_table[palette[i].green];
2464 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2465 }
2466 }
2467 }
2468 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002469 else
2470#endif
2471#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002472 if (png_ptr->transformations & PNG_GAMMA)
Guy Schalnat0d580581995-07-20 02:43:20 -05002473 {
2474 int i;
2475
2476 for (i = 0; i < num_palette; i++)
2477 {
2478 palette[i].red = png_ptr->gamma_table[palette[i].red];
2479 palette[i].green = png_ptr->gamma_table[palette[i].green];
2480 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2481 }
2482 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002483#if defined(PNG_READ_BACKGROUND_SUPPORTED)
2484 else
2485#endif
2486#endif
2487#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002488 if (png_ptr->transformations & PNG_BACKGROUND)
Guy Schalnat0d580581995-07-20 02:43:20 -05002489 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002490 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05002491 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002492 png_color back;
Guy Schalnat0d580581995-07-20 02:43:20 -05002493
Guy Schalnate5a37791996-06-05 15:50:50 -05002494 back.red = (png_byte)png_ptr->background.red;
2495 back.green = (png_byte)png_ptr->background.green;
2496 back.blue = (png_byte)png_ptr->background.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002497
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06002498 for (i = 0; i < (int)png_ptr->num_trans; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002499 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002500 if (png_ptr->trans[i] == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -05002501 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002502 palette[i].red = back.red;
2503 palette[i].green = back.green;
2504 palette[i].blue = back.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002505 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002506 else if (png_ptr->trans[i] != 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002507 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002508 png_composite(palette[i].red, png_ptr->palette[i].red,
2509 png_ptr->trans[i], back.red);
2510 png_composite(palette[i].green, png_ptr->palette[i].green,
2511 png_ptr->trans[i], back.green);
2512 png_composite(palette[i].blue, png_ptr->palette[i].blue,
2513 png_ptr->trans[i], back.blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05002514 }
2515 }
2516 }
2517 else /* assume grayscale palette (what else could it be?) */
2518 {
2519 int i;
2520
2521 for (i = 0; i < num_palette; i++)
2522 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002523 if (i == (png_byte)png_ptr->trans_values.gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002524 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002525 palette[i].red = (png_byte)png_ptr->background.red;
2526 palette[i].green = (png_byte)png_ptr->background.green;
2527 palette[i].blue = (png_byte)png_ptr->background.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002528 }
2529 }
2530 }
2531 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002532#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002533}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002534#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002535
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002536#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002537/* Replace any alpha or transparency with the supplied background color.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002538 * "background" is already in the screen gamma, while "background_1" is
2539 * at a gamma of 1.0. Paletted files have already been taken care of.
2540 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002541void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002542png_do_background(png_row_infop row_info, png_bytep row,
2543 png_color_16p trans_values, png_color_16p background,
2544 png_color_16p background_1,
2545 png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002546 png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
2547 png_uint_16pp gamma_16_to_1, int gamma_shift)
Guy Schalnat0d580581995-07-20 02:43:20 -05002548{
Guy Schalnat6d764711995-12-19 03:22:19 -06002549 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002550 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002551 png_uint_32 row_width=row_info->width;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002552 int shift;
Guy Schalnate5a37791996-06-05 15:50:50 -05002553
Andreas Dilger47a0c421997-05-16 02:46:07 -05002554 png_debug(1, "in png_do_background\n");
2555 if (background != NULL &&
2556#if defined(PNG_USELESS_TESTS_SUPPORTED)
2557 row != NULL && row_info != NULL &&
2558#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002559 (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
Andreas Dilger47a0c421997-05-16 02:46:07 -05002560 (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
Guy Schalnat0d580581995-07-20 02:43:20 -05002561 {
2562 switch (row_info->color_type)
2563 {
2564 case PNG_COLOR_TYPE_GRAY:
2565 {
2566 switch (row_info->bit_depth)
2567 {
2568 case 1:
2569 {
Guy Schalnat0d580581995-07-20 02:43:20 -05002570 sp = row;
2571 shift = 7;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002572 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002573 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002574 if ((png_uint_16)((*sp >> shift) & 0x01)
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002575 == trans_values->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002576 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002577 *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2578 *sp |= (png_byte)(background->gray << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002579 }
2580 if (!shift)
2581 {
2582 shift = 7;
2583 sp++;
2584 }
2585 else
2586 shift--;
2587 }
2588 break;
2589 }
2590 case 2:
2591 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002592#if defined(PNG_READ_GAMMA_SUPPORTED)
2593 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002594 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002595 sp = row;
2596 shift = 6;
2597 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002598 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002599 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002600 == trans_values->gray)
2601 {
2602 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2603 *sp |= (png_byte)(background->gray << shift);
2604 }
2605 else
2606 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002607 png_byte p = (png_byte)((*sp >> shift) & 0x03);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002608 png_byte g = (png_byte)((gamma_table [p | (p << 2) |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002609 (p << 4) | (p << 6)] >> 6) & 0x03);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002610 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2611 *sp |= (png_byte)(g << shift);
2612 }
2613 if (!shift)
2614 {
2615 shift = 6;
2616 sp++;
2617 }
2618 else
2619 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002620 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002621 }
2622 else
2623#endif
2624 {
2625 sp = row;
2626 shift = 6;
2627 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002628 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002629 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002630 == trans_values->gray)
2631 {
2632 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2633 *sp |= (png_byte)(background->gray << shift);
2634 }
2635 if (!shift)
2636 {
2637 shift = 6;
2638 sp++;
2639 }
2640 else
2641 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002642 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002643 }
2644 break;
2645 }
2646 case 4:
2647 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002648#if defined(PNG_READ_GAMMA_SUPPORTED)
2649 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002650 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002651 sp = row;
2652 shift = 4;
2653 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002654 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002655 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002656 == trans_values->gray)
2657 {
2658 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2659 *sp |= (png_byte)(background->gray << shift);
2660 }
2661 else
2662 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002663 png_byte p = (png_byte)((*sp >> shift) & 0x0f);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002664 png_byte g = (png_byte)((gamma_table[p |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002665 (p << 4)] >> 4) & 0x0f);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002666 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2667 *sp |= (png_byte)(g << shift);
2668 }
2669 if (!shift)
2670 {
2671 shift = 4;
2672 sp++;
2673 }
2674 else
2675 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002676 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002677 }
2678 else
2679#endif
2680 {
2681 sp = row;
2682 shift = 4;
2683 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002684 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002685 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002686 == trans_values->gray)
2687 {
2688 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2689 *sp |= (png_byte)(background->gray << shift);
2690 }
2691 if (!shift)
2692 {
2693 shift = 4;
2694 sp++;
2695 }
2696 else
2697 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002698 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002699 }
2700 break;
2701 }
2702 case 8:
2703 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002704#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002705 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002706 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002707 sp = row;
2708 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002709 {
2710 if (*sp == trans_values->gray)
2711 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002712 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002713 }
2714 else
2715 {
2716 *sp = gamma_table[*sp];
2717 }
2718 }
2719 }
2720 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002721#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002722 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002723 sp = row;
2724 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002725 {
2726 if (*sp == trans_values->gray)
2727 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002728 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002729 }
2730 }
2731 }
2732 break;
2733 }
2734 case 16:
2735 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002736#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002737 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002738 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002739 sp = row;
2740 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002741 {
2742 png_uint_16 v;
2743
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002744 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05002745 if (v == trans_values->gray)
2746 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002747 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002748 *sp = (png_byte)((background->gray >> 8) & 0xff);
2749 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002750 }
2751 else
2752 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002753 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002754 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002755 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002756 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002757 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002758 }
2759 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002760#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002761 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002762 sp = row;
2763 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002764 {
2765 png_uint_16 v;
2766
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002767 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05002768 if (v == trans_values->gray)
2769 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002770 *sp = (png_byte)((background->gray >> 8) & 0xff);
2771 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002772 }
2773 }
2774 }
2775 break;
2776 }
2777 }
2778 break;
2779 }
2780 case PNG_COLOR_TYPE_RGB:
2781 {
2782 if (row_info->bit_depth == 8)
2783 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002784#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002785 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002786 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002787 sp = row;
2788 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002789 {
2790 if (*sp == trans_values->red &&
2791 *(sp + 1) == trans_values->green &&
2792 *(sp + 2) == trans_values->blue)
2793 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002794 *sp = (png_byte)background->red;
2795 *(sp + 1) = (png_byte)background->green;
2796 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002797 }
2798 else
2799 {
2800 *sp = gamma_table[*sp];
2801 *(sp + 1) = gamma_table[*(sp + 1)];
2802 *(sp + 2) = gamma_table[*(sp + 2)];
2803 }
2804 }
2805 }
2806 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002807#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002808 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002809 sp = row;
2810 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002811 {
2812 if (*sp == trans_values->red &&
2813 *(sp + 1) == trans_values->green &&
2814 *(sp + 2) == trans_values->blue)
2815 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002816 *sp = (png_byte)background->red;
2817 *(sp + 1) = (png_byte)background->green;
2818 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002819 }
2820 }
2821 }
2822 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002823 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05002824 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002825#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002826 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002827 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002828 sp = row;
2829 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002830 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002831 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2832 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2833 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05002834 if (r == trans_values->red && g == trans_values->green &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002835 b == trans_values->blue)
2836 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002837 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002838 *sp = (png_byte)((background->red >> 8) & 0xff);
2839 *(sp + 1) = (png_byte)(background->red & 0xff);
2840 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2841 *(sp + 3) = (png_byte)(background->green & 0xff);
2842 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2843 *(sp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002844 }
2845 else
2846 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002847 png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002848 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002849 *(sp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002850 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002851 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
2852 *(sp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002853 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002854 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
2855 *(sp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002856 }
2857 }
2858 }
2859 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002860#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002861 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002862 sp = row;
2863 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05002864 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002865 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
2866 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2867 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Guy Schalnat0d580581995-07-20 02:43:20 -05002868
Andreas Dilger47a0c421997-05-16 02:46:07 -05002869 if (r == trans_values->red && g == trans_values->green &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002870 b == trans_values->blue)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002871 {
2872 *sp = (png_byte)((background->red >> 8) & 0xff);
2873 *(sp + 1) = (png_byte)(background->red & 0xff);
2874 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2875 *(sp + 3) = (png_byte)(background->green & 0xff);
2876 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2877 *(sp + 5) = (png_byte)(background->blue & 0xff);
2878 }
2879 }
2880 }
2881 }
2882 break;
2883 }
2884 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -05002885 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002886 if (row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002887 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002888#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002889 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
2890 gamma_table != NULL)
2891 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002892 sp = row;
2893 dp = row;
2894 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002895 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002896 png_uint_16 a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002897
Andreas Dilger47a0c421997-05-16 02:46:07 -05002898 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002899 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002900 *dp = gamma_table[*sp];
2901 }
2902 else if (a == 0)
2903 {
2904 /* background is already in screen gamma */
2905 *dp = (png_byte)background->gray;
2906 }
2907 else
2908 {
2909 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05002910
Andreas Dilger47a0c421997-05-16 02:46:07 -05002911 v = gamma_to_1[*sp];
2912 png_composite(w, v, a, background_1->gray);
2913 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002914 }
2915 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002916 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002917 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002918#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002919 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002920 sp = row;
2921 dp = row;
2922 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002923 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002924 png_byte a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002925
Andreas Dilger47a0c421997-05-16 02:46:07 -05002926 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002927 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002928 *dp = *sp;
2929 }
2930 else if (a == 0)
2931 {
2932 *dp = (png_byte)background->gray;
2933 }
2934 else
2935 {
2936 png_composite(*dp, *sp, a, background_1->gray);
Guy Schalnat0d580581995-07-20 02:43:20 -05002937 }
2938 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002939 }
2940 }
2941 else /* if (png_ptr->bit_depth == 16) */
2942 {
2943#if defined(PNG_READ_GAMMA_SUPPORTED)
2944 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
2945 gamma_16_to_1 != NULL)
2946 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002947 sp = row;
2948 dp = row;
2949 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002950 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002951 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05002952
Andreas Dilger47a0c421997-05-16 02:46:07 -05002953 if (a == (png_uint_16)0xffff)
2954 {
2955 png_uint_16 v;
2956
2957 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
2958 *dp = (png_byte)((v >> 8) & 0xff);
2959 *(dp + 1) = (png_byte)(v & 0xff);
2960 }
2961 else if (a == 0)
2962 {
2963 /* background is already in screen gamma */
2964 *dp = (png_byte)((background->gray >> 8) & 0xff);
2965 *(dp + 1) = (png_byte)(background->gray & 0xff);
2966 }
2967 else
2968 {
2969 png_uint_16 g, v, w;
2970
2971 g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
2972 png_composite_16(v, g, a, background_1->gray);
2973 w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
2974 *dp = (png_byte)((w >> 8) & 0xff);
2975 *(dp + 1) = (png_byte)(w & 0xff);
2976 }
2977 }
2978 }
2979 else
2980#endif
2981 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002982 sp = row;
2983 dp = row;
2984 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002985 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002986 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05002987 if (a == (png_uint_16)0xffff)
2988 {
2989 png_memcpy(dp, sp, 2);
2990 }
2991 else if (a == 0)
2992 {
2993 *dp = (png_byte)((background->gray >> 8) & 0xff);
2994 *(dp + 1) = (png_byte)(background->gray & 0xff);
2995 }
2996 else
2997 {
2998 png_uint_16 g, v;
2999
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003000 g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003001 png_composite_16(v, g, a, background_1->gray);
3002 *dp = (png_byte)((v >> 8) & 0xff);
3003 *(dp + 1) = (png_byte)(v & 0xff);
3004 }
3005 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003006 }
3007 }
3008 break;
3009 }
3010 case PNG_COLOR_TYPE_RGB_ALPHA:
3011 {
3012 if (row_info->bit_depth == 8)
3013 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003014#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003015 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3016 gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003017 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003018 sp = row;
3019 dp = row;
3020 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003021 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003022 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003023
Guy Schalnat0d580581995-07-20 02:43:20 -05003024 if (a == 0xff)
3025 {
3026 *dp = gamma_table[*sp];
3027 *(dp + 1) = gamma_table[*(sp + 1)];
3028 *(dp + 2) = gamma_table[*(sp + 2)];
3029 }
3030 else if (a == 0)
3031 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003032 /* background is already in screen gamma */
3033 *dp = (png_byte)background->red;
3034 *(dp + 1) = (png_byte)background->green;
3035 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003036 }
3037 else
3038 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003039 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05003040
3041 v = gamma_to_1[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003042 png_composite(w, v, a, background_1->red);
3043 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003044 v = gamma_to_1[*(sp + 1)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003045 png_composite(w, v, a, background_1->green);
3046 *(dp + 1) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003047 v = gamma_to_1[*(sp + 2)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003048 png_composite(w, v, a, background_1->blue);
3049 *(dp + 2) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003050 }
3051 }
3052 }
3053 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003054#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003055 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003056 sp = row;
3057 dp = row;
3058 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003059 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003060 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003061
Guy Schalnat0d580581995-07-20 02:43:20 -05003062 if (a == 0xff)
3063 {
3064 *dp = *sp;
3065 *(dp + 1) = *(sp + 1);
3066 *(dp + 2) = *(sp + 2);
3067 }
3068 else if (a == 0)
3069 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003070 *dp = (png_byte)background->red;
3071 *(dp + 1) = (png_byte)background->green;
3072 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003073 }
3074 else
3075 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003076 png_composite(*dp, *sp, a, background->red);
3077 png_composite(*(dp + 1), *(sp + 1), a,
3078 background->green);
3079 png_composite(*(dp + 2), *(sp + 2), a,
3080 background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003081 }
3082 }
3083 }
3084 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003085 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003086 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003087#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003088 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3089 gamma_16_to_1 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003090 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003091 sp = row;
3092 dp = row;
3093 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003094 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003095 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3096 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003097 if (a == (png_uint_16)0xffff)
3098 {
3099 png_uint_16 v;
3100
Andreas Dilger47a0c421997-05-16 02:46:07 -05003101 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003102 *dp = (png_byte)((v >> 8) & 0xff);
3103 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003104 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003105 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3106 *(dp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003107 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003108 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3109 *(dp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003110 }
3111 else if (a == 0)
3112 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003113 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003114 *dp = (png_byte)((background->red >> 8) & 0xff);
3115 *(dp + 1) = (png_byte)(background->red & 0xff);
3116 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3117 *(dp + 3) = (png_byte)(background->green & 0xff);
3118 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3119 *(dp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003120 }
3121 else
3122 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003123 png_uint_16 v, w, x;
Guy Schalnat0d580581995-07-20 02:43:20 -05003124
Andreas Dilger47a0c421997-05-16 02:46:07 -05003125 v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3126 png_composite_16(w, v, a, background->red);
3127 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3128 *dp = (png_byte)((x >> 8) & 0xff);
3129 *(dp + 1) = (png_byte)(x & 0xff);
3130 v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
3131 png_composite_16(w, v, a, background->green);
3132 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3133 *(dp + 2) = (png_byte)((x >> 8) & 0xff);
3134 *(dp + 3) = (png_byte)(x & 0xff);
3135 v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
3136 png_composite_16(w, v, a, background->blue);
3137 x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
3138 *(dp + 4) = (png_byte)((x >> 8) & 0xff);
3139 *(dp + 5) = (png_byte)(x & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003140 }
3141 }
3142 }
3143 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003144#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003145 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003146 sp = row;
3147 dp = row;
3148 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003149 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003150 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3151 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003152 if (a == (png_uint_16)0xffff)
3153 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003154 png_memcpy(dp, sp, 6);
Guy Schalnat0d580581995-07-20 02:43:20 -05003155 }
3156 else if (a == 0)
3157 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003158 *dp = (png_byte)((background->red >> 8) & 0xff);
3159 *(dp + 1) = (png_byte)(background->red & 0xff);
3160 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3161 *(dp + 3) = (png_byte)(background->green & 0xff);
3162 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3163 *(dp + 5) = (png_byte)(background->blue & 0xff);
3164 }
3165 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003166 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003167 png_uint_16 v;
Guy Schalnat0d580581995-07-20 02:43:20 -05003168
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003169 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3170 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3171 + *(sp + 3));
3172 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3173 + *(sp + 5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003174
3175 png_composite_16(v, r, a, background->red);
Guy Schalnat0d580581995-07-20 02:43:20 -05003176 *dp = (png_byte)((v >> 8) & 0xff);
3177 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003178 png_composite_16(v, g, a, background->green);
Guy Schalnat0d580581995-07-20 02:43:20 -05003179 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3180 *(dp + 3) = (png_byte)(v & 0xff);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003181 png_composite_16(v, b, a, background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003182 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3183 *(dp + 5) = (png_byte)(v & 0xff);
3184 }
3185 }
3186 }
3187 }
3188 break;
3189 }
3190 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003191
Guy Schalnat0d580581995-07-20 02:43:20 -05003192 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
3193 {
3194 row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
Guy Schalnate5a37791996-06-05 15:50:50 -05003195 row_info->channels--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003196 row_info->pixel_depth = (png_byte)(row_info->channels *
3197 row_info->bit_depth);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003198 row_info->rowbytes = ((row_width *
Guy Schalnat0d580581995-07-20 02:43:20 -05003199 row_info->pixel_depth + 7) >> 3);
3200 }
3201 }
3202}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003203#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003204
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003205#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003206/* Gamma correct the image, avoiding the alpha channel. Make sure
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003207 * you do this after you deal with the transparency issue on grayscale
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003208 * or RGB images. If your bit depth is 8, use gamma_table, if it
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003209 * is 16, use gamma_16_table and gamma_shift. Build these with
3210 * build_gamma_table().
3211 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003212void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003213png_do_gamma(png_row_infop row_info, png_bytep row,
3214 png_bytep gamma_table, png_uint_16pp gamma_16_table,
Guy Schalnat0d580581995-07-20 02:43:20 -05003215 int gamma_shift)
3216{
Guy Schalnat6d764711995-12-19 03:22:19 -06003217 png_bytep sp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003218 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003219 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003220
Andreas Dilger47a0c421997-05-16 02:46:07 -05003221 png_debug(1, "in png_do_gamma\n");
3222 if (
3223#if defined(PNG_USELESS_TESTS_SUPPORTED)
3224 row != NULL && row_info != NULL &&
3225#endif
3226 ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
3227 (row_info->bit_depth == 16 && gamma_16_table != NULL)))
Guy Schalnat0d580581995-07-20 02:43:20 -05003228 {
3229 switch (row_info->color_type)
3230 {
3231 case PNG_COLOR_TYPE_RGB:
3232 {
3233 if (row_info->bit_depth == 8)
3234 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003235 sp = row;
3236 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003237 {
3238 *sp = gamma_table[*sp];
3239 sp++;
3240 *sp = gamma_table[*sp];
3241 sp++;
3242 *sp = gamma_table[*sp];
3243 sp++;
3244 }
3245 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003246 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003247 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003248 sp = row;
3249 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003250 {
3251 png_uint_16 v;
3252
Andreas Dilger47a0c421997-05-16 02:46:07 -05003253 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003254 *sp = (png_byte)((v >> 8) & 0xff);
3255 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003256 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003257 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003258 *sp = (png_byte)((v >> 8) & 0xff);
3259 *(sp + 1) = (png_byte)(v & 0xff);
3260 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003261 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003262 *sp = (png_byte)((v >> 8) & 0xff);
3263 *(sp + 1) = (png_byte)(v & 0xff);
3264 sp += 2;
3265 }
3266 }
3267 break;
3268 }
3269 case PNG_COLOR_TYPE_RGB_ALPHA:
3270 {
3271 if (row_info->bit_depth == 8)
3272 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003273 sp = row;
3274 for (i = 0; i < row_width; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003275 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003276 *sp = gamma_table[*sp];
3277 sp++;
3278 *sp = gamma_table[*sp];
3279 sp++;
3280 *sp = gamma_table[*sp];
3281 sp++;
3282 sp++;
3283 }
3284 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003285 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003286 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003287 sp = row;
3288 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003289 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003290 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003291 *sp = (png_byte)((v >> 8) & 0xff);
3292 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003293 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003294 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003295 *sp = (png_byte)((v >> 8) & 0xff);
3296 *(sp + 1) = (png_byte)(v & 0xff);
3297 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003298 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003299 *sp = (png_byte)((v >> 8) & 0xff);
3300 *(sp + 1) = (png_byte)(v & 0xff);
3301 sp += 4;
3302 }
3303 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003304 break;
3305 }
3306 case PNG_COLOR_TYPE_GRAY_ALPHA:
3307 {
3308 if (row_info->bit_depth == 8)
3309 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003310 sp = row;
3311 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003312 {
3313 *sp = gamma_table[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003314 sp += 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05003315 }
3316 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003317 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003318 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003319 sp = row;
3320 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003321 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003322 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003323 *sp = (png_byte)((v >> 8) & 0xff);
3324 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003325 sp += 4;
3326 }
3327 }
3328 break;
3329 }
3330 case PNG_COLOR_TYPE_GRAY:
3331 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003332 if (row_info->bit_depth == 2)
3333 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003334 sp = row;
3335 for (i = 0; i < row_width; i += 4)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003336 {
3337 int a = *sp & 0xc0;
3338 int b = *sp & 0x30;
3339 int c = *sp & 0x0c;
3340 int d = *sp & 0x03;
3341
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003342 *sp = (png_byte)(
3343 ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003344 ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
3345 ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003346 ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003347 sp++;
3348 }
3349 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003350 if (row_info->bit_depth == 4)
Guy Schalnat0d580581995-07-20 02:43:20 -05003351 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003352 sp = row;
3353 for (i = 0; i < row_width; i += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003354 {
3355 int msb = *sp & 0xf0;
3356 int lsb = *sp & 0x0f;
3357
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003358 *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
3359 | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003360 sp++;
3361 }
3362 }
3363 else if (row_info->bit_depth == 8)
3364 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003365 sp = row;
3366 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003367 {
3368 *sp = gamma_table[*sp];
3369 sp++;
3370 }
3371 }
3372 else if (row_info->bit_depth == 16)
3373 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003374 sp = row;
3375 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003376 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003377 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003378 *sp = (png_byte)((v >> 8) & 0xff);
3379 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003380 sp += 2;
3381 }
3382 }
3383 break;
3384 }
3385 }
3386 }
3387}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003388#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003389
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003390#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003391/* Expands a palette row to an RGB or RGBA row depending
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003392 * upon whether you supply trans and num_trans.
3393 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003394void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003395png_do_expand_palette(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05003396 png_colorp palette, png_bytep trans, int num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003397{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003398 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003399 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003400 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003401 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003402
Andreas Dilger47a0c421997-05-16 02:46:07 -05003403 png_debug(1, "in png_do_expand_palette\n");
3404 if (
3405#if defined(PNG_USELESS_TESTS_SUPPORTED)
3406 row != NULL && row_info != NULL &&
3407#endif
3408 row_info->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05003409 {
3410 if (row_info->bit_depth < 8)
3411 {
3412 switch (row_info->bit_depth)
3413 {
3414 case 1:
3415 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003416 sp = row + (png_size_t)((row_width - 1) >> 3);
3417 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003418 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003419 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003420 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003421 if ((*sp >> shift) & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -05003422 *dp = 1;
3423 else
3424 *dp = 0;
3425 if (shift == 7)
3426 {
3427 shift = 0;
3428 sp--;
3429 }
3430 else
3431 shift++;
3432
3433 dp--;
3434 }
3435 break;
3436 }
3437 case 2:
3438 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003439 sp = row + (png_size_t)((row_width - 1) >> 2);
3440 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003441 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003442 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003443 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003444 value = (*sp >> shift) & 0x03;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003445 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003446 if (shift == 6)
3447 {
3448 shift = 0;
3449 sp--;
3450 }
3451 else
3452 shift += 2;
3453
3454 dp--;
3455 }
3456 break;
3457 }
3458 case 4:
3459 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003460 sp = row + (png_size_t)((row_width - 1) >> 1);
3461 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003462 shift = (int)((row_width & 0x01) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003463 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003464 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003465 value = (*sp >> shift) & 0x0f;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003466 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003467 if (shift == 4)
3468 {
3469 shift = 0;
3470 sp--;
3471 }
3472 else
3473 shift += 4;
3474
3475 dp--;
3476 }
3477 break;
3478 }
3479 }
3480 row_info->bit_depth = 8;
3481 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003482 row_info->rowbytes = row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003483 }
3484 switch (row_info->bit_depth)
3485 {
3486 case 8:
3487 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003488 if (trans != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003489 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003490 sp = row + (png_size_t)row_width - 1;
3491 dp = row + (png_size_t)(row_width << 2) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003492
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003493 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003494 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003495 if ((int)(*sp) >= num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003496 *dp-- = 0xff;
3497 else
3498 *dp-- = trans[*sp];
3499 *dp-- = palette[*sp].blue;
3500 *dp-- = palette[*sp].green;
3501 *dp-- = palette[*sp].red;
3502 sp--;
3503 }
3504 row_info->bit_depth = 8;
3505 row_info->pixel_depth = 32;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003506 row_info->rowbytes = row_width * 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05003507 row_info->color_type = 6;
3508 row_info->channels = 4;
3509 }
3510 else
3511 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003512 sp = row + (png_size_t)row_width - 1;
3513 dp = row + (png_size_t)(row_width * 3) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003514
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003515 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003516 {
3517 *dp-- = palette[*sp].blue;
3518 *dp-- = palette[*sp].green;
3519 *dp-- = palette[*sp].red;
3520 sp--;
3521 }
3522 row_info->bit_depth = 8;
3523 row_info->pixel_depth = 24;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003524 row_info->rowbytes = row_width * 3;
Guy Schalnat0d580581995-07-20 02:43:20 -05003525 row_info->color_type = 2;
3526 row_info->channels = 3;
3527 }
3528 break;
3529 }
3530 }
3531 }
3532}
3533
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003534/* If the bit depth < 8, it is expanded to 8. Also, if the
3535 * transparency value is supplied, an alpha channel is built.
3536 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003537void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003538png_do_expand(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003539 png_color_16p trans_value)
Guy Schalnat0d580581995-07-20 02:43:20 -05003540{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003541 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003542 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003543 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003544 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003545
Andreas Dilger47a0c421997-05-16 02:46:07 -05003546 png_debug(1, "in png_do_expand\n");
3547#if defined(PNG_USELESS_TESTS_SUPPORTED)
3548 if (row != NULL && row_info != NULL)
3549#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003550 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003551 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05003552 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003553 png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003554
3555 if (row_info->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003556 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003557 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05003558 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003559 case 1:
3560 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003561 gray = (png_uint_16)(gray*0xff);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003562 sp = row + (png_size_t)((row_width - 1) >> 3);
3563 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003564 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003565 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003566 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003567 if ((*sp >> shift) & 0x01)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003568 *dp = 0xff;
3569 else
3570 *dp = 0;
3571 if (shift == 7)
3572 {
3573 shift = 0;
3574 sp--;
3575 }
3576 else
3577 shift++;
3578
3579 dp--;
3580 }
3581 break;
3582 }
3583 case 2:
3584 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003585 gray = (png_uint_16)(gray*0x55);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003586 sp = row + (png_size_t)((row_width - 1) >> 2);
3587 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003588 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003589 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003590 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003591 value = (*sp >> shift) & 0x03;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003592 *dp = (png_byte)(value | (value << 2) | (value << 4) |
3593 (value << 6));
3594 if (shift == 6)
3595 {
3596 shift = 0;
3597 sp--;
3598 }
3599 else
3600 shift += 2;
3601
3602 dp--;
3603 }
3604 break;
3605 }
3606 case 4:
3607 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003608 gray = (png_uint_16)(gray*0x11);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003609 sp = row + (png_size_t)((row_width - 1) >> 1);
3610 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003611 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003612 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003613 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003614 value = (*sp >> shift) & 0x0f;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003615 *dp = (png_byte)(value | (value << 4));
3616 if (shift == 4)
3617 {
3618 shift = 0;
3619 sp--;
3620 }
3621 else
3622 shift = 4;
3623
3624 dp--;
3625 }
3626 break;
3627 }
3628 }
3629 row_info->bit_depth = 8;
3630 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003631 row_info->rowbytes = row_width;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003632 }
3633
Andreas Dilger47a0c421997-05-16 02:46:07 -05003634 if (trans_value != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003635 {
3636 if (row_info->bit_depth == 8)
3637 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003638 sp = row + (png_size_t)row_width - 1;
3639 dp = row + (png_size_t)(row_width << 1) - 1;
3640 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003641 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003642 if (*sp == gray)
3643 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003644 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003645 *dp-- = 0xff;
3646 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003647 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003648 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003649 else if (row_info->bit_depth == 16)
Guy Schalnat0d580581995-07-20 02:43:20 -05003650 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003651 sp = row + row_info->rowbytes - 1;
3652 dp = row + (row_info->rowbytes << 1) - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003653 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003654 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003655 if (((png_uint_16)*(sp) |
3656 ((png_uint_16)*(sp - 1) << 8)) == gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05003657 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003658 *dp-- = 0;
3659 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003660 }
3661 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003662 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003663 *dp-- = 0xff;
3664 *dp-- = 0xff;
Guy Schalnat0d580581995-07-20 02:43:20 -05003665 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003666 *dp-- = *sp--;
3667 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003668 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003669 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003670 row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
3671 row_info->channels = 2;
3672 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
3673 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003674 ((row_width * row_info->pixel_depth) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003675 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003676 }
3677 else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
3678 {
3679 if (row_info->bit_depth == 8)
3680 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003681 sp = row + (png_size_t)row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003682 dp = row + (png_size_t)(row_width << 2) - 1;
3683 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003684 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003685 if (*(sp - 2) == trans_value->red &&
Guy Schalnat0d580581995-07-20 02:43:20 -05003686 *(sp - 1) == trans_value->green &&
3687 *(sp - 0) == trans_value->blue)
3688 *dp-- = 0;
3689 else
3690 *dp-- = 0xff;
3691 *dp-- = *sp--;
3692 *dp-- = *sp--;
3693 *dp-- = *sp--;
3694 }
3695 }
3696 else if (row_info->bit_depth == 16)
3697 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003698 sp = row + row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003699 dp = row + (png_size_t)(row_width << 3) - 1;
3700 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003701 {
3702 if ((((png_uint_16)*(sp - 4) |
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003703 ((png_uint_16)*(sp - 5) << 8)) == trans_value->red) &&
Guy Schalnat0d580581995-07-20 02:43:20 -05003704 (((png_uint_16)*(sp - 2) |
3705 ((png_uint_16)*(sp - 3) << 8)) == trans_value->green) &&
3706 (((png_uint_16)*(sp - 0) |
3707 ((png_uint_16)*(sp - 1) << 8)) == trans_value->blue))
3708 {
3709 *dp-- = 0;
3710 *dp-- = 0;
3711 }
3712 else
3713 {
3714 *dp-- = 0xff;
3715 *dp-- = 0xff;
3716 }
3717 *dp-- = *sp--;
3718 *dp-- = *sp--;
3719 *dp-- = *sp--;
3720 *dp-- = *sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003721 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003722 *dp-- = *sp--;
3723 }
3724 }
3725 row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
3726 row_info->channels = 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003727 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
Guy Schalnat0d580581995-07-20 02:43:20 -05003728 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003729 ((row_width * row_info->pixel_depth) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003730 }
3731 }
3732}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003733#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003734
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003735#if defined(PNG_READ_DITHER_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003736void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003737png_do_dither(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003738 png_bytep palette_lookup, png_bytep dither_lookup)
Guy Schalnat0d580581995-07-20 02:43:20 -05003739{
Guy Schalnat6d764711995-12-19 03:22:19 -06003740 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003741 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003742 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003743
Andreas Dilger47a0c421997-05-16 02:46:07 -05003744 png_debug(1, "in png_do_dither\n");
3745#if defined(PNG_USELESS_TESTS_SUPPORTED)
3746 if (row != NULL && row_info != NULL)
3747#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003748 {
3749 if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
3750 palette_lookup && row_info->bit_depth == 8)
3751 {
3752 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003753 sp = row;
3754 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003755 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003756 {
3757 r = *sp++;
3758 g = *sp++;
3759 b = *sp++;
3760
3761 /* this looks real messy, but the compiler will reduce
3762 it down to a reasonable formula. For example, with
3763 5 bits per color, we get:
3764 p = (((r >> 3) & 0x1f) << 10) |
3765 (((g >> 3) & 0x1f) << 5) |
3766 ((b >> 3) & 0x1f);
3767 */
3768 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
3769 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
3770 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3771 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003772 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003773 (PNG_DITHER_BLUE_BITS)) |
3774 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3775 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3776
3777 *dp++ = palette_lookup[p];
3778 }
3779 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3780 row_info->channels = 1;
3781 row_info->pixel_depth = row_info->bit_depth;
3782 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003783 ((row_width * row_info->pixel_depth + 7) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003784 }
3785 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
Andreas Dilger47a0c421997-05-16 02:46:07 -05003786 palette_lookup != NULL && row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003787 {
3788 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003789 sp = row;
3790 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003791 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003792 {
3793 r = *sp++;
3794 g = *sp++;
3795 b = *sp++;
3796 sp++;
3797
3798 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003799 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003800 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3801 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
3802 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
3803 (PNG_DITHER_BLUE_BITS)) |
3804 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3805 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3806
3807 *dp++ = palette_lookup[p];
3808 }
3809 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3810 row_info->channels = 1;
3811 row_info->pixel_depth = row_info->bit_depth;
3812 row_info->rowbytes =
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003813 ((row_width * row_info->pixel_depth + 7) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003814 }
3815 else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
3816 dither_lookup && row_info->bit_depth == 8)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003817 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003818 sp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003819 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003820 {
3821 *sp = dither_lookup[*sp];
3822 }
3823 }
3824 }
3825}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003826#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003827
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003828#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003829#if defined(PNG_READ_GAMMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05003830static int png_gamma_shift[] =
3831 {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0};
3832
Andreas Dilger47a0c421997-05-16 02:46:07 -05003833/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003834 * tables, we don't make a full table if we are reducing to 8-bit in
3835 * the future. Note also how the gamma_16 tables are segmented so that
3836 * we don't need to allocate > 64K chunks for a full 16-bit table.
3837 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003838void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003839png_build_gamma_table(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003840{
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003841 png_debug(1, "in png_build_gamma_table\n");
3842 if(png_ptr->gamma != 0.0)
3843 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003844 if (png_ptr->bit_depth <= 8)
3845 {
3846 int i;
3847 double g;
3848
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003849 if (png_ptr->screen_gamma > .000001)
3850 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
3851 else
3852 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003853
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003854 png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -05003855 (png_uint_32)256);
3856
3857 for (i = 0; i < 256; i++)
3858 {
3859 png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
3860 g) * 255.0 + .5);
3861 }
3862
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003863#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
3864 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003865 if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05003866 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003867
Guy Schalnat0d580581995-07-20 02:43:20 -05003868 g = 1.0 / (png_ptr->gamma);
3869
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003870 png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -05003871 (png_uint_32)256);
3872
3873 for (i = 0; i < 256; i++)
3874 {
3875 png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
3876 g) * 255.0 + .5);
3877 }
3878
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003879
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003880 png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -05003881 (png_uint_32)256);
3882
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003883 if(png_ptr->screen_gamma > 0.000001)
3884 g = 1.0 / png_ptr->screen_gamma;
3885 else
3886 g = png_ptr->gamma; /* probably doing rgb_to_gray */
3887
Guy Schalnat0d580581995-07-20 02:43:20 -05003888 for (i = 0; i < 256; i++)
3889 {
3890 png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
3891 g) * 255.0 + .5);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003892
Guy Schalnat0d580581995-07-20 02:43:20 -05003893 }
3894 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003895#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003896 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003897 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003898 {
3899 double g;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003900 int i, j, shift, num;
3901 int sig_bit;
3902 png_uint_32 ig;
Guy Schalnat0d580581995-07-20 02:43:20 -05003903
3904 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003905 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003906 sig_bit = (int)png_ptr->sig_bit.red;
3907 if ((int)png_ptr->sig_bit.green > sig_bit)
3908 sig_bit = png_ptr->sig_bit.green;
3909 if ((int)png_ptr->sig_bit.blue > sig_bit)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003910 sig_bit = png_ptr->sig_bit.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003911 }
3912 else
3913 {
3914 sig_bit = (int)png_ptr->sig_bit.gray;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003915 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003916
3917 if (sig_bit > 0)
3918 shift = 16 - sig_bit;
3919 else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003920 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003921
3922 if (png_ptr->transformations & PNG_16_TO_8)
3923 {
3924 if (shift < (16 - PNG_MAX_GAMMA_8))
3925 shift = (16 - PNG_MAX_GAMMA_8);
3926 }
3927
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003928 if (shift > 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003929 shift = 8;
3930 if (shift < 0)
3931 shift = 0;
3932
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003933 png_ptr->gamma_shift = (png_byte)shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05003934
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003935 num = (1 << (8 - shift));
Guy Schalnat0d580581995-07-20 02:43:20 -05003936
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003937 if (png_ptr->screen_gamma > .000001)
3938 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
3939 else
3940 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003941
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003942 png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06003943 (png_uint_32)(num * sizeof (png_uint_16p)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003944
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003945 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003946 {
3947 double fin, fout;
3948 png_uint_32 last, max;
Guy Schalnat0d580581995-07-20 02:43:20 -05003949
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003950 for (i = 0; i < num; i++)
3951 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003952 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06003953 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003954 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003955
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003956 g = 1.0 / g;
3957 last = 0;
3958 for (i = 0; i < 256; i++)
3959 {
3960 fout = ((double)i + 0.5) / 256.0;
3961 fin = pow(fout, g);
3962 max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
3963 while (last <= max)
3964 {
3965 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
3966 [(int)(last >> (8 - shift))] = (png_uint_16)(
3967 (png_uint_16)i | ((png_uint_16)i << 8));
3968 last++;
3969 }
3970 }
3971 while (last < ((png_uint_32)num << 8))
3972 {
3973 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
Andreas Dilger47a0c421997-05-16 02:46:07 -05003974 [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003975 last++;
Guy Schalnat6d764711995-12-19 03:22:19 -06003976 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003977 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003978 else
3979 {
3980 for (i = 0; i < num; i++)
3981 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003982 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06003983 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003984
Andreas Dilger47a0c421997-05-16 02:46:07 -05003985 ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003986 for (j = 0; j < 256; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003987 {
3988 png_ptr->gamma_16_table[i][j] =
3989 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
3990 65535.0, g) * 65535.0 + .5);
3991 }
3992 }
3993 }
3994
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003995#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
3996 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
3997 if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05003998 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003999
Guy Schalnat0d580581995-07-20 02:43:20 -05004000 g = 1.0 / (png_ptr->gamma);
4001
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004002 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004003 (png_uint_32)(num * sizeof (png_uint_16p )));
Guy Schalnat0d580581995-07-20 02:43:20 -05004004
4005 for (i = 0; i < num; i++)
4006 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004007 png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004008 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004009
4010 ig = (((png_uint_32)i *
4011 (png_uint_32)png_gamma_shift[shift]) >> 4);
4012 for (j = 0; j < 256; j++)
4013 {
4014 png_ptr->gamma_16_to_1[i][j] =
4015 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4016 65535.0, g) * 65535.0 + .5);
4017 }
4018 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004019
4020 if(png_ptr->screen_gamma > 0.000001)
4021 g = 1.0 / png_ptr->screen_gamma;
4022 else
4023 g = png_ptr->gamma; /* probably doing rgb_to_gray */
Guy Schalnat0d580581995-07-20 02:43:20 -05004024
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004025 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004026 (png_uint_32)(num * sizeof (png_uint_16p)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004027
4028 for (i = 0; i < num; i++)
4029 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004030 png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06004031 (png_uint_32)(256 * sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004032
4033 ig = (((png_uint_32)i *
4034 (png_uint_32)png_gamma_shift[shift]) >> 4);
4035 for (j = 0; j < 256; j++)
4036 {
4037 png_ptr->gamma_16_from_1[i][j] =
4038 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4039 65535.0, g) * 65535.0 + .5);
4040 }
4041 }
4042 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004043#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05004044 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004045 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004046}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004047#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06004048/* To do: install integer version of png_build_gamma_table here */
4049#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004050