blob: 2e9b839df19258b34ba3d0ca4731e9cba30cd8f5 [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-Pehrson5265c382009-12-22 09:09:34 -06004 * Last changed in libpng 1.4.0 [December 22, 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
Glenn Randers-Pehrson03f9b022009-12-04 08:40:41 -060019#define PNG_NO_PEDANTIC_WARNINGS
Guy Schalnat0d580581995-07-20 02:43:20 -050020#include "png.h"
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -050021#ifdef PNG_READ_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050022#include "pngpriv.h"
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060023
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060024/* Set the action on getting a CRC error for an ancillary or critical chunk. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050025void PNGAPI
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060026png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
27{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -050028 png_debug(1, "in png_set_crc_action");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -050029
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050030 if (png_ptr == NULL)
31 return;
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -050032
33 /* Tell libpng how we react to CRC errors in critical chunks */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060034 switch (crit_action)
35 {
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050036 case PNG_CRC_NO_CHANGE: /* Leave setting as is */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060037 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050038
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050039 case PNG_CRC_WARN_USE: /* Warn/use data */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060040 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
41 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
42 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050043
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050044 case PNG_CRC_QUIET_USE: /* Quiet/use data */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060045 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
46 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
47 PNG_FLAG_CRC_CRITICAL_IGNORE;
48 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050049
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050050 case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050051 png_warning(png_ptr,
52 "Can't discard critical data on CRC error");
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050053 case PNG_CRC_ERROR_QUIT: /* Error/quit */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050054
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060055 case PNG_CRC_DEFAULT:
56 default:
57 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
58 break;
59 }
60
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -050061 /* Tell libpng how we react to CRC errors in ancillary chunks */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060062 switch (ancil_action)
63 {
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050064 case PNG_CRC_NO_CHANGE: /* Leave setting as is */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060065 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050066
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050067 case PNG_CRC_WARN_USE: /* Warn/use data */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060068 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
69 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
70 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050071
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050072 case PNG_CRC_QUIET_USE: /* Quiet/use data */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060073 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
74 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
75 PNG_FLAG_CRC_ANCILLARY_NOWARN;
76 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050077
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050078 case PNG_CRC_ERROR_QUIT: /* Error/quit */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060079 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
80 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
81 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050082
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050083 case PNG_CRC_WARN_DISCARD: /* Warn/discard data */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050084
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060085 case PNG_CRC_DEFAULT:
86 default:
87 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
88 break;
89 }
90}
91
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060092#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
93 defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050094/* Handle alpha and tRNS via a background color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050095void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060096png_set_background(png_structp png_ptr,
97 png_color_16p background_color, int background_gamma_code,
Guy Schalnat51f0eb41995-09-26 05:22:39 -050098 int need_expand, double background_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -050099{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500100 png_debug(1, "in png_set_background");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500101
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500102 if (png_ptr == NULL)
103 return;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600104 if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
105 {
106 png_warning(png_ptr, "Application must supply a known background gamma");
107 return;
108 }
109
Guy Schalnat0d580581995-07-20 02:43:20 -0500110 png_ptr->transformations |= PNG_BACKGROUND;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500111 png_memcpy(&(png_ptr->background), background_color,
112 png_sizeof(png_color_16));
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500113 png_ptr->background_gamma = (float)background_gamma;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600114 png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
Guy Schalnate5a37791996-06-05 15:50:50 -0500115 png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500116}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500117#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500118
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500119#ifdef PNG_READ_16_TO_8_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500120/* Strip 16 bit depth files to 8 bit depth */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500121void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600122png_set_strip_16(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500123{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500124 png_debug(1, "in png_set_strip_16");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500125
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500126 if (png_ptr == NULL)
127 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500128 png_ptr->transformations |= PNG_16_TO_8;
129}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500130#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500131
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500132#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500133void PNGAPI
Andreas Dilger47a0c421997-05-16 02:46:07 -0500134png_set_strip_alpha(png_structp png_ptr)
135{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500136 png_debug(1, "in png_set_strip_alpha");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500137
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500138 if (png_ptr == NULL)
139 return;
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -0600140 png_ptr->flags |= PNG_FLAG_STRIP_ALPHA;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500141}
142#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500143
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500144#ifdef PNG_READ_DITHER_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500145/* Dither file to 8 bit. Supply a palette, the current number
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600146 * of elements in the palette, the maximum number of elements
147 * allowed, and a histogram if possible. If the current number
148 * of colors is greater then the maximum number, the palette will be
149 * modified to fit in the maximum number. "full_dither" indicates
150 * whether we need a dithering cube set up for RGB images, or if we
151 * simply are reducing the number of colors in a paletted image.
152 */
Guy Schalnat6d764711995-12-19 03:22:19 -0600153
154typedef struct png_dsort_struct
Guy Schalnat0d580581995-07-20 02:43:20 -0500155{
Guy Schalnat6d764711995-12-19 03:22:19 -0600156 struct png_dsort_struct FAR * next;
Guy Schalnat0d580581995-07-20 02:43:20 -0500157 png_byte left;
158 png_byte right;
Guy Schalnat6d764711995-12-19 03:22:19 -0600159} png_dsort;
160typedef png_dsort FAR * png_dsortp;
161typedef png_dsort FAR * FAR * png_dsortpp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500162
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500163void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600164png_set_dither(png_structp png_ptr, png_colorp palette,
165 int num_palette, int maximum_colors, png_uint_16p histogram,
Guy Schalnat0d580581995-07-20 02:43:20 -0500166 int full_dither)
167{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500168 png_debug(1, "in png_set_dither");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500169
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500170 if (png_ptr == NULL)
171 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500172 png_ptr->transformations |= PNG_DITHER;
173
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600174 if (!full_dither)
Guy Schalnat0d580581995-07-20 02:43:20 -0500175 {
176 int i;
177
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600178 png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500179 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500180 for (i = 0; i < num_palette; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600181 png_ptr->dither_index[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500182 }
183
184 if (num_palette > maximum_colors)
185 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500186 if (histogram != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500187 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500188 /* This is easy enough, just throw out the least used colors.
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500189 * Perhaps not the best solution, but good enough.
190 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500191
192 int i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500193
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500194 /* Initialize an array to sort colors */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500195 png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500196 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500197
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500198 /* Initialize the dither_sort array */
Guy Schalnat0d580581995-07-20 02:43:20 -0500199 for (i = 0; i < num_palette; i++)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500200 png_ptr->dither_sort[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500201
Andreas Dilger47a0c421997-05-16 02:46:07 -0500202 /* Find the least used palette entries by starting a
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500203 * bubble sort, and running it until we have sorted
204 * out enough colors. Note that we don't care about
205 * sorting all the colors, just finding which are
206 * least used.
207 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500208
209 for (i = num_palette - 1; i >= maximum_colors; i--)
210 {
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500211 int done; /* To stop early if the list is pre-sorted */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600212 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500213
214 done = 1;
215 for (j = 0; j < i; j++)
216 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500217 if (histogram[png_ptr->dither_sort[j]]
218 < histogram[png_ptr->dither_sort[j + 1]])
Guy Schalnat0d580581995-07-20 02:43:20 -0500219 {
220 png_byte t;
221
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500222 t = png_ptr->dither_sort[j];
223 png_ptr->dither_sort[j] = png_ptr->dither_sort[j + 1];
224 png_ptr->dither_sort[j + 1] = t;
Guy Schalnat0d580581995-07-20 02:43:20 -0500225 done = 0;
226 }
227 }
228 if (done)
229 break;
230 }
231
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500232 /* Swap the palette around, and set up a table, if necessary */
Guy Schalnat0d580581995-07-20 02:43:20 -0500233 if (full_dither)
234 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500235 int j = num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500236
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500237 /* Put all the useful colors within the max, but don't
238 * move the others.
239 */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500240 for (i = 0; i < maximum_colors; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500241 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500242 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500243 {
244 do
245 j--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500246 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
Guy Schalnat0d580581995-07-20 02:43:20 -0500247 palette[i] = palette[j];
248 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600249 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500250 }
251 else
252 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500253 int j = num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500254
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500255 /* Move all the used colors inside the max limit, and
256 * develop a translation table.
257 */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500258 for (i = 0; i < maximum_colors; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500259 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500260 /* Only move the colors we need to */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500261 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500262 {
263 png_color tmp_color;
264
265 do
266 j--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500267 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
Guy Schalnat0d580581995-07-20 02:43:20 -0500268
269 tmp_color = palette[j];
270 palette[j] = palette[i];
271 palette[i] = tmp_color;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500272 /* Indicate where the color went */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600273 png_ptr->dither_index[j] = (png_byte)i;
274 png_ptr->dither_index[i] = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500275 }
276 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500277
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500278 /* Find closest color for those colors we are not using */
Guy Schalnat0d580581995-07-20 02:43:20 -0500279 for (i = 0; i < num_palette; i++)
280 {
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600281 if ((int)png_ptr->dither_index[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500282 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500283 int min_d, k, min_k, d_index;
Guy Schalnat0d580581995-07-20 02:43:20 -0500284
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500285 /* Find the closest color to one we threw out */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500286 d_index = png_ptr->dither_index[i];
287 min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
288 for (k = 1, min_k = 0; k < maximum_colors; k++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500289 {
290 int d;
291
Andreas Dilger47a0c421997-05-16 02:46:07 -0500292 d = PNG_COLOR_DIST(palette[d_index], palette[k]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500293
294 if (d < min_d)
295 {
296 min_d = d;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500297 min_k = k;
Guy Schalnat0d580581995-07-20 02:43:20 -0500298 }
299 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500300 /* Point to closest color */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500301 png_ptr->dither_index[i] = (png_byte)min_k;
Guy Schalnat0d580581995-07-20 02:43:20 -0500302 }
303 }
304 }
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500305 png_free(png_ptr, png_ptr->dither_sort);
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500306 png_ptr->dither_sort = NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500307 }
308 else
309 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500310 /* This is much harder to do simply (and quickly). Perhaps
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500311 * we need to go through a median cut routine, but those
312 * don't always behave themselves with only a few colors
313 * as input. So we will just find the closest two colors,
314 * and throw out one of them (chosen somewhat randomly).
315 * [We don't understand this at all, so if someone wants to
316 * work on improving it, be our guest - AED, GRP]
317 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500318 int i;
319 int max_d;
320 int num_new_palette;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500321 png_dsortp t;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600322 png_dsortpp hash;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500323
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500324 t = NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500325
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500326 /* Initialize palette index arrays */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500327 png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500328 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500329 png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500330 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500331
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500332 /* Initialize the sort array */
Guy Schalnat0d580581995-07-20 02:43:20 -0500333 for (i = 0; i < num_palette; i++)
334 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500335 png_ptr->index_to_palette[i] = (png_byte)i;
336 png_ptr->palette_to_index[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500337 }
338
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600339 hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 *
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500340 png_sizeof(png_dsortp)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500341
342 num_new_palette = num_palette;
343
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500344 /* Initial wild guess at how far apart the farthest pixel
345 * pair we will be eliminating will be. Larger
346 * numbers mean more areas will be allocated, Smaller
347 * numbers run the risk of not saving enough data, and
348 * having to do this all over again.
349 *
350 * I have not done extensive checking on this number.
351 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500352 max_d = 96;
353
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600354 while (num_new_palette > maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500355 {
356 for (i = 0; i < num_new_palette - 1; i++)
357 {
358 int j;
359
360 for (j = i + 1; j < num_new_palette; j++)
361 {
362 int d;
363
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600364 d = PNG_COLOR_DIST(palette[i], palette[j]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500365
366 if (d <= max_d)
367 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500368
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500369 t = (png_dsortp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500370 (png_uint_32)(png_sizeof(png_dsort)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500371 if (t == NULL)
372 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500373 t->next = hash[d];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600374 t->left = (png_byte)i;
375 t->right = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500376 hash[d] = t;
377 }
378 }
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500379 if (t == NULL)
380 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500381 }
382
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500383 if (t != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500384 for (i = 0; i <= max_d; i++)
385 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500386 if (hash[i] != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500387 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600388 png_dsortp p;
Guy Schalnat0d580581995-07-20 02:43:20 -0500389
390 for (p = hash[i]; p; p = p->next)
391 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500392 if ((int)png_ptr->index_to_palette[p->left]
393 < num_new_palette &&
394 (int)png_ptr->index_to_palette[p->right]
395 < num_new_palette)
Guy Schalnat0d580581995-07-20 02:43:20 -0500396 {
397 int j, next_j;
398
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600399 if (num_new_palette & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -0500400 {
401 j = p->left;
402 next_j = p->right;
403 }
404 else
405 {
406 j = p->right;
407 next_j = p->left;
408 }
409
410 num_new_palette--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500411 palette[png_ptr->index_to_palette[j]]
412 = palette[num_new_palette];
Guy Schalnat0d580581995-07-20 02:43:20 -0500413 if (!full_dither)
414 {
415 int k;
416
417 for (k = 0; k < num_palette; k++)
418 {
419 if (png_ptr->dither_index[k] ==
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500420 png_ptr->index_to_palette[j])
Guy Schalnat0d580581995-07-20 02:43:20 -0500421 png_ptr->dither_index[k] =
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500422 png_ptr->index_to_palette[next_j];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600423 if ((int)png_ptr->dither_index[k] ==
Guy Schalnat0d580581995-07-20 02:43:20 -0500424 num_new_palette)
425 png_ptr->dither_index[k] =
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500426 png_ptr->index_to_palette[j];
Guy Schalnat0d580581995-07-20 02:43:20 -0500427 }
428 }
429
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500430 png_ptr->index_to_palette[png_ptr->palette_to_index
431 [num_new_palette]] = png_ptr->index_to_palette[j];
432 png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
433 = png_ptr->palette_to_index[num_new_palette];
Guy Schalnat0d580581995-07-20 02:43:20 -0500434
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500435 png_ptr->index_to_palette[j] = (png_byte)num_new_palette;
436 png_ptr->palette_to_index[num_new_palette] = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500437 }
438 if (num_new_palette <= maximum_colors)
439 break;
440 }
441 if (num_new_palette <= maximum_colors)
442 break;
443 }
444 }
445
446 for (i = 0; i < 769; i++)
447 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500448 if (hash[i] != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500449 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500450 png_dsortp p = hash[i];
Guy Schalnat0d580581995-07-20 02:43:20 -0500451 while (p)
452 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500453 t = p->next;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600454 png_free(png_ptr, p);
Guy Schalnat0d580581995-07-20 02:43:20 -0500455 p = t;
456 }
457 }
458 hash[i] = 0;
459 }
460 max_d += 96;
461 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600462 png_free(png_ptr, hash);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500463 png_free(png_ptr, png_ptr->palette_to_index);
464 png_free(png_ptr, png_ptr->index_to_palette);
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500465 png_ptr->palette_to_index = NULL;
466 png_ptr->index_to_palette = NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500467 }
468 num_palette = maximum_colors;
469 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500470 if (png_ptr->palette == NULL)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600471 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500472 png_ptr->palette = palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500473 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600474 png_ptr->num_palette = (png_uint_16)num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500475
476 if (full_dither)
477 {
478 int i;
Guy Schalnat6d764711995-12-19 03:22:19 -0600479 png_bytep distance;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500480 int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600481 PNG_DITHER_BLUE_BITS;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500482 int num_red = (1 << PNG_DITHER_RED_BITS);
483 int num_green = (1 << PNG_DITHER_GREEN_BITS);
484 int num_blue = (1 << PNG_DITHER_BLUE_BITS);
485 png_size_t num_entries = ((png_size_t)1 << total_bits);
Guy Schalnat0d580581995-07-20 02:43:20 -0500486
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600487 png_ptr->palette_lookup = (png_bytep )png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500488 (png_uint_32)(num_entries * png_sizeof(png_byte)));
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500489
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500490 distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
491 png_sizeof(png_byte)));
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500492 png_memset(distance, 0xff, num_entries * png_sizeof(png_byte));
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500493
494 for (i = 0; i < num_palette; i++)
495 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500496 int ir, ig, ib;
497 int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
498 int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
499 int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
Guy Schalnat0d580581995-07-20 02:43:20 -0500500
501 for (ir = 0; ir < num_red; ir++)
502 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500503 /* int dr = abs(ir - r); */
504 int dr = ((ir > r) ? ir - r : r - ir);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500505 int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
Guy Schalnat0d580581995-07-20 02:43:20 -0500506
Guy Schalnat0d580581995-07-20 02:43:20 -0500507 for (ig = 0; ig < num_green; ig++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600508 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500509 /* int dg = abs(ig - g); */
510 int dg = ((ig > g) ? ig - g : g - ig);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500511 int dt = dr + dg;
512 int dm = ((dr > dg) ? dr : dg);
513 int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
Guy Schalnat0d580581995-07-20 02:43:20 -0500514
Guy Schalnat0d580581995-07-20 02:43:20 -0500515 for (ib = 0; ib < num_blue; ib++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600516 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500517 int d_index = index_g | ib;
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500518 /* int db = abs(ib - b); */
519 int db = ((ib > b) ? ib - b : b - ib);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500520 int dmax = ((dm > db) ? dm : db);
521 int d = dmax + dt + db;
Guy Schalnat0d580581995-07-20 02:43:20 -0500522
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600523 if (d < (int)distance[d_index])
Guy Schalnat0d580581995-07-20 02:43:20 -0500524 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500525 distance[d_index] = (png_byte)d;
526 png_ptr->palette_lookup[d_index] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500527 }
528 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500529 }
530 }
531 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500532
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600533 png_free(png_ptr, distance);
Guy Schalnat0d580581995-07-20 02:43:20 -0500534 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500535}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500536#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500537
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600538#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600539/* Transform the image from the file_gamma to the screen_gamma. We
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600540 * only do transformations on images where the file_gamma and screen_gamma
541 * are not close reciprocals, otherwise it slows things down slightly, and
542 * also needlessly introduces small errors.
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600543 *
544 * We will turn off gamma transformation later if no semitransparent entries
545 * are present in the tRNS array for palette images. We can't do it here
546 * because we don't necessarily have the tRNS chunk yet.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600547 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500548void PNGAPI
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600549png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -0500550{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500551 png_debug(1, "in png_set_gamma");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500552
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500553 if (png_ptr == NULL)
554 return;
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500555
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600556 if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) ||
557 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) ||
558 (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
559 png_ptr->transformations |= PNG_GAMMA;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500560 png_ptr->gamma = (float)file_gamma;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600561 png_ptr->screen_gamma = (float)scrn_gamma;
Guy Schalnat0d580581995-07-20 02:43:20 -0500562}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500563#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500564
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500565#ifdef PNG_READ_EXPAND_SUPPORTED
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -0500566/* Expand paletted images to RGB, expand grayscale images of
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500567 * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600568 * to alpha channels.
569 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500570void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600571png_set_expand(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500572{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500573 png_debug(1, "in png_set_expand");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500574
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500575 if (png_ptr == NULL)
576 return;
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500577
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600578 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500579 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -0500580}
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500581
582/* GRR 19990627: the following three functions currently are identical
583 * to png_set_expand(). However, it is entirely reasonable that someone
584 * might wish to expand an indexed image to RGB but *not* expand a single,
585 * fully transparent palette entry to a full alpha channel--perhaps instead
586 * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
587 * the transparent color with a particular RGB value, or drop tRNS entirely.
588 * IOW, a future version of the library may make the transformations flag
589 * a bit more fine-grained, with separate bits for each of these three
590 * functions.
591 *
592 * More to the point, these functions make it obvious what libpng will be
593 * doing, whereas "expand" can (and does) mean any number of things.
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600594 *
Glenn Randers-Pehrson17ca3402009-11-09 06:51:16 -0600595 * GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified
596 * to expand only the sample depth but not to expand the tRNS to alpha
597 * and its name was changed to png_set_expand_gray_1_2_4_to_8().
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500598 */
599
600/* Expand paletted images to RGB. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500601void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500602png_set_palette_to_rgb(png_structp png_ptr)
603{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500604 png_debug(1, "in png_set_palette_to_rgb");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500605
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500606 if (png_ptr == NULL)
607 return;
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500608
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600609 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500610 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500611}
612
613/* Expand grayscale images of less than 8-bit depth to 8 bits. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500614void PNGAPI
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600615png_set_expand_gray_1_2_4_to_8(png_structp png_ptr)
616{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500617 png_debug(1, "in png_set_expand_gray_1_2_4_to_8");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500618
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500619 if (png_ptr == NULL)
620 return;
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500621
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500622 png_ptr->transformations |= PNG_EXPAND;
623 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600624}
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500625
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500626
627
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500628/* Expand tRNS chunks to alpha channels. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500629void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500630png_set_tRNS_to_alpha(png_structp png_ptr)
631{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500632 png_debug(1, "in png_set_tRNS_to_alpha");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500633
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600634 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500635 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500636}
637#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500638
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500639#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500640void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600641png_set_gray_to_rgb(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500642{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500643 png_debug(1, "in png_set_gray_to_rgb");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500644
Guy Schalnat0d580581995-07-20 02:43:20 -0500645 png_ptr->transformations |= PNG_GRAY_TO_RGB;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500646 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -0500647}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500648#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500649
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500650#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
651#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600652/* Convert a RGB image to a grayscale of the same width. This allows us,
653 * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600654 */
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600655
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500656void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500657png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red,
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600658 double green)
659{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500660 int red_fixed = (int)((float)red*100000.0 + 0.5);
661 int green_fixed = (int)((float)green*100000.0 + 0.5);
662 if (png_ptr == NULL)
663 return;
664 png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed);
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600665}
666#endif
667
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500668void PNGAPI
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600669png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
670 png_fixed_point red, png_fixed_point green)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600671{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500672 png_debug(1, "in png_set_rgb_to_gray");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500673
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500674 if (png_ptr == NULL)
675 return;
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500676
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600677 switch(error_action)
678 {
679 case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY;
680 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500681
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600682 case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
683 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500684
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600685 case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
686 }
687 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500688#ifdef PNG_READ_EXPAND_SUPPORTED
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600689 png_ptr->transformations |= PNG_EXPAND;
690#else
691 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500692 png_warning(png_ptr,
693 "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED");
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600694 png_ptr->transformations &= ~PNG_RGB_TO_GRAY;
695 }
696#endif
697 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600698 png_uint_16 red_int, green_int;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500699 if (red < 0 || green < 0)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600700 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600701 red_int = 6968; /* .212671 * 32768 + .5 */
702 green_int = 23434; /* .715160 * 32768 + .5 */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600703 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500704 else if (red + green < 100000L)
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600705 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500706 red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
707 green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600708 }
709 else
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600710 {
711 png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600712 red_int = 6968;
713 green_int = 23434;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600714 }
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600715 png_ptr->rgb_to_gray_red_coeff = red_int;
716 png_ptr->rgb_to_gray_green_coeff = green_int;
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600717 png_ptr->rgb_to_gray_blue_coeff =
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500718 (png_uint_16)(32768 - red_int - green_int);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600719 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600720}
721#endif
722
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500723#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
Glenn Randers-Pehrson33188ac2009-06-16 14:12:35 -0500724 defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500725void PNGAPI
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600726png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
727 read_user_transform_fn)
728{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500729 png_debug(1, "in png_set_read_user_transform_fn");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500730
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500731 if (png_ptr == NULL)
732 return;
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500733
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500734#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600735 png_ptr->transformations |= PNG_USER_TRANSFORM;
736 png_ptr->read_user_transform_fn = read_user_transform_fn;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500737#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600738}
739#endif
740
Andreas Dilger47a0c421997-05-16 02:46:07 -0500741/* Initialize everything needed for the read. This includes modifying
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600742 * the palette.
743 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500744void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -0600745png_init_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500746{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500747 png_debug(1, "in png_init_read_transformations");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500748
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500749 {
750#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
751 || defined(PNG_READ_GAMMA_SUPPORTED)
752 int color_type = png_ptr->color_type;
753#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500754
Guy Schalnate5a37791996-06-05 15:50:50 -0500755#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500756
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500757#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500758 /* Detect gray background and attempt to enable optimization
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500759 * for gray --> RGB case
760 *
761 * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500762 * RGB_ALPHA (in which case need_expand is superfluous anyway), the
763 * background color might actually be gray yet not be flagged as such.
764 * This is not a problem for the current code, which uses
765 * PNG_BACKGROUND_IS_GRAY only to decide when to do the
766 * png_do_gray_to_rgb() transformation.
767 */
768 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
769 !(color_type & PNG_COLOR_MASK_COLOR))
770 {
771 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
772 } else if ((png_ptr->transformations & PNG_BACKGROUND) &&
773 !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
774 (png_ptr->transformations & PNG_GRAY_TO_RGB) &&
775 png_ptr->background.red == png_ptr->background.green &&
776 png_ptr->background.red == png_ptr->background.blue)
777 {
778 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
779 png_ptr->background.gray = png_ptr->background.red;
780 }
781#endif
782
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600783 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
784 (png_ptr->transformations & PNG_EXPAND))
Guy Schalnat0d580581995-07-20 02:43:20 -0500785 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500786 if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
Guy Schalnat0d580581995-07-20 02:43:20 -0500787 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500788 /* Expand background and tRNS chunks */
Guy Schalnat0d580581995-07-20 02:43:20 -0500789 switch (png_ptr->bit_depth)
790 {
791 case 1:
Guy Schalnate5a37791996-06-05 15:50:50 -0500792 png_ptr->background.gray *= (png_uint_16)0xff;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600793 png_ptr->background.red = png_ptr->background.green
794 = png_ptr->background.blue = png_ptr->background.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600795 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
796 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -0500797 png_ptr->trans_color.gray *= (png_uint_16)0xff;
798 png_ptr->trans_color.red = png_ptr->trans_color.green
799 = png_ptr->trans_color.blue = png_ptr->trans_color.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600800 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500801 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500802
Guy Schalnat0d580581995-07-20 02:43:20 -0500803 case 2:
Guy Schalnate5a37791996-06-05 15:50:50 -0500804 png_ptr->background.gray *= (png_uint_16)0x55;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600805 png_ptr->background.red = png_ptr->background.green
806 = png_ptr->background.blue = png_ptr->background.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600807 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
808 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -0500809 png_ptr->trans_color.gray *= (png_uint_16)0x55;
810 png_ptr->trans_color.red = png_ptr->trans_color.green
811 = png_ptr->trans_color.blue = png_ptr->trans_color.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600812 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500813 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500814
Guy Schalnat0d580581995-07-20 02:43:20 -0500815 case 4:
Guy Schalnate5a37791996-06-05 15:50:50 -0500816 png_ptr->background.gray *= (png_uint_16)0x11;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600817 png_ptr->background.red = png_ptr->background.green
818 = png_ptr->background.blue = png_ptr->background.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600819 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
820 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -0500821 png_ptr->trans_color.gray *= (png_uint_16)0x11;
822 png_ptr->trans_color.red = png_ptr->trans_color.green
823 = png_ptr->trans_color.blue = png_ptr->trans_color.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600824 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500825 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500826
Guy Schalnate5a37791996-06-05 15:50:50 -0500827 case 8:
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500828
Guy Schalnate5a37791996-06-05 15:50:50 -0500829 case 16:
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600830 png_ptr->background.red = png_ptr->background.green
831 = png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500832 break;
833 }
834 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500835 else if (color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -0500836 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500837 png_ptr->background.red =
Guy Schalnat0d580581995-07-20 02:43:20 -0500838 png_ptr->palette[png_ptr->background.index].red;
839 png_ptr->background.green =
840 png_ptr->palette[png_ptr->background.index].green;
Guy Schalnate5a37791996-06-05 15:50:50 -0500841 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -0500842 png_ptr->palette[png_ptr->background.index].blue;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600843
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500844#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600845 if (png_ptr->transformations & PNG_INVERT_ALPHA)
846 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500847#ifdef PNG_READ_EXPAND_SUPPORTED
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600848 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600849#endif
850 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500851 /* Invert the alpha channel (in tRNS) unless the pixels are
852 * going to be expanded, in which case leave it for later
853 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500854 int i, istop;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500855 istop=(int)png_ptr->num_trans;
856 for (i=0; i<istop; i++)
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -0500857 png_ptr->trans_alpha[i] = (png_byte)(255 - png_ptr->trans_alpha[i]);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600858 }
859 }
860#endif
861
Guy Schalnat0d580581995-07-20 02:43:20 -0500862 }
863 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500864#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500865
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500866#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500867 png_ptr->background_1 = png_ptr->background;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500868#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600869#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600870
871 if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0)
872 && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0)
873 < PNG_GAMMA_THRESHOLD))
874 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500875 int i, k;
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600876 k=0;
877 for (i=0; i<png_ptr->num_trans; i++)
878 {
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -0500879 if (png_ptr->trans_alpha[i] != 0 && png_ptr->trans_alpha[i] != 0xff)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500880 k=1; /* Partial transparency is present */
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600881 }
882 if (k == 0)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500883 png_ptr->transformations &= ~PNG_GAMMA;
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600884 }
885
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600886 if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) &&
887 png_ptr->gamma != 0.0)
Guy Schalnat0d580581995-07-20 02:43:20 -0500888 {
Glenn Randers-Pehrsonffa89242009-12-13 08:14:40 -0600889 if (png_ptr->transformations & PNG_16_TO_8)
890 png_build_gamma_table(png_ptr, 8);
891 else
892 png_build_gamma_table(png_ptr, png_ptr->bit_depth);
893
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500894#ifdef PNG_READ_BACKGROUND_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -0500895 if (png_ptr->transformations & PNG_BACKGROUND)
Guy Schalnat0d580581995-07-20 02:43:20 -0500896 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500897 if (color_type == PNG_COLOR_TYPE_PALETTE)
898 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500899 /* Could skip if no transparency */
Guy Schalnate5a37791996-06-05 15:50:50 -0500900 png_color back, back_1;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500901 png_colorp palette = png_ptr->palette;
902 int num_palette = png_ptr->num_palette;
903 int i;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500904 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
905 {
906 back.red = png_ptr->gamma_table[png_ptr->background.red];
907 back.green = png_ptr->gamma_table[png_ptr->background.green];
908 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
Guy Schalnate5a37791996-06-05 15:50:50 -0500909
Andreas Dilger47a0c421997-05-16 02:46:07 -0500910 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
911 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
912 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
913 }
914 else
915 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600916 double g, gs;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500917
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600918 switch (png_ptr->background_gamma_type)
Glenn Randers-Pehrson4922b1b1998-03-08 22:55:17 -0600919 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600920 case PNG_BACKGROUND_GAMMA_SCREEN:
921 g = (png_ptr->screen_gamma);
922 gs = 1.0;
923 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500924
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600925 case PNG_BACKGROUND_GAMMA_FILE:
926 g = 1.0 / (png_ptr->gamma);
927 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
928 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500929
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600930 case PNG_BACKGROUND_GAMMA_UNIQUE:
931 g = 1.0 / (png_ptr->background_gamma);
932 gs = 1.0 / (png_ptr->background_gamma *
933 png_ptr->screen_gamma);
934 break;
935 default:
936 g = 1.0; /* back_1 */
937 gs = 1.0; /* back */
938 }
939
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -0600940 if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD)
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600941 {
942 back.red = (png_byte)png_ptr->background.red;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500943 back.green = (png_byte)png_ptr->background.green;
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600944 back.blue = (png_byte)png_ptr->background.blue;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500945 }
946 else
947 {
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600948 back.red = (png_byte)(pow(
Glenn Randers-Pehrson768429b2009-11-24 07:26:06 -0600949 (double)png_ptr->background.red/255.0, gs) * 255.0 + .5);
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600950 back.green = (png_byte)(pow(
Glenn Randers-Pehrson768429b2009-11-24 07:26:06 -0600951 (double)png_ptr->background.green/255.0, gs) * 255.0 + .5);
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600952 back.blue = (png_byte)(pow(
Glenn Randers-Pehrson768429b2009-11-24 07:26:06 -0600953 (double)png_ptr->background.blue/255.0, gs) * 255.0 + .5);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500954 }
955
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600956 back_1.red = (png_byte)(pow(
Glenn Randers-Pehrson768429b2009-11-24 07:26:06 -0600957 (double)png_ptr->background.red/255.0, g) * 255.0 + .5);
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600958 back_1.green = (png_byte)(pow(
Glenn Randers-Pehrson768429b2009-11-24 07:26:06 -0600959 (double)png_ptr->background.green/255.0, g) * 255.0 + .5);
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600960 back_1.blue = (png_byte)(pow(
Glenn Randers-Pehrson768429b2009-11-24 07:26:06 -0600961 (double)png_ptr->background.blue/255.0, g) * 255.0 + .5);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500962 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500963 for (i = 0; i < num_palette; i++)
964 {
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -0500965 if (i < (int)png_ptr->num_trans && png_ptr->trans_alpha[i] != 0xff)
Guy Schalnate5a37791996-06-05 15:50:50 -0500966 {
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -0500967 if (png_ptr->trans_alpha[i] == 0)
Guy Schalnate5a37791996-06-05 15:50:50 -0500968 {
969 palette[i] = back;
970 }
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -0500971 else /* if (png_ptr->trans_alpha[i] != 0xff) */
Guy Schalnate5a37791996-06-05 15:50:50 -0500972 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500973 png_byte v, w;
Guy Schalnate5a37791996-06-05 15:50:50 -0500974
975 v = png_ptr->gamma_to_1[palette[i].red];
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -0500976 png_composite(w, v, png_ptr->trans_alpha[i], back_1.red);
Guy Schalnate5a37791996-06-05 15:50:50 -0500977 palette[i].red = png_ptr->gamma_from_1[w];
978
979 v = png_ptr->gamma_to_1[palette[i].green];
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -0500980 png_composite(w, v, png_ptr->trans_alpha[i], back_1.green);
Guy Schalnate5a37791996-06-05 15:50:50 -0500981 palette[i].green = png_ptr->gamma_from_1[w];
982
983 v = png_ptr->gamma_to_1[palette[i].blue];
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -0500984 png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue);
Guy Schalnate5a37791996-06-05 15:50:50 -0500985 palette[i].blue = png_ptr->gamma_from_1[w];
986 }
987 }
988 else
989 {
990 palette[i].red = png_ptr->gamma_table[palette[i].red];
991 palette[i].green = png_ptr->gamma_table[palette[i].green];
992 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
993 }
994 }
Glenn Randers-Pehrson72cbc6e2009-09-20 07:28:43 -0500995 /* Prevent the transformations being done again, and make sure
996 * that the now spurious alpha channel is stripped - the code
997 * has just reduced background composition and gamma correction
998 * to a simple alpha channel strip.
999 */
1000 png_ptr->transformations &= ~PNG_BACKGROUND;
1001 png_ptr->transformations &= ~PNG_GAMMA;
1002 png_ptr->transformations |= PNG_STRIP_ALPHA;
Guy Schalnate5a37791996-06-05 15:50:50 -05001003 }
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001004 /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001005 else
1006 /* color_type != PNG_COLOR_TYPE_PALETTE */
Guy Schalnat0d580581995-07-20 02:43:20 -05001007 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001008 double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
1009 double g = 1.0;
1010 double gs = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05001011
1012 switch (png_ptr->background_gamma_type)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001013 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001014 case PNG_BACKGROUND_GAMMA_SCREEN:
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001015 g = (png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05001016 gs = 1.0;
1017 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001018
Guy Schalnat0d580581995-07-20 02:43:20 -05001019 case PNG_BACKGROUND_GAMMA_FILE:
1020 g = 1.0 / (png_ptr->gamma);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001021 gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05001022 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001023
Guy Schalnat0d580581995-07-20 02:43:20 -05001024 case PNG_BACKGROUND_GAMMA_UNIQUE:
1025 g = 1.0 / (png_ptr->background_gamma);
1026 gs = 1.0 / (png_ptr->background_gamma *
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001027 png_ptr->screen_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05001028 break;
1029 }
1030
Glenn Randers-Pehrson377657d2002-03-08 01:31:27 -06001031 png_ptr->background_1.gray = (png_uint_16)(pow(
1032 (double)png_ptr->background.gray / m, g) * m + .5);
1033 png_ptr->background.gray = (png_uint_16)(pow(
1034 (double)png_ptr->background.gray / m, gs) * m + .5);
1035
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06001036 if ((png_ptr->background.red != png_ptr->background.green) ||
1037 (png_ptr->background.red != png_ptr->background.blue) ||
1038 (png_ptr->background.red != png_ptr->background.gray))
Guy Schalnat0d580581995-07-20 02:43:20 -05001039 {
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06001040 /* RGB or RGBA with color background */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001041 png_ptr->background_1.red = (png_uint_16)(pow(
Guy Schalnat0d580581995-07-20 02:43:20 -05001042 (double)png_ptr->background.red / m, g) * m + .5);
1043 png_ptr->background_1.green = (png_uint_16)(pow(
1044 (double)png_ptr->background.green / m, g) * m + .5);
1045 png_ptr->background_1.blue = (png_uint_16)(pow(
1046 (double)png_ptr->background.blue / m, g) * m + .5);
1047 png_ptr->background.red = (png_uint_16)(pow(
1048 (double)png_ptr->background.red / m, gs) * m + .5);
1049 png_ptr->background.green = (png_uint_16)(pow(
1050 (double)png_ptr->background.green / m, gs) * m + .5);
1051 png_ptr->background.blue = (png_uint_16)(pow(
1052 (double)png_ptr->background.blue / m, gs) * m + .5);
1053 }
1054 else
1055 {
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06001056 /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */
1057 png_ptr->background_1.red = png_ptr->background_1.green
1058 = png_ptr->background_1.blue = png_ptr->background_1.gray;
1059 png_ptr->background.red = png_ptr->background.green
1060 = png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05001061 }
1062 }
1063 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001064 else
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001065 /* Transformation does not include PNG_BACKGROUND */
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001066#endif /* PNG_READ_BACKGROUND_SUPPORTED */
Guy Schalnate5a37791996-06-05 15:50:50 -05001067 if (color_type == PNG_COLOR_TYPE_PALETTE)
1068 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001069 png_colorp palette = png_ptr->palette;
1070 int num_palette = png_ptr->num_palette;
1071 int i;
Guy Schalnate5a37791996-06-05 15:50:50 -05001072
1073 for (i = 0; i < num_palette; i++)
1074 {
1075 palette[i].red = png_ptr->gamma_table[palette[i].red];
1076 palette[i].green = png_ptr->gamma_table[palette[i].green];
1077 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
1078 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001079
Glenn Randers-Pehrson72cbc6e2009-09-20 07:28:43 -05001080 /* Done the gamma correction. */
1081 png_ptr->transformations &= ~PNG_GAMMA;
Guy Schalnate5a37791996-06-05 15:50:50 -05001082 }
1083 }
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001084#ifdef PNG_READ_BACKGROUND_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -05001085 else
1086#endif
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001087#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001088#ifdef PNG_READ_BACKGROUND_SUPPORTED
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001089 /* No GAMMA transformation */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001090 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1091 (color_type == PNG_COLOR_TYPE_PALETTE))
Guy Schalnate5a37791996-06-05 15:50:50 -05001092 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001093 int i;
1094 int istop = (int)png_ptr->num_trans;
Guy Schalnate5a37791996-06-05 15:50:50 -05001095 png_color back;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001096 png_colorp palette = png_ptr->palette;
Guy Schalnate5a37791996-06-05 15:50:50 -05001097
Guy Schalnate5a37791996-06-05 15:50:50 -05001098 back.red = (png_byte)png_ptr->background.red;
1099 back.green = (png_byte)png_ptr->background.green;
1100 back.blue = (png_byte)png_ptr->background.blue;
1101
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001102 for (i = 0; i < istop; i++)
Guy Schalnate5a37791996-06-05 15:50:50 -05001103 {
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -05001104 if (png_ptr->trans_alpha[i] == 0)
Guy Schalnate5a37791996-06-05 15:50:50 -05001105 {
1106 palette[i] = back;
1107 }
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -05001108 else if (png_ptr->trans_alpha[i] != 0xff)
Guy Schalnate5a37791996-06-05 15:50:50 -05001109 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001110 /* The png_composite() macro is defined in png.h */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001111 png_composite(palette[i].red, palette[i].red,
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -05001112 png_ptr->trans_alpha[i], back.red);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001113 png_composite(palette[i].green, palette[i].green,
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -05001114 png_ptr->trans_alpha[i], back.green);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001115 png_composite(palette[i].blue, palette[i].blue,
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -05001116 png_ptr->trans_alpha[i], back.blue);
Guy Schalnate5a37791996-06-05 15:50:50 -05001117 }
1118 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001119
1120 /* Handled alpha, still need to strip the channel. */
1121 png_ptr->transformations &= ~PNG_BACKGROUND;
1122 png_ptr->transformations |= PNG_STRIP_ALPHA;
Guy Schalnat0d580581995-07-20 02:43:20 -05001123 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001124#endif /* PNG_READ_BACKGROUND_SUPPORTED */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001125
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001126#ifdef PNG_READ_SHIFT_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001127 if ((png_ptr->transformations & PNG_SHIFT) &&
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001128 (color_type == PNG_COLOR_TYPE_PALETTE))
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001129 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001130 png_uint_16 i;
1131 png_uint_16 istop = png_ptr->num_palette;
1132 int sr = 8 - png_ptr->sig_bit.red;
1133 int sg = 8 - png_ptr->sig_bit.green;
1134 int sb = 8 - png_ptr->sig_bit.blue;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001135
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001136 if (sr < 0 || sr > 8)
1137 sr = 0;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001138 if (sg < 0 || sg > 8)
1139 sg = 0;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001140 if (sb < 0 || sb > 8)
1141 sb = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001142 for (i = 0; i < istop; i++)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001143 {
1144 png_ptr->palette[i].red >>= sr;
1145 png_ptr->palette[i].green >>= sg;
1146 png_ptr->palette[i].blue >>= sb;
1147 }
1148 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001149#endif /* PNG_READ_SHIFT_SUPPORTED */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001150 }
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001151#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \
1152 && !defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001153 if (png_ptr)
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001154 return;
1155#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001156}
1157
Andreas Dilger47a0c421997-05-16 02:46:07 -05001158/* Modify the info structure to reflect the transformations. The
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001159 * info should be updated so a PNG file could be written with it,
1160 * assuming the transformations result in valid PNG data.
1161 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001162void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001163png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001164{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001165 png_debug(1, "in png_read_transform_info");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05001166
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001167#ifdef 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
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001194#ifdef PNG_READ_BACKGROUND_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001195 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-Pehrsone26c0952009-09-23 11:22:08 -05001203#ifdef PNG_READ_GAMMA_SUPPORTED
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001204 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
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001215#ifdef 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-Pehrsone26c0952009-09-23 11:22:08 -05001220#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Glenn Randers-Pehrsonddfebd32006-02-22 09:19:25 -06001221 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
1222 info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
1223#endif
1224
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001225#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
Glenn Randers-Pehrsonddfebd32006-02-22 09:19:25 -06001226 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1227 info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
1228#endif
1229
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001230#ifdef PNG_READ_DITHER_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001231 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
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001242#ifdef 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-Pehrsone26c0952009-09-23 11:22:08 -05001254#ifdef 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
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001262#ifdef PNG_READ_FILLER_SUPPORTED
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001263 /* 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-Pehrsonb2aca212009-09-23 11:32:37 -05001291#ifndef 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");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05001305
Andreas Dilger47a0c421997-05-16 02:46:07 -05001306 if (png_ptr->row_buf == NULL)
1307 {
Glenn Randers-Pehrsonef9c0e92009-11-02 15:42:31 -06001308#ifdef PNG_STDIO_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05001309 char msg[50];
1310
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001311 png_snprintf2(msg, 50,
1312 "NULL row buffer for row %ld, pass %d", (long)png_ptr->row_number,
1313 png_ptr->pass);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001314 png_error(png_ptr, msg);
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001315#else
1316 png_error(png_ptr, "NULL row buffer");
1317#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001318 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001319#ifdef PNG_WARN_UNINITIALIZED_ROW
1320 if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
1321 /* Application has failed to call either png_read_start_image()
1322 * or png_read_update_info() after setting transforms that expand
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001323 * pixels. This check added to libpng-1.2.19
1324 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001325#if (PNG_WARN_UNINITIALIZED_ROW==1)
1326 png_error(png_ptr, "Uninitialized row");
1327#else
1328 png_warning(png_ptr, "Uninitialized row");
1329#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001330#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001331
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001332#ifdef PNG_READ_EXPAND_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05001333 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05001334 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001335 if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
1336 {
1337 png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -05001338 png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001339 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001340 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001341 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001342 if (png_ptr->num_trans &&
1343 (png_ptr->transformations & PNG_EXPAND_tRNS))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001344 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001345 &(png_ptr->trans_color));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001346 else
1347 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1348 NULL);
1349 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001350 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001351#endif
1352
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001353#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001354 if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001355 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001356 PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001357#endif
1358
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001359#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001360 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1361 {
1362 int rgb_error =
1363 png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001364 if (rgb_error)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001365 {
1366 png_ptr->rgb_to_gray_status=1;
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06001367 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001368 PNG_RGB_TO_GRAY_WARN)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001369 png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001370 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
1371 PNG_RGB_TO_GRAY_ERR)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001372 png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1373 }
1374 }
1375#endif
1376
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001377/* From Andreas Dilger e-mail to png-implement, 26 March 1998:
Glenn Randers-Pehrsond60c8862009-06-15 21:56:14 -05001378 *
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001379 * In most cases, the "simple transparency" should be done prior to doing
1380 * gray-to-RGB, or you will have to test 3x as many bytes to check if a
1381 * pixel is transparent. You would also need to make sure that the
1382 * transparency information is upgraded to RGB.
Glenn Randers-Pehrsond60c8862009-06-15 21:56:14 -05001383 *
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001384 * To summarize, the current flow is:
1385 * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
1386 * with background "in place" if transparent,
1387 * convert to RGB if necessary
1388 * - Gray + alpha -> composite with gray background and remove alpha bytes,
1389 * convert to RGB if necessary
1390 *
1391 * To support RGB backgrounds for gray images we need:
1392 * - Gray + simple transparency -> convert to RGB + simple transparency,
1393 * compare 3 or 6 bytes and composite with
1394 * background "in place" if transparent
1395 * (3x compare/pixel compared to doing
1396 * composite with gray bkgrnd)
1397 * - Gray + alpha -> convert to RGB + alpha, composite with background and
1398 * remove alpha bytes (3x float
1399 * operations/pixel compared with composite
1400 * on gray background)
1401 *
1402 * Greg's change will do this. The reason it wasn't done before is for
1403 * performance, as this increases the per-pixel operations. If we would check
1404 * in advance if the background was gray or RGB, and position the gray-to-RGB
1405 * transform appropriately, then it would save a lot of work/time.
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001406 */
1407
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001408#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001409 /* If gray -> RGB, do so now only if background is non-gray; else do later
1410 * for performance reasons
1411 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001412 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001413 !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001414 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
1415#endif
1416
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001417#ifdef PNG_READ_BACKGROUND_SUPPORTED
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001418 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1419 ((png_ptr->num_trans != 0 ) ||
1420 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
Guy Schalnat0d580581995-07-20 02:43:20 -05001421 png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001422 &(png_ptr->trans_color), &(png_ptr->background)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001423#ifdef PNG_READ_GAMMA_SUPPORTED
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001424 , &(png_ptr->background_1),
Guy Schalnat0d580581995-07-20 02:43:20 -05001425 png_ptr->gamma_table, png_ptr->gamma_from_1,
1426 png_ptr->gamma_to_1, png_ptr->gamma_16_table,
1427 png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001428 png_ptr->gamma_shift
1429#endif
1430);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001431#endif
1432
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001433#ifdef PNG_READ_GAMMA_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001434 if ((png_ptr->transformations & PNG_GAMMA) &&
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001435#ifdef PNG_READ_BACKGROUND_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001436 !((png_ptr->transformations & PNG_BACKGROUND) &&
1437 ((png_ptr->num_trans != 0) ||
1438 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001439#endif
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001440 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
Guy Schalnat0d580581995-07-20 02:43:20 -05001441 png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001442 png_ptr->gamma_table, png_ptr->gamma_16_table,
1443 png_ptr->gamma_shift);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001444#endif
1445
Glenn Randers-Pehrson7a59e1e2009-12-11 07:57:36 -06001446#ifdef PNG_READ_16_TO_8_SUPPORTED
1447 if (png_ptr->transformations & PNG_16_TO_8)
1448 png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
1449#endif
1450
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001451#ifdef PNG_READ_DITHER_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05001452 if (png_ptr->transformations & PNG_DITHER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001453 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001454 png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
1455 png_ptr->palette_lookup, png_ptr->dither_index);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001456 if (png_ptr->row_info.rowbytes == (png_uint_32)0)
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001457 png_error(png_ptr, "png_do_dither returned rowbytes=0");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001458 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001459#endif
1460
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001461#ifdef PNG_READ_INVERT_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05001462 if (png_ptr->transformations & PNG_INVERT_MONO)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001463 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001464#endif
1465
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001466#ifdef PNG_READ_SHIFT_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05001467 if (png_ptr->transformations & PNG_SHIFT)
1468 png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
1469 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001470#endif
1471
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001472#ifdef PNG_READ_PACK_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05001473 if (png_ptr->transformations & PNG_PACK)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001474 png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001475#endif
1476
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001477#ifdef PNG_READ_BGR_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05001478 if (png_ptr->transformations & PNG_BGR)
1479 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001480#endif
1481
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001482#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05001483 if (png_ptr->transformations & PNG_PACKSWAP)
1484 png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1485#endif
1486
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001487#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001488 /* If gray -> RGB, do so now only if we did not do so above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001489 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
1490 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05001491 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001492#endif
1493
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001494#ifdef PNG_READ_FILLER_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001495 if (png_ptr->transformations & PNG_FILLER)
1496 png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001497 (png_uint_32)png_ptr->filler, png_ptr->flags);
1498#endif
1499
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001500#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001501 if (png_ptr->transformations & PNG_INVERT_ALPHA)
1502 png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1503#endif
1504
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001505#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001506 if (png_ptr->transformations & PNG_SWAP_ALPHA)
1507 png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1508#endif
1509
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001510#ifdef PNG_READ_SWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05001511 if (png_ptr->transformations & PNG_SWAP_BYTES)
1512 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001513#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001514
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001515#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001516 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001517 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001518 if (png_ptr->read_user_transform_fn != NULL)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001519 (*(png_ptr->read_user_transform_fn)) /* User read transform function */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001520 (png_ptr, /* png_ptr */
1521 &(png_ptr->row_info), /* row_info: */
1522 /* png_uint_32 width; width of row */
1523 /* png_uint_32 rowbytes; number of bytes in row */
1524 /* png_byte color_type; color type of pixels */
1525 /* png_byte bit_depth; bit depth of samples */
1526 /* png_byte channels; number of channels (1-4) */
1527 /* png_byte pixel_depth; bits per pixel (depth*channels) */
1528 png_ptr->row_buf + 1); /* start of pixel data for row */
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001529#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001530 if (png_ptr->user_transform_depth)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001531 png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001532 if (png_ptr->user_transform_channels)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001533 png_ptr->row_info.channels = png_ptr->user_transform_channels;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001534#endif
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001535 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
1536 png_ptr->row_info.channels);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001537 png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
1538 png_ptr->row_info.width);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001539 }
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001540#endif
1541
Guy Schalnat0d580581995-07-20 02:43:20 -05001542}
1543
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001544#ifdef PNG_READ_PACK_SUPPORTED
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001545/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
1546 * without changing the actual values. Thus, if you had a row with
1547 * a bit depth of 1, you would end up with bytes that only contained
1548 * the numbers 0 or 1. If you would rather they contain 0 and 255, use
1549 * png_do_shift() after this.
1550 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001551void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001552png_do_unpack(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001553{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001554 png_debug(1, "in png_do_unpack");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05001555
Andreas Dilger47a0c421997-05-16 02:46:07 -05001556 if (row_info->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05001557 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001558 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001559 png_uint_32 row_width=row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001560
Guy Schalnat0d580581995-07-20 02:43:20 -05001561 switch (row_info->bit_depth)
1562 {
1563 case 1:
1564 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001565 png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
1566 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001567 png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001568 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001569 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001570 *dp = (png_byte)((*sp >> shift) & 0x01);
Guy Schalnat0d580581995-07-20 02:43:20 -05001571 if (shift == 7)
1572 {
1573 shift = 0;
1574 sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001575 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001576 else
1577 shift++;
1578
1579 dp--;
1580 }
1581 break;
1582 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001583
Guy Schalnat0d580581995-07-20 02:43:20 -05001584 case 2:
1585 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001586
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001587 png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
1588 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001589 png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001590 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001591 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001592 *dp = (png_byte)((*sp >> shift) & 0x03);
Guy Schalnat0d580581995-07-20 02:43:20 -05001593 if (shift == 6)
1594 {
1595 shift = 0;
1596 sp--;
1597 }
1598 else
1599 shift += 2;
1600
1601 dp--;
1602 }
1603 break;
1604 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001605
Guy Schalnat0d580581995-07-20 02:43:20 -05001606 case 4:
1607 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001608 png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
1609 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001610 png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001611 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001612 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001613 *dp = (png_byte)((*sp >> shift) & 0x0f);
Guy Schalnat0d580581995-07-20 02:43:20 -05001614 if (shift == 4)
1615 {
1616 shift = 0;
1617 sp--;
1618 }
1619 else
1620 shift = 4;
1621
1622 dp--;
1623 }
1624 break;
1625 }
1626 }
1627 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001628 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001629 row_info->rowbytes = row_width * row_info->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001630 }
1631}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001632#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001633
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001634#ifdef PNG_READ_SHIFT_SUPPORTED
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001635/* Reverse the effects of png_do_shift. This routine merely shifts the
1636 * pixels back to their significant bits values. Thus, if you have
1637 * a row of bit depth 8, but only 5 are significant, this will shift
1638 * the values back to 0 through 31.
1639 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001640void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001641png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
Guy Schalnat0d580581995-07-20 02:43:20 -05001642{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001643 png_debug(1, "in png_do_unshift");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05001644
Andreas Dilger47a0c421997-05-16 02:46:07 -05001645 if (
Andreas Dilger47a0c421997-05-16 02:46:07 -05001646 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001647 {
1648 int shift[4];
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001649 int channels = 0;
1650 int c;
1651 png_uint_16 value = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001652 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001653
Guy Schalnat0d580581995-07-20 02:43:20 -05001654 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
1655 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001656 shift[channels++] = row_info->bit_depth - sig_bits->red;
1657 shift[channels++] = row_info->bit_depth - sig_bits->green;
1658 shift[channels++] = row_info->bit_depth - sig_bits->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05001659 }
1660 else
1661 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001662 shift[channels++] = row_info->bit_depth - sig_bits->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05001663 }
1664 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
1665 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001666 shift[channels++] = row_info->bit_depth - sig_bits->alpha;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001667 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001668
Andreas Dilger47a0c421997-05-16 02:46:07 -05001669 for (c = 0; c < channels; c++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001670 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001671 if (shift[c] <= 0)
1672 shift[c] = 0;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001673 else
1674 value = 1;
1675 }
Guy Schalnat0f716451995-11-28 11:22:13 -06001676
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001677 if (!value)
1678 return;
Guy Schalnat0f716451995-11-28 11:22:13 -06001679
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001680 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05001681 {
1682 case 2:
1683 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001684 png_bytep bp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001685 png_uint_32 i;
1686 png_uint_32 istop = row_info->rowbytes;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001687
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001688 for (bp = row, i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001689 {
1690 *bp >>= 1;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001691 *bp++ &= 0x55;
Guy Schalnat0d580581995-07-20 02:43:20 -05001692 }
1693 break;
1694 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001695
Guy Schalnat0d580581995-07-20 02:43:20 -05001696 case 4:
1697 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001698 png_bytep bp = row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001699 png_uint_32 i;
1700 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001701 png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
1702 (png_byte)((int)0xf >> shift[0]));
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001703
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001704 for (i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001705 {
1706 *bp >>= shift[0];
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001707 *bp++ &= mask;
Guy Schalnat0d580581995-07-20 02:43:20 -05001708 }
1709 break;
1710 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001711
Guy Schalnat0d580581995-07-20 02:43:20 -05001712 case 8:
1713 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001714 png_bytep bp = row;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001715 png_uint_32 i;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001716 png_uint_32 istop = row_width * channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001717
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001718 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001719 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001720 *bp++ >>= shift[i%channels];
Guy Schalnat0d580581995-07-20 02:43:20 -05001721 }
1722 break;
1723 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001724
Guy Schalnat0d580581995-07-20 02:43:20 -05001725 case 16:
1726 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001727 png_bytep bp = row;
1728 png_uint_32 i;
1729 png_uint_32 istop = channels * row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001730
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001731 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001732 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001733 value = (png_uint_16)((*bp << 8) + *(bp + 1));
1734 value >>= shift[i%channels];
1735 *bp++ = (png_byte)(value >> 8);
1736 *bp++ = (png_byte)(value & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05001737 }
1738 break;
1739 }
1740 }
1741 }
1742}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001743#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001744
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001745#ifdef PNG_READ_16_TO_8_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001746/* Chop rows of bit depth 16 down to 8 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001747void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001748png_do_chop(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001749{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001750 png_debug(1, "in png_do_chop");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05001751
Andreas Dilger47a0c421997-05-16 02:46:07 -05001752 if (row_info->bit_depth == 16)
Guy Schalnat0d580581995-07-20 02:43:20 -05001753 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001754 png_bytep sp = row;
1755 png_bytep dp = row;
1756 png_uint_32 i;
1757 png_uint_32 istop = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001758
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001759 for (i = 0; i<istop; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001760 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001761#ifdef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001762 /* This does a more accurate scaling of the 16-bit color
1763 * value, rather than a simple low-byte truncation.
1764 *
1765 * What the ideal calculation should be:
1766 * *dp = (((((png_uint_32)(*sp) << 8) |
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001767 * (png_uint_32)(*(sp + 1))) * 255 + 127)
1768 * / (png_uint_32)65535L;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001769 *
1770 * GRR: no, I think this is what it really should be:
1771 * *dp = (((((png_uint_32)(*sp) << 8) |
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001772 * (png_uint_32)(*(sp + 1))) + 128L)
1773 * / (png_uint_32)257L;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001774 *
1775 * GRR: here's the exact calculation with shifts:
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001776 * temp = (((png_uint_32)(*sp) << 8) |
1777 * (png_uint_32)(*(sp + 1))) + 128L;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001778 * *dp = (temp - (temp >> 8)) >> 8;
1779 *
1780 * Approximate calculation with shift/add instead of multiply/divide:
1781 * *dp = ((((png_uint_32)(*sp) << 8) |
1782 * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
1783 *
1784 * What we actually do to avoid extra shifting and conversion:
1785 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001786
Andreas Dilger47a0c421997-05-16 02:46:07 -05001787 *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
1788#else
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001789 /* Simply discard the low order byte */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001790 *dp = *sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001791#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001792 }
1793 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001794 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001795 row_info->rowbytes = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001796 }
1797}
1798#endif
1799
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001800#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001801void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001802png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
1803{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001804 png_debug(1, "in png_do_read_swap_alpha");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05001805
Andreas Dilger47a0c421997-05-16 02:46:07 -05001806 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001807 png_uint_32 row_width = row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001808 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1809 {
1810 /* This converts from RGBA to ARGB */
1811 if (row_info->bit_depth == 8)
1812 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001813 png_bytep sp = row + row_info->rowbytes;
1814 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001815 png_byte save;
1816 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001817
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001818 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001819 {
1820 save = *(--sp);
1821 *(--dp) = *(--sp);
1822 *(--dp) = *(--sp);
1823 *(--dp) = *(--sp);
1824 *(--dp) = save;
1825 }
1826 }
1827 /* This converts from RRGGBBAA to AARRGGBB */
1828 else
1829 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001830 png_bytep sp = row + row_info->rowbytes;
1831 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001832 png_byte save[2];
1833 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001834
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001835 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001836 {
1837 save[0] = *(--sp);
1838 save[1] = *(--sp);
1839 *(--dp) = *(--sp);
1840 *(--dp) = *(--sp);
1841 *(--dp) = *(--sp);
1842 *(--dp) = *(--sp);
1843 *(--dp) = *(--sp);
1844 *(--dp) = *(--sp);
1845 *(--dp) = save[0];
1846 *(--dp) = save[1];
1847 }
1848 }
1849 }
1850 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1851 {
1852 /* This converts from GA to AG */
1853 if (row_info->bit_depth == 8)
1854 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001855 png_bytep sp = row + row_info->rowbytes;
1856 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001857 png_byte save;
1858 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001859
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001860 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001861 {
1862 save = *(--sp);
1863 *(--dp) = *(--sp);
1864 *(--dp) = save;
1865 }
1866 }
1867 /* This converts from GGAA to AAGG */
1868 else
1869 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001870 png_bytep sp = row + row_info->rowbytes;
1871 png_bytep dp = sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001872 png_byte save[2];
1873 png_uint_32 i;
1874
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001875 for (i = 0; i < row_width; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001876 {
1877 save[0] = *(--sp);
1878 save[1] = *(--sp);
1879 *(--dp) = *(--sp);
1880 *(--dp) = *(--sp);
1881 *(--dp) = save[0];
1882 *(--dp) = save[1];
1883 }
1884 }
1885 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001886 }
1887}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001888#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001889
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001890#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001891void /* PRIVATE */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001892png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
1893{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001894 png_debug(1, "in png_do_read_invert_alpha");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05001895
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-Pehrsone26c0952009-09-23 11:22:08 -05001986#ifdef PNG_READ_FILLER_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05001987/* Add filler channel if we have RGB color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001988void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001989png_do_read_filler(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001990 png_uint_32 filler, png_uint_32 flags)
Guy Schalnat0d580581995-07-20 02:43:20 -05001991{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001992 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001993 png_uint_32 row_width = row_info->width;
1994
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001995 png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001996 png_byte lo_filler = (png_byte)(filler & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001997
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001998 png_debug(1, "in png_do_read_filler");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05001999
Andreas Dilger47a0c421997-05-16 02:46:07 -05002000 if (
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002001 row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05002002 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002003 if (row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002004 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002005 /* This changes the data from G to GX */
2006 if (flags & PNG_FLAG_FILLER_AFTER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002007 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002008 png_bytep sp = row + (png_size_t)row_width;
2009 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002010 for (i = 1; i < row_width; i++)
2011 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002012 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002013 *(--dp) = *(--sp);
2014 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002015 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002016 row_info->channels = 2;
2017 row_info->pixel_depth = 16;
2018 row_info->rowbytes = row_width * 2;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002019 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002020 /* This changes the data from G to XG */
2021 else
2022 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002023 png_bytep sp = row + (png_size_t)row_width;
2024 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002025 for (i = 0; i < row_width; i++)
2026 {
2027 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002028 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002029 }
2030 row_info->channels = 2;
2031 row_info->pixel_depth = 16;
2032 row_info->rowbytes = row_width * 2;
2033 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002034 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002035 else if (row_info->bit_depth == 16)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002036 {
2037 /* This changes the data from GG to GGXX */
2038 if (flags & PNG_FLAG_FILLER_AFTER)
2039 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002040 png_bytep sp = row + (png_size_t)row_width * 2;
2041 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002042 for (i = 1; i < row_width; i++)
2043 {
2044 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002045 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002046 *(--dp) = *(--sp);
2047 *(--dp) = *(--sp);
2048 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002049 *(--dp) = hi_filler;
2050 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002051 row_info->channels = 2;
2052 row_info->pixel_depth = 32;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002053 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002054 }
2055 /* This changes the data from GG to XXGG */
2056 else
2057 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002058 png_bytep sp = row + (png_size_t)row_width * 2;
2059 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002060 for (i = 0; i < row_width; i++)
2061 {
2062 *(--dp) = *(--sp);
2063 *(--dp) = *(--sp);
2064 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002065 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002066 }
2067 row_info->channels = 2;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002068 row_info->pixel_depth = 32;
2069 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002070 }
2071 }
2072 } /* COLOR_TYPE == GRAY */
2073 else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2074 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002075 if (row_info->bit_depth == 8)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002076 {
2077 /* This changes the data from RGB to RGBX */
2078 if (flags & PNG_FLAG_FILLER_AFTER)
2079 {
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002080 png_bytep sp = row + (png_size_t)row_width * 3;
2081 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002082 for (i = 1; i < row_width; i++)
2083 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002084 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002085 *(--dp) = *(--sp);
2086 *(--dp) = *(--sp);
2087 *(--dp) = *(--sp);
2088 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002089 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002090 row_info->channels = 4;
2091 row_info->pixel_depth = 32;
2092 row_info->rowbytes = row_width * 4;
2093 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002094 /* This changes the data from RGB to XRGB */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002095 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002096 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002097 png_bytep sp = row + (png_size_t)row_width * 3;
2098 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002099 for (i = 0; i < row_width; i++)
2100 {
2101 *(--dp) = *(--sp);
2102 *(--dp) = *(--sp);
2103 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002104 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002105 }
2106 row_info->channels = 4;
2107 row_info->pixel_depth = 32;
2108 row_info->rowbytes = row_width * 4;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002109 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002110 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002111 else if (row_info->bit_depth == 16)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002112 {
2113 /* This changes the data from RRGGBB to RRGGBBXX */
2114 if (flags & PNG_FLAG_FILLER_AFTER)
2115 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002116 png_bytep sp = row + (png_size_t)row_width * 6;
2117 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002118 for (i = 1; i < row_width; i++)
2119 {
2120 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002121 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002122 *(--dp) = *(--sp);
2123 *(--dp) = *(--sp);
2124 *(--dp) = *(--sp);
2125 *(--dp) = *(--sp);
2126 *(--dp) = *(--sp);
2127 *(--dp) = *(--sp);
2128 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002129 *(--dp) = hi_filler;
2130 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002131 row_info->channels = 4;
2132 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002133 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002134 }
2135 /* This changes the data from RRGGBB to XXRRGGBB */
2136 else
2137 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002138 png_bytep sp = row + (png_size_t)row_width * 6;
2139 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002140 for (i = 0; i < row_width; i++)
2141 {
2142 *(--dp) = *(--sp);
2143 *(--dp) = *(--sp);
2144 *(--dp) = *(--sp);
2145 *(--dp) = *(--sp);
2146 *(--dp) = *(--sp);
2147 *(--dp) = *(--sp);
2148 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002149 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002150 }
2151 row_info->channels = 4;
2152 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002153 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002154 }
2155 }
2156 } /* COLOR_TYPE == RGB */
Guy Schalnat0d580581995-07-20 02:43:20 -05002157}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002158#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002159
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002160#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002161/* Expand grayscale files to RGB, with or without alpha */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002162void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002163png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05002164{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002165 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002166 png_uint_32 row_width = row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06002167
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002168 png_debug(1, "in png_do_gray_to_rgb");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05002169
Andreas Dilger47a0c421997-05-16 02:46:07 -05002170 if (row_info->bit_depth >= 8 &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002171 !(row_info->color_type & PNG_COLOR_MASK_COLOR))
2172 {
2173 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
2174 {
2175 if (row_info->bit_depth == 8)
2176 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002177 png_bytep sp = row + (png_size_t)row_width - 1;
2178 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002179 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002180 {
2181 *(dp--) = *sp;
2182 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002183 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002184 }
2185 }
2186 else
2187 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002188 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2189 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002190 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002191 {
2192 *(dp--) = *sp;
2193 *(dp--) = *(sp - 1);
2194 *(dp--) = *sp;
2195 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002196 *(dp--) = *(sp--);
2197 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002198 }
2199 }
2200 }
2201 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2202 {
2203 if (row_info->bit_depth == 8)
2204 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002205 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2206 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002207 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002208 {
2209 *(dp--) = *(sp--);
2210 *(dp--) = *sp;
2211 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002212 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002213 }
2214 }
2215 else
2216 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002217 png_bytep sp = row + (png_size_t)row_width * 4 - 1;
2218 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002219 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002220 {
2221 *(dp--) = *(sp--);
2222 *(dp--) = *(sp--);
2223 *(dp--) = *sp;
2224 *(dp--) = *(sp - 1);
2225 *(dp--) = *sp;
2226 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002227 *(dp--) = *(sp--);
2228 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002229 }
2230 }
2231 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002232 row_info->channels += (png_byte)2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002233 row_info->color_type |= PNG_COLOR_MASK_COLOR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002234 row_info->pixel_depth = (png_byte)(row_info->channels *
2235 row_info->bit_depth);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002236 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05002237 }
2238}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002239#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002240
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002241#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002242/* Reduce RGB files to grayscale, with or without alpha
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002243 * using the equation given in Poynton's ColorFAQ at
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002244 * <http://www.inforamp.net/~poynton/> (THIS LINK IS DEAD June 2008)
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002245 * New link:
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002246 * <http://www.poynton.com/notes/colour_and_gamma/>
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002247 * Charles Poynton poynton at poynton.com
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002248 *
2249 * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
2250 *
2251 * We approximate this with
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002252 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002253 * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002254 *
2255 * which can be expressed with integers as
2256 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002257 * Y = (6969 * R + 23434 * G + 2365 * B)/32768
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002258 *
2259 * The calculation is to be done in a linear colorspace.
2260 *
2261 * Other integer coefficents can be used via png_set_rgb_to_gray().
2262 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002263int /* PRIVATE */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002264png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
2265
2266{
2267 png_uint_32 i;
2268
2269 png_uint_32 row_width = row_info->width;
2270 int rgb_error = 0;
2271
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002272 png_debug(1, "in png_do_rgb_to_gray");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05002273
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002274 if (
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002275 (row_info->color_type & PNG_COLOR_MASK_COLOR))
2276 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002277 png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
2278 png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
2279 png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002280
2281 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2282 {
2283 if (row_info->bit_depth == 8)
2284 {
2285#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2286 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2287 {
2288 png_bytep sp = row;
2289 png_bytep dp = row;
2290
2291 for (i = 0; i < row_width; i++)
2292 {
2293 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2294 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2295 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002296 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002297 {
2298 rgb_error |= 1;
2299 *(dp++) = png_ptr->gamma_from_1[
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002300 (rc*red + gc*green + bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002301 }
2302 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002303 *(dp++) = *(sp - 1);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002304 }
2305 }
2306 else
2307#endif
2308 {
2309 png_bytep sp = row;
2310 png_bytep dp = row;
2311 for (i = 0; i < row_width; i++)
2312 {
2313 png_byte red = *(sp++);
2314 png_byte green = *(sp++);
2315 png_byte blue = *(sp++);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002316 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002317 {
2318 rgb_error |= 1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002319 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002320 }
2321 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002322 *(dp++) = *(sp - 1);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002323 }
2324 }
2325 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002326
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002327 else /* RGB bit_depth == 16 */
2328 {
2329#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2330 if (png_ptr->gamma_16_to_1 != NULL &&
2331 png_ptr->gamma_16_from_1 != NULL)
2332 {
2333 png_bytep sp = row;
2334 png_bytep dp = row;
2335 for (i = 0; i < row_width; i++)
2336 {
2337 png_uint_16 red, green, blue, w;
2338
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002339 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2340 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2341 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002342
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002343 if (red == green && red == blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002344 w = red;
2345 else
2346 {
2347 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2348 png_ptr->gamma_shift][red>>8];
2349 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2350 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002351 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002352 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002353 png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002354 + bc*blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002355 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2356 png_ptr->gamma_shift][gray16 >> 8];
2357 rgb_error |= 1;
2358 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002359
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002360 *(dp++) = (png_byte)((w>>8) & 0xff);
2361 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002362 }
2363 }
2364 else
2365#endif
2366 {
2367 png_bytep sp = row;
2368 png_bytep dp = row;
2369 for (i = 0; i < row_width; i++)
2370 {
2371 png_uint_16 red, green, blue, gray16;
2372
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002373 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2374 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2375 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002376
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002377 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002378 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002379 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002380 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2381 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002382 }
2383 }
2384 }
2385 }
2386 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2387 {
2388 if (row_info->bit_depth == 8)
2389 {
2390#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2391 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2392 {
2393 png_bytep sp = row;
2394 png_bytep dp = row;
2395 for (i = 0; i < row_width; i++)
2396 {
2397 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2398 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2399 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002400 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002401 rgb_error |= 1;
2402 *(dp++) = png_ptr->gamma_from_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002403 [(rc*red + gc*green + bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002404 *(dp++) = *(sp++); /* alpha */
2405 }
2406 }
2407 else
2408#endif
2409 {
2410 png_bytep sp = row;
2411 png_bytep dp = row;
2412 for (i = 0; i < row_width; i++)
2413 {
2414 png_byte red = *(sp++);
2415 png_byte green = *(sp++);
2416 png_byte blue = *(sp++);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002417 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002418 rgb_error |= 1;
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002419 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002420 *(dp++) = *(sp++); /* alpha */
2421 }
2422 }
2423 }
2424 else /* RGBA bit_depth == 16 */
2425 {
2426#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2427 if (png_ptr->gamma_16_to_1 != NULL &&
2428 png_ptr->gamma_16_from_1 != NULL)
2429 {
2430 png_bytep sp = row;
2431 png_bytep dp = row;
2432 for (i = 0; i < row_width; i++)
2433 {
2434 png_uint_16 red, green, blue, w;
2435
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002436 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2437 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2438 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002439
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002440 if (red == green && red == blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002441 w = red;
2442 else
2443 {
2444 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2445 png_ptr->gamma_shift][red>>8];
2446 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2447 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002448 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002449 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002450 png_uint_16 gray16 = (png_uint_16)((rc * red_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002451 + gc * green_1 + bc * blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002452 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2453 png_ptr->gamma_shift][gray16 >> 8];
2454 rgb_error |= 1;
2455 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002456
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002457 *(dp++) = (png_byte)((w>>8) & 0xff);
2458 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002459 *(dp++) = *(sp++); /* alpha */
2460 *(dp++) = *(sp++);
2461 }
2462 }
2463 else
2464#endif
2465 {
2466 png_bytep sp = row;
2467 png_bytep dp = row;
2468 for (i = 0; i < row_width; i++)
2469 {
2470 png_uint_16 red, green, blue, gray16;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002471 red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2472 green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2473 blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002474 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002475 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002476 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002477 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2478 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002479 *(dp++) = *(sp++); /* alpha */
2480 *(dp++) = *(sp++);
2481 }
2482 }
2483 }
2484 }
2485 row_info->channels -= (png_byte)2;
2486 row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
2487 row_info->pixel_depth = (png_byte)(row_info->channels *
2488 row_info->bit_depth);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002489 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002490 }
2491 return rgb_error;
2492}
2493#endif
2494
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002495/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
2496 * large of png_color. This lets grayscale images be treated as
2497 * paletted. Most useful for gamma correction and simplification
2498 * of code.
2499 */
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06002500void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -06002501png_build_grayscale_palette(int bit_depth, png_colorp palette)
Guy Schalnat0d580581995-07-20 02:43:20 -05002502{
2503 int num_palette;
2504 int color_inc;
2505 int i;
2506 int v;
2507
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002508 png_debug(1, "in png_do_build_grayscale_palette");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05002509
Andreas Dilger47a0c421997-05-16 02:46:07 -05002510 if (palette == NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002511 return;
2512
2513 switch (bit_depth)
2514 {
2515 case 1:
2516 num_palette = 2;
2517 color_inc = 0xff;
2518 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002519
Guy Schalnat0d580581995-07-20 02:43:20 -05002520 case 2:
2521 num_palette = 4;
2522 color_inc = 0x55;
2523 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002524
Guy Schalnat0d580581995-07-20 02:43:20 -05002525 case 4:
2526 num_palette = 16;
2527 color_inc = 0x11;
2528 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002529
Guy Schalnat0d580581995-07-20 02:43:20 -05002530 case 8:
2531 num_palette = 256;
2532 color_inc = 1;
2533 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002534
Guy Schalnat0d580581995-07-20 02:43:20 -05002535 default:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002536 num_palette = 0;
Guy Schalnat69b14481996-01-10 02:56:49 -06002537 color_inc = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002538 break;
2539 }
2540
2541 for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
2542 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002543 palette[i].red = (png_byte)v;
2544 palette[i].green = (png_byte)v;
2545 palette[i].blue = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002546 }
2547}
2548
Guy Schalnat0d580581995-07-20 02:43:20 -05002549
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002550#ifdef PNG_READ_BACKGROUND_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002551/* Replace any alpha or transparency with the supplied background color.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002552 * "background" is already in the screen gamma, while "background_1" is
2553 * at a gamma of 1.0. Paletted files have already been taken care of.
2554 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002555void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002556png_do_background(png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002557 png_color_16p trans_color, png_color_16p background
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002558#ifdef PNG_READ_GAMMA_SUPPORTED
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002559 , png_color_16p background_1,
Guy Schalnat6d764711995-12-19 03:22:19 -06002560 png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002561 png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002562 png_uint_16pp gamma_16_to_1, int gamma_shift
2563#endif
2564 )
Guy Schalnat0d580581995-07-20 02:43:20 -05002565{
Guy Schalnat6d764711995-12-19 03:22:19 -06002566 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002567 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002568 png_uint_32 row_width=row_info->width;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002569 int shift;
Guy Schalnate5a37791996-06-05 15:50:50 -05002570
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002571 png_debug(1, "in png_do_background");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05002572
Andreas Dilger47a0c421997-05-16 02:46:07 -05002573 if (background != NULL &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002574 (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002575 (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_color)))
Guy Schalnat0d580581995-07-20 02:43:20 -05002576 {
2577 switch (row_info->color_type)
2578 {
2579 case PNG_COLOR_TYPE_GRAY:
2580 {
2581 switch (row_info->bit_depth)
2582 {
2583 case 1:
2584 {
Guy Schalnat0d580581995-07-20 02:43:20 -05002585 sp = row;
2586 shift = 7;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002587 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002588 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002589 if ((png_uint_16)((*sp >> shift) & 0x01)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002590 == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002591 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002592 *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2593 *sp |= (png_byte)(background->gray << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002594 }
2595 if (!shift)
2596 {
2597 shift = 7;
2598 sp++;
2599 }
2600 else
2601 shift--;
2602 }
2603 break;
2604 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002605
Guy Schalnat0d580581995-07-20 02:43:20 -05002606 case 2:
2607 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002608#ifdef PNG_READ_GAMMA_SUPPORTED
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002609 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002610 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002611 sp = row;
2612 shift = 6;
2613 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002614 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002615 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002616 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002617 {
2618 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2619 *sp |= (png_byte)(background->gray << shift);
2620 }
2621 else
2622 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002623 png_byte p = (png_byte)((*sp >> shift) & 0x03);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002624 png_byte g = (png_byte)((gamma_table [p | (p << 2) |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002625 (p << 4) | (p << 6)] >> 6) & 0x03);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002626 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2627 *sp |= (png_byte)(g << shift);
2628 }
2629 if (!shift)
2630 {
2631 shift = 6;
2632 sp++;
2633 }
2634 else
2635 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002636 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002637 }
2638 else
2639#endif
2640 {
2641 sp = row;
2642 shift = 6;
2643 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002644 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002645 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002646 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002647 {
2648 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2649 *sp |= (png_byte)(background->gray << shift);
2650 }
2651 if (!shift)
2652 {
2653 shift = 6;
2654 sp++;
2655 }
2656 else
2657 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002658 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002659 }
2660 break;
2661 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002662
Guy Schalnat0d580581995-07-20 02:43:20 -05002663 case 4:
2664 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002665#ifdef PNG_READ_GAMMA_SUPPORTED
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002666 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002667 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002668 sp = row;
2669 shift = 4;
2670 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002671 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002672 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002673 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002674 {
2675 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2676 *sp |= (png_byte)(background->gray << shift);
2677 }
2678 else
2679 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002680 png_byte p = (png_byte)((*sp >> shift) & 0x0f);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002681 png_byte g = (png_byte)((gamma_table[p |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002682 (p << 4)] >> 4) & 0x0f);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002683 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2684 *sp |= (png_byte)(g << shift);
2685 }
2686 if (!shift)
2687 {
2688 shift = 4;
2689 sp++;
2690 }
2691 else
2692 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002693 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002694 }
2695 else
2696#endif
2697 {
2698 sp = row;
2699 shift = 4;
2700 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002701 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002702 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002703 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002704 {
2705 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2706 *sp |= (png_byte)(background->gray << shift);
2707 }
2708 if (!shift)
2709 {
2710 shift = 4;
2711 sp++;
2712 }
2713 else
2714 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002715 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002716 }
2717 break;
2718 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002719
Guy Schalnat0d580581995-07-20 02:43:20 -05002720 case 8:
2721 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002722#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002723 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002724 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002725 sp = row;
2726 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002727 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002728 if (*sp == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002729 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002730 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002731 }
2732 else
2733 {
2734 *sp = gamma_table[*sp];
2735 }
2736 }
2737 }
2738 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002739#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002740 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002741 sp = row;
2742 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002743 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002744 if (*sp == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002745 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002746 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002747 }
2748 }
2749 }
2750 break;
2751 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002752
Guy Schalnat0d580581995-07-20 02:43:20 -05002753 case 16:
2754 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002755#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002756 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002757 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002758 sp = row;
2759 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002760 {
2761 png_uint_16 v;
2762
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002763 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002764 if (v == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002765 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002766 /* Background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002767 *sp = (png_byte)((background->gray >> 8) & 0xff);
2768 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002769 }
2770 else
2771 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002772 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002773 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002774 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002775 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002776 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002777 }
2778 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002779#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002780 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002781 sp = row;
2782 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002783 {
2784 png_uint_16 v;
2785
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002786 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002787 if (v == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002788 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002789 *sp = (png_byte)((background->gray >> 8) & 0xff);
2790 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002791 }
2792 }
2793 }
2794 break;
2795 }
2796 }
2797 break;
2798 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002799
Guy Schalnat0d580581995-07-20 02:43:20 -05002800 case PNG_COLOR_TYPE_RGB:
2801 {
2802 if (row_info->bit_depth == 8)
2803 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002804#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002805 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002806 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002807 sp = row;
2808 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002809 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002810 if (*sp == trans_color->red &&
2811 *(sp + 1) == trans_color->green &&
2812 *(sp + 2) == trans_color->blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05002813 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002814 *sp = (png_byte)background->red;
2815 *(sp + 1) = (png_byte)background->green;
2816 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002817 }
2818 else
2819 {
2820 *sp = gamma_table[*sp];
2821 *(sp + 1) = gamma_table[*(sp + 1)];
2822 *(sp + 2) = gamma_table[*(sp + 2)];
2823 }
2824 }
2825 }
2826 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002827#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002828 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002829 sp = row;
2830 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002831 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002832 if (*sp == trans_color->red &&
2833 *(sp + 1) == trans_color->green &&
2834 *(sp + 2) == trans_color->blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05002835 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002836 *sp = (png_byte)background->red;
2837 *(sp + 1) = (png_byte)background->green;
2838 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002839 }
2840 }
2841 }
2842 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002843 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05002844 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002845#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002846 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002847 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002848 sp = row;
2849 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002850 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002851 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2852 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2853 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002854 if (r == trans_color->red && g == trans_color->green &&
2855 b == trans_color->blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05002856 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002857 /* Background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002858 *sp = (png_byte)((background->red >> 8) & 0xff);
2859 *(sp + 1) = (png_byte)(background->red & 0xff);
2860 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2861 *(sp + 3) = (png_byte)(background->green & 0xff);
2862 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2863 *(sp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002864 }
2865 else
2866 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002867 png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002868 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002869 *(sp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002870 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002871 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
2872 *(sp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002873 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002874 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
2875 *(sp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002876 }
2877 }
2878 }
2879 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002880#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002881 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002882 sp = row;
2883 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05002884 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002885 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
2886 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2887 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Guy Schalnat0d580581995-07-20 02:43:20 -05002888
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002889 if (r == trans_color->red && g == trans_color->green &&
2890 b == trans_color->blue)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002891 {
2892 *sp = (png_byte)((background->red >> 8) & 0xff);
2893 *(sp + 1) = (png_byte)(background->red & 0xff);
2894 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2895 *(sp + 3) = (png_byte)(background->green & 0xff);
2896 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2897 *(sp + 5) = (png_byte)(background->blue & 0xff);
2898 }
2899 }
2900 }
2901 }
2902 break;
2903 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002904
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002905 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -05002906 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002907 if (row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002908 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002909#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002910 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
2911 gamma_table != NULL)
2912 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002913 sp = row;
2914 dp = row;
2915 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002916 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002917 png_uint_16 a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002918
Andreas Dilger47a0c421997-05-16 02:46:07 -05002919 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002920 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002921 *dp = gamma_table[*sp];
2922 }
2923 else if (a == 0)
2924 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002925 /* Background is already in screen gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002926 *dp = (png_byte)background->gray;
2927 }
2928 else
2929 {
2930 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05002931
Andreas Dilger47a0c421997-05-16 02:46:07 -05002932 v = gamma_to_1[*sp];
2933 png_composite(w, v, a, background_1->gray);
2934 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05002935 }
2936 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002937 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002938 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002939#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002940 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002941 sp = row;
2942 dp = row;
2943 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002944 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002945 png_byte a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002946
Andreas Dilger47a0c421997-05-16 02:46:07 -05002947 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002948 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002949 *dp = *sp;
2950 }
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002951#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002952 else if (a == 0)
2953 {
2954 *dp = (png_byte)background->gray;
2955 }
2956 else
2957 {
2958 png_composite(*dp, *sp, a, background_1->gray);
Guy Schalnat0d580581995-07-20 02:43:20 -05002959 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002960#else
2961 *dp = (png_byte)background->gray;
2962#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002963 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002964 }
2965 }
2966 else /* if (png_ptr->bit_depth == 16) */
2967 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002968#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002969 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
2970 gamma_16_to_1 != NULL)
2971 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002972 sp = row;
2973 dp = row;
2974 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002975 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002976 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05002977
Andreas Dilger47a0c421997-05-16 02:46:07 -05002978 if (a == (png_uint_16)0xffff)
2979 {
2980 png_uint_16 v;
2981
2982 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
2983 *dp = (png_byte)((v >> 8) & 0xff);
2984 *(dp + 1) = (png_byte)(v & 0xff);
2985 }
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002986#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002987 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002988#else
2989 else
2990#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002991 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002992 /* Background is already in screen gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002993 *dp = (png_byte)((background->gray >> 8) & 0xff);
2994 *(dp + 1) = (png_byte)(background->gray & 0xff);
2995 }
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002996#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002997 else
2998 {
2999 png_uint_16 g, v, w;
3000
3001 g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3002 png_composite_16(v, g, a, background_1->gray);
3003 w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
3004 *dp = (png_byte)((w >> 8) & 0xff);
3005 *(dp + 1) = (png_byte)(w & 0xff);
3006 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003007#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003008 }
3009 }
3010 else
3011#endif
3012 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003013 sp = row;
3014 dp = row;
3015 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003016 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003017 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003018 if (a == (png_uint_16)0xffff)
3019 {
3020 png_memcpy(dp, sp, 2);
3021 }
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003022#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05003023 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003024#else
3025 else
3026#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003027 {
3028 *dp = (png_byte)((background->gray >> 8) & 0xff);
3029 *(dp + 1) = (png_byte)(background->gray & 0xff);
3030 }
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003031#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05003032 else
3033 {
3034 png_uint_16 g, v;
3035
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003036 g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003037 png_composite_16(v, g, a, background_1->gray);
3038 *dp = (png_byte)((v >> 8) & 0xff);
3039 *(dp + 1) = (png_byte)(v & 0xff);
3040 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003041#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003042 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003043 }
3044 }
3045 break;
3046 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003047
Guy Schalnat0d580581995-07-20 02:43:20 -05003048 case PNG_COLOR_TYPE_RGB_ALPHA:
3049 {
3050 if (row_info->bit_depth == 8)
3051 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003052#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05003053 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3054 gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003055 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003056 sp = row;
3057 dp = row;
3058 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003059 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003060 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003061
Guy Schalnat0d580581995-07-20 02:43:20 -05003062 if (a == 0xff)
3063 {
3064 *dp = gamma_table[*sp];
3065 *(dp + 1) = gamma_table[*(sp + 1)];
3066 *(dp + 2) = gamma_table[*(sp + 2)];
3067 }
3068 else if (a == 0)
3069 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003070 /* Background is already in screen gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -05003071 *dp = (png_byte)background->red;
3072 *(dp + 1) = (png_byte)background->green;
3073 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003074 }
3075 else
3076 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003077 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05003078
3079 v = gamma_to_1[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003080 png_composite(w, v, a, background_1->red);
3081 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003082 v = gamma_to_1[*(sp + 1)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003083 png_composite(w, v, a, background_1->green);
3084 *(dp + 1) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003085 v = gamma_to_1[*(sp + 2)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003086 png_composite(w, v, a, background_1->blue);
3087 *(dp + 2) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003088 }
3089 }
3090 }
3091 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003092#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003093 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003094 sp = row;
3095 dp = row;
3096 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003097 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003098 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003099
Guy Schalnat0d580581995-07-20 02:43:20 -05003100 if (a == 0xff)
3101 {
3102 *dp = *sp;
3103 *(dp + 1) = *(sp + 1);
3104 *(dp + 2) = *(sp + 2);
3105 }
3106 else if (a == 0)
3107 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003108 *dp = (png_byte)background->red;
3109 *(dp + 1) = (png_byte)background->green;
3110 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003111 }
3112 else
3113 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003114 png_composite(*dp, *sp, a, background->red);
3115 png_composite(*(dp + 1), *(sp + 1), a,
3116 background->green);
3117 png_composite(*(dp + 2), *(sp + 2), a,
3118 background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003119 }
3120 }
3121 }
3122 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003123 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003124 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003125#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05003126 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3127 gamma_16_to_1 != 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 += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003132 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003133 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3134 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003135 if (a == (png_uint_16)0xffff)
3136 {
3137 png_uint_16 v;
3138
Andreas Dilger47a0c421997-05-16 02:46:07 -05003139 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003140 *dp = (png_byte)((v >> 8) & 0xff);
3141 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003142 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003143 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3144 *(dp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003145 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003146 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3147 *(dp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003148 }
3149 else if (a == 0)
3150 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003151 /* Background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003152 *dp = (png_byte)((background->red >> 8) & 0xff);
3153 *(dp + 1) = (png_byte)(background->red & 0xff);
3154 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3155 *(dp + 3) = (png_byte)(background->green & 0xff);
3156 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3157 *(dp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003158 }
3159 else
3160 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003161 png_uint_16 v, w, x;
Guy Schalnat0d580581995-07-20 02:43:20 -05003162
Andreas Dilger47a0c421997-05-16 02:46:07 -05003163 v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003164 png_composite_16(w, v, a, background_1->red);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003165 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3166 *dp = (png_byte)((x >> 8) & 0xff);
3167 *(dp + 1) = (png_byte)(x & 0xff);
3168 v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003169 png_composite_16(w, v, a, background_1->green);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003170 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3171 *(dp + 2) = (png_byte)((x >> 8) & 0xff);
3172 *(dp + 3) = (png_byte)(x & 0xff);
3173 v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003174 png_composite_16(w, v, a, background_1->blue);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003175 x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
3176 *(dp + 4) = (png_byte)((x >> 8) & 0xff);
3177 *(dp + 5) = (png_byte)(x & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003178 }
3179 }
3180 }
3181 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003182#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003183 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003184 sp = row;
3185 dp = row;
3186 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003187 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003188 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3189 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003190 if (a == (png_uint_16)0xffff)
3191 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003192 png_memcpy(dp, sp, 6);
Guy Schalnat0d580581995-07-20 02:43:20 -05003193 }
3194 else if (a == 0)
3195 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003196 *dp = (png_byte)((background->red >> 8) & 0xff);
3197 *(dp + 1) = (png_byte)(background->red & 0xff);
3198 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3199 *(dp + 3) = (png_byte)(background->green & 0xff);
3200 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3201 *(dp + 5) = (png_byte)(background->blue & 0xff);
3202 }
3203 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003204 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003205 png_uint_16 v;
Guy Schalnat0d580581995-07-20 02:43:20 -05003206
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003207 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3208 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3209 + *(sp + 3));
3210 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3211 + *(sp + 5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003212
3213 png_composite_16(v, r, a, background->red);
Guy Schalnat0d580581995-07-20 02:43:20 -05003214 *dp = (png_byte)((v >> 8) & 0xff);
3215 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003216 png_composite_16(v, g, a, background->green);
Guy Schalnat0d580581995-07-20 02:43:20 -05003217 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3218 *(dp + 3) = (png_byte)(v & 0xff);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003219 png_composite_16(v, b, a, background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003220 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3221 *(dp + 5) = (png_byte)(v & 0xff);
3222 }
3223 }
3224 }
3225 }
3226 break;
3227 }
3228 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003229
Guy Schalnat0d580581995-07-20 02:43:20 -05003230 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
3231 {
3232 row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
Guy Schalnate5a37791996-06-05 15:50:50 -05003233 row_info->channels--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003234 row_info->pixel_depth = (png_byte)(row_info->channels *
3235 row_info->bit_depth);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003236 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003237 }
3238 }
3239}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003240#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003241
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003242#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05003243/* Gamma correct the image, avoiding the alpha channel. Make sure
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003244 * you do this after you deal with the transparency issue on grayscale
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003245 * or RGB images. If your bit depth is 8, use gamma_table, if it
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003246 * is 16, use gamma_16_table and gamma_shift. Build these with
3247 * build_gamma_table().
3248 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003249void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003250png_do_gamma(png_row_infop row_info, png_bytep row,
3251 png_bytep gamma_table, png_uint_16pp gamma_16_table,
Guy Schalnat0d580581995-07-20 02:43:20 -05003252 int gamma_shift)
3253{
Guy Schalnat6d764711995-12-19 03:22:19 -06003254 png_bytep sp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003255 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003256 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003257
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003258 png_debug(1, "in png_do_gamma");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05003259
Andreas Dilger47a0c421997-05-16 02:46:07 -05003260 if (
Andreas Dilger47a0c421997-05-16 02:46:07 -05003261 ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
3262 (row_info->bit_depth == 16 && gamma_16_table != NULL)))
Guy Schalnat0d580581995-07-20 02:43:20 -05003263 {
3264 switch (row_info->color_type)
3265 {
3266 case PNG_COLOR_TYPE_RGB:
3267 {
3268 if (row_info->bit_depth == 8)
3269 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003270 sp = row;
3271 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003272 {
3273 *sp = gamma_table[*sp];
3274 sp++;
3275 *sp = gamma_table[*sp];
3276 sp++;
3277 *sp = gamma_table[*sp];
3278 sp++;
3279 }
3280 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003281 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003282 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003283 sp = row;
3284 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003285 {
3286 png_uint_16 v;
3287
Andreas Dilger47a0c421997-05-16 02:46:07 -05003288 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003289 *sp = (png_byte)((v >> 8) & 0xff);
3290 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003291 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003292 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003293 *sp = (png_byte)((v >> 8) & 0xff);
3294 *(sp + 1) = (png_byte)(v & 0xff);
3295 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003296 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003297 *sp = (png_byte)((v >> 8) & 0xff);
3298 *(sp + 1) = (png_byte)(v & 0xff);
3299 sp += 2;
3300 }
3301 }
3302 break;
3303 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003304
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003305 case PNG_COLOR_TYPE_RGB_ALPHA:
3306 {
3307 if (row_info->bit_depth == 8)
3308 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003309 sp = row;
3310 for (i = 0; i < row_width; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003311 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003312 *sp = gamma_table[*sp];
3313 sp++;
3314 *sp = gamma_table[*sp];
3315 sp++;
3316 *sp = gamma_table[*sp];
3317 sp++;
3318 sp++;
3319 }
3320 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003321 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003322 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003323 sp = row;
3324 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003325 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003326 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003327 *sp = (png_byte)((v >> 8) & 0xff);
3328 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003329 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003330 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003331 *sp = (png_byte)((v >> 8) & 0xff);
3332 *(sp + 1) = (png_byte)(v & 0xff);
3333 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003334 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003335 *sp = (png_byte)((v >> 8) & 0xff);
3336 *(sp + 1) = (png_byte)(v & 0xff);
3337 sp += 4;
3338 }
3339 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003340 break;
3341 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003342
Guy Schalnat0d580581995-07-20 02:43:20 -05003343 case PNG_COLOR_TYPE_GRAY_ALPHA:
3344 {
3345 if (row_info->bit_depth == 8)
3346 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003347 sp = row;
3348 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003349 {
3350 *sp = gamma_table[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003351 sp += 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05003352 }
3353 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003354 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003355 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003356 sp = row;
3357 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003358 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003359 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003360 *sp = (png_byte)((v >> 8) & 0xff);
3361 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003362 sp += 4;
3363 }
3364 }
3365 break;
3366 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003367
Guy Schalnat0d580581995-07-20 02:43:20 -05003368 case PNG_COLOR_TYPE_GRAY:
3369 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003370 if (row_info->bit_depth == 2)
3371 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003372 sp = row;
3373 for (i = 0; i < row_width; i += 4)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003374 {
3375 int a = *sp & 0xc0;
3376 int b = *sp & 0x30;
3377 int c = *sp & 0x0c;
3378 int d = *sp & 0x03;
3379
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003380 *sp = (png_byte)(
3381 ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003382 ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
3383 ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003384 ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003385 sp++;
3386 }
3387 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003388
Andreas Dilger47a0c421997-05-16 02:46:07 -05003389 if (row_info->bit_depth == 4)
Guy Schalnat0d580581995-07-20 02:43:20 -05003390 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003391 sp = row;
3392 for (i = 0; i < row_width; i += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003393 {
3394 int msb = *sp & 0xf0;
3395 int lsb = *sp & 0x0f;
3396
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003397 *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
3398 | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003399 sp++;
3400 }
3401 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003402
Andreas Dilger47a0c421997-05-16 02:46:07 -05003403 else if (row_info->bit_depth == 8)
3404 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003405 sp = row;
3406 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003407 {
3408 *sp = gamma_table[*sp];
3409 sp++;
3410 }
3411 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003412
Guy Schalnat0d580581995-07-20 02:43:20 -05003413 else if (row_info->bit_depth == 16)
3414 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003415 sp = row;
3416 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003417 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003418 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003419 *sp = (png_byte)((v >> 8) & 0xff);
3420 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003421 sp += 2;
3422 }
3423 }
3424 break;
3425 }
3426 }
3427 }
3428}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003429#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003430
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003431#ifdef PNG_READ_EXPAND_SUPPORTED
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003432/* Expands a palette row to an RGB or RGBA row depending
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003433 * upon whether you supply trans and num_trans.
3434 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003435void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003436png_do_expand_palette(png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -05003437 png_colorp palette, png_bytep trans_alpha, int num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003438{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003439 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003440 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003441 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003442 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003443
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003444 png_debug(1, "in png_do_expand_palette");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05003445
Andreas Dilger47a0c421997-05-16 02:46:07 -05003446 if (
Andreas Dilger47a0c421997-05-16 02:46:07 -05003447 row_info->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05003448 {
3449 if (row_info->bit_depth < 8)
3450 {
3451 switch (row_info->bit_depth)
3452 {
3453 case 1:
3454 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003455 sp = row + (png_size_t)((row_width - 1) >> 3);
3456 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003457 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003458 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003459 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003460 if ((*sp >> shift) & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -05003461 *dp = 1;
3462 else
3463 *dp = 0;
3464 if (shift == 7)
3465 {
3466 shift = 0;
3467 sp--;
3468 }
3469 else
3470 shift++;
3471
3472 dp--;
3473 }
3474 break;
3475 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003476
Guy Schalnat0d580581995-07-20 02:43:20 -05003477 case 2:
3478 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003479 sp = row + (png_size_t)((row_width - 1) >> 2);
3480 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003481 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003482 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003483 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003484 value = (*sp >> shift) & 0x03;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003485 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003486 if (shift == 6)
3487 {
3488 shift = 0;
3489 sp--;
3490 }
3491 else
3492 shift += 2;
3493
3494 dp--;
3495 }
3496 break;
3497 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003498
Guy Schalnat0d580581995-07-20 02:43:20 -05003499 case 4:
3500 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003501 sp = row + (png_size_t)((row_width - 1) >> 1);
3502 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003503 shift = (int)((row_width & 0x01) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003504 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003505 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003506 value = (*sp >> shift) & 0x0f;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003507 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003508 if (shift == 4)
3509 {
3510 shift = 0;
3511 sp--;
3512 }
3513 else
3514 shift += 4;
3515
3516 dp--;
3517 }
3518 break;
3519 }
3520 }
3521 row_info->bit_depth = 8;
3522 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003523 row_info->rowbytes = row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003524 }
3525 switch (row_info->bit_depth)
3526 {
3527 case 8:
3528 {
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -05003529 if (trans_alpha != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003530 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003531 sp = row + (png_size_t)row_width - 1;
3532 dp = row + (png_size_t)(row_width << 2) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003533
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003534 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003535 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003536 if ((int)(*sp) >= num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003537 *dp-- = 0xff;
3538 else
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -05003539 *dp-- = trans_alpha[*sp];
Guy Schalnat0d580581995-07-20 02:43:20 -05003540 *dp-- = palette[*sp].blue;
3541 *dp-- = palette[*sp].green;
3542 *dp-- = palette[*sp].red;
3543 sp--;
3544 }
3545 row_info->bit_depth = 8;
3546 row_info->pixel_depth = 32;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003547 row_info->rowbytes = row_width * 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05003548 row_info->color_type = 6;
3549 row_info->channels = 4;
3550 }
3551 else
3552 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003553 sp = row + (png_size_t)row_width - 1;
3554 dp = row + (png_size_t)(row_width * 3) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003555
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003556 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003557 {
3558 *dp-- = palette[*sp].blue;
3559 *dp-- = palette[*sp].green;
3560 *dp-- = palette[*sp].red;
3561 sp--;
3562 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003563
Guy Schalnat0d580581995-07-20 02:43:20 -05003564 row_info->bit_depth = 8;
3565 row_info->pixel_depth = 24;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003566 row_info->rowbytes = row_width * 3;
Guy Schalnat0d580581995-07-20 02:43:20 -05003567 row_info->color_type = 2;
3568 row_info->channels = 3;
3569 }
3570 break;
3571 }
3572 }
3573 }
3574}
3575
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -06003576/* If the bit depth < 8, it is expanded to 8. Also, if the already
3577 * expanded transparency value is supplied, an alpha channel is built.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003578 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003579void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003580png_do_expand(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003581 png_color_16p trans_value)
Guy Schalnat0d580581995-07-20 02:43:20 -05003582{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003583 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003584 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003585 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003586 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003587
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003588 png_debug(1, "in png_do_expand");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05003589
Guy Schalnat0d580581995-07-20 02:43:20 -05003590 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003591 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05003592 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003593 png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003594
3595 if (row_info->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003596 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003597 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05003598 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003599 case 1:
3600 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003601 gray = (png_uint_16)((gray&0x01)*0xff);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003602 sp = row + (png_size_t)((row_width - 1) >> 3);
3603 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003604 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003605 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003606 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003607 if ((*sp >> shift) & 0x01)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003608 *dp = 0xff;
3609 else
3610 *dp = 0;
3611 if (shift == 7)
3612 {
3613 shift = 0;
3614 sp--;
3615 }
3616 else
3617 shift++;
3618
3619 dp--;
3620 }
3621 break;
3622 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003623
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003624 case 2:
3625 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003626 gray = (png_uint_16)((gray&0x03)*0x55);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003627 sp = row + (png_size_t)((row_width - 1) >> 2);
3628 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003629 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003630 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003631 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003632 value = (*sp >> shift) & 0x03;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003633 *dp = (png_byte)(value | (value << 2) | (value << 4) |
3634 (value << 6));
3635 if (shift == 6)
3636 {
3637 shift = 0;
3638 sp--;
3639 }
3640 else
3641 shift += 2;
3642
3643 dp--;
3644 }
3645 break;
3646 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003647
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003648 case 4:
3649 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003650 gray = (png_uint_16)((gray&0x0f)*0x11);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003651 sp = row + (png_size_t)((row_width - 1) >> 1);
3652 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003653 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003654 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003655 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003656 value = (*sp >> shift) & 0x0f;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003657 *dp = (png_byte)(value | (value << 4));
3658 if (shift == 4)
3659 {
3660 shift = 0;
3661 sp--;
3662 }
3663 else
3664 shift = 4;
3665
3666 dp--;
3667 }
3668 break;
3669 }
3670 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003671
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003672 row_info->bit_depth = 8;
3673 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003674 row_info->rowbytes = row_width;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003675 }
3676
Andreas Dilger47a0c421997-05-16 02:46:07 -05003677 if (trans_value != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003678 {
3679 if (row_info->bit_depth == 8)
3680 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003681 gray = gray & 0xff;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003682 sp = row + (png_size_t)row_width - 1;
3683 dp = row + (png_size_t)(row_width << 1) - 1;
3684 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003685 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003686 if (*sp == gray)
3687 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003688 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003689 *dp-- = 0xff;
3690 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003691 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003692 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003693
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003694 else if (row_info->bit_depth == 16)
Guy Schalnat0d580581995-07-20 02:43:20 -05003695 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003696 png_byte gray_high = (gray >> 8) & 0xff;
3697 png_byte gray_low = gray & 0xff;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003698 sp = row + row_info->rowbytes - 1;
3699 dp = row + (row_info->rowbytes << 1) - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003700 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003701 {
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06003702 if (*(sp - 1) == gray_high && *(sp) == gray_low)
Guy Schalnat0d580581995-07-20 02:43:20 -05003703 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003704 *dp-- = 0;
3705 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003706 }
3707 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003708 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003709 *dp-- = 0xff;
3710 *dp-- = 0xff;
Guy Schalnat0d580581995-07-20 02:43:20 -05003711 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003712 *dp-- = *sp--;
3713 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003714 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003715 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003716
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003717 row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
3718 row_info->channels = 2;
3719 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003720 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
3721 row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003722 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003723 }
3724 else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
3725 {
3726 if (row_info->bit_depth == 8)
3727 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003728 png_byte red = trans_value->red & 0xff;
3729 png_byte green = trans_value->green & 0xff;
3730 png_byte blue = trans_value->blue & 0xff;
Guy Schalnat0d580581995-07-20 02:43:20 -05003731 sp = row + (png_size_t)row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003732 dp = row + (png_size_t)(row_width << 2) - 1;
3733 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003734 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003735 if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05003736 *dp-- = 0;
3737 else
3738 *dp-- = 0xff;
3739 *dp-- = *sp--;
3740 *dp-- = *sp--;
3741 *dp-- = *sp--;
3742 }
3743 }
3744 else if (row_info->bit_depth == 16)
3745 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003746 png_byte red_high = (trans_value->red >> 8) & 0xff;
3747 png_byte green_high = (trans_value->green >> 8) & 0xff;
3748 png_byte blue_high = (trans_value->blue >> 8) & 0xff;
3749 png_byte red_low = trans_value->red & 0xff;
3750 png_byte green_low = trans_value->green & 0xff;
3751 png_byte blue_low = trans_value->blue & 0xff;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003752 sp = row + row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003753 dp = row + (png_size_t)(row_width << 3) - 1;
3754 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003755 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003756 if (*(sp - 5) == red_high &&
3757 *(sp - 4) == red_low &&
3758 *(sp - 3) == green_high &&
3759 *(sp - 2) == green_low &&
3760 *(sp - 1) == blue_high &&
3761 *(sp ) == blue_low)
Guy Schalnat0d580581995-07-20 02:43:20 -05003762 {
3763 *dp-- = 0;
3764 *dp-- = 0;
3765 }
3766 else
3767 {
3768 *dp-- = 0xff;
3769 *dp-- = 0xff;
3770 }
3771 *dp-- = *sp--;
3772 *dp-- = *sp--;
3773 *dp-- = *sp--;
3774 *dp-- = *sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003775 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003776 *dp-- = *sp--;
3777 }
3778 }
3779 row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
3780 row_info->channels = 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003781 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003782 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003783 }
3784 }
3785}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003786#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003787
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003788#ifdef PNG_READ_DITHER_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003789void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003790png_do_dither(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003791 png_bytep palette_lookup, png_bytep dither_lookup)
Guy Schalnat0d580581995-07-20 02:43:20 -05003792{
Guy Schalnat6d764711995-12-19 03:22:19 -06003793 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003794 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003795 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003796
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003797 png_debug(1, "in png_do_dither");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05003798
Guy Schalnat0d580581995-07-20 02:43:20 -05003799 {
3800 if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
3801 palette_lookup && row_info->bit_depth == 8)
3802 {
3803 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003804 sp = row;
3805 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003806 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003807 {
3808 r = *sp++;
3809 g = *sp++;
3810 b = *sp++;
3811
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003812 /* This looks real messy, but the compiler will reduce
3813 * it down to a reasonable formula. For example, with
3814 * 5 bits per color, we get:
3815 * p = (((r >> 3) & 0x1f) << 10) |
3816 * (((g >> 3) & 0x1f) << 5) |
3817 * ((b >> 3) & 0x1f);
3818 */
Guy Schalnat0d580581995-07-20 02:43:20 -05003819 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
3820 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
3821 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3822 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003823 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003824 (PNG_DITHER_BLUE_BITS)) |
3825 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3826 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3827
3828 *dp++ = palette_lookup[p];
3829 }
3830 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3831 row_info->channels = 1;
3832 row_info->pixel_depth = row_info->bit_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003833 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003834 }
3835 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
Andreas Dilger47a0c421997-05-16 02:46:07 -05003836 palette_lookup != NULL && row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003837 {
3838 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003839 sp = row;
3840 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003841 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003842 {
3843 r = *sp++;
3844 g = *sp++;
3845 b = *sp++;
3846 sp++;
3847
3848 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003849 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003850 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3851 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
3852 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
3853 (PNG_DITHER_BLUE_BITS)) |
3854 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3855 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3856
3857 *dp++ = palette_lookup[p];
3858 }
3859 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3860 row_info->channels = 1;
3861 row_info->pixel_depth = row_info->bit_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003862 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003863 }
3864 else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
3865 dither_lookup && row_info->bit_depth == 8)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003866 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003867 sp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003868 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003869 {
3870 *sp = dither_lookup[*sp];
3871 }
3872 }
3873 }
3874}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003875#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003876
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003877#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003878#ifdef PNG_READ_GAMMA_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003879static PNG_CONST int png_gamma_shift[] =
3880 {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0, 0x00};
Guy Schalnat0d580581995-07-20 02:43:20 -05003881
Andreas Dilger47a0c421997-05-16 02:46:07 -05003882/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003883 * tables, we don't make a full table if we are reducing to 8-bit in
3884 * the future. Note also how the gamma_16 tables are segmented so that
3885 * we don't need to allocate > 64K chunks for a full 16-bit table.
Glenn Randers-Pehrsonbc7156d2009-07-06 09:11:54 -05003886 *
3887 * See the PNG extensions document for an integer algorithm for creating
3888 * the gamma tables. Maybe we will implement that here someday.
3889 *
3890 * We should only reach this point if
3891 *
3892 * the file_gamma is known (i.e., the gAMA or sRGB chunk is present,
3893 * or the application has provided a file_gamma)
3894 *
3895 * AND
3896 * {
3897 * the screen_gamma is known
3898 *
3899 * OR
3900 *
3901 * RGB_to_gray transformation is being performed
3902 * }
3903 *
3904 * AND
3905 * {
3906 * the screen_gamma is different from the reciprocal of the
3907 * file_gamma by more than the specified threshold
3908 *
3909 * OR
3910 *
3911 * a background color has been specified and the file_gamma
3912 * and screen_gamma are not 1.0, within the specified threshold.
3913 * }
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003914 */
Glenn Randers-Pehrsona2567be2009-10-19 20:31:31 -05003915
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003916void /* PRIVATE */
Glenn Randers-Pehrsonffa89242009-12-13 08:14:40 -06003917png_build_gamma_table(png_structp png_ptr, png_byte bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05003918{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003919 png_debug(1, "in png_build_gamma_table");
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003920
Glenn Randers-Pehrsonffa89242009-12-13 08:14:40 -06003921 if (bit_depth <= 8)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003922 {
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003923 int i;
3924 double g;
Guy Schalnat0d580581995-07-20 02:43:20 -05003925
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003926 if (png_ptr->screen_gamma > .000001)
3927 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003928
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003929 else
3930 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003931
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003932 png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
3933 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05003934
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003935 for (i = 0; i < 256; i++)
3936 {
3937 png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
3938 g) * 255.0 + .5);
3939 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003940
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003941#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003942 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
3943 if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
3944 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003945
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003946 g = 1.0 / (png_ptr->gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05003947
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003948 png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
3949 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05003950
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003951 for (i = 0; i < 256; i++)
3952 {
3953 png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
3954 g) * 255.0 + .5);
3955 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003956
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003957
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003958 png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
3959 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05003960
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003961 if (png_ptr->screen_gamma > 0.000001)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003962 g = 1.0 / png_ptr->screen_gamma;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003963
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003964 else
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003965 g = png_ptr->gamma; /* Probably doing rgb_to_gray */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003966
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003967 for (i = 0; i < 256; i++)
3968 {
3969 png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
3970 g) * 255.0 + .5);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003971
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003972 }
3973 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003974#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003975 }
3976 else
3977 {
3978 double g;
3979 int i, j, shift, num;
3980 int sig_bit;
3981 png_uint_32 ig;
Guy Schalnat0d580581995-07-20 02:43:20 -05003982
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003983 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
3984 {
3985 sig_bit = (int)png_ptr->sig_bit.red;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003986
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003987 if ((int)png_ptr->sig_bit.green > sig_bit)
3988 sig_bit = png_ptr->sig_bit.green;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003989
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003990 if ((int)png_ptr->sig_bit.blue > sig_bit)
3991 sig_bit = png_ptr->sig_bit.blue;
3992 }
3993 else
3994 {
3995 sig_bit = (int)png_ptr->sig_bit.gray;
3996 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003997
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003998 if (sig_bit > 0)
3999 shift = 16 - sig_bit;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004000
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004001 else
4002 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05004003
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004004 if (png_ptr->transformations & PNG_16_TO_8)
4005 {
4006 if (shift < (16 - PNG_MAX_GAMMA_8))
4007 shift = (16 - PNG_MAX_GAMMA_8);
4008 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004009
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004010 if (shift > 8)
4011 shift = 8;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004012
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004013 if (shift < 0)
4014 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05004015
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004016 png_ptr->gamma_shift = (png_byte)shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05004017
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004018 num = (1 << (8 - shift));
Guy Schalnat0d580581995-07-20 02:43:20 -05004019
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004020 if (png_ptr->screen_gamma > .000001)
4021 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
4022 else
4023 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05004024
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06004025 png_ptr->gamma_16_table = (png_uint_16pp)png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004026 (png_uint_32)(num * png_sizeof(png_uint_16p)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004027
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004028 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
4029 {
4030 double fin, fout;
4031 png_uint_32 last, max;
Guy Schalnat0d580581995-07-20 02:43:20 -05004032
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004033 for (i = 0; i < num; i++)
4034 {
4035 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004036 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004037 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004038
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004039 g = 1.0 / g;
4040 last = 0;
4041 for (i = 0; i < 256; i++)
4042 {
4043 fout = ((double)i + 0.5) / 256.0;
4044 fin = pow(fout, g);
4045 max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
4046 while (last <= max)
4047 {
4048 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4049 [(int)(last >> (8 - shift))] = (png_uint_16)(
4050 (png_uint_16)i | ((png_uint_16)i << 8));
4051 last++;
4052 }
4053 }
4054 while (last < ((png_uint_32)num << 8))
4055 {
4056 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4057 [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
4058 last++;
4059 }
4060 }
4061 else
4062 {
4063 for (i = 0; i < num; i++)
4064 {
4065 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004066 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004067
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004068 ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004069
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004070 for (j = 0; j < 256; j++)
4071 {
4072 png_ptr->gamma_16_table[i][j] =
4073 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4074 65535.0, g) * 65535.0 + .5);
4075 }
4076 }
4077 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004078
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004079#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004080 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4081 if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
4082 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004083
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004084 g = 1.0 / (png_ptr->gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05004085
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06004086 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004087 (png_uint_32)(num * png_sizeof(png_uint_16p )));
Guy Schalnat0d580581995-07-20 02:43:20 -05004088
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004089 for (i = 0; i < num; i++)
4090 {
4091 png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004092 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004093
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004094 ig = (((png_uint_32)i *
4095 (png_uint_32)png_gamma_shift[shift]) >> 4);
4096 for (j = 0; j < 256; j++)
4097 {
4098 png_ptr->gamma_16_to_1[i][j] =
4099 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4100 65535.0, g) * 65535.0 + .5);
4101 }
4102 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004103
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004104 if (png_ptr->screen_gamma > 0.000001)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004105 g = 1.0 / png_ptr->screen_gamma;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004106
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004107 else
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05004108 g = png_ptr->gamma; /* Probably doing rgb_to_gray */
Guy Schalnat0d580581995-07-20 02:43:20 -05004109
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06004110 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004111 (png_uint_32)(num * png_sizeof(png_uint_16p)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004112
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004113 for (i = 0; i < num; i++)
4114 {
4115 png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004116 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004117
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004118 ig = (((png_uint_32)i *
4119 (png_uint_32)png_gamma_shift[shift]) >> 4);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004120
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004121 for (j = 0; j < 256; j++)
4122 {
4123 png_ptr->gamma_16_from_1[i][j] =
4124 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4125 65535.0, g) * 65535.0 + .5);
4126 }
4127 }
4128 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004129#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004130 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004131}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004132#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06004133/* To do: install integer version of png_build_gamma_table here */
4134#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004135
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05004136#ifdef PNG_MNG_FEATURES_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05004137/* Undoes intrapixel differencing */
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004138void /* PRIVATE */
4139png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
4140{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05004141 png_debug(1, "in png_do_read_intrapixel");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -05004142
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004143 if (
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004144 (row_info->color_type & PNG_COLOR_MASK_COLOR))
4145 {
4146 int bytes_per_pixel;
4147 png_uint_32 row_width = row_info->width;
4148 if (row_info->bit_depth == 8)
4149 {
4150 png_bytep rp;
4151 png_uint_32 i;
4152
4153 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4154 bytes_per_pixel = 3;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004155
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004156 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4157 bytes_per_pixel = 4;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004158
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004159 else
4160 return;
4161
4162 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4163 {
4164 *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff);
4165 *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff);
4166 }
4167 }
4168 else if (row_info->bit_depth == 16)
4169 {
4170 png_bytep rp;
4171 png_uint_32 i;
4172
4173 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4174 bytes_per_pixel = 6;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004175
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004176 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4177 bytes_per_pixel = 8;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004178
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004179 else
4180 return;
4181
4182 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4183 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004184 png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1);
4185 png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3);
4186 png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5);
4187 png_uint_32 red = (png_uint_32)((s0 + s1 + 65536L) & 0xffffL);
4188 png_uint_32 blue = (png_uint_32)((s2 + s1 + 65536L) & 0xffffL);
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05004189 *(rp ) = (png_byte)((red >> 8) & 0xff);
4190 *(rp+1) = (png_byte)(red & 0xff);
4191 *(rp+4) = (png_byte)((blue >> 8) & 0xff);
4192 *(rp+5) = (png_byte)(blue & 0xff);
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004193 }
4194 }
4195 }
4196}
4197#endif /* PNG_MNG_FEATURES_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004198#endif /* PNG_READ_SUPPORTED */