blob: fa81922681335ed075519650d7e4bff3bdd23833 [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-Pehrsonbc7156d2009-07-06 09:11:54 -05004 * Last changed in libpng 1.4.0 [July 6, 2009]
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06005 * Copyright (c) 1998-2009 Glenn Randers-Pehrson
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05006 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06008 *
Glenn Randers-Pehrsonbfbf8652009-06-26 21:46:52 -05009 * This code is released under the libpng license.
Glenn Randers-Pehrsonc332bbc2009-06-25 13:43:50 -050010 * For conditions of distribution and use, see the disclaimer
Glenn Randers-Pehrson037023b2009-06-24 10:27:36 -050011 * and license in png.h
Glenn Randers-Pehrson3e61d792009-06-24 09:31:28 -050012 *
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -060013 * This file contains functions optionally called by an application
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060014 * in order to tell libpng how to handle data when reading a PNG.
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050015 * Transformations that are used in both reading and writing are
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060016 * in pngtrans.c.
17 */
Guy Schalnat0d580581995-07-20 02:43:20 -050018
Guy Schalnat0d580581995-07-20 02:43:20 -050019#include "png.h"
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060020#if defined(PNG_READ_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050021#include "pngpriv.h"
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060022
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060023/* Set the action on getting a CRC error for an ancillary or critical chunk. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050024void PNGAPI
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060025png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
26{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -050027 png_debug(1, "in png_set_crc_action");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060028 /* Tell libpng how we react to CRC errors in critical chunks */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050029 if (png_ptr == NULL)
30 return;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060031 switch (crit_action)
32 {
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050033 case PNG_CRC_NO_CHANGE: /* Leave setting as is */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060034 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050035
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050036 case PNG_CRC_WARN_USE: /* Warn/use data */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060037 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
38 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
39 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050040
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050041 case PNG_CRC_QUIET_USE: /* Quiet/use data */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060042 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
43 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
44 PNG_FLAG_CRC_CRITICAL_IGNORE;
45 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050046
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050047 case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050048 png_warning(png_ptr,
49 "Can't discard critical data on CRC error");
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050050 case PNG_CRC_ERROR_QUIT: /* Error/quit */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050051
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060052 case PNG_CRC_DEFAULT:
53 default:
54 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
55 break;
56 }
57
58 switch (ancil_action)
59 {
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050060 case PNG_CRC_NO_CHANGE: /* Leave setting as is */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060061 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050062
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050063 case PNG_CRC_WARN_USE: /* Warn/use data */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060064 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
65 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
66 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050067
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050068 case PNG_CRC_QUIET_USE: /* Quiet/use data */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060069 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
70 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
71 PNG_FLAG_CRC_ANCILLARY_NOWARN;
72 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050073
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050074 case PNG_CRC_ERROR_QUIT: /* Error/quit */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060075 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
76 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
77 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050078
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050079 case PNG_CRC_WARN_DISCARD: /* Warn/discard data */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050080
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060081 case PNG_CRC_DEFAULT:
82 default:
83 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
84 break;
85 }
86}
87
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060088#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
89 defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050090/* Handle alpha and tRNS via a background color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050091void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060092png_set_background(png_structp png_ptr,
93 png_color_16p background_color, int background_gamma_code,
Guy Schalnat51f0eb41995-09-26 05:22:39 -050094 int need_expand, double background_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -050095{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -050096 png_debug(1, "in png_set_background");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050097 if (png_ptr == NULL)
98 return;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060099 if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
100 {
101 png_warning(png_ptr, "Application must supply a known background gamma");
102 return;
103 }
104
Guy Schalnat0d580581995-07-20 02:43:20 -0500105 png_ptr->transformations |= PNG_BACKGROUND;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500106 png_memcpy(&(png_ptr->background), background_color,
107 png_sizeof(png_color_16));
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500108 png_ptr->background_gamma = (float)background_gamma;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600109 png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
Guy Schalnate5a37791996-06-05 15:50:50 -0500110 png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500111}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500112#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500113
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500114#if defined(PNG_READ_16_TO_8_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500115/* Strip 16 bit depth files to 8 bit depth */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500116void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600117png_set_strip_16(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500118{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500119 png_debug(1, "in png_set_strip_16");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500120 if (png_ptr == NULL)
121 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500122 png_ptr->transformations |= PNG_16_TO_8;
123}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500124#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500125
Andreas Dilger47a0c421997-05-16 02:46:07 -0500126#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500127void PNGAPI
Andreas Dilger47a0c421997-05-16 02:46:07 -0500128png_set_strip_alpha(png_structp png_ptr)
129{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500130 png_debug(1, "in png_set_strip_alpha");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500131 if (png_ptr == NULL)
132 return;
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -0600133 png_ptr->flags |= PNG_FLAG_STRIP_ALPHA;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500134}
135#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500136
Glenn Randers-Pehrson41983602008-08-18 21:52:21 -0500137#if defined(PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED)
138void PNGAPI
139png_set_premultiply_alpha(png_structp png_ptr)
140{
Glenn Randers-Pehrsond6d80752008-12-02 09:49:43 -0600141 png_debug(1, "in png_set_premultiply_alpha");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500142 if(png_ptr == NULL)
143 return;
Glenn Randers-Pehrson41983602008-08-18 21:52:21 -0500144 png_ptr->transformations |=
145 (PNG_PREMULTIPLY_ALPHA | PNG_EXPAND_tRNS);
146 png_ptr->transformations |=
147 PNG_EXPAND; /* This shouldn't be necessary */
148 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
149}
150#endif
151
Andreas Dilger47a0c421997-05-16 02:46:07 -0500152#if defined(PNG_READ_DITHER_SUPPORTED)
153/* Dither file to 8 bit. Supply a palette, the current number
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600154 * of elements in the palette, the maximum number of elements
155 * allowed, and a histogram if possible. If the current number
156 * of colors is greater then the maximum number, the palette will be
157 * modified to fit in the maximum number. "full_dither" indicates
158 * whether we need a dithering cube set up for RGB images, or if we
159 * simply are reducing the number of colors in a paletted image.
160 */
Guy Schalnat6d764711995-12-19 03:22:19 -0600161
162typedef struct png_dsort_struct
Guy Schalnat0d580581995-07-20 02:43:20 -0500163{
Guy Schalnat6d764711995-12-19 03:22:19 -0600164 struct png_dsort_struct FAR * next;
Guy Schalnat0d580581995-07-20 02:43:20 -0500165 png_byte left;
166 png_byte right;
Guy Schalnat6d764711995-12-19 03:22:19 -0600167} png_dsort;
168typedef png_dsort FAR * png_dsortp;
169typedef png_dsort FAR * FAR * png_dsortpp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500170
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500171void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600172png_set_dither(png_structp png_ptr, png_colorp palette,
173 int num_palette, int maximum_colors, png_uint_16p histogram,
Guy Schalnat0d580581995-07-20 02:43:20 -0500174 int full_dither)
175{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500176 png_debug(1, "in png_set_dither");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500177 if (png_ptr == NULL)
178 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500179 png_ptr->transformations |= PNG_DITHER;
180
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600181 if (!full_dither)
Guy Schalnat0d580581995-07-20 02:43:20 -0500182 {
183 int i;
184
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600185 png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500186 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500187 for (i = 0; i < num_palette; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600188 png_ptr->dither_index[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500189 }
190
191 if (num_palette > maximum_colors)
192 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500193 if (histogram != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500194 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500195 /* This is easy enough, just throw out the least used colors.
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500196 * Perhaps not the best solution, but good enough.
197 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500198
199 int i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500200
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500201 /* Initialize an array to sort colors */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500202 png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500203 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500204
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500205 /* Initialize the dither_sort array */
Guy Schalnat0d580581995-07-20 02:43:20 -0500206 for (i = 0; i < num_palette; i++)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500207 png_ptr->dither_sort[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500208
Andreas Dilger47a0c421997-05-16 02:46:07 -0500209 /* Find the least used palette entries by starting a
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500210 * bubble sort, and running it until we have sorted
211 * out enough colors. Note that we don't care about
212 * sorting all the colors, just finding which are
213 * least used.
214 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500215
216 for (i = num_palette - 1; i >= maximum_colors; i--)
217 {
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500218 int done; /* To stop early if the list is pre-sorted */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600219 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500220
221 done = 1;
222 for (j = 0; j < i; j++)
223 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500224 if (histogram[png_ptr->dither_sort[j]]
225 < histogram[png_ptr->dither_sort[j + 1]])
Guy Schalnat0d580581995-07-20 02:43:20 -0500226 {
227 png_byte t;
228
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500229 t = png_ptr->dither_sort[j];
230 png_ptr->dither_sort[j] = png_ptr->dither_sort[j + 1];
231 png_ptr->dither_sort[j + 1] = t;
Guy Schalnat0d580581995-07-20 02:43:20 -0500232 done = 0;
233 }
234 }
235 if (done)
236 break;
237 }
238
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500239 /* Swap the palette around, and set up a table, if necessary */
Guy Schalnat0d580581995-07-20 02:43:20 -0500240 if (full_dither)
241 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500242 int j = num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500243
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500244 /* Put all the useful colors within the max, but don't
245 * move the others.
246 */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500247 for (i = 0; i < maximum_colors; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500248 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500249 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500250 {
251 do
252 j--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500253 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
Guy Schalnat0d580581995-07-20 02:43:20 -0500254 palette[i] = palette[j];
255 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600256 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500257 }
258 else
259 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500260 int j = num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500261
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500262 /* Move all the used colors inside the max limit, and
263 * develop a translation table.
264 */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500265 for (i = 0; i < maximum_colors; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500266 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500267 /* Only move the colors we need to */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500268 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500269 {
270 png_color tmp_color;
271
272 do
273 j--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500274 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
Guy Schalnat0d580581995-07-20 02:43:20 -0500275
276 tmp_color = palette[j];
277 palette[j] = palette[i];
278 palette[i] = tmp_color;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500279 /* Indicate where the color went */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600280 png_ptr->dither_index[j] = (png_byte)i;
281 png_ptr->dither_index[i] = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500282 }
283 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500284
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500285 /* Find closest color for those colors we are not using */
Guy Schalnat0d580581995-07-20 02:43:20 -0500286 for (i = 0; i < num_palette; i++)
287 {
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600288 if ((int)png_ptr->dither_index[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500289 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500290 int min_d, k, min_k, d_index;
Guy Schalnat0d580581995-07-20 02:43:20 -0500291
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500292 /* Find the closest color to one we threw out */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500293 d_index = png_ptr->dither_index[i];
294 min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
295 for (k = 1, min_k = 0; k < maximum_colors; k++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500296 {
297 int d;
298
Andreas Dilger47a0c421997-05-16 02:46:07 -0500299 d = PNG_COLOR_DIST(palette[d_index], palette[k]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500300
301 if (d < min_d)
302 {
303 min_d = d;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500304 min_k = k;
Guy Schalnat0d580581995-07-20 02:43:20 -0500305 }
306 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500307 /* Point to closest color */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500308 png_ptr->dither_index[i] = (png_byte)min_k;
Guy Schalnat0d580581995-07-20 02:43:20 -0500309 }
310 }
311 }
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500312 png_free(png_ptr, png_ptr->dither_sort);
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500313 png_ptr->dither_sort = NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500314 }
315 else
316 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500317 /* This is much harder to do simply (and quickly). Perhaps
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500318 * we need to go through a median cut routine, but those
319 * don't always behave themselves with only a few colors
320 * as input. So we will just find the closest two colors,
321 * and throw out one of them (chosen somewhat randomly).
322 * [We don't understand this at all, so if someone wants to
323 * work on improving it, be our guest - AED, GRP]
324 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500325 int i;
326 int max_d;
327 int num_new_palette;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500328 png_dsortp t;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600329 png_dsortpp hash;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500330
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500331 t = NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500332
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500333 /* Initialize palette index arrays */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500334 png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500335 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500336 png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500337 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500338
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500339 /* Initialize the sort array */
Guy Schalnat0d580581995-07-20 02:43:20 -0500340 for (i = 0; i < num_palette; i++)
341 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500342 png_ptr->index_to_palette[i] = (png_byte)i;
343 png_ptr->palette_to_index[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500344 }
345
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -0600346#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600347 hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 *
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500348 png_sizeof(png_dsortp)));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -0600349#else
350 hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 *
351 png_sizeof(png_dsortp)));
352 png_memset(hash, 0, 769 * png_sizeof(png_dsortp));
353#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500354
355 num_new_palette = num_palette;
356
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500357 /* Initial wild guess at how far apart the farthest pixel
358 * pair we will be eliminating will be. Larger
359 * numbers mean more areas will be allocated, Smaller
360 * numbers run the risk of not saving enough data, and
361 * having to do this all over again.
362 *
363 * I have not done extensive checking on this number.
364 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500365 max_d = 96;
366
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600367 while (num_new_palette > maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500368 {
369 for (i = 0; i < num_new_palette - 1; i++)
370 {
371 int j;
372
373 for (j = i + 1; j < num_new_palette; j++)
374 {
375 int d;
376
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600377 d = PNG_COLOR_DIST(palette[i], palette[j]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500378
379 if (d <= max_d)
380 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500381
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500382 t = (png_dsortp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500383 (png_uint_32)(png_sizeof(png_dsort)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500384 if (t == NULL)
385 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500386 t->next = hash[d];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600387 t->left = (png_byte)i;
388 t->right = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500389 hash[d] = t;
390 }
391 }
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500392 if (t == NULL)
393 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500394 }
395
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500396 if (t != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500397 for (i = 0; i <= max_d; i++)
398 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500399 if (hash[i] != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500400 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600401 png_dsortp p;
Guy Schalnat0d580581995-07-20 02:43:20 -0500402
403 for (p = hash[i]; p; p = p->next)
404 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500405 if ((int)png_ptr->index_to_palette[p->left]
406 < num_new_palette &&
407 (int)png_ptr->index_to_palette[p->right]
408 < num_new_palette)
Guy Schalnat0d580581995-07-20 02:43:20 -0500409 {
410 int j, next_j;
411
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600412 if (num_new_palette & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -0500413 {
414 j = p->left;
415 next_j = p->right;
416 }
417 else
418 {
419 j = p->right;
420 next_j = p->left;
421 }
422
423 num_new_palette--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500424 palette[png_ptr->index_to_palette[j]]
425 = palette[num_new_palette];
Guy Schalnat0d580581995-07-20 02:43:20 -0500426 if (!full_dither)
427 {
428 int k;
429
430 for (k = 0; k < num_palette; k++)
431 {
432 if (png_ptr->dither_index[k] ==
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500433 png_ptr->index_to_palette[j])
Guy Schalnat0d580581995-07-20 02:43:20 -0500434 png_ptr->dither_index[k] =
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500435 png_ptr->index_to_palette[next_j];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600436 if ((int)png_ptr->dither_index[k] ==
Guy Schalnat0d580581995-07-20 02:43:20 -0500437 num_new_palette)
438 png_ptr->dither_index[k] =
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500439 png_ptr->index_to_palette[j];
Guy Schalnat0d580581995-07-20 02:43:20 -0500440 }
441 }
442
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500443 png_ptr->index_to_palette[png_ptr->palette_to_index
444 [num_new_palette]] = png_ptr->index_to_palette[j];
445 png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
446 = png_ptr->palette_to_index[num_new_palette];
Guy Schalnat0d580581995-07-20 02:43:20 -0500447
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500448 png_ptr->index_to_palette[j] = (png_byte)num_new_palette;
449 png_ptr->palette_to_index[num_new_palette] = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500450 }
451 if (num_new_palette <= maximum_colors)
452 break;
453 }
454 if (num_new_palette <= maximum_colors)
455 break;
456 }
457 }
458
459 for (i = 0; i < 769; i++)
460 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500461 if (hash[i] != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500462 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500463 png_dsortp p = hash[i];
Guy Schalnat0d580581995-07-20 02:43:20 -0500464 while (p)
465 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500466 t = p->next;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600467 png_free(png_ptr, p);
Guy Schalnat0d580581995-07-20 02:43:20 -0500468 p = t;
469 }
470 }
471 hash[i] = 0;
472 }
473 max_d += 96;
474 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600475 png_free(png_ptr, hash);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500476 png_free(png_ptr, png_ptr->palette_to_index);
477 png_free(png_ptr, png_ptr->index_to_palette);
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500478 png_ptr->palette_to_index = NULL;
479 png_ptr->index_to_palette = NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500480 }
481 num_palette = maximum_colors;
482 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500483 if (png_ptr->palette == NULL)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600484 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500485 png_ptr->palette = palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500486 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600487 png_ptr->num_palette = (png_uint_16)num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500488
489 if (full_dither)
490 {
491 int i;
Guy Schalnat6d764711995-12-19 03:22:19 -0600492 png_bytep distance;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500493 int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600494 PNG_DITHER_BLUE_BITS;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500495 int num_red = (1 << PNG_DITHER_RED_BITS);
496 int num_green = (1 << PNG_DITHER_GREEN_BITS);
497 int num_blue = (1 << PNG_DITHER_BLUE_BITS);
498 png_size_t num_entries = ((png_size_t)1 << total_bits);
Guy Schalnat0d580581995-07-20 02:43:20 -0500499
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -0600500#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600501 png_ptr->palette_lookup = (png_bytep )png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500502 (png_uint_32)(num_entries * png_sizeof(png_byte)));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -0600503#else
504 png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
505 (png_uint_32)(num_entries * png_sizeof(png_byte)));
506 png_memset(png_ptr->palette_lookup, 0, num_entries *
507 png_sizeof(png_byte));
508#endif
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500509
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500510 distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
511 png_sizeof(png_byte)));
Glenn Randers-Pehrsone1eff582001-04-14 20:15:41 -0500512
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500513 png_memset(distance, 0xff, num_entries * png_sizeof(png_byte));
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500514
515 for (i = 0; i < num_palette; i++)
516 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500517 int ir, ig, ib;
518 int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
519 int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
520 int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
Guy Schalnat0d580581995-07-20 02:43:20 -0500521
522 for (ir = 0; ir < num_red; ir++)
523 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500524 /* int dr = abs(ir - r); */
525 int dr = ((ir > r) ? ir - r : r - ir);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500526 int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
Guy Schalnat0d580581995-07-20 02:43:20 -0500527
Guy Schalnat0d580581995-07-20 02:43:20 -0500528 for (ig = 0; ig < num_green; ig++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600529 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500530 /* int dg = abs(ig - g); */
531 int dg = ((ig > g) ? ig - g : g - ig);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500532 int dt = dr + dg;
533 int dm = ((dr > dg) ? dr : dg);
534 int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
Guy Schalnat0d580581995-07-20 02:43:20 -0500535
Guy Schalnat0d580581995-07-20 02:43:20 -0500536 for (ib = 0; ib < num_blue; ib++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600537 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500538 int d_index = index_g | ib;
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500539 /* int db = abs(ib - b); */
540 int db = ((ib > b) ? ib - b : b - ib);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500541 int dmax = ((dm > db) ? dm : db);
542 int d = dmax + dt + db;
Guy Schalnat0d580581995-07-20 02:43:20 -0500543
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600544 if (d < (int)distance[d_index])
Guy Schalnat0d580581995-07-20 02:43:20 -0500545 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500546 distance[d_index] = (png_byte)d;
547 png_ptr->palette_lookup[d_index] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500548 }
549 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500550 }
551 }
552 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500553
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600554 png_free(png_ptr, distance);
Guy Schalnat0d580581995-07-20 02:43:20 -0500555 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500556}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500557#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500558
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600559#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600560/* Transform the image from the file_gamma to the screen_gamma. We
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600561 * only do transformations on images where the file_gamma and screen_gamma
562 * are not close reciprocals, otherwise it slows things down slightly, and
563 * also needlessly introduces small errors.
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600564 *
565 * We will turn off gamma transformation later if no semitransparent entries
566 * are present in the tRNS array for palette images. We can't do it here
567 * because we don't necessarily have the tRNS chunk yet.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600568 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500569void PNGAPI
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600570png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -0500571{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500572 png_debug(1, "in png_set_gamma");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500573 if (png_ptr == NULL)
574 return;
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600575 if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) ||
576 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) ||
577 (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
578 png_ptr->transformations |= PNG_GAMMA;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500579 png_ptr->gamma = (float)file_gamma;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600580 png_ptr->screen_gamma = (float)scrn_gamma;
Guy Schalnat0d580581995-07-20 02:43:20 -0500581}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500582#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500583
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500584#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -0500585/* Expand paletted images to RGB, expand grayscale images of
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500586 * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600587 * to alpha channels.
588 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500589void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600590png_set_expand(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500591{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500592 png_debug(1, "in png_set_expand");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500593 if (png_ptr == NULL)
594 return;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600595 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500596 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -0500597}
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500598
599/* GRR 19990627: the following three functions currently are identical
600 * to png_set_expand(). However, it is entirely reasonable that someone
601 * might wish to expand an indexed image to RGB but *not* expand a single,
602 * fully transparent palette entry to a full alpha channel--perhaps instead
603 * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
604 * the transparent color with a particular RGB value, or drop tRNS entirely.
605 * IOW, a future version of the library may make the transformations flag
606 * a bit more fine-grained, with separate bits for each of these three
607 * functions.
608 *
609 * More to the point, these functions make it obvious what libpng will be
610 * doing, whereas "expand" can (and does) mean any number of things.
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600611 *
612 * GRP 20060307: In libpng-1.4.0, png_set_gray_1_2_4_to_8() was modified
613 * to expand only the sample depth but not to expand the tRNS to alpha.
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500614 */
615
616/* Expand paletted images to RGB. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500617void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500618png_set_palette_to_rgb(png_structp png_ptr)
619{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500620 png_debug(1, "in png_set_palette_to_rgb");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500621 if (png_ptr == NULL)
622 return;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600623 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500624 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500625}
626
627/* Expand grayscale images of less than 8-bit depth to 8 bits. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500628void PNGAPI
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600629png_set_expand_gray_1_2_4_to_8(png_structp png_ptr)
630{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500631 png_debug(1, "in png_set_expand_gray_1_2_4_to_8");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500632 if (png_ptr == NULL)
633 return;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500634 png_ptr->transformations |= PNG_EXPAND;
635 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600636}
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500637
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500638
639
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500640/* Expand tRNS chunks to alpha channels. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500641void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500642png_set_tRNS_to_alpha(png_structp png_ptr)
643{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500644 png_debug(1, "in png_set_tRNS_to_alpha");
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600645 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500646 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500647}
648#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500649
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500650#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500651void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600652png_set_gray_to_rgb(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500653{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500654 png_debug(1, "in png_set_gray_to_rgb");
Guy Schalnat0d580581995-07-20 02:43:20 -0500655 png_ptr->transformations |= PNG_GRAY_TO_RGB;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500656 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -0500657}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500658#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500659
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600660#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
661#if defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600662/* Convert a RGB image to a grayscale of the same width. This allows us,
663 * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600664 */
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600665
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500666void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500667png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red,
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600668 double green)
669{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500670 int red_fixed = (int)((float)red*100000.0 + 0.5);
671 int green_fixed = (int)((float)green*100000.0 + 0.5);
672 if (png_ptr == NULL)
673 return;
674 png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed);
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600675}
676#endif
677
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500678void PNGAPI
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600679png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
680 png_fixed_point red, png_fixed_point green)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600681{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500682 png_debug(1, "in png_set_rgb_to_gray");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500683 if (png_ptr == NULL)
684 return;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600685 switch(error_action)
686 {
687 case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY;
688 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500689
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600690 case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
691 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500692
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600693 case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
694 }
695 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
696#if defined(PNG_READ_EXPAND_SUPPORTED)
697 png_ptr->transformations |= PNG_EXPAND;
698#else
699 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500700 png_warning(png_ptr,
701 "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED");
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600702 png_ptr->transformations &= ~PNG_RGB_TO_GRAY;
703 }
704#endif
705 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600706 png_uint_16 red_int, green_int;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500707 if (red < 0 || green < 0)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600708 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600709 red_int = 6968; /* .212671 * 32768 + .5 */
710 green_int = 23434; /* .715160 * 32768 + .5 */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600711 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500712 else if (red + green < 100000L)
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600713 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500714 red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
715 green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600716 }
717 else
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600718 {
719 png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600720 red_int = 6968;
721 green_int = 23434;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600722 }
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600723 png_ptr->rgb_to_gray_red_coeff = red_int;
724 png_ptr->rgb_to_gray_green_coeff = green_int;
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600725 png_ptr->rgb_to_gray_blue_coeff =
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500726 (png_uint_16)(32768 - red_int - green_int);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600727 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600728}
729#endif
730
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500731#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
Glenn Randers-Pehrson33188ac2009-06-16 14:12:35 -0500732 defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500733void PNGAPI
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600734png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
735 read_user_transform_fn)
736{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500737 png_debug(1, "in png_set_read_user_transform_fn");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500738 if (png_ptr == NULL)
739 return;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500740#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600741 png_ptr->transformations |= PNG_USER_TRANSFORM;
742 png_ptr->read_user_transform_fn = read_user_transform_fn;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500743#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600744}
745#endif
746
Andreas Dilger47a0c421997-05-16 02:46:07 -0500747/* Initialize everything needed for the read. This includes modifying
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600748 * the palette.
749 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500750void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -0600751png_init_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500752{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500753 png_debug(1, "in png_init_read_transformations");
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500754 {
755#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
756 || defined(PNG_READ_GAMMA_SUPPORTED)
757 int color_type = png_ptr->color_type;
758#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500759
Guy Schalnate5a37791996-06-05 15:50:50 -0500760#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500761
762#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
763 /* Detect gray background and attempt to enable optimization
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500764 * for gray --> RGB case
765 *
766 * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500767 * RGB_ALPHA (in which case need_expand is superfluous anyway), the
768 * background color might actually be gray yet not be flagged as such.
769 * This is not a problem for the current code, which uses
770 * PNG_BACKGROUND_IS_GRAY only to decide when to do the
771 * png_do_gray_to_rgb() transformation.
772 */
773 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
774 !(color_type & PNG_COLOR_MASK_COLOR))
775 {
776 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
777 } else if ((png_ptr->transformations & PNG_BACKGROUND) &&
778 !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
779 (png_ptr->transformations & PNG_GRAY_TO_RGB) &&
780 png_ptr->background.red == png_ptr->background.green &&
781 png_ptr->background.red == png_ptr->background.blue)
782 {
783 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
784 png_ptr->background.gray = png_ptr->background.red;
785 }
786#endif
787
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600788 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
789 (png_ptr->transformations & PNG_EXPAND))
Guy Schalnat0d580581995-07-20 02:43:20 -0500790 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500791 if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
Guy Schalnat0d580581995-07-20 02:43:20 -0500792 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500793 /* Expand background and tRNS chunks */
Guy Schalnat0d580581995-07-20 02:43:20 -0500794 switch (png_ptr->bit_depth)
795 {
796 case 1:
Guy Schalnate5a37791996-06-05 15:50:50 -0500797 png_ptr->background.gray *= (png_uint_16)0xff;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600798 png_ptr->background.red = png_ptr->background.green
799 = png_ptr->background.blue = png_ptr->background.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600800 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
801 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -0500802 png_ptr->trans_color.gray *= (png_uint_16)0xff;
803 png_ptr->trans_color.red = png_ptr->trans_color.green
804 = png_ptr->trans_color.blue = png_ptr->trans_color.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600805 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500806 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500807
Guy Schalnat0d580581995-07-20 02:43:20 -0500808 case 2:
Guy Schalnate5a37791996-06-05 15:50:50 -0500809 png_ptr->background.gray *= (png_uint_16)0x55;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600810 png_ptr->background.red = png_ptr->background.green
811 = png_ptr->background.blue = png_ptr->background.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600812 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
813 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -0500814 png_ptr->trans_color.gray *= (png_uint_16)0x55;
815 png_ptr->trans_color.red = png_ptr->trans_color.green
816 = png_ptr->trans_color.blue = png_ptr->trans_color.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600817 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500818 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500819
Guy Schalnat0d580581995-07-20 02:43:20 -0500820 case 4:
Guy Schalnate5a37791996-06-05 15:50:50 -0500821 png_ptr->background.gray *= (png_uint_16)0x11;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600822 png_ptr->background.red = png_ptr->background.green
823 = png_ptr->background.blue = png_ptr->background.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600824 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
825 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -0500826 png_ptr->trans_color.gray *= (png_uint_16)0x11;
827 png_ptr->trans_color.red = png_ptr->trans_color.green
828 = png_ptr->trans_color.blue = png_ptr->trans_color.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600829 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500830 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500831
Guy Schalnate5a37791996-06-05 15:50:50 -0500832 case 8:
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500833
Guy Schalnate5a37791996-06-05 15:50:50 -0500834 case 16:
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600835 png_ptr->background.red = png_ptr->background.green
836 = png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500837 break;
838 }
839 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500840 else if (color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -0500841 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500842 png_ptr->background.red =
Guy Schalnat0d580581995-07-20 02:43:20 -0500843 png_ptr->palette[png_ptr->background.index].red;
844 png_ptr->background.green =
845 png_ptr->palette[png_ptr->background.index].green;
Guy Schalnate5a37791996-06-05 15:50:50 -0500846 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -0500847 png_ptr->palette[png_ptr->background.index].blue;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600848
849#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
850 if (png_ptr->transformations & PNG_INVERT_ALPHA)
851 {
852#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600853 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600854#endif
855 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500856 /* Invert the alpha channel (in tRNS) unless the pixels are
857 * going to be expanded, in which case leave it for later
858 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500859 int i, istop;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500860 istop=(int)png_ptr->num_trans;
861 for (i=0; i<istop; i++)
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -0500862 png_ptr->trans[i] = (png_byte)(255 - png_ptr->trans[i]);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600863 }
864 }
865#endif
866
Guy Schalnat0d580581995-07-20 02:43:20 -0500867 }
868 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500869#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500870
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500871#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500872 png_ptr->background_1 = png_ptr->background;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500873#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600874#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600875
876 if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0)
877 && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0)
878 < PNG_GAMMA_THRESHOLD))
879 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500880 int i, k;
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600881 k=0;
882 for (i=0; i<png_ptr->num_trans; i++)
883 {
884 if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500885 k=1; /* Partial transparency is present */
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600886 }
887 if (k == 0)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500888 png_ptr->transformations &= ~PNG_GAMMA;
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600889 }
890
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600891 if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) &&
892 png_ptr->gamma != 0.0)
Guy Schalnat0d580581995-07-20 02:43:20 -0500893 {
894 png_build_gamma_table(png_ptr);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500895#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Guy Schalnate5a37791996-06-05 15:50:50 -0500896 if (png_ptr->transformations & PNG_BACKGROUND)
Guy Schalnat0d580581995-07-20 02:43:20 -0500897 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500898 if (color_type == PNG_COLOR_TYPE_PALETTE)
899 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500900 /* Could skip if no transparency */
Guy Schalnate5a37791996-06-05 15:50:50 -0500901 png_color back, back_1;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500902 png_colorp palette = png_ptr->palette;
903 int num_palette = png_ptr->num_palette;
904 int i;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500905 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
906 {
907 back.red = png_ptr->gamma_table[png_ptr->background.red];
908 back.green = png_ptr->gamma_table[png_ptr->background.green];
909 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
Guy Schalnate5a37791996-06-05 15:50:50 -0500910
Andreas Dilger47a0c421997-05-16 02:46:07 -0500911 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
912 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
913 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
914 }
915 else
916 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600917 double g, gs;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500918
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600919 switch (png_ptr->background_gamma_type)
Glenn Randers-Pehrson4922b1b1998-03-08 22:55:17 -0600920 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600921 case PNG_BACKGROUND_GAMMA_SCREEN:
922 g = (png_ptr->screen_gamma);
923 gs = 1.0;
924 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500925
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600926 case PNG_BACKGROUND_GAMMA_FILE:
927 g = 1.0 / (png_ptr->gamma);
928 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
929 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500930
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600931 case PNG_BACKGROUND_GAMMA_UNIQUE:
932 g = 1.0 / (png_ptr->background_gamma);
933 gs = 1.0 / (png_ptr->background_gamma *
934 png_ptr->screen_gamma);
935 break;
936 default:
937 g = 1.0; /* back_1 */
938 gs = 1.0; /* back */
939 }
940
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -0600941 if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD)
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600942 {
943 back.red = (png_byte)png_ptr->background.red;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500944 back.green = (png_byte)png_ptr->background.green;
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600945 back.blue = (png_byte)png_ptr->background.blue;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500946 }
947 else
948 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600949 back.red = (png_byte)(pow(
950 (double)png_ptr->background.red/255, gs) * 255.0 + .5);
951 back.green = (png_byte)(pow(
952 (double)png_ptr->background.green/255, gs) * 255.0 + .5);
953 back.blue = (png_byte)(pow(
954 (double)png_ptr->background.blue/255, gs) * 255.0 + .5);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500955 }
956
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600957 back_1.red = (png_byte)(pow(
958 (double)png_ptr->background.red/255, g) * 255.0 + .5);
959 back_1.green = (png_byte)(pow(
960 (double)png_ptr->background.green/255, g) * 255.0 + .5);
961 back_1.blue = (png_byte)(pow(
962 (double)png_ptr->background.blue/255, g) * 255.0 + .5);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500963 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500964 for (i = 0; i < num_palette; i++)
965 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500966 if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
Guy Schalnate5a37791996-06-05 15:50:50 -0500967 {
968 if (png_ptr->trans[i] == 0)
969 {
970 palette[i] = back;
971 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500972 else /* if (png_ptr->trans[i] != 0xff) */
Guy Schalnate5a37791996-06-05 15:50:50 -0500973 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500974 png_byte v, w;
Guy Schalnate5a37791996-06-05 15:50:50 -0500975
976 v = png_ptr->gamma_to_1[palette[i].red];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500977 png_composite(w, v, png_ptr->trans[i], back_1.red);
Guy Schalnate5a37791996-06-05 15:50:50 -0500978 palette[i].red = png_ptr->gamma_from_1[w];
979
980 v = png_ptr->gamma_to_1[palette[i].green];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500981 png_composite(w, v, png_ptr->trans[i], back_1.green);
Guy Schalnate5a37791996-06-05 15:50:50 -0500982 palette[i].green = png_ptr->gamma_from_1[w];
983
984 v = png_ptr->gamma_to_1[palette[i].blue];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500985 png_composite(w, v, png_ptr->trans[i], back_1.blue);
Guy Schalnate5a37791996-06-05 15:50:50 -0500986 palette[i].blue = png_ptr->gamma_from_1[w];
987 }
988 }
989 else
990 {
991 palette[i].red = png_ptr->gamma_table[palette[i].red];
992 palette[i].green = png_ptr->gamma_table[palette[i].green];
993 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
994 }
995 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500996 /* Prevent the transformations being done again, and make sure
997 * that the now spurious alpha channel is stripped - the code
998 * has just reduced background composition and gamma correction
999 * to a simple alpha channel strip.
1000 */
1001 png_ptr->transformations &= ~PNG_BACKGROUND;
1002 png_ptr->transformations &= ~PNG_GAMMA;
1003 png_ptr->transformations |= PNG_STRIP_ALPHA;
Guy Schalnate5a37791996-06-05 15:50:50 -05001004 }
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001005 /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001006 else
1007 /* color_type != PNG_COLOR_TYPE_PALETTE */
Guy Schalnat0d580581995-07-20 02:43:20 -05001008 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001009 double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
1010 double g = 1.0;
1011 double gs = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05001012
1013 switch (png_ptr->background_gamma_type)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001014 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001015 case PNG_BACKGROUND_GAMMA_SCREEN:
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001016 g = (png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05001017 gs = 1.0;
1018 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001019
Guy Schalnat0d580581995-07-20 02:43:20 -05001020 case PNG_BACKGROUND_GAMMA_FILE:
1021 g = 1.0 / (png_ptr->gamma);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001022 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05001023 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001024
Guy Schalnat0d580581995-07-20 02:43:20 -05001025 case PNG_BACKGROUND_GAMMA_UNIQUE:
1026 g = 1.0 / (png_ptr->background_gamma);
1027 gs = 1.0 / (png_ptr->background_gamma *
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001028 png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05001029 break;
1030 }
1031
Glenn Randers-Pehrson377657d2002-03-08 01:31:27 -06001032 png_ptr->background_1.gray = (png_uint_16)(pow(
1033 (double)png_ptr->background.gray / m, g) * m + .5);
1034 png_ptr->background.gray = (png_uint_16)(pow(
1035 (double)png_ptr->background.gray / m, gs) * m + .5);
1036
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06001037 if ((png_ptr->background.red != png_ptr->background.green) ||
1038 (png_ptr->background.red != png_ptr->background.blue) ||
1039 (png_ptr->background.red != png_ptr->background.gray))
Guy Schalnat0d580581995-07-20 02:43:20 -05001040 {
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06001041 /* RGB or RGBA with color background */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001042 png_ptr->background_1.red = (png_uint_16)(pow(
Guy Schalnat0d580581995-07-20 02:43:20 -05001043 (double)png_ptr->background.red / m, g) * m + .5);
1044 png_ptr->background_1.green = (png_uint_16)(pow(
1045 (double)png_ptr->background.green / m, g) * m + .5);
1046 png_ptr->background_1.blue = (png_uint_16)(pow(
1047 (double)png_ptr->background.blue / m, g) * m + .5);
1048 png_ptr->background.red = (png_uint_16)(pow(
1049 (double)png_ptr->background.red / m, gs) * m + .5);
1050 png_ptr->background.green = (png_uint_16)(pow(
1051 (double)png_ptr->background.green / m, gs) * m + .5);
1052 png_ptr->background.blue = (png_uint_16)(pow(
1053 (double)png_ptr->background.blue / m, gs) * m + .5);
1054 }
1055 else
1056 {
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06001057 /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */
1058 png_ptr->background_1.red = png_ptr->background_1.green
1059 = png_ptr->background_1.blue = png_ptr->background_1.gray;
1060 png_ptr->background.red = png_ptr->background.green
1061 = png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05001062 }
1063 }
1064 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001065 else
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001066 /* Transformation does not include PNG_BACKGROUND */
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001067#endif /* PNG_READ_BACKGROUND_SUPPORTED */
Guy Schalnate5a37791996-06-05 15:50:50 -05001068 if (color_type == PNG_COLOR_TYPE_PALETTE)
1069 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001070 png_colorp palette = png_ptr->palette;
1071 int num_palette = png_ptr->num_palette;
1072 int i;
Guy Schalnate5a37791996-06-05 15:50:50 -05001073
1074 for (i = 0; i < num_palette; i++)
1075 {
1076 palette[i].red = png_ptr->gamma_table[palette[i].red];
1077 palette[i].green = png_ptr->gamma_table[palette[i].green];
1078 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
1079 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001080
1081 /* Done the gamma correction. */
1082 png_ptr->transformations &= ~PNG_GAMMA;
Guy Schalnate5a37791996-06-05 15:50:50 -05001083 }
1084 }
1085#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1086 else
1087#endif
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001088#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */
Guy Schalnate5a37791996-06-05 15:50:50 -05001089#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001090 /* No GAMMA transformation */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001091 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1092 (color_type == PNG_COLOR_TYPE_PALETTE))
Guy Schalnate5a37791996-06-05 15:50:50 -05001093 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001094 int i;
1095 int istop = (int)png_ptr->num_trans;
Guy Schalnate5a37791996-06-05 15:50:50 -05001096 png_color back;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001097 png_colorp palette = png_ptr->palette;
Guy Schalnate5a37791996-06-05 15:50:50 -05001098
Guy Schalnate5a37791996-06-05 15:50:50 -05001099 back.red = (png_byte)png_ptr->background.red;
1100 back.green = (png_byte)png_ptr->background.green;
1101 back.blue = (png_byte)png_ptr->background.blue;
1102
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001103 for (i = 0; i < istop; i++)
Guy Schalnate5a37791996-06-05 15:50:50 -05001104 {
1105 if (png_ptr->trans[i] == 0)
1106 {
1107 palette[i] = back;
1108 }
1109 else if (png_ptr->trans[i] != 0xff)
1110 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001111 /* The png_composite() macro is defined in png.h */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001112 png_composite(palette[i].red, palette[i].red,
1113 png_ptr->trans[i], back.red);
1114 png_composite(palette[i].green, palette[i].green,
1115 png_ptr->trans[i], back.green);
1116 png_composite(palette[i].blue, palette[i].blue,
1117 png_ptr->trans[i], back.blue);
Guy Schalnate5a37791996-06-05 15:50:50 -05001118 }
1119 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001120
1121 /* Handled alpha, still need to strip the channel. */
1122 png_ptr->transformations &= ~PNG_BACKGROUND;
1123 png_ptr->transformations |= PNG_STRIP_ALPHA;
Guy Schalnat0d580581995-07-20 02:43:20 -05001124 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001125#endif /* PNG_READ_BACKGROUND_SUPPORTED */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001126
Guy Schalnat6d764711995-12-19 03:22:19 -06001127#if defined(PNG_READ_SHIFT_SUPPORTED)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001128 if ((png_ptr->transformations & PNG_SHIFT) &&
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001129 (color_type == PNG_COLOR_TYPE_PALETTE))
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001130 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001131 png_uint_16 i;
1132 png_uint_16 istop = png_ptr->num_palette;
1133 int sr = 8 - png_ptr->sig_bit.red;
1134 int sg = 8 - png_ptr->sig_bit.green;
1135 int sb = 8 - png_ptr->sig_bit.blue;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001136
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001137 if (sr < 0 || sr > 8)
1138 sr = 0;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001139 if (sg < 0 || sg > 8)
1140 sg = 0;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001141 if (sb < 0 || sb > 8)
1142 sb = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001143 for (i = 0; i < istop; i++)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001144 {
1145 png_ptr->palette[i].red >>= sr;
1146 png_ptr->palette[i].green >>= sg;
1147 png_ptr->palette[i].blue >>= sb;
1148 }
1149 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001150#endif /* PNG_READ_SHIFT_SUPPORTED */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001151 }
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001152#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \
1153 && !defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001154 if (png_ptr)
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001155 return;
1156#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001157}
1158
Andreas Dilger47a0c421997-05-16 02:46:07 -05001159/* Modify the info structure to reflect the transformations. The
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001160 * info should be updated so a PNG file could be written with it,
1161 * assuming the transformations result in valid PNG data.
1162 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001163void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001164png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001165{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001166 png_debug(1, "in png_read_transform_info");
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001167#if defined(PNG_READ_EXPAND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001168 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001169 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001170 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1171 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001172 if (png_ptr->num_trans &&
1173 (png_ptr->transformations & PNG_EXPAND_tRNS))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001174 info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1175 else
1176 info_ptr->color_type = PNG_COLOR_TYPE_RGB;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001177 info_ptr->bit_depth = 8;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001178 info_ptr->num_trans = 0;
1179 }
1180 else
1181 {
1182 if (png_ptr->num_trans)
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -06001183 {
1184 if (png_ptr->transformations & PNG_EXPAND_tRNS)
1185 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -06001186 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001187 if (info_ptr->bit_depth < 8)
1188 info_ptr->bit_depth = 8;
1189 info_ptr->num_trans = 0;
1190 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001191 }
1192#endif
1193
1194#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1195 if (png_ptr->transformations & PNG_BACKGROUND)
1196 {
1197 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
1198 info_ptr->num_trans = 0;
1199 info_ptr->background = png_ptr->background;
1200 }
1201#endif
1202
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001203#if defined(PNG_READ_GAMMA_SUPPORTED)
1204 if (png_ptr->transformations & PNG_GAMMA)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001205 {
1206#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001207 info_ptr->gamma = png_ptr->gamma;
1208#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001209#ifdef PNG_FIXED_POINT_SUPPORTED
1210 info_ptr->int_gamma = png_ptr->int_gamma;
1211#endif
1212 }
1213#endif
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001214
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001215#if defined(PNG_READ_16_TO_8_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001216 if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001217 info_ptr->bit_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001218#endif
1219
Glenn Randers-Pehrsonddfebd32006-02-22 09:19:25 -06001220#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1221 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
1222 info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
1223#endif
1224
1225#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1226 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1227 info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
1228#endif
1229
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001230#if defined(PNG_READ_DITHER_SUPPORTED)
1231 if (png_ptr->transformations & PNG_DITHER)
1232 {
1233 if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001234 (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
1235 png_ptr->palette_lookup && info_ptr->bit_depth == 8)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001236 {
1237 info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
1238 }
1239 }
1240#endif
1241
1242#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001243 if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001244 info_ptr->bit_depth = 8;
1245#endif
1246
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001247 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001248 info_ptr->channels = 1;
1249 else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
1250 info_ptr->channels = 3;
1251 else
1252 info_ptr->channels = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001253
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001254#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001255 if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001256 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001257#endif
1258
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001259 if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
1260 info_ptr->channels++;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001261
1262#if defined(PNG_READ_FILLER_SUPPORTED)
1263 /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001264 if ((png_ptr->transformations & PNG_FILLER) &&
1265 ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
1266 (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001267 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001268 info_ptr->channels++;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001269 /* If adding a true alpha channel not just filler */
Glenn Randers-Pehrson67864af2004-08-28 23:30:07 -05001270 if (png_ptr->transformations & PNG_ADD_ALPHA)
1271 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001272 }
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001273#endif
1274
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001275#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
1276defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001277 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001278 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001279 if (info_ptr->bit_depth < png_ptr->user_transform_depth)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001280 info_ptr->bit_depth = png_ptr->user_transform_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001281 if (info_ptr->channels < png_ptr->user_transform_channels)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001282 info_ptr->channels = png_ptr->user_transform_channels;
1283 }
1284#endif
1285
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001286 info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
1287 info_ptr->bit_depth);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001288
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001289 info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width);
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05001290
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001291#if !defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001292 if (png_ptr)
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001293 return;
1294#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001295}
1296
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001297/* Transform the row. The order of transformations is significant,
1298 * and is very touchy. If you add a transformation, take care to
1299 * decide how it fits in with the other transformations here.
1300 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001301void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001302png_do_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05001303{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001304 png_debug(1, "in png_do_read_transformations");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001305 if (png_ptr->row_buf == NULL)
1306 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001307#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001308 char msg[50];
1309
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001310 png_snprintf2(msg, 50,
1311 "NULL row buffer for row %ld, pass %d", (long)png_ptr->row_number,
1312 png_ptr->pass);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001313 png_error(png_ptr, msg);
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001314#else
1315 png_error(png_ptr, "NULL row buffer");
1316#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001317 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001318#ifdef PNG_WARN_UNINITIALIZED_ROW
1319 if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
1320 /* Application has failed to call either png_read_start_image()
1321 * or png_read_update_info() after setting transforms that expand
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001322 * pixels. This check added to libpng-1.2.19
1323 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001324#if (PNG_WARN_UNINITIALIZED_ROW==1)
1325 png_error(png_ptr, "Uninitialized row");
1326#else
1327 png_warning(png_ptr, "Uninitialized row");
1328#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001329#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001330
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001331#if defined(PNG_READ_EXPAND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001332 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05001333 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001334 if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
1335 {
1336 png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
1337 png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
1338 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001339 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001340 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001341 if (png_ptr->num_trans &&
1342 (png_ptr->transformations & PNG_EXPAND_tRNS))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001343 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001344 &(png_ptr->trans_color));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001345 else
1346 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1347 NULL);
1348 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001349 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001350#endif
1351
1352#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001353 if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001354 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001355 PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001356#endif
1357
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001358#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1359 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1360 {
1361 int rgb_error =
1362 png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001363 if (rgb_error)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001364 {
1365 png_ptr->rgb_to_gray_status=1;
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06001366 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001367 PNG_RGB_TO_GRAY_WARN)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001368 png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001369 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
1370 PNG_RGB_TO_GRAY_ERR)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001371 png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1372 }
1373 }
1374#endif
1375
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001376/* From Andreas Dilger e-mail to png-implement, 26 March 1998:
Glenn Randers-Pehrsond60c8862009-06-15 21:56:14 -05001377 *
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001378 * In most cases, the "simple transparency" should be done prior to doing
1379 * gray-to-RGB, or you will have to test 3x as many bytes to check if a
1380 * pixel is transparent. You would also need to make sure that the
1381 * transparency information is upgraded to RGB.
Glenn Randers-Pehrsond60c8862009-06-15 21:56:14 -05001382 *
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001383 * To summarize, the current flow is:
1384 * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
1385 * with background "in place" if transparent,
1386 * convert to RGB if necessary
1387 * - Gray + alpha -> composite with gray background and remove alpha bytes,
1388 * convert to RGB if necessary
1389 *
1390 * To support RGB backgrounds for gray images we need:
1391 * - Gray + simple transparency -> convert to RGB + simple transparency,
1392 * compare 3 or 6 bytes and composite with
1393 * background "in place" if transparent
1394 * (3x compare/pixel compared to doing
1395 * composite with gray bkgrnd)
1396 * - Gray + alpha -> convert to RGB + alpha, composite with background and
1397 * remove alpha bytes (3x float
1398 * operations/pixel compared with composite
1399 * on gray background)
1400 *
1401 * Greg's change will do this. The reason it wasn't done before is for
1402 * performance, as this increases the per-pixel operations. If we would check
1403 * in advance if the background was gray or RGB, and position the gray-to-RGB
1404 * transform appropriately, then it would save a lot of work/time.
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001405 */
1406
1407#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001408 /* If gray -> RGB, do so now only if background is non-gray; else do later
1409 * for performance reasons
1410 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001411 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001412 !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001413 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
1414#endif
1415
Glenn Randers-Pehrson6a9c2ce2009-03-27 19:30:10 -05001416#if defined(PNG_READ_16_TO_8_SUPPORTED)
1417 if (png_ptr->transformations & PNG_16_TO_8)
1418 png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
1419#endif
1420
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001421#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001422 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1423 ((png_ptr->num_trans != 0 ) ||
1424 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
Guy Schalnat0d580581995-07-20 02:43:20 -05001425 png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001426 &(png_ptr->trans_color), &(png_ptr->background)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001427#if defined(PNG_READ_GAMMA_SUPPORTED)
1428 , &(png_ptr->background_1),
Guy Schalnat0d580581995-07-20 02:43:20 -05001429 png_ptr->gamma_table, png_ptr->gamma_from_1,
1430 png_ptr->gamma_to_1, png_ptr->gamma_16_table,
1431 png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001432 png_ptr->gamma_shift
1433#endif
1434);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001435#endif
1436
1437#if defined(PNG_READ_GAMMA_SUPPORTED)
1438 if ((png_ptr->transformations & PNG_GAMMA) &&
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001439#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001440 !((png_ptr->transformations & PNG_BACKGROUND) &&
1441 ((png_ptr->num_trans != 0) ||
1442 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001443#endif
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001444 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
Guy Schalnat0d580581995-07-20 02:43:20 -05001445 png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001446 png_ptr->gamma_table, png_ptr->gamma_16_table,
1447 png_ptr->gamma_shift);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001448#endif
1449
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001450#if defined(PNG_READ_DITHER_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001451 if (png_ptr->transformations & PNG_DITHER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001452 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001453 png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
1454 png_ptr->palette_lookup, png_ptr->dither_index);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001455 if (png_ptr->row_info.rowbytes == (png_uint_32)0)
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001456 png_error(png_ptr, "png_do_dither returned rowbytes=0");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001457 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001458#endif
1459
1460#if defined(PNG_READ_INVERT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001461 if (png_ptr->transformations & PNG_INVERT_MONO)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001462 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001463#endif
1464
1465#if defined(PNG_READ_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001466 if (png_ptr->transformations & PNG_SHIFT)
1467 png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
1468 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001469#endif
1470
1471#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001472 if (png_ptr->transformations & PNG_PACK)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001473 png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001474#endif
1475
1476#if defined(PNG_READ_BGR_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001477 if (png_ptr->transformations & PNG_BGR)
1478 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001479#endif
1480
Andreas Dilger47a0c421997-05-16 02:46:07 -05001481#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1482 if (png_ptr->transformations & PNG_PACKSWAP)
1483 png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1484#endif
1485
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001486#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001487 /* If gray -> RGB, do so now only if we did not do so above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001488 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
1489 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05001490 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001491#endif
1492
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001493#if defined(PNG_READ_FILLER_SUPPORTED)
1494 if (png_ptr->transformations & PNG_FILLER)
1495 png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001496 (png_uint_32)png_ptr->filler, png_ptr->flags);
1497#endif
1498
Glenn Randers-Pehrson1916f6a2008-08-14 13:44:49 -05001499#if defined(PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED)
1500 if (png_ptr->transformations & PNG_PREMULTIPLY_ALPHA)
Glenn Randers-Pehrson8fb550c2009-03-21 08:15:32 -05001501 png_do_read_premultiply_alpha(&(png_ptr->row_info),
1502 png_ptr->row_buf + 1);
Glenn Randers-Pehrson1916f6a2008-08-14 13:44:49 -05001503#endif
1504
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001505#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
1506 if (png_ptr->transformations & PNG_INVERT_ALPHA)
1507 png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1508#endif
1509
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001510#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
1511 if (png_ptr->transformations & PNG_SWAP_ALPHA)
1512 png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1513#endif
1514
Andreas Dilger47a0c421997-05-16 02:46:07 -05001515#if defined(PNG_READ_SWAP_SUPPORTED)
1516 if (png_ptr->transformations & PNG_SWAP_BYTES)
1517 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001518#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001519
1520#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1521 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001522 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001523 if (png_ptr->read_user_transform_fn != NULL)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001524 (*(png_ptr->read_user_transform_fn)) /* User read transform function */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001525 (png_ptr, /* png_ptr */
1526 &(png_ptr->row_info), /* row_info: */
1527 /* png_uint_32 width; width of row */
1528 /* png_uint_32 rowbytes; number of bytes in row */
1529 /* png_byte color_type; color type of pixels */
1530 /* png_byte bit_depth; bit depth of samples */
1531 /* png_byte channels; number of channels (1-4) */
1532 /* png_byte pixel_depth; bits per pixel (depth*channels) */
1533 png_ptr->row_buf + 1); /* start of pixel data for row */
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001534#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001535 if (png_ptr->user_transform_depth)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001536 png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001537 if (png_ptr->user_transform_channels)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001538 png_ptr->row_info.channels = png_ptr->user_transform_channels;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001539#endif
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001540 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
1541 png_ptr->row_info.channels);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001542 png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
1543 png_ptr->row_info.width);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001544 }
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001545#endif
1546
Guy Schalnat0d580581995-07-20 02:43:20 -05001547}
1548
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001549#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001550/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
1551 * without changing the actual values. Thus, if you had a row with
1552 * a bit depth of 1, you would end up with bytes that only contained
1553 * the numbers 0 or 1. If you would rather they contain 0 and 255, use
1554 * png_do_shift() after this.
1555 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001556void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001557png_do_unpack(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001558{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001559 png_debug(1, "in png_do_unpack");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001560 if (row_info->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05001561 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001562 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001563 png_uint_32 row_width=row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001564
Guy Schalnat0d580581995-07-20 02:43:20 -05001565 switch (row_info->bit_depth)
1566 {
1567 case 1:
1568 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001569 png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
1570 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001571 png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001572 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001573 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001574 *dp = (png_byte)((*sp >> shift) & 0x01);
Guy Schalnat0d580581995-07-20 02:43:20 -05001575 if (shift == 7)
1576 {
1577 shift = 0;
1578 sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001579 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001580 else
1581 shift++;
1582
1583 dp--;
1584 }
1585 break;
1586 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001587
Guy Schalnat0d580581995-07-20 02:43:20 -05001588 case 2:
1589 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001590
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001591 png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
1592 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001593 png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001594 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001595 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001596 *dp = (png_byte)((*sp >> shift) & 0x03);
Guy Schalnat0d580581995-07-20 02:43:20 -05001597 if (shift == 6)
1598 {
1599 shift = 0;
1600 sp--;
1601 }
1602 else
1603 shift += 2;
1604
1605 dp--;
1606 }
1607 break;
1608 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001609
Guy Schalnat0d580581995-07-20 02:43:20 -05001610 case 4:
1611 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001612 png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
1613 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001614 png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001615 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001616 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001617 *dp = (png_byte)((*sp >> shift) & 0x0f);
Guy Schalnat0d580581995-07-20 02:43:20 -05001618 if (shift == 4)
1619 {
1620 shift = 0;
1621 sp--;
1622 }
1623 else
1624 shift = 4;
1625
1626 dp--;
1627 }
1628 break;
1629 }
1630 }
1631 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001632 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001633 row_info->rowbytes = row_width * row_info->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001634 }
1635}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001636#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001637
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001638#if defined(PNG_READ_SHIFT_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001639/* Reverse the effects of png_do_shift. This routine merely shifts the
1640 * pixels back to their significant bits values. Thus, if you have
1641 * a row of bit depth 8, but only 5 are significant, this will shift
1642 * the values back to 0 through 31.
1643 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001644void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001645png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
Guy Schalnat0d580581995-07-20 02:43:20 -05001646{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001647 png_debug(1, "in png_do_unshift");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001648 if (
Andreas Dilger47a0c421997-05-16 02:46:07 -05001649 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001650 {
1651 int shift[4];
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001652 int channels = 0;
1653 int c;
1654 png_uint_16 value = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001655 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001656
Guy Schalnat0d580581995-07-20 02:43:20 -05001657 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
1658 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001659 shift[channels++] = row_info->bit_depth - sig_bits->red;
1660 shift[channels++] = row_info->bit_depth - sig_bits->green;
1661 shift[channels++] = row_info->bit_depth - sig_bits->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05001662 }
1663 else
1664 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001665 shift[channels++] = row_info->bit_depth - sig_bits->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05001666 }
1667 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
1668 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001669 shift[channels++] = row_info->bit_depth - sig_bits->alpha;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001670 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001671
Andreas Dilger47a0c421997-05-16 02:46:07 -05001672 for (c = 0; c < channels; c++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001673 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001674 if (shift[c] <= 0)
1675 shift[c] = 0;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001676 else
1677 value = 1;
1678 }
Guy Schalnat0f716451995-11-28 11:22:13 -06001679
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001680 if (!value)
1681 return;
Guy Schalnat0f716451995-11-28 11:22:13 -06001682
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001683 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05001684 {
1685 case 2:
1686 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001687 png_bytep bp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001688 png_uint_32 i;
1689 png_uint_32 istop = row_info->rowbytes;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001690
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001691 for (bp = row, i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001692 {
1693 *bp >>= 1;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001694 *bp++ &= 0x55;
Guy Schalnat0d580581995-07-20 02:43:20 -05001695 }
1696 break;
1697 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001698
Guy Schalnat0d580581995-07-20 02:43:20 -05001699 case 4:
1700 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001701 png_bytep bp = row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001702 png_uint_32 i;
1703 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001704 png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
1705 (png_byte)((int)0xf >> shift[0]));
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001706
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001707 for (i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001708 {
1709 *bp >>= shift[0];
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001710 *bp++ &= mask;
Guy Schalnat0d580581995-07-20 02:43:20 -05001711 }
1712 break;
1713 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001714
Guy Schalnat0d580581995-07-20 02:43:20 -05001715 case 8:
1716 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001717 png_bytep bp = row;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001718 png_uint_32 i;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001719 png_uint_32 istop = row_width * channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001720
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001721 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001722 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001723 *bp++ >>= shift[i%channels];
Guy Schalnat0d580581995-07-20 02:43:20 -05001724 }
1725 break;
1726 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001727
Guy Schalnat0d580581995-07-20 02:43:20 -05001728 case 16:
1729 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001730 png_bytep bp = row;
1731 png_uint_32 i;
1732 png_uint_32 istop = channels * row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001733
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001734 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001735 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001736 value = (png_uint_16)((*bp << 8) + *(bp + 1));
1737 value >>= shift[i%channels];
1738 *bp++ = (png_byte)(value >> 8);
1739 *bp++ = (png_byte)(value & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05001740 }
1741 break;
1742 }
1743 }
1744 }
1745}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001746#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001747
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001748#if defined(PNG_READ_16_TO_8_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001749/* Chop rows of bit depth 16 down to 8 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001750void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001751png_do_chop(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001752{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001753 png_debug(1, "in png_do_chop");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001754 if (row_info->bit_depth == 16)
Guy Schalnat0d580581995-07-20 02:43:20 -05001755 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001756 png_bytep sp = row;
1757 png_bytep dp = row;
1758 png_uint_32 i;
1759 png_uint_32 istop = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001760
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001761 for (i = 0; i<istop; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001762 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001763#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001764 /* This does a more accurate scaling of the 16-bit color
1765 * value, rather than a simple low-byte truncation.
1766 *
1767 * What the ideal calculation should be:
1768 * *dp = (((((png_uint_32)(*sp) << 8) |
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001769 * (png_uint_32)(*(sp + 1))) * 255 + 127)
1770 * / (png_uint_32)65535L;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001771 *
1772 * GRR: no, I think this is what it really should be:
1773 * *dp = (((((png_uint_32)(*sp) << 8) |
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001774 * (png_uint_32)(*(sp + 1))) + 128L)
1775 * / (png_uint_32)257L;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001776 *
1777 * GRR: here's the exact calculation with shifts:
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001778 * temp = (((png_uint_32)(*sp) << 8) |
1779 * (png_uint_32)(*(sp + 1))) + 128L;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001780 * *dp = (temp - (temp >> 8)) >> 8;
1781 *
1782 * Approximate calculation with shift/add instead of multiply/divide:
1783 * *dp = ((((png_uint_32)(*sp) << 8) |
1784 * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
1785 *
1786 * What we actually do to avoid extra shifting and conversion:
1787 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001788
Andreas Dilger47a0c421997-05-16 02:46:07 -05001789 *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
1790#else
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001791 /* Simply discard the low order byte */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001792 *dp = *sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001793#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001794 }
1795 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001796 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001797 row_info->rowbytes = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001798 }
1799}
1800#endif
1801
1802#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001803void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001804png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
1805{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001806 png_debug(1, "in png_do_read_swap_alpha");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001807 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001808 png_uint_32 row_width = row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001809 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1810 {
1811 /* This converts from RGBA to ARGB */
1812 if (row_info->bit_depth == 8)
1813 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001814 png_bytep sp = row + row_info->rowbytes;
1815 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001816 png_byte save;
1817 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001818
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001819 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001820 {
1821 save = *(--sp);
1822 *(--dp) = *(--sp);
1823 *(--dp) = *(--sp);
1824 *(--dp) = *(--sp);
1825 *(--dp) = save;
1826 }
1827 }
1828 /* This converts from RRGGBBAA to AARRGGBB */
1829 else
1830 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001831 png_bytep sp = row + row_info->rowbytes;
1832 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001833 png_byte save[2];
1834 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001835
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001836 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001837 {
1838 save[0] = *(--sp);
1839 save[1] = *(--sp);
1840 *(--dp) = *(--sp);
1841 *(--dp) = *(--sp);
1842 *(--dp) = *(--sp);
1843 *(--dp) = *(--sp);
1844 *(--dp) = *(--sp);
1845 *(--dp) = *(--sp);
1846 *(--dp) = save[0];
1847 *(--dp) = save[1];
1848 }
1849 }
1850 }
1851 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1852 {
1853 /* This converts from GA to AG */
1854 if (row_info->bit_depth == 8)
1855 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001856 png_bytep sp = row + row_info->rowbytes;
1857 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001858 png_byte save;
1859 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001860
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001861 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001862 {
1863 save = *(--sp);
1864 *(--dp) = *(--sp);
1865 *(--dp) = save;
1866 }
1867 }
1868 /* This converts from GGAA to AAGG */
1869 else
1870 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001871 png_bytep sp = row + row_info->rowbytes;
1872 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001873 png_byte save[2];
1874 png_uint_32 i;
1875
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001876 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001877 {
1878 save[0] = *(--sp);
1879 save[1] = *(--sp);
1880 *(--dp) = *(--sp);
1881 *(--dp) = *(--sp);
1882 *(--dp) = save[0];
1883 *(--dp) = save[1];
1884 }
1885 }
1886 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001887 }
1888}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001889#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001890
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001891#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001892void /* PRIVATE */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001893png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
1894{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001895 png_debug(1, "in png_do_read_invert_alpha");
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001896 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001897 png_uint_32 row_width = row_info->width;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001898 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1899 {
1900 /* This inverts the alpha channel in RGBA */
1901 if (row_info->bit_depth == 8)
1902 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001903 png_bytep sp = row + row_info->rowbytes;
1904 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001905 png_uint_32 i;
1906
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001907 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001908 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001909 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001910
1911/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001912 *(--dp) = *(--sp);
1913 *(--dp) = *(--sp);
1914 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001915 We can replace it with:
1916*/
1917 sp-=3;
1918 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001919 }
1920 }
1921 /* This inverts the alpha channel in RRGGBBAA */
1922 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
1933/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001934 *(--dp) = *(--sp);
1935 *(--dp) = *(--sp);
1936 *(--dp) = *(--sp);
1937 *(--dp) = *(--sp);
1938 *(--dp) = *(--sp);
1939 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001940 We can replace it with:
1941*/
1942 sp-=6;
1943 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001944 }
1945 }
1946 }
1947 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1948 {
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001949 /* This inverts the alpha channel in GA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001950 if (row_info->bit_depth == 8)
1951 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001952 png_bytep sp = row + row_info->rowbytes;
1953 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001954 png_uint_32 i;
1955
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001956 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001957 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001958 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001959 *(--dp) = *(--sp);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001960 }
1961 }
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001962 /* This inverts the alpha channel in GGAA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001963 else
1964 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001965 png_bytep sp = row + row_info->rowbytes;
1966 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001967 png_uint_32 i;
1968
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001969 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001970 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001971 *(--dp) = (png_byte)(255 - *(--sp));
1972 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001973/*
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001974 *(--dp) = *(--sp);
1975 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001976*/
1977 sp-=2;
1978 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001979 }
1980 }
1981 }
1982 }
1983}
1984#endif
1985
Glenn Randers-Pehrson1916f6a2008-08-14 13:44:49 -05001986#if defined(PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED)
1987void /* PRIVATE */
1988png_do_read_premultiply_alpha(png_row_infop row_info, png_bytep row)
1989{
Glenn Randers-Pehrsond6d80752008-12-02 09:49:43 -06001990 png_debug(1, "in png_do_read_premultiply_alpha");
Glenn Randers-Pehrson1916f6a2008-08-14 13:44:49 -05001991 {
1992 png_uint_32 row_width = row_info->width;
1993 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1994 {
1995 /* This premultiplies the pixels with the alpha channel in RGBA */
1996 if (row_info->bit_depth == 8)
1997 {
1998 png_bytep sp = row + row_info->rowbytes;
1999 png_bytep dp = sp;
2000 png_uint_16 a = 0;
2001 png_uint_32 i;
2002
2003 for (i = 0; i < row_width; i++)
2004 {
2005 a = *(--sp); --dp;
2006
2007 *(--dp) = (*(--sp) * a) / 255;
2008 *(--dp) = (*(--sp) * a) / 255;
2009 *(--dp) = (*(--sp) * a) / 255;
2010 }
2011 }
2012 /* This premultiplies the pixels with the alpha channel in RRGGBBAA */
2013 else
2014 {
2015 png_uint_16p sp = (png_uint_16p)(row + row_info->rowbytes);
2016 png_uint_16p dp = sp;
2017 png_uint_32 a = 0;
2018 png_uint_32 i;
2019
2020 for (i = 0; i < row_width; i++)
2021 {
2022 a = *(--sp); --dp;
2023 *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535);
2024 *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535);
2025 *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535);
2026 }
2027 }
2028 }
2029 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2030 {
2031 /* This premultiplies the pixels with the alpha channel in GA */
2032 if (row_info->bit_depth == 8)
2033 {
2034 png_bytep sp = row + row_info->rowbytes;
2035 png_bytep dp = sp;
2036 png_uint_16 a = 0;
2037 png_uint_32 i;
2038
2039 for (i = 0; i < row_width; i++)
2040 {
2041 a = *(--sp); --dp;
2042 *(--dp) = (*(--sp) * a) / 255;
2043 }
2044 }
2045 /* This premultiplies the pixels with the alpha channel in GGAA */
2046 else
2047 {
2048 png_uint_16p sp = (png_uint_16p) (row + row_info->rowbytes);
2049 png_uint_16p dp = sp;
2050 png_uint_32 a = 0;
2051 png_uint_32 i;
2052
2053 for (i = 0; i < row_width; i++)
2054 {
2055 a = *(--sp); --dp;
2056 *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535);
2057 }
2058 }
2059 }
2060 }
2061}
2062#endif
2063
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002064#if defined(PNG_READ_FILLER_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002065/* Add filler channel if we have RGB color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002066void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002067png_do_read_filler(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05002068 png_uint_32 filler, png_uint_32 flags)
Guy Schalnat0d580581995-07-20 02:43:20 -05002069{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002070 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002071 png_uint_32 row_width = row_info->width;
2072
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002073 png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002074 png_byte lo_filler = (png_byte)(filler & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002075
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002076 png_debug(1, "in png_do_read_filler");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002077 if (
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002078 row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05002079 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002080 if (row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002081 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002082 /* This changes the data from G to GX */
2083 if (flags & PNG_FLAG_FILLER_AFTER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002084 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002085 png_bytep sp = row + (png_size_t)row_width;
2086 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002087 for (i = 1; i < row_width; i++)
2088 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002089 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002090 *(--dp) = *(--sp);
2091 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002092 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002093 row_info->channels = 2;
2094 row_info->pixel_depth = 16;
2095 row_info->rowbytes = row_width * 2;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002096 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002097 /* This changes the data from G to XG */
2098 else
2099 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002100 png_bytep sp = row + (png_size_t)row_width;
2101 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002102 for (i = 0; i < row_width; i++)
2103 {
2104 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002105 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002106 }
2107 row_info->channels = 2;
2108 row_info->pixel_depth = 16;
2109 row_info->rowbytes = row_width * 2;
2110 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002111 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002112 else if (row_info->bit_depth == 16)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002113 {
2114 /* This changes the data from GG to GGXX */
2115 if (flags & PNG_FLAG_FILLER_AFTER)
2116 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002117 png_bytep sp = row + (png_size_t)row_width * 2;
2118 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002119 for (i = 1; i < row_width; i++)
2120 {
2121 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002122 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002123 *(--dp) = *(--sp);
2124 *(--dp) = *(--sp);
2125 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002126 *(--dp) = hi_filler;
2127 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002128 row_info->channels = 2;
2129 row_info->pixel_depth = 32;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002130 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002131 }
2132 /* This changes the data from GG to XXGG */
2133 else
2134 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002135 png_bytep sp = row + (png_size_t)row_width * 2;
2136 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002137 for (i = 0; i < row_width; i++)
2138 {
2139 *(--dp) = *(--sp);
2140 *(--dp) = *(--sp);
2141 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002142 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002143 }
2144 row_info->channels = 2;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002145 row_info->pixel_depth = 32;
2146 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002147 }
2148 }
2149 } /* COLOR_TYPE == GRAY */
2150 else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2151 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002152 if (row_info->bit_depth == 8)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002153 {
2154 /* This changes the data from RGB to RGBX */
2155 if (flags & PNG_FLAG_FILLER_AFTER)
2156 {
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002157 png_bytep sp = row + (png_size_t)row_width * 3;
2158 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002159 for (i = 1; i < row_width; i++)
2160 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002161 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002162 *(--dp) = *(--sp);
2163 *(--dp) = *(--sp);
2164 *(--dp) = *(--sp);
2165 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002166 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002167 row_info->channels = 4;
2168 row_info->pixel_depth = 32;
2169 row_info->rowbytes = row_width * 4;
2170 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002171 /* This changes the data from RGB to XRGB */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002172 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002173 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002174 png_bytep sp = row + (png_size_t)row_width * 3;
2175 png_bytep dp = sp + (png_size_t)row_width;
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);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002181 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002182 }
2183 row_info->channels = 4;
2184 row_info->pixel_depth = 32;
2185 row_info->rowbytes = row_width * 4;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002186 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002187 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002188 else if (row_info->bit_depth == 16)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002189 {
2190 /* This changes the data from RRGGBB to RRGGBBXX */
2191 if (flags & PNG_FLAG_FILLER_AFTER)
2192 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002193 png_bytep sp = row + (png_size_t)row_width * 6;
2194 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002195 for (i = 1; i < row_width; i++)
2196 {
2197 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002198 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002199 *(--dp) = *(--sp);
2200 *(--dp) = *(--sp);
2201 *(--dp) = *(--sp);
2202 *(--dp) = *(--sp);
2203 *(--dp) = *(--sp);
2204 *(--dp) = *(--sp);
2205 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002206 *(--dp) = hi_filler;
2207 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002208 row_info->channels = 4;
2209 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002210 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002211 }
2212 /* This changes the data from RRGGBB to XXRRGGBB */
2213 else
2214 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002215 png_bytep sp = row + (png_size_t)row_width * 6;
2216 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002217 for (i = 0; i < row_width; i++)
2218 {
2219 *(--dp) = *(--sp);
2220 *(--dp) = *(--sp);
2221 *(--dp) = *(--sp);
2222 *(--dp) = *(--sp);
2223 *(--dp) = *(--sp);
2224 *(--dp) = *(--sp);
2225 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002226 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002227 }
2228 row_info->channels = 4;
2229 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002230 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002231 }
2232 }
2233 } /* COLOR_TYPE == RGB */
Guy Schalnat0d580581995-07-20 02:43:20 -05002234}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002235#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002236
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002237#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002238/* Expand grayscale files to RGB, with or without alpha */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002239void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002240png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05002241{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002242 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002243 png_uint_32 row_width = row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06002244
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002245 png_debug(1, "in png_do_gray_to_rgb");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002246 if (row_info->bit_depth >= 8 &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002247 !(row_info->color_type & PNG_COLOR_MASK_COLOR))
2248 {
2249 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
2250 {
2251 if (row_info->bit_depth == 8)
2252 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002253 png_bytep sp = row + (png_size_t)row_width - 1;
2254 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002255 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002256 {
2257 *(dp--) = *sp;
2258 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002259 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002260 }
2261 }
2262 else
2263 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002264 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2265 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002266 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002267 {
2268 *(dp--) = *sp;
2269 *(dp--) = *(sp - 1);
2270 *(dp--) = *sp;
2271 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002272 *(dp--) = *(sp--);
2273 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002274 }
2275 }
2276 }
2277 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2278 {
2279 if (row_info->bit_depth == 8)
2280 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002281 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2282 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002283 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002284 {
2285 *(dp--) = *(sp--);
2286 *(dp--) = *sp;
2287 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002288 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002289 }
2290 }
2291 else
2292 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002293 png_bytep sp = row + (png_size_t)row_width * 4 - 1;
2294 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002295 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002296 {
2297 *(dp--) = *(sp--);
2298 *(dp--) = *(sp--);
2299 *(dp--) = *sp;
2300 *(dp--) = *(sp - 1);
2301 *(dp--) = *sp;
2302 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002303 *(dp--) = *(sp--);
2304 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002305 }
2306 }
2307 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002308 row_info->channels += (png_byte)2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002309 row_info->color_type |= PNG_COLOR_MASK_COLOR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002310 row_info->pixel_depth = (png_byte)(row_info->channels *
2311 row_info->bit_depth);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002312 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05002313 }
2314}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002315#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002316
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002317#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002318/* Reduce RGB files to grayscale, with or without alpha
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002319 * using the equation given in Poynton's ColorFAQ at
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002320 * <http://www.inforamp.net/~poynton/> (THIS LINK IS DEAD June 2008)
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002321 * New link:
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002322 * <http://www.poynton.com/notes/colour_and_gamma/>
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002323 * Charles Poynton poynton at poynton.com
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002324 *
2325 * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
2326 *
2327 * We approximate this with
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002328 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002329 * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002330 *
2331 * which can be expressed with integers as
2332 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002333 * Y = (6969 * R + 23434 * G + 2365 * B)/32768
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002334 *
2335 * The calculation is to be done in a linear colorspace.
2336 *
2337 * Other integer coefficents can be used via png_set_rgb_to_gray().
2338 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002339int /* PRIVATE */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002340png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
2341
2342{
2343 png_uint_32 i;
2344
2345 png_uint_32 row_width = row_info->width;
2346 int rgb_error = 0;
2347
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002348 png_debug(1, "in png_do_rgb_to_gray");
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002349 if (
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002350 (row_info->color_type & PNG_COLOR_MASK_COLOR))
2351 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002352 png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
2353 png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
2354 png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002355
2356 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2357 {
2358 if (row_info->bit_depth == 8)
2359 {
2360#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2361 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2362 {
2363 png_bytep sp = row;
2364 png_bytep dp = row;
2365
2366 for (i = 0; i < row_width; i++)
2367 {
2368 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2369 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2370 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002371 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002372 {
2373 rgb_error |= 1;
2374 *(dp++) = png_ptr->gamma_from_1[
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002375 (rc*red + gc*green + bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002376 }
2377 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002378 *(dp++) = *(sp - 1);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002379 }
2380 }
2381 else
2382#endif
2383 {
2384 png_bytep sp = row;
2385 png_bytep dp = row;
2386 for (i = 0; i < row_width; i++)
2387 {
2388 png_byte red = *(sp++);
2389 png_byte green = *(sp++);
2390 png_byte blue = *(sp++);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002391 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002392 {
2393 rgb_error |= 1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002394 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002395 }
2396 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002397 *(dp++) = *(sp - 1);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002398 }
2399 }
2400 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002401
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002402 else /* RGB bit_depth == 16 */
2403 {
2404#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2405 if (png_ptr->gamma_16_to_1 != NULL &&
2406 png_ptr->gamma_16_from_1 != NULL)
2407 {
2408 png_bytep sp = row;
2409 png_bytep dp = row;
2410 for (i = 0; i < row_width; i++)
2411 {
2412 png_uint_16 red, green, blue, w;
2413
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002414 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2415 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2416 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002417
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002418 if (red == green && red == blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002419 w = red;
2420 else
2421 {
2422 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2423 png_ptr->gamma_shift][red>>8];
2424 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2425 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002426 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002427 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002428 png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002429 + bc*blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002430 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2431 png_ptr->gamma_shift][gray16 >> 8];
2432 rgb_error |= 1;
2433 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002434
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002435 *(dp++) = (png_byte)((w>>8) & 0xff);
2436 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002437 }
2438 }
2439 else
2440#endif
2441 {
2442 png_bytep sp = row;
2443 png_bytep dp = row;
2444 for (i = 0; i < row_width; i++)
2445 {
2446 png_uint_16 red, green, blue, gray16;
2447
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002448 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2449 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2450 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002451
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002452 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002453 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002454 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002455 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2456 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002457 }
2458 }
2459 }
2460 }
2461 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2462 {
2463 if (row_info->bit_depth == 8)
2464 {
2465#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2466 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2467 {
2468 png_bytep sp = row;
2469 png_bytep dp = row;
2470 for (i = 0; i < row_width; i++)
2471 {
2472 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2473 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2474 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002475 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002476 rgb_error |= 1;
2477 *(dp++) = png_ptr->gamma_from_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002478 [(rc*red + gc*green + bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002479 *(dp++) = *(sp++); /* alpha */
2480 }
2481 }
2482 else
2483#endif
2484 {
2485 png_bytep sp = row;
2486 png_bytep dp = row;
2487 for (i = 0; i < row_width; i++)
2488 {
2489 png_byte red = *(sp++);
2490 png_byte green = *(sp++);
2491 png_byte blue = *(sp++);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002492 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002493 rgb_error |= 1;
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002494 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002495 *(dp++) = *(sp++); /* alpha */
2496 }
2497 }
2498 }
2499 else /* RGBA bit_depth == 16 */
2500 {
2501#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2502 if (png_ptr->gamma_16_to_1 != NULL &&
2503 png_ptr->gamma_16_from_1 != NULL)
2504 {
2505 png_bytep sp = row;
2506 png_bytep dp = row;
2507 for (i = 0; i < row_width; i++)
2508 {
2509 png_uint_16 red, green, blue, w;
2510
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002511 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2512 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2513 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002514
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002515 if (red == green && red == blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002516 w = red;
2517 else
2518 {
2519 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2520 png_ptr->gamma_shift][red>>8];
2521 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2522 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002523 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002524 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002525 png_uint_16 gray16 = (png_uint_16)((rc * red_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002526 + gc * green_1 + bc * blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002527 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2528 png_ptr->gamma_shift][gray16 >> 8];
2529 rgb_error |= 1;
2530 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002531
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002532 *(dp++) = (png_byte)((w>>8) & 0xff);
2533 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002534 *(dp++) = *(sp++); /* alpha */
2535 *(dp++) = *(sp++);
2536 }
2537 }
2538 else
2539#endif
2540 {
2541 png_bytep sp = row;
2542 png_bytep dp = row;
2543 for (i = 0; i < row_width; i++)
2544 {
2545 png_uint_16 red, green, blue, gray16;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002546 red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2547 green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2548 blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002549 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002550 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002551 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002552 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2553 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002554 *(dp++) = *(sp++); /* alpha */
2555 *(dp++) = *(sp++);
2556 }
2557 }
2558 }
2559 }
2560 row_info->channels -= (png_byte)2;
2561 row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
2562 row_info->pixel_depth = (png_byte)(row_info->channels *
2563 row_info->bit_depth);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002564 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002565 }
2566 return rgb_error;
2567}
2568#endif
2569
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002570/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
2571 * large of png_color. This lets grayscale images be treated as
2572 * paletted. Most useful for gamma correction and simplification
2573 * of code.
2574 */
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06002575void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -06002576png_build_grayscale_palette(int bit_depth, png_colorp palette)
Guy Schalnat0d580581995-07-20 02:43:20 -05002577{
2578 int num_palette;
2579 int color_inc;
2580 int i;
2581 int v;
2582
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002583 png_debug(1, "in png_do_build_grayscale_palette");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002584 if (palette == NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002585 return;
2586
2587 switch (bit_depth)
2588 {
2589 case 1:
2590 num_palette = 2;
2591 color_inc = 0xff;
2592 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002593
Guy Schalnat0d580581995-07-20 02:43:20 -05002594 case 2:
2595 num_palette = 4;
2596 color_inc = 0x55;
2597 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002598
Guy Schalnat0d580581995-07-20 02:43:20 -05002599 case 4:
2600 num_palette = 16;
2601 color_inc = 0x11;
2602 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002603
Guy Schalnat0d580581995-07-20 02:43:20 -05002604 case 8:
2605 num_palette = 256;
2606 color_inc = 1;
2607 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002608
Guy Schalnat0d580581995-07-20 02:43:20 -05002609 default:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002610 num_palette = 0;
Guy Schalnat69b14481996-01-10 02:56:49 -06002611 color_inc = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002612 break;
2613 }
2614
2615 for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
2616 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002617 palette[i].red = (png_byte)v;
2618 palette[i].green = (png_byte)v;
2619 palette[i].blue = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002620 }
2621}
2622
Guy Schalnat0d580581995-07-20 02:43:20 -05002623
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002624#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002625/* Replace any alpha or transparency with the supplied background color.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002626 * "background" is already in the screen gamma, while "background_1" is
2627 * at a gamma of 1.0. Paletted files have already been taken care of.
2628 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002629void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002630png_do_background(png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002631 png_color_16p trans_color, png_color_16p background
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002632#if defined(PNG_READ_GAMMA_SUPPORTED)
2633 , png_color_16p background_1,
Guy Schalnat6d764711995-12-19 03:22:19 -06002634 png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002635 png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002636 png_uint_16pp gamma_16_to_1, int gamma_shift
2637#endif
2638 )
Guy Schalnat0d580581995-07-20 02:43:20 -05002639{
Guy Schalnat6d764711995-12-19 03:22:19 -06002640 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002641 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002642 png_uint_32 row_width=row_info->width;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002643 int shift;
Guy Schalnate5a37791996-06-05 15:50:50 -05002644
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002645 png_debug(1, "in png_do_background");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002646 if (background != NULL &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002647 (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002648 (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_color)))
Guy Schalnat0d580581995-07-20 02:43:20 -05002649 {
2650 switch (row_info->color_type)
2651 {
2652 case PNG_COLOR_TYPE_GRAY:
2653 {
2654 switch (row_info->bit_depth)
2655 {
2656 case 1:
2657 {
Guy Schalnat0d580581995-07-20 02:43:20 -05002658 sp = row;
2659 shift = 7;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002660 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002661 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002662 if ((png_uint_16)((*sp >> shift) & 0x01)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002663 == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002664 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002665 *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2666 *sp |= (png_byte)(background->gray << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002667 }
2668 if (!shift)
2669 {
2670 shift = 7;
2671 sp++;
2672 }
2673 else
2674 shift--;
2675 }
2676 break;
2677 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002678
Guy Schalnat0d580581995-07-20 02:43:20 -05002679 case 2:
2680 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002681#if defined(PNG_READ_GAMMA_SUPPORTED)
2682 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002683 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002684 sp = row;
2685 shift = 6;
2686 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002687 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002688 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002689 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002690 {
2691 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2692 *sp |= (png_byte)(background->gray << shift);
2693 }
2694 else
2695 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002696 png_byte p = (png_byte)((*sp >> shift) & 0x03);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002697 png_byte g = (png_byte)((gamma_table [p | (p << 2) |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002698 (p << 4) | (p << 6)] >> 6) & 0x03);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002699 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2700 *sp |= (png_byte)(g << shift);
2701 }
2702 if (!shift)
2703 {
2704 shift = 6;
2705 sp++;
2706 }
2707 else
2708 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002709 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002710 }
2711 else
2712#endif
2713 {
2714 sp = row;
2715 shift = 6;
2716 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002717 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002718 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002719 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002720 {
2721 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2722 *sp |= (png_byte)(background->gray << shift);
2723 }
2724 if (!shift)
2725 {
2726 shift = 6;
2727 sp++;
2728 }
2729 else
2730 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002731 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002732 }
2733 break;
2734 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002735
Guy Schalnat0d580581995-07-20 02:43:20 -05002736 case 4:
2737 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002738#if defined(PNG_READ_GAMMA_SUPPORTED)
2739 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002740 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002741 sp = row;
2742 shift = 4;
2743 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002744 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002745 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002746 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002747 {
2748 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2749 *sp |= (png_byte)(background->gray << shift);
2750 }
2751 else
2752 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002753 png_byte p = (png_byte)((*sp >> shift) & 0x0f);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002754 png_byte g = (png_byte)((gamma_table[p |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002755 (p << 4)] >> 4) & 0x0f);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002756 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2757 *sp |= (png_byte)(g << shift);
2758 }
2759 if (!shift)
2760 {
2761 shift = 4;
2762 sp++;
2763 }
2764 else
2765 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002766 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002767 }
2768 else
2769#endif
2770 {
2771 sp = row;
2772 shift = 4;
2773 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002774 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002775 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002776 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002777 {
2778 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2779 *sp |= (png_byte)(background->gray << shift);
2780 }
2781 if (!shift)
2782 {
2783 shift = 4;
2784 sp++;
2785 }
2786 else
2787 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002788 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002789 }
2790 break;
2791 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002792
Guy Schalnat0d580581995-07-20 02:43:20 -05002793 case 8:
2794 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002795#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002796 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002797 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002798 sp = row;
2799 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002800 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002801 if (*sp == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002802 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002803 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002804 }
2805 else
2806 {
2807 *sp = gamma_table[*sp];
2808 }
2809 }
2810 }
2811 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002812#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002813 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002814 sp = row;
2815 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002816 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002817 if (*sp == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002818 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002819 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002820 }
2821 }
2822 }
2823 break;
2824 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002825
Guy Schalnat0d580581995-07-20 02:43:20 -05002826 case 16:
2827 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002828#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002829 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002830 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002831 sp = row;
2832 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002833 {
2834 png_uint_16 v;
2835
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002836 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002837 if (v == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002838 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002839 /* Background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002840 *sp = (png_byte)((background->gray >> 8) & 0xff);
2841 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002842 }
2843 else
2844 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002845 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002846 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002847 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002848 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002849 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002850 }
2851 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002852#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002853 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002854 sp = row;
2855 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002856 {
2857 png_uint_16 v;
2858
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002859 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002860 if (v == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002861 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002862 *sp = (png_byte)((background->gray >> 8) & 0xff);
2863 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002864 }
2865 }
2866 }
2867 break;
2868 }
2869 }
2870 break;
2871 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002872
Guy Schalnat0d580581995-07-20 02:43:20 -05002873 case PNG_COLOR_TYPE_RGB:
2874 {
2875 if (row_info->bit_depth == 8)
2876 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002877#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002878 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002879 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002880 sp = row;
2881 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002882 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002883 if (*sp == trans_color->red &&
2884 *(sp + 1) == trans_color->green &&
2885 *(sp + 2) == trans_color->blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05002886 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002887 *sp = (png_byte)background->red;
2888 *(sp + 1) = (png_byte)background->green;
2889 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002890 }
2891 else
2892 {
2893 *sp = gamma_table[*sp];
2894 *(sp + 1) = gamma_table[*(sp + 1)];
2895 *(sp + 2) = gamma_table[*(sp + 2)];
2896 }
2897 }
2898 }
2899 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002900#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002901 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002902 sp = row;
2903 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002904 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002905 if (*sp == trans_color->red &&
2906 *(sp + 1) == trans_color->green &&
2907 *(sp + 2) == trans_color->blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05002908 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002909 *sp = (png_byte)background->red;
2910 *(sp + 1) = (png_byte)background->green;
2911 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002912 }
2913 }
2914 }
2915 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002916 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05002917 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002918#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002919 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002920 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002921 sp = row;
2922 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002923 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002924 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2925 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2926 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002927 if (r == trans_color->red && g == trans_color->green &&
2928 b == trans_color->blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05002929 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002930 /* Background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002931 *sp = (png_byte)((background->red >> 8) & 0xff);
2932 *(sp + 1) = (png_byte)(background->red & 0xff);
2933 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2934 *(sp + 3) = (png_byte)(background->green & 0xff);
2935 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2936 *(sp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002937 }
2938 else
2939 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002940 png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002941 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002942 *(sp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002943 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002944 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
2945 *(sp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002946 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002947 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
2948 *(sp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002949 }
2950 }
2951 }
2952 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002953#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002954 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002955 sp = row;
2956 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05002957 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002958 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
2959 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2960 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Guy Schalnat0d580581995-07-20 02:43:20 -05002961
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002962 if (r == trans_color->red && g == trans_color->green &&
2963 b == trans_color->blue)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002964 {
2965 *sp = (png_byte)((background->red >> 8) & 0xff);
2966 *(sp + 1) = (png_byte)(background->red & 0xff);
2967 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2968 *(sp + 3) = (png_byte)(background->green & 0xff);
2969 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2970 *(sp + 5) = (png_byte)(background->blue & 0xff);
2971 }
2972 }
2973 }
2974 }
2975 break;
2976 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002977
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002978 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -05002979 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002980 if (row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002981 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002982#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002983 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
2984 gamma_table != NULL)
2985 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002986 sp = row;
2987 dp = row;
2988 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002989 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002990 png_uint_16 a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002991
Andreas Dilger47a0c421997-05-16 02:46:07 -05002992 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002993 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002994 *dp = gamma_table[*sp];
2995 }
2996 else if (a == 0)
2997 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002998 /* Background is already in screen gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002999 *dp = (png_byte)background->gray;
3000 }
3001 else
3002 {
3003 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05003004
Andreas Dilger47a0c421997-05-16 02:46:07 -05003005 v = gamma_to_1[*sp];
3006 png_composite(w, v, a, background_1->gray);
3007 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003008 }
3009 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003010 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003011 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003012#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003013 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003014 sp = row;
3015 dp = row;
3016 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003017 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003018 png_byte a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003019
Andreas Dilger47a0c421997-05-16 02:46:07 -05003020 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05003021 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003022 *dp = *sp;
3023 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003024#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003025 else if (a == 0)
3026 {
3027 *dp = (png_byte)background->gray;
3028 }
3029 else
3030 {
3031 png_composite(*dp, *sp, a, background_1->gray);
Guy Schalnat0d580581995-07-20 02:43:20 -05003032 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003033#else
3034 *dp = (png_byte)background->gray;
3035#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003036 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003037 }
3038 }
3039 else /* if (png_ptr->bit_depth == 16) */
3040 {
3041#if defined(PNG_READ_GAMMA_SUPPORTED)
3042 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3043 gamma_16_to_1 != NULL)
3044 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003045 sp = row;
3046 dp = row;
3047 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003048 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003049 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003050
Andreas Dilger47a0c421997-05-16 02:46:07 -05003051 if (a == (png_uint_16)0xffff)
3052 {
3053 png_uint_16 v;
3054
3055 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3056 *dp = (png_byte)((v >> 8) & 0xff);
3057 *(dp + 1) = (png_byte)(v & 0xff);
3058 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003059#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003060 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003061#else
3062 else
3063#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003064 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003065 /* Background is already in screen gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -05003066 *dp = (png_byte)((background->gray >> 8) & 0xff);
3067 *(dp + 1) = (png_byte)(background->gray & 0xff);
3068 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003069#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003070 else
3071 {
3072 png_uint_16 g, v, w;
3073
3074 g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3075 png_composite_16(v, g, a, background_1->gray);
3076 w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
3077 *dp = (png_byte)((w >> 8) & 0xff);
3078 *(dp + 1) = (png_byte)(w & 0xff);
3079 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003080#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003081 }
3082 }
3083 else
3084#endif
3085 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003086 sp = row;
3087 dp = row;
3088 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003089 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003090 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003091 if (a == (png_uint_16)0xffff)
3092 {
3093 png_memcpy(dp, sp, 2);
3094 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003095#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003096 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003097#else
3098 else
3099#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003100 {
3101 *dp = (png_byte)((background->gray >> 8) & 0xff);
3102 *(dp + 1) = (png_byte)(background->gray & 0xff);
3103 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003104#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003105 else
3106 {
3107 png_uint_16 g, v;
3108
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003109 g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003110 png_composite_16(v, g, a, background_1->gray);
3111 *dp = (png_byte)((v >> 8) & 0xff);
3112 *(dp + 1) = (png_byte)(v & 0xff);
3113 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003114#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003115 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003116 }
3117 }
3118 break;
3119 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003120
Guy Schalnat0d580581995-07-20 02:43:20 -05003121 case PNG_COLOR_TYPE_RGB_ALPHA:
3122 {
3123 if (row_info->bit_depth == 8)
3124 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003125#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003126 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3127 gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003128 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003129 sp = row;
3130 dp = row;
3131 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003132 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003133 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003134
Guy Schalnat0d580581995-07-20 02:43:20 -05003135 if (a == 0xff)
3136 {
3137 *dp = gamma_table[*sp];
3138 *(dp + 1) = gamma_table[*(sp + 1)];
3139 *(dp + 2) = gamma_table[*(sp + 2)];
3140 }
3141 else if (a == 0)
3142 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003143 /* Background is already in screen gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -05003144 *dp = (png_byte)background->red;
3145 *(dp + 1) = (png_byte)background->green;
3146 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003147 }
3148 else
3149 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003150 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05003151
3152 v = gamma_to_1[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003153 png_composite(w, v, a, background_1->red);
3154 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003155 v = gamma_to_1[*(sp + 1)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003156 png_composite(w, v, a, background_1->green);
3157 *(dp + 1) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003158 v = gamma_to_1[*(sp + 2)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003159 png_composite(w, v, a, background_1->blue);
3160 *(dp + 2) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003161 }
3162 }
3163 }
3164 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003165#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003166 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003167 sp = row;
3168 dp = row;
3169 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003170 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003171 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003172
Guy Schalnat0d580581995-07-20 02:43:20 -05003173 if (a == 0xff)
3174 {
3175 *dp = *sp;
3176 *(dp + 1) = *(sp + 1);
3177 *(dp + 2) = *(sp + 2);
3178 }
3179 else if (a == 0)
3180 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003181 *dp = (png_byte)background->red;
3182 *(dp + 1) = (png_byte)background->green;
3183 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003184 }
3185 else
3186 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003187 png_composite(*dp, *sp, a, background->red);
3188 png_composite(*(dp + 1), *(sp + 1), a,
3189 background->green);
3190 png_composite(*(dp + 2), *(sp + 2), a,
3191 background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003192 }
3193 }
3194 }
3195 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003196 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003197 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003198#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003199 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3200 gamma_16_to_1 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003201 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003202 sp = row;
3203 dp = row;
3204 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003205 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003206 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3207 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003208 if (a == (png_uint_16)0xffff)
3209 {
3210 png_uint_16 v;
3211
Andreas Dilger47a0c421997-05-16 02:46:07 -05003212 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003213 *dp = (png_byte)((v >> 8) & 0xff);
3214 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003215 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003216 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3217 *(dp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003218 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003219 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3220 *(dp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003221 }
3222 else if (a == 0)
3223 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003224 /* Background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003225 *dp = (png_byte)((background->red >> 8) & 0xff);
3226 *(dp + 1) = (png_byte)(background->red & 0xff);
3227 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3228 *(dp + 3) = (png_byte)(background->green & 0xff);
3229 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3230 *(dp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003231 }
3232 else
3233 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003234 png_uint_16 v, w, x;
Guy Schalnat0d580581995-07-20 02:43:20 -05003235
Andreas Dilger47a0c421997-05-16 02:46:07 -05003236 v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003237 png_composite_16(w, v, a, background_1->red);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003238 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3239 *dp = (png_byte)((x >> 8) & 0xff);
3240 *(dp + 1) = (png_byte)(x & 0xff);
3241 v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003242 png_composite_16(w, v, a, background_1->green);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003243 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3244 *(dp + 2) = (png_byte)((x >> 8) & 0xff);
3245 *(dp + 3) = (png_byte)(x & 0xff);
3246 v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003247 png_composite_16(w, v, a, background_1->blue);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003248 x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
3249 *(dp + 4) = (png_byte)((x >> 8) & 0xff);
3250 *(dp + 5) = (png_byte)(x & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003251 }
3252 }
3253 }
3254 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003255#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003256 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003257 sp = row;
3258 dp = row;
3259 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003260 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003261 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3262 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003263 if (a == (png_uint_16)0xffff)
3264 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003265 png_memcpy(dp, sp, 6);
Guy Schalnat0d580581995-07-20 02:43:20 -05003266 }
3267 else if (a == 0)
3268 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003269 *dp = (png_byte)((background->red >> 8) & 0xff);
3270 *(dp + 1) = (png_byte)(background->red & 0xff);
3271 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3272 *(dp + 3) = (png_byte)(background->green & 0xff);
3273 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3274 *(dp + 5) = (png_byte)(background->blue & 0xff);
3275 }
3276 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003277 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003278 png_uint_16 v;
Guy Schalnat0d580581995-07-20 02:43:20 -05003279
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003280 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3281 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3282 + *(sp + 3));
3283 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3284 + *(sp + 5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003285
3286 png_composite_16(v, r, a, background->red);
Guy Schalnat0d580581995-07-20 02:43:20 -05003287 *dp = (png_byte)((v >> 8) & 0xff);
3288 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003289 png_composite_16(v, g, a, background->green);
Guy Schalnat0d580581995-07-20 02:43:20 -05003290 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3291 *(dp + 3) = (png_byte)(v & 0xff);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003292 png_composite_16(v, b, a, background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003293 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3294 *(dp + 5) = (png_byte)(v & 0xff);
3295 }
3296 }
3297 }
3298 }
3299 break;
3300 }
3301 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003302
Guy Schalnat0d580581995-07-20 02:43:20 -05003303 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
3304 {
3305 row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
Guy Schalnate5a37791996-06-05 15:50:50 -05003306 row_info->channels--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003307 row_info->pixel_depth = (png_byte)(row_info->channels *
3308 row_info->bit_depth);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003309 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003310 }
3311 }
3312}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003313#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003314
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003315#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003316/* Gamma correct the image, avoiding the alpha channel. Make sure
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003317 * you do this after you deal with the transparency issue on grayscale
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003318 * or RGB images. If your bit depth is 8, use gamma_table, if it
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003319 * is 16, use gamma_16_table and gamma_shift. Build these with
3320 * build_gamma_table().
3321 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003322void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003323png_do_gamma(png_row_infop row_info, png_bytep row,
3324 png_bytep gamma_table, png_uint_16pp gamma_16_table,
Guy Schalnat0d580581995-07-20 02:43:20 -05003325 int gamma_shift)
3326{
Guy Schalnat6d764711995-12-19 03:22:19 -06003327 png_bytep sp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003328 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003329 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003330
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003331 png_debug(1, "in png_do_gamma");
Andreas Dilger47a0c421997-05-16 02:46:07 -05003332 if (
Andreas Dilger47a0c421997-05-16 02:46:07 -05003333 ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
3334 (row_info->bit_depth == 16 && gamma_16_table != NULL)))
Guy Schalnat0d580581995-07-20 02:43:20 -05003335 {
3336 switch (row_info->color_type)
3337 {
3338 case PNG_COLOR_TYPE_RGB:
3339 {
3340 if (row_info->bit_depth == 8)
3341 {
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 {
3345 *sp = gamma_table[*sp];
3346 sp++;
3347 *sp = gamma_table[*sp];
3348 sp++;
3349 *sp = gamma_table[*sp];
3350 sp++;
3351 }
3352 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003353 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003354 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003355 sp = row;
3356 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003357 {
3358 png_uint_16 v;
3359
Andreas Dilger47a0c421997-05-16 02:46:07 -05003360 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003361 *sp = (png_byte)((v >> 8) & 0xff);
3362 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003363 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003364 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003365 *sp = (png_byte)((v >> 8) & 0xff);
3366 *(sp + 1) = (png_byte)(v & 0xff);
3367 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003368 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003369 *sp = (png_byte)((v >> 8) & 0xff);
3370 *(sp + 1) = (png_byte)(v & 0xff);
3371 sp += 2;
3372 }
3373 }
3374 break;
3375 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003376
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003377 case PNG_COLOR_TYPE_RGB_ALPHA:
3378 {
3379 if (row_info->bit_depth == 8)
3380 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003381 sp = row;
3382 for (i = 0; i < row_width; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003383 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003384 *sp = gamma_table[*sp];
3385 sp++;
3386 *sp = gamma_table[*sp];
3387 sp++;
3388 *sp = gamma_table[*sp];
3389 sp++;
3390 sp++;
3391 }
3392 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003393 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003394 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003395 sp = row;
3396 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003397 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003398 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003399 *sp = (png_byte)((v >> 8) & 0xff);
3400 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003401 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003402 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003403 *sp = (png_byte)((v >> 8) & 0xff);
3404 *(sp + 1) = (png_byte)(v & 0xff);
3405 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003406 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003407 *sp = (png_byte)((v >> 8) & 0xff);
3408 *(sp + 1) = (png_byte)(v & 0xff);
3409 sp += 4;
3410 }
3411 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003412 break;
3413 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003414
Guy Schalnat0d580581995-07-20 02:43:20 -05003415 case PNG_COLOR_TYPE_GRAY_ALPHA:
3416 {
3417 if (row_info->bit_depth == 8)
3418 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003419 sp = row;
3420 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003421 {
3422 *sp = gamma_table[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003423 sp += 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05003424 }
3425 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003426 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003427 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003428 sp = row;
3429 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003430 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003431 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003432 *sp = (png_byte)((v >> 8) & 0xff);
3433 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003434 sp += 4;
3435 }
3436 }
3437 break;
3438 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003439
Guy Schalnat0d580581995-07-20 02:43:20 -05003440 case PNG_COLOR_TYPE_GRAY:
3441 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003442 if (row_info->bit_depth == 2)
3443 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003444 sp = row;
3445 for (i = 0; i < row_width; i += 4)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003446 {
3447 int a = *sp & 0xc0;
3448 int b = *sp & 0x30;
3449 int c = *sp & 0x0c;
3450 int d = *sp & 0x03;
3451
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003452 *sp = (png_byte)(
3453 ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003454 ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
3455 ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003456 ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003457 sp++;
3458 }
3459 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003460
Andreas Dilger47a0c421997-05-16 02:46:07 -05003461 if (row_info->bit_depth == 4)
Guy Schalnat0d580581995-07-20 02:43:20 -05003462 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003463 sp = row;
3464 for (i = 0; i < row_width; i += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003465 {
3466 int msb = *sp & 0xf0;
3467 int lsb = *sp & 0x0f;
3468
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003469 *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
3470 | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003471 sp++;
3472 }
3473 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003474
Andreas Dilger47a0c421997-05-16 02:46:07 -05003475 else if (row_info->bit_depth == 8)
3476 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003477 sp = row;
3478 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003479 {
3480 *sp = gamma_table[*sp];
3481 sp++;
3482 }
3483 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003484
Guy Schalnat0d580581995-07-20 02:43:20 -05003485 else if (row_info->bit_depth == 16)
3486 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003487 sp = row;
3488 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003489 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003490 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003491 *sp = (png_byte)((v >> 8) & 0xff);
3492 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003493 sp += 2;
3494 }
3495 }
3496 break;
3497 }
3498 }
3499 }
3500}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003501#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003502
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003503#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003504/* Expands a palette row to an RGB or RGBA row depending
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003505 * upon whether you supply trans and num_trans.
3506 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003507void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003508png_do_expand_palette(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05003509 png_colorp palette, png_bytep trans, int num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003510{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003511 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003512 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003513 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003514 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003515
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003516 png_debug(1, "in png_do_expand_palette");
Andreas Dilger47a0c421997-05-16 02:46:07 -05003517 if (
Andreas Dilger47a0c421997-05-16 02:46:07 -05003518 row_info->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05003519 {
3520 if (row_info->bit_depth < 8)
3521 {
3522 switch (row_info->bit_depth)
3523 {
3524 case 1:
3525 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003526 sp = row + (png_size_t)((row_width - 1) >> 3);
3527 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003528 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003529 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003530 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003531 if ((*sp >> shift) & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -05003532 *dp = 1;
3533 else
3534 *dp = 0;
3535 if (shift == 7)
3536 {
3537 shift = 0;
3538 sp--;
3539 }
3540 else
3541 shift++;
3542
3543 dp--;
3544 }
3545 break;
3546 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003547
Guy Schalnat0d580581995-07-20 02:43:20 -05003548 case 2:
3549 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003550 sp = row + (png_size_t)((row_width - 1) >> 2);
3551 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003552 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003553 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003554 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003555 value = (*sp >> shift) & 0x03;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003556 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003557 if (shift == 6)
3558 {
3559 shift = 0;
3560 sp--;
3561 }
3562 else
3563 shift += 2;
3564
3565 dp--;
3566 }
3567 break;
3568 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003569
Guy Schalnat0d580581995-07-20 02:43:20 -05003570 case 4:
3571 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003572 sp = row + (png_size_t)((row_width - 1) >> 1);
3573 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003574 shift = (int)((row_width & 0x01) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003575 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003576 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003577 value = (*sp >> shift) & 0x0f;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003578 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003579 if (shift == 4)
3580 {
3581 shift = 0;
3582 sp--;
3583 }
3584 else
3585 shift += 4;
3586
3587 dp--;
3588 }
3589 break;
3590 }
3591 }
3592 row_info->bit_depth = 8;
3593 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003594 row_info->rowbytes = row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003595 }
3596 switch (row_info->bit_depth)
3597 {
3598 case 8:
3599 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003600 if (trans != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003601 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003602 sp = row + (png_size_t)row_width - 1;
3603 dp = row + (png_size_t)(row_width << 2) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003604
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003605 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003606 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003607 if ((int)(*sp) >= num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003608 *dp-- = 0xff;
3609 else
3610 *dp-- = trans[*sp];
3611 *dp-- = palette[*sp].blue;
3612 *dp-- = palette[*sp].green;
3613 *dp-- = palette[*sp].red;
3614 sp--;
3615 }
3616 row_info->bit_depth = 8;
3617 row_info->pixel_depth = 32;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003618 row_info->rowbytes = row_width * 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05003619 row_info->color_type = 6;
3620 row_info->channels = 4;
3621 }
3622 else
3623 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003624 sp = row + (png_size_t)row_width - 1;
3625 dp = row + (png_size_t)(row_width * 3) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003626
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003627 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003628 {
3629 *dp-- = palette[*sp].blue;
3630 *dp-- = palette[*sp].green;
3631 *dp-- = palette[*sp].red;
3632 sp--;
3633 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003634
Guy Schalnat0d580581995-07-20 02:43:20 -05003635 row_info->bit_depth = 8;
3636 row_info->pixel_depth = 24;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003637 row_info->rowbytes = row_width * 3;
Guy Schalnat0d580581995-07-20 02:43:20 -05003638 row_info->color_type = 2;
3639 row_info->channels = 3;
3640 }
3641 break;
3642 }
3643 }
3644 }
3645}
3646
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -06003647/* If the bit depth < 8, it is expanded to 8. Also, if the already
3648 * expanded transparency value is supplied, an alpha channel is built.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003649 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003650void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003651png_do_expand(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003652 png_color_16p trans_value)
Guy Schalnat0d580581995-07-20 02:43:20 -05003653{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003654 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003655 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003656 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003657 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003658
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003659 png_debug(1, "in png_do_expand");
Guy Schalnat0d580581995-07-20 02:43:20 -05003660 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003661 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05003662 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003663 png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003664
3665 if (row_info->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003666 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003667 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05003668 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003669 case 1:
3670 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003671 gray = (png_uint_16)((gray&0x01)*0xff);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003672 sp = row + (png_size_t)((row_width - 1) >> 3);
3673 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003674 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003675 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003676 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003677 if ((*sp >> shift) & 0x01)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003678 *dp = 0xff;
3679 else
3680 *dp = 0;
3681 if (shift == 7)
3682 {
3683 shift = 0;
3684 sp--;
3685 }
3686 else
3687 shift++;
3688
3689 dp--;
3690 }
3691 break;
3692 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003693
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003694 case 2:
3695 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003696 gray = (png_uint_16)((gray&0x03)*0x55);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003697 sp = row + (png_size_t)((row_width - 1) >> 2);
3698 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003699 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003700 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003701 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003702 value = (*sp >> shift) & 0x03;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003703 *dp = (png_byte)(value | (value << 2) | (value << 4) |
3704 (value << 6));
3705 if (shift == 6)
3706 {
3707 shift = 0;
3708 sp--;
3709 }
3710 else
3711 shift += 2;
3712
3713 dp--;
3714 }
3715 break;
3716 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003717
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003718 case 4:
3719 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003720 gray = (png_uint_16)((gray&0x0f)*0x11);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003721 sp = row + (png_size_t)((row_width - 1) >> 1);
3722 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003723 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003724 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003725 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003726 value = (*sp >> shift) & 0x0f;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003727 *dp = (png_byte)(value | (value << 4));
3728 if (shift == 4)
3729 {
3730 shift = 0;
3731 sp--;
3732 }
3733 else
3734 shift = 4;
3735
3736 dp--;
3737 }
3738 break;
3739 }
3740 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003741
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003742 row_info->bit_depth = 8;
3743 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003744 row_info->rowbytes = row_width;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003745 }
3746
Andreas Dilger47a0c421997-05-16 02:46:07 -05003747 if (trans_value != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003748 {
3749 if (row_info->bit_depth == 8)
3750 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003751 gray = gray & 0xff;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003752 sp = row + (png_size_t)row_width - 1;
3753 dp = row + (png_size_t)(row_width << 1) - 1;
3754 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003755 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003756 if (*sp == gray)
3757 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003758 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003759 *dp-- = 0xff;
3760 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003761 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003762 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003763
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003764 else if (row_info->bit_depth == 16)
Guy Schalnat0d580581995-07-20 02:43:20 -05003765 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003766 png_byte gray_high = (gray >> 8) & 0xff;
3767 png_byte gray_low = gray & 0xff;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003768 sp = row + row_info->rowbytes - 1;
3769 dp = row + (row_info->rowbytes << 1) - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003770 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003771 {
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06003772 if (*(sp - 1) == gray_high && *(sp) == gray_low)
Guy Schalnat0d580581995-07-20 02:43:20 -05003773 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003774 *dp-- = 0;
3775 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003776 }
3777 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003778 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003779 *dp-- = 0xff;
3780 *dp-- = 0xff;
Guy Schalnat0d580581995-07-20 02:43:20 -05003781 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003782 *dp-- = *sp--;
3783 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003784 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003785 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003786
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003787 row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
3788 row_info->channels = 2;
3789 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003790 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
3791 row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003792 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003793 }
3794 else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
3795 {
3796 if (row_info->bit_depth == 8)
3797 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003798 png_byte red = trans_value->red & 0xff;
3799 png_byte green = trans_value->green & 0xff;
3800 png_byte blue = trans_value->blue & 0xff;
Guy Schalnat0d580581995-07-20 02:43:20 -05003801 sp = row + (png_size_t)row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003802 dp = row + (png_size_t)(row_width << 2) - 1;
3803 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003804 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003805 if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05003806 *dp-- = 0;
3807 else
3808 *dp-- = 0xff;
3809 *dp-- = *sp--;
3810 *dp-- = *sp--;
3811 *dp-- = *sp--;
3812 }
3813 }
3814 else if (row_info->bit_depth == 16)
3815 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003816 png_byte red_high = (trans_value->red >> 8) & 0xff;
3817 png_byte green_high = (trans_value->green >> 8) & 0xff;
3818 png_byte blue_high = (trans_value->blue >> 8) & 0xff;
3819 png_byte red_low = trans_value->red & 0xff;
3820 png_byte green_low = trans_value->green & 0xff;
3821 png_byte blue_low = trans_value->blue & 0xff;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003822 sp = row + row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003823 dp = row + (png_size_t)(row_width << 3) - 1;
3824 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003825 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003826 if (*(sp - 5) == red_high &&
3827 *(sp - 4) == red_low &&
3828 *(sp - 3) == green_high &&
3829 *(sp - 2) == green_low &&
3830 *(sp - 1) == blue_high &&
3831 *(sp ) == blue_low)
Guy Schalnat0d580581995-07-20 02:43:20 -05003832 {
3833 *dp-- = 0;
3834 *dp-- = 0;
3835 }
3836 else
3837 {
3838 *dp-- = 0xff;
3839 *dp-- = 0xff;
3840 }
3841 *dp-- = *sp--;
3842 *dp-- = *sp--;
3843 *dp-- = *sp--;
3844 *dp-- = *sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003845 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003846 *dp-- = *sp--;
3847 }
3848 }
3849 row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
3850 row_info->channels = 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003851 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003852 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003853 }
3854 }
3855}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003856#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003857
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003858#if defined(PNG_READ_DITHER_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003859void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003860png_do_dither(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003861 png_bytep palette_lookup, png_bytep dither_lookup)
Guy Schalnat0d580581995-07-20 02:43:20 -05003862{
Guy Schalnat6d764711995-12-19 03:22:19 -06003863 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003864 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003865 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003866
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003867 png_debug(1, "in png_do_dither");
Guy Schalnat0d580581995-07-20 02:43:20 -05003868 {
3869 if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
3870 palette_lookup && row_info->bit_depth == 8)
3871 {
3872 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003873 sp = row;
3874 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003875 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003876 {
3877 r = *sp++;
3878 g = *sp++;
3879 b = *sp++;
3880
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003881 /* This looks real messy, but the compiler will reduce
3882 * it down to a reasonable formula. For example, with
3883 * 5 bits per color, we get:
3884 * p = (((r >> 3) & 0x1f) << 10) |
3885 * (((g >> 3) & 0x1f) << 5) |
3886 * ((b >> 3) & 0x1f);
3887 */
Guy Schalnat0d580581995-07-20 02:43:20 -05003888 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
3889 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
3890 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3891 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003892 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003893 (PNG_DITHER_BLUE_BITS)) |
3894 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3895 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3896
3897 *dp++ = palette_lookup[p];
3898 }
3899 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3900 row_info->channels = 1;
3901 row_info->pixel_depth = row_info->bit_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003902 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003903 }
3904 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
Andreas Dilger47a0c421997-05-16 02:46:07 -05003905 palette_lookup != NULL && row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003906 {
3907 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003908 sp = row;
3909 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003910 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003911 {
3912 r = *sp++;
3913 g = *sp++;
3914 b = *sp++;
3915 sp++;
3916
3917 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003918 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003919 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3920 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
3921 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
3922 (PNG_DITHER_BLUE_BITS)) |
3923 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3924 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3925
3926 *dp++ = palette_lookup[p];
3927 }
3928 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3929 row_info->channels = 1;
3930 row_info->pixel_depth = row_info->bit_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003931 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003932 }
3933 else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
3934 dither_lookup && row_info->bit_depth == 8)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003935 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003936 sp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003937 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003938 {
3939 *sp = dither_lookup[*sp];
3940 }
3941 }
3942 }
3943}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003944#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003945
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003946#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003947#if defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003948static PNG_CONST int png_gamma_shift[] =
3949 {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0, 0x00};
Guy Schalnat0d580581995-07-20 02:43:20 -05003950
Andreas Dilger47a0c421997-05-16 02:46:07 -05003951/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003952 * tables, we don't make a full table if we are reducing to 8-bit in
3953 * the future. Note also how the gamma_16 tables are segmented so that
3954 * we don't need to allocate > 64K chunks for a full 16-bit table.
Glenn Randers-Pehrsonbc7156d2009-07-06 09:11:54 -05003955 *
3956 * See the PNG extensions document for an integer algorithm for creating
3957 * the gamma tables. Maybe we will implement that here someday.
3958 *
3959 * We should only reach this point if
3960 *
3961 * the file_gamma is known (i.e., the gAMA or sRGB chunk is present,
3962 * or the application has provided a file_gamma)
3963 *
3964 * AND
3965 * {
3966 * the screen_gamma is known
3967 *
3968 * OR
3969 *
3970 * RGB_to_gray transformation is being performed
3971 * }
3972 *
3973 * AND
3974 * {
3975 * the screen_gamma is different from the reciprocal of the
3976 * file_gamma by more than the specified threshold
3977 *
3978 * OR
3979 *
3980 * a background color has been specified and the file_gamma
3981 * and screen_gamma are not 1.0, within the specified threshold.
3982 * }
3983 *
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003984 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003985void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003986png_build_gamma_table(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003987{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003988 png_debug(1, "in png_build_gamma_table");
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003989
3990 if (png_ptr->bit_depth <= 8)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003991 {
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003992 int i;
3993 double g;
Guy Schalnat0d580581995-07-20 02:43:20 -05003994
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003995 if (png_ptr->screen_gamma > .000001)
3996 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003997
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003998 else
3999 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05004000
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004001 png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
4002 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05004003
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004004 for (i = 0; i < 256; i++)
4005 {
4006 png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
4007 g) * 255.0 + .5);
4008 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004009
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004010#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004011 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4012 if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
4013 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004014
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004015 g = 1.0 / (png_ptr->gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05004016
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004017 png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
4018 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05004019
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004020 for (i = 0; i < 256; i++)
4021 {
4022 png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
4023 g) * 255.0 + .5);
4024 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004025
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06004026
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004027 png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
4028 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05004029
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004030 if (png_ptr->screen_gamma > 0.000001)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004031 g = 1.0 / png_ptr->screen_gamma;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004032
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004033 else
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05004034 g = png_ptr->gamma; /* Probably doing rgb_to_gray */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004035
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004036 for (i = 0; i < 256; i++)
4037 {
4038 png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
4039 g) * 255.0 + .5);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004040
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004041 }
4042 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004043#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004044 }
4045 else
4046 {
4047 double g;
4048 int i, j, shift, num;
4049 int sig_bit;
4050 png_uint_32 ig;
Guy Schalnat0d580581995-07-20 02:43:20 -05004051
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004052 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
4053 {
4054 sig_bit = (int)png_ptr->sig_bit.red;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004055
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004056 if ((int)png_ptr->sig_bit.green > sig_bit)
4057 sig_bit = png_ptr->sig_bit.green;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004058
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004059 if ((int)png_ptr->sig_bit.blue > sig_bit)
4060 sig_bit = png_ptr->sig_bit.blue;
4061 }
4062 else
4063 {
4064 sig_bit = (int)png_ptr->sig_bit.gray;
4065 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004066
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004067 if (sig_bit > 0)
4068 shift = 16 - sig_bit;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004069
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004070 else
4071 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05004072
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004073 if (png_ptr->transformations & PNG_16_TO_8)
4074 {
4075 if (shift < (16 - PNG_MAX_GAMMA_8))
4076 shift = (16 - PNG_MAX_GAMMA_8);
4077 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004078
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004079 if (shift > 8)
4080 shift = 8;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004081
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004082 if (shift < 0)
4083 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05004084
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004085 png_ptr->gamma_shift = (png_byte)shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05004086
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004087 num = (1 << (8 - shift));
Guy Schalnat0d580581995-07-20 02:43:20 -05004088
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004089 if (png_ptr->screen_gamma > .000001)
4090 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
4091 else
4092 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05004093
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004094#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06004095 png_ptr->gamma_16_table = (png_uint_16pp)png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004096 (png_uint_32)(num * png_sizeof(png_uint_16p)));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004097#else
4098 png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
4099 (png_uint_32)(num * png_sizeof(png_uint_16p)));
Glenn Randers-Pehrsond60c8862009-06-15 21:56:14 -05004100 png_memset(png_ptr->gamma_16_table, 0, num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004101#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05004102
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004103 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
4104 {
4105 double fin, fout;
4106 png_uint_32 last, max;
Guy Schalnat0d580581995-07-20 02:43:20 -05004107
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004108 for (i = 0; i < num; i++)
4109 {
4110 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004111 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004112 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004113
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004114 g = 1.0 / g;
4115 last = 0;
4116 for (i = 0; i < 256; i++)
4117 {
4118 fout = ((double)i + 0.5) / 256.0;
4119 fin = pow(fout, g);
4120 max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
4121 while (last <= max)
4122 {
4123 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4124 [(int)(last >> (8 - shift))] = (png_uint_16)(
4125 (png_uint_16)i | ((png_uint_16)i << 8));
4126 last++;
4127 }
4128 }
4129 while (last < ((png_uint_32)num << 8))
4130 {
4131 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4132 [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
4133 last++;
4134 }
4135 }
4136 else
4137 {
4138 for (i = 0; i < num; i++)
4139 {
4140 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004141 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004142
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004143 ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004144
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004145 for (j = 0; j < 256; j++)
4146 {
4147 png_ptr->gamma_16_table[i][j] =
4148 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4149 65535.0, g) * 65535.0 + .5);
4150 }
4151 }
4152 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004153
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004154#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004155 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4156 if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
4157 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004158
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004159 g = 1.0 / (png_ptr->gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05004160
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004161#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06004162 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004163 (png_uint_32)(num * png_sizeof(png_uint_16p )));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004164#else
4165 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
4166 (png_uint_32)(num * png_sizeof(png_uint_16p )));
Glenn Randers-Pehrsond60c8862009-06-15 21:56:14 -05004167 png_memset(png_ptr->gamma_16_to_1, 0, num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004168#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05004169
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004170 for (i = 0; i < num; i++)
4171 {
4172 png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004173 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004174
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004175 ig = (((png_uint_32)i *
4176 (png_uint_32)png_gamma_shift[shift]) >> 4);
4177 for (j = 0; j < 256; j++)
4178 {
4179 png_ptr->gamma_16_to_1[i][j] =
4180 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4181 65535.0, g) * 65535.0 + .5);
4182 }
4183 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004184
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004185 if (png_ptr->screen_gamma > 0.000001)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004186 g = 1.0 / png_ptr->screen_gamma;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004187
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004188 else
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05004189 g = png_ptr->gamma; /* Probably doing rgb_to_gray */
Guy Schalnat0d580581995-07-20 02:43:20 -05004190
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004191#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06004192 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004193 (png_uint_32)(num * png_sizeof(png_uint_16p)));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004194#else
4195 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
4196 (png_uint_32)(num * png_sizeof(png_uint_16p)));
4197 png_memset(png_ptr->gamma_16_from_1, 0,
Glenn Randers-Pehrsond60c8862009-06-15 21:56:14 -05004198 num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004199#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05004200
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004201 for (i = 0; i < num; i++)
4202 {
4203 png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004204 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004205
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004206 ig = (((png_uint_32)i *
4207 (png_uint_32)png_gamma_shift[shift]) >> 4);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004208
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004209 for (j = 0; j < 256; j++)
4210 {
4211 png_ptr->gamma_16_from_1[i][j] =
4212 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4213 65535.0, g) * 65535.0 + .5);
4214 }
4215 }
4216 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004217#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004218 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004219}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004220#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06004221/* To do: install integer version of png_build_gamma_table here */
4222#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004223
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004224#if defined(PNG_MNG_FEATURES_SUPPORTED)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05004225/* Undoes intrapixel differencing */
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004226void /* PRIVATE */
4227png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
4228{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05004229 png_debug(1, "in png_do_read_intrapixel");
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004230 if (
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004231 (row_info->color_type & PNG_COLOR_MASK_COLOR))
4232 {
4233 int bytes_per_pixel;
4234 png_uint_32 row_width = row_info->width;
4235 if (row_info->bit_depth == 8)
4236 {
4237 png_bytep rp;
4238 png_uint_32 i;
4239
4240 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4241 bytes_per_pixel = 3;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004242
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004243 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4244 bytes_per_pixel = 4;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004245
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004246 else
4247 return;
4248
4249 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4250 {
4251 *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff);
4252 *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff);
4253 }
4254 }
4255 else if (row_info->bit_depth == 16)
4256 {
4257 png_bytep rp;
4258 png_uint_32 i;
4259
4260 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4261 bytes_per_pixel = 6;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004262
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004263 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4264 bytes_per_pixel = 8;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004265
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004266 else
4267 return;
4268
4269 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4270 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004271 png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1);
4272 png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3);
4273 png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5);
4274 png_uint_32 red = (png_uint_32)((s0 + s1 + 65536L) & 0xffffL);
4275 png_uint_32 blue = (png_uint_32)((s2 + s1 + 65536L) & 0xffffL);
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05004276 *(rp ) = (png_byte)((red >> 8) & 0xff);
4277 *(rp+1) = (png_byte)(red & 0xff);
4278 *(rp+4) = (png_byte)((blue >> 8) & 0xff);
4279 *(rp+5) = (png_byte)(blue & 0xff);
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004280 }
4281 }
4282 }
4283}
4284#endif /* PNG_MNG_FEATURES_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004285#endif /* PNG_READ_SUPPORTED */