blob: c17c0dfc494c7a596b2762d079f3ee47394ed601 [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-Pehrson9c3ab682006-02-20 22:09:05 -06004 * libpng version 1.2.9beta1 - February 21, 2006
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06006 * Copyright (c) 1998-2006 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-Pehrson9c3ab682006-02-20 22:09:05 -060019#if defined(PNG_READ_SUPPORTED)
20
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060021/* Set the action on getting a CRC error for an ancillary or critical chunk. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050022void PNGAPI
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060023png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
24{
25 png_debug(1, "in png_set_crc_action\n");
26 /* Tell libpng how we react to CRC errors in critical chunks */
27 switch (crit_action)
28 {
29 case PNG_CRC_NO_CHANGE: /* leave setting as is */
30 break;
31 case PNG_CRC_WARN_USE: /* warn/use data */
32 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
33 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
34 break;
35 case PNG_CRC_QUIET_USE: /* quiet/use data */
36 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
37 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
38 PNG_FLAG_CRC_CRITICAL_IGNORE;
39 break;
40 case PNG_CRC_WARN_DISCARD: /* not a valid action for critical data */
41 png_warning(png_ptr, "Can't discard critical data on CRC error.");
42 case PNG_CRC_ERROR_QUIT: /* error/quit */
43 case PNG_CRC_DEFAULT:
44 default:
45 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
46 break;
47 }
48
49 switch (ancil_action)
50 {
51 case PNG_CRC_NO_CHANGE: /* leave setting as is */
52 break;
53 case PNG_CRC_WARN_USE: /* warn/use data */
54 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
55 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
56 break;
57 case PNG_CRC_QUIET_USE: /* quiet/use data */
58 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
59 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
60 PNG_FLAG_CRC_ANCILLARY_NOWARN;
61 break;
62 case PNG_CRC_ERROR_QUIT: /* error/quit */
63 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
64 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
65 break;
66 case PNG_CRC_WARN_DISCARD: /* warn/discard data */
67 case PNG_CRC_DEFAULT:
68 default:
69 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
70 break;
71 }
72}
73
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060074#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
75 defined(PNG_FLOATING_POINT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050076/* handle alpha and tRNS via a background color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050077void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060078png_set_background(png_structp png_ptr,
79 png_color_16p background_color, int background_gamma_code,
Guy Schalnat51f0eb41995-09-26 05:22:39 -050080 int need_expand, double background_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -050081{
Andreas Dilger47a0c421997-05-16 02:46:07 -050082 png_debug(1, "in png_set_background\n");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060083 if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
84 {
85 png_warning(png_ptr, "Application must supply a known background gamma");
86 return;
87 }
88
Guy Schalnat0d580581995-07-20 02:43:20 -050089 png_ptr->transformations |= PNG_BACKGROUND;
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050090 png_memcpy(&(png_ptr->background), background_color,
91 png_sizeof(png_color_16));
Guy Schalnat51f0eb41995-09-26 05:22:39 -050092 png_ptr->background_gamma = (float)background_gamma;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060093 png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
Guy Schalnate5a37791996-06-05 15:50:50 -050094 png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050095
96 /* Note: if need_expand is set and color_type is either RGB or RGB_ALPHA
97 * (in which case need_expand is superfluous anyway), the background color
98 * might actually be gray yet not be flagged as such. This is not a problem
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -060099 * for the current code, which uses PNG_BACKGROUND_IS_GRAY only to
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500100 * decide when to do the png_do_gray_to_rgb() transformation.
101 */
102 if ((need_expand && !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) ||
103 (!need_expand && background_color->red == background_color->green &&
104 background_color->red == background_color->blue))
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600105 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
Guy Schalnat0d580581995-07-20 02:43:20 -0500106}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500107#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500108
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500109#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500110/* strip 16 bit depth files to 8 bit depth */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500111void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600112png_set_strip_16(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500113{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500114 png_debug(1, "in png_set_strip_16\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500115 png_ptr->transformations |= PNG_16_TO_8;
116}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500117#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500118
Andreas Dilger47a0c421997-05-16 02:46:07 -0500119#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500120void PNGAPI
Andreas Dilger47a0c421997-05-16 02:46:07 -0500121png_set_strip_alpha(png_structp png_ptr)
122{
123 png_debug(1, "in png_set_strip_alpha\n");
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -0600124 png_ptr->flags |= PNG_FLAG_STRIP_ALPHA;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500125}
126#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500127
Andreas Dilger47a0c421997-05-16 02:46:07 -0500128#if defined(PNG_READ_DITHER_SUPPORTED)
129/* Dither file to 8 bit. Supply a palette, the current number
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600130 * of elements in the palette, the maximum number of elements
131 * allowed, and a histogram if possible. If the current number
132 * of colors is greater then the maximum number, the palette will be
133 * modified to fit in the maximum number. "full_dither" indicates
134 * whether we need a dithering cube set up for RGB images, or if we
135 * simply are reducing the number of colors in a paletted image.
136 */
Guy Schalnat6d764711995-12-19 03:22:19 -0600137
138typedef struct png_dsort_struct
Guy Schalnat0d580581995-07-20 02:43:20 -0500139{
Guy Schalnat6d764711995-12-19 03:22:19 -0600140 struct png_dsort_struct FAR * next;
Guy Schalnat0d580581995-07-20 02:43:20 -0500141 png_byte left;
142 png_byte right;
Guy Schalnat6d764711995-12-19 03:22:19 -0600143} png_dsort;
144typedef png_dsort FAR * png_dsortp;
145typedef png_dsort FAR * FAR * png_dsortpp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500146
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500147void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600148png_set_dither(png_structp png_ptr, png_colorp palette,
149 int num_palette, int maximum_colors, png_uint_16p histogram,
Guy Schalnat0d580581995-07-20 02:43:20 -0500150 int full_dither)
151{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500152 png_debug(1, "in png_set_dither\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500153 png_ptr->transformations |= PNG_DITHER;
154
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600155 if (!full_dither)
Guy Schalnat0d580581995-07-20 02:43:20 -0500156 {
157 int i;
158
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600159 png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500160 (png_uint_32)(num_palette * png_sizeof (png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500161 for (i = 0; i < num_palette; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600162 png_ptr->dither_index[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500163 }
164
165 if (num_palette > maximum_colors)
166 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500167 if (histogram != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500168 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500169 /* This is easy enough, just throw out the least used colors.
170 Perhaps not the best solution, but good enough. */
Guy Schalnat0d580581995-07-20 02:43:20 -0500171
172 int i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500173
174 /* initialize an array to sort colors */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500175 png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500176 (png_uint_32)(num_palette * png_sizeof (png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500177
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500178 /* initialize the dither_sort array */
Guy Schalnat0d580581995-07-20 02:43:20 -0500179 for (i = 0; i < num_palette; i++)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500180 png_ptr->dither_sort[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500181
Andreas Dilger47a0c421997-05-16 02:46:07 -0500182 /* Find the least used palette entries by starting a
Guy Schalnat0d580581995-07-20 02:43:20 -0500183 bubble sort, and running it until we have sorted
184 out enough colors. Note that we don't care about
185 sorting all the colors, just finding which are
186 least used. */
187
188 for (i = num_palette - 1; i >= maximum_colors; i--)
189 {
190 int done; /* to stop early if the list is pre-sorted */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600191 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500192
193 done = 1;
194 for (j = 0; j < i; j++)
195 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500196 if (histogram[png_ptr->dither_sort[j]]
197 < histogram[png_ptr->dither_sort[j + 1]])
Guy Schalnat0d580581995-07-20 02:43:20 -0500198 {
199 png_byte t;
200
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500201 t = png_ptr->dither_sort[j];
202 png_ptr->dither_sort[j] = png_ptr->dither_sort[j + 1];
203 png_ptr->dither_sort[j + 1] = t;
Guy Schalnat0d580581995-07-20 02:43:20 -0500204 done = 0;
205 }
206 }
207 if (done)
208 break;
209 }
210
211 /* swap the palette around, and set up a table, if necessary */
212 if (full_dither)
213 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500214 int j = num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500215
216 /* put all the useful colors within the max, but don't
217 move the others */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500218 for (i = 0; i < maximum_colors; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500219 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500220 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500221 {
222 do
223 j--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500224 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
Guy Schalnat0d580581995-07-20 02:43:20 -0500225 palette[i] = palette[j];
226 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600227 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500228 }
229 else
230 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500231 int j = num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500232
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600233 /* move all the used colors inside the max limit, and
Guy Schalnat0d580581995-07-20 02:43:20 -0500234 develop a translation table */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500235 for (i = 0; i < maximum_colors; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500236 {
237 /* only move the colors we need to */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500238 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500239 {
240 png_color tmp_color;
241
242 do
243 j--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500244 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
Guy Schalnat0d580581995-07-20 02:43:20 -0500245
246 tmp_color = palette[j];
247 palette[j] = palette[i];
248 palette[i] = tmp_color;
249 /* indicate where the color went */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600250 png_ptr->dither_index[j] = (png_byte)i;
251 png_ptr->dither_index[i] = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500252 }
253 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500254
255 /* find closest color for those colors we are not using */
Guy Schalnat0d580581995-07-20 02:43:20 -0500256 for (i = 0; i < num_palette; i++)
257 {
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600258 if ((int)png_ptr->dither_index[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500259 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500260 int min_d, k, min_k, d_index;
Guy Schalnat0d580581995-07-20 02:43:20 -0500261
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600262 /* find the closest color to one we threw out */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500263 d_index = png_ptr->dither_index[i];
264 min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
265 for (k = 1, min_k = 0; k < maximum_colors; k++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500266 {
267 int d;
268
Andreas Dilger47a0c421997-05-16 02:46:07 -0500269 d = PNG_COLOR_DIST(palette[d_index], palette[k]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500270
271 if (d < min_d)
272 {
273 min_d = d;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500274 min_k = k;
Guy Schalnat0d580581995-07-20 02:43:20 -0500275 }
276 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600277 /* point to closest color */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500278 png_ptr->dither_index[i] = (png_byte)min_k;
Guy Schalnat0d580581995-07-20 02:43:20 -0500279 }
280 }
281 }
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500282 png_free(png_ptr, png_ptr->dither_sort);
283 png_ptr->dither_sort=NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500284 }
285 else
286 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500287 /* This is much harder to do simply (and quickly). Perhaps
Guy Schalnat0d580581995-07-20 02:43:20 -0500288 we need to go through a median cut routine, but those
289 don't always behave themselves with only a few colors
290 as input. So we will just find the closest two colors,
291 and throw out one of them (chosen somewhat randomly).
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600292 [We don't understand this at all, so if someone wants to
293 work on improving it, be our guest - AED, GRP]
Guy Schalnat0d580581995-07-20 02:43:20 -0500294 */
295 int i;
296 int max_d;
297 int num_new_palette;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500298 png_dsortp t;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600299 png_dsortpp hash;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500300
301 t=NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500302
303 /* initialize palette index arrays */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500304 png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500305 (png_uint_32)(num_palette * png_sizeof (png_byte)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500306 png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500307 (png_uint_32)(num_palette * png_sizeof (png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500308
309 /* initialize the sort array */
310 for (i = 0; i < num_palette; i++)
311 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500312 png_ptr->index_to_palette[i] = (png_byte)i;
313 png_ptr->palette_to_index[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500314 }
315
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600316 hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 *
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500317 png_sizeof (png_dsortp)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500318 for (i = 0; i < 769; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500319 hash[i] = NULL;
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500320/* png_memset(hash, 0, 769 * png_sizeof (png_dsortp)); */
Guy Schalnat0d580581995-07-20 02:43:20 -0500321
322 num_new_palette = num_palette;
323
324 /* initial wild guess at how far apart the farthest pixel
325 pair we will be eliminating will be. Larger
326 numbers mean more areas will be allocated, Smaller
327 numbers run the risk of not saving enough data, and
328 having to do this all over again.
329
330 I have not done extensive checking on this number.
331 */
332 max_d = 96;
333
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600334 while (num_new_palette > maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500335 {
336 for (i = 0; i < num_new_palette - 1; i++)
337 {
338 int j;
339
340 for (j = i + 1; j < num_new_palette; j++)
341 {
342 int d;
343
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600344 d = PNG_COLOR_DIST(palette[i], palette[j]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500345
346 if (d <= max_d)
347 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500348
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500349 t = (png_dsortp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500350 (png_uint_32)(png_sizeof(png_dsort)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500351 if (t == NULL)
352 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500353 t->next = hash[d];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600354 t->left = (png_byte)i;
355 t->right = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500356 hash[d] = t;
357 }
358 }
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500359 if (t == NULL)
360 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500361 }
362
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500363 if (t != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500364 for (i = 0; i <= max_d; i++)
365 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500366 if (hash[i] != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500367 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600368 png_dsortp p;
Guy Schalnat0d580581995-07-20 02:43:20 -0500369
370 for (p = hash[i]; p; p = p->next)
371 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500372 if ((int)png_ptr->index_to_palette[p->left]
373 < num_new_palette &&
374 (int)png_ptr->index_to_palette[p->right]
375 < num_new_palette)
Guy Schalnat0d580581995-07-20 02:43:20 -0500376 {
377 int j, next_j;
378
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600379 if (num_new_palette & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -0500380 {
381 j = p->left;
382 next_j = p->right;
383 }
384 else
385 {
386 j = p->right;
387 next_j = p->left;
388 }
389
390 num_new_palette--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500391 palette[png_ptr->index_to_palette[j]]
392 = palette[num_new_palette];
Guy Schalnat0d580581995-07-20 02:43:20 -0500393 if (!full_dither)
394 {
395 int k;
396
397 for (k = 0; k < num_palette; k++)
398 {
399 if (png_ptr->dither_index[k] ==
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500400 png_ptr->index_to_palette[j])
Guy Schalnat0d580581995-07-20 02:43:20 -0500401 png_ptr->dither_index[k] =
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500402 png_ptr->index_to_palette[next_j];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600403 if ((int)png_ptr->dither_index[k] ==
Guy Schalnat0d580581995-07-20 02:43:20 -0500404 num_new_palette)
405 png_ptr->dither_index[k] =
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500406 png_ptr->index_to_palette[j];
Guy Schalnat0d580581995-07-20 02:43:20 -0500407 }
408 }
409
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500410 png_ptr->index_to_palette[png_ptr->palette_to_index
411 [num_new_palette]] = png_ptr->index_to_palette[j];
412 png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
413 = png_ptr->palette_to_index[num_new_palette];
Guy Schalnat0d580581995-07-20 02:43:20 -0500414
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500415 png_ptr->index_to_palette[j] = (png_byte)num_new_palette;
416 png_ptr->palette_to_index[num_new_palette] = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500417 }
418 if (num_new_palette <= maximum_colors)
419 break;
420 }
421 if (num_new_palette <= maximum_colors)
422 break;
423 }
424 }
425
426 for (i = 0; i < 769; i++)
427 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500428 if (hash[i] != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500429 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500430 png_dsortp p = hash[i];
Guy Schalnat0d580581995-07-20 02:43:20 -0500431 while (p)
432 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500433 t = p->next;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600434 png_free(png_ptr, p);
Guy Schalnat0d580581995-07-20 02:43:20 -0500435 p = t;
436 }
437 }
438 hash[i] = 0;
439 }
440 max_d += 96;
441 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600442 png_free(png_ptr, hash);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500443 png_free(png_ptr, png_ptr->palette_to_index);
444 png_free(png_ptr, png_ptr->index_to_palette);
445 png_ptr->palette_to_index=NULL;
446 png_ptr->index_to_palette=NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500447 }
448 num_palette = maximum_colors;
449 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500450 if (png_ptr->palette == NULL)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600451 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500452 png_ptr->palette = palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500453 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600454 png_ptr->num_palette = (png_uint_16)num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500455
456 if (full_dither)
457 {
458 int i;
Guy Schalnat6d764711995-12-19 03:22:19 -0600459 png_bytep distance;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500460 int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600461 PNG_DITHER_BLUE_BITS;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500462 int num_red = (1 << PNG_DITHER_RED_BITS);
463 int num_green = (1 << PNG_DITHER_GREEN_BITS);
464 int num_blue = (1 << PNG_DITHER_BLUE_BITS);
465 png_size_t num_entries = ((png_size_t)1 << total_bits);
Guy Schalnat0d580581995-07-20 02:43:20 -0500466
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600467 png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500468 (png_uint_32)(num_entries * png_sizeof (png_byte)));
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500469
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500470 png_memset(png_ptr->palette_lookup, 0, num_entries *
471 png_sizeof (png_byte));
Guy Schalnat0d580581995-07-20 02:43:20 -0500472
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600473 distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500474 png_sizeof(png_byte)));
Glenn Randers-Pehrsone1eff582001-04-14 20:15:41 -0500475
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500476 png_memset(distance, 0xff, num_entries * png_sizeof(png_byte));
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500477
478 for (i = 0; i < num_palette; i++)
479 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500480 int ir, ig, ib;
481 int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
482 int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
483 int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
Guy Schalnat0d580581995-07-20 02:43:20 -0500484
485 for (ir = 0; ir < num_red; ir++)
486 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500487 /* int dr = abs(ir - r); */
488 int dr = ((ir > r) ? ir - r : r - ir);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500489 int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
Guy Schalnat0d580581995-07-20 02:43:20 -0500490
Guy Schalnat0d580581995-07-20 02:43:20 -0500491 for (ig = 0; ig < num_green; ig++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600492 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500493 /* int dg = abs(ig - g); */
494 int dg = ((ig > g) ? ig - g : g - ig);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500495 int dt = dr + dg;
496 int dm = ((dr > dg) ? dr : dg);
497 int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
Guy Schalnat0d580581995-07-20 02:43:20 -0500498
Guy Schalnat0d580581995-07-20 02:43:20 -0500499 for (ib = 0; ib < num_blue; ib++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600500 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500501 int d_index = index_g | ib;
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500502 /* int db = abs(ib - b); */
503 int db = ((ib > b) ? ib - b : b - ib);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500504 int dmax = ((dm > db) ? dm : db);
505 int d = dmax + dt + db;
Guy Schalnat0d580581995-07-20 02:43:20 -0500506
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600507 if (d < (int)distance[d_index])
Guy Schalnat0d580581995-07-20 02:43:20 -0500508 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500509 distance[d_index] = (png_byte)d;
510 png_ptr->palette_lookup[d_index] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500511 }
512 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500513 }
514 }
515 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500516
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600517 png_free(png_ptr, distance);
Guy Schalnat0d580581995-07-20 02:43:20 -0500518 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500519}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500520#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500521
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600522#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600523/* Transform the image from the file_gamma to the screen_gamma. We
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600524 * only do transformations on images where the file_gamma and screen_gamma
525 * are not close reciprocals, otherwise it slows things down slightly, and
526 * also needlessly introduces small errors.
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600527 *
528 * We will turn off gamma transformation later if no semitransparent entries
529 * are present in the tRNS array for palette images. We can't do it here
530 * because we don't necessarily have the tRNS chunk yet.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600531 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500532void PNGAPI
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600533png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -0500534{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500535 png_debug(1, "in png_set_gamma\n");
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600536 if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) ||
537 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) ||
538 (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
539 png_ptr->transformations |= PNG_GAMMA;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500540 png_ptr->gamma = (float)file_gamma;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600541 png_ptr->screen_gamma = (float)scrn_gamma;
Guy Schalnat0d580581995-07-20 02:43:20 -0500542}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500543#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500544
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500545#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -0500546/* Expand paletted images to RGB, expand grayscale images of
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500547 * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600548 * to alpha channels.
549 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500550void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600551png_set_expand(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500552{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500553 png_debug(1, "in png_set_expand\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500554 png_ptr->transformations |= PNG_EXPAND;
555}
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500556
557/* GRR 19990627: the following three functions currently are identical
558 * to png_set_expand(). However, it is entirely reasonable that someone
559 * might wish to expand an indexed image to RGB but *not* expand a single,
560 * fully transparent palette entry to a full alpha channel--perhaps instead
561 * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
562 * the transparent color with a particular RGB value, or drop tRNS entirely.
563 * IOW, a future version of the library may make the transformations flag
564 * a bit more fine-grained, with separate bits for each of these three
565 * functions.
566 *
567 * More to the point, these functions make it obvious what libpng will be
568 * doing, whereas "expand" can (and does) mean any number of things.
569 */
570
571/* Expand paletted images to RGB. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500572void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500573png_set_palette_to_rgb(png_structp png_ptr)
574{
575 png_debug(1, "in png_set_expand\n");
576 png_ptr->transformations |= PNG_EXPAND;
577}
578
579/* Expand grayscale images of less than 8-bit depth to 8 bits. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500580void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500581png_set_gray_1_2_4_to_8(png_structp png_ptr)
582{
583 png_debug(1, "in png_set_expand\n");
584 png_ptr->transformations |= PNG_EXPAND;
585}
586
587/* Expand tRNS chunks to alpha channels. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500588void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500589png_set_tRNS_to_alpha(png_structp png_ptr)
590{
591 png_debug(1, "in png_set_expand\n");
592 png_ptr->transformations |= PNG_EXPAND;
593}
594#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500595
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500596#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500597void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600598png_set_gray_to_rgb(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500599{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500600 png_debug(1, "in png_set_gray_to_rgb\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500601 png_ptr->transformations |= PNG_GRAY_TO_RGB;
602}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500603#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500604
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600605#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
606#if defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600607/* Convert a RGB image to a grayscale of the same width. This allows us,
608 * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600609 */
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600610
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500611void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500612png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red,
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600613 double green)
614{
615 int red_fixed = (int)((float)red*100000.0 + 0.5);
616 int green_fixed = (int)((float)green*100000.0 + 0.5);
617 png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed);
618}
619#endif
620
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500621void PNGAPI
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600622png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
623 png_fixed_point red, png_fixed_point green)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600624{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500625 png_debug(1, "in png_set_rgb_to_gray\n");
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600626 switch(error_action)
627 {
628 case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY;
629 break;
630 case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
631 break;
632 case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
633 }
634 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
635#if defined(PNG_READ_EXPAND_SUPPORTED)
636 png_ptr->transformations |= PNG_EXPAND;
637#else
638 {
639 png_warning(png_ptr, "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED.");
640 png_ptr->transformations &= ~PNG_RGB_TO_GRAY;
641 }
642#endif
643 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600644 png_uint_16 red_int, green_int;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600645 if(red < 0 || green < 0)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600646 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600647 red_int = 6968; /* .212671 * 32768 + .5 */
648 green_int = 23434; /* .715160 * 32768 + .5 */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600649 }
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600650 else if(red + green < 100000L)
651 {
652 red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
653 green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
654 }
655 else
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600656 {
657 png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600658 red_int = 6968;
659 green_int = 23434;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600660 }
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600661 png_ptr->rgb_to_gray_red_coeff = red_int;
662 png_ptr->rgb_to_gray_green_coeff = green_int;
663 png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(32768-red_int-green_int);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600664 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600665}
666#endif
667
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500668#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
669 defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
670 defined(PNG_LEGACY_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500671void PNGAPI
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600672png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
673 read_user_transform_fn)
674{
675 png_debug(1, "in png_set_read_user_transform_fn\n");
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500676#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600677 png_ptr->transformations |= PNG_USER_TRANSFORM;
678 png_ptr->read_user_transform_fn = read_user_transform_fn;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500679#endif
680#ifdef PNG_LEGACY_SUPPORTED
681 if(read_user_transform_fn)
682 png_warning(png_ptr,
683 "This version of libpng does not support user transforms");
684#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600685}
686#endif
687
Andreas Dilger47a0c421997-05-16 02:46:07 -0500688/* Initialize everything needed for the read. This includes modifying
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600689 * the palette.
690 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500691void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -0600692png_init_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500693{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500694 png_debug(1, "in png_init_read_transformations\n");
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500695#if defined(PNG_USELESS_TESTS_SUPPORTED)
696 if(png_ptr != NULL)
697#endif
698 {
699#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
700 || defined(PNG_READ_GAMMA_SUPPORTED)
701 int color_type = png_ptr->color_type;
702#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500703
Guy Schalnate5a37791996-06-05 15:50:50 -0500704#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600705 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
706 (png_ptr->transformations & PNG_EXPAND))
Guy Schalnat0d580581995-07-20 02:43:20 -0500707 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500708 if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
Guy Schalnat0d580581995-07-20 02:43:20 -0500709 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500710 /* expand background chunk. */
Guy Schalnat0d580581995-07-20 02:43:20 -0500711 switch (png_ptr->bit_depth)
712 {
713 case 1:
Guy Schalnate5a37791996-06-05 15:50:50 -0500714 png_ptr->background.gray *= (png_uint_16)0xff;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600715 png_ptr->background.red = png_ptr->background.green
716 = png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500717 break;
718 case 2:
Guy Schalnate5a37791996-06-05 15:50:50 -0500719 png_ptr->background.gray *= (png_uint_16)0x55;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600720 png_ptr->background.red = png_ptr->background.green
721 = png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500722 break;
723 case 4:
Guy Schalnate5a37791996-06-05 15:50:50 -0500724 png_ptr->background.gray *= (png_uint_16)0x11;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600725 png_ptr->background.red = png_ptr->background.green
726 = png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnate5a37791996-06-05 15:50:50 -0500727 break;
728 case 8:
729 case 16:
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600730 png_ptr->background.red = png_ptr->background.green
731 = png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500732 break;
733 }
734 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500735 else if (color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -0500736 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500737 png_ptr->background.red =
Guy Schalnat0d580581995-07-20 02:43:20 -0500738 png_ptr->palette[png_ptr->background.index].red;
739 png_ptr->background.green =
740 png_ptr->palette[png_ptr->background.index].green;
Guy Schalnate5a37791996-06-05 15:50:50 -0500741 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -0500742 png_ptr->palette[png_ptr->background.index].blue;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600743
744#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
745 if (png_ptr->transformations & PNG_INVERT_ALPHA)
746 {
747#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600748 if (!(png_ptr->transformations & PNG_EXPAND))
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600749#endif
750 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600751 /* invert the alpha channel (in tRNS) unless the pixels are
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600752 going to be expanded, in which case leave it for later */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500753 int i,istop;
754 istop=(int)png_ptr->num_trans;
755 for (i=0; i<istop; i++)
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -0500756 png_ptr->trans[i] = (png_byte)(255 - png_ptr->trans[i]);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600757 }
758 }
759#endif
760
Guy Schalnat0d580581995-07-20 02:43:20 -0500761 }
762 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500763#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500764
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500765#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500766 png_ptr->background_1 = png_ptr->background;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500767#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600768#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600769
770 if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0)
771 && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0)
772 < PNG_GAMMA_THRESHOLD))
773 {
774 int i,k;
775 k=0;
776 for (i=0; i<png_ptr->num_trans; i++)
777 {
778 if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff)
779 k=1; /* partial transparency is present */
780 }
781 if (k == 0)
782 png_ptr->transformations &= (~PNG_GAMMA);
783 }
784
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600785 if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) &&
786 png_ptr->gamma != 0.0)
Guy Schalnat0d580581995-07-20 02:43:20 -0500787 {
788 png_build_gamma_table(png_ptr);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500789#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Guy Schalnate5a37791996-06-05 15:50:50 -0500790 if (png_ptr->transformations & PNG_BACKGROUND)
Guy Schalnat0d580581995-07-20 02:43:20 -0500791 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500792 if (color_type == PNG_COLOR_TYPE_PALETTE)
793 {
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600794 /* could skip if no transparency and
795 */
Guy Schalnate5a37791996-06-05 15:50:50 -0500796 png_color back, back_1;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500797 png_colorp palette = png_ptr->palette;
798 int num_palette = png_ptr->num_palette;
799 int i;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500800 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
801 {
802 back.red = png_ptr->gamma_table[png_ptr->background.red];
803 back.green = png_ptr->gamma_table[png_ptr->background.green];
804 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
Guy Schalnate5a37791996-06-05 15:50:50 -0500805
Andreas Dilger47a0c421997-05-16 02:46:07 -0500806 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
807 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
808 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
809 }
810 else
811 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600812 double g, gs;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500813
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600814 switch (png_ptr->background_gamma_type)
Glenn Randers-Pehrson4922b1b1998-03-08 22:55:17 -0600815 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600816 case PNG_BACKGROUND_GAMMA_SCREEN:
817 g = (png_ptr->screen_gamma);
818 gs = 1.0;
819 break;
820 case PNG_BACKGROUND_GAMMA_FILE:
821 g = 1.0 / (png_ptr->gamma);
822 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
823 break;
824 case PNG_BACKGROUND_GAMMA_UNIQUE:
825 g = 1.0 / (png_ptr->background_gamma);
826 gs = 1.0 / (png_ptr->background_gamma *
827 png_ptr->screen_gamma);
828 break;
829 default:
830 g = 1.0; /* back_1 */
831 gs = 1.0; /* back */
832 }
833
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -0600834 if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD)
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600835 {
836 back.red = (png_byte)png_ptr->background.red;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500837 back.green = (png_byte)png_ptr->background.green;
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600838 back.blue = (png_byte)png_ptr->background.blue;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500839 }
840 else
841 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600842 back.red = (png_byte)(pow(
843 (double)png_ptr->background.red/255, gs) * 255.0 + .5);
844 back.green = (png_byte)(pow(
845 (double)png_ptr->background.green/255, gs) * 255.0 + .5);
846 back.blue = (png_byte)(pow(
847 (double)png_ptr->background.blue/255, gs) * 255.0 + .5);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500848 }
849
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600850 back_1.red = (png_byte)(pow(
851 (double)png_ptr->background.red/255, g) * 255.0 + .5);
852 back_1.green = (png_byte)(pow(
853 (double)png_ptr->background.green/255, g) * 255.0 + .5);
854 back_1.blue = (png_byte)(pow(
855 (double)png_ptr->background.blue/255, g) * 255.0 + .5);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500856 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500857 for (i = 0; i < num_palette; i++)
858 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500859 if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
Guy Schalnate5a37791996-06-05 15:50:50 -0500860 {
861 if (png_ptr->trans[i] == 0)
862 {
863 palette[i] = back;
864 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500865 else /* if (png_ptr->trans[i] != 0xff) */
Guy Schalnate5a37791996-06-05 15:50:50 -0500866 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500867 png_byte v, w;
Guy Schalnate5a37791996-06-05 15:50:50 -0500868
869 v = png_ptr->gamma_to_1[palette[i].red];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500870 png_composite(w, v, png_ptr->trans[i], back_1.red);
Guy Schalnate5a37791996-06-05 15:50:50 -0500871 palette[i].red = png_ptr->gamma_from_1[w];
872
873 v = png_ptr->gamma_to_1[palette[i].green];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500874 png_composite(w, v, png_ptr->trans[i], back_1.green);
Guy Schalnate5a37791996-06-05 15:50:50 -0500875 palette[i].green = png_ptr->gamma_from_1[w];
876
877 v = png_ptr->gamma_to_1[palette[i].blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500878 png_composite(w, v, png_ptr->trans[i], back_1.blue);
Guy Schalnate5a37791996-06-05 15:50:50 -0500879 palette[i].blue = png_ptr->gamma_from_1[w];
880 }
881 }
882 else
883 {
884 palette[i].red = png_ptr->gamma_table[palette[i].red];
885 palette[i].green = png_ptr->gamma_table[palette[i].green];
886 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
887 }
888 }
889 }
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -0500890 /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600891 else
892 /* color_type != PNG_COLOR_TYPE_PALETTE */
Guy Schalnat0d580581995-07-20 02:43:20 -0500893 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500894 double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
895 double g = 1.0;
896 double gs = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500897
898 switch (png_ptr->background_gamma_type)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600899 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500900 case PNG_BACKGROUND_GAMMA_SCREEN:
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600901 g = (png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500902 gs = 1.0;
903 break;
904 case PNG_BACKGROUND_GAMMA_FILE:
905 g = 1.0 / (png_ptr->gamma);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600906 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500907 break;
908 case PNG_BACKGROUND_GAMMA_UNIQUE:
909 g = 1.0 / (png_ptr->background_gamma);
910 gs = 1.0 / (png_ptr->background_gamma *
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600911 png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500912 break;
913 }
914
Glenn Randers-Pehrson377657d2002-03-08 01:31:27 -0600915 png_ptr->background_1.gray = (png_uint_16)(pow(
916 (double)png_ptr->background.gray / m, g) * m + .5);
917 png_ptr->background.gray = (png_uint_16)(pow(
918 (double)png_ptr->background.gray / m, gs) * m + .5);
919
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600920 if ((png_ptr->background.red != png_ptr->background.green) ||
921 (png_ptr->background.red != png_ptr->background.blue) ||
922 (png_ptr->background.red != png_ptr->background.gray))
Guy Schalnat0d580581995-07-20 02:43:20 -0500923 {
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600924 /* RGB or RGBA with color background */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600925 png_ptr->background_1.red = (png_uint_16)(pow(
Guy Schalnat0d580581995-07-20 02:43:20 -0500926 (double)png_ptr->background.red / m, g) * m + .5);
927 png_ptr->background_1.green = (png_uint_16)(pow(
928 (double)png_ptr->background.green / m, g) * m + .5);
929 png_ptr->background_1.blue = (png_uint_16)(pow(
930 (double)png_ptr->background.blue / m, g) * m + .5);
931 png_ptr->background.red = (png_uint_16)(pow(
932 (double)png_ptr->background.red / m, gs) * m + .5);
933 png_ptr->background.green = (png_uint_16)(pow(
934 (double)png_ptr->background.green / m, gs) * m + .5);
935 png_ptr->background.blue = (png_uint_16)(pow(
936 (double)png_ptr->background.blue / m, gs) * m + .5);
937 }
938 else
939 {
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600940 /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */
941 png_ptr->background_1.red = png_ptr->background_1.green
942 = png_ptr->background_1.blue = png_ptr->background_1.gray;
943 png_ptr->background.red = png_ptr->background.green
944 = png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500945 }
946 }
947 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500948 else
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600949 /* transformation does not include PNG_BACKGROUND */
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500950#endif /* PNG_READ_BACKGROUND_SUPPORTED */
Guy Schalnate5a37791996-06-05 15:50:50 -0500951 if (color_type == PNG_COLOR_TYPE_PALETTE)
952 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500953 png_colorp palette = png_ptr->palette;
954 int num_palette = png_ptr->num_palette;
955 int i;
Guy Schalnate5a37791996-06-05 15:50:50 -0500956
957 for (i = 0; i < num_palette; i++)
958 {
959 palette[i].red = png_ptr->gamma_table[palette[i].red];
960 palette[i].green = png_ptr->gamma_table[palette[i].green];
961 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
962 }
963 }
964 }
965#if defined(PNG_READ_BACKGROUND_SUPPORTED)
966 else
967#endif
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500968#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */
Guy Schalnate5a37791996-06-05 15:50:50 -0500969#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600970 /* No GAMMA transformation */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600971 if ((png_ptr->transformations & PNG_BACKGROUND) &&
972 (color_type == PNG_COLOR_TYPE_PALETTE))
Guy Schalnate5a37791996-06-05 15:50:50 -0500973 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500974 int i;
975 int istop = (int)png_ptr->num_trans;
Guy Schalnate5a37791996-06-05 15:50:50 -0500976 png_color back;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500977 png_colorp palette = png_ptr->palette;
Guy Schalnate5a37791996-06-05 15:50:50 -0500978
Guy Schalnate5a37791996-06-05 15:50:50 -0500979 back.red = (png_byte)png_ptr->background.red;
980 back.green = (png_byte)png_ptr->background.green;
981 back.blue = (png_byte)png_ptr->background.blue;
982
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500983 for (i = 0; i < istop; i++)
Guy Schalnate5a37791996-06-05 15:50:50 -0500984 {
985 if (png_ptr->trans[i] == 0)
986 {
987 palette[i] = back;
988 }
989 else if (png_ptr->trans[i] != 0xff)
990 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500991 /* The png_composite() macro is defined in png.h */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500992 png_composite(palette[i].red, palette[i].red,
993 png_ptr->trans[i], back.red);
994 png_composite(palette[i].green, palette[i].green,
995 png_ptr->trans[i], back.green);
996 png_composite(palette[i].blue, palette[i].blue,
997 png_ptr->trans[i], back.blue);
Guy Schalnate5a37791996-06-05 15:50:50 -0500998 }
999 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001000 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001001#endif /* PNG_READ_BACKGROUND_SUPPORTED */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001002
Guy Schalnat6d764711995-12-19 03:22:19 -06001003#if defined(PNG_READ_SHIFT_SUPPORTED)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001004 if ((png_ptr->transformations & PNG_SHIFT) &&
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001005 (color_type == PNG_COLOR_TYPE_PALETTE))
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001006 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001007 png_uint_16 i;
1008 png_uint_16 istop = png_ptr->num_palette;
1009 int sr = 8 - png_ptr->sig_bit.red;
1010 int sg = 8 - png_ptr->sig_bit.green;
1011 int sb = 8 - png_ptr->sig_bit.blue;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001012
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001013 if (sr < 0 || sr > 8)
1014 sr = 0;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001015 if (sg < 0 || sg > 8)
1016 sg = 0;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001017 if (sb < 0 || sb > 8)
1018 sb = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001019 for (i = 0; i < istop; i++)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001020 {
1021 png_ptr->palette[i].red >>= sr;
1022 png_ptr->palette[i].green >>= sg;
1023 png_ptr->palette[i].blue >>= sb;
1024 }
1025 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001026#endif /* PNG_READ_SHIFT_SUPPORTED */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001027 }
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001028#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \
1029 && !defined(PNG_READ_BACKGROUND_SUPPORTED)
1030 if(png_ptr)
1031 return;
1032#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001033}
1034
Andreas Dilger47a0c421997-05-16 02:46:07 -05001035/* Modify the info structure to reflect the transformations. The
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001036 * info should be updated so a PNG file could be written with it,
1037 * assuming the transformations result in valid PNG data.
1038 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001039void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001040png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001041{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001042 png_debug(1, "in png_read_transform_info\n");
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001043#if defined(PNG_READ_EXPAND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001044 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001045 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001046 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1047 {
1048 if (png_ptr->num_trans)
1049 info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1050 else
1051 info_ptr->color_type = PNG_COLOR_TYPE_RGB;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001052 info_ptr->bit_depth = 8;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001053 info_ptr->num_trans = 0;
1054 }
1055 else
1056 {
1057 if (png_ptr->num_trans)
1058 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
1059 if (info_ptr->bit_depth < 8)
1060 info_ptr->bit_depth = 8;
1061 info_ptr->num_trans = 0;
1062 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001063 }
1064#endif
1065
1066#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1067 if (png_ptr->transformations & PNG_BACKGROUND)
1068 {
1069 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
1070 info_ptr->num_trans = 0;
1071 info_ptr->background = png_ptr->background;
1072 }
1073#endif
1074
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001075#if defined(PNG_READ_GAMMA_SUPPORTED)
1076 if (png_ptr->transformations & PNG_GAMMA)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001077 {
1078#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001079 info_ptr->gamma = png_ptr->gamma;
1080#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001081#ifdef PNG_FIXED_POINT_SUPPORTED
1082 info_ptr->int_gamma = png_ptr->int_gamma;
1083#endif
1084 }
1085#endif
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001086
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001087#if defined(PNG_READ_16_TO_8_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001088 if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001089 info_ptr->bit_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001090#endif
1091
1092#if defined(PNG_READ_DITHER_SUPPORTED)
1093 if (png_ptr->transformations & PNG_DITHER)
1094 {
1095 if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
1096 (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
1097 png_ptr->palette_lookup && info_ptr->bit_depth == 8)
1098 {
1099 info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
1100 }
1101 }
1102#endif
1103
1104#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001105 if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001106 info_ptr->bit_depth = 8;
1107#endif
1108
1109#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001110 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001111 info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
1112#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001113
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001114#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1115 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1116 info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
1117#endif
1118
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001119 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001120 info_ptr->channels = 1;
1121 else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
1122 info_ptr->channels = 3;
1123 else
1124 info_ptr->channels = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001125
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001126#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001127 if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001128 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001129#endif
1130
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001131 if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
1132 info_ptr->channels++;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001133
1134#if defined(PNG_READ_FILLER_SUPPORTED)
1135 /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001136 if ((png_ptr->transformations & PNG_FILLER) &&
1137 ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
1138 (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001139 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001140 info_ptr->channels++;
Glenn Randers-Pehrson67864af2004-08-28 23:30:07 -05001141 /* if adding a true alpha channel not just filler */
1142#if !defined(PNG_1_0_X)
1143 if (png_ptr->transformations & PNG_ADD_ALPHA)
1144 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001145#endif
1146 }
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001147#endif
1148
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001149#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
1150defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001151 if(png_ptr->transformations & PNG_USER_TRANSFORM)
1152 {
1153 if(info_ptr->bit_depth < png_ptr->user_transform_depth)
1154 info_ptr->bit_depth = png_ptr->user_transform_depth;
1155 if(info_ptr->channels < png_ptr->user_transform_channels)
1156 info_ptr->channels = png_ptr->user_transform_channels;
1157 }
1158#endif
1159
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001160 info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
1161 info_ptr->bit_depth);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001162
1163 info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,info_ptr->width);
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05001164
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001165#if !defined(PNG_READ_EXPAND_SUPPORTED)
1166 if(png_ptr)
1167 return;
1168#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001169}
1170
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001171/* Transform the row. The order of transformations is significant,
1172 * and is very touchy. If you add a transformation, take care to
1173 * decide how it fits in with the other transformations here.
1174 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001175void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001176png_do_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05001177{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001178 png_debug(1, "in png_do_read_transformations\n");
1179#if !defined(PNG_USELESS_TESTS_SUPPORTED)
1180 if (png_ptr->row_buf == NULL)
1181 {
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -05001182#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001183 char msg[50];
1184
1185 sprintf(msg, "NULL row buffer for row %ld, pass %d", png_ptr->row_number,
1186 png_ptr->pass);
1187 png_error(png_ptr, msg);
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001188#else
1189 png_error(png_ptr, "NULL row buffer");
1190#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001191 }
1192#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001193
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001194#if defined(PNG_READ_EXPAND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001195 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05001196 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001197 if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
1198 {
1199 png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
1200 png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
1201 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001202 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001203 {
1204 if (png_ptr->num_trans)
1205 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1206 &(png_ptr->trans_values));
1207 else
1208 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1209 NULL);
1210 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001211 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001212#endif
1213
1214#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001215 if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001216 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001217 PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001218#endif
1219
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001220#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1221 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1222 {
1223 int rgb_error =
1224 png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1);
1225 if(rgb_error)
1226 {
1227 png_ptr->rgb_to_gray_status=1;
1228 if(png_ptr->transformations == PNG_RGB_TO_GRAY_WARN)
1229 png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1230 if(png_ptr->transformations == PNG_RGB_TO_GRAY_ERR)
1231 png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1232 }
1233 }
1234#endif
1235
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001236/*
1237From Andreas Dilger e-mail to png-implement, 26 March 1998:
1238
1239 In most cases, the "simple transparency" should be done prior to doing
1240 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 -06001241 pixel is transparent. You would also need to make sure that the
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001242 transparency information is upgraded to RGB.
1243
1244 To summarize, the current flow is:
1245 - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
1246 with background "in place" if transparent,
1247 convert to RGB if necessary
1248 - Gray + alpha -> composite with gray background and remove alpha bytes,
1249 convert to RGB if necessary
1250
1251 To support RGB backgrounds for gray images we need:
1252 - Gray + simple transparency -> convert to RGB + simple transparency, compare
1253 3 or 6 bytes and composite with background
1254 "in place" if transparent (3x compare/pixel
1255 compared to doing composite with gray bkgrnd)
1256 - Gray + alpha -> convert to RGB + alpha, composite with background and
1257 remove alpha bytes (3x float operations/pixel
1258 compared with composite on gray background)
1259
1260 Greg's change will do this. The reason it wasn't done before is for
1261 performance, as this increases the per-pixel operations. If we would check
1262 in advance if the background was gray or RGB, and position the gray-to-RGB
1263 transform appropriately, then it would save a lot of work/time.
1264 */
1265
1266#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1267 /* if gray -> RGB, do so now only if background is non-gray; else do later
1268 * for performance reasons */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001269 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001270 !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001271 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
1272#endif
1273
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001274#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001275 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1276 ((png_ptr->num_trans != 0 ) ||
1277 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
Guy Schalnat0d580581995-07-20 02:43:20 -05001278 png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001279 &(png_ptr->trans_values), &(png_ptr->background)
1280#if defined(PNG_READ_GAMMA_SUPPORTED)
1281 , &(png_ptr->background_1),
Guy Schalnat0d580581995-07-20 02:43:20 -05001282 png_ptr->gamma_table, png_ptr->gamma_from_1,
1283 png_ptr->gamma_to_1, png_ptr->gamma_16_table,
1284 png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001285 png_ptr->gamma_shift
1286#endif
1287);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001288#endif
1289
1290#if defined(PNG_READ_GAMMA_SUPPORTED)
1291 if ((png_ptr->transformations & PNG_GAMMA) &&
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001292#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1293 !((png_ptr->transformations & PNG_BACKGROUND) &&
1294 ((png_ptr->num_trans != 0) ||
1295 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
1296#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001297 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
Guy Schalnat0d580581995-07-20 02:43:20 -05001298 png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
1299 png_ptr->gamma_table, png_ptr->gamma_16_table,
1300 png_ptr->gamma_shift);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001301#endif
1302
1303#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001304 if (png_ptr->transformations & PNG_16_TO_8)
1305 png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001306#endif
1307
1308#if defined(PNG_READ_DITHER_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001309 if (png_ptr->transformations & PNG_DITHER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001310 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001311 png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
1312 png_ptr->palette_lookup, png_ptr->dither_index);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001313 if(png_ptr->row_info.rowbytes == (png_uint_32)0)
1314 png_error(png_ptr, "png_do_dither returned rowbytes=0");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001315 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001316#endif
1317
1318#if defined(PNG_READ_INVERT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001319 if (png_ptr->transformations & PNG_INVERT_MONO)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001320 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001321#endif
1322
1323#if defined(PNG_READ_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001324 if (png_ptr->transformations & PNG_SHIFT)
1325 png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
1326 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001327#endif
1328
1329#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001330 if (png_ptr->transformations & PNG_PACK)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001331 png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001332#endif
1333
1334#if defined(PNG_READ_BGR_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001335 if (png_ptr->transformations & PNG_BGR)
1336 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001337#endif
1338
Andreas Dilger47a0c421997-05-16 02:46:07 -05001339#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1340 if (png_ptr->transformations & PNG_PACKSWAP)
1341 png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1342#endif
1343
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001344#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001345 /* if gray -> RGB, do so now only if we did not do so above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001346 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
1347 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05001348 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001349#endif
1350
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001351#if defined(PNG_READ_FILLER_SUPPORTED)
1352 if (png_ptr->transformations & PNG_FILLER)
1353 png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001354 (png_uint_32)png_ptr->filler, png_ptr->flags);
1355#endif
1356
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001357#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
1358 if (png_ptr->transformations & PNG_INVERT_ALPHA)
1359 png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1360#endif
1361
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001362#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
1363 if (png_ptr->transformations & PNG_SWAP_ALPHA)
1364 png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1365#endif
1366
Andreas Dilger47a0c421997-05-16 02:46:07 -05001367#if defined(PNG_READ_SWAP_SUPPORTED)
1368 if (png_ptr->transformations & PNG_SWAP_BYTES)
1369 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001370#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001371
1372#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1373 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001374 {
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001375 if(png_ptr->read_user_transform_fn != NULL)
1376 (*(png_ptr->read_user_transform_fn)) /* user read transform function */
1377 (png_ptr, /* png_ptr */
1378 &(png_ptr->row_info), /* row_info: */
1379 /* png_uint_32 width; width of row */
1380 /* png_uint_32 rowbytes; number of bytes in row */
1381 /* png_byte color_type; color type of pixels */
1382 /* png_byte bit_depth; bit depth of samples */
1383 /* png_byte channels; number of channels (1-4) */
1384 /* png_byte pixel_depth; bits per pixel (depth*channels) */
1385 png_ptr->row_buf + 1); /* start of pixel data for row */
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001386#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001387 if(png_ptr->user_transform_depth)
1388 png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
1389 if(png_ptr->user_transform_channels)
1390 png_ptr->row_info.channels = png_ptr->user_transform_channels;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001391#endif
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001392 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
1393 png_ptr->row_info.channels);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001394 png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
1395 png_ptr->row_info.width);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001396 }
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001397#endif
1398
Guy Schalnat0d580581995-07-20 02:43:20 -05001399}
1400
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001401#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001402/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
1403 * without changing the actual values. Thus, if you had a row with
1404 * a bit depth of 1, you would end up with bytes that only contained
1405 * the numbers 0 or 1. If you would rather they contain 0 and 255, use
1406 * png_do_shift() after this.
1407 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001408void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001409png_do_unpack(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001410{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001411 png_debug(1, "in png_do_unpack\n");
1412#if defined(PNG_USELESS_TESTS_SUPPORTED)
1413 if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
1414#else
1415 if (row_info->bit_depth < 8)
1416#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001417 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001418 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001419 png_uint_32 row_width=row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001420
Guy Schalnat0d580581995-07-20 02:43:20 -05001421 switch (row_info->bit_depth)
1422 {
1423 case 1:
1424 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001425 png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
1426 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001427 png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001428 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001429 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001430 *dp = (png_byte)((*sp >> shift) & 0x01);
Guy Schalnat0d580581995-07-20 02:43:20 -05001431 if (shift == 7)
1432 {
1433 shift = 0;
1434 sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001435 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001436 else
1437 shift++;
1438
1439 dp--;
1440 }
1441 break;
1442 }
1443 case 2:
1444 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001445
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001446 png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
1447 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001448 png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001449 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001450 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001451 *dp = (png_byte)((*sp >> shift) & 0x03);
Guy Schalnat0d580581995-07-20 02:43:20 -05001452 if (shift == 6)
1453 {
1454 shift = 0;
1455 sp--;
1456 }
1457 else
1458 shift += 2;
1459
1460 dp--;
1461 }
1462 break;
1463 }
1464 case 4:
1465 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001466 png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
1467 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001468 png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001469 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001470 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001471 *dp = (png_byte)((*sp >> shift) & 0x0f);
Guy Schalnat0d580581995-07-20 02:43:20 -05001472 if (shift == 4)
1473 {
1474 shift = 0;
1475 sp--;
1476 }
1477 else
1478 shift = 4;
1479
1480 dp--;
1481 }
1482 break;
1483 }
1484 }
1485 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001486 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001487 row_info->rowbytes = row_width * row_info->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001488 }
1489}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001490#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001491
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001492#if defined(PNG_READ_SHIFT_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001493/* Reverse the effects of png_do_shift. This routine merely shifts the
1494 * pixels back to their significant bits values. Thus, if you have
1495 * a row of bit depth 8, but only 5 are significant, this will shift
1496 * the values back to 0 through 31.
1497 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001498void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001499png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
Guy Schalnat0d580581995-07-20 02:43:20 -05001500{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001501 png_debug(1, "in png_do_unshift\n");
1502 if (
1503#if defined(PNG_USELESS_TESTS_SUPPORTED)
1504 row != NULL && row_info != NULL && sig_bits != NULL &&
1505#endif
1506 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001507 {
1508 int shift[4];
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001509 int channels = 0;
1510 int c;
1511 png_uint_16 value = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001512 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001513
Guy Schalnat0d580581995-07-20 02:43:20 -05001514 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
1515 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001516 shift[channels++] = row_info->bit_depth - sig_bits->red;
1517 shift[channels++] = row_info->bit_depth - sig_bits->green;
1518 shift[channels++] = row_info->bit_depth - sig_bits->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05001519 }
1520 else
1521 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001522 shift[channels++] = row_info->bit_depth - sig_bits->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05001523 }
1524 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
1525 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001526 shift[channels++] = row_info->bit_depth - sig_bits->alpha;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001527 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001528
Andreas Dilger47a0c421997-05-16 02:46:07 -05001529 for (c = 0; c < channels; c++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001530 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001531 if (shift[c] <= 0)
1532 shift[c] = 0;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001533 else
1534 value = 1;
1535 }
Guy Schalnat0f716451995-11-28 11:22:13 -06001536
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001537 if (!value)
1538 return;
Guy Schalnat0f716451995-11-28 11:22:13 -06001539
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001540 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05001541 {
1542 case 2:
1543 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001544 png_bytep bp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001545 png_uint_32 i;
1546 png_uint_32 istop = row_info->rowbytes;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001547
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001548 for (bp = row, i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001549 {
1550 *bp >>= 1;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001551 *bp++ &= 0x55;
Guy Schalnat0d580581995-07-20 02:43:20 -05001552 }
1553 break;
1554 }
1555 case 4:
1556 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001557 png_bytep bp = row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001558 png_uint_32 i;
1559 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001560 png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
1561 (png_byte)((int)0xf >> shift[0]));
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001562
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001563 for (i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001564 {
1565 *bp >>= shift[0];
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001566 *bp++ &= mask;
Guy Schalnat0d580581995-07-20 02:43:20 -05001567 }
1568 break;
1569 }
1570 case 8:
1571 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001572 png_bytep bp = row;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001573 png_uint_32 i;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001574 png_uint_32 istop = row_width * channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001575
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001576 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001577 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001578 *bp++ >>= shift[i%channels];
Guy Schalnat0d580581995-07-20 02:43:20 -05001579 }
1580 break;
1581 }
1582 case 16:
1583 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001584 png_bytep bp = row;
1585 png_uint_32 i;
1586 png_uint_32 istop = channels * row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001587
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001588 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001589 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001590 value = (png_uint_16)((*bp << 8) + *(bp + 1));
1591 value >>= shift[i%channels];
1592 *bp++ = (png_byte)(value >> 8);
1593 *bp++ = (png_byte)(value & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05001594 }
1595 break;
1596 }
1597 }
1598 }
1599}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001600#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001601
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001602#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001603/* chop rows of bit depth 16 down to 8 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001604void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001605png_do_chop(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001606{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001607 png_debug(1, "in png_do_chop\n");
1608#if defined(PNG_USELESS_TESTS_SUPPORTED)
1609 if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
1610#else
1611 if (row_info->bit_depth == 16)
1612#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001613 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001614 png_bytep sp = row;
1615 png_bytep dp = row;
1616 png_uint_32 i;
1617 png_uint_32 istop = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001618
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001619 for (i = 0; i<istop; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001620 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001621#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001622 /* This does a more accurate scaling of the 16-bit color
1623 * value, rather than a simple low-byte truncation.
1624 *
1625 * What the ideal calculation should be:
1626 * *dp = (((((png_uint_32)(*sp) << 8) |
1627 * (png_uint_32)(*(sp + 1))) * 255 + 127) / (png_uint_32)65535L;
1628 *
1629 * GRR: no, I think this is what it really should be:
1630 * *dp = (((((png_uint_32)(*sp) << 8) |
1631 * (png_uint_32)(*(sp + 1))) + 128L) / (png_uint_32)257L;
1632 *
1633 * GRR: here's the exact calculation with shifts:
1634 * temp = (((png_uint_32)(*sp) << 8) | (png_uint_32)(*(sp + 1))) + 128L;
1635 * *dp = (temp - (temp >> 8)) >> 8;
1636 *
1637 * Approximate calculation with shift/add instead of multiply/divide:
1638 * *dp = ((((png_uint_32)(*sp) << 8) |
1639 * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
1640 *
1641 * What we actually do to avoid extra shifting and conversion:
1642 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001643
Andreas Dilger47a0c421997-05-16 02:46:07 -05001644 *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
1645#else
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001646 /* Simply discard the low order byte */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001647 *dp = *sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001648#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001649 }
1650 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001651 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001652 row_info->rowbytes = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001653 }
1654}
1655#endif
1656
1657#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001658void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001659png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
1660{
1661 png_debug(1, "in png_do_read_swap_alpha\n");
1662#if defined(PNG_USELESS_TESTS_SUPPORTED)
1663 if (row != NULL && row_info != NULL)
1664#endif
1665 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001666 png_uint_32 row_width = row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001667 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1668 {
1669 /* This converts from RGBA to ARGB */
1670 if (row_info->bit_depth == 8)
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;
1675 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001676
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 = *(--sp);
1680 *(--dp) = *(--sp);
1681 *(--dp) = *(--sp);
1682 *(--dp) = *(--sp);
1683 *(--dp) = save;
1684 }
1685 }
1686 /* This converts from RRGGBBAA to AARRGGBB */
1687 else
1688 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001689 png_bytep sp = row + row_info->rowbytes;
1690 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001691 png_byte save[2];
1692 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001693
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001694 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001695 {
1696 save[0] = *(--sp);
1697 save[1] = *(--sp);
1698 *(--dp) = *(--sp);
1699 *(--dp) = *(--sp);
1700 *(--dp) = *(--sp);
1701 *(--dp) = *(--sp);
1702 *(--dp) = *(--sp);
1703 *(--dp) = *(--sp);
1704 *(--dp) = save[0];
1705 *(--dp) = save[1];
1706 }
1707 }
1708 }
1709 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1710 {
1711 /* This converts from GA to AG */
1712 if (row_info->bit_depth == 8)
1713 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001714 png_bytep sp = row + row_info->rowbytes;
1715 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001716 png_byte save;
1717 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001718
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001719 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001720 {
1721 save = *(--sp);
1722 *(--dp) = *(--sp);
1723 *(--dp) = save;
1724 }
1725 }
1726 /* This converts from GGAA to AAGG */
1727 else
1728 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001729 png_bytep sp = row + row_info->rowbytes;
1730 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001731 png_byte save[2];
1732 png_uint_32 i;
1733
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001734 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001735 {
1736 save[0] = *(--sp);
1737 save[1] = *(--sp);
1738 *(--dp) = *(--sp);
1739 *(--dp) = *(--sp);
1740 *(--dp) = save[0];
1741 *(--dp) = save[1];
1742 }
1743 }
1744 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001745 }
1746}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001747#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001748
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001749#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001750void /* PRIVATE */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001751png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
1752{
1753 png_debug(1, "in png_do_read_invert_alpha\n");
1754#if defined(PNG_USELESS_TESTS_SUPPORTED)
1755 if (row != NULL && row_info != NULL)
1756#endif
1757 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001758 png_uint_32 row_width = row_info->width;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001759 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1760 {
1761 /* This inverts the alpha channel in RGBA */
1762 if (row_info->bit_depth == 8)
1763 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001764 png_bytep sp = row + row_info->rowbytes;
1765 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001766 png_uint_32 i;
1767
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001768 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001769 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001770 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001771
1772/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001773 *(--dp) = *(--sp);
1774 *(--dp) = *(--sp);
1775 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001776 We can replace it with:
1777*/
1778 sp-=3;
1779 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001780 }
1781 }
1782 /* This inverts the alpha channel in RRGGBBAA */
1783 else
1784 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001785 png_bytep sp = row + row_info->rowbytes;
1786 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001787 png_uint_32 i;
1788
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001789 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001790 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001791 *(--dp) = (png_byte)(255 - *(--sp));
1792 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001793
1794/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001795 *(--dp) = *(--sp);
1796 *(--dp) = *(--sp);
1797 *(--dp) = *(--sp);
1798 *(--dp) = *(--sp);
1799 *(--dp) = *(--sp);
1800 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001801 We can replace it with:
1802*/
1803 sp-=6;
1804 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001805 }
1806 }
1807 }
1808 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1809 {
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001810 /* This inverts the alpha channel in GA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001811 if (row_info->bit_depth == 8)
1812 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001813 png_bytep sp = row + row_info->rowbytes;
1814 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001815 png_uint_32 i;
1816
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001817 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001818 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001819 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001820 *(--dp) = *(--sp);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001821 }
1822 }
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001823 /* This inverts the alpha channel in GGAA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001824 else
1825 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001826 png_bytep sp = row + row_info->rowbytes;
1827 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001828 png_uint_32 i;
1829
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001830 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001831 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001832 *(--dp) = (png_byte)(255 - *(--sp));
1833 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001834/*
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001835 *(--dp) = *(--sp);
1836 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001837*/
1838 sp-=2;
1839 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001840 }
1841 }
1842 }
1843 }
1844}
1845#endif
1846
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001847#if defined(PNG_READ_FILLER_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001848/* Add filler channel if we have RGB color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001849void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001850png_do_read_filler(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001851 png_uint_32 filler, png_uint_32 flags)
Guy Schalnat0d580581995-07-20 02:43:20 -05001852{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001853 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001854 png_uint_32 row_width = row_info->width;
1855
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001856 png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001857 png_byte lo_filler = (png_byte)(filler & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001858
1859 png_debug(1, "in png_do_read_filler\n");
1860 if (
1861#if defined(PNG_USELESS_TESTS_SUPPORTED)
1862 row != NULL && row_info != NULL &&
1863#endif
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001864 row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001865 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001866 if(row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05001867 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001868 /* This changes the data from G to GX */
1869 if (flags & PNG_FLAG_FILLER_AFTER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001870 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001871 png_bytep sp = row + (png_size_t)row_width;
1872 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001873 for (i = 1; i < row_width; i++)
1874 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001875 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001876 *(--dp) = *(--sp);
1877 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001878 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001879 row_info->channels = 2;
1880 row_info->pixel_depth = 16;
1881 row_info->rowbytes = row_width * 2;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001882 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001883 /* This changes the data from G to XG */
1884 else
1885 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001886 png_bytep sp = row + (png_size_t)row_width;
1887 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001888 for (i = 0; i < row_width; i++)
1889 {
1890 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001891 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001892 }
1893 row_info->channels = 2;
1894 row_info->pixel_depth = 16;
1895 row_info->rowbytes = row_width * 2;
1896 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001897 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001898 else if(row_info->bit_depth == 16)
1899 {
1900 /* This changes the data from GG to GGXX */
1901 if (flags & PNG_FLAG_FILLER_AFTER)
1902 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05001903 png_bytep sp = row + (png_size_t)row_width * 2;
1904 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001905 for (i = 1; i < row_width; i++)
1906 {
1907 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001908 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001909 *(--dp) = *(--sp);
1910 *(--dp) = *(--sp);
1911 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001912 *(--dp) = hi_filler;
1913 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001914 row_info->channels = 2;
1915 row_info->pixel_depth = 32;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001916 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001917 }
1918 /* This changes the data from GG to XXGG */
1919 else
1920 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05001921 png_bytep sp = row + (png_size_t)row_width * 2;
1922 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001923 for (i = 0; i < row_width; i++)
1924 {
1925 *(--dp) = *(--sp);
1926 *(--dp) = *(--sp);
1927 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001928 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001929 }
1930 row_info->channels = 2;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001931 row_info->pixel_depth = 32;
1932 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001933 }
1934 }
1935 } /* COLOR_TYPE == GRAY */
1936 else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
1937 {
1938 if(row_info->bit_depth == 8)
1939 {
1940 /* This changes the data from RGB to RGBX */
1941 if (flags & PNG_FLAG_FILLER_AFTER)
1942 {
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05001943 png_bytep sp = row + (png_size_t)row_width * 3;
1944 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001945 for (i = 1; i < row_width; i++)
1946 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001947 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001948 *(--dp) = *(--sp);
1949 *(--dp) = *(--sp);
1950 *(--dp) = *(--sp);
1951 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001952 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001953 row_info->channels = 4;
1954 row_info->pixel_depth = 32;
1955 row_info->rowbytes = row_width * 4;
1956 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001957 /* This changes the data from RGB to XRGB */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001958 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001959 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001960 png_bytep sp = row + (png_size_t)row_width * 3;
1961 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001962 for (i = 0; i < row_width; i++)
1963 {
1964 *(--dp) = *(--sp);
1965 *(--dp) = *(--sp);
1966 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001967 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001968 }
1969 row_info->channels = 4;
1970 row_info->pixel_depth = 32;
1971 row_info->rowbytes = row_width * 4;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001972 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001973 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001974 else if(row_info->bit_depth == 16)
1975 {
1976 /* This changes the data from RRGGBB to RRGGBBXX */
1977 if (flags & PNG_FLAG_FILLER_AFTER)
1978 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05001979 png_bytep sp = row + (png_size_t)row_width * 6;
1980 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001981 for (i = 1; i < row_width; i++)
1982 {
1983 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001984 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001985 *(--dp) = *(--sp);
1986 *(--dp) = *(--sp);
1987 *(--dp) = *(--sp);
1988 *(--dp) = *(--sp);
1989 *(--dp) = *(--sp);
1990 *(--dp) = *(--sp);
1991 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001992 *(--dp) = hi_filler;
1993 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001994 row_info->channels = 4;
1995 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001996 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001997 }
1998 /* This changes the data from RRGGBB to XXRRGGBB */
1999 else
2000 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002001 png_bytep sp = row + (png_size_t)row_width * 6;
2002 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002003 for (i = 0; i < row_width; i++)
2004 {
2005 *(--dp) = *(--sp);
2006 *(--dp) = *(--sp);
2007 *(--dp) = *(--sp);
2008 *(--dp) = *(--sp);
2009 *(--dp) = *(--sp);
2010 *(--dp) = *(--sp);
2011 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002012 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002013 }
2014 row_info->channels = 4;
2015 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002016 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002017 }
2018 }
2019 } /* COLOR_TYPE == RGB */
Guy Schalnat0d580581995-07-20 02:43:20 -05002020}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002021#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002022
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002023#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002024/* expand grayscale files to RGB, with or without alpha */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002025void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002026png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05002027{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002028 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002029 png_uint_32 row_width = row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06002030
Andreas Dilger47a0c421997-05-16 02:46:07 -05002031 png_debug(1, "in png_do_gray_to_rgb\n");
2032 if (row_info->bit_depth >= 8 &&
2033#if defined(PNG_USELESS_TESTS_SUPPORTED)
2034 row != NULL && row_info != NULL &&
2035#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002036 !(row_info->color_type & PNG_COLOR_MASK_COLOR))
2037 {
2038 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
2039 {
2040 if (row_info->bit_depth == 8)
2041 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002042 png_bytep sp = row + (png_size_t)row_width - 1;
2043 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002044 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002045 {
2046 *(dp--) = *sp;
2047 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002048 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002049 }
2050 }
2051 else
2052 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002053 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2054 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002055 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002056 {
2057 *(dp--) = *sp;
2058 *(dp--) = *(sp - 1);
2059 *(dp--) = *sp;
2060 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002061 *(dp--) = *(sp--);
2062 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002063 }
2064 }
2065 }
2066 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2067 {
2068 if (row_info->bit_depth == 8)
2069 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002070 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2071 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002072 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002073 {
2074 *(dp--) = *(sp--);
2075 *(dp--) = *sp;
2076 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002077 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002078 }
2079 }
2080 else
2081 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002082 png_bytep sp = row + (png_size_t)row_width * 4 - 1;
2083 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002084 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002085 {
2086 *(dp--) = *(sp--);
2087 *(dp--) = *(sp--);
2088 *(dp--) = *sp;
2089 *(dp--) = *(sp - 1);
2090 *(dp--) = *sp;
2091 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002092 *(dp--) = *(sp--);
2093 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002094 }
2095 }
2096 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002097 row_info->channels += (png_byte)2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002098 row_info->color_type |= PNG_COLOR_MASK_COLOR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002099 row_info->pixel_depth = (png_byte)(row_info->channels *
2100 row_info->bit_depth);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05002101 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05002102 }
2103}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002104#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002105
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002106#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002107/* reduce RGB files to grayscale, with or without alpha
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002108 * using the equation given in Poynton's ColorFAQ at
2109 * <http://www.inforamp.net/~poynton/>
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002110 * Copyright (c) 1998-01-04 Charles Poynton poynton at inforamp.net
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002111 *
2112 * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
2113 *
2114 * We approximate this with
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002115 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002116 * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002117 *
2118 * which can be expressed with integers as
2119 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002120 * Y = (6969 * R + 23434 * G + 2365 * B)/32768
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002121 *
2122 * The calculation is to be done in a linear colorspace.
2123 *
2124 * Other integer coefficents can be used via png_set_rgb_to_gray().
2125 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002126int /* PRIVATE */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002127png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
2128
2129{
2130 png_uint_32 i;
2131
2132 png_uint_32 row_width = row_info->width;
2133 int rgb_error = 0;
2134
2135 png_debug(1, "in png_do_rgb_to_gray\n");
2136 if (
2137#if defined(PNG_USELESS_TESTS_SUPPORTED)
2138 row != NULL && row_info != NULL &&
2139#endif
2140 (row_info->color_type & PNG_COLOR_MASK_COLOR))
2141 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002142 png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
2143 png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
2144 png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002145
2146 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2147 {
2148 if (row_info->bit_depth == 8)
2149 {
2150#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2151 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2152 {
2153 png_bytep sp = row;
2154 png_bytep dp = row;
2155
2156 for (i = 0; i < row_width; i++)
2157 {
2158 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2159 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2160 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
2161 if(red != green || red != blue)
2162 {
2163 rgb_error |= 1;
2164 *(dp++) = png_ptr->gamma_from_1[
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002165 (rc*red+gc*green+bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002166 }
2167 else
2168 *(dp++) = *(sp-1);
2169 }
2170 }
2171 else
2172#endif
2173 {
2174 png_bytep sp = row;
2175 png_bytep dp = row;
2176 for (i = 0; i < row_width; i++)
2177 {
2178 png_byte red = *(sp++);
2179 png_byte green = *(sp++);
2180 png_byte blue = *(sp++);
2181 if(red != green || red != blue)
2182 {
2183 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002184 *(dp++) = (png_byte)((rc*red+gc*green+bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002185 }
2186 else
2187 *(dp++) = *(sp-1);
2188 }
2189 }
2190 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002191
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002192 else /* RGB bit_depth == 16 */
2193 {
2194#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2195 if (png_ptr->gamma_16_to_1 != NULL &&
2196 png_ptr->gamma_16_from_1 != NULL)
2197 {
2198 png_bytep sp = row;
2199 png_bytep dp = row;
2200 for (i = 0; i < row_width; i++)
2201 {
2202 png_uint_16 red, green, blue, w;
2203
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002204 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2205 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2206 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002207
2208 if(red == green && red == blue)
2209 w = red;
2210 else
2211 {
2212 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2213 png_ptr->gamma_shift][red>>8];
2214 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2215 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002216 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002217 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002218 png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002219 + bc*blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002220 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2221 png_ptr->gamma_shift][gray16 >> 8];
2222 rgb_error |= 1;
2223 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002224
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002225 *(dp++) = (png_byte)((w>>8) & 0xff);
2226 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002227 }
2228 }
2229 else
2230#endif
2231 {
2232 png_bytep sp = row;
2233 png_bytep dp = row;
2234 for (i = 0; i < row_width; i++)
2235 {
2236 png_uint_16 red, green, blue, gray16;
2237
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002238 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2239 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2240 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002241
2242 if(red != green || red != blue)
2243 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002244 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002245 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2246 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002247 }
2248 }
2249 }
2250 }
2251 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2252 {
2253 if (row_info->bit_depth == 8)
2254 {
2255#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2256 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2257 {
2258 png_bytep sp = row;
2259 png_bytep dp = row;
2260 for (i = 0; i < row_width; i++)
2261 {
2262 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2263 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2264 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
2265 if(red != green || red != blue)
2266 rgb_error |= 1;
2267 *(dp++) = png_ptr->gamma_from_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002268 [(rc*red + gc*green + bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002269 *(dp++) = *(sp++); /* alpha */
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_byte red = *(sp++);
2280 png_byte green = *(sp++);
2281 png_byte blue = *(sp++);
2282 if(red != green || red != blue)
2283 rgb_error |= 1;
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002284 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002285 *(dp++) = *(sp++); /* alpha */
2286 }
2287 }
2288 }
2289 else /* RGBA bit_depth == 16 */
2290 {
2291#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2292 if (png_ptr->gamma_16_to_1 != NULL &&
2293 png_ptr->gamma_16_from_1 != NULL)
2294 {
2295 png_bytep sp = row;
2296 png_bytep dp = row;
2297 for (i = 0; i < row_width; i++)
2298 {
2299 png_uint_16 red, green, blue, w;
2300
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002301 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2302 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2303 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002304
2305 if(red == green && red == blue)
2306 w = red;
2307 else
2308 {
2309 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2310 png_ptr->gamma_shift][red>>8];
2311 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2312 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002313 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002314 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002315 png_uint_16 gray16 = (png_uint_16)((rc * red_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002316 + gc * green_1 + bc * blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002317 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2318 png_ptr->gamma_shift][gray16 >> 8];
2319 rgb_error |= 1;
2320 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002321
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002322 *(dp++) = (png_byte)((w>>8) & 0xff);
2323 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002324 *(dp++) = *(sp++); /* alpha */
2325 *(dp++) = *(sp++);
2326 }
2327 }
2328 else
2329#endif
2330 {
2331 png_bytep sp = row;
2332 png_bytep dp = row;
2333 for (i = 0; i < row_width; i++)
2334 {
2335 png_uint_16 red, green, blue, gray16;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002336 red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2337 green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2338 blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002339 if(red != green || red != blue)
2340 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002341 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002342 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2343 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002344 *(dp++) = *(sp++); /* alpha */
2345 *(dp++) = *(sp++);
2346 }
2347 }
2348 }
2349 }
2350 row_info->channels -= (png_byte)2;
2351 row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
2352 row_info->pixel_depth = (png_byte)(row_info->channels *
2353 row_info->bit_depth);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05002354 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002355 }
2356 return rgb_error;
2357}
2358#endif
2359
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002360/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
2361 * large of png_color. This lets grayscale images be treated as
2362 * paletted. Most useful for gamma correction and simplification
2363 * of code.
2364 */
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06002365void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -06002366png_build_grayscale_palette(int bit_depth, png_colorp palette)
Guy Schalnat0d580581995-07-20 02:43:20 -05002367{
2368 int num_palette;
2369 int color_inc;
2370 int i;
2371 int v;
2372
Andreas Dilger47a0c421997-05-16 02:46:07 -05002373 png_debug(1, "in png_do_build_grayscale_palette\n");
2374 if (palette == NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002375 return;
2376
2377 switch (bit_depth)
2378 {
2379 case 1:
2380 num_palette = 2;
2381 color_inc = 0xff;
2382 break;
2383 case 2:
2384 num_palette = 4;
2385 color_inc = 0x55;
2386 break;
2387 case 4:
2388 num_palette = 16;
2389 color_inc = 0x11;
2390 break;
2391 case 8:
2392 num_palette = 256;
2393 color_inc = 1;
2394 break;
2395 default:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002396 num_palette = 0;
Guy Schalnat69b14481996-01-10 02:56:49 -06002397 color_inc = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002398 break;
2399 }
2400
2401 for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
2402 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002403 palette[i].red = (png_byte)v;
2404 palette[i].green = (png_byte)v;
2405 palette[i].blue = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002406 }
2407}
2408
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002409/* This function is currently unused. Do we really need it? */
2410#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002411void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002412png_correct_palette(png_structp png_ptr, png_colorp palette,
Guy Schalnat0d580581995-07-20 02:43:20 -05002413 int num_palette)
2414{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002415 png_debug(1, "in png_correct_palette\n");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002416#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
2417 defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002418 if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND))
Guy Schalnat0d580581995-07-20 02:43:20 -05002419 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002420 png_color back, back_1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002421
Andreas Dilger47a0c421997-05-16 02:46:07 -05002422 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
2423 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002424 back.red = png_ptr->gamma_table[png_ptr->background.red];
2425 back.green = png_ptr->gamma_table[png_ptr->background.green];
2426 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
Guy Schalnat0d580581995-07-20 02:43:20 -05002427
Guy Schalnate5a37791996-06-05 15:50:50 -05002428 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
2429 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
2430 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002431 }
2432 else
2433 {
2434 double g;
Guy Schalnat0d580581995-07-20 02:43:20 -05002435
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06002436 g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002437
2438 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
2439 fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
Guy Schalnat0d580581995-07-20 02:43:20 -05002440 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002441 back.red = png_ptr->background.red;
2442 back.green = png_ptr->background.green;
2443 back.blue = png_ptr->background.blue;
2444 }
2445 else
2446 {
2447 back.red =
2448 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2449 255.0 + 0.5);
2450 back.green =
2451 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2452 255.0 + 0.5);
2453 back.blue =
2454 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2455 255.0 + 0.5);
2456 }
2457
2458 g = 1.0 / png_ptr->background_gamma;
2459
2460 back_1.red =
2461 (png_byte)(pow((double)png_ptr->background.red/255, g) *
2462 255.0 + 0.5);
2463 back_1.green =
2464 (png_byte)(pow((double)png_ptr->background.green/255, g) *
2465 255.0 + 0.5);
2466 back_1.blue =
2467 (png_byte)(pow((double)png_ptr->background.blue/255, g) *
2468 255.0 + 0.5);
2469 }
2470
2471 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2472 {
2473 png_uint_32 i;
2474
2475 for (i = 0; i < (png_uint_32)num_palette; i++)
2476 {
2477 if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -05002478 {
2479 palette[i] = back;
2480 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002481 else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002482 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002483 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05002484
2485 v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002486 png_composite(w, v, png_ptr->trans[i], back_1.red);
2487 palette[i].red = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002488
2489 v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002490 png_composite(w, v, png_ptr->trans[i], back_1.green);
2491 palette[i].green = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002492
2493 v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002494 png_composite(w, v, png_ptr->trans[i], back_1.blue);
2495 palette[i].blue = png_ptr->gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002496 }
2497 else
2498 {
2499 palette[i].red = png_ptr->gamma_table[palette[i].red];
2500 palette[i].green = png_ptr->gamma_table[palette[i].green];
2501 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2502 }
2503 }
2504 }
2505 else
2506 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002507 int i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002508
2509 for (i = 0; i < num_palette; i++)
2510 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002511 if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002512 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002513 palette[i] = back;
Guy Schalnat0d580581995-07-20 02:43:20 -05002514 }
2515 else
2516 {
2517 palette[i].red = png_ptr->gamma_table[palette[i].red];
2518 palette[i].green = png_ptr->gamma_table[palette[i].green];
2519 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2520 }
2521 }
2522 }
2523 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002524 else
2525#endif
2526#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002527 if (png_ptr->transformations & PNG_GAMMA)
Guy Schalnat0d580581995-07-20 02:43:20 -05002528 {
2529 int i;
2530
2531 for (i = 0; i < num_palette; i++)
2532 {
2533 palette[i].red = png_ptr->gamma_table[palette[i].red];
2534 palette[i].green = png_ptr->gamma_table[palette[i].green];
2535 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
2536 }
2537 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002538#if defined(PNG_READ_BACKGROUND_SUPPORTED)
2539 else
2540#endif
2541#endif
2542#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002543 if (png_ptr->transformations & PNG_BACKGROUND)
Guy Schalnat0d580581995-07-20 02:43:20 -05002544 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002545 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05002546 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002547 png_color back;
Guy Schalnat0d580581995-07-20 02:43:20 -05002548
Guy Schalnate5a37791996-06-05 15:50:50 -05002549 back.red = (png_byte)png_ptr->background.red;
2550 back.green = (png_byte)png_ptr->background.green;
2551 back.blue = (png_byte)png_ptr->background.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002552
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06002553 for (i = 0; i < (int)png_ptr->num_trans; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002554 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002555 if (png_ptr->trans[i] == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -05002556 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002557 palette[i].red = back.red;
2558 palette[i].green = back.green;
2559 palette[i].blue = back.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002560 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002561 else if (png_ptr->trans[i] != 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002562 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002563 png_composite(palette[i].red, png_ptr->palette[i].red,
2564 png_ptr->trans[i], back.red);
2565 png_composite(palette[i].green, png_ptr->palette[i].green,
2566 png_ptr->trans[i], back.green);
2567 png_composite(palette[i].blue, png_ptr->palette[i].blue,
2568 png_ptr->trans[i], back.blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05002569 }
2570 }
2571 }
2572 else /* assume grayscale palette (what else could it be?) */
2573 {
2574 int i;
2575
2576 for (i = 0; i < num_palette; i++)
2577 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002578 if (i == (png_byte)png_ptr->trans_values.gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002579 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002580 palette[i].red = (png_byte)png_ptr->background.red;
2581 palette[i].green = (png_byte)png_ptr->background.green;
2582 palette[i].blue = (png_byte)png_ptr->background.blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002583 }
2584 }
2585 }
2586 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002587#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002588}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002589#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002590
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002591#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002592/* Replace any alpha or transparency with the supplied background color.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002593 * "background" is already in the screen gamma, while "background_1" is
2594 * at a gamma of 1.0. Paletted files have already been taken care of.
2595 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002596void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002597png_do_background(png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002598 png_color_16p trans_values, png_color_16p background
2599#if defined(PNG_READ_GAMMA_SUPPORTED)
2600 , png_color_16p background_1,
Guy Schalnat6d764711995-12-19 03:22:19 -06002601 png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002602 png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002603 png_uint_16pp gamma_16_to_1, int gamma_shift
2604#endif
2605 )
Guy Schalnat0d580581995-07-20 02:43:20 -05002606{
Guy Schalnat6d764711995-12-19 03:22:19 -06002607 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002608 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002609 png_uint_32 row_width=row_info->width;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002610 int shift;
Guy Schalnate5a37791996-06-05 15:50:50 -05002611
Andreas Dilger47a0c421997-05-16 02:46:07 -05002612 png_debug(1, "in png_do_background\n");
2613 if (background != NULL &&
2614#if defined(PNG_USELESS_TESTS_SUPPORTED)
2615 row != NULL && row_info != NULL &&
2616#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002617 (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
Andreas Dilger47a0c421997-05-16 02:46:07 -05002618 (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
Guy Schalnat0d580581995-07-20 02:43:20 -05002619 {
2620 switch (row_info->color_type)
2621 {
2622 case PNG_COLOR_TYPE_GRAY:
2623 {
2624 switch (row_info->bit_depth)
2625 {
2626 case 1:
2627 {
Guy Schalnat0d580581995-07-20 02:43:20 -05002628 sp = row;
2629 shift = 7;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002630 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002631 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002632 if ((png_uint_16)((*sp >> shift) & 0x01)
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002633 == trans_values->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002634 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002635 *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2636 *sp |= (png_byte)(background->gray << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002637 }
2638 if (!shift)
2639 {
2640 shift = 7;
2641 sp++;
2642 }
2643 else
2644 shift--;
2645 }
2646 break;
2647 }
2648 case 2:
2649 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002650#if defined(PNG_READ_GAMMA_SUPPORTED)
2651 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002652 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002653 sp = row;
2654 shift = 6;
2655 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002656 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002657 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002658 == trans_values->gray)
2659 {
2660 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2661 *sp |= (png_byte)(background->gray << shift);
2662 }
2663 else
2664 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002665 png_byte p = (png_byte)((*sp >> shift) & 0x03);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002666 png_byte g = (png_byte)((gamma_table [p | (p << 2) |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002667 (p << 4) | (p << 6)] >> 6) & 0x03);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002668 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2669 *sp |= (png_byte)(g << shift);
2670 }
2671 if (!shift)
2672 {
2673 shift = 6;
2674 sp++;
2675 }
2676 else
2677 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002678 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002679 }
2680 else
2681#endif
2682 {
2683 sp = row;
2684 shift = 6;
2685 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002686 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002687 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002688 == trans_values->gray)
2689 {
2690 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2691 *sp |= (png_byte)(background->gray << shift);
2692 }
2693 if (!shift)
2694 {
2695 shift = 6;
2696 sp++;
2697 }
2698 else
2699 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002700 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002701 }
2702 break;
2703 }
2704 case 4:
2705 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002706#if defined(PNG_READ_GAMMA_SUPPORTED)
2707 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002708 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002709 sp = row;
2710 shift = 4;
2711 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002712 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002713 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002714 == trans_values->gray)
2715 {
2716 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2717 *sp |= (png_byte)(background->gray << shift);
2718 }
2719 else
2720 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002721 png_byte p = (png_byte)((*sp >> shift) & 0x0f);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002722 png_byte g = (png_byte)((gamma_table[p |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002723 (p << 4)] >> 4) & 0x0f);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002724 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2725 *sp |= (png_byte)(g << shift);
2726 }
2727 if (!shift)
2728 {
2729 shift = 4;
2730 sp++;
2731 }
2732 else
2733 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002734 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002735 }
2736 else
2737#endif
2738 {
2739 sp = row;
2740 shift = 4;
2741 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002742 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002743 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002744 == trans_values->gray)
2745 {
2746 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2747 *sp |= (png_byte)(background->gray << shift);
2748 }
2749 if (!shift)
2750 {
2751 shift = 4;
2752 sp++;
2753 }
2754 else
2755 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002756 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002757 }
2758 break;
2759 }
2760 case 8:
2761 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002762#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002763 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002764 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002765 sp = row;
2766 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002767 {
2768 if (*sp == trans_values->gray)
2769 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002770 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002771 }
2772 else
2773 {
2774 *sp = gamma_table[*sp];
2775 }
2776 }
2777 }
2778 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002779#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002780 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002781 sp = row;
2782 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002783 {
2784 if (*sp == trans_values->gray)
2785 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002786 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002787 }
2788 }
2789 }
2790 break;
2791 }
2792 case 16:
2793 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002794#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002795 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002796 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002797 sp = row;
2798 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002799 {
2800 png_uint_16 v;
2801
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002802 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05002803 if (v == trans_values->gray)
2804 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002805 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002806 *sp = (png_byte)((background->gray >> 8) & 0xff);
2807 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002808 }
2809 else
2810 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002811 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002812 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002813 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002814 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002815 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002816 }
2817 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002818#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002819 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002820 sp = row;
2821 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002822 {
2823 png_uint_16 v;
2824
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002825 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05002826 if (v == trans_values->gray)
2827 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002828 *sp = (png_byte)((background->gray >> 8) & 0xff);
2829 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002830 }
2831 }
2832 }
2833 break;
2834 }
2835 }
2836 break;
2837 }
2838 case PNG_COLOR_TYPE_RGB:
2839 {
2840 if (row_info->bit_depth == 8)
2841 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002842#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002843 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002844 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002845 sp = row;
2846 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002847 {
2848 if (*sp == trans_values->red &&
2849 *(sp + 1) == trans_values->green &&
2850 *(sp + 2) == trans_values->blue)
2851 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002852 *sp = (png_byte)background->red;
2853 *(sp + 1) = (png_byte)background->green;
2854 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002855 }
2856 else
2857 {
2858 *sp = gamma_table[*sp];
2859 *(sp + 1) = gamma_table[*(sp + 1)];
2860 *(sp + 2) = gamma_table[*(sp + 2)];
2861 }
2862 }
2863 }
2864 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002865#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002866 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002867 sp = row;
2868 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002869 {
2870 if (*sp == trans_values->red &&
2871 *(sp + 1) == trans_values->green &&
2872 *(sp + 2) == trans_values->blue)
2873 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002874 *sp = (png_byte)background->red;
2875 *(sp + 1) = (png_byte)background->green;
2876 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002877 }
2878 }
2879 }
2880 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002881 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05002882 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002883#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002884 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002885 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002886 sp = row;
2887 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002888 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002889 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2890 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2891 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05002892 if (r == trans_values->red && g == trans_values->green &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002893 b == trans_values->blue)
2894 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002895 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002896 *sp = (png_byte)((background->red >> 8) & 0xff);
2897 *(sp + 1) = (png_byte)(background->red & 0xff);
2898 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2899 *(sp + 3) = (png_byte)(background->green & 0xff);
2900 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2901 *(sp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002902 }
2903 else
2904 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002905 png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002906 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002907 *(sp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002908 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002909 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
2910 *(sp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002911 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002912 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
2913 *(sp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002914 }
2915 }
2916 }
2917 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002918#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002919 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002920 sp = row;
2921 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05002922 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002923 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
2924 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2925 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Guy Schalnat0d580581995-07-20 02:43:20 -05002926
Andreas Dilger47a0c421997-05-16 02:46:07 -05002927 if (r == trans_values->red && g == trans_values->green &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002928 b == trans_values->blue)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002929 {
2930 *sp = (png_byte)((background->red >> 8) & 0xff);
2931 *(sp + 1) = (png_byte)(background->red & 0xff);
2932 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2933 *(sp + 3) = (png_byte)(background->green & 0xff);
2934 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2935 *(sp + 5) = (png_byte)(background->blue & 0xff);
2936 }
2937 }
2938 }
2939 }
2940 break;
2941 }
2942 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -05002943 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002944 if (row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002945 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002946#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002947 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
2948 gamma_table != NULL)
2949 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002950 sp = row;
2951 dp = row;
2952 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002953 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002954 png_uint_16 a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002955
Andreas Dilger47a0c421997-05-16 02:46:07 -05002956 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002957 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002958 *dp = gamma_table[*sp];
2959 }
2960 else if (a == 0)
2961 {
2962 /* background is already in screen gamma */
2963 *dp = (png_byte)background->gray;
2964 }
2965 else
2966 {
2967 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05002968
Andreas Dilger47a0c421997-05-16 02:46:07 -05002969 v = gamma_to_1[*sp];
2970 png_composite(w, v, a, background_1->gray);
2971 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002972 }
2973 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002974 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002975 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002976#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002977 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002978 sp = row;
2979 dp = row;
2980 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002981 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002982 png_byte a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002983
Andreas Dilger47a0c421997-05-16 02:46:07 -05002984 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002985 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002986 *dp = *sp;
2987 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002988#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002989 else if (a == 0)
2990 {
2991 *dp = (png_byte)background->gray;
2992 }
2993 else
2994 {
2995 png_composite(*dp, *sp, a, background_1->gray);
Guy Schalnat0d580581995-07-20 02:43:20 -05002996 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002997#else
2998 *dp = (png_byte)background->gray;
2999#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003000 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003001 }
3002 }
3003 else /* if (png_ptr->bit_depth == 16) */
3004 {
3005#if defined(PNG_READ_GAMMA_SUPPORTED)
3006 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3007 gamma_16_to_1 != NULL)
3008 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003009 sp = row;
3010 dp = row;
3011 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003012 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003013 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003014
Andreas Dilger47a0c421997-05-16 02:46:07 -05003015 if (a == (png_uint_16)0xffff)
3016 {
3017 png_uint_16 v;
3018
3019 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3020 *dp = (png_byte)((v >> 8) & 0xff);
3021 *(dp + 1) = (png_byte)(v & 0xff);
3022 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003023#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003024 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003025#else
3026 else
3027#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003028 {
3029 /* background is already in screen gamma */
3030 *dp = (png_byte)((background->gray >> 8) & 0xff);
3031 *(dp + 1) = (png_byte)(background->gray & 0xff);
3032 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003033#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003034 else
3035 {
3036 png_uint_16 g, v, w;
3037
3038 g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3039 png_composite_16(v, g, a, background_1->gray);
3040 w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
3041 *dp = (png_byte)((w >> 8) & 0xff);
3042 *(dp + 1) = (png_byte)(w & 0xff);
3043 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003044#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003045 }
3046 }
3047 else
3048#endif
3049 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003050 sp = row;
3051 dp = row;
3052 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003053 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003054 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003055 if (a == (png_uint_16)0xffff)
3056 {
3057 png_memcpy(dp, sp, 2);
3058 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003059#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003060 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003061#else
3062 else
3063#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003064 {
3065 *dp = (png_byte)((background->gray >> 8) & 0xff);
3066 *(dp + 1) = (png_byte)(background->gray & 0xff);
3067 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003068#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003069 else
3070 {
3071 png_uint_16 g, v;
3072
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003073 g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003074 png_composite_16(v, g, a, background_1->gray);
3075 *dp = (png_byte)((v >> 8) & 0xff);
3076 *(dp + 1) = (png_byte)(v & 0xff);
3077 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003078#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003079 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003080 }
3081 }
3082 break;
3083 }
3084 case PNG_COLOR_TYPE_RGB_ALPHA:
3085 {
3086 if (row_info->bit_depth == 8)
3087 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003088#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003089 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3090 gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003091 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003092 sp = row;
3093 dp = row;
3094 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003095 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003096 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003097
Guy Schalnat0d580581995-07-20 02:43:20 -05003098 if (a == 0xff)
3099 {
3100 *dp = gamma_table[*sp];
3101 *(dp + 1) = gamma_table[*(sp + 1)];
3102 *(dp + 2) = gamma_table[*(sp + 2)];
3103 }
3104 else if (a == 0)
3105 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003106 /* background is already in screen gamma */
3107 *dp = (png_byte)background->red;
3108 *(dp + 1) = (png_byte)background->green;
3109 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003110 }
3111 else
3112 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003113 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05003114
3115 v = gamma_to_1[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003116 png_composite(w, v, a, background_1->red);
3117 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003118 v = gamma_to_1[*(sp + 1)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003119 png_composite(w, v, a, background_1->green);
3120 *(dp + 1) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003121 v = gamma_to_1[*(sp + 2)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003122 png_composite(w, v, a, background_1->blue);
3123 *(dp + 2) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003124 }
3125 }
3126 }
3127 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003128#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003129 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003130 sp = row;
3131 dp = row;
3132 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003133 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003134 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003135
Guy Schalnat0d580581995-07-20 02:43:20 -05003136 if (a == 0xff)
3137 {
3138 *dp = *sp;
3139 *(dp + 1) = *(sp + 1);
3140 *(dp + 2) = *(sp + 2);
3141 }
3142 else if (a == 0)
3143 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003144 *dp = (png_byte)background->red;
3145 *(dp + 1) = (png_byte)background->green;
3146 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003147 }
3148 else
3149 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003150 png_composite(*dp, *sp, a, background->red);
3151 png_composite(*(dp + 1), *(sp + 1), a,
3152 background->green);
3153 png_composite(*(dp + 2), *(sp + 2), a,
3154 background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003155 }
3156 }
3157 }
3158 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003159 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003160 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003161#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003162 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3163 gamma_16_to_1 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003164 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003165 sp = row;
3166 dp = row;
3167 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003168 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003169 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3170 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003171 if (a == (png_uint_16)0xffff)
3172 {
3173 png_uint_16 v;
3174
Andreas Dilger47a0c421997-05-16 02:46:07 -05003175 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003176 *dp = (png_byte)((v >> 8) & 0xff);
3177 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003178 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003179 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3180 *(dp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003181 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003182 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3183 *(dp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003184 }
3185 else if (a == 0)
3186 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003187 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003188 *dp = (png_byte)((background->red >> 8) & 0xff);
3189 *(dp + 1) = (png_byte)(background->red & 0xff);
3190 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3191 *(dp + 3) = (png_byte)(background->green & 0xff);
3192 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3193 *(dp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003194 }
3195 else
3196 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003197 png_uint_16 v, w, x;
Guy Schalnat0d580581995-07-20 02:43:20 -05003198
Andreas Dilger47a0c421997-05-16 02:46:07 -05003199 v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003200 png_composite_16(w, v, a, background_1->red);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003201 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3202 *dp = (png_byte)((x >> 8) & 0xff);
3203 *(dp + 1) = (png_byte)(x & 0xff);
3204 v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003205 png_composite_16(w, v, a, background_1->green);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003206 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3207 *(dp + 2) = (png_byte)((x >> 8) & 0xff);
3208 *(dp + 3) = (png_byte)(x & 0xff);
3209 v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003210 png_composite_16(w, v, a, background_1->blue);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003211 x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
3212 *(dp + 4) = (png_byte)((x >> 8) & 0xff);
3213 *(dp + 5) = (png_byte)(x & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003214 }
3215 }
3216 }
3217 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003218#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003219 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003220 sp = row;
3221 dp = row;
3222 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003223 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003224 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3225 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003226 if (a == (png_uint_16)0xffff)
3227 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003228 png_memcpy(dp, sp, 6);
Guy Schalnat0d580581995-07-20 02:43:20 -05003229 }
3230 else if (a == 0)
3231 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003232 *dp = (png_byte)((background->red >> 8) & 0xff);
3233 *(dp + 1) = (png_byte)(background->red & 0xff);
3234 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3235 *(dp + 3) = (png_byte)(background->green & 0xff);
3236 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3237 *(dp + 5) = (png_byte)(background->blue & 0xff);
3238 }
3239 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003240 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003241 png_uint_16 v;
Guy Schalnat0d580581995-07-20 02:43:20 -05003242
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003243 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3244 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3245 + *(sp + 3));
3246 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3247 + *(sp + 5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003248
3249 png_composite_16(v, r, a, background->red);
Guy Schalnat0d580581995-07-20 02:43:20 -05003250 *dp = (png_byte)((v >> 8) & 0xff);
3251 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003252 png_composite_16(v, g, a, background->green);
Guy Schalnat0d580581995-07-20 02:43:20 -05003253 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3254 *(dp + 3) = (png_byte)(v & 0xff);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003255 png_composite_16(v, b, a, background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003256 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3257 *(dp + 5) = (png_byte)(v & 0xff);
3258 }
3259 }
3260 }
3261 }
3262 break;
3263 }
3264 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003265
Guy Schalnat0d580581995-07-20 02:43:20 -05003266 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
3267 {
3268 row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
Guy Schalnate5a37791996-06-05 15:50:50 -05003269 row_info->channels--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003270 row_info->pixel_depth = (png_byte)(row_info->channels *
3271 row_info->bit_depth);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003272 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003273 }
3274 }
3275}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003276#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003277
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003278#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003279/* Gamma correct the image, avoiding the alpha channel. Make sure
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003280 * you do this after you deal with the transparency issue on grayscale
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003281 * or RGB images. If your bit depth is 8, use gamma_table, if it
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003282 * is 16, use gamma_16_table and gamma_shift. Build these with
3283 * build_gamma_table().
3284 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003285void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003286png_do_gamma(png_row_infop row_info, png_bytep row,
3287 png_bytep gamma_table, png_uint_16pp gamma_16_table,
Guy Schalnat0d580581995-07-20 02:43:20 -05003288 int gamma_shift)
3289{
Guy Schalnat6d764711995-12-19 03:22:19 -06003290 png_bytep sp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003291 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003292 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003293
Andreas Dilger47a0c421997-05-16 02:46:07 -05003294 png_debug(1, "in png_do_gamma\n");
3295 if (
3296#if defined(PNG_USELESS_TESTS_SUPPORTED)
3297 row != NULL && row_info != NULL &&
3298#endif
3299 ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
3300 (row_info->bit_depth == 16 && gamma_16_table != NULL)))
Guy Schalnat0d580581995-07-20 02:43:20 -05003301 {
3302 switch (row_info->color_type)
3303 {
3304 case PNG_COLOR_TYPE_RGB:
3305 {
3306 if (row_info->bit_depth == 8)
3307 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003308 sp = row;
3309 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003310 {
3311 *sp = gamma_table[*sp];
3312 sp++;
3313 *sp = gamma_table[*sp];
3314 sp++;
3315 *sp = gamma_table[*sp];
3316 sp++;
3317 }
3318 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003319 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003320 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003321 sp = row;
3322 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003323 {
3324 png_uint_16 v;
3325
Andreas Dilger47a0c421997-05-16 02:46:07 -05003326 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003327 *sp = (png_byte)((v >> 8) & 0xff);
3328 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003329 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003330 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003331 *sp = (png_byte)((v >> 8) & 0xff);
3332 *(sp + 1) = (png_byte)(v & 0xff);
3333 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003334 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003335 *sp = (png_byte)((v >> 8) & 0xff);
3336 *(sp + 1) = (png_byte)(v & 0xff);
3337 sp += 2;
3338 }
3339 }
3340 break;
3341 }
3342 case PNG_COLOR_TYPE_RGB_ALPHA:
3343 {
3344 if (row_info->bit_depth == 8)
3345 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003346 sp = row;
3347 for (i = 0; i < row_width; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003348 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003349 *sp = gamma_table[*sp];
3350 sp++;
3351 *sp = gamma_table[*sp];
3352 sp++;
3353 *sp = gamma_table[*sp];
3354 sp++;
3355 sp++;
3356 }
3357 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003358 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003359 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003360 sp = row;
3361 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003362 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003363 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003364 *sp = (png_byte)((v >> 8) & 0xff);
3365 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003366 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003367 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003368 *sp = (png_byte)((v >> 8) & 0xff);
3369 *(sp + 1) = (png_byte)(v & 0xff);
3370 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003371 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003372 *sp = (png_byte)((v >> 8) & 0xff);
3373 *(sp + 1) = (png_byte)(v & 0xff);
3374 sp += 4;
3375 }
3376 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003377 break;
3378 }
3379 case PNG_COLOR_TYPE_GRAY_ALPHA:
3380 {
3381 if (row_info->bit_depth == 8)
3382 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003383 sp = row;
3384 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003385 {
3386 *sp = gamma_table[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003387 sp += 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05003388 }
3389 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003390 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003391 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003392 sp = row;
3393 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003394 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003395 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003396 *sp = (png_byte)((v >> 8) & 0xff);
3397 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003398 sp += 4;
3399 }
3400 }
3401 break;
3402 }
3403 case PNG_COLOR_TYPE_GRAY:
3404 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003405 if (row_info->bit_depth == 2)
3406 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003407 sp = row;
3408 for (i = 0; i < row_width; i += 4)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003409 {
3410 int a = *sp & 0xc0;
3411 int b = *sp & 0x30;
3412 int c = *sp & 0x0c;
3413 int d = *sp & 0x03;
3414
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003415 *sp = (png_byte)(
3416 ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003417 ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
3418 ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003419 ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003420 sp++;
3421 }
3422 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003423 if (row_info->bit_depth == 4)
Guy Schalnat0d580581995-07-20 02:43:20 -05003424 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003425 sp = row;
3426 for (i = 0; i < row_width; i += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003427 {
3428 int msb = *sp & 0xf0;
3429 int lsb = *sp & 0x0f;
3430
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003431 *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
3432 | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003433 sp++;
3434 }
3435 }
3436 else if (row_info->bit_depth == 8)
3437 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003438 sp = row;
3439 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003440 {
3441 *sp = gamma_table[*sp];
3442 sp++;
3443 }
3444 }
3445 else if (row_info->bit_depth == 16)
3446 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003447 sp = row;
3448 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003449 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003450 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003451 *sp = (png_byte)((v >> 8) & 0xff);
3452 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003453 sp += 2;
3454 }
3455 }
3456 break;
3457 }
3458 }
3459 }
3460}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003461#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003462
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003463#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003464/* Expands a palette row to an RGB or RGBA row depending
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003465 * upon whether you supply trans and num_trans.
3466 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003467void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003468png_do_expand_palette(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05003469 png_colorp palette, png_bytep trans, int num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003470{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003471 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003472 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003473 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003474 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003475
Andreas Dilger47a0c421997-05-16 02:46:07 -05003476 png_debug(1, "in png_do_expand_palette\n");
3477 if (
3478#if defined(PNG_USELESS_TESTS_SUPPORTED)
3479 row != NULL && row_info != NULL &&
3480#endif
3481 row_info->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05003482 {
3483 if (row_info->bit_depth < 8)
3484 {
3485 switch (row_info->bit_depth)
3486 {
3487 case 1:
3488 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003489 sp = row + (png_size_t)((row_width - 1) >> 3);
3490 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003491 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003492 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003493 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003494 if ((*sp >> shift) & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -05003495 *dp = 1;
3496 else
3497 *dp = 0;
3498 if (shift == 7)
3499 {
3500 shift = 0;
3501 sp--;
3502 }
3503 else
3504 shift++;
3505
3506 dp--;
3507 }
3508 break;
3509 }
3510 case 2:
3511 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003512 sp = row + (png_size_t)((row_width - 1) >> 2);
3513 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003514 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003515 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003516 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003517 value = (*sp >> shift) & 0x03;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003518 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003519 if (shift == 6)
3520 {
3521 shift = 0;
3522 sp--;
3523 }
3524 else
3525 shift += 2;
3526
3527 dp--;
3528 }
3529 break;
3530 }
3531 case 4:
3532 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003533 sp = row + (png_size_t)((row_width - 1) >> 1);
3534 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003535 shift = (int)((row_width & 0x01) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003536 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003537 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003538 value = (*sp >> shift) & 0x0f;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003539 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003540 if (shift == 4)
3541 {
3542 shift = 0;
3543 sp--;
3544 }
3545 else
3546 shift += 4;
3547
3548 dp--;
3549 }
3550 break;
3551 }
3552 }
3553 row_info->bit_depth = 8;
3554 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003555 row_info->rowbytes = row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003556 }
3557 switch (row_info->bit_depth)
3558 {
3559 case 8:
3560 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003561 if (trans != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003562 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003563 sp = row + (png_size_t)row_width - 1;
3564 dp = row + (png_size_t)(row_width << 2) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003565
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003566 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003567 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003568 if ((int)(*sp) >= num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003569 *dp-- = 0xff;
3570 else
3571 *dp-- = trans[*sp];
3572 *dp-- = palette[*sp].blue;
3573 *dp-- = palette[*sp].green;
3574 *dp-- = palette[*sp].red;
3575 sp--;
3576 }
3577 row_info->bit_depth = 8;
3578 row_info->pixel_depth = 32;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003579 row_info->rowbytes = row_width * 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05003580 row_info->color_type = 6;
3581 row_info->channels = 4;
3582 }
3583 else
3584 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003585 sp = row + (png_size_t)row_width - 1;
3586 dp = row + (png_size_t)(row_width * 3) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003587
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003588 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003589 {
3590 *dp-- = palette[*sp].blue;
3591 *dp-- = palette[*sp].green;
3592 *dp-- = palette[*sp].red;
3593 sp--;
3594 }
3595 row_info->bit_depth = 8;
3596 row_info->pixel_depth = 24;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003597 row_info->rowbytes = row_width * 3;
Guy Schalnat0d580581995-07-20 02:43:20 -05003598 row_info->color_type = 2;
3599 row_info->channels = 3;
3600 }
3601 break;
3602 }
3603 }
3604 }
3605}
3606
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003607/* If the bit depth < 8, it is expanded to 8. Also, if the
3608 * transparency value is supplied, an alpha channel is built.
3609 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003610void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003611png_do_expand(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003612 png_color_16p trans_value)
Guy Schalnat0d580581995-07-20 02:43:20 -05003613{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003614 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003615 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003616 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003617 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003618
Andreas Dilger47a0c421997-05-16 02:46:07 -05003619 png_debug(1, "in png_do_expand\n");
3620#if defined(PNG_USELESS_TESTS_SUPPORTED)
3621 if (row != NULL && row_info != NULL)
3622#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003623 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003624 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05003625 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003626 png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003627
3628 if (row_info->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003629 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003630 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05003631 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003632 case 1:
3633 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003634 gray = (png_uint_16)(gray*0xff);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003635 sp = row + (png_size_t)((row_width - 1) >> 3);
3636 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003637 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003638 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003639 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003640 if ((*sp >> shift) & 0x01)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003641 *dp = 0xff;
3642 else
3643 *dp = 0;
3644 if (shift == 7)
3645 {
3646 shift = 0;
3647 sp--;
3648 }
3649 else
3650 shift++;
3651
3652 dp--;
3653 }
3654 break;
3655 }
3656 case 2:
3657 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003658 gray = (png_uint_16)(gray*0x55);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003659 sp = row + (png_size_t)((row_width - 1) >> 2);
3660 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003661 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003662 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003663 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003664 value = (*sp >> shift) & 0x03;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003665 *dp = (png_byte)(value | (value << 2) | (value << 4) |
3666 (value << 6));
3667 if (shift == 6)
3668 {
3669 shift = 0;
3670 sp--;
3671 }
3672 else
3673 shift += 2;
3674
3675 dp--;
3676 }
3677 break;
3678 }
3679 case 4:
3680 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003681 gray = (png_uint_16)(gray*0x11);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003682 sp = row + (png_size_t)((row_width - 1) >> 1);
3683 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003684 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003685 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003686 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003687 value = (*sp >> shift) & 0x0f;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003688 *dp = (png_byte)(value | (value << 4));
3689 if (shift == 4)
3690 {
3691 shift = 0;
3692 sp--;
3693 }
3694 else
3695 shift = 4;
3696
3697 dp--;
3698 }
3699 break;
3700 }
3701 }
3702 row_info->bit_depth = 8;
3703 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003704 row_info->rowbytes = row_width;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003705 }
3706
Andreas Dilger47a0c421997-05-16 02:46:07 -05003707 if (trans_value != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003708 {
3709 if (row_info->bit_depth == 8)
3710 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003711 sp = row + (png_size_t)row_width - 1;
3712 dp = row + (png_size_t)(row_width << 1) - 1;
3713 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003714 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003715 if (*sp == gray)
3716 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003717 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003718 *dp-- = 0xff;
3719 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003720 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003721 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003722 else if (row_info->bit_depth == 16)
Guy Schalnat0d580581995-07-20 02:43:20 -05003723 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003724 sp = row + row_info->rowbytes - 1;
3725 dp = row + (row_info->rowbytes << 1) - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003726 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003727 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003728 if (((png_uint_16)*(sp) |
3729 ((png_uint_16)*(sp - 1) << 8)) == gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05003730 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003731 *dp-- = 0;
3732 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003733 }
3734 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003735 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003736 *dp-- = 0xff;
3737 *dp-- = 0xff;
Guy Schalnat0d580581995-07-20 02:43:20 -05003738 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003739 *dp-- = *sp--;
3740 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003741 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003742 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003743 row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
3744 row_info->channels = 2;
3745 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003746 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
3747 row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003748 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003749 }
3750 else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
3751 {
3752 if (row_info->bit_depth == 8)
3753 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003754 sp = row + (png_size_t)row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003755 dp = row + (png_size_t)(row_width << 2) - 1;
3756 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003757 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003758 if (*(sp - 2) == trans_value->red &&
Guy Schalnat0d580581995-07-20 02:43:20 -05003759 *(sp - 1) == trans_value->green &&
3760 *(sp - 0) == trans_value->blue)
3761 *dp-- = 0;
3762 else
3763 *dp-- = 0xff;
3764 *dp-- = *sp--;
3765 *dp-- = *sp--;
3766 *dp-- = *sp--;
3767 }
3768 }
3769 else if (row_info->bit_depth == 16)
3770 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003771 sp = row + row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003772 dp = row + (png_size_t)(row_width << 3) - 1;
3773 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003774 {
3775 if ((((png_uint_16)*(sp - 4) |
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003776 ((png_uint_16)*(sp - 5) << 8)) == trans_value->red) &&
Guy Schalnat0d580581995-07-20 02:43:20 -05003777 (((png_uint_16)*(sp - 2) |
3778 ((png_uint_16)*(sp - 3) << 8)) == trans_value->green) &&
3779 (((png_uint_16)*(sp - 0) |
3780 ((png_uint_16)*(sp - 1) << 8)) == trans_value->blue))
3781 {
3782 *dp-- = 0;
3783 *dp-- = 0;
3784 }
3785 else
3786 {
3787 *dp-- = 0xff;
3788 *dp-- = 0xff;
3789 }
3790 *dp-- = *sp--;
3791 *dp-- = *sp--;
3792 *dp-- = *sp--;
3793 *dp-- = *sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003794 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003795 *dp-- = *sp--;
3796 }
3797 }
3798 row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
3799 row_info->channels = 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003800 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003801 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003802 }
3803 }
3804}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003805#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003806
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003807#if defined(PNG_READ_DITHER_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003808void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003809png_do_dither(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003810 png_bytep palette_lookup, png_bytep dither_lookup)
Guy Schalnat0d580581995-07-20 02:43:20 -05003811{
Guy Schalnat6d764711995-12-19 03:22:19 -06003812 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003813 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003814 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003815
Andreas Dilger47a0c421997-05-16 02:46:07 -05003816 png_debug(1, "in png_do_dither\n");
3817#if defined(PNG_USELESS_TESTS_SUPPORTED)
3818 if (row != NULL && row_info != NULL)
3819#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003820 {
3821 if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
3822 palette_lookup && row_info->bit_depth == 8)
3823 {
3824 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003825 sp = row;
3826 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003827 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003828 {
3829 r = *sp++;
3830 g = *sp++;
3831 b = *sp++;
3832
3833 /* this looks real messy, but the compiler will reduce
3834 it down to a reasonable formula. For example, with
3835 5 bits per color, we get:
3836 p = (((r >> 3) & 0x1f) << 10) |
3837 (((g >> 3) & 0x1f) << 5) |
3838 ((b >> 3) & 0x1f);
3839 */
3840 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
3841 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
3842 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3843 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003844 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003845 (PNG_DITHER_BLUE_BITS)) |
3846 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3847 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3848
3849 *dp++ = palette_lookup[p];
3850 }
3851 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3852 row_info->channels = 1;
3853 row_info->pixel_depth = row_info->bit_depth;
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003854 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003855 }
3856 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
Andreas Dilger47a0c421997-05-16 02:46:07 -05003857 palette_lookup != NULL && row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003858 {
3859 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003860 sp = row;
3861 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003862 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003863 {
3864 r = *sp++;
3865 g = *sp++;
3866 b = *sp++;
3867 sp++;
3868
3869 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003870 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003871 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3872 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
3873 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
3874 (PNG_DITHER_BLUE_BITS)) |
3875 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3876 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3877
3878 *dp++ = palette_lookup[p];
3879 }
3880 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3881 row_info->channels = 1;
3882 row_info->pixel_depth = row_info->bit_depth;
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003883 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003884 }
3885 else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
3886 dither_lookup && row_info->bit_depth == 8)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003887 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003888 sp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003889 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003890 {
3891 *sp = dither_lookup[*sp];
3892 }
3893 }
3894 }
3895}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003896#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003897
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003898#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003899#if defined(PNG_READ_GAMMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05003900static int png_gamma_shift[] =
3901 {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0};
3902
Andreas Dilger47a0c421997-05-16 02:46:07 -05003903/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003904 * tables, we don't make a full table if we are reducing to 8-bit in
3905 * the future. Note also how the gamma_16 tables are segmented so that
3906 * we don't need to allocate > 64K chunks for a full 16-bit table.
3907 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003908void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003909png_build_gamma_table(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003910{
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003911 png_debug(1, "in png_build_gamma_table\n");
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003912
3913 if (png_ptr->bit_depth <= 8)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003914 {
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003915 int i;
3916 double g;
Guy Schalnat0d580581995-07-20 02:43:20 -05003917
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003918 if (png_ptr->screen_gamma > .000001)
3919 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
3920 else
3921 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003922
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003923 png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
3924 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05003925
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003926 for (i = 0; i < 256; i++)
3927 {
3928 png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
3929 g) * 255.0 + .5);
3930 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003931
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003932#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003933 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
3934 if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
3935 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003936
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003937 g = 1.0 / (png_ptr->gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05003938
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003939 png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
3940 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05003941
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003942 for (i = 0; i < 256; i++)
3943 {
3944 png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
3945 g) * 255.0 + .5);
3946 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003947
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003948
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003949 png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
3950 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05003951
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003952 if(png_ptr->screen_gamma > 0.000001)
3953 g = 1.0 / png_ptr->screen_gamma;
3954 else
3955 g = png_ptr->gamma; /* probably doing rgb_to_gray */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003956
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003957 for (i = 0; i < 256; i++)
3958 {
3959 png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
3960 g) * 255.0 + .5);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003961
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003962 }
3963 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003964#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003965 }
3966 else
3967 {
3968 double g;
3969 int i, j, shift, num;
3970 int sig_bit;
3971 png_uint_32 ig;
Guy Schalnat0d580581995-07-20 02:43:20 -05003972
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003973 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
3974 {
3975 sig_bit = (int)png_ptr->sig_bit.red;
3976 if ((int)png_ptr->sig_bit.green > sig_bit)
3977 sig_bit = png_ptr->sig_bit.green;
3978 if ((int)png_ptr->sig_bit.blue > sig_bit)
3979 sig_bit = png_ptr->sig_bit.blue;
3980 }
3981 else
3982 {
3983 sig_bit = (int)png_ptr->sig_bit.gray;
3984 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003985
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003986 if (sig_bit > 0)
3987 shift = 16 - sig_bit;
3988 else
3989 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003990
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003991 if (png_ptr->transformations & PNG_16_TO_8)
3992 {
3993 if (shift < (16 - PNG_MAX_GAMMA_8))
3994 shift = (16 - PNG_MAX_GAMMA_8);
3995 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003996
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003997 if (shift > 8)
3998 shift = 8;
3999 if (shift < 0)
4000 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05004001
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004002 png_ptr->gamma_shift = (png_byte)shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05004003
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004004 num = (1 << (8 - shift));
Guy Schalnat0d580581995-07-20 02:43:20 -05004005
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004006 if (png_ptr->screen_gamma > .000001)
4007 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
4008 else
4009 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05004010
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004011 png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
4012 (png_uint_32)(num * png_sizeof (png_uint_16p)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004013
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004014 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
4015 {
4016 double fin, fout;
4017 png_uint_32 last, max;
Guy Schalnat0d580581995-07-20 02:43:20 -05004018
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004019 for (i = 0; i < num; i++)
4020 {
4021 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
4022 (png_uint_32)(256 * png_sizeof (png_uint_16)));
4023 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004024
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004025 g = 1.0 / g;
4026 last = 0;
4027 for (i = 0; i < 256; i++)
4028 {
4029 fout = ((double)i + 0.5) / 256.0;
4030 fin = pow(fout, g);
4031 max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
4032 while (last <= max)
4033 {
4034 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4035 [(int)(last >> (8 - shift))] = (png_uint_16)(
4036 (png_uint_16)i | ((png_uint_16)i << 8));
4037 last++;
4038 }
4039 }
4040 while (last < ((png_uint_32)num << 8))
4041 {
4042 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4043 [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
4044 last++;
4045 }
4046 }
4047 else
4048 {
4049 for (i = 0; i < num; i++)
4050 {
4051 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
4052 (png_uint_32)(256 * png_sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004053
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004054 ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
4055 for (j = 0; j < 256; j++)
4056 {
4057 png_ptr->gamma_16_table[i][j] =
4058 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4059 65535.0, g) * 65535.0 + .5);
4060 }
4061 }
4062 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004063
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004064#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004065 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4066 if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
4067 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004068
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004069 g = 1.0 / (png_ptr->gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05004070
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004071 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
4072 (png_uint_32)(num * png_sizeof (png_uint_16p )));
Guy Schalnat0d580581995-07-20 02:43:20 -05004073
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004074 for (i = 0; i < num; i++)
4075 {
4076 png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
4077 (png_uint_32)(256 * png_sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004078
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004079 ig = (((png_uint_32)i *
4080 (png_uint_32)png_gamma_shift[shift]) >> 4);
4081 for (j = 0; j < 256; j++)
4082 {
4083 png_ptr->gamma_16_to_1[i][j] =
4084 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4085 65535.0, g) * 65535.0 + .5);
4086 }
4087 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004088
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004089 if(png_ptr->screen_gamma > 0.000001)
4090 g = 1.0 / png_ptr->screen_gamma;
4091 else
4092 g = png_ptr->gamma; /* probably doing rgb_to_gray */
Guy Schalnat0d580581995-07-20 02:43:20 -05004093
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004094 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
4095 (png_uint_32)(num * png_sizeof (png_uint_16p)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004096
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004097 for (i = 0; i < num; i++)
4098 {
4099 png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
4100 (png_uint_32)(256 * png_sizeof (png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004101
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004102 ig = (((png_uint_32)i *
4103 (png_uint_32)png_gamma_shift[shift]) >> 4);
4104 for (j = 0; j < 256; j++)
4105 {
4106 png_ptr->gamma_16_from_1[i][j] =
4107 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4108 65535.0, g) * 65535.0 + .5);
4109 }
4110 }
4111 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004112#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004113 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004114}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004115#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06004116/* To do: install integer version of png_build_gamma_table here */
4117#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004118
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004119#if defined(PNG_MNG_FEATURES_SUPPORTED)
4120/* undoes intrapixel differencing */
4121void /* PRIVATE */
4122png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
4123{
4124 png_debug(1, "in png_do_read_intrapixel\n");
4125 if (
4126#if defined(PNG_USELESS_TESTS_SUPPORTED)
4127 row != NULL && row_info != NULL &&
4128#endif
4129 (row_info->color_type & PNG_COLOR_MASK_COLOR))
4130 {
4131 int bytes_per_pixel;
4132 png_uint_32 row_width = row_info->width;
4133 if (row_info->bit_depth == 8)
4134 {
4135 png_bytep rp;
4136 png_uint_32 i;
4137
4138 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4139 bytes_per_pixel = 3;
4140 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4141 bytes_per_pixel = 4;
4142 else
4143 return;
4144
4145 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4146 {
4147 *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff);
4148 *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff);
4149 }
4150 }
4151 else if (row_info->bit_depth == 16)
4152 {
4153 png_bytep rp;
4154 png_uint_32 i;
4155
4156 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4157 bytes_per_pixel = 6;
4158 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4159 bytes_per_pixel = 8;
4160 else
4161 return;
4162
4163 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4164 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05004165 png_uint_32 s0 = (*(rp ) << 8) | *(rp+1);
4166 png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3);
4167 png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5);
4168 png_uint_32 red = (png_uint_32)((s0+s1+65536L) & 0xffffL);
4169 png_uint_32 blue = (png_uint_32)((s2+s1+65536L) & 0xffffL);
4170 *(rp ) = (png_byte)((red >> 8) & 0xff);
4171 *(rp+1) = (png_byte)(red & 0xff);
4172 *(rp+4) = (png_byte)((blue >> 8) & 0xff);
4173 *(rp+5) = (png_byte)(blue & 0xff);
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004174 }
4175 }
4176 }
4177}
4178#endif /* PNG_MNG_FEATURES_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004179#endif /* PNG_READ_SUPPORTED */