blob: 9335c91405b20b1e43a13f0882819ad13df0baf1 [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-Pehrson8fb550c2009-03-21 08:15:32 -05004 * Last changed in libpng 1.4.0 [March 21, 2009]
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06006 * Copyright (c) 1998-2009 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
Guy Schalnat0d580581995-07-20 02:43:20 -050016#include "png.h"
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060017#if defined(PNG_READ_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050018#include "pngpriv.h"
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060019
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060020/* Set the action on getting a CRC error for an ancillary or critical chunk. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050021void PNGAPI
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060022png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
23{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -050024 png_debug(1, "in png_set_crc_action");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060025 /* Tell libpng how we react to CRC errors in critical chunks */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050026 if (png_ptr == NULL) return;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060027 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 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050041 png_warning(png_ptr,
42 "Can't discard critical data on CRC error");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060043 case PNG_CRC_ERROR_QUIT: /* error/quit */
44 case PNG_CRC_DEFAULT:
45 default:
46 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
47 break;
48 }
49
50 switch (ancil_action)
51 {
52 case PNG_CRC_NO_CHANGE: /* leave setting as is */
53 break;
54 case PNG_CRC_WARN_USE: /* warn/use data */
55 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
56 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
57 break;
58 case PNG_CRC_QUIET_USE: /* quiet/use data */
59 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
60 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
61 PNG_FLAG_CRC_ANCILLARY_NOWARN;
62 break;
63 case PNG_CRC_ERROR_QUIT: /* error/quit */
64 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
65 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
66 break;
67 case PNG_CRC_WARN_DISCARD: /* warn/discard data */
68 case PNG_CRC_DEFAULT:
69 default:
70 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
71 break;
72 }
73}
74
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060075#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
76 defined(PNG_FLOATING_POINT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050077/* handle alpha and tRNS via a background color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050078void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060079png_set_background(png_structp png_ptr,
80 png_color_16p background_color, int background_gamma_code,
Guy Schalnat51f0eb41995-09-26 05:22:39 -050081 int need_expand, double background_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -050082{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -050083 png_debug(1, "in png_set_background");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050084 if (png_ptr == NULL) return;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060085 if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
86 {
87 png_warning(png_ptr, "Application must supply a known background gamma");
88 return;
89 }
90
Guy Schalnat0d580581995-07-20 02:43:20 -050091 png_ptr->transformations |= PNG_BACKGROUND;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050092 png_memcpy(&(png_ptr->background), background_color,
93 png_sizeof(png_color_16));
Guy Schalnat51f0eb41995-09-26 05:22:39 -050094 png_ptr->background_gamma = (float)background_gamma;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060095 png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
Guy Schalnate5a37791996-06-05 15:50:50 -050096 png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
Guy Schalnat0d580581995-07-20 02:43:20 -050097}
Guy Schalnat51f0eb41995-09-26 05:22:39 -050098#endif
Guy Schalnat0d580581995-07-20 02:43:20 -050099
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500100#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500101/* strip 16 bit depth files to 8 bit depth */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500102void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600103png_set_strip_16(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500104{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500105 png_debug(1, "in png_set_strip_16");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500106 if (png_ptr == NULL) return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500107 png_ptr->transformations |= PNG_16_TO_8;
108}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500109#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500110
Andreas Dilger47a0c421997-05-16 02:46:07 -0500111#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500112void PNGAPI
Andreas Dilger47a0c421997-05-16 02:46:07 -0500113png_set_strip_alpha(png_structp png_ptr)
114{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500115 png_debug(1, "in png_set_strip_alpha");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500116 if (png_ptr == NULL) return;
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -0600117 png_ptr->flags |= PNG_FLAG_STRIP_ALPHA;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500118}
119#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500120
Glenn Randers-Pehrson41983602008-08-18 21:52:21 -0500121#if defined(PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED)
122void PNGAPI
123png_set_premultiply_alpha(png_structp png_ptr)
124{
Glenn Randers-Pehrsond6d80752008-12-02 09:49:43 -0600125 png_debug(1, "in png_set_premultiply_alpha");
Glenn Randers-Pehrson41983602008-08-18 21:52:21 -0500126 if(png_ptr == NULL) return;
127 png_ptr->transformations |=
128 (PNG_PREMULTIPLY_ALPHA | PNG_EXPAND_tRNS);
129 png_ptr->transformations |=
130 PNG_EXPAND; /* This shouldn't be necessary */
131 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
132}
133#endif
134
Andreas Dilger47a0c421997-05-16 02:46:07 -0500135#if defined(PNG_READ_DITHER_SUPPORTED)
136/* Dither file to 8 bit. Supply a palette, the current number
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600137 * of elements in the palette, the maximum number of elements
138 * allowed, and a histogram if possible. If the current number
139 * of colors is greater then the maximum number, the palette will be
140 * modified to fit in the maximum number. "full_dither" indicates
141 * whether we need a dithering cube set up for RGB images, or if we
142 * simply are reducing the number of colors in a paletted image.
143 */
Guy Schalnat6d764711995-12-19 03:22:19 -0600144
145typedef struct png_dsort_struct
Guy Schalnat0d580581995-07-20 02:43:20 -0500146{
Guy Schalnat6d764711995-12-19 03:22:19 -0600147 struct png_dsort_struct FAR * next;
Guy Schalnat0d580581995-07-20 02:43:20 -0500148 png_byte left;
149 png_byte right;
Guy Schalnat6d764711995-12-19 03:22:19 -0600150} png_dsort;
151typedef png_dsort FAR * png_dsortp;
152typedef png_dsort FAR * FAR * png_dsortpp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500153
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500154void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600155png_set_dither(png_structp png_ptr, png_colorp palette,
156 int num_palette, int maximum_colors, png_uint_16p histogram,
Guy Schalnat0d580581995-07-20 02:43:20 -0500157 int full_dither)
158{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500159 png_debug(1, "in png_set_dither");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500160 if (png_ptr == NULL) return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500161 png_ptr->transformations |= PNG_DITHER;
162
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600163 if (!full_dither)
Guy Schalnat0d580581995-07-20 02:43:20 -0500164 {
165 int i;
166
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600167 png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500168 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500169 for (i = 0; i < num_palette; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600170 png_ptr->dither_index[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500171 }
172
173 if (num_palette > maximum_colors)
174 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500175 if (histogram != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500176 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500177 /* This is easy enough, just throw out the least used colors.
178 Perhaps not the best solution, but good enough. */
Guy Schalnat0d580581995-07-20 02:43:20 -0500179
180 int i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500181
182 /* initialize an array to sort colors */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500183 png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500184 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500185
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500186 /* initialize the dither_sort array */
Guy Schalnat0d580581995-07-20 02:43:20 -0500187 for (i = 0; i < num_palette; i++)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500188 png_ptr->dither_sort[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500189
Andreas Dilger47a0c421997-05-16 02:46:07 -0500190 /* Find the least used palette entries by starting a
Guy Schalnat0d580581995-07-20 02:43:20 -0500191 bubble sort, and running it until we have sorted
192 out enough colors. Note that we don't care about
193 sorting all the colors, just finding which are
194 least used. */
195
196 for (i = num_palette - 1; i >= maximum_colors; i--)
197 {
198 int done; /* to stop early if the list is pre-sorted */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600199 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500200
201 done = 1;
202 for (j = 0; j < i; j++)
203 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500204 if (histogram[png_ptr->dither_sort[j]]
205 < histogram[png_ptr->dither_sort[j + 1]])
Guy Schalnat0d580581995-07-20 02:43:20 -0500206 {
207 png_byte t;
208
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500209 t = png_ptr->dither_sort[j];
210 png_ptr->dither_sort[j] = png_ptr->dither_sort[j + 1];
211 png_ptr->dither_sort[j + 1] = t;
Guy Schalnat0d580581995-07-20 02:43:20 -0500212 done = 0;
213 }
214 }
215 if (done)
216 break;
217 }
218
219 /* swap the palette around, and set up a table, if necessary */
220 if (full_dither)
221 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500222 int j = num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500223
224 /* put all the useful colors within the max, but don't
225 move the others */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500226 for (i = 0; i < maximum_colors; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500227 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500228 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500229 {
230 do
231 j--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500232 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
Guy Schalnat0d580581995-07-20 02:43:20 -0500233 palette[i] = palette[j];
234 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600235 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500236 }
237 else
238 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500239 int j = num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500240
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600241 /* move all the used colors inside the max limit, and
Guy Schalnat0d580581995-07-20 02:43:20 -0500242 develop a translation table */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500243 for (i = 0; i < maximum_colors; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500244 {
245 /* only move the colors we need to */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500246 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500247 {
248 png_color tmp_color;
249
250 do
251 j--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500252 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
Guy Schalnat0d580581995-07-20 02:43:20 -0500253
254 tmp_color = palette[j];
255 palette[j] = palette[i];
256 palette[i] = tmp_color;
257 /* indicate where the color went */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600258 png_ptr->dither_index[j] = (png_byte)i;
259 png_ptr->dither_index[i] = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500260 }
261 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500262
263 /* find closest color for those colors we are not using */
Guy Schalnat0d580581995-07-20 02:43:20 -0500264 for (i = 0; i < num_palette; i++)
265 {
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600266 if ((int)png_ptr->dither_index[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500267 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500268 int min_d, k, min_k, d_index;
Guy Schalnat0d580581995-07-20 02:43:20 -0500269
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600270 /* find the closest color to one we threw out */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500271 d_index = png_ptr->dither_index[i];
272 min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
273 for (k = 1, min_k = 0; k < maximum_colors; k++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500274 {
275 int d;
276
Andreas Dilger47a0c421997-05-16 02:46:07 -0500277 d = PNG_COLOR_DIST(palette[d_index], palette[k]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500278
279 if (d < min_d)
280 {
281 min_d = d;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500282 min_k = k;
Guy Schalnat0d580581995-07-20 02:43:20 -0500283 }
284 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600285 /* point to closest color */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500286 png_ptr->dither_index[i] = (png_byte)min_k;
Guy Schalnat0d580581995-07-20 02:43:20 -0500287 }
288 }
289 }
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500290 png_free(png_ptr, png_ptr->dither_sort);
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500291 png_ptr->dither_sort = NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500292 }
293 else
294 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500295 /* This is much harder to do simply (and quickly). Perhaps
Guy Schalnat0d580581995-07-20 02:43:20 -0500296 we need to go through a median cut routine, but those
297 don't always behave themselves with only a few colors
298 as input. So we will just find the closest two colors,
299 and throw out one of them (chosen somewhat randomly).
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600300 [We don't understand this at all, so if someone wants to
301 work on improving it, be our guest - AED, GRP]
Guy Schalnat0d580581995-07-20 02:43:20 -0500302 */
303 int i;
304 int max_d;
305 int num_new_palette;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500306 png_dsortp t;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600307 png_dsortpp hash;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500308
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500309 t = NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500310
311 /* initialize palette index arrays */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500312 png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500313 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500314 png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500315 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500316
317 /* initialize the sort array */
318 for (i = 0; i < num_palette; i++)
319 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500320 png_ptr->index_to_palette[i] = (png_byte)i;
321 png_ptr->palette_to_index[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500322 }
323
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -0600324#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600325 hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 *
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500326 png_sizeof(png_dsortp)));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -0600327#else
328 hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 *
329 png_sizeof(png_dsortp)));
330 png_memset(hash, 0, 769 * png_sizeof(png_dsortp));
331#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500332
333 num_new_palette = num_palette;
334
335 /* initial wild guess at how far apart the farthest pixel
336 pair we will be eliminating will be. Larger
337 numbers mean more areas will be allocated, Smaller
338 numbers run the risk of not saving enough data, and
339 having to do this all over again.
340
341 I have not done extensive checking on this number.
342 */
343 max_d = 96;
344
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600345 while (num_new_palette > maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500346 {
347 for (i = 0; i < num_new_palette - 1; i++)
348 {
349 int j;
350
351 for (j = i + 1; j < num_new_palette; j++)
352 {
353 int d;
354
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600355 d = PNG_COLOR_DIST(palette[i], palette[j]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500356
357 if (d <= max_d)
358 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500359
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500360 t = (png_dsortp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500361 (png_uint_32)(png_sizeof(png_dsort)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500362 if (t == NULL)
363 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500364 t->next = hash[d];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600365 t->left = (png_byte)i;
366 t->right = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500367 hash[d] = t;
368 }
369 }
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500370 if (t == NULL)
371 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500372 }
373
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500374 if (t != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500375 for (i = 0; i <= max_d; i++)
376 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500377 if (hash[i] != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500378 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600379 png_dsortp p;
Guy Schalnat0d580581995-07-20 02:43:20 -0500380
381 for (p = hash[i]; p; p = p->next)
382 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500383 if ((int)png_ptr->index_to_palette[p->left]
384 < num_new_palette &&
385 (int)png_ptr->index_to_palette[p->right]
386 < num_new_palette)
Guy Schalnat0d580581995-07-20 02:43:20 -0500387 {
388 int j, next_j;
389
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600390 if (num_new_palette & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -0500391 {
392 j = p->left;
393 next_j = p->right;
394 }
395 else
396 {
397 j = p->right;
398 next_j = p->left;
399 }
400
401 num_new_palette--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500402 palette[png_ptr->index_to_palette[j]]
403 = palette[num_new_palette];
Guy Schalnat0d580581995-07-20 02:43:20 -0500404 if (!full_dither)
405 {
406 int k;
407
408 for (k = 0; k < num_palette; k++)
409 {
410 if (png_ptr->dither_index[k] ==
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500411 png_ptr->index_to_palette[j])
Guy Schalnat0d580581995-07-20 02:43:20 -0500412 png_ptr->dither_index[k] =
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500413 png_ptr->index_to_palette[next_j];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600414 if ((int)png_ptr->dither_index[k] ==
Guy Schalnat0d580581995-07-20 02:43:20 -0500415 num_new_palette)
416 png_ptr->dither_index[k] =
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500417 png_ptr->index_to_palette[j];
Guy Schalnat0d580581995-07-20 02:43:20 -0500418 }
419 }
420
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500421 png_ptr->index_to_palette[png_ptr->palette_to_index
422 [num_new_palette]] = png_ptr->index_to_palette[j];
423 png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
424 = png_ptr->palette_to_index[num_new_palette];
Guy Schalnat0d580581995-07-20 02:43:20 -0500425
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500426 png_ptr->index_to_palette[j] = (png_byte)num_new_palette;
427 png_ptr->palette_to_index[num_new_palette] = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500428 }
429 if (num_new_palette <= maximum_colors)
430 break;
431 }
432 if (num_new_palette <= maximum_colors)
433 break;
434 }
435 }
436
437 for (i = 0; i < 769; i++)
438 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500439 if (hash[i] != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500440 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500441 png_dsortp p = hash[i];
Guy Schalnat0d580581995-07-20 02:43:20 -0500442 while (p)
443 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500444 t = p->next;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600445 png_free(png_ptr, p);
Guy Schalnat0d580581995-07-20 02:43:20 -0500446 p = t;
447 }
448 }
449 hash[i] = 0;
450 }
451 max_d += 96;
452 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600453 png_free(png_ptr, hash);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500454 png_free(png_ptr, png_ptr->palette_to_index);
455 png_free(png_ptr, png_ptr->index_to_palette);
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500456 png_ptr->palette_to_index = NULL;
457 png_ptr->index_to_palette = NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500458 }
459 num_palette = maximum_colors;
460 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500461 if (png_ptr->palette == NULL)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600462 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500463 png_ptr->palette = palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500464 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600465 png_ptr->num_palette = (png_uint_16)num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500466
467 if (full_dither)
468 {
469 int i;
Guy Schalnat6d764711995-12-19 03:22:19 -0600470 png_bytep distance;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500471 int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600472 PNG_DITHER_BLUE_BITS;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500473 int num_red = (1 << PNG_DITHER_RED_BITS);
474 int num_green = (1 << PNG_DITHER_GREEN_BITS);
475 int num_blue = (1 << PNG_DITHER_BLUE_BITS);
476 png_size_t num_entries = ((png_size_t)1 << total_bits);
Guy Schalnat0d580581995-07-20 02:43:20 -0500477
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -0600478#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600479 png_ptr->palette_lookup = (png_bytep )png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500480 (png_uint_32)(num_entries * png_sizeof(png_byte)));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -0600481#else
482 png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
483 (png_uint_32)(num_entries * png_sizeof(png_byte)));
484 png_memset(png_ptr->palette_lookup, 0, num_entries *
485 png_sizeof(png_byte));
486#endif
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500487
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500488 distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
489 png_sizeof(png_byte)));
Glenn Randers-Pehrsone1eff582001-04-14 20:15:41 -0500490
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500491 png_memset(distance, 0xff, num_entries * png_sizeof(png_byte));
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500492
493 for (i = 0; i < num_palette; i++)
494 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500495 int ir, ig, ib;
496 int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
497 int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
498 int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
Guy Schalnat0d580581995-07-20 02:43:20 -0500499
500 for (ir = 0; ir < num_red; ir++)
501 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500502 /* int dr = abs(ir - r); */
503 int dr = ((ir > r) ? ir - r : r - ir);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500504 int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
Guy Schalnat0d580581995-07-20 02:43:20 -0500505
Guy Schalnat0d580581995-07-20 02:43:20 -0500506 for (ig = 0; ig < num_green; ig++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600507 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500508 /* int dg = abs(ig - g); */
509 int dg = ((ig > g) ? ig - g : g - ig);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500510 int dt = dr + dg;
511 int dm = ((dr > dg) ? dr : dg);
512 int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
Guy Schalnat0d580581995-07-20 02:43:20 -0500513
Guy Schalnat0d580581995-07-20 02:43:20 -0500514 for (ib = 0; ib < num_blue; ib++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600515 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500516 int d_index = index_g | ib;
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500517 /* int db = abs(ib - b); */
518 int db = ((ib > b) ? ib - b : b - ib);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500519 int dmax = ((dm > db) ? dm : db);
520 int d = dmax + dt + db;
Guy Schalnat0d580581995-07-20 02:43:20 -0500521
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600522 if (d < (int)distance[d_index])
Guy Schalnat0d580581995-07-20 02:43:20 -0500523 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500524 distance[d_index] = (png_byte)d;
525 png_ptr->palette_lookup[d_index] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500526 }
527 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500528 }
529 }
530 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500531
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600532 png_free(png_ptr, distance);
Guy Schalnat0d580581995-07-20 02:43:20 -0500533 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500534}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500535#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500536
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600537#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600538/* Transform the image from the file_gamma to the screen_gamma. We
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600539 * only do transformations on images where the file_gamma and screen_gamma
540 * are not close reciprocals, otherwise it slows things down slightly, and
541 * also needlessly introduces small errors.
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600542 *
543 * We will turn off gamma transformation later if no semitransparent entries
544 * are present in the tRNS array for palette images. We can't do it here
545 * because we don't necessarily have the tRNS chunk yet.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600546 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500547void PNGAPI
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600548png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -0500549{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500550 png_debug(1, "in png_set_gamma");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500551 if (png_ptr == NULL) return;
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600552 if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) ||
553 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) ||
554 (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
555 png_ptr->transformations |= PNG_GAMMA;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500556 png_ptr->gamma = (float)file_gamma;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600557 png_ptr->screen_gamma = (float)scrn_gamma;
Guy Schalnat0d580581995-07-20 02:43:20 -0500558}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500559#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500560
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500561#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -0500562/* Expand paletted images to RGB, expand grayscale images of
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500563 * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600564 * to alpha channels.
565 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500566void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600567png_set_expand(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500568{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500569 png_debug(1, "in png_set_expand");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500570 if (png_ptr == NULL) return;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600571 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500572 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -0500573}
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500574
575/* GRR 19990627: the following three functions currently are identical
576 * to png_set_expand(). However, it is entirely reasonable that someone
577 * might wish to expand an indexed image to RGB but *not* expand a single,
578 * fully transparent palette entry to a full alpha channel--perhaps instead
579 * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
580 * the transparent color with a particular RGB value, or drop tRNS entirely.
581 * IOW, a future version of the library may make the transformations flag
582 * a bit more fine-grained, with separate bits for each of these three
583 * functions.
584 *
585 * More to the point, these functions make it obvious what libpng will be
586 * doing, whereas "expand" can (and does) mean any number of things.
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600587 *
588 * GRP 20060307: In libpng-1.4.0, png_set_gray_1_2_4_to_8() was modified
589 * to expand only the sample depth but not to expand the tRNS to alpha.
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500590 */
591
592/* Expand paletted images to RGB. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500593void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500594png_set_palette_to_rgb(png_structp png_ptr)
595{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500596 png_debug(1, "in png_set_palette_to_rgb");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500597 if (png_ptr == NULL) return;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600598 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500599 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500600}
601
602/* Expand grayscale images of less than 8-bit depth to 8 bits. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500603void PNGAPI
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600604png_set_expand_gray_1_2_4_to_8(png_structp png_ptr)
605{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500606 png_debug(1, "in png_set_expand_gray_1_2_4_to_8");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500607 if (png_ptr == NULL) return;
608 png_ptr->transformations |= PNG_EXPAND;
609 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600610}
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500611
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500612
613
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500614/* Expand tRNS chunks to alpha channels. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500615void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500616png_set_tRNS_to_alpha(png_structp png_ptr)
617{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500618 png_debug(1, "in png_set_tRNS_to_alpha");
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600619 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500620 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500621}
622#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500623
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500624#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500625void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600626png_set_gray_to_rgb(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500627{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500628 png_debug(1, "in png_set_gray_to_rgb");
Guy Schalnat0d580581995-07-20 02:43:20 -0500629 png_ptr->transformations |= PNG_GRAY_TO_RGB;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500630 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -0500631}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500632#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500633
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600634#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
635#if defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600636/* Convert a RGB image to a grayscale of the same width. This allows us,
637 * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600638 */
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600639
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500640void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500641png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red,
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600642 double green)
643{
644 int red_fixed = (int)((float)red*100000.0 + 0.5);
645 int green_fixed = (int)((float)green*100000.0 + 0.5);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500646 if (png_ptr == NULL) return;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600647 png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed);
648}
649#endif
650
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500651void PNGAPI
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600652png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
653 png_fixed_point red, png_fixed_point green)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600654{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500655 png_debug(1, "in png_set_rgb_to_gray");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500656 if (png_ptr == NULL) return;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600657 switch(error_action)
658 {
659 case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY;
660 break;
661 case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
662 break;
663 case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
664 }
665 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
666#if defined(PNG_READ_EXPAND_SUPPORTED)
667 png_ptr->transformations |= PNG_EXPAND;
668#else
669 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500670 png_warning(png_ptr,
671 "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED");
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600672 png_ptr->transformations &= ~PNG_RGB_TO_GRAY;
673 }
674#endif
675 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600676 png_uint_16 red_int, green_int;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500677 if (red < 0 || green < 0)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600678 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600679 red_int = 6968; /* .212671 * 32768 + .5 */
680 green_int = 23434; /* .715160 * 32768 + .5 */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600681 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500682 else if (red + green < 100000L)
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600683 {
684 red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
685 green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
686 }
687 else
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600688 {
689 png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600690 red_int = 6968;
691 green_int = 23434;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600692 }
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600693 png_ptr->rgb_to_gray_red_coeff = red_int;
694 png_ptr->rgb_to_gray_green_coeff = green_int;
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600695 png_ptr->rgb_to_gray_blue_coeff =
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500696 (png_uint_16)(32768 - red_int - green_int);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600697 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600698}
699#endif
700
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500701#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
702 defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
703 defined(PNG_LEGACY_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500704void PNGAPI
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600705png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
706 read_user_transform_fn)
707{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500708 png_debug(1, "in png_set_read_user_transform_fn");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500709 if (png_ptr == NULL) return;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500710#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600711 png_ptr->transformations |= PNG_USER_TRANSFORM;
712 png_ptr->read_user_transform_fn = read_user_transform_fn;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500713#endif
714#ifdef PNG_LEGACY_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500715 if (read_user_transform_fn)
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500716 png_warning(png_ptr,
717 "This version of libpng does not support user transforms");
718#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600719}
720#endif
721
Andreas Dilger47a0c421997-05-16 02:46:07 -0500722/* Initialize everything needed for the read. This includes modifying
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600723 * the palette.
724 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500725void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -0600726png_init_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500727{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500728 png_debug(1, "in png_init_read_transformations");
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500729 {
730#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
731 || defined(PNG_READ_GAMMA_SUPPORTED)
732 int color_type = png_ptr->color_type;
733#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500734
Guy Schalnate5a37791996-06-05 15:50:50 -0500735#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500736
737#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
738 /* Detect gray background and attempt to enable optimization
739 * for gray --> RGB case */
740 /* Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
741 * RGB_ALPHA (in which case need_expand is superfluous anyway), the
742 * background color might actually be gray yet not be flagged as such.
743 * This is not a problem for the current code, which uses
744 * PNG_BACKGROUND_IS_GRAY only to decide when to do the
745 * png_do_gray_to_rgb() transformation.
746 */
747 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
748 !(color_type & PNG_COLOR_MASK_COLOR))
749 {
750 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
751 } else if ((png_ptr->transformations & PNG_BACKGROUND) &&
752 !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
753 (png_ptr->transformations & PNG_GRAY_TO_RGB) &&
754 png_ptr->background.red == png_ptr->background.green &&
755 png_ptr->background.red == png_ptr->background.blue)
756 {
757 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
758 png_ptr->background.gray = png_ptr->background.red;
759 }
760#endif
761
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600762 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
763 (png_ptr->transformations & PNG_EXPAND))
Guy Schalnat0d580581995-07-20 02:43:20 -0500764 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500765 if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
Guy Schalnat0d580581995-07-20 02:43:20 -0500766 {
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600767 /* expand background and tRNS chunks */
Guy Schalnat0d580581995-07-20 02:43:20 -0500768 switch (png_ptr->bit_depth)
769 {
770 case 1:
Guy Schalnate5a37791996-06-05 15:50:50 -0500771 png_ptr->background.gray *= (png_uint_16)0xff;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600772 png_ptr->background.red = png_ptr->background.green
773 = png_ptr->background.blue = png_ptr->background.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600774 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
775 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -0500776 png_ptr->trans_color.gray *= (png_uint_16)0xff;
777 png_ptr->trans_color.red = png_ptr->trans_color.green
778 = png_ptr->trans_color.blue = png_ptr->trans_color.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600779 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500780 break;
781 case 2:
Guy Schalnate5a37791996-06-05 15:50:50 -0500782 png_ptr->background.gray *= (png_uint_16)0x55;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600783 png_ptr->background.red = png_ptr->background.green
784 = png_ptr->background.blue = png_ptr->background.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600785 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
786 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -0500787 png_ptr->trans_color.gray *= (png_uint_16)0x55;
788 png_ptr->trans_color.red = png_ptr->trans_color.green
789 = png_ptr->trans_color.blue = png_ptr->trans_color.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600790 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500791 break;
792 case 4:
Guy Schalnate5a37791996-06-05 15:50:50 -0500793 png_ptr->background.gray *= (png_uint_16)0x11;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600794 png_ptr->background.red = png_ptr->background.green
795 = png_ptr->background.blue = png_ptr->background.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600796 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
797 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -0500798 png_ptr->trans_color.gray *= (png_uint_16)0x11;
799 png_ptr->trans_color.red = png_ptr->trans_color.green
800 = png_ptr->trans_color.blue = png_ptr->trans_color.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600801 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500802 break;
803 case 8:
804 case 16:
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600805 png_ptr->background.red = png_ptr->background.green
806 = png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500807 break;
808 }
809 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500810 else if (color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -0500811 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500812 png_ptr->background.red =
Guy Schalnat0d580581995-07-20 02:43:20 -0500813 png_ptr->palette[png_ptr->background.index].red;
814 png_ptr->background.green =
815 png_ptr->palette[png_ptr->background.index].green;
Guy Schalnate5a37791996-06-05 15:50:50 -0500816 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -0500817 png_ptr->palette[png_ptr->background.index].blue;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600818
819#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
820 if (png_ptr->transformations & PNG_INVERT_ALPHA)
821 {
822#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600823 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600824#endif
825 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600826 /* invert the alpha channel (in tRNS) unless the pixels are
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600827 going to be expanded, in which case leave it for later */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500828 int i, istop;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500829 istop=(int)png_ptr->num_trans;
830 for (i=0; i<istop; i++)
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -0500831 png_ptr->trans[i] = (png_byte)(255 - png_ptr->trans[i]);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600832 }
833 }
834#endif
835
Guy Schalnat0d580581995-07-20 02:43:20 -0500836 }
837 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500838#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500839
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500840#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500841 png_ptr->background_1 = png_ptr->background;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500842#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600843#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600844
845 if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0)
846 && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0)
847 < PNG_GAMMA_THRESHOLD))
848 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500849 int i, k;
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600850 k=0;
851 for (i=0; i<png_ptr->num_trans; i++)
852 {
853 if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff)
854 k=1; /* partial transparency is present */
855 }
856 if (k == 0)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500857 png_ptr->transformations &= ~PNG_GAMMA;
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600858 }
859
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600860 if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) &&
861 png_ptr->gamma != 0.0)
Guy Schalnat0d580581995-07-20 02:43:20 -0500862 {
863 png_build_gamma_table(png_ptr);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500864#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Guy Schalnate5a37791996-06-05 15:50:50 -0500865 if (png_ptr->transformations & PNG_BACKGROUND)
Guy Schalnat0d580581995-07-20 02:43:20 -0500866 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500867 if (color_type == PNG_COLOR_TYPE_PALETTE)
868 {
Glenn Randers-Pehrsone6474622006-03-04 16:50:47 -0600869 /* could skip if no transparency and
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600870 */
Guy Schalnate5a37791996-06-05 15:50:50 -0500871 png_color back, back_1;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500872 png_colorp palette = png_ptr->palette;
873 int num_palette = png_ptr->num_palette;
874 int i;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500875 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
876 {
877 back.red = png_ptr->gamma_table[png_ptr->background.red];
878 back.green = png_ptr->gamma_table[png_ptr->background.green];
879 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
Guy Schalnate5a37791996-06-05 15:50:50 -0500880
Andreas Dilger47a0c421997-05-16 02:46:07 -0500881 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
882 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
883 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
884 }
885 else
886 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600887 double g, gs;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500888
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600889 switch (png_ptr->background_gamma_type)
Glenn Randers-Pehrson4922b1b1998-03-08 22:55:17 -0600890 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600891 case PNG_BACKGROUND_GAMMA_SCREEN:
892 g = (png_ptr->screen_gamma);
893 gs = 1.0;
894 break;
895 case PNG_BACKGROUND_GAMMA_FILE:
896 g = 1.0 / (png_ptr->gamma);
897 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
898 break;
899 case PNG_BACKGROUND_GAMMA_UNIQUE:
900 g = 1.0 / (png_ptr->background_gamma);
901 gs = 1.0 / (png_ptr->background_gamma *
902 png_ptr->screen_gamma);
903 break;
904 default:
905 g = 1.0; /* back_1 */
906 gs = 1.0; /* back */
907 }
908
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -0600909 if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD)
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600910 {
911 back.red = (png_byte)png_ptr->background.red;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500912 back.green = (png_byte)png_ptr->background.green;
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600913 back.blue = (png_byte)png_ptr->background.blue;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500914 }
915 else
916 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600917 back.red = (png_byte)(pow(
918 (double)png_ptr->background.red/255, gs) * 255.0 + .5);
919 back.green = (png_byte)(pow(
920 (double)png_ptr->background.green/255, gs) * 255.0 + .5);
921 back.blue = (png_byte)(pow(
922 (double)png_ptr->background.blue/255, gs) * 255.0 + .5);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500923 }
924
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600925 back_1.red = (png_byte)(pow(
926 (double)png_ptr->background.red/255, g) * 255.0 + .5);
927 back_1.green = (png_byte)(pow(
928 (double)png_ptr->background.green/255, g) * 255.0 + .5);
929 back_1.blue = (png_byte)(pow(
930 (double)png_ptr->background.blue/255, g) * 255.0 + .5);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500931 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500932 for (i = 0; i < num_palette; i++)
933 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500934 if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
Guy Schalnate5a37791996-06-05 15:50:50 -0500935 {
936 if (png_ptr->trans[i] == 0)
937 {
938 palette[i] = back;
939 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500940 else /* if (png_ptr->trans[i] != 0xff) */
Guy Schalnate5a37791996-06-05 15:50:50 -0500941 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500942 png_byte v, w;
Guy Schalnate5a37791996-06-05 15:50:50 -0500943
944 v = png_ptr->gamma_to_1[palette[i].red];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500945 png_composite(w, v, png_ptr->trans[i], back_1.red);
Guy Schalnate5a37791996-06-05 15:50:50 -0500946 palette[i].red = png_ptr->gamma_from_1[w];
947
948 v = png_ptr->gamma_to_1[palette[i].green];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500949 png_composite(w, v, png_ptr->trans[i], back_1.green);
Guy Schalnate5a37791996-06-05 15:50:50 -0500950 palette[i].green = png_ptr->gamma_from_1[w];
951
952 v = png_ptr->gamma_to_1[palette[i].blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500953 png_composite(w, v, png_ptr->trans[i], back_1.blue);
Guy Schalnate5a37791996-06-05 15:50:50 -0500954 palette[i].blue = png_ptr->gamma_from_1[w];
955 }
956 }
957 else
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 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500964 /* Prevent the transformations being done again, and make sure
965 * that the now spurious alpha channel is stripped - the code
966 * has just reduced background composition and gamma correction
967 * to a simple alpha channel strip.
968 */
969 png_ptr->transformations &= ~PNG_BACKGROUND;
970 png_ptr->transformations &= ~PNG_GAMMA;
971 png_ptr->transformations |= PNG_STRIP_ALPHA;
Guy Schalnate5a37791996-06-05 15:50:50 -0500972 }
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -0500973 /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600974 else
975 /* color_type != PNG_COLOR_TYPE_PALETTE */
Guy Schalnat0d580581995-07-20 02:43:20 -0500976 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500977 double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
978 double g = 1.0;
979 double gs = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500980
981 switch (png_ptr->background_gamma_type)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600982 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500983 case PNG_BACKGROUND_GAMMA_SCREEN:
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600984 g = (png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500985 gs = 1.0;
986 break;
987 case PNG_BACKGROUND_GAMMA_FILE:
988 g = 1.0 / (png_ptr->gamma);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600989 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500990 break;
991 case PNG_BACKGROUND_GAMMA_UNIQUE:
992 g = 1.0 / (png_ptr->background_gamma);
993 gs = 1.0 / (png_ptr->background_gamma *
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600994 png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500995 break;
996 }
997
Glenn Randers-Pehrson377657d2002-03-08 01:31:27 -0600998 png_ptr->background_1.gray = (png_uint_16)(pow(
999 (double)png_ptr->background.gray / m, g) * m + .5);
1000 png_ptr->background.gray = (png_uint_16)(pow(
1001 (double)png_ptr->background.gray / m, gs) * m + .5);
1002
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06001003 if ((png_ptr->background.red != png_ptr->background.green) ||
1004 (png_ptr->background.red != png_ptr->background.blue) ||
1005 (png_ptr->background.red != png_ptr->background.gray))
Guy Schalnat0d580581995-07-20 02:43:20 -05001006 {
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06001007 /* RGB or RGBA with color background */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001008 png_ptr->background_1.red = (png_uint_16)(pow(
Guy Schalnat0d580581995-07-20 02:43:20 -05001009 (double)png_ptr->background.red / m, g) * m + .5);
1010 png_ptr->background_1.green = (png_uint_16)(pow(
1011 (double)png_ptr->background.green / m, g) * m + .5);
1012 png_ptr->background_1.blue = (png_uint_16)(pow(
1013 (double)png_ptr->background.blue / m, g) * m + .5);
1014 png_ptr->background.red = (png_uint_16)(pow(
1015 (double)png_ptr->background.red / m, gs) * m + .5);
1016 png_ptr->background.green = (png_uint_16)(pow(
1017 (double)png_ptr->background.green / m, gs) * m + .5);
1018 png_ptr->background.blue = (png_uint_16)(pow(
1019 (double)png_ptr->background.blue / m, gs) * m + .5);
1020 }
1021 else
1022 {
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06001023 /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */
1024 png_ptr->background_1.red = png_ptr->background_1.green
1025 = png_ptr->background_1.blue = png_ptr->background_1.gray;
1026 png_ptr->background.red = png_ptr->background.green
1027 = png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05001028 }
1029 }
1030 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001031 else
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001032 /* transformation does not include PNG_BACKGROUND */
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001033#endif /* PNG_READ_BACKGROUND_SUPPORTED */
Guy Schalnate5a37791996-06-05 15:50:50 -05001034 if (color_type == PNG_COLOR_TYPE_PALETTE)
1035 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001036 png_colorp palette = png_ptr->palette;
1037 int num_palette = png_ptr->num_palette;
1038 int i;
Guy Schalnate5a37791996-06-05 15:50:50 -05001039
1040 for (i = 0; i < num_palette; i++)
1041 {
1042 palette[i].red = png_ptr->gamma_table[palette[i].red];
1043 palette[i].green = png_ptr->gamma_table[palette[i].green];
1044 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
1045 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001046
1047 /* Done the gamma correction. */
1048 png_ptr->transformations &= ~PNG_GAMMA;
Guy Schalnate5a37791996-06-05 15:50:50 -05001049 }
1050 }
1051#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1052 else
1053#endif
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001054#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */
Guy Schalnate5a37791996-06-05 15:50:50 -05001055#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001056 /* No GAMMA transformation */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001057 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1058 (color_type == PNG_COLOR_TYPE_PALETTE))
Guy Schalnate5a37791996-06-05 15:50:50 -05001059 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001060 int i;
1061 int istop = (int)png_ptr->num_trans;
Guy Schalnate5a37791996-06-05 15:50:50 -05001062 png_color back;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001063 png_colorp palette = png_ptr->palette;
Guy Schalnate5a37791996-06-05 15:50:50 -05001064
Guy Schalnate5a37791996-06-05 15:50:50 -05001065 back.red = (png_byte)png_ptr->background.red;
1066 back.green = (png_byte)png_ptr->background.green;
1067 back.blue = (png_byte)png_ptr->background.blue;
1068
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001069 for (i = 0; i < istop; i++)
Guy Schalnate5a37791996-06-05 15:50:50 -05001070 {
1071 if (png_ptr->trans[i] == 0)
1072 {
1073 palette[i] = back;
1074 }
1075 else if (png_ptr->trans[i] != 0xff)
1076 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001077 /* The png_composite() macro is defined in png.h */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001078 png_composite(palette[i].red, palette[i].red,
1079 png_ptr->trans[i], back.red);
1080 png_composite(palette[i].green, palette[i].green,
1081 png_ptr->trans[i], back.green);
1082 png_composite(palette[i].blue, palette[i].blue,
1083 png_ptr->trans[i], back.blue);
Guy Schalnate5a37791996-06-05 15:50:50 -05001084 }
1085 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001086
1087 /* Handled alpha, still need to strip the channel. */
1088 png_ptr->transformations &= ~PNG_BACKGROUND;
1089 png_ptr->transformations |= PNG_STRIP_ALPHA;
Guy Schalnat0d580581995-07-20 02:43:20 -05001090 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001091#endif /* PNG_READ_BACKGROUND_SUPPORTED */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001092
Guy Schalnat6d764711995-12-19 03:22:19 -06001093#if defined(PNG_READ_SHIFT_SUPPORTED)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001094 if ((png_ptr->transformations & PNG_SHIFT) &&
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001095 (color_type == PNG_COLOR_TYPE_PALETTE))
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001096 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001097 png_uint_16 i;
1098 png_uint_16 istop = png_ptr->num_palette;
1099 int sr = 8 - png_ptr->sig_bit.red;
1100 int sg = 8 - png_ptr->sig_bit.green;
1101 int sb = 8 - png_ptr->sig_bit.blue;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001102
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001103 if (sr < 0 || sr > 8)
1104 sr = 0;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001105 if (sg < 0 || sg > 8)
1106 sg = 0;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001107 if (sb < 0 || sb > 8)
1108 sb = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001109 for (i = 0; i < istop; i++)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001110 {
1111 png_ptr->palette[i].red >>= sr;
1112 png_ptr->palette[i].green >>= sg;
1113 png_ptr->palette[i].blue >>= sb;
1114 }
1115 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001116#endif /* PNG_READ_SHIFT_SUPPORTED */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001117 }
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001118#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \
1119 && !defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001120 if (png_ptr)
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001121 return;
1122#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001123}
1124
Andreas Dilger47a0c421997-05-16 02:46:07 -05001125/* Modify the info structure to reflect the transformations. The
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001126 * info should be updated so a PNG file could be written with it,
1127 * assuming the transformations result in valid PNG data.
1128 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001129void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001130png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001131{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001132 png_debug(1, "in png_read_transform_info");
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001133#if defined(PNG_READ_EXPAND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001134 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001135 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001136 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1137 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001138 if (png_ptr->num_trans &&
1139 (png_ptr->transformations & PNG_EXPAND_tRNS))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001140 info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1141 else
1142 info_ptr->color_type = PNG_COLOR_TYPE_RGB;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001143 info_ptr->bit_depth = 8;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001144 info_ptr->num_trans = 0;
1145 }
1146 else
1147 {
1148 if (png_ptr->num_trans)
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -06001149 {
1150 if (png_ptr->transformations & PNG_EXPAND_tRNS)
1151 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001152#if 0 /* Removed from libpng-1.2.27 */
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -06001153 else
1154 info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001155#endif
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -06001156 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001157 if (info_ptr->bit_depth < 8)
1158 info_ptr->bit_depth = 8;
1159 info_ptr->num_trans = 0;
1160 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001161 }
1162#endif
1163
1164#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1165 if (png_ptr->transformations & PNG_BACKGROUND)
1166 {
1167 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
1168 info_ptr->num_trans = 0;
1169 info_ptr->background = png_ptr->background;
1170 }
1171#endif
1172
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001173#if defined(PNG_READ_GAMMA_SUPPORTED)
1174 if (png_ptr->transformations & PNG_GAMMA)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001175 {
1176#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001177 info_ptr->gamma = png_ptr->gamma;
1178#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001179#ifdef PNG_FIXED_POINT_SUPPORTED
1180 info_ptr->int_gamma = png_ptr->int_gamma;
1181#endif
1182 }
1183#endif
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001184
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001185#if defined(PNG_READ_16_TO_8_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001186 if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001187 info_ptr->bit_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001188#endif
1189
Glenn Randers-Pehrsonddfebd32006-02-22 09:19:25 -06001190#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1191 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
1192 info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
1193#endif
1194
1195#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1196 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1197 info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
1198#endif
1199
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001200#if defined(PNG_READ_DITHER_SUPPORTED)
1201 if (png_ptr->transformations & PNG_DITHER)
1202 {
1203 if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
1204 (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
1205 png_ptr->palette_lookup && info_ptr->bit_depth == 8)
1206 {
1207 info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
1208 }
1209 }
1210#endif
1211
1212#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001213 if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001214 info_ptr->bit_depth = 8;
1215#endif
1216
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001217 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001218 info_ptr->channels = 1;
1219 else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
1220 info_ptr->channels = 3;
1221 else
1222 info_ptr->channels = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001223
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001224#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001225 if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001226 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001227#endif
1228
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001229 if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
1230 info_ptr->channels++;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001231
1232#if defined(PNG_READ_FILLER_SUPPORTED)
1233 /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001234 if ((png_ptr->transformations & PNG_FILLER) &&
1235 ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
1236 (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001237 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001238 info_ptr->channels++;
Glenn Randers-Pehrson67864af2004-08-28 23:30:07 -05001239 /* if adding a true alpha channel not just filler */
Glenn Randers-Pehrson67864af2004-08-28 23:30:07 -05001240 if (png_ptr->transformations & PNG_ADD_ALPHA)
1241 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001242 }
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001243#endif
1244
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001245#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
1246defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001247 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001248 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001249 if (info_ptr->bit_depth < png_ptr->user_transform_depth)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001250 info_ptr->bit_depth = png_ptr->user_transform_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001251 if (info_ptr->channels < png_ptr->user_transform_channels)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001252 info_ptr->channels = png_ptr->user_transform_channels;
1253 }
1254#endif
1255
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001256 info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
1257 info_ptr->bit_depth);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001258
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001259 info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width);
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05001260
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001261#if !defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001262 if (png_ptr)
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001263 return;
1264#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001265}
1266
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001267/* Transform the row. The order of transformations is significant,
1268 * and is very touchy. If you add a transformation, take care to
1269 * decide how it fits in with the other transformations here.
1270 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001271void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001272png_do_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05001273{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001274 png_debug(1, "in png_do_read_transformations");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001275 if (png_ptr->row_buf == NULL)
1276 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001277#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001278 char msg[50];
1279
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001280 png_snprintf2(msg, 50,
1281 "NULL row buffer for row %ld, pass %d", (long)png_ptr->row_number,
1282 png_ptr->pass);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001283 png_error(png_ptr, msg);
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001284#else
1285 png_error(png_ptr, "NULL row buffer");
1286#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001287 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001288#ifdef PNG_WARN_UNINITIALIZED_ROW
1289 if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
1290 /* Application has failed to call either png_read_start_image()
1291 * or png_read_update_info() after setting transforms that expand
1292 * pixels. This check added to libpng-1.2.19 */
1293#if (PNG_WARN_UNINITIALIZED_ROW==1)
1294 png_error(png_ptr, "Uninitialized row");
1295#else
1296 png_warning(png_ptr, "Uninitialized row");
1297#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001298#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001299
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001300#if defined(PNG_READ_EXPAND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001301 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05001302 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001303 if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
1304 {
1305 png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
1306 png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
1307 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001308 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001309 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001310 if (png_ptr->num_trans &&
1311 (png_ptr->transformations & PNG_EXPAND_tRNS))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001312 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001313 &(png_ptr->trans_color));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001314 else
1315 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1316 NULL);
1317 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001318 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001319#endif
1320
1321#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001322 if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001323 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001324 PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001325#endif
1326
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001327#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1328 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1329 {
1330 int rgb_error =
1331 png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001332 if (rgb_error)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001333 {
1334 png_ptr->rgb_to_gray_status=1;
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06001335 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001336 PNG_RGB_TO_GRAY_WARN)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001337 png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001338 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
1339 PNG_RGB_TO_GRAY_ERR)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001340 png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1341 }
1342 }
1343#endif
1344
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001345/*
1346From Andreas Dilger e-mail to png-implement, 26 March 1998:
1347
1348 In most cases, the "simple transparency" should be done prior to doing
1349 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 -06001350 pixel is transparent. You would also need to make sure that the
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001351 transparency information is upgraded to RGB.
1352
1353 To summarize, the current flow is:
1354 - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
1355 with background "in place" if transparent,
1356 convert to RGB if necessary
1357 - Gray + alpha -> composite with gray background and remove alpha bytes,
1358 convert to RGB if necessary
1359
1360 To support RGB backgrounds for gray images we need:
1361 - Gray + simple transparency -> convert to RGB + simple transparency, compare
1362 3 or 6 bytes and composite with background
1363 "in place" if transparent (3x compare/pixel
1364 compared to doing composite with gray bkgrnd)
1365 - Gray + alpha -> convert to RGB + alpha, composite with background and
1366 remove alpha bytes (3x float operations/pixel
1367 compared with composite on gray background)
1368
1369 Greg's change will do this. The reason it wasn't done before is for
1370 performance, as this increases the per-pixel operations. If we would check
1371 in advance if the background was gray or RGB, and position the gray-to-RGB
1372 transform appropriately, then it would save a lot of work/time.
1373 */
1374
1375#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1376 /* if gray -> RGB, do so now only if background is non-gray; else do later
1377 * for performance reasons */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001378 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001379 !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001380 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
1381#endif
1382
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001383#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001384 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1385 ((png_ptr->num_trans != 0 ) ||
1386 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
Guy Schalnat0d580581995-07-20 02:43:20 -05001387 png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001388 &(png_ptr->trans_color), &(png_ptr->background)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001389#if defined(PNG_READ_GAMMA_SUPPORTED)
1390 , &(png_ptr->background_1),
Guy Schalnat0d580581995-07-20 02:43:20 -05001391 png_ptr->gamma_table, png_ptr->gamma_from_1,
1392 png_ptr->gamma_to_1, png_ptr->gamma_16_table,
1393 png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001394 png_ptr->gamma_shift
1395#endif
1396);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001397#endif
1398
1399#if defined(PNG_READ_GAMMA_SUPPORTED)
1400 if ((png_ptr->transformations & PNG_GAMMA) &&
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001401#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1402 !((png_ptr->transformations & PNG_BACKGROUND) &&
1403 ((png_ptr->num_trans != 0) ||
1404 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
1405#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001406 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
Guy Schalnat0d580581995-07-20 02:43:20 -05001407 png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
1408 png_ptr->gamma_table, png_ptr->gamma_16_table,
1409 png_ptr->gamma_shift);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001410#endif
1411
1412#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001413 if (png_ptr->transformations & PNG_16_TO_8)
1414 png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001415#endif
1416
1417#if defined(PNG_READ_DITHER_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001418 if (png_ptr->transformations & PNG_DITHER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001419 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001420 png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
1421 png_ptr->palette_lookup, png_ptr->dither_index);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001422 if (png_ptr->row_info.rowbytes == (png_uint_32)0)
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001423 png_error(png_ptr, "png_do_dither returned rowbytes=0");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001424 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001425#endif
1426
1427#if defined(PNG_READ_INVERT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001428 if (png_ptr->transformations & PNG_INVERT_MONO)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001429 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001430#endif
1431
1432#if defined(PNG_READ_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001433 if (png_ptr->transformations & PNG_SHIFT)
1434 png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
1435 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001436#endif
1437
1438#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001439 if (png_ptr->transformations & PNG_PACK)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001440 png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001441#endif
1442
1443#if defined(PNG_READ_BGR_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001444 if (png_ptr->transformations & PNG_BGR)
1445 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001446#endif
1447
Andreas Dilger47a0c421997-05-16 02:46:07 -05001448#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1449 if (png_ptr->transformations & PNG_PACKSWAP)
1450 png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1451#endif
1452
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001453#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001454 /* if gray -> RGB, do so now only if we did not do so above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001455 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
1456 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05001457 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001458#endif
1459
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001460#if defined(PNG_READ_FILLER_SUPPORTED)
1461 if (png_ptr->transformations & PNG_FILLER)
1462 png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001463 (png_uint_32)png_ptr->filler, png_ptr->flags);
1464#endif
1465
Glenn Randers-Pehrson1916f6a2008-08-14 13:44:49 -05001466#if defined(PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED)
1467 if (png_ptr->transformations & PNG_PREMULTIPLY_ALPHA)
Glenn Randers-Pehrson8fb550c2009-03-21 08:15:32 -05001468 png_do_read_premultiply_alpha(&(png_ptr->row_info),
1469 png_ptr->row_buf + 1);
Glenn Randers-Pehrson1916f6a2008-08-14 13:44:49 -05001470#endif
1471
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001472#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
1473 if (png_ptr->transformations & PNG_INVERT_ALPHA)
1474 png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1475#endif
1476
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001477#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
1478 if (png_ptr->transformations & PNG_SWAP_ALPHA)
1479 png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1480#endif
1481
Andreas Dilger47a0c421997-05-16 02:46:07 -05001482#if defined(PNG_READ_SWAP_SUPPORTED)
1483 if (png_ptr->transformations & PNG_SWAP_BYTES)
1484 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001485#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001486
1487#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1488 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001489 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001490 if (png_ptr->read_user_transform_fn != NULL)
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001491 (*(png_ptr->read_user_transform_fn)) /* user read transform function */
1492 (png_ptr, /* png_ptr */
1493 &(png_ptr->row_info), /* row_info: */
1494 /* png_uint_32 width; width of row */
1495 /* png_uint_32 rowbytes; number of bytes in row */
1496 /* png_byte color_type; color type of pixels */
1497 /* png_byte bit_depth; bit depth of samples */
1498 /* png_byte channels; number of channels (1-4) */
1499 /* png_byte pixel_depth; bits per pixel (depth*channels) */
1500 png_ptr->row_buf + 1); /* start of pixel data for row */
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001501#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001502 if (png_ptr->user_transform_depth)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001503 png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001504 if (png_ptr->user_transform_channels)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001505 png_ptr->row_info.channels = png_ptr->user_transform_channels;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001506#endif
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001507 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
1508 png_ptr->row_info.channels);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001509 png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
1510 png_ptr->row_info.width);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001511 }
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001512#endif
1513
Guy Schalnat0d580581995-07-20 02:43:20 -05001514}
1515
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001516#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001517/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
1518 * without changing the actual values. Thus, if you had a row with
1519 * a bit depth of 1, you would end up with bytes that only contained
1520 * the numbers 0 or 1. If you would rather they contain 0 and 255, use
1521 * png_do_shift() after this.
1522 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001523void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001524png_do_unpack(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001525{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001526 png_debug(1, "in png_do_unpack");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001527 if (row_info->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05001528 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001529 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001530 png_uint_32 row_width=row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001531
Guy Schalnat0d580581995-07-20 02:43:20 -05001532 switch (row_info->bit_depth)
1533 {
1534 case 1:
1535 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001536 png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
1537 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001538 png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001539 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001540 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001541 *dp = (png_byte)((*sp >> shift) & 0x01);
Guy Schalnat0d580581995-07-20 02:43:20 -05001542 if (shift == 7)
1543 {
1544 shift = 0;
1545 sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001546 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001547 else
1548 shift++;
1549
1550 dp--;
1551 }
1552 break;
1553 }
1554 case 2:
1555 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001556
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001557 png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
1558 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001559 png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001560 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001561 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001562 *dp = (png_byte)((*sp >> shift) & 0x03);
Guy Schalnat0d580581995-07-20 02:43:20 -05001563 if (shift == 6)
1564 {
1565 shift = 0;
1566 sp--;
1567 }
1568 else
1569 shift += 2;
1570
1571 dp--;
1572 }
1573 break;
1574 }
1575 case 4:
1576 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001577 png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
1578 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001579 png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001580 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001581 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001582 *dp = (png_byte)((*sp >> shift) & 0x0f);
Guy Schalnat0d580581995-07-20 02:43:20 -05001583 if (shift == 4)
1584 {
1585 shift = 0;
1586 sp--;
1587 }
1588 else
1589 shift = 4;
1590
1591 dp--;
1592 }
1593 break;
1594 }
1595 }
1596 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001597 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001598 row_info->rowbytes = row_width * row_info->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001599 }
1600}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001601#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001602
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001603#if defined(PNG_READ_SHIFT_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001604/* Reverse the effects of png_do_shift. This routine merely shifts the
1605 * pixels back to their significant bits values. Thus, if you have
1606 * a row of bit depth 8, but only 5 are significant, this will shift
1607 * the values back to 0 through 31.
1608 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001609void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001610png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
Guy Schalnat0d580581995-07-20 02:43:20 -05001611{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001612 png_debug(1, "in png_do_unshift");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001613 if (
Andreas Dilger47a0c421997-05-16 02:46:07 -05001614 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001615 {
1616 int shift[4];
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001617 int channels = 0;
1618 int c;
1619 png_uint_16 value = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001620 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001621
Guy Schalnat0d580581995-07-20 02:43:20 -05001622 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
1623 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001624 shift[channels++] = row_info->bit_depth - sig_bits->red;
1625 shift[channels++] = row_info->bit_depth - sig_bits->green;
1626 shift[channels++] = row_info->bit_depth - sig_bits->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05001627 }
1628 else
1629 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001630 shift[channels++] = row_info->bit_depth - sig_bits->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05001631 }
1632 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
1633 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001634 shift[channels++] = row_info->bit_depth - sig_bits->alpha;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001635 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001636
Andreas Dilger47a0c421997-05-16 02:46:07 -05001637 for (c = 0; c < channels; c++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001638 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001639 if (shift[c] <= 0)
1640 shift[c] = 0;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001641 else
1642 value = 1;
1643 }
Guy Schalnat0f716451995-11-28 11:22:13 -06001644
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001645 if (!value)
1646 return;
Guy Schalnat0f716451995-11-28 11:22:13 -06001647
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001648 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05001649 {
1650 case 2:
1651 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001652 png_bytep bp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001653 png_uint_32 i;
1654 png_uint_32 istop = row_info->rowbytes;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001655
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001656 for (bp = row, i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001657 {
1658 *bp >>= 1;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001659 *bp++ &= 0x55;
Guy Schalnat0d580581995-07-20 02:43:20 -05001660 }
1661 break;
1662 }
1663 case 4:
1664 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001665 png_bytep bp = row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001666 png_uint_32 i;
1667 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001668 png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
1669 (png_byte)((int)0xf >> shift[0]));
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001670
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001671 for (i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001672 {
1673 *bp >>= shift[0];
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001674 *bp++ &= mask;
Guy Schalnat0d580581995-07-20 02:43:20 -05001675 }
1676 break;
1677 }
1678 case 8:
1679 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001680 png_bytep bp = row;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001681 png_uint_32 i;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001682 png_uint_32 istop = row_width * channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001683
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001684 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001685 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001686 *bp++ >>= shift[i%channels];
Guy Schalnat0d580581995-07-20 02:43:20 -05001687 }
1688 break;
1689 }
1690 case 16:
1691 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001692 png_bytep bp = row;
1693 png_uint_32 i;
1694 png_uint_32 istop = channels * row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001695
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001696 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001697 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001698 value = (png_uint_16)((*bp << 8) + *(bp + 1));
1699 value >>= shift[i%channels];
1700 *bp++ = (png_byte)(value >> 8);
1701 *bp++ = (png_byte)(value & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05001702 }
1703 break;
1704 }
1705 }
1706 }
1707}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001708#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001709
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001710#if defined(PNG_READ_16_TO_8_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001711/* chop rows of bit depth 16 down to 8 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001712void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001713png_do_chop(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001714{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001715 png_debug(1, "in png_do_chop");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001716 if (row_info->bit_depth == 16)
Guy Schalnat0d580581995-07-20 02:43:20 -05001717 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001718 png_bytep sp = row;
1719 png_bytep dp = row;
1720 png_uint_32 i;
1721 png_uint_32 istop = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001722
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001723 for (i = 0; i<istop; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001724 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001725#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001726 /* This does a more accurate scaling of the 16-bit color
1727 * value, rather than a simple low-byte truncation.
1728 *
1729 * What the ideal calculation should be:
1730 * *dp = (((((png_uint_32)(*sp) << 8) |
1731 * (png_uint_32)(*(sp + 1))) * 255 + 127) / (png_uint_32)65535L;
1732 *
1733 * GRR: no, I think this is what it really should be:
1734 * *dp = (((((png_uint_32)(*sp) << 8) |
1735 * (png_uint_32)(*(sp + 1))) + 128L) / (png_uint_32)257L;
1736 *
1737 * GRR: here's the exact calculation with shifts:
1738 * temp = (((png_uint_32)(*sp) << 8) | (png_uint_32)(*(sp + 1))) + 128L;
1739 * *dp = (temp - (temp >> 8)) >> 8;
1740 *
1741 * Approximate calculation with shift/add instead of multiply/divide:
1742 * *dp = ((((png_uint_32)(*sp) << 8) |
1743 * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
1744 *
1745 * What we actually do to avoid extra shifting and conversion:
1746 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001747
Andreas Dilger47a0c421997-05-16 02:46:07 -05001748 *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
1749#else
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001750 /* Simply discard the low order byte */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001751 *dp = *sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001752#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001753 }
1754 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001755 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001756 row_info->rowbytes = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001757 }
1758}
1759#endif
1760
1761#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001762void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001763png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
1764{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001765 png_debug(1, "in png_do_read_swap_alpha");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001766 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001767 png_uint_32 row_width = row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001768 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1769 {
1770 /* This converts from RGBA to ARGB */
1771 if (row_info->bit_depth == 8)
1772 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001773 png_bytep sp = row + row_info->rowbytes;
1774 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001775 png_byte save;
1776 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001777
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001778 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001779 {
1780 save = *(--sp);
1781 *(--dp) = *(--sp);
1782 *(--dp) = *(--sp);
1783 *(--dp) = *(--sp);
1784 *(--dp) = save;
1785 }
1786 }
1787 /* This converts from RRGGBBAA to AARRGGBB */
1788 else
1789 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001790 png_bytep sp = row + row_info->rowbytes;
1791 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001792 png_byte save[2];
1793 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001794
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001795 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001796 {
1797 save[0] = *(--sp);
1798 save[1] = *(--sp);
1799 *(--dp) = *(--sp);
1800 *(--dp) = *(--sp);
1801 *(--dp) = *(--sp);
1802 *(--dp) = *(--sp);
1803 *(--dp) = *(--sp);
1804 *(--dp) = *(--sp);
1805 *(--dp) = save[0];
1806 *(--dp) = save[1];
1807 }
1808 }
1809 }
1810 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1811 {
1812 /* This converts from GA to AG */
1813 if (row_info->bit_depth == 8)
1814 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001815 png_bytep sp = row + row_info->rowbytes;
1816 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001817 png_byte save;
1818 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001819
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001820 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001821 {
1822 save = *(--sp);
1823 *(--dp) = *(--sp);
1824 *(--dp) = save;
1825 }
1826 }
1827 /* This converts from GGAA to AAGG */
1828 else
1829 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001830 png_bytep sp = row + row_info->rowbytes;
1831 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001832 png_byte save[2];
1833 png_uint_32 i;
1834
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001835 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001836 {
1837 save[0] = *(--sp);
1838 save[1] = *(--sp);
1839 *(--dp) = *(--sp);
1840 *(--dp) = *(--sp);
1841 *(--dp) = save[0];
1842 *(--dp) = save[1];
1843 }
1844 }
1845 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001846 }
1847}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001848#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001849
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001850#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001851void /* PRIVATE */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001852png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
1853{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001854 png_debug(1, "in png_do_read_invert_alpha");
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001855 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001856 png_uint_32 row_width = row_info->width;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001857 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1858 {
1859 /* This inverts the alpha channel in RGBA */
1860 if (row_info->bit_depth == 8)
1861 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001862 png_bytep sp = row + row_info->rowbytes;
1863 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001864 png_uint_32 i;
1865
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001866 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001867 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001868 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001869
1870/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001871 *(--dp) = *(--sp);
1872 *(--dp) = *(--sp);
1873 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001874 We can replace it with:
1875*/
1876 sp-=3;
1877 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001878 }
1879 }
1880 /* This inverts the alpha channel in RRGGBBAA */
1881 else
1882 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001883 png_bytep sp = row + row_info->rowbytes;
1884 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001885 png_uint_32 i;
1886
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001887 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001888 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001889 *(--dp) = (png_byte)(255 - *(--sp));
1890 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001891
1892/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001893 *(--dp) = *(--sp);
1894 *(--dp) = *(--sp);
1895 *(--dp) = *(--sp);
1896 *(--dp) = *(--sp);
1897 *(--dp) = *(--sp);
1898 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001899 We can replace it with:
1900*/
1901 sp-=6;
1902 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001903 }
1904 }
1905 }
1906 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1907 {
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001908 /* This inverts the alpha channel in GA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001909 if (row_info->bit_depth == 8)
1910 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001911 png_bytep sp = row + row_info->rowbytes;
1912 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001913 png_uint_32 i;
1914
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001915 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001916 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001917 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001918 *(--dp) = *(--sp);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001919 }
1920 }
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001921 /* This inverts the alpha channel in GGAA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001922 else
1923 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001924 png_bytep sp = row + row_info->rowbytes;
1925 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001926 png_uint_32 i;
1927
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001928 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001929 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001930 *(--dp) = (png_byte)(255 - *(--sp));
1931 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001932/*
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001933 *(--dp) = *(--sp);
1934 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001935*/
1936 sp-=2;
1937 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001938 }
1939 }
1940 }
1941 }
1942}
1943#endif
1944
Glenn Randers-Pehrson1916f6a2008-08-14 13:44:49 -05001945#if defined(PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED)
1946void /* PRIVATE */
1947png_do_read_premultiply_alpha(png_row_infop row_info, png_bytep row)
1948{
Glenn Randers-Pehrsond6d80752008-12-02 09:49:43 -06001949 png_debug(1, "in png_do_read_premultiply_alpha");
Glenn Randers-Pehrson1916f6a2008-08-14 13:44:49 -05001950 {
1951 png_uint_32 row_width = row_info->width;
1952 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1953 {
1954 /* This premultiplies the pixels with the alpha channel in RGBA */
1955 if (row_info->bit_depth == 8)
1956 {
1957 png_bytep sp = row + row_info->rowbytes;
1958 png_bytep dp = sp;
1959 png_uint_16 a = 0;
1960 png_uint_32 i;
1961
1962 for (i = 0; i < row_width; i++)
1963 {
1964 a = *(--sp); --dp;
1965
1966 *(--dp) = (*(--sp) * a) / 255;
1967 *(--dp) = (*(--sp) * a) / 255;
1968 *(--dp) = (*(--sp) * a) / 255;
1969 }
1970 }
1971 /* This premultiplies the pixels with the alpha channel in RRGGBBAA */
1972 else
1973 {
1974 png_uint_16p sp = (png_uint_16p)(row + row_info->rowbytes);
1975 png_uint_16p dp = sp;
1976 png_uint_32 a = 0;
1977 png_uint_32 i;
1978
1979 for (i = 0; i < row_width; i++)
1980 {
1981 a = *(--sp); --dp;
1982 *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535);
1983 *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535);
1984 *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535);
1985 }
1986 }
1987 }
1988 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1989 {
1990 /* This premultiplies the pixels with the alpha channel in GA */
1991 if (row_info->bit_depth == 8)
1992 {
1993 png_bytep sp = row + row_info->rowbytes;
1994 png_bytep dp = sp;
1995 png_uint_16 a = 0;
1996 png_uint_32 i;
1997
1998 for (i = 0; i < row_width; i++)
1999 {
2000 a = *(--sp); --dp;
2001 *(--dp) = (*(--sp) * a) / 255;
2002 }
2003 }
2004 /* This premultiplies the pixels with the alpha channel in GGAA */
2005 else
2006 {
2007 png_uint_16p sp = (png_uint_16p) (row + row_info->rowbytes);
2008 png_uint_16p dp = sp;
2009 png_uint_32 a = 0;
2010 png_uint_32 i;
2011
2012 for (i = 0; i < row_width; i++)
2013 {
2014 a = *(--sp); --dp;
2015 *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535);
2016 }
2017 }
2018 }
2019 }
2020}
2021#endif
2022
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002023#if defined(PNG_READ_FILLER_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002024/* Add filler channel if we have RGB color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002025void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002026png_do_read_filler(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05002027 png_uint_32 filler, png_uint_32 flags)
Guy Schalnat0d580581995-07-20 02:43:20 -05002028{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002029 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002030 png_uint_32 row_width = row_info->width;
2031
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002032 png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002033 png_byte lo_filler = (png_byte)(filler & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002034
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002035 png_debug(1, "in png_do_read_filler");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002036 if (
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002037 row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05002038 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002039 if (row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002040 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002041 /* This changes the data from G to GX */
2042 if (flags & PNG_FLAG_FILLER_AFTER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002043 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002044 png_bytep sp = row + (png_size_t)row_width;
2045 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002046 for (i = 1; i < row_width; i++)
2047 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002048 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002049 *(--dp) = *(--sp);
2050 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002051 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002052 row_info->channels = 2;
2053 row_info->pixel_depth = 16;
2054 row_info->rowbytes = row_width * 2;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002055 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002056 /* This changes the data from G to XG */
2057 else
2058 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002059 png_bytep sp = row + (png_size_t)row_width;
2060 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002061 for (i = 0; i < row_width; i++)
2062 {
2063 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002064 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002065 }
2066 row_info->channels = 2;
2067 row_info->pixel_depth = 16;
2068 row_info->rowbytes = row_width * 2;
2069 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002070 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002071 else if (row_info->bit_depth == 16)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002072 {
2073 /* This changes the data from GG to GGXX */
2074 if (flags & PNG_FLAG_FILLER_AFTER)
2075 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002076 png_bytep sp = row + (png_size_t)row_width * 2;
2077 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002078 for (i = 1; i < row_width; i++)
2079 {
2080 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002081 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002082 *(--dp) = *(--sp);
2083 *(--dp) = *(--sp);
2084 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002085 *(--dp) = hi_filler;
2086 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002087 row_info->channels = 2;
2088 row_info->pixel_depth = 32;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002089 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002090 }
2091 /* This changes the data from GG to XXGG */
2092 else
2093 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002094 png_bytep sp = row + (png_size_t)row_width * 2;
2095 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002096 for (i = 0; i < row_width; i++)
2097 {
2098 *(--dp) = *(--sp);
2099 *(--dp) = *(--sp);
2100 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002101 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002102 }
2103 row_info->channels = 2;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002104 row_info->pixel_depth = 32;
2105 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002106 }
2107 }
2108 } /* COLOR_TYPE == GRAY */
2109 else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2110 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002111 if (row_info->bit_depth == 8)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002112 {
2113 /* This changes the data from RGB to RGBX */
2114 if (flags & PNG_FLAG_FILLER_AFTER)
2115 {
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002116 png_bytep sp = row + (png_size_t)row_width * 3;
2117 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002118 for (i = 1; i < row_width; i++)
2119 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002120 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002121 *(--dp) = *(--sp);
2122 *(--dp) = *(--sp);
2123 *(--dp) = *(--sp);
2124 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002125 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002126 row_info->channels = 4;
2127 row_info->pixel_depth = 32;
2128 row_info->rowbytes = row_width * 4;
2129 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002130 /* This changes the data from RGB to XRGB */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002131 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002132 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002133 png_bytep sp = row + (png_size_t)row_width * 3;
2134 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002135 for (i = 0; i < row_width; i++)
2136 {
2137 *(--dp) = *(--sp);
2138 *(--dp) = *(--sp);
2139 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002140 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002141 }
2142 row_info->channels = 4;
2143 row_info->pixel_depth = 32;
2144 row_info->rowbytes = row_width * 4;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002145 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002146 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002147 else if (row_info->bit_depth == 16)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002148 {
2149 /* This changes the data from RRGGBB to RRGGBBXX */
2150 if (flags & PNG_FLAG_FILLER_AFTER)
2151 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002152 png_bytep sp = row + (png_size_t)row_width * 6;
2153 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002154 for (i = 1; i < row_width; i++)
2155 {
2156 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002157 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002158 *(--dp) = *(--sp);
2159 *(--dp) = *(--sp);
2160 *(--dp) = *(--sp);
2161 *(--dp) = *(--sp);
2162 *(--dp) = *(--sp);
2163 *(--dp) = *(--sp);
2164 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002165 *(--dp) = hi_filler;
2166 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002167 row_info->channels = 4;
2168 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002169 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002170 }
2171 /* This changes the data from RRGGBB to XXRRGGBB */
2172 else
2173 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002174 png_bytep sp = row + (png_size_t)row_width * 6;
2175 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002176 for (i = 0; i < row_width; i++)
2177 {
2178 *(--dp) = *(--sp);
2179 *(--dp) = *(--sp);
2180 *(--dp) = *(--sp);
2181 *(--dp) = *(--sp);
2182 *(--dp) = *(--sp);
2183 *(--dp) = *(--sp);
2184 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002185 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002186 }
2187 row_info->channels = 4;
2188 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002189 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002190 }
2191 }
2192 } /* COLOR_TYPE == RGB */
Guy Schalnat0d580581995-07-20 02:43:20 -05002193}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002194#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002195
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002196#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002197/* expand grayscale files to RGB, with or without alpha */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002198void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002199png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05002200{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002201 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002202 png_uint_32 row_width = row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06002203
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002204 png_debug(1, "in png_do_gray_to_rgb");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002205 if (row_info->bit_depth >= 8 &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002206 !(row_info->color_type & PNG_COLOR_MASK_COLOR))
2207 {
2208 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
2209 {
2210 if (row_info->bit_depth == 8)
2211 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002212 png_bytep sp = row + (png_size_t)row_width - 1;
2213 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002214 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002215 {
2216 *(dp--) = *sp;
2217 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002218 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002219 }
2220 }
2221 else
2222 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002223 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2224 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002225 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002226 {
2227 *(dp--) = *sp;
2228 *(dp--) = *(sp - 1);
2229 *(dp--) = *sp;
2230 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002231 *(dp--) = *(sp--);
2232 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002233 }
2234 }
2235 }
2236 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2237 {
2238 if (row_info->bit_depth == 8)
2239 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002240 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2241 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002242 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002243 {
2244 *(dp--) = *(sp--);
2245 *(dp--) = *sp;
2246 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002247 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002248 }
2249 }
2250 else
2251 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002252 png_bytep sp = row + (png_size_t)row_width * 4 - 1;
2253 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002254 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002255 {
2256 *(dp--) = *(sp--);
2257 *(dp--) = *(sp--);
2258 *(dp--) = *sp;
2259 *(dp--) = *(sp - 1);
2260 *(dp--) = *sp;
2261 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002262 *(dp--) = *(sp--);
2263 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002264 }
2265 }
2266 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002267 row_info->channels += (png_byte)2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002268 row_info->color_type |= PNG_COLOR_MASK_COLOR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002269 row_info->pixel_depth = (png_byte)(row_info->channels *
2270 row_info->bit_depth);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002271 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05002272 }
2273}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002274#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002275
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002276#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002277/* reduce RGB files to grayscale, with or without alpha
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002278 * using the equation given in Poynton's ColorFAQ at
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002279 * <http://www.inforamp.net/~poynton/> (THIS LINK IS DEAD June 2008)
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002280 * New link:
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002281 * <http://www.poynton.com/notes/colour_and_gamma/>
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002282 * Charles Poynton poynton at poynton.com
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002283 *
2284 * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
2285 *
2286 * We approximate this with
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002287 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002288 * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002289 *
2290 * which can be expressed with integers as
2291 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002292 * Y = (6969 * R + 23434 * G + 2365 * B)/32768
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002293 *
2294 * The calculation is to be done in a linear colorspace.
2295 *
2296 * Other integer coefficents can be used via png_set_rgb_to_gray().
2297 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002298int /* PRIVATE */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002299png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
2300
2301{
2302 png_uint_32 i;
2303
2304 png_uint_32 row_width = row_info->width;
2305 int rgb_error = 0;
2306
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002307 png_debug(1, "in png_do_rgb_to_gray");
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002308 if (
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002309 (row_info->color_type & PNG_COLOR_MASK_COLOR))
2310 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002311 png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
2312 png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
2313 png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002314
2315 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2316 {
2317 if (row_info->bit_depth == 8)
2318 {
2319#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2320 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2321 {
2322 png_bytep sp = row;
2323 png_bytep dp = row;
2324
2325 for (i = 0; i < row_width; i++)
2326 {
2327 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2328 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2329 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002330 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002331 {
2332 rgb_error |= 1;
2333 *(dp++) = png_ptr->gamma_from_1[
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002334 (rc*red + gc*green + bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002335 }
2336 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002337 *(dp++) = *(sp - 1);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002338 }
2339 }
2340 else
2341#endif
2342 {
2343 png_bytep sp = row;
2344 png_bytep dp = row;
2345 for (i = 0; i < row_width; i++)
2346 {
2347 png_byte red = *(sp++);
2348 png_byte green = *(sp++);
2349 png_byte blue = *(sp++);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002350 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002351 {
2352 rgb_error |= 1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002353 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002354 }
2355 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002356 *(dp++) = *(sp - 1);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002357 }
2358 }
2359 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002360
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002361 else /* RGB bit_depth == 16 */
2362 {
2363#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2364 if (png_ptr->gamma_16_to_1 != NULL &&
2365 png_ptr->gamma_16_from_1 != NULL)
2366 {
2367 png_bytep sp = row;
2368 png_bytep dp = row;
2369 for (i = 0; i < row_width; i++)
2370 {
2371 png_uint_16 red, green, blue, w;
2372
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002373 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2374 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2375 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002376
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002377 if (red == green && red == blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002378 w = red;
2379 else
2380 {
2381 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2382 png_ptr->gamma_shift][red>>8];
2383 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2384 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002385 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002386 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002387 png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002388 + bc*blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002389 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2390 png_ptr->gamma_shift][gray16 >> 8];
2391 rgb_error |= 1;
2392 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002393
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002394 *(dp++) = (png_byte)((w>>8) & 0xff);
2395 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002396 }
2397 }
2398 else
2399#endif
2400 {
2401 png_bytep sp = row;
2402 png_bytep dp = row;
2403 for (i = 0; i < row_width; i++)
2404 {
2405 png_uint_16 red, green, blue, gray16;
2406
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002407 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2408 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2409 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002410
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002411 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002412 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002413 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002414 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2415 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002416 }
2417 }
2418 }
2419 }
2420 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2421 {
2422 if (row_info->bit_depth == 8)
2423 {
2424#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2425 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2426 {
2427 png_bytep sp = row;
2428 png_bytep dp = row;
2429 for (i = 0; i < row_width; i++)
2430 {
2431 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2432 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2433 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002434 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002435 rgb_error |= 1;
2436 *(dp++) = png_ptr->gamma_from_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002437 [(rc*red + gc*green + bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002438 *(dp++) = *(sp++); /* alpha */
2439 }
2440 }
2441 else
2442#endif
2443 {
2444 png_bytep sp = row;
2445 png_bytep dp = row;
2446 for (i = 0; i < row_width; i++)
2447 {
2448 png_byte red = *(sp++);
2449 png_byte green = *(sp++);
2450 png_byte blue = *(sp++);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002451 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002452 rgb_error |= 1;
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002453 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002454 *(dp++) = *(sp++); /* alpha */
2455 }
2456 }
2457 }
2458 else /* RGBA bit_depth == 16 */
2459 {
2460#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2461 if (png_ptr->gamma_16_to_1 != NULL &&
2462 png_ptr->gamma_16_from_1 != NULL)
2463 {
2464 png_bytep sp = row;
2465 png_bytep dp = row;
2466 for (i = 0; i < row_width; i++)
2467 {
2468 png_uint_16 red, green, blue, w;
2469
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002470 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2471 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2472 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002473
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002474 if (red == green && red == blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002475 w = red;
2476 else
2477 {
2478 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2479 png_ptr->gamma_shift][red>>8];
2480 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2481 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002482 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002483 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002484 png_uint_16 gray16 = (png_uint_16)((rc * red_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002485 + gc * green_1 + bc * blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002486 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2487 png_ptr->gamma_shift][gray16 >> 8];
2488 rgb_error |= 1;
2489 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002490
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002491 *(dp++) = (png_byte)((w>>8) & 0xff);
2492 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002493 *(dp++) = *(sp++); /* alpha */
2494 *(dp++) = *(sp++);
2495 }
2496 }
2497 else
2498#endif
2499 {
2500 png_bytep sp = row;
2501 png_bytep dp = row;
2502 for (i = 0; i < row_width; i++)
2503 {
2504 png_uint_16 red, green, blue, gray16;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002505 red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2506 green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2507 blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002508 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002509 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002510 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002511 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2512 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002513 *(dp++) = *(sp++); /* alpha */
2514 *(dp++) = *(sp++);
2515 }
2516 }
2517 }
2518 }
2519 row_info->channels -= (png_byte)2;
2520 row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
2521 row_info->pixel_depth = (png_byte)(row_info->channels *
2522 row_info->bit_depth);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002523 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002524 }
2525 return rgb_error;
2526}
2527#endif
2528
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002529/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
2530 * large of png_color. This lets grayscale images be treated as
2531 * paletted. Most useful for gamma correction and simplification
2532 * of code.
2533 */
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06002534void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -06002535png_build_grayscale_palette(int bit_depth, png_colorp palette)
Guy Schalnat0d580581995-07-20 02:43:20 -05002536{
2537 int num_palette;
2538 int color_inc;
2539 int i;
2540 int v;
2541
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002542 png_debug(1, "in png_do_build_grayscale_palette");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002543 if (palette == NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002544 return;
2545
2546 switch (bit_depth)
2547 {
2548 case 1:
2549 num_palette = 2;
2550 color_inc = 0xff;
2551 break;
2552 case 2:
2553 num_palette = 4;
2554 color_inc = 0x55;
2555 break;
2556 case 4:
2557 num_palette = 16;
2558 color_inc = 0x11;
2559 break;
2560 case 8:
2561 num_palette = 256;
2562 color_inc = 1;
2563 break;
2564 default:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002565 num_palette = 0;
Guy Schalnat69b14481996-01-10 02:56:49 -06002566 color_inc = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002567 break;
2568 }
2569
2570 for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
2571 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002572 palette[i].red = (png_byte)v;
2573 palette[i].green = (png_byte)v;
2574 palette[i].blue = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002575 }
2576}
2577
Guy Schalnat0d580581995-07-20 02:43:20 -05002578
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002579#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002580/* Replace any alpha or transparency with the supplied background color.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002581 * "background" is already in the screen gamma, while "background_1" is
2582 * at a gamma of 1.0. Paletted files have already been taken care of.
2583 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002584void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002585png_do_background(png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002586 png_color_16p trans_color, png_color_16p background
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002587#if defined(PNG_READ_GAMMA_SUPPORTED)
2588 , png_color_16p background_1,
Guy Schalnat6d764711995-12-19 03:22:19 -06002589 png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002590 png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002591 png_uint_16pp gamma_16_to_1, int gamma_shift
2592#endif
2593 )
Guy Schalnat0d580581995-07-20 02:43:20 -05002594{
Guy Schalnat6d764711995-12-19 03:22:19 -06002595 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002596 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002597 png_uint_32 row_width=row_info->width;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002598 int shift;
Guy Schalnate5a37791996-06-05 15:50:50 -05002599
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002600 png_debug(1, "in png_do_background");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002601 if (background != NULL &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002602 (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002603 (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_color)))
Guy Schalnat0d580581995-07-20 02:43:20 -05002604 {
2605 switch (row_info->color_type)
2606 {
2607 case PNG_COLOR_TYPE_GRAY:
2608 {
2609 switch (row_info->bit_depth)
2610 {
2611 case 1:
2612 {
Guy Schalnat0d580581995-07-20 02:43:20 -05002613 sp = row;
2614 shift = 7;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002615 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002616 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002617 if ((png_uint_16)((*sp >> shift) & 0x01)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002618 == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002619 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002620 *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2621 *sp |= (png_byte)(background->gray << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002622 }
2623 if (!shift)
2624 {
2625 shift = 7;
2626 sp++;
2627 }
2628 else
2629 shift--;
2630 }
2631 break;
2632 }
2633 case 2:
2634 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002635#if defined(PNG_READ_GAMMA_SUPPORTED)
2636 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002637 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002638 sp = row;
2639 shift = 6;
2640 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002641 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002642 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002643 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002644 {
2645 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2646 *sp |= (png_byte)(background->gray << shift);
2647 }
2648 else
2649 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002650 png_byte p = (png_byte)((*sp >> shift) & 0x03);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002651 png_byte g = (png_byte)((gamma_table [p | (p << 2) |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002652 (p << 4) | (p << 6)] >> 6) & 0x03);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002653 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2654 *sp |= (png_byte)(g << shift);
2655 }
2656 if (!shift)
2657 {
2658 shift = 6;
2659 sp++;
2660 }
2661 else
2662 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002663 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002664 }
2665 else
2666#endif
2667 {
2668 sp = row;
2669 shift = 6;
2670 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002671 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002672 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002673 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002674 {
2675 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2676 *sp |= (png_byte)(background->gray << shift);
2677 }
2678 if (!shift)
2679 {
2680 shift = 6;
2681 sp++;
2682 }
2683 else
2684 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002685 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002686 }
2687 break;
2688 }
2689 case 4:
2690 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002691#if defined(PNG_READ_GAMMA_SUPPORTED)
2692 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002693 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002694 sp = row;
2695 shift = 4;
2696 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002697 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002698 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002699 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002700 {
2701 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2702 *sp |= (png_byte)(background->gray << shift);
2703 }
2704 else
2705 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002706 png_byte p = (png_byte)((*sp >> shift) & 0x0f);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002707 png_byte g = (png_byte)((gamma_table[p |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002708 (p << 4)] >> 4) & 0x0f);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002709 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2710 *sp |= (png_byte)(g << shift);
2711 }
2712 if (!shift)
2713 {
2714 shift = 4;
2715 sp++;
2716 }
2717 else
2718 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002719 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002720 }
2721 else
2722#endif
2723 {
2724 sp = row;
2725 shift = 4;
2726 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002727 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002728 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002729 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002730 {
2731 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2732 *sp |= (png_byte)(background->gray << shift);
2733 }
2734 if (!shift)
2735 {
2736 shift = 4;
2737 sp++;
2738 }
2739 else
2740 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002741 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002742 }
2743 break;
2744 }
2745 case 8:
2746 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002747#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002748 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002749 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002750 sp = row;
2751 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002752 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002753 if (*sp == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002754 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002755 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002756 }
2757 else
2758 {
2759 *sp = gamma_table[*sp];
2760 }
2761 }
2762 }
2763 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002764#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002765 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002766 sp = row;
2767 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002768 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002769 if (*sp == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002770 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002771 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002772 }
2773 }
2774 }
2775 break;
2776 }
2777 case 16:
2778 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002779#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002780 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002781 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002782 sp = row;
2783 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002784 {
2785 png_uint_16 v;
2786
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002787 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002788 if (v == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002789 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002790 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002791 *sp = (png_byte)((background->gray >> 8) & 0xff);
2792 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002793 }
2794 else
2795 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002796 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002797 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002798 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002799 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002800 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002801 }
2802 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002803#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002804 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002805 sp = row;
2806 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002807 {
2808 png_uint_16 v;
2809
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002810 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002811 if (v == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002812 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002813 *sp = (png_byte)((background->gray >> 8) & 0xff);
2814 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002815 }
2816 }
2817 }
2818 break;
2819 }
2820 }
2821 break;
2822 }
2823 case PNG_COLOR_TYPE_RGB:
2824 {
2825 if (row_info->bit_depth == 8)
2826 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002827#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002828 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002829 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002830 sp = row;
2831 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002832 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002833 if (*sp == trans_color->red &&
2834 *(sp + 1) == trans_color->green &&
2835 *(sp + 2) == trans_color->blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05002836 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002837 *sp = (png_byte)background->red;
2838 *(sp + 1) = (png_byte)background->green;
2839 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002840 }
2841 else
2842 {
2843 *sp = gamma_table[*sp];
2844 *(sp + 1) = gamma_table[*(sp + 1)];
2845 *(sp + 2) = gamma_table[*(sp + 2)];
2846 }
2847 }
2848 }
2849 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002850#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002851 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002852 sp = row;
2853 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002854 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002855 if (*sp == trans_color->red &&
2856 *(sp + 1) == trans_color->green &&
2857 *(sp + 2) == trans_color->blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05002858 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002859 *sp = (png_byte)background->red;
2860 *(sp + 1) = (png_byte)background->green;
2861 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002862 }
2863 }
2864 }
2865 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002866 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05002867 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002868#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002869 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002870 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002871 sp = row;
2872 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002873 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002874 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2875 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2876 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002877 if (r == trans_color->red && g == trans_color->green &&
2878 b == trans_color->blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05002879 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002880 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002881 *sp = (png_byte)((background->red >> 8) & 0xff);
2882 *(sp + 1) = (png_byte)(background->red & 0xff);
2883 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2884 *(sp + 3) = (png_byte)(background->green & 0xff);
2885 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2886 *(sp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002887 }
2888 else
2889 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002890 png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002891 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002892 *(sp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002893 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002894 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
2895 *(sp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002896 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002897 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
2898 *(sp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002899 }
2900 }
2901 }
2902 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002903#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002904 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002905 sp = row;
2906 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05002907 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002908 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
2909 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2910 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Guy Schalnat0d580581995-07-20 02:43:20 -05002911
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002912 if (r == trans_color->red && g == trans_color->green &&
2913 b == trans_color->blue)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002914 {
2915 *sp = (png_byte)((background->red >> 8) & 0xff);
2916 *(sp + 1) = (png_byte)(background->red & 0xff);
2917 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2918 *(sp + 3) = (png_byte)(background->green & 0xff);
2919 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2920 *(sp + 5) = (png_byte)(background->blue & 0xff);
2921 }
2922 }
2923 }
2924 }
2925 break;
2926 }
2927 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -05002928 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002929 if (row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002930 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002931#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002932 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
2933 gamma_table != NULL)
2934 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002935 sp = row;
2936 dp = row;
2937 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002938 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002939 png_uint_16 a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002940
Andreas Dilger47a0c421997-05-16 02:46:07 -05002941 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002942 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002943 *dp = gamma_table[*sp];
2944 }
2945 else if (a == 0)
2946 {
2947 /* background is already in screen gamma */
2948 *dp = (png_byte)background->gray;
2949 }
2950 else
2951 {
2952 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05002953
Andreas Dilger47a0c421997-05-16 02:46:07 -05002954 v = gamma_to_1[*sp];
2955 png_composite(w, v, a, background_1->gray);
2956 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002957 }
2958 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002959 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002960 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002961#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002962 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002963 sp = row;
2964 dp = row;
2965 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002966 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002967 png_byte a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002968
Andreas Dilger47a0c421997-05-16 02:46:07 -05002969 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002970 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002971 *dp = *sp;
2972 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002973#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002974 else if (a == 0)
2975 {
2976 *dp = (png_byte)background->gray;
2977 }
2978 else
2979 {
2980 png_composite(*dp, *sp, a, background_1->gray);
Guy Schalnat0d580581995-07-20 02:43:20 -05002981 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002982#else
2983 *dp = (png_byte)background->gray;
2984#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002985 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002986 }
2987 }
2988 else /* if (png_ptr->bit_depth == 16) */
2989 {
2990#if defined(PNG_READ_GAMMA_SUPPORTED)
2991 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
2992 gamma_16_to_1 != NULL)
2993 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002994 sp = row;
2995 dp = row;
2996 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002997 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002998 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05002999
Andreas Dilger47a0c421997-05-16 02:46:07 -05003000 if (a == (png_uint_16)0xffff)
3001 {
3002 png_uint_16 v;
3003
3004 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3005 *dp = (png_byte)((v >> 8) & 0xff);
3006 *(dp + 1) = (png_byte)(v & 0xff);
3007 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003008#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003009 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003010#else
3011 else
3012#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003013 {
3014 /* background is already in screen gamma */
3015 *dp = (png_byte)((background->gray >> 8) & 0xff);
3016 *(dp + 1) = (png_byte)(background->gray & 0xff);
3017 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003018#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003019 else
3020 {
3021 png_uint_16 g, v, w;
3022
3023 g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3024 png_composite_16(v, g, a, background_1->gray);
3025 w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
3026 *dp = (png_byte)((w >> 8) & 0xff);
3027 *(dp + 1) = (png_byte)(w & 0xff);
3028 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003029#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003030 }
3031 }
3032 else
3033#endif
3034 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003035 sp = row;
3036 dp = row;
3037 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003038 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003039 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003040 if (a == (png_uint_16)0xffff)
3041 {
3042 png_memcpy(dp, sp, 2);
3043 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003044#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003045 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003046#else
3047 else
3048#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003049 {
3050 *dp = (png_byte)((background->gray >> 8) & 0xff);
3051 *(dp + 1) = (png_byte)(background->gray & 0xff);
3052 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003053#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003054 else
3055 {
3056 png_uint_16 g, v;
3057
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003058 g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003059 png_composite_16(v, g, a, background_1->gray);
3060 *dp = (png_byte)((v >> 8) & 0xff);
3061 *(dp + 1) = (png_byte)(v & 0xff);
3062 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003063#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003064 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003065 }
3066 }
3067 break;
3068 }
3069 case PNG_COLOR_TYPE_RGB_ALPHA:
3070 {
3071 if (row_info->bit_depth == 8)
3072 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003073#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003074 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3075 gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003076 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003077 sp = row;
3078 dp = row;
3079 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003080 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003081 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003082
Guy Schalnat0d580581995-07-20 02:43:20 -05003083 if (a == 0xff)
3084 {
3085 *dp = gamma_table[*sp];
3086 *(dp + 1) = gamma_table[*(sp + 1)];
3087 *(dp + 2) = gamma_table[*(sp + 2)];
3088 }
3089 else if (a == 0)
3090 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003091 /* background is already in screen gamma */
3092 *dp = (png_byte)background->red;
3093 *(dp + 1) = (png_byte)background->green;
3094 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003095 }
3096 else
3097 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003098 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05003099
3100 v = gamma_to_1[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003101 png_composite(w, v, a, background_1->red);
3102 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003103 v = gamma_to_1[*(sp + 1)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003104 png_composite(w, v, a, background_1->green);
3105 *(dp + 1) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003106 v = gamma_to_1[*(sp + 2)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003107 png_composite(w, v, a, background_1->blue);
3108 *(dp + 2) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003109 }
3110 }
3111 }
3112 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003113#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003114 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003115 sp = row;
3116 dp = row;
3117 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003118 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003119 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003120
Guy Schalnat0d580581995-07-20 02:43:20 -05003121 if (a == 0xff)
3122 {
3123 *dp = *sp;
3124 *(dp + 1) = *(sp + 1);
3125 *(dp + 2) = *(sp + 2);
3126 }
3127 else if (a == 0)
3128 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003129 *dp = (png_byte)background->red;
3130 *(dp + 1) = (png_byte)background->green;
3131 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003132 }
3133 else
3134 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003135 png_composite(*dp, *sp, a, background->red);
3136 png_composite(*(dp + 1), *(sp + 1), a,
3137 background->green);
3138 png_composite(*(dp + 2), *(sp + 2), a,
3139 background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003140 }
3141 }
3142 }
3143 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003144 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003145 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003146#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003147 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3148 gamma_16_to_1 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003149 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003150 sp = row;
3151 dp = row;
3152 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003153 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003154 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3155 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003156 if (a == (png_uint_16)0xffff)
3157 {
3158 png_uint_16 v;
3159
Andreas Dilger47a0c421997-05-16 02:46:07 -05003160 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003161 *dp = (png_byte)((v >> 8) & 0xff);
3162 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003163 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003164 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3165 *(dp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003166 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003167 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3168 *(dp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003169 }
3170 else if (a == 0)
3171 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003172 /* background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003173 *dp = (png_byte)((background->red >> 8) & 0xff);
3174 *(dp + 1) = (png_byte)(background->red & 0xff);
3175 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3176 *(dp + 3) = (png_byte)(background->green & 0xff);
3177 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3178 *(dp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003179 }
3180 else
3181 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003182 png_uint_16 v, w, x;
Guy Schalnat0d580581995-07-20 02:43:20 -05003183
Andreas Dilger47a0c421997-05-16 02:46:07 -05003184 v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003185 png_composite_16(w, v, a, background_1->red);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003186 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3187 *dp = (png_byte)((x >> 8) & 0xff);
3188 *(dp + 1) = (png_byte)(x & 0xff);
3189 v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003190 png_composite_16(w, v, a, background_1->green);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003191 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3192 *(dp + 2) = (png_byte)((x >> 8) & 0xff);
3193 *(dp + 3) = (png_byte)(x & 0xff);
3194 v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003195 png_composite_16(w, v, a, background_1->blue);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003196 x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
3197 *(dp + 4) = (png_byte)((x >> 8) & 0xff);
3198 *(dp + 5) = (png_byte)(x & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003199 }
3200 }
3201 }
3202 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003203#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003204 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003205 sp = row;
3206 dp = row;
3207 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003208 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003209 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3210 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003211 if (a == (png_uint_16)0xffff)
3212 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003213 png_memcpy(dp, sp, 6);
Guy Schalnat0d580581995-07-20 02:43:20 -05003214 }
3215 else if (a == 0)
3216 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003217 *dp = (png_byte)((background->red >> 8) & 0xff);
3218 *(dp + 1) = (png_byte)(background->red & 0xff);
3219 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3220 *(dp + 3) = (png_byte)(background->green & 0xff);
3221 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3222 *(dp + 5) = (png_byte)(background->blue & 0xff);
3223 }
3224 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003225 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003226 png_uint_16 v;
Guy Schalnat0d580581995-07-20 02:43:20 -05003227
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003228 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3229 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3230 + *(sp + 3));
3231 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3232 + *(sp + 5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003233
3234 png_composite_16(v, r, a, background->red);
Guy Schalnat0d580581995-07-20 02:43:20 -05003235 *dp = (png_byte)((v >> 8) & 0xff);
3236 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003237 png_composite_16(v, g, a, background->green);
Guy Schalnat0d580581995-07-20 02:43:20 -05003238 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3239 *(dp + 3) = (png_byte)(v & 0xff);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003240 png_composite_16(v, b, a, background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003241 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3242 *(dp + 5) = (png_byte)(v & 0xff);
3243 }
3244 }
3245 }
3246 }
3247 break;
3248 }
3249 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003250
Guy Schalnat0d580581995-07-20 02:43:20 -05003251 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
3252 {
3253 row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
Guy Schalnate5a37791996-06-05 15:50:50 -05003254 row_info->channels--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003255 row_info->pixel_depth = (png_byte)(row_info->channels *
3256 row_info->bit_depth);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003257 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003258 }
3259 }
3260}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003261#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003262
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003263#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003264/* Gamma correct the image, avoiding the alpha channel. Make sure
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003265 * you do this after you deal with the transparency issue on grayscale
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003266 * or RGB images. If your bit depth is 8, use gamma_table, if it
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003267 * is 16, use gamma_16_table and gamma_shift. Build these with
3268 * build_gamma_table().
3269 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003270void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003271png_do_gamma(png_row_infop row_info, png_bytep row,
3272 png_bytep gamma_table, png_uint_16pp gamma_16_table,
Guy Schalnat0d580581995-07-20 02:43:20 -05003273 int gamma_shift)
3274{
Guy Schalnat6d764711995-12-19 03:22:19 -06003275 png_bytep sp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003276 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003277 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003278
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003279 png_debug(1, "in png_do_gamma");
Andreas Dilger47a0c421997-05-16 02:46:07 -05003280 if (
Andreas Dilger47a0c421997-05-16 02:46:07 -05003281 ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
3282 (row_info->bit_depth == 16 && gamma_16_table != NULL)))
Guy Schalnat0d580581995-07-20 02:43:20 -05003283 {
3284 switch (row_info->color_type)
3285 {
3286 case PNG_COLOR_TYPE_RGB:
3287 {
3288 if (row_info->bit_depth == 8)
3289 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003290 sp = row;
3291 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003292 {
3293 *sp = gamma_table[*sp];
3294 sp++;
3295 *sp = gamma_table[*sp];
3296 sp++;
3297 *sp = gamma_table[*sp];
3298 sp++;
3299 }
3300 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003301 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003302 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003303 sp = row;
3304 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003305 {
3306 png_uint_16 v;
3307
Andreas Dilger47a0c421997-05-16 02:46:07 -05003308 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003309 *sp = (png_byte)((v >> 8) & 0xff);
3310 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003311 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003312 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003313 *sp = (png_byte)((v >> 8) & 0xff);
3314 *(sp + 1) = (png_byte)(v & 0xff);
3315 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003316 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003317 *sp = (png_byte)((v >> 8) & 0xff);
3318 *(sp + 1) = (png_byte)(v & 0xff);
3319 sp += 2;
3320 }
3321 }
3322 break;
3323 }
3324 case PNG_COLOR_TYPE_RGB_ALPHA:
3325 {
3326 if (row_info->bit_depth == 8)
3327 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003328 sp = row;
3329 for (i = 0; i < row_width; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003330 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003331 *sp = gamma_table[*sp];
3332 sp++;
3333 *sp = gamma_table[*sp];
3334 sp++;
3335 *sp = gamma_table[*sp];
3336 sp++;
3337 sp++;
3338 }
3339 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003340 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003341 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003342 sp = row;
3343 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003344 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003345 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003346 *sp = (png_byte)((v >> 8) & 0xff);
3347 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003348 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003349 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003350 *sp = (png_byte)((v >> 8) & 0xff);
3351 *(sp + 1) = (png_byte)(v & 0xff);
3352 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003353 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003354 *sp = (png_byte)((v >> 8) & 0xff);
3355 *(sp + 1) = (png_byte)(v & 0xff);
3356 sp += 4;
3357 }
3358 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003359 break;
3360 }
3361 case PNG_COLOR_TYPE_GRAY_ALPHA:
3362 {
3363 if (row_info->bit_depth == 8)
3364 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003365 sp = row;
3366 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003367 {
3368 *sp = gamma_table[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003369 sp += 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05003370 }
3371 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003372 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003373 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003374 sp = row;
3375 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003376 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003377 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003378 *sp = (png_byte)((v >> 8) & 0xff);
3379 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003380 sp += 4;
3381 }
3382 }
3383 break;
3384 }
3385 case PNG_COLOR_TYPE_GRAY:
3386 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003387 if (row_info->bit_depth == 2)
3388 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003389 sp = row;
3390 for (i = 0; i < row_width; i += 4)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003391 {
3392 int a = *sp & 0xc0;
3393 int b = *sp & 0x30;
3394 int c = *sp & 0x0c;
3395 int d = *sp & 0x03;
3396
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003397 *sp = (png_byte)(
3398 ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003399 ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
3400 ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003401 ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003402 sp++;
3403 }
3404 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003405 if (row_info->bit_depth == 4)
Guy Schalnat0d580581995-07-20 02:43:20 -05003406 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003407 sp = row;
3408 for (i = 0; i < row_width; i += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003409 {
3410 int msb = *sp & 0xf0;
3411 int lsb = *sp & 0x0f;
3412
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003413 *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
3414 | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003415 sp++;
3416 }
3417 }
3418 else if (row_info->bit_depth == 8)
3419 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003420 sp = row;
3421 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003422 {
3423 *sp = gamma_table[*sp];
3424 sp++;
3425 }
3426 }
3427 else if (row_info->bit_depth == 16)
3428 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003429 sp = row;
3430 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003431 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003432 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003433 *sp = (png_byte)((v >> 8) & 0xff);
3434 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003435 sp += 2;
3436 }
3437 }
3438 break;
3439 }
3440 }
3441 }
3442}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003443#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003444
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003445#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003446/* Expands a palette row to an RGB or RGBA row depending
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003447 * upon whether you supply trans and num_trans.
3448 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003449void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003450png_do_expand_palette(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05003451 png_colorp palette, png_bytep trans, int num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003452{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003453 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003454 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003455 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003456 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003457
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003458 png_debug(1, "in png_do_expand_palette");
Andreas Dilger47a0c421997-05-16 02:46:07 -05003459 if (
Andreas Dilger47a0c421997-05-16 02:46:07 -05003460 row_info->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05003461 {
3462 if (row_info->bit_depth < 8)
3463 {
3464 switch (row_info->bit_depth)
3465 {
3466 case 1:
3467 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003468 sp = row + (png_size_t)((row_width - 1) >> 3);
3469 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003470 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003471 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003472 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003473 if ((*sp >> shift) & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -05003474 *dp = 1;
3475 else
3476 *dp = 0;
3477 if (shift == 7)
3478 {
3479 shift = 0;
3480 sp--;
3481 }
3482 else
3483 shift++;
3484
3485 dp--;
3486 }
3487 break;
3488 }
3489 case 2:
3490 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003491 sp = row + (png_size_t)((row_width - 1) >> 2);
3492 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003493 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003494 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003495 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003496 value = (*sp >> shift) & 0x03;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003497 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003498 if (shift == 6)
3499 {
3500 shift = 0;
3501 sp--;
3502 }
3503 else
3504 shift += 2;
3505
3506 dp--;
3507 }
3508 break;
3509 }
3510 case 4:
3511 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003512 sp = row + (png_size_t)((row_width - 1) >> 1);
3513 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003514 shift = (int)((row_width & 0x01) << 2);
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) & 0x0f;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003518 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003519 if (shift == 4)
3520 {
3521 shift = 0;
3522 sp--;
3523 }
3524 else
3525 shift += 4;
3526
3527 dp--;
3528 }
3529 break;
3530 }
3531 }
3532 row_info->bit_depth = 8;
3533 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003534 row_info->rowbytes = row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003535 }
3536 switch (row_info->bit_depth)
3537 {
3538 case 8:
3539 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003540 if (trans != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003541 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003542 sp = row + (png_size_t)row_width - 1;
3543 dp = row + (png_size_t)(row_width << 2) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003544
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003545 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003546 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003547 if ((int)(*sp) >= num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003548 *dp-- = 0xff;
3549 else
3550 *dp-- = trans[*sp];
3551 *dp-- = palette[*sp].blue;
3552 *dp-- = palette[*sp].green;
3553 *dp-- = palette[*sp].red;
3554 sp--;
3555 }
3556 row_info->bit_depth = 8;
3557 row_info->pixel_depth = 32;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003558 row_info->rowbytes = row_width * 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05003559 row_info->color_type = 6;
3560 row_info->channels = 4;
3561 }
3562 else
3563 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003564 sp = row + (png_size_t)row_width - 1;
3565 dp = row + (png_size_t)(row_width * 3) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003566
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003567 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003568 {
3569 *dp-- = palette[*sp].blue;
3570 *dp-- = palette[*sp].green;
3571 *dp-- = palette[*sp].red;
3572 sp--;
3573 }
3574 row_info->bit_depth = 8;
3575 row_info->pixel_depth = 24;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003576 row_info->rowbytes = row_width * 3;
Guy Schalnat0d580581995-07-20 02:43:20 -05003577 row_info->color_type = 2;
3578 row_info->channels = 3;
3579 }
3580 break;
3581 }
3582 }
3583 }
3584}
3585
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -06003586/* If the bit depth < 8, it is expanded to 8. Also, if the already
3587 * expanded transparency value is supplied, an alpha channel is built.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003588 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003589void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003590png_do_expand(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003591 png_color_16p trans_value)
Guy Schalnat0d580581995-07-20 02:43:20 -05003592{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003593 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003594 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003595 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003596 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003597
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003598 png_debug(1, "in png_do_expand");
Guy Schalnat0d580581995-07-20 02:43:20 -05003599 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003600 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05003601 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003602 png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003603
3604 if (row_info->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003605 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003606 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05003607 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003608 case 1:
3609 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003610 gray = (png_uint_16)((gray&0x01)*0xff);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003611 sp = row + (png_size_t)((row_width - 1) >> 3);
3612 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003613 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003614 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003615 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003616 if ((*sp >> shift) & 0x01)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003617 *dp = 0xff;
3618 else
3619 *dp = 0;
3620 if (shift == 7)
3621 {
3622 shift = 0;
3623 sp--;
3624 }
3625 else
3626 shift++;
3627
3628 dp--;
3629 }
3630 break;
3631 }
3632 case 2:
3633 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003634 gray = (png_uint_16)((gray&0x03)*0x55);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003635 sp = row + (png_size_t)((row_width - 1) >> 2);
3636 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003637 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
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 value = (*sp >> shift) & 0x03;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003641 *dp = (png_byte)(value | (value << 2) | (value << 4) |
3642 (value << 6));
3643 if (shift == 6)
3644 {
3645 shift = 0;
3646 sp--;
3647 }
3648 else
3649 shift += 2;
3650
3651 dp--;
3652 }
3653 break;
3654 }
3655 case 4:
3656 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003657 gray = (png_uint_16)((gray&0x0f)*0x11);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003658 sp = row + (png_size_t)((row_width - 1) >> 1);
3659 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003660 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003661 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003662 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003663 value = (*sp >> shift) & 0x0f;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003664 *dp = (png_byte)(value | (value << 4));
3665 if (shift == 4)
3666 {
3667 shift = 0;
3668 sp--;
3669 }
3670 else
3671 shift = 4;
3672
3673 dp--;
3674 }
3675 break;
3676 }
3677 }
3678 row_info->bit_depth = 8;
3679 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003680 row_info->rowbytes = row_width;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003681 }
3682
Andreas Dilger47a0c421997-05-16 02:46:07 -05003683 if (trans_value != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003684 {
3685 if (row_info->bit_depth == 8)
3686 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003687 gray = gray & 0xff;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003688 sp = row + (png_size_t)row_width - 1;
3689 dp = row + (png_size_t)(row_width << 1) - 1;
3690 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003691 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003692 if (*sp == gray)
3693 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003694 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003695 *dp-- = 0xff;
3696 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003697 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003698 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003699 else if (row_info->bit_depth == 16)
Guy Schalnat0d580581995-07-20 02:43:20 -05003700 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003701 png_byte gray_high = (gray >> 8) & 0xff;
3702 png_byte gray_low = gray & 0xff;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003703 sp = row + row_info->rowbytes - 1;
3704 dp = row + (row_info->rowbytes << 1) - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003705 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003706 {
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06003707 if (*(sp - 1) == gray_high && *(sp) == gray_low)
Guy Schalnat0d580581995-07-20 02:43:20 -05003708 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003709 *dp-- = 0;
3710 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003711 }
3712 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003713 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003714 *dp-- = 0xff;
3715 *dp-- = 0xff;
Guy Schalnat0d580581995-07-20 02:43:20 -05003716 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003717 *dp-- = *sp--;
3718 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003719 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003720 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003721 row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
3722 row_info->channels = 2;
3723 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003724 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
3725 row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003726 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003727 }
3728 else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
3729 {
3730 if (row_info->bit_depth == 8)
3731 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003732 png_byte red = trans_value->red & 0xff;
3733 png_byte green = trans_value->green & 0xff;
3734 png_byte blue = trans_value->blue & 0xff;
Guy Schalnat0d580581995-07-20 02:43:20 -05003735 sp = row + (png_size_t)row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003736 dp = row + (png_size_t)(row_width << 2) - 1;
3737 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003738 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003739 if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05003740 *dp-- = 0;
3741 else
3742 *dp-- = 0xff;
3743 *dp-- = *sp--;
3744 *dp-- = *sp--;
3745 *dp-- = *sp--;
3746 }
3747 }
3748 else if (row_info->bit_depth == 16)
3749 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003750 png_byte red_high = (trans_value->red >> 8) & 0xff;
3751 png_byte green_high = (trans_value->green >> 8) & 0xff;
3752 png_byte blue_high = (trans_value->blue >> 8) & 0xff;
3753 png_byte red_low = trans_value->red & 0xff;
3754 png_byte green_low = trans_value->green & 0xff;
3755 png_byte blue_low = trans_value->blue & 0xff;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003756 sp = row + row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003757 dp = row + (png_size_t)(row_width << 3) - 1;
3758 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003759 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003760 if (*(sp - 5) == red_high &&
3761 *(sp - 4) == red_low &&
3762 *(sp - 3) == green_high &&
3763 *(sp - 2) == green_low &&
3764 *(sp - 1) == blue_high &&
3765 *(sp ) == blue_low)
Guy Schalnat0d580581995-07-20 02:43:20 -05003766 {
3767 *dp-- = 0;
3768 *dp-- = 0;
3769 }
3770 else
3771 {
3772 *dp-- = 0xff;
3773 *dp-- = 0xff;
3774 }
3775 *dp-- = *sp--;
3776 *dp-- = *sp--;
3777 *dp-- = *sp--;
3778 *dp-- = *sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003779 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003780 *dp-- = *sp--;
3781 }
3782 }
3783 row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
3784 row_info->channels = 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003785 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003786 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003787 }
3788 }
3789}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003790#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003791
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003792#if defined(PNG_READ_DITHER_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003793void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003794png_do_dither(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003795 png_bytep palette_lookup, png_bytep dither_lookup)
Guy Schalnat0d580581995-07-20 02:43:20 -05003796{
Guy Schalnat6d764711995-12-19 03:22:19 -06003797 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003798 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003799 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003800
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003801 png_debug(1, "in png_do_dither");
Guy Schalnat0d580581995-07-20 02:43:20 -05003802 {
3803 if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
3804 palette_lookup && row_info->bit_depth == 8)
3805 {
3806 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003807 sp = row;
3808 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003809 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003810 {
3811 r = *sp++;
3812 g = *sp++;
3813 b = *sp++;
3814
3815 /* this looks real messy, but the compiler will reduce
3816 it down to a reasonable formula. For example, with
3817 5 bits per color, we get:
3818 p = (((r >> 3) & 0x1f) << 10) |
3819 (((g >> 3) & 0x1f) << 5) |
3820 ((b >> 3) & 0x1f);
3821 */
3822 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
3823 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
3824 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3825 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003826 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003827 (PNG_DITHER_BLUE_BITS)) |
3828 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3829 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3830
3831 *dp++ = palette_lookup[p];
3832 }
3833 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3834 row_info->channels = 1;
3835 row_info->pixel_depth = row_info->bit_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003836 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003837 }
3838 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
Andreas Dilger47a0c421997-05-16 02:46:07 -05003839 palette_lookup != NULL && row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003840 {
3841 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003842 sp = row;
3843 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003844 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003845 {
3846 r = *sp++;
3847 g = *sp++;
3848 b = *sp++;
3849 sp++;
3850
3851 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003852 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003853 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3854 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
3855 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
3856 (PNG_DITHER_BLUE_BITS)) |
3857 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3858 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3859
3860 *dp++ = palette_lookup[p];
3861 }
3862 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3863 row_info->channels = 1;
3864 row_info->pixel_depth = row_info->bit_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003865 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003866 }
3867 else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
3868 dither_lookup && row_info->bit_depth == 8)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003869 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003870 sp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003871 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003872 {
3873 *sp = dither_lookup[*sp];
3874 }
3875 }
3876 }
3877}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003878#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003879
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003880#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003881#if defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003882static PNG_CONST int png_gamma_shift[] =
3883 {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0, 0x00};
Guy Schalnat0d580581995-07-20 02:43:20 -05003884
Andreas Dilger47a0c421997-05-16 02:46:07 -05003885/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003886 * tables, we don't make a full table if we are reducing to 8-bit in
3887 * the future. Note also how the gamma_16 tables are segmented so that
3888 * we don't need to allocate > 64K chunks for a full 16-bit table.
3889 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003890void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003891png_build_gamma_table(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003892{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003893 png_debug(1, "in png_build_gamma_table");
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003894
3895 if (png_ptr->bit_depth <= 8)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003896 {
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003897 int i;
3898 double g;
Guy Schalnat0d580581995-07-20 02:43:20 -05003899
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003900 if (png_ptr->screen_gamma > .000001)
3901 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
3902 else
3903 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003904
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003905 png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
3906 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05003907
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003908 for (i = 0; i < 256; i++)
3909 {
3910 png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
3911 g) * 255.0 + .5);
3912 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003913
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003914#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003915 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
3916 if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
3917 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003918
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003919 g = 1.0 / (png_ptr->gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05003920
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003921 png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
3922 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05003923
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003924 for (i = 0; i < 256; i++)
3925 {
3926 png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
3927 g) * 255.0 + .5);
3928 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003929
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003930
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003931 png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
3932 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05003933
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003934 if (png_ptr->screen_gamma > 0.000001)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003935 g = 1.0 / png_ptr->screen_gamma;
3936 else
3937 g = png_ptr->gamma; /* probably doing rgb_to_gray */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003938
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003939 for (i = 0; i < 256; i++)
3940 {
3941 png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
3942 g) * 255.0 + .5);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003943
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003944 }
3945 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003946#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003947 }
3948 else
3949 {
3950 double g;
3951 int i, j, shift, num;
3952 int sig_bit;
3953 png_uint_32 ig;
Guy Schalnat0d580581995-07-20 02:43:20 -05003954
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003955 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
3956 {
3957 sig_bit = (int)png_ptr->sig_bit.red;
3958 if ((int)png_ptr->sig_bit.green > sig_bit)
3959 sig_bit = png_ptr->sig_bit.green;
3960 if ((int)png_ptr->sig_bit.blue > sig_bit)
3961 sig_bit = png_ptr->sig_bit.blue;
3962 }
3963 else
3964 {
3965 sig_bit = (int)png_ptr->sig_bit.gray;
3966 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003967
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003968 if (sig_bit > 0)
3969 shift = 16 - sig_bit;
3970 else
3971 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003972
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003973 if (png_ptr->transformations & PNG_16_TO_8)
3974 {
3975 if (shift < (16 - PNG_MAX_GAMMA_8))
3976 shift = (16 - PNG_MAX_GAMMA_8);
3977 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003978
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003979 if (shift > 8)
3980 shift = 8;
3981 if (shift < 0)
3982 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003983
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003984 png_ptr->gamma_shift = (png_byte)shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05003985
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003986 num = (1 << (8 - shift));
Guy Schalnat0d580581995-07-20 02:43:20 -05003987
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003988 if (png_ptr->screen_gamma > .000001)
3989 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
3990 else
3991 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003992
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06003993#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06003994 png_ptr->gamma_16_table = (png_uint_16pp)png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003995 (png_uint_32)(num * png_sizeof(png_uint_16p)));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06003996#else
3997 png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
3998 (png_uint_32)(num * png_sizeof(png_uint_16p)));
3999 png_memset(png_ptr->gamma_16_table, 0, num * png_sizeof(png_uint_16p));
4000#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05004001
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004002 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
4003 {
4004 double fin, fout;
4005 png_uint_32 last, max;
Guy Schalnat0d580581995-07-20 02:43:20 -05004006
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004007 for (i = 0; i < num; i++)
4008 {
4009 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004010 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004011 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004012
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004013 g = 1.0 / g;
4014 last = 0;
4015 for (i = 0; i < 256; i++)
4016 {
4017 fout = ((double)i + 0.5) / 256.0;
4018 fin = pow(fout, g);
4019 max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
4020 while (last <= max)
4021 {
4022 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4023 [(int)(last >> (8 - shift))] = (png_uint_16)(
4024 (png_uint_16)i | ((png_uint_16)i << 8));
4025 last++;
4026 }
4027 }
4028 while (last < ((png_uint_32)num << 8))
4029 {
4030 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4031 [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
4032 last++;
4033 }
4034 }
4035 else
4036 {
4037 for (i = 0; i < num; i++)
4038 {
4039 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004040 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004041
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004042 ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
4043 for (j = 0; j < 256; j++)
4044 {
4045 png_ptr->gamma_16_table[i][j] =
4046 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4047 65535.0, g) * 65535.0 + .5);
4048 }
4049 }
4050 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004051
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004052#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004053 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4054 if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
4055 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004056
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004057 g = 1.0 / (png_ptr->gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05004058
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004059#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06004060 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004061 (png_uint_32)(num * png_sizeof(png_uint_16p )));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004062#else
4063 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
4064 (png_uint_32)(num * png_sizeof(png_uint_16p )));
4065 png_memset(png_ptr->gamma_16_to_1, 0, num * png_sizeof(png_uint_16p));
4066#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05004067
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004068 for (i = 0; i < num; i++)
4069 {
4070 png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004071 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004072
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004073 ig = (((png_uint_32)i *
4074 (png_uint_32)png_gamma_shift[shift]) >> 4);
4075 for (j = 0; j < 256; j++)
4076 {
4077 png_ptr->gamma_16_to_1[i][j] =
4078 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4079 65535.0, g) * 65535.0 + .5);
4080 }
4081 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004082
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004083 if (png_ptr->screen_gamma > 0.000001)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004084 g = 1.0 / png_ptr->screen_gamma;
4085 else
4086 g = png_ptr->gamma; /* probably doing rgb_to_gray */
Guy Schalnat0d580581995-07-20 02:43:20 -05004087
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004088#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06004089 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004090 (png_uint_32)(num * png_sizeof(png_uint_16p)));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004091#else
4092 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
4093 (png_uint_32)(num * png_sizeof(png_uint_16p)));
4094 png_memset(png_ptr->gamma_16_from_1, 0,
4095 num * png_sizeof(png_uint_16p));
4096#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05004097
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004098 for (i = 0; i < num; i++)
4099 {
4100 png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004101 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004102
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004103 ig = (((png_uint_32)i *
4104 (png_uint_32)png_gamma_shift[shift]) >> 4);
4105 for (j = 0; j < 256; j++)
4106 {
4107 png_ptr->gamma_16_from_1[i][j] =
4108 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4109 65535.0, g) * 65535.0 + .5);
4110 }
4111 }
4112 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004113#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004114 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004115}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004116#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06004117/* To do: install integer version of png_build_gamma_table here */
4118#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004119
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004120#if defined(PNG_MNG_FEATURES_SUPPORTED)
4121/* undoes intrapixel differencing */
4122void /* PRIVATE */
4123png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
4124{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05004125 png_debug(1, "in png_do_read_intrapixel");
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004126 if (
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004127 (row_info->color_type & PNG_COLOR_MASK_COLOR))
4128 {
4129 int bytes_per_pixel;
4130 png_uint_32 row_width = row_info->width;
4131 if (row_info->bit_depth == 8)
4132 {
4133 png_bytep rp;
4134 png_uint_32 i;
4135
4136 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4137 bytes_per_pixel = 3;
4138 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4139 bytes_per_pixel = 4;
4140 else
4141 return;
4142
4143 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4144 {
4145 *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff);
4146 *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff);
4147 }
4148 }
4149 else if (row_info->bit_depth == 16)
4150 {
4151 png_bytep rp;
4152 png_uint_32 i;
4153
4154 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4155 bytes_per_pixel = 6;
4156 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4157 bytes_per_pixel = 8;
4158 else
4159 return;
4160
4161 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4162 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004163 png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1);
4164 png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3);
4165 png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5);
4166 png_uint_32 red = (png_uint_32)((s0 + s1 + 65536L) & 0xffffL);
4167 png_uint_32 blue = (png_uint_32)((s2 + s1 + 65536L) & 0xffffL);
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05004168 *(rp ) = (png_byte)((red >> 8) & 0xff);
4169 *(rp+1) = (png_byte)(red & 0xff);
4170 *(rp+4) = (png_byte)((blue >> 8) & 0xff);
4171 *(rp+5) = (png_byte)(blue & 0xff);
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004172 }
4173 }
4174 }
4175}
4176#endif /* PNG_MNG_FEATURES_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004177#endif /* PNG_READ_SUPPORTED */