blob: f1a2b6ad1206c1d7f940f30c23ceef0cde2407bd [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-Pehrson668af4e2009-06-24 06:35:59 -05004 * Last changed in libpng 1.4.0 [June 24, 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-Pehrson3e61d792009-06-24 09:31:28 -05009 * This code is released under the zlib-libpng license.
10 * For conditions of distribution and use, see copyright notice in png.h
11 *
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -060012 * This file contains functions optionally called by an application
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060013 * in order to tell libpng how to handle data when reading a PNG.
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050014 * Transformations that are used in both reading and writing are
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060015 * in pngtrans.c.
16 */
Guy Schalnat0d580581995-07-20 02:43:20 -050017
Guy Schalnat0d580581995-07-20 02:43:20 -050018#include "png.h"
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060019#if defined(PNG_READ_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050020#include "pngpriv.h"
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060021
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060022/* Set the action on getting a CRC error for an ancillary or critical chunk. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050023void PNGAPI
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060024png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
25{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -050026 png_debug(1, "in png_set_crc_action");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060027 /* Tell libpng how we react to CRC errors in critical chunks */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050028 if (png_ptr == NULL)
29 return;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060030 switch (crit_action)
31 {
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050032 case PNG_CRC_NO_CHANGE: /* Leave setting as is */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060033 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050034
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050035 case PNG_CRC_WARN_USE: /* Warn/use data */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060036 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
37 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
38 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050039
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050040 case PNG_CRC_QUIET_USE: /* Quiet/use data */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060041 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
42 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
43 PNG_FLAG_CRC_CRITICAL_IGNORE;
44 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050045
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050046 case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050047 png_warning(png_ptr,
48 "Can't discard critical data on CRC error");
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050049 case PNG_CRC_ERROR_QUIT: /* Error/quit */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050050
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060051 case PNG_CRC_DEFAULT:
52 default:
53 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
54 break;
55 }
56
57 switch (ancil_action)
58 {
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050059 case PNG_CRC_NO_CHANGE: /* Leave setting as is */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060060 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050061
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050062 case PNG_CRC_WARN_USE: /* Warn/use data */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060063 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
64 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
65 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_QUIET_USE: /* Quiet/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 PNG_FLAG_CRC_ANCILLARY_NOWARN;
71 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050072
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050073 case PNG_CRC_ERROR_QUIT: /* Error/quit */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060074 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
75 png_ptr->flags |= 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_WARN_DISCARD: /* Warn/discard data */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050079
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060080 case PNG_CRC_DEFAULT:
81 default:
82 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
83 break;
84 }
85}
86
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060087#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
88 defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050089/* Handle alpha and tRNS via a background color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050090void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060091png_set_background(png_structp png_ptr,
92 png_color_16p background_color, int background_gamma_code,
Guy Schalnat51f0eb41995-09-26 05:22:39 -050093 int need_expand, double background_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -050094{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -050095 png_debug(1, "in png_set_background");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050096 if (png_ptr == NULL)
97 return;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060098 if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
99 {
100 png_warning(png_ptr, "Application must supply a known background gamma");
101 return;
102 }
103
Guy Schalnat0d580581995-07-20 02:43:20 -0500104 png_ptr->transformations |= PNG_BACKGROUND;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500105 png_memcpy(&(png_ptr->background), background_color,
106 png_sizeof(png_color_16));
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500107 png_ptr->background_gamma = (float)background_gamma;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600108 png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
Guy Schalnate5a37791996-06-05 15:50:50 -0500109 png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500110}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500111#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500112
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500113#if defined(PNG_READ_16_TO_8_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500114/* Strip 16 bit depth files to 8 bit depth */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500115void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600116png_set_strip_16(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500117{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500118 png_debug(1, "in png_set_strip_16");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500119 if (png_ptr == NULL)
120 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500121 png_ptr->transformations |= PNG_16_TO_8;
122}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500123#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500124
Andreas Dilger47a0c421997-05-16 02:46:07 -0500125#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500126void PNGAPI
Andreas Dilger47a0c421997-05-16 02:46:07 -0500127png_set_strip_alpha(png_structp png_ptr)
128{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500129 png_debug(1, "in png_set_strip_alpha");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500130 if (png_ptr == NULL)
131 return;
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -0600132 png_ptr->flags |= PNG_FLAG_STRIP_ALPHA;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500133}
134#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500135
Glenn Randers-Pehrson41983602008-08-18 21:52:21 -0500136#if defined(PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED)
137void PNGAPI
138png_set_premultiply_alpha(png_structp png_ptr)
139{
Glenn Randers-Pehrsond6d80752008-12-02 09:49:43 -0600140 png_debug(1, "in png_set_premultiply_alpha");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500141 if(png_ptr == NULL)
142 return;
Glenn Randers-Pehrson41983602008-08-18 21:52:21 -0500143 png_ptr->transformations |=
144 (PNG_PREMULTIPLY_ALPHA | PNG_EXPAND_tRNS);
145 png_ptr->transformations |=
146 PNG_EXPAND; /* This shouldn't be necessary */
147 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
148}
149#endif
150
Andreas Dilger47a0c421997-05-16 02:46:07 -0500151#if defined(PNG_READ_DITHER_SUPPORTED)
152/* Dither file to 8 bit. Supply a palette, the current number
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600153 * of elements in the palette, the maximum number of elements
154 * allowed, and a histogram if possible. If the current number
155 * of colors is greater then the maximum number, the palette will be
156 * modified to fit in the maximum number. "full_dither" indicates
157 * whether we need a dithering cube set up for RGB images, or if we
158 * simply are reducing the number of colors in a paletted image.
159 */
Guy Schalnat6d764711995-12-19 03:22:19 -0600160
161typedef struct png_dsort_struct
Guy Schalnat0d580581995-07-20 02:43:20 -0500162{
Guy Schalnat6d764711995-12-19 03:22:19 -0600163 struct png_dsort_struct FAR * next;
Guy Schalnat0d580581995-07-20 02:43:20 -0500164 png_byte left;
165 png_byte right;
Guy Schalnat6d764711995-12-19 03:22:19 -0600166} png_dsort;
167typedef png_dsort FAR * png_dsortp;
168typedef png_dsort FAR * FAR * png_dsortpp;
Guy Schalnat0d580581995-07-20 02:43:20 -0500169
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500170void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600171png_set_dither(png_structp png_ptr, png_colorp palette,
172 int num_palette, int maximum_colors, png_uint_16p histogram,
Guy Schalnat0d580581995-07-20 02:43:20 -0500173 int full_dither)
174{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500175 png_debug(1, "in png_set_dither");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500176 if (png_ptr == NULL)
177 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500178 png_ptr->transformations |= PNG_DITHER;
179
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600180 if (!full_dither)
Guy Schalnat0d580581995-07-20 02:43:20 -0500181 {
182 int i;
183
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600184 png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500185 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500186 for (i = 0; i < num_palette; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600187 png_ptr->dither_index[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500188 }
189
190 if (num_palette > maximum_colors)
191 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500192 if (histogram != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500193 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500194 /* This is easy enough, just throw out the least used colors.
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500195 * Perhaps not the best solution, but good enough.
196 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500197
198 int i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500199
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500200 /* Initialize an array to sort colors */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500201 png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500202 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500203
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500204 /* Initialize the dither_sort array */
Guy Schalnat0d580581995-07-20 02:43:20 -0500205 for (i = 0; i < num_palette; i++)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500206 png_ptr->dither_sort[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500207
Andreas Dilger47a0c421997-05-16 02:46:07 -0500208 /* Find the least used palette entries by starting a
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500209 * bubble sort, and running it until we have sorted
210 * out enough colors. Note that we don't care about
211 * sorting all the colors, just finding which are
212 * least used.
213 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500214
215 for (i = num_palette - 1; i >= maximum_colors; i--)
216 {
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500217 int done; /* To stop early if the list is pre-sorted */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600218 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500219
220 done = 1;
221 for (j = 0; j < i; j++)
222 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500223 if (histogram[png_ptr->dither_sort[j]]
224 < histogram[png_ptr->dither_sort[j + 1]])
Guy Schalnat0d580581995-07-20 02:43:20 -0500225 {
226 png_byte t;
227
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500228 t = png_ptr->dither_sort[j];
229 png_ptr->dither_sort[j] = png_ptr->dither_sort[j + 1];
230 png_ptr->dither_sort[j + 1] = t;
Guy Schalnat0d580581995-07-20 02:43:20 -0500231 done = 0;
232 }
233 }
234 if (done)
235 break;
236 }
237
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500238 /* Swap the palette around, and set up a table, if necessary */
Guy Schalnat0d580581995-07-20 02:43:20 -0500239 if (full_dither)
240 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500241 int j = num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500242
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500243 /* Put all the useful colors within the max, but don't
244 * move the others.
245 */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500246 for (i = 0; i < maximum_colors; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500247 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500248 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500249 {
250 do
251 j--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500252 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
Guy Schalnat0d580581995-07-20 02:43:20 -0500253 palette[i] = palette[j];
254 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600255 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500256 }
257 else
258 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500259 int j = num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500260
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500261 /* Move all the used colors inside the max limit, and
262 * develop a translation table.
263 */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500264 for (i = 0; i < maximum_colors; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500265 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500266 /* Only move the colors we need to */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500267 if ((int)png_ptr->dither_sort[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500268 {
269 png_color tmp_color;
270
271 do
272 j--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500273 while ((int)png_ptr->dither_sort[j] >= maximum_colors);
Guy Schalnat0d580581995-07-20 02:43:20 -0500274
275 tmp_color = palette[j];
276 palette[j] = palette[i];
277 palette[i] = tmp_color;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500278 /* Indicate where the color went */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600279 png_ptr->dither_index[j] = (png_byte)i;
280 png_ptr->dither_index[i] = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500281 }
282 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500283
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500284 /* Find closest color for those colors we are not using */
Guy Schalnat0d580581995-07-20 02:43:20 -0500285 for (i = 0; i < num_palette; i++)
286 {
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600287 if ((int)png_ptr->dither_index[i] >= maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500288 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500289 int min_d, k, min_k, d_index;
Guy Schalnat0d580581995-07-20 02:43:20 -0500290
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500291 /* Find the closest color to one we threw out */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500292 d_index = png_ptr->dither_index[i];
293 min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
294 for (k = 1, min_k = 0; k < maximum_colors; k++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500295 {
296 int d;
297
Andreas Dilger47a0c421997-05-16 02:46:07 -0500298 d = PNG_COLOR_DIST(palette[d_index], palette[k]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500299
300 if (d < min_d)
301 {
302 min_d = d;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500303 min_k = k;
Guy Schalnat0d580581995-07-20 02:43:20 -0500304 }
305 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500306 /* Point to closest color */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500307 png_ptr->dither_index[i] = (png_byte)min_k;
Guy Schalnat0d580581995-07-20 02:43:20 -0500308 }
309 }
310 }
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500311 png_free(png_ptr, png_ptr->dither_sort);
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500312 png_ptr->dither_sort = NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500313 }
314 else
315 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500316 /* This is much harder to do simply (and quickly). Perhaps
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500317 * we need to go through a median cut routine, but those
318 * don't always behave themselves with only a few colors
319 * as input. So we will just find the closest two colors,
320 * and throw out one of them (chosen somewhat randomly).
321 * [We don't understand this at all, so if someone wants to
322 * work on improving it, be our guest - AED, GRP]
323 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500324 int i;
325 int max_d;
326 int num_new_palette;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500327 png_dsortp t;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600328 png_dsortpp hash;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500329
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500330 t = NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500331
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500332 /* Initialize palette index arrays */
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500333 png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500334 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500335 png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500336 (png_uint_32)(num_palette * png_sizeof(png_byte)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500337
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500338 /* Initialize the sort array */
Guy Schalnat0d580581995-07-20 02:43:20 -0500339 for (i = 0; i < num_palette; i++)
340 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500341 png_ptr->index_to_palette[i] = (png_byte)i;
342 png_ptr->palette_to_index[i] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500343 }
344
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -0600345#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600346 hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 *
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500347 png_sizeof(png_dsortp)));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -0600348#else
349 hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 *
350 png_sizeof(png_dsortp)));
351 png_memset(hash, 0, 769 * png_sizeof(png_dsortp));
352#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500353
354 num_new_palette = num_palette;
355
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500356 /* Initial wild guess at how far apart the farthest pixel
357 * pair we will be eliminating will be. Larger
358 * numbers mean more areas will be allocated, Smaller
359 * numbers run the risk of not saving enough data, and
360 * having to do this all over again.
361 *
362 * I have not done extensive checking on this number.
363 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500364 max_d = 96;
365
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600366 while (num_new_palette > maximum_colors)
Guy Schalnat0d580581995-07-20 02:43:20 -0500367 {
368 for (i = 0; i < num_new_palette - 1; i++)
369 {
370 int j;
371
372 for (j = i + 1; j < num_new_palette; j++)
373 {
374 int d;
375
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600376 d = PNG_COLOR_DIST(palette[i], palette[j]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500377
378 if (d <= max_d)
379 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500380
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500381 t = (png_dsortp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500382 (png_uint_32)(png_sizeof(png_dsort)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500383 if (t == NULL)
384 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500385 t->next = hash[d];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600386 t->left = (png_byte)i;
387 t->right = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500388 hash[d] = t;
389 }
390 }
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500391 if (t == NULL)
392 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500393 }
394
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500395 if (t != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500396 for (i = 0; i <= max_d; i++)
397 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500398 if (hash[i] != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500399 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600400 png_dsortp p;
Guy Schalnat0d580581995-07-20 02:43:20 -0500401
402 for (p = hash[i]; p; p = p->next)
403 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500404 if ((int)png_ptr->index_to_palette[p->left]
405 < num_new_palette &&
406 (int)png_ptr->index_to_palette[p->right]
407 < num_new_palette)
Guy Schalnat0d580581995-07-20 02:43:20 -0500408 {
409 int j, next_j;
410
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600411 if (num_new_palette & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -0500412 {
413 j = p->left;
414 next_j = p->right;
415 }
416 else
417 {
418 j = p->right;
419 next_j = p->left;
420 }
421
422 num_new_palette--;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500423 palette[png_ptr->index_to_palette[j]]
424 = palette[num_new_palette];
Guy Schalnat0d580581995-07-20 02:43:20 -0500425 if (!full_dither)
426 {
427 int k;
428
429 for (k = 0; k < num_palette; k++)
430 {
431 if (png_ptr->dither_index[k] ==
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500432 png_ptr->index_to_palette[j])
Guy Schalnat0d580581995-07-20 02:43:20 -0500433 png_ptr->dither_index[k] =
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500434 png_ptr->index_to_palette[next_j];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600435 if ((int)png_ptr->dither_index[k] ==
Guy Schalnat0d580581995-07-20 02:43:20 -0500436 num_new_palette)
437 png_ptr->dither_index[k] =
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500438 png_ptr->index_to_palette[j];
Guy Schalnat0d580581995-07-20 02:43:20 -0500439 }
440 }
441
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500442 png_ptr->index_to_palette[png_ptr->palette_to_index
443 [num_new_palette]] = png_ptr->index_to_palette[j];
444 png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
445 = png_ptr->palette_to_index[num_new_palette];
Guy Schalnat0d580581995-07-20 02:43:20 -0500446
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500447 png_ptr->index_to_palette[j] = (png_byte)num_new_palette;
448 png_ptr->palette_to_index[num_new_palette] = (png_byte)j;
Guy Schalnat0d580581995-07-20 02:43:20 -0500449 }
450 if (num_new_palette <= maximum_colors)
451 break;
452 }
453 if (num_new_palette <= maximum_colors)
454 break;
455 }
456 }
457
458 for (i = 0; i < 769; i++)
459 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500460 if (hash[i] != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -0500461 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500462 png_dsortp p = hash[i];
Guy Schalnat0d580581995-07-20 02:43:20 -0500463 while (p)
464 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500465 t = p->next;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600466 png_free(png_ptr, p);
Guy Schalnat0d580581995-07-20 02:43:20 -0500467 p = t;
468 }
469 }
470 hash[i] = 0;
471 }
472 max_d += 96;
473 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600474 png_free(png_ptr, hash);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500475 png_free(png_ptr, png_ptr->palette_to_index);
476 png_free(png_ptr, png_ptr->index_to_palette);
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500477 png_ptr->palette_to_index = NULL;
478 png_ptr->index_to_palette = NULL;
Guy Schalnat0d580581995-07-20 02:43:20 -0500479 }
480 num_palette = maximum_colors;
481 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500482 if (png_ptr->palette == NULL)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600483 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500484 png_ptr->palette = palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500485 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600486 png_ptr->num_palette = (png_uint_16)num_palette;
Guy Schalnat0d580581995-07-20 02:43:20 -0500487
488 if (full_dither)
489 {
490 int i;
Guy Schalnat6d764711995-12-19 03:22:19 -0600491 png_bytep distance;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500492 int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600493 PNG_DITHER_BLUE_BITS;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500494 int num_red = (1 << PNG_DITHER_RED_BITS);
495 int num_green = (1 << PNG_DITHER_GREEN_BITS);
496 int num_blue = (1 << PNG_DITHER_BLUE_BITS);
497 png_size_t num_entries = ((png_size_t)1 << total_bits);
Guy Schalnat0d580581995-07-20 02:43:20 -0500498
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -0600499#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600500 png_ptr->palette_lookup = (png_bytep )png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500501 (png_uint_32)(num_entries * png_sizeof(png_byte)));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -0600502#else
503 png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
504 (png_uint_32)(num_entries * png_sizeof(png_byte)));
505 png_memset(png_ptr->palette_lookup, 0, num_entries *
506 png_sizeof(png_byte));
507#endif
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500508
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500509 distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
510 png_sizeof(png_byte)));
Glenn Randers-Pehrsone1eff582001-04-14 20:15:41 -0500511
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500512 png_memset(distance, 0xff, num_entries * png_sizeof(png_byte));
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500513
514 for (i = 0; i < num_palette; i++)
515 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500516 int ir, ig, ib;
517 int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
518 int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
519 int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
Guy Schalnat0d580581995-07-20 02:43:20 -0500520
521 for (ir = 0; ir < num_red; ir++)
522 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500523 /* int dr = abs(ir - r); */
524 int dr = ((ir > r) ? ir - r : r - ir);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500525 int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
Guy Schalnat0d580581995-07-20 02:43:20 -0500526
Guy Schalnat0d580581995-07-20 02:43:20 -0500527 for (ig = 0; ig < num_green; ig++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600528 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500529 /* int dg = abs(ig - g); */
530 int dg = ((ig > g) ? ig - g : g - ig);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500531 int dt = dr + dg;
532 int dm = ((dr > dg) ? dr : dg);
533 int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
Guy Schalnat0d580581995-07-20 02:43:20 -0500534
Guy Schalnat0d580581995-07-20 02:43:20 -0500535 for (ib = 0; ib < num_blue; ib++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600536 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500537 int d_index = index_g | ib;
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500538 /* int db = abs(ib - b); */
539 int db = ((ib > b) ? ib - b : b - ib);
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500540 int dmax = ((dm > db) ? dm : db);
541 int d = dmax + dt + db;
Guy Schalnat0d580581995-07-20 02:43:20 -0500542
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600543 if (d < (int)distance[d_index])
Guy Schalnat0d580581995-07-20 02:43:20 -0500544 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500545 distance[d_index] = (png_byte)d;
546 png_ptr->palette_lookup[d_index] = (png_byte)i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500547 }
548 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500549 }
550 }
551 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500552
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600553 png_free(png_ptr, distance);
Guy Schalnat0d580581995-07-20 02:43:20 -0500554 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500555}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500556#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500557
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600558#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600559/* Transform the image from the file_gamma to the screen_gamma. We
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600560 * only do transformations on images where the file_gamma and screen_gamma
561 * are not close reciprocals, otherwise it slows things down slightly, and
562 * also needlessly introduces small errors.
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600563 *
564 * We will turn off gamma transformation later if no semitransparent entries
565 * are present in the tRNS array for palette images. We can't do it here
566 * because we don't necessarily have the tRNS chunk yet.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600567 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500568void PNGAPI
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600569png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -0500570{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500571 png_debug(1, "in png_set_gamma");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500572 if (png_ptr == NULL)
573 return;
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600574 if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) ||
575 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) ||
576 (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
577 png_ptr->transformations |= PNG_GAMMA;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500578 png_ptr->gamma = (float)file_gamma;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600579 png_ptr->screen_gamma = (float)scrn_gamma;
Guy Schalnat0d580581995-07-20 02:43:20 -0500580}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500581#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500582
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500583#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -0500584/* Expand paletted images to RGB, expand grayscale images of
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500585 * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600586 * to alpha channels.
587 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500588void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600589png_set_expand(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500590{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500591 png_debug(1, "in png_set_expand");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500592 if (png_ptr == NULL)
593 return;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600594 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500595 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -0500596}
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500597
598/* GRR 19990627: the following three functions currently are identical
599 * to png_set_expand(). However, it is entirely reasonable that someone
600 * might wish to expand an indexed image to RGB but *not* expand a single,
601 * fully transparent palette entry to a full alpha channel--perhaps instead
602 * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
603 * the transparent color with a particular RGB value, or drop tRNS entirely.
604 * IOW, a future version of the library may make the transformations flag
605 * a bit more fine-grained, with separate bits for each of these three
606 * functions.
607 *
608 * More to the point, these functions make it obvious what libpng will be
609 * doing, whereas "expand" can (and does) mean any number of things.
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600610 *
611 * GRP 20060307: In libpng-1.4.0, png_set_gray_1_2_4_to_8() was modified
612 * to expand only the sample depth but not to expand the tRNS to alpha.
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500613 */
614
615/* Expand paletted images to RGB. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500616void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500617png_set_palette_to_rgb(png_structp png_ptr)
618{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500619 png_debug(1, "in png_set_palette_to_rgb");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500620 if (png_ptr == NULL)
621 return;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600622 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500623 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500624}
625
626/* Expand grayscale images of less than 8-bit depth to 8 bits. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500627void PNGAPI
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600628png_set_expand_gray_1_2_4_to_8(png_structp png_ptr)
629{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500630 png_debug(1, "in png_set_expand_gray_1_2_4_to_8");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500631 if (png_ptr == NULL)
632 return;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500633 png_ptr->transformations |= PNG_EXPAND;
634 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600635}
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500636
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500637
638
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500639/* Expand tRNS chunks to alpha channels. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500640void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500641png_set_tRNS_to_alpha(png_structp png_ptr)
642{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500643 png_debug(1, "in png_set_tRNS_to_alpha");
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600644 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500645 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500646}
647#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500648
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500649#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500650void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600651png_set_gray_to_rgb(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500652{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500653 png_debug(1, "in png_set_gray_to_rgb");
Guy Schalnat0d580581995-07-20 02:43:20 -0500654 png_ptr->transformations |= PNG_GRAY_TO_RGB;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500655 png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -0500656}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500657#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500658
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600659#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
660#if defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600661/* Convert a RGB image to a grayscale of the same width. This allows us,
662 * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600663 */
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600664
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500665void PNGAPI
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500666png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red,
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600667 double green)
668{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500669 int red_fixed = (int)((float)red*100000.0 + 0.5);
670 int green_fixed = (int)((float)green*100000.0 + 0.5);
671 if (png_ptr == NULL)
672 return;
673 png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed);
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600674}
675#endif
676
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500677void PNGAPI
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600678png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
679 png_fixed_point red, png_fixed_point green)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600680{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500681 png_debug(1, "in png_set_rgb_to_gray");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500682 if (png_ptr == NULL)
683 return;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600684 switch(error_action)
685 {
686 case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY;
687 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500688
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600689 case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
690 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500691
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600692 case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
693 }
694 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
695#if defined(PNG_READ_EXPAND_SUPPORTED)
696 png_ptr->transformations |= PNG_EXPAND;
697#else
698 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500699 png_warning(png_ptr,
700 "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED");
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600701 png_ptr->transformations &= ~PNG_RGB_TO_GRAY;
702 }
703#endif
704 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600705 png_uint_16 red_int, green_int;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500706 if (red < 0 || green < 0)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600707 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600708 red_int = 6968; /* .212671 * 32768 + .5 */
709 green_int = 23434; /* .715160 * 32768 + .5 */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600710 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500711 else if (red + green < 100000L)
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600712 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500713 red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
714 green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600715 }
716 else
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600717 {
718 png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600719 red_int = 6968;
720 green_int = 23434;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600721 }
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600722 png_ptr->rgb_to_gray_red_coeff = red_int;
723 png_ptr->rgb_to_gray_green_coeff = green_int;
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600724 png_ptr->rgb_to_gray_blue_coeff =
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500725 (png_uint_16)(32768 - red_int - green_int);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600726 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600727}
728#endif
729
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500730#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
Glenn Randers-Pehrson33188ac2009-06-16 14:12:35 -0500731 defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500732void PNGAPI
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600733png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
734 read_user_transform_fn)
735{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500736 png_debug(1, "in png_set_read_user_transform_fn");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500737 if (png_ptr == NULL)
738 return;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500739#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600740 png_ptr->transformations |= PNG_USER_TRANSFORM;
741 png_ptr->read_user_transform_fn = read_user_transform_fn;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500742#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600743}
744#endif
745
Andreas Dilger47a0c421997-05-16 02:46:07 -0500746/* Initialize everything needed for the read. This includes modifying
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600747 * the palette.
748 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500749void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -0600750png_init_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500751{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500752 png_debug(1, "in png_init_read_transformations");
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500753 {
754#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
755 || defined(PNG_READ_GAMMA_SUPPORTED)
756 int color_type = png_ptr->color_type;
757#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500758
Guy Schalnate5a37791996-06-05 15:50:50 -0500759#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500760
761#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
762 /* Detect gray background and attempt to enable optimization
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500763 * for gray --> RGB case
764 *
765 * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500766 * RGB_ALPHA (in which case need_expand is superfluous anyway), the
767 * background color might actually be gray yet not be flagged as such.
768 * This is not a problem for the current code, which uses
769 * PNG_BACKGROUND_IS_GRAY only to decide when to do the
770 * png_do_gray_to_rgb() transformation.
771 */
772 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
773 !(color_type & PNG_COLOR_MASK_COLOR))
774 {
775 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
776 } else if ((png_ptr->transformations & PNG_BACKGROUND) &&
777 !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
778 (png_ptr->transformations & PNG_GRAY_TO_RGB) &&
779 png_ptr->background.red == png_ptr->background.green &&
780 png_ptr->background.red == png_ptr->background.blue)
781 {
782 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
783 png_ptr->background.gray = png_ptr->background.red;
784 }
785#endif
786
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600787 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
788 (png_ptr->transformations & PNG_EXPAND))
Guy Schalnat0d580581995-07-20 02:43:20 -0500789 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500790 if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
Guy Schalnat0d580581995-07-20 02:43:20 -0500791 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500792 /* Expand background and tRNS chunks */
Guy Schalnat0d580581995-07-20 02:43:20 -0500793 switch (png_ptr->bit_depth)
794 {
795 case 1:
Guy Schalnate5a37791996-06-05 15:50:50 -0500796 png_ptr->background.gray *= (png_uint_16)0xff;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600797 png_ptr->background.red = png_ptr->background.green
798 = png_ptr->background.blue = png_ptr->background.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600799 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
800 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -0500801 png_ptr->trans_color.gray *= (png_uint_16)0xff;
802 png_ptr->trans_color.red = png_ptr->trans_color.green
803 = png_ptr->trans_color.blue = png_ptr->trans_color.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600804 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500805 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500806
Guy Schalnat0d580581995-07-20 02:43:20 -0500807 case 2:
Guy Schalnate5a37791996-06-05 15:50:50 -0500808 png_ptr->background.gray *= (png_uint_16)0x55;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600809 png_ptr->background.red = png_ptr->background.green
810 = png_ptr->background.blue = png_ptr->background.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600811 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
812 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -0500813 png_ptr->trans_color.gray *= (png_uint_16)0x55;
814 png_ptr->trans_color.red = png_ptr->trans_color.green
815 = png_ptr->trans_color.blue = png_ptr->trans_color.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600816 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500817 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500818
Guy Schalnat0d580581995-07-20 02:43:20 -0500819 case 4:
Guy Schalnate5a37791996-06-05 15:50:50 -0500820 png_ptr->background.gray *= (png_uint_16)0x11;
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600821 png_ptr->background.red = png_ptr->background.green
822 = png_ptr->background.blue = png_ptr->background.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600823 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
824 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -0500825 png_ptr->trans_color.gray *= (png_uint_16)0x11;
826 png_ptr->trans_color.red = png_ptr->trans_color.green
827 = png_ptr->trans_color.blue = png_ptr->trans_color.gray;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600828 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500829 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500830
Guy Schalnate5a37791996-06-05 15:50:50 -0500831 case 8:
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500832
Guy Schalnate5a37791996-06-05 15:50:50 -0500833 case 16:
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -0600834 png_ptr->background.red = png_ptr->background.green
835 = png_ptr->background.blue = png_ptr->background.gray;
Guy Schalnat0d580581995-07-20 02:43:20 -0500836 break;
837 }
838 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500839 else if (color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -0500840 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500841 png_ptr->background.red =
Guy Schalnat0d580581995-07-20 02:43:20 -0500842 png_ptr->palette[png_ptr->background.index].red;
843 png_ptr->background.green =
844 png_ptr->palette[png_ptr->background.index].green;
Guy Schalnate5a37791996-06-05 15:50:50 -0500845 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -0500846 png_ptr->palette[png_ptr->background.index].blue;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600847
848#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
849 if (png_ptr->transformations & PNG_INVERT_ALPHA)
850 {
851#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -0600852 if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600853#endif
854 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500855 /* Invert the alpha channel (in tRNS) unless the pixels are
856 * going to be expanded, in which case leave it for later
857 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500858 int i, istop;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500859 istop=(int)png_ptr->num_trans;
860 for (i=0; i<istop; i++)
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -0500861 png_ptr->trans[i] = (png_byte)(255 - png_ptr->trans[i]);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600862 }
863 }
864#endif
865
Guy Schalnat0d580581995-07-20 02:43:20 -0500866 }
867 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500868#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500869
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -0500870#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500871 png_ptr->background_1 = png_ptr->background;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500872#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600873#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600874
875 if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0)
876 && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0)
877 < PNG_GAMMA_THRESHOLD))
878 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500879 int i, k;
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600880 k=0;
881 for (i=0; i<png_ptr->num_trans; i++)
882 {
883 if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500884 k=1; /* Partial transparency is present */
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600885 }
886 if (k == 0)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500887 png_ptr->transformations &= ~PNG_GAMMA;
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -0600888 }
889
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600890 if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) &&
891 png_ptr->gamma != 0.0)
Guy Schalnat0d580581995-07-20 02:43:20 -0500892 {
893 png_build_gamma_table(png_ptr);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500894#if defined(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(
949 (double)png_ptr->background.red/255, gs) * 255.0 + .5);
950 back.green = (png_byte)(pow(
951 (double)png_ptr->background.green/255, gs) * 255.0 + .5);
952 back.blue = (png_byte)(pow(
953 (double)png_ptr->background.blue/255, 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(
957 (double)png_ptr->background.red/255, g) * 255.0 + .5);
958 back_1.green = (png_byte)(pow(
959 (double)png_ptr->background.green/255, g) * 255.0 + .5);
960 back_1.blue = (png_byte)(pow(
961 (double)png_ptr->background.blue/255, 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 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500965 if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
Guy Schalnate5a37791996-06-05 15:50:50 -0500966 {
967 if (png_ptr->trans[i] == 0)
968 {
969 palette[i] = back;
970 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500971 else /* if (png_ptr->trans[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];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500976 png_composite(w, v, png_ptr->trans[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];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500980 png_composite(w, v, png_ptr->trans[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];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500984 png_composite(w, v, png_ptr->trans[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-Pehrson145f5c82008-07-10 09:13:13 -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
1080 /* Done the gamma correction. */
1081 png_ptr->transformations &= ~PNG_GAMMA;
Guy Schalnate5a37791996-06-05 15:50:50 -05001082 }
1083 }
1084#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1085 else
1086#endif
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001087#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */
Guy Schalnate5a37791996-06-05 15:50:50 -05001088#if defined(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 {
1104 if (png_ptr->trans[i] == 0)
1105 {
1106 palette[i] = back;
1107 }
1108 else if (png_ptr->trans[i] != 0xff)
1109 {
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,
1112 png_ptr->trans[i], back.red);
1113 png_composite(palette[i].green, palette[i].green,
1114 png_ptr->trans[i], back.green);
1115 png_composite(palette[i].blue, palette[i].blue,
1116 png_ptr->trans[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
Guy Schalnat6d764711995-12-19 03:22:19 -06001126#if defined(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");
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001166#if defined(PNG_READ_EXPAND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001167 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001168 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001169 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1170 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001171 if (png_ptr->num_trans &&
1172 (png_ptr->transformations & PNG_EXPAND_tRNS))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001173 info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1174 else
1175 info_ptr->color_type = PNG_COLOR_TYPE_RGB;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001176 info_ptr->bit_depth = 8;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001177 info_ptr->num_trans = 0;
1178 }
1179 else
1180 {
1181 if (png_ptr->num_trans)
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -06001182 {
1183 if (png_ptr->transformations & PNG_EXPAND_tRNS)
1184 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -06001185 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001186 if (info_ptr->bit_depth < 8)
1187 info_ptr->bit_depth = 8;
1188 info_ptr->num_trans = 0;
1189 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001190 }
1191#endif
1192
1193#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1194 if (png_ptr->transformations & PNG_BACKGROUND)
1195 {
1196 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
1197 info_ptr->num_trans = 0;
1198 info_ptr->background = png_ptr->background;
1199 }
1200#endif
1201
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001202#if defined(PNG_READ_GAMMA_SUPPORTED)
1203 if (png_ptr->transformations & PNG_GAMMA)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001204 {
1205#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001206 info_ptr->gamma = png_ptr->gamma;
1207#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001208#ifdef PNG_FIXED_POINT_SUPPORTED
1209 info_ptr->int_gamma = png_ptr->int_gamma;
1210#endif
1211 }
1212#endif
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001213
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001214#if defined(PNG_READ_16_TO_8_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001215 if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001216 info_ptr->bit_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001217#endif
1218
Glenn Randers-Pehrsonddfebd32006-02-22 09:19:25 -06001219#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
1220 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
1221 info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
1222#endif
1223
1224#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1225 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1226 info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
1227#endif
1228
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001229#if defined(PNG_READ_DITHER_SUPPORTED)
1230 if (png_ptr->transformations & PNG_DITHER)
1231 {
1232 if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001233 (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
1234 png_ptr->palette_lookup && info_ptr->bit_depth == 8)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001235 {
1236 info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
1237 }
1238 }
1239#endif
1240
1241#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001242 if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001243 info_ptr->bit_depth = 8;
1244#endif
1245
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001246 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001247 info_ptr->channels = 1;
1248 else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
1249 info_ptr->channels = 3;
1250 else
1251 info_ptr->channels = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001252
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001253#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001254 if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001255 info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001256#endif
1257
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001258 if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
1259 info_ptr->channels++;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001260
1261#if defined(PNG_READ_FILLER_SUPPORTED)
1262 /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001263 if ((png_ptr->transformations & PNG_FILLER) &&
1264 ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
1265 (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001266 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001267 info_ptr->channels++;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001268 /* If adding a true alpha channel not just filler */
Glenn Randers-Pehrson67864af2004-08-28 23:30:07 -05001269 if (png_ptr->transformations & PNG_ADD_ALPHA)
1270 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001271 }
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001272#endif
1273
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001274#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
1275defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001276 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001277 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001278 if (info_ptr->bit_depth < png_ptr->user_transform_depth)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001279 info_ptr->bit_depth = png_ptr->user_transform_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001280 if (info_ptr->channels < png_ptr->user_transform_channels)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001281 info_ptr->channels = png_ptr->user_transform_channels;
1282 }
1283#endif
1284
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001285 info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
1286 info_ptr->bit_depth);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001287
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001288 info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width);
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05001289
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001290#if !defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001291 if (png_ptr)
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001292 return;
1293#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001294}
1295
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001296/* Transform the row. The order of transformations is significant,
1297 * and is very touchy. If you add a transformation, take care to
1298 * decide how it fits in with the other transformations here.
1299 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001300void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001301png_do_read_transformations(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05001302{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001303 png_debug(1, "in png_do_read_transformations");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001304 if (png_ptr->row_buf == NULL)
1305 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001306#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001307 char msg[50];
1308
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001309 png_snprintf2(msg, 50,
1310 "NULL row buffer for row %ld, pass %d", (long)png_ptr->row_number,
1311 png_ptr->pass);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001312 png_error(png_ptr, msg);
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001313#else
1314 png_error(png_ptr, "NULL row buffer");
1315#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001316 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001317#ifdef PNG_WARN_UNINITIALIZED_ROW
1318 if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
1319 /* Application has failed to call either png_read_start_image()
1320 * or png_read_update_info() after setting transforms that expand
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001321 * pixels. This check added to libpng-1.2.19
1322 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001323#if (PNG_WARN_UNINITIALIZED_ROW==1)
1324 png_error(png_ptr, "Uninitialized row");
1325#else
1326 png_warning(png_ptr, "Uninitialized row");
1327#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001328#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001329
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001330#if defined(PNG_READ_EXPAND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001331 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05001332 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001333 if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
1334 {
1335 png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
1336 png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
1337 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001338 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001339 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001340 if (png_ptr->num_trans &&
1341 (png_ptr->transformations & PNG_EXPAND_tRNS))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001342 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001343 &(png_ptr->trans_color));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001344 else
1345 png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
1346 NULL);
1347 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001348 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001349#endif
1350
1351#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001352 if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001353 png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson40936072004-11-20 11:18:40 -06001354 PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001355#endif
1356
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001357#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
1358 if (png_ptr->transformations & PNG_RGB_TO_GRAY)
1359 {
1360 int rgb_error =
1361 png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001362 if (rgb_error)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001363 {
1364 png_ptr->rgb_to_gray_status=1;
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06001365 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001366 PNG_RGB_TO_GRAY_WARN)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001367 png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001368 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
1369 PNG_RGB_TO_GRAY_ERR)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001370 png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
1371 }
1372 }
1373#endif
1374
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001375/* From Andreas Dilger e-mail to png-implement, 26 March 1998:
Glenn Randers-Pehrsond60c8862009-06-15 21:56:14 -05001376 *
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001377 * In most cases, the "simple transparency" should be done prior to doing
1378 * gray-to-RGB, or you will have to test 3x as many bytes to check if a
1379 * pixel is transparent. You would also need to make sure that the
1380 * transparency information is upgraded to RGB.
Glenn Randers-Pehrsond60c8862009-06-15 21:56:14 -05001381 *
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001382 * To summarize, the current flow is:
1383 * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
1384 * with background "in place" if transparent,
1385 * convert to RGB if necessary
1386 * - Gray + alpha -> composite with gray background and remove alpha bytes,
1387 * convert to RGB if necessary
1388 *
1389 * To support RGB backgrounds for gray images we need:
1390 * - Gray + simple transparency -> convert to RGB + simple transparency,
1391 * compare 3 or 6 bytes and composite with
1392 * background "in place" if transparent
1393 * (3x compare/pixel compared to doing
1394 * composite with gray bkgrnd)
1395 * - Gray + alpha -> convert to RGB + alpha, composite with background and
1396 * remove alpha bytes (3x float
1397 * operations/pixel compared with composite
1398 * on gray background)
1399 *
1400 * Greg's change will do this. The reason it wasn't done before is for
1401 * performance, as this increases the per-pixel operations. If we would check
1402 * in advance if the background was gray or RGB, and position the gray-to-RGB
1403 * transform appropriately, then it would save a lot of work/time.
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001404 */
1405
1406#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001407 /* If gray -> RGB, do so now only if background is non-gray; else do later
1408 * for performance reasons
1409 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001410 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001411 !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001412 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
1413#endif
1414
Glenn Randers-Pehrson6a9c2ce2009-03-27 19:30:10 -05001415#if defined(PNG_READ_16_TO_8_SUPPORTED)
1416 if (png_ptr->transformations & PNG_16_TO_8)
1417 png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
1418#endif
1419
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001420#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001421 if ((png_ptr->transformations & PNG_BACKGROUND) &&
1422 ((png_ptr->num_trans != 0 ) ||
1423 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
Guy Schalnat0d580581995-07-20 02:43:20 -05001424 png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001425 &(png_ptr->trans_color), &(png_ptr->background)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001426#if defined(PNG_READ_GAMMA_SUPPORTED)
1427 , &(png_ptr->background_1),
Guy Schalnat0d580581995-07-20 02:43:20 -05001428 png_ptr->gamma_table, png_ptr->gamma_from_1,
1429 png_ptr->gamma_to_1, png_ptr->gamma_16_table,
1430 png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05001431 png_ptr->gamma_shift
1432#endif
1433);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001434#endif
1435
1436#if defined(PNG_READ_GAMMA_SUPPORTED)
1437 if ((png_ptr->transformations & PNG_GAMMA) &&
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001438#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001439 !((png_ptr->transformations & PNG_BACKGROUND) &&
1440 ((png_ptr->num_trans != 0) ||
1441 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001442#endif
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001443 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
Guy Schalnat0d580581995-07-20 02:43:20 -05001444 png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001445 png_ptr->gamma_table, png_ptr->gamma_16_table,
1446 png_ptr->gamma_shift);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001447#endif
1448
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001449#if defined(PNG_READ_DITHER_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001450 if (png_ptr->transformations & PNG_DITHER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001451 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001452 png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
1453 png_ptr->palette_lookup, png_ptr->dither_index);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001454 if (png_ptr->row_info.rowbytes == (png_uint_32)0)
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001455 png_error(png_ptr, "png_do_dither returned rowbytes=0");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001456 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001457#endif
1458
1459#if defined(PNG_READ_INVERT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001460 if (png_ptr->transformations & PNG_INVERT_MONO)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001461 png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001462#endif
1463
1464#if defined(PNG_READ_SHIFT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001465 if (png_ptr->transformations & PNG_SHIFT)
1466 png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
1467 &(png_ptr->shift));
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001468#endif
1469
1470#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001471 if (png_ptr->transformations & PNG_PACK)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001472 png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001473#endif
1474
1475#if defined(PNG_READ_BGR_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001476 if (png_ptr->transformations & PNG_BGR)
1477 png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001478#endif
1479
Andreas Dilger47a0c421997-05-16 02:46:07 -05001480#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1481 if (png_ptr->transformations & PNG_PACKSWAP)
1482 png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
1483#endif
1484
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001485#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001486 /* If gray -> RGB, do so now only if we did not do so above */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001487 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
1488 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
Guy Schalnat0d580581995-07-20 02:43:20 -05001489 png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001490#endif
1491
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001492#if defined(PNG_READ_FILLER_SUPPORTED)
1493 if (png_ptr->transformations & PNG_FILLER)
1494 png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001495 (png_uint_32)png_ptr->filler, png_ptr->flags);
1496#endif
1497
Glenn Randers-Pehrson1916f6a2008-08-14 13:44:49 -05001498#if defined(PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED)
1499 if (png_ptr->transformations & PNG_PREMULTIPLY_ALPHA)
Glenn Randers-Pehrson8fb550c2009-03-21 08:15:32 -05001500 png_do_read_premultiply_alpha(&(png_ptr->row_info),
1501 png_ptr->row_buf + 1);
Glenn Randers-Pehrson1916f6a2008-08-14 13:44:49 -05001502#endif
1503
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001504#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
1505 if (png_ptr->transformations & PNG_INVERT_ALPHA)
1506 png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1507#endif
1508
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001509#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
1510 if (png_ptr->transformations & PNG_SWAP_ALPHA)
1511 png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
1512#endif
1513
Andreas Dilger47a0c421997-05-16 02:46:07 -05001514#if defined(PNG_READ_SWAP_SUPPORTED)
1515 if (png_ptr->transformations & PNG_SWAP_BYTES)
1516 png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001517#endif
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001518
1519#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1520 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001521 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001522 if (png_ptr->read_user_transform_fn != NULL)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001523 (*(png_ptr->read_user_transform_fn)) /* User read transform function */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001524 (png_ptr, /* png_ptr */
1525 &(png_ptr->row_info), /* row_info: */
1526 /* png_uint_32 width; width of row */
1527 /* png_uint_32 rowbytes; number of bytes in row */
1528 /* png_byte color_type; color type of pixels */
1529 /* png_byte bit_depth; bit depth of samples */
1530 /* png_byte channels; number of channels (1-4) */
1531 /* png_byte pixel_depth; bits per pixel (depth*channels) */
1532 png_ptr->row_buf + 1); /* start of pixel data for row */
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001533#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001534 if (png_ptr->user_transform_depth)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001535 png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001536 if (png_ptr->user_transform_channels)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001537 png_ptr->row_info.channels = png_ptr->user_transform_channels;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001538#endif
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001539 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
1540 png_ptr->row_info.channels);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001541 png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
1542 png_ptr->row_info.width);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001543 }
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001544#endif
1545
Guy Schalnat0d580581995-07-20 02:43:20 -05001546}
1547
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001548#if defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001549/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
1550 * without changing the actual values. Thus, if you had a row with
1551 * a bit depth of 1, you would end up with bytes that only contained
1552 * the numbers 0 or 1. If you would rather they contain 0 and 255, use
1553 * png_do_shift() after this.
1554 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001555void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001556png_do_unpack(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001557{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001558 png_debug(1, "in png_do_unpack");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001559 if (row_info->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05001560 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001561 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001562 png_uint_32 row_width=row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001563
Guy Schalnat0d580581995-07-20 02:43:20 -05001564 switch (row_info->bit_depth)
1565 {
1566 case 1:
1567 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001568 png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
1569 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001570 png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001571 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001572 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001573 *dp = (png_byte)((*sp >> shift) & 0x01);
Guy Schalnat0d580581995-07-20 02:43:20 -05001574 if (shift == 7)
1575 {
1576 shift = 0;
1577 sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001578 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001579 else
1580 shift++;
1581
1582 dp--;
1583 }
1584 break;
1585 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001586
Guy Schalnat0d580581995-07-20 02:43:20 -05001587 case 2:
1588 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001589
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001590 png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
1591 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001592 png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001593 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001594 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001595 *dp = (png_byte)((*sp >> shift) & 0x03);
Guy Schalnat0d580581995-07-20 02:43:20 -05001596 if (shift == 6)
1597 {
1598 shift = 0;
1599 sp--;
1600 }
1601 else
1602 shift += 2;
1603
1604 dp--;
1605 }
1606 break;
1607 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001608
Guy Schalnat0d580581995-07-20 02:43:20 -05001609 case 4:
1610 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001611 png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
1612 png_bytep dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001613 png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001614 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001615 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001616 *dp = (png_byte)((*sp >> shift) & 0x0f);
Guy Schalnat0d580581995-07-20 02:43:20 -05001617 if (shift == 4)
1618 {
1619 shift = 0;
1620 sp--;
1621 }
1622 else
1623 shift = 4;
1624
1625 dp--;
1626 }
1627 break;
1628 }
1629 }
1630 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001631 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001632 row_info->rowbytes = row_width * row_info->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001633 }
1634}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001635#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001636
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001637#if defined(PNG_READ_SHIFT_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001638/* Reverse the effects of png_do_shift. This routine merely shifts the
1639 * pixels back to their significant bits values. Thus, if you have
1640 * a row of bit depth 8, but only 5 are significant, this will shift
1641 * the values back to 0 through 31.
1642 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001643void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001644png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
Guy Schalnat0d580581995-07-20 02:43:20 -05001645{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001646 png_debug(1, "in png_do_unshift");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001647 if (
Andreas Dilger47a0c421997-05-16 02:46:07 -05001648 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001649 {
1650 int shift[4];
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001651 int channels = 0;
1652 int c;
1653 png_uint_16 value = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001654 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001655
Guy Schalnat0d580581995-07-20 02:43:20 -05001656 if (row_info->color_type & PNG_COLOR_MASK_COLOR)
1657 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001658 shift[channels++] = row_info->bit_depth - sig_bits->red;
1659 shift[channels++] = row_info->bit_depth - sig_bits->green;
1660 shift[channels++] = row_info->bit_depth - sig_bits->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05001661 }
1662 else
1663 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001664 shift[channels++] = row_info->bit_depth - sig_bits->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05001665 }
1666 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
1667 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001668 shift[channels++] = row_info->bit_depth - sig_bits->alpha;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001669 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001670
Andreas Dilger47a0c421997-05-16 02:46:07 -05001671 for (c = 0; c < channels; c++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001672 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001673 if (shift[c] <= 0)
1674 shift[c] = 0;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001675 else
1676 value = 1;
1677 }
Guy Schalnat0f716451995-11-28 11:22:13 -06001678
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001679 if (!value)
1680 return;
Guy Schalnat0f716451995-11-28 11:22:13 -06001681
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001682 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05001683 {
1684 case 2:
1685 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001686 png_bytep bp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001687 png_uint_32 i;
1688 png_uint_32 istop = row_info->rowbytes;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001689
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001690 for (bp = row, i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001691 {
1692 *bp >>= 1;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001693 *bp++ &= 0x55;
Guy Schalnat0d580581995-07-20 02:43:20 -05001694 }
1695 break;
1696 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001697
Guy Schalnat0d580581995-07-20 02:43:20 -05001698 case 4:
1699 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001700 png_bytep bp = row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001701 png_uint_32 i;
1702 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001703 png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
1704 (png_byte)((int)0xf >> shift[0]));
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001705
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001706 for (i = 0; i < istop; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001707 {
1708 *bp >>= shift[0];
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001709 *bp++ &= mask;
Guy Schalnat0d580581995-07-20 02:43:20 -05001710 }
1711 break;
1712 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001713
Guy Schalnat0d580581995-07-20 02:43:20 -05001714 case 8:
1715 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001716 png_bytep bp = row;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001717 png_uint_32 i;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001718 png_uint_32 istop = row_width * channels;
Guy Schalnat0d580581995-07-20 02:43:20 -05001719
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001720 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001721 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001722 *bp++ >>= shift[i%channels];
Guy Schalnat0d580581995-07-20 02:43:20 -05001723 }
1724 break;
1725 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001726
Guy Schalnat0d580581995-07-20 02:43:20 -05001727 case 16:
1728 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001729 png_bytep bp = row;
1730 png_uint_32 i;
1731 png_uint_32 istop = channels * row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001732
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001733 for (i = 0; i < istop; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001734 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001735 value = (png_uint_16)((*bp << 8) + *(bp + 1));
1736 value >>= shift[i%channels];
1737 *bp++ = (png_byte)(value >> 8);
1738 *bp++ = (png_byte)(value & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05001739 }
1740 break;
1741 }
1742 }
1743 }
1744}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001745#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001746
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001747#if defined(PNG_READ_16_TO_8_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001748/* Chop rows of bit depth 16 down to 8 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001749void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06001750png_do_chop(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05001751{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001752 png_debug(1, "in png_do_chop");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001753 if (row_info->bit_depth == 16)
Guy Schalnat0d580581995-07-20 02:43:20 -05001754 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001755 png_bytep sp = row;
1756 png_bytep dp = row;
1757 png_uint_32 i;
1758 png_uint_32 istop = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001759
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001760 for (i = 0; i<istop; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001761 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001762#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001763 /* This does a more accurate scaling of the 16-bit color
1764 * value, rather than a simple low-byte truncation.
1765 *
1766 * What the ideal calculation should be:
1767 * *dp = (((((png_uint_32)(*sp) << 8) |
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001768 * (png_uint_32)(*(sp + 1))) * 255 + 127)
1769 * / (png_uint_32)65535L;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001770 *
1771 * GRR: no, I think this is what it really should be:
1772 * *dp = (((((png_uint_32)(*sp) << 8) |
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001773 * (png_uint_32)(*(sp + 1))) + 128L)
1774 * / (png_uint_32)257L;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001775 *
1776 * GRR: here's the exact calculation with shifts:
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001777 * temp = (((png_uint_32)(*sp) << 8) |
1778 * (png_uint_32)(*(sp + 1))) + 128L;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001779 * *dp = (temp - (temp >> 8)) >> 8;
1780 *
1781 * Approximate calculation with shift/add instead of multiply/divide:
1782 * *dp = ((((png_uint_32)(*sp) << 8) |
1783 * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
1784 *
1785 * What we actually do to avoid extra shifting and conversion:
1786 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001787
Andreas Dilger47a0c421997-05-16 02:46:07 -05001788 *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
1789#else
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001790 /* Simply discard the low order byte */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001791 *dp = *sp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001792#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001793 }
1794 row_info->bit_depth = 8;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001795 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001796 row_info->rowbytes = row_info->width * row_info->channels;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001797 }
1798}
1799#endif
1800
1801#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001802void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001803png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
1804{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001805 png_debug(1, "in png_do_read_swap_alpha");
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-Pehrsonc4a2ae61998-01-16 22:06:18 -06001890#if defined(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-Pehrsonc4a2ae61998-01-16 22:06:18 -06001895 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001896 png_uint_32 row_width = row_info->width;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001897 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1898 {
1899 /* This inverts the alpha channel in RGBA */
1900 if (row_info->bit_depth == 8)
1901 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001902 png_bytep sp = row + row_info->rowbytes;
1903 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001904 png_uint_32 i;
1905
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001906 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001907 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001908 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001909
1910/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001911 *(--dp) = *(--sp);
1912 *(--dp) = *(--sp);
1913 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001914 We can replace it with:
1915*/
1916 sp-=3;
1917 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001918 }
1919 }
1920 /* This inverts the alpha channel in RRGGBBAA */
1921 else
1922 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001923 png_bytep sp = row + row_info->rowbytes;
1924 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001925 png_uint_32 i;
1926
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001927 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001928 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001929 *(--dp) = (png_byte)(255 - *(--sp));
1930 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001931
1932/* This does nothing:
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001933 *(--dp) = *(--sp);
1934 *(--dp) = *(--sp);
1935 *(--dp) = *(--sp);
1936 *(--dp) = *(--sp);
1937 *(--dp) = *(--sp);
1938 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001939 We can replace it with:
1940*/
1941 sp-=6;
1942 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001943 }
1944 }
1945 }
1946 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1947 {
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001948 /* This inverts the alpha channel in GA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001949 if (row_info->bit_depth == 8)
1950 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001951 png_bytep sp = row + row_info->rowbytes;
1952 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001953 png_uint_32 i;
1954
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001955 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001956 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001957 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001958 *(--dp) = *(--sp);
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001959 }
1960 }
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001961 /* This inverts the alpha channel in GGAA */
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001962 else
1963 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001964 png_bytep sp = row + row_info->rowbytes;
1965 png_bytep dp = sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001966 png_uint_32 i;
1967
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001968 for (i = 0; i < row_width; i++)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001969 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001970 *(--dp) = (png_byte)(255 - *(--sp));
1971 *(--dp) = (png_byte)(255 - *(--sp));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001972/*
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001973 *(--dp) = *(--sp);
1974 *(--dp) = *(--sp);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001975*/
1976 sp-=2;
1977 dp=sp;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001978 }
1979 }
1980 }
1981 }
1982}
1983#endif
1984
Glenn Randers-Pehrson1916f6a2008-08-14 13:44:49 -05001985#if defined(PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED)
1986void /* PRIVATE */
1987png_do_read_premultiply_alpha(png_row_infop row_info, png_bytep row)
1988{
Glenn Randers-Pehrsond6d80752008-12-02 09:49:43 -06001989 png_debug(1, "in png_do_read_premultiply_alpha");
Glenn Randers-Pehrson1916f6a2008-08-14 13:44:49 -05001990 {
1991 png_uint_32 row_width = row_info->width;
1992 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
1993 {
1994 /* This premultiplies the pixels with the alpha channel in RGBA */
1995 if (row_info->bit_depth == 8)
1996 {
1997 png_bytep sp = row + row_info->rowbytes;
1998 png_bytep dp = sp;
1999 png_uint_16 a = 0;
2000 png_uint_32 i;
2001
2002 for (i = 0; i < row_width; i++)
2003 {
2004 a = *(--sp); --dp;
2005
2006 *(--dp) = (*(--sp) * a) / 255;
2007 *(--dp) = (*(--sp) * a) / 255;
2008 *(--dp) = (*(--sp) * a) / 255;
2009 }
2010 }
2011 /* This premultiplies the pixels with the alpha channel in RRGGBBAA */
2012 else
2013 {
2014 png_uint_16p sp = (png_uint_16p)(row + row_info->rowbytes);
2015 png_uint_16p dp = sp;
2016 png_uint_32 a = 0;
2017 png_uint_32 i;
2018
2019 for (i = 0; i < row_width; i++)
2020 {
2021 a = *(--sp); --dp;
2022 *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535);
2023 *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535);
2024 *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535);
2025 }
2026 }
2027 }
2028 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2029 {
2030 /* This premultiplies the pixels with the alpha channel in GA */
2031 if (row_info->bit_depth == 8)
2032 {
2033 png_bytep sp = row + row_info->rowbytes;
2034 png_bytep dp = sp;
2035 png_uint_16 a = 0;
2036 png_uint_32 i;
2037
2038 for (i = 0; i < row_width; i++)
2039 {
2040 a = *(--sp); --dp;
2041 *(--dp) = (*(--sp) * a) / 255;
2042 }
2043 }
2044 /* This premultiplies the pixels with the alpha channel in GGAA */
2045 else
2046 {
2047 png_uint_16p sp = (png_uint_16p) (row + row_info->rowbytes);
2048 png_uint_16p dp = sp;
2049 png_uint_32 a = 0;
2050 png_uint_32 i;
2051
2052 for (i = 0; i < row_width; i++)
2053 {
2054 a = *(--sp); --dp;
2055 *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535);
2056 }
2057 }
2058 }
2059 }
2060}
2061#endif
2062
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002063#if defined(PNG_READ_FILLER_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002064/* Add filler channel if we have RGB color */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002065void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002066png_do_read_filler(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05002067 png_uint_32 filler, png_uint_32 flags)
Guy Schalnat0d580581995-07-20 02:43:20 -05002068{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002069 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002070 png_uint_32 row_width = row_info->width;
2071
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002072 png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002073 png_byte lo_filler = (png_byte)(filler & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002074
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002075 png_debug(1, "in png_do_read_filler");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002076 if (
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002077 row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05002078 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002079 if (row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002080 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002081 /* This changes the data from G to GX */
2082 if (flags & PNG_FLAG_FILLER_AFTER)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002083 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002084 png_bytep sp = row + (png_size_t)row_width;
2085 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002086 for (i = 1; i < row_width; i++)
2087 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002088 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002089 *(--dp) = *(--sp);
2090 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002091 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002092 row_info->channels = 2;
2093 row_info->pixel_depth = 16;
2094 row_info->rowbytes = row_width * 2;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002095 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002096 /* This changes the data from G to XG */
2097 else
2098 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002099 png_bytep sp = row + (png_size_t)row_width;
2100 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002101 for (i = 0; i < row_width; i++)
2102 {
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 = 2;
2107 row_info->pixel_depth = 16;
2108 row_info->rowbytes = row_width * 2;
2109 }
Guy Schalnat0d580581995-07-20 02:43:20 -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 GG to GGXX */
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 * 2;
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 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002125 *(--dp) = hi_filler;
2126 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002127 row_info->channels = 2;
2128 row_info->pixel_depth = 32;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002129 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002130 }
2131 /* This changes the data from GG to XXGG */
2132 else
2133 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002134 png_bytep sp = row + (png_size_t)row_width * 2;
2135 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002136 for (i = 0; i < row_width; i++)
2137 {
2138 *(--dp) = *(--sp);
2139 *(--dp) = *(--sp);
2140 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002141 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002142 }
2143 row_info->channels = 2;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002144 row_info->pixel_depth = 32;
2145 row_info->rowbytes = row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002146 }
2147 }
2148 } /* COLOR_TYPE == GRAY */
2149 else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2150 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002151 if (row_info->bit_depth == 8)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002152 {
2153 /* This changes the data from RGB to RGBX */
2154 if (flags & PNG_FLAG_FILLER_AFTER)
2155 {
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002156 png_bytep sp = row + (png_size_t)row_width * 3;
2157 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002158 for (i = 1; i < row_width; i++)
2159 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002160 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002161 *(--dp) = *(--sp);
2162 *(--dp) = *(--sp);
2163 *(--dp) = *(--sp);
2164 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002165 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002166 row_info->channels = 4;
2167 row_info->pixel_depth = 32;
2168 row_info->rowbytes = row_width * 4;
2169 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002170 /* This changes the data from RGB to XRGB */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002171 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002172 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002173 png_bytep sp = row + (png_size_t)row_width * 3;
2174 png_bytep dp = sp + (png_size_t)row_width;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002175 for (i = 0; i < row_width; i++)
2176 {
2177 *(--dp) = *(--sp);
2178 *(--dp) = *(--sp);
2179 *(--dp) = *(--sp);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002180 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002181 }
2182 row_info->channels = 4;
2183 row_info->pixel_depth = 32;
2184 row_info->rowbytes = row_width * 4;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002185 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002186 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002187 else if (row_info->bit_depth == 16)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002188 {
2189 /* This changes the data from RRGGBB to RRGGBBXX */
2190 if (flags & PNG_FLAG_FILLER_AFTER)
2191 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002192 png_bytep sp = row + (png_size_t)row_width * 6;
2193 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002194 for (i = 1; i < row_width; i++)
2195 {
2196 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002197 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002198 *(--dp) = *(--sp);
2199 *(--dp) = *(--sp);
2200 *(--dp) = *(--sp);
2201 *(--dp) = *(--sp);
2202 *(--dp) = *(--sp);
2203 *(--dp) = *(--sp);
2204 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002205 *(--dp) = hi_filler;
2206 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002207 row_info->channels = 4;
2208 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002209 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002210 }
2211 /* This changes the data from RRGGBB to XXRRGGBB */
2212 else
2213 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002214 png_bytep sp = row + (png_size_t)row_width * 6;
2215 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002216 for (i = 0; i < row_width; i++)
2217 {
2218 *(--dp) = *(--sp);
2219 *(--dp) = *(--sp);
2220 *(--dp) = *(--sp);
2221 *(--dp) = *(--sp);
2222 *(--dp) = *(--sp);
2223 *(--dp) = *(--sp);
2224 *(--dp) = hi_filler;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002225 *(--dp) = lo_filler;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002226 }
2227 row_info->channels = 4;
2228 row_info->pixel_depth = 64;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002229 row_info->rowbytes = row_width * 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002230 }
2231 }
2232 } /* COLOR_TYPE == RGB */
Guy Schalnat0d580581995-07-20 02:43:20 -05002233}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002234#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002235
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002236#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002237/* Expand grayscale files to RGB, with or without alpha */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002238void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002239png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -05002240{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002241 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002242 png_uint_32 row_width = row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06002243
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002244 png_debug(1, "in png_do_gray_to_rgb");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002245 if (row_info->bit_depth >= 8 &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002246 !(row_info->color_type & PNG_COLOR_MASK_COLOR))
2247 {
2248 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
2249 {
2250 if (row_info->bit_depth == 8)
2251 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002252 png_bytep sp = row + (png_size_t)row_width - 1;
2253 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002254 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002255 {
2256 *(dp--) = *sp;
2257 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002258 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002259 }
2260 }
2261 else
2262 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002263 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2264 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002265 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002266 {
2267 *(dp--) = *sp;
2268 *(dp--) = *(sp - 1);
2269 *(dp--) = *sp;
2270 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002271 *(dp--) = *(sp--);
2272 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002273 }
2274 }
2275 }
2276 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2277 {
2278 if (row_info->bit_depth == 8)
2279 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002280 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2281 png_bytep dp = sp + (png_size_t)row_width * 2;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002282 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002283 {
2284 *(dp--) = *(sp--);
2285 *(dp--) = *sp;
2286 *(dp--) = *sp;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002287 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002288 }
2289 }
2290 else
2291 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002292 png_bytep sp = row + (png_size_t)row_width * 4 - 1;
2293 png_bytep dp = sp + (png_size_t)row_width * 4;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002294 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002295 {
2296 *(dp--) = *(sp--);
2297 *(dp--) = *(sp--);
2298 *(dp--) = *sp;
2299 *(dp--) = *(sp - 1);
2300 *(dp--) = *sp;
2301 *(dp--) = *(sp - 1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002302 *(dp--) = *(sp--);
2303 *(dp--) = *(sp--);
Guy Schalnat0d580581995-07-20 02:43:20 -05002304 }
2305 }
2306 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002307 row_info->channels += (png_byte)2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002308 row_info->color_type |= PNG_COLOR_MASK_COLOR;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002309 row_info->pixel_depth = (png_byte)(row_info->channels *
2310 row_info->bit_depth);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002311 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05002312 }
2313}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002314#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002315
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002316#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002317/* Reduce RGB files to grayscale, with or without alpha
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002318 * using the equation given in Poynton's ColorFAQ at
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002319 * <http://www.inforamp.net/~poynton/> (THIS LINK IS DEAD June 2008)
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002320 * New link:
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002321 * <http://www.poynton.com/notes/colour_and_gamma/>
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002322 * Charles Poynton poynton at poynton.com
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002323 *
2324 * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
2325 *
2326 * We approximate this with
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002327 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002328 * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002329 *
2330 * which can be expressed with integers as
2331 *
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002332 * Y = (6969 * R + 23434 * G + 2365 * B)/32768
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002333 *
2334 * The calculation is to be done in a linear colorspace.
2335 *
2336 * Other integer coefficents can be used via png_set_rgb_to_gray().
2337 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002338int /* PRIVATE */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002339png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
2340
2341{
2342 png_uint_32 i;
2343
2344 png_uint_32 row_width = row_info->width;
2345 int rgb_error = 0;
2346
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002347 png_debug(1, "in png_do_rgb_to_gray");
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002348 if (
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002349 (row_info->color_type & PNG_COLOR_MASK_COLOR))
2350 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002351 png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
2352 png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
2353 png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002354
2355 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2356 {
2357 if (row_info->bit_depth == 8)
2358 {
2359#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2360 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2361 {
2362 png_bytep sp = row;
2363 png_bytep dp = row;
2364
2365 for (i = 0; i < row_width; i++)
2366 {
2367 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2368 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2369 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002370 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002371 {
2372 rgb_error |= 1;
2373 *(dp++) = png_ptr->gamma_from_1[
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002374 (rc*red + gc*green + bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002375 }
2376 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002377 *(dp++) = *(sp - 1);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002378 }
2379 }
2380 else
2381#endif
2382 {
2383 png_bytep sp = row;
2384 png_bytep dp = row;
2385 for (i = 0; i < row_width; i++)
2386 {
2387 png_byte red = *(sp++);
2388 png_byte green = *(sp++);
2389 png_byte blue = *(sp++);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002390 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002391 {
2392 rgb_error |= 1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002393 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002394 }
2395 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002396 *(dp++) = *(sp - 1);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002397 }
2398 }
2399 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002400
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002401 else /* RGB bit_depth == 16 */
2402 {
2403#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2404 if (png_ptr->gamma_16_to_1 != NULL &&
2405 png_ptr->gamma_16_from_1 != NULL)
2406 {
2407 png_bytep sp = row;
2408 png_bytep dp = row;
2409 for (i = 0; i < row_width; i++)
2410 {
2411 png_uint_16 red, green, blue, w;
2412
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002413 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2414 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2415 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002416
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002417 if (red == green && red == blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002418 w = red;
2419 else
2420 {
2421 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2422 png_ptr->gamma_shift][red>>8];
2423 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2424 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002425 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002426 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002427 png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002428 + bc*blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002429 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2430 png_ptr->gamma_shift][gray16 >> 8];
2431 rgb_error |= 1;
2432 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002433
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002434 *(dp++) = (png_byte)((w>>8) & 0xff);
2435 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002436 }
2437 }
2438 else
2439#endif
2440 {
2441 png_bytep sp = row;
2442 png_bytep dp = row;
2443 for (i = 0; i < row_width; i++)
2444 {
2445 png_uint_16 red, green, blue, gray16;
2446
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002447 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2448 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2449 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002450
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002451 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002452 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002453 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002454 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2455 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002456 }
2457 }
2458 }
2459 }
2460 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2461 {
2462 if (row_info->bit_depth == 8)
2463 {
2464#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2465 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
2466 {
2467 png_bytep sp = row;
2468 png_bytep dp = row;
2469 for (i = 0; i < row_width; i++)
2470 {
2471 png_byte red = png_ptr->gamma_to_1[*(sp++)];
2472 png_byte green = png_ptr->gamma_to_1[*(sp++)];
2473 png_byte blue = png_ptr->gamma_to_1[*(sp++)];
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;
2476 *(dp++) = png_ptr->gamma_from_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002477 [(rc*red + gc*green + bc*blue)>>15];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002478 *(dp++) = *(sp++); /* alpha */
2479 }
2480 }
2481 else
2482#endif
2483 {
2484 png_bytep sp = row;
2485 png_bytep dp = row;
2486 for (i = 0; i < row_width; i++)
2487 {
2488 png_byte red = *(sp++);
2489 png_byte green = *(sp++);
2490 png_byte blue = *(sp++);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002491 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002492 rgb_error |= 1;
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002493 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002494 *(dp++) = *(sp++); /* alpha */
2495 }
2496 }
2497 }
2498 else /* RGBA bit_depth == 16 */
2499 {
2500#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
2501 if (png_ptr->gamma_16_to_1 != NULL &&
2502 png_ptr->gamma_16_from_1 != NULL)
2503 {
2504 png_bytep sp = row;
2505 png_bytep dp = row;
2506 for (i = 0; i < row_width; i++)
2507 {
2508 png_uint_16 red, green, blue, w;
2509
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002510 red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2511 green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
2512 blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002513
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002514 if (red == green && red == blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002515 w = red;
2516 else
2517 {
2518 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
2519 png_ptr->gamma_shift][red>>8];
2520 png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
2521 png_ptr->gamma_shift][green>>8];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002522 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002523 png_ptr->gamma_shift][blue>>8];
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002524 png_uint_16 gray16 = (png_uint_16)((rc * red_1
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002525 + gc * green_1 + bc * blue_1)>>15);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002526 w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
2527 png_ptr->gamma_shift][gray16 >> 8];
2528 rgb_error |= 1;
2529 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002530
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002531 *(dp++) = (png_byte)((w>>8) & 0xff);
2532 *(dp++) = (png_byte)(w & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002533 *(dp++) = *(sp++); /* alpha */
2534 *(dp++) = *(sp++);
2535 }
2536 }
2537 else
2538#endif
2539 {
2540 png_bytep sp = row;
2541 png_bytep dp = row;
2542 for (i = 0; i < row_width; i++)
2543 {
2544 png_uint_16 red, green, blue, gray16;
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002545 red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2546 green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
2547 blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002548 if (red != green || red != blue)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002549 rgb_error |= 1;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002550 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002551 *(dp++) = (png_byte)((gray16>>8) & 0xff);
2552 *(dp++) = (png_byte)(gray16 & 0xff);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002553 *(dp++) = *(sp++); /* alpha */
2554 *(dp++) = *(sp++);
2555 }
2556 }
2557 }
2558 }
2559 row_info->channels -= (png_byte)2;
2560 row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
2561 row_info->pixel_depth = (png_byte)(row_info->channels *
2562 row_info->bit_depth);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002563 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002564 }
2565 return rgb_error;
2566}
2567#endif
2568
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002569/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
2570 * large of png_color. This lets grayscale images be treated as
2571 * paletted. Most useful for gamma correction and simplification
2572 * of code.
2573 */
Glenn Randers-Pehrson73d57cb2002-03-25 18:49:08 -06002574void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -06002575png_build_grayscale_palette(int bit_depth, png_colorp palette)
Guy Schalnat0d580581995-07-20 02:43:20 -05002576{
2577 int num_palette;
2578 int color_inc;
2579 int i;
2580 int v;
2581
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002582 png_debug(1, "in png_do_build_grayscale_palette");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002583 if (palette == NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002584 return;
2585
2586 switch (bit_depth)
2587 {
2588 case 1:
2589 num_palette = 2;
2590 color_inc = 0xff;
2591 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002592
Guy Schalnat0d580581995-07-20 02:43:20 -05002593 case 2:
2594 num_palette = 4;
2595 color_inc = 0x55;
2596 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002597
Guy Schalnat0d580581995-07-20 02:43:20 -05002598 case 4:
2599 num_palette = 16;
2600 color_inc = 0x11;
2601 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002602
Guy Schalnat0d580581995-07-20 02:43:20 -05002603 case 8:
2604 num_palette = 256;
2605 color_inc = 1;
2606 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002607
Guy Schalnat0d580581995-07-20 02:43:20 -05002608 default:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002609 num_palette = 0;
Guy Schalnat69b14481996-01-10 02:56:49 -06002610 color_inc = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002611 break;
2612 }
2613
2614 for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
2615 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002616 palette[i].red = (png_byte)v;
2617 palette[i].green = (png_byte)v;
2618 palette[i].blue = (png_byte)v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002619 }
2620}
2621
Guy Schalnat0d580581995-07-20 02:43:20 -05002622
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002623#if defined(PNG_READ_BACKGROUND_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002624/* Replace any alpha or transparency with the supplied background color.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002625 * "background" is already in the screen gamma, while "background_1" is
2626 * at a gamma of 1.0. Paletted files have already been taken care of.
2627 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002628void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002629png_do_background(png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002630 png_color_16p trans_color, png_color_16p background
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002631#if defined(PNG_READ_GAMMA_SUPPORTED)
2632 , png_color_16p background_1,
Guy Schalnat6d764711995-12-19 03:22:19 -06002633 png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002634 png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05002635 png_uint_16pp gamma_16_to_1, int gamma_shift
2636#endif
2637 )
Guy Schalnat0d580581995-07-20 02:43:20 -05002638{
Guy Schalnat6d764711995-12-19 03:22:19 -06002639 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002640 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002641 png_uint_32 row_width=row_info->width;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002642 int shift;
Guy Schalnate5a37791996-06-05 15:50:50 -05002643
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002644 png_debug(1, "in png_do_background");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002645 if (background != NULL &&
Guy Schalnat0d580581995-07-20 02:43:20 -05002646 (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002647 (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_color)))
Guy Schalnat0d580581995-07-20 02:43:20 -05002648 {
2649 switch (row_info->color_type)
2650 {
2651 case PNG_COLOR_TYPE_GRAY:
2652 {
2653 switch (row_info->bit_depth)
2654 {
2655 case 1:
2656 {
Guy Schalnat0d580581995-07-20 02:43:20 -05002657 sp = row;
2658 shift = 7;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002659 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002660 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002661 if ((png_uint_16)((*sp >> shift) & 0x01)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002662 == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002663 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002664 *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2665 *sp |= (png_byte)(background->gray << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002666 }
2667 if (!shift)
2668 {
2669 shift = 7;
2670 sp++;
2671 }
2672 else
2673 shift--;
2674 }
2675 break;
2676 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002677
Guy Schalnat0d580581995-07-20 02:43:20 -05002678 case 2:
2679 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002680#if defined(PNG_READ_GAMMA_SUPPORTED)
2681 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002682 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002683 sp = row;
2684 shift = 6;
2685 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002686 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002687 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002688 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002689 {
2690 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2691 *sp |= (png_byte)(background->gray << shift);
2692 }
2693 else
2694 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002695 png_byte p = (png_byte)((*sp >> shift) & 0x03);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002696 png_byte g = (png_byte)((gamma_table [p | (p << 2) |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002697 (p << 4) | (p << 6)] >> 6) & 0x03);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002698 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2699 *sp |= (png_byte)(g << shift);
2700 }
2701 if (!shift)
2702 {
2703 shift = 6;
2704 sp++;
2705 }
2706 else
2707 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002708 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002709 }
2710 else
2711#endif
2712 {
2713 sp = row;
2714 shift = 6;
2715 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002716 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002717 if ((png_uint_16)((*sp >> shift) & 0x03)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002718 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002719 {
2720 *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2721 *sp |= (png_byte)(background->gray << shift);
2722 }
2723 if (!shift)
2724 {
2725 shift = 6;
2726 sp++;
2727 }
2728 else
2729 shift -= 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05002730 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002731 }
2732 break;
2733 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002734
Guy Schalnat0d580581995-07-20 02:43:20 -05002735 case 4:
2736 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002737#if defined(PNG_READ_GAMMA_SUPPORTED)
2738 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002739 {
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002740 sp = row;
2741 shift = 4;
2742 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002743 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002744 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002745 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002746 {
2747 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2748 *sp |= (png_byte)(background->gray << shift);
2749 }
2750 else
2751 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002752 png_byte p = (png_byte)((*sp >> shift) & 0x0f);
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002753 png_byte g = (png_byte)((gamma_table[p |
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002754 (p << 4)] >> 4) & 0x0f);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002755 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2756 *sp |= (png_byte)(g << shift);
2757 }
2758 if (!shift)
2759 {
2760 shift = 4;
2761 sp++;
2762 }
2763 else
2764 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002765 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002766 }
2767 else
2768#endif
2769 {
2770 sp = row;
2771 shift = 4;
2772 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002773 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002774 if ((png_uint_16)((*sp >> shift) & 0x0f)
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002775 == trans_color->gray)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05002776 {
2777 *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2778 *sp |= (png_byte)(background->gray << shift);
2779 }
2780 if (!shift)
2781 {
2782 shift = 4;
2783 sp++;
2784 }
2785 else
2786 shift -= 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05002787 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002788 }
2789 break;
2790 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002791
Guy Schalnat0d580581995-07-20 02:43:20 -05002792 case 8:
2793 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002794#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002795 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002796 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002797 sp = row;
2798 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002799 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002800 if (*sp == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002801 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002802 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002803 }
2804 else
2805 {
2806 *sp = gamma_table[*sp];
2807 }
2808 }
2809 }
2810 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002811#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002812 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002813 sp = row;
2814 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002815 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002816 if (*sp == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002817 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002818 *sp = (png_byte)background->gray;
Guy Schalnat0d580581995-07-20 02:43:20 -05002819 }
2820 }
2821 }
2822 break;
2823 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002824
Guy Schalnat0d580581995-07-20 02:43:20 -05002825 case 16:
2826 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002827#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002828 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002829 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002830 sp = row;
2831 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002832 {
2833 png_uint_16 v;
2834
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002835 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002836 if (v == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002837 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002838 /* Background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002839 *sp = (png_byte)((background->gray >> 8) & 0xff);
2840 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002841 }
2842 else
2843 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002844 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002845 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002846 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002847 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002848 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002849 }
2850 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002851#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002852 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002853 sp = row;
2854 for (i = 0; i < row_width; i++, sp += 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002855 {
2856 png_uint_16 v;
2857
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002858 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002859 if (v == trans_color->gray)
Guy Schalnat0d580581995-07-20 02:43:20 -05002860 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002861 *sp = (png_byte)((background->gray >> 8) & 0xff);
2862 *(sp + 1) = (png_byte)(background->gray & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002863 }
2864 }
2865 }
2866 break;
2867 }
2868 }
2869 break;
2870 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002871
Guy Schalnat0d580581995-07-20 02:43:20 -05002872 case PNG_COLOR_TYPE_RGB:
2873 {
2874 if (row_info->bit_depth == 8)
2875 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002876#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002877 if (gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002878 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002879 sp = row;
2880 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002881 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002882 if (*sp == trans_color->red &&
2883 *(sp + 1) == trans_color->green &&
2884 *(sp + 2) == trans_color->blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05002885 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002886 *sp = (png_byte)background->red;
2887 *(sp + 1) = (png_byte)background->green;
2888 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002889 }
2890 else
2891 {
2892 *sp = gamma_table[*sp];
2893 *(sp + 1) = gamma_table[*(sp + 1)];
2894 *(sp + 2) = gamma_table[*(sp + 2)];
2895 }
2896 }
2897 }
2898 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002899#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002900 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002901 sp = row;
2902 for (i = 0; i < row_width; i++, sp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05002903 {
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002904 if (*sp == trans_color->red &&
2905 *(sp + 1) == trans_color->green &&
2906 *(sp + 2) == trans_color->blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05002907 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002908 *sp = (png_byte)background->red;
2909 *(sp + 1) = (png_byte)background->green;
2910 *(sp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05002911 }
2912 }
2913 }
2914 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002915 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05002916 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002917#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002918 if (gamma_16 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002919 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002920 sp = row;
2921 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002922 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002923 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
2924 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2925 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002926 if (r == trans_color->red && g == trans_color->green &&
2927 b == trans_color->blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05002928 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002929 /* Background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002930 *sp = (png_byte)((background->red >> 8) & 0xff);
2931 *(sp + 1) = (png_byte)(background->red & 0xff);
2932 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2933 *(sp + 3) = (png_byte)(background->green & 0xff);
2934 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2935 *(sp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002936 }
2937 else
2938 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002939 png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002940 *sp = (png_byte)((v >> 8) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002941 *(sp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002942 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002943 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
2944 *(sp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002945 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002946 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
2947 *(sp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05002948 }
2949 }
2950 }
2951 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002952#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002953 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002954 sp = row;
2955 for (i = 0; i < row_width; i++, sp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05002956 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05002957 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
2958 png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
2959 png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
Guy Schalnat0d580581995-07-20 02:43:20 -05002960
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05002961 if (r == trans_color->red && g == trans_color->green &&
2962 b == trans_color->blue)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002963 {
2964 *sp = (png_byte)((background->red >> 8) & 0xff);
2965 *(sp + 1) = (png_byte)(background->red & 0xff);
2966 *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
2967 *(sp + 3) = (png_byte)(background->green & 0xff);
2968 *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
2969 *(sp + 5) = (png_byte)(background->blue & 0xff);
2970 }
2971 }
2972 }
2973 }
2974 break;
2975 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002976
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002977 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -05002978 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002979 if (row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002980 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002981#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002982 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
2983 gamma_table != NULL)
2984 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002985 sp = row;
2986 dp = row;
2987 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002988 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002989 png_uint_16 a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002990
Andreas Dilger47a0c421997-05-16 02:46:07 -05002991 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05002992 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002993 *dp = gamma_table[*sp];
2994 }
2995 else if (a == 0)
2996 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05002997 /* Background is already in screen gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002998 *dp = (png_byte)background->gray;
2999 }
3000 else
3001 {
3002 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05003003
Andreas Dilger47a0c421997-05-16 02:46:07 -05003004 v = gamma_to_1[*sp];
3005 png_composite(w, v, a, background_1->gray);
3006 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003007 }
3008 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003009 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003010 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003011#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003012 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003013 sp = row;
3014 dp = row;
3015 for (i = 0; i < row_width; i++, sp += 2, dp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003016 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003017 png_byte a = *(sp + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003018
Andreas Dilger47a0c421997-05-16 02:46:07 -05003019 if (a == 0xff)
Guy Schalnat0d580581995-07-20 02:43:20 -05003020 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003021 *dp = *sp;
3022 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003023#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003024 else if (a == 0)
3025 {
3026 *dp = (png_byte)background->gray;
3027 }
3028 else
3029 {
3030 png_composite(*dp, *sp, a, background_1->gray);
Guy Schalnat0d580581995-07-20 02:43:20 -05003031 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003032#else
3033 *dp = (png_byte)background->gray;
3034#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003035 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003036 }
3037 }
3038 else /* if (png_ptr->bit_depth == 16) */
3039 {
3040#if defined(PNG_READ_GAMMA_SUPPORTED)
3041 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3042 gamma_16_to_1 != NULL)
3043 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003044 sp = row;
3045 dp = row;
3046 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003047 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003048 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003049
Andreas Dilger47a0c421997-05-16 02:46:07 -05003050 if (a == (png_uint_16)0xffff)
3051 {
3052 png_uint_16 v;
3053
3054 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3055 *dp = (png_byte)((v >> 8) & 0xff);
3056 *(dp + 1) = (png_byte)(v & 0xff);
3057 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003058#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003059 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003060#else
3061 else
3062#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003063 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003064 /* Background is already in screen gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -05003065 *dp = (png_byte)((background->gray >> 8) & 0xff);
3066 *(dp + 1) = (png_byte)(background->gray & 0xff);
3067 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003068#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003069 else
3070 {
3071 png_uint_16 g, v, w;
3072
3073 g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3074 png_composite_16(v, g, a, background_1->gray);
3075 w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
3076 *dp = (png_byte)((w >> 8) & 0xff);
3077 *(dp + 1) = (png_byte)(w & 0xff);
3078 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003079#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003080 }
3081 }
3082 else
3083#endif
3084 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003085 sp = row;
3086 dp = row;
3087 for (i = 0; i < row_width; i++, sp += 4, dp += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003088 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003089 png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003090 if (a == (png_uint_16)0xffff)
3091 {
3092 png_memcpy(dp, sp, 2);
3093 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003094#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003095 else if (a == 0)
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003096#else
3097 else
3098#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003099 {
3100 *dp = (png_byte)((background->gray >> 8) & 0xff);
3101 *(dp + 1) = (png_byte)(background->gray & 0xff);
3102 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003103#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003104 else
3105 {
3106 png_uint_16 g, v;
3107
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003108 g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003109 png_composite_16(v, g, a, background_1->gray);
3110 *dp = (png_byte)((v >> 8) & 0xff);
3111 *(dp + 1) = (png_byte)(v & 0xff);
3112 }
Glenn Randers-Pehrson5a0be342001-10-18 20:55:13 -05003113#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05003114 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003115 }
3116 }
3117 break;
3118 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003119
Guy Schalnat0d580581995-07-20 02:43:20 -05003120 case PNG_COLOR_TYPE_RGB_ALPHA:
3121 {
3122 if (row_info->bit_depth == 8)
3123 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003124#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003125 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3126 gamma_table != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003127 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003128 sp = row;
3129 dp = row;
3130 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003131 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003132 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003133
Guy Schalnat0d580581995-07-20 02:43:20 -05003134 if (a == 0xff)
3135 {
3136 *dp = gamma_table[*sp];
3137 *(dp + 1) = gamma_table[*(sp + 1)];
3138 *(dp + 2) = gamma_table[*(sp + 2)];
3139 }
3140 else if (a == 0)
3141 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003142 /* Background is already in screen gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -05003143 *dp = (png_byte)background->red;
3144 *(dp + 1) = (png_byte)background->green;
3145 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003146 }
3147 else
3148 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003149 png_byte v, w;
Guy Schalnat0d580581995-07-20 02:43:20 -05003150
3151 v = gamma_to_1[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003152 png_composite(w, v, a, background_1->red);
3153 *dp = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003154 v = gamma_to_1[*(sp + 1)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003155 png_composite(w, v, a, background_1->green);
3156 *(dp + 1) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003157 v = gamma_to_1[*(sp + 2)];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003158 png_composite(w, v, a, background_1->blue);
3159 *(dp + 2) = gamma_from_1[w];
Guy Schalnat0d580581995-07-20 02:43:20 -05003160 }
3161 }
3162 }
3163 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003164#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003165 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003166 sp = row;
3167 dp = row;
3168 for (i = 0; i < row_width; i++, sp += 4, dp += 3)
Guy Schalnat0d580581995-07-20 02:43:20 -05003169 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003170 png_byte a = *(sp + 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003171
Guy Schalnat0d580581995-07-20 02:43:20 -05003172 if (a == 0xff)
3173 {
3174 *dp = *sp;
3175 *(dp + 1) = *(sp + 1);
3176 *(dp + 2) = *(sp + 2);
3177 }
3178 else if (a == 0)
3179 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003180 *dp = (png_byte)background->red;
3181 *(dp + 1) = (png_byte)background->green;
3182 *(dp + 2) = (png_byte)background->blue;
Guy Schalnat0d580581995-07-20 02:43:20 -05003183 }
3184 else
3185 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003186 png_composite(*dp, *sp, a, background->red);
3187 png_composite(*(dp + 1), *(sp + 1), a,
3188 background->green);
3189 png_composite(*(dp + 2), *(sp + 2), a,
3190 background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003191 }
3192 }
3193 }
3194 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003195 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003196 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003197#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003198 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3199 gamma_16_to_1 != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003200 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003201 sp = row;
3202 dp = row;
3203 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003204 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003205 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3206 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003207 if (a == (png_uint_16)0xffff)
3208 {
3209 png_uint_16 v;
3210
Andreas Dilger47a0c421997-05-16 02:46:07 -05003211 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003212 *dp = (png_byte)((v >> 8) & 0xff);
3213 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003214 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003215 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3216 *(dp + 3) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003217 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003218 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3219 *(dp + 5) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003220 }
3221 else if (a == 0)
3222 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003223 /* Background is already in screen gamma */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003224 *dp = (png_byte)((background->red >> 8) & 0xff);
3225 *(dp + 1) = (png_byte)(background->red & 0xff);
3226 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3227 *(dp + 3) = (png_byte)(background->green & 0xff);
3228 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3229 *(dp + 5) = (png_byte)(background->blue & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003230 }
3231 else
3232 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003233 png_uint_16 v, w, x;
Guy Schalnat0d580581995-07-20 02:43:20 -05003234
Andreas Dilger47a0c421997-05-16 02:46:07 -05003235 v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003236 png_composite_16(w, v, a, background_1->red);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003237 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3238 *dp = (png_byte)((x >> 8) & 0xff);
3239 *(dp + 1) = (png_byte)(x & 0xff);
3240 v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003241 png_composite_16(w, v, a, background_1->green);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003242 x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
3243 *(dp + 2) = (png_byte)((x >> 8) & 0xff);
3244 *(dp + 3) = (png_byte)(x & 0xff);
3245 v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06003246 png_composite_16(w, v, a, background_1->blue);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003247 x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
3248 *(dp + 4) = (png_byte)((x >> 8) & 0xff);
3249 *(dp + 5) = (png_byte)(x & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003250 }
3251 }
3252 }
3253 else
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003254#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003255 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003256 sp = row;
3257 dp = row;
3258 for (i = 0; i < row_width; i++, sp += 8, dp += 6)
Guy Schalnat0d580581995-07-20 02:43:20 -05003259 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003260 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3261 << 8) + (png_uint_16)(*(sp + 7)));
Guy Schalnat0d580581995-07-20 02:43:20 -05003262 if (a == (png_uint_16)0xffff)
3263 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003264 png_memcpy(dp, sp, 6);
Guy Schalnat0d580581995-07-20 02:43:20 -05003265 }
3266 else if (a == 0)
3267 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003268 *dp = (png_byte)((background->red >> 8) & 0xff);
3269 *(dp + 1) = (png_byte)(background->red & 0xff);
3270 *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
3271 *(dp + 3) = (png_byte)(background->green & 0xff);
3272 *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
3273 *(dp + 5) = (png_byte)(background->blue & 0xff);
3274 }
3275 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003276 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003277 png_uint_16 v;
Guy Schalnat0d580581995-07-20 02:43:20 -05003278
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003279 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3280 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3281 + *(sp + 3));
3282 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3283 + *(sp + 5));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003284
3285 png_composite_16(v, r, a, background->red);
Guy Schalnat0d580581995-07-20 02:43:20 -05003286 *dp = (png_byte)((v >> 8) & 0xff);
3287 *(dp + 1) = (png_byte)(v & 0xff);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003288 png_composite_16(v, g, a, background->green);
Guy Schalnat0d580581995-07-20 02:43:20 -05003289 *(dp + 2) = (png_byte)((v >> 8) & 0xff);
3290 *(dp + 3) = (png_byte)(v & 0xff);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003291 png_composite_16(v, b, a, background->blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05003292 *(dp + 4) = (png_byte)((v >> 8) & 0xff);
3293 *(dp + 5) = (png_byte)(v & 0xff);
3294 }
3295 }
3296 }
3297 }
3298 break;
3299 }
3300 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003301
Guy Schalnat0d580581995-07-20 02:43:20 -05003302 if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
3303 {
3304 row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
Guy Schalnate5a37791996-06-05 15:50:50 -05003305 row_info->channels--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003306 row_info->pixel_depth = (png_byte)(row_info->channels *
3307 row_info->bit_depth);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003308 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003309 }
3310 }
3311}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003312#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003313
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003314#if defined(PNG_READ_GAMMA_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003315/* Gamma correct the image, avoiding the alpha channel. Make sure
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003316 * you do this after you deal with the transparency issue on grayscale
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003317 * or RGB images. If your bit depth is 8, use gamma_table, if it
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003318 * is 16, use gamma_16_table and gamma_shift. Build these with
3319 * build_gamma_table().
3320 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003321void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003322png_do_gamma(png_row_infop row_info, png_bytep row,
3323 png_bytep gamma_table, png_uint_16pp gamma_16_table,
Guy Schalnat0d580581995-07-20 02:43:20 -05003324 int gamma_shift)
3325{
Guy Schalnat6d764711995-12-19 03:22:19 -06003326 png_bytep sp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003327 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003328 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003329
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003330 png_debug(1, "in png_do_gamma");
Andreas Dilger47a0c421997-05-16 02:46:07 -05003331 if (
Andreas Dilger47a0c421997-05-16 02:46:07 -05003332 ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
3333 (row_info->bit_depth == 16 && gamma_16_table != NULL)))
Guy Schalnat0d580581995-07-20 02:43:20 -05003334 {
3335 switch (row_info->color_type)
3336 {
3337 case PNG_COLOR_TYPE_RGB:
3338 {
3339 if (row_info->bit_depth == 8)
3340 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003341 sp = row;
3342 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003343 {
3344 *sp = gamma_table[*sp];
3345 sp++;
3346 *sp = gamma_table[*sp];
3347 sp++;
3348 *sp = gamma_table[*sp];
3349 sp++;
3350 }
3351 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003352 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003353 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003354 sp = row;
3355 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003356 {
3357 png_uint_16 v;
3358
Andreas Dilger47a0c421997-05-16 02:46:07 -05003359 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 += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003363 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003364 *sp = (png_byte)((v >> 8) & 0xff);
3365 *(sp + 1) = (png_byte)(v & 0xff);
3366 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003367 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003368 *sp = (png_byte)((v >> 8) & 0xff);
3369 *(sp + 1) = (png_byte)(v & 0xff);
3370 sp += 2;
3371 }
3372 }
3373 break;
3374 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003375
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003376 case PNG_COLOR_TYPE_RGB_ALPHA:
3377 {
3378 if (row_info->bit_depth == 8)
3379 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003380 sp = row;
3381 for (i = 0; i < row_width; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003382 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003383 *sp = gamma_table[*sp];
3384 sp++;
3385 *sp = gamma_table[*sp];
3386 sp++;
3387 *sp = gamma_table[*sp];
3388 sp++;
3389 sp++;
3390 }
3391 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003392 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003393 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003394 sp = row;
3395 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003396 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003397 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003398 *sp = (png_byte)((v >> 8) & 0xff);
3399 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003400 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003401 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003402 *sp = (png_byte)((v >> 8) & 0xff);
3403 *(sp + 1) = (png_byte)(v & 0xff);
3404 sp += 2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003405 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003406 *sp = (png_byte)((v >> 8) & 0xff);
3407 *(sp + 1) = (png_byte)(v & 0xff);
3408 sp += 4;
3409 }
3410 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003411 break;
3412 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003413
Guy Schalnat0d580581995-07-20 02:43:20 -05003414 case PNG_COLOR_TYPE_GRAY_ALPHA:
3415 {
3416 if (row_info->bit_depth == 8)
3417 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003418 sp = row;
3419 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003420 {
3421 *sp = gamma_table[*sp];
Andreas Dilger47a0c421997-05-16 02:46:07 -05003422 sp += 2;
Guy Schalnat0d580581995-07-20 02:43:20 -05003423 }
3424 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003425 else /* if (row_info->bit_depth == 16) */
Guy Schalnat0d580581995-07-20 02:43:20 -05003426 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003427 sp = row;
3428 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003429 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003430 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003431 *sp = (png_byte)((v >> 8) & 0xff);
3432 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003433 sp += 4;
3434 }
3435 }
3436 break;
3437 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003438
Guy Schalnat0d580581995-07-20 02:43:20 -05003439 case PNG_COLOR_TYPE_GRAY:
3440 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003441 if (row_info->bit_depth == 2)
3442 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003443 sp = row;
3444 for (i = 0; i < row_width; i += 4)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003445 {
3446 int a = *sp & 0xc0;
3447 int b = *sp & 0x30;
3448 int c = *sp & 0x0c;
3449 int d = *sp & 0x03;
3450
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003451 *sp = (png_byte)(
3452 ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003453 ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
3454 ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003455 ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06003456 sp++;
3457 }
3458 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003459
Andreas Dilger47a0c421997-05-16 02:46:07 -05003460 if (row_info->bit_depth == 4)
Guy Schalnat0d580581995-07-20 02:43:20 -05003461 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003462 sp = row;
3463 for (i = 0; i < row_width; i += 2)
Andreas Dilger47a0c421997-05-16 02:46:07 -05003464 {
3465 int msb = *sp & 0xf0;
3466 int lsb = *sp & 0x0f;
3467
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003468 *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
3469 | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
Andreas Dilger47a0c421997-05-16 02:46:07 -05003470 sp++;
3471 }
3472 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003473
Andreas Dilger47a0c421997-05-16 02:46:07 -05003474 else if (row_info->bit_depth == 8)
3475 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003476 sp = row;
3477 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003478 {
3479 *sp = gamma_table[*sp];
3480 sp++;
3481 }
3482 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003483
Guy Schalnat0d580581995-07-20 02:43:20 -05003484 else if (row_info->bit_depth == 16)
3485 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003486 sp = row;
3487 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003488 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003489 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003490 *sp = (png_byte)((v >> 8) & 0xff);
3491 *(sp + 1) = (png_byte)(v & 0xff);
Guy Schalnat0d580581995-07-20 02:43:20 -05003492 sp += 2;
3493 }
3494 }
3495 break;
3496 }
3497 }
3498 }
3499}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003500#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003501
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003502#if defined(PNG_READ_EXPAND_SUPPORTED)
Glenn Randers-Pehrson352ca6b1999-09-18 15:49:20 -05003503/* Expands a palette row to an RGB or RGBA row depending
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003504 * upon whether you supply trans and num_trans.
3505 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003506void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003507png_do_expand_palette(png_row_infop row_info, png_bytep row,
Andreas Dilger47a0c421997-05-16 02:46:07 -05003508 png_colorp palette, png_bytep trans, int num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003509{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003510 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003511 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003512 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003513 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003514
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003515 png_debug(1, "in png_do_expand_palette");
Andreas Dilger47a0c421997-05-16 02:46:07 -05003516 if (
Andreas Dilger47a0c421997-05-16 02:46:07 -05003517 row_info->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnat0d580581995-07-20 02:43:20 -05003518 {
3519 if (row_info->bit_depth < 8)
3520 {
3521 switch (row_info->bit_depth)
3522 {
3523 case 1:
3524 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003525 sp = row + (png_size_t)((row_width - 1) >> 3);
3526 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003527 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003528 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003529 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003530 if ((*sp >> shift) & 0x01)
Guy Schalnat0d580581995-07-20 02:43:20 -05003531 *dp = 1;
3532 else
3533 *dp = 0;
3534 if (shift == 7)
3535 {
3536 shift = 0;
3537 sp--;
3538 }
3539 else
3540 shift++;
3541
3542 dp--;
3543 }
3544 break;
3545 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003546
Guy Schalnat0d580581995-07-20 02:43:20 -05003547 case 2:
3548 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003549 sp = row + (png_size_t)((row_width - 1) >> 2);
3550 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003551 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003552 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003553 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003554 value = (*sp >> shift) & 0x03;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003555 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003556 if (shift == 6)
3557 {
3558 shift = 0;
3559 sp--;
3560 }
3561 else
3562 shift += 2;
3563
3564 dp--;
3565 }
3566 break;
3567 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003568
Guy Schalnat0d580581995-07-20 02:43:20 -05003569 case 4:
3570 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003571 sp = row + (png_size_t)((row_width - 1) >> 1);
3572 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003573 shift = (int)((row_width & 0x01) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003574 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003575 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003576 value = (*sp >> shift) & 0x0f;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003577 *dp = (png_byte)value;
Guy Schalnat0d580581995-07-20 02:43:20 -05003578 if (shift == 4)
3579 {
3580 shift = 0;
3581 sp--;
3582 }
3583 else
3584 shift += 4;
3585
3586 dp--;
3587 }
3588 break;
3589 }
3590 }
3591 row_info->bit_depth = 8;
3592 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003593 row_info->rowbytes = row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003594 }
3595 switch (row_info->bit_depth)
3596 {
3597 case 8:
3598 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003599 if (trans != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05003600 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003601 sp = row + (png_size_t)row_width - 1;
3602 dp = row + (png_size_t)(row_width << 2) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003603
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003604 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003605 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003606 if ((int)(*sp) >= num_trans)
Guy Schalnat0d580581995-07-20 02:43:20 -05003607 *dp-- = 0xff;
3608 else
3609 *dp-- = trans[*sp];
3610 *dp-- = palette[*sp].blue;
3611 *dp-- = palette[*sp].green;
3612 *dp-- = palette[*sp].red;
3613 sp--;
3614 }
3615 row_info->bit_depth = 8;
3616 row_info->pixel_depth = 32;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003617 row_info->rowbytes = row_width * 4;
Guy Schalnat0d580581995-07-20 02:43:20 -05003618 row_info->color_type = 6;
3619 row_info->channels = 4;
3620 }
3621 else
3622 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003623 sp = row + (png_size_t)row_width - 1;
3624 dp = row + (png_size_t)(row_width * 3) - 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003625
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003626 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003627 {
3628 *dp-- = palette[*sp].blue;
3629 *dp-- = palette[*sp].green;
3630 *dp-- = palette[*sp].red;
3631 sp--;
3632 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003633
Guy Schalnat0d580581995-07-20 02:43:20 -05003634 row_info->bit_depth = 8;
3635 row_info->pixel_depth = 24;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003636 row_info->rowbytes = row_width * 3;
Guy Schalnat0d580581995-07-20 02:43:20 -05003637 row_info->color_type = 2;
3638 row_info->channels = 3;
3639 }
3640 break;
3641 }
3642 }
3643 }
3644}
3645
Glenn Randers-Pehrson1ce08362006-03-08 23:35:59 -06003646/* If the bit depth < 8, it is expanded to 8. Also, if the already
3647 * expanded transparency value is supplied, an alpha channel is built.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003648 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003649void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003650png_do_expand(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003651 png_color_16p trans_value)
Guy Schalnat0d580581995-07-20 02:43:20 -05003652{
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003653 int shift, value;
Guy Schalnat6d764711995-12-19 03:22:19 -06003654 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003655 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003656 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003657
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003658 png_debug(1, "in png_do_expand");
Guy Schalnat0d580581995-07-20 02:43:20 -05003659 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05003660 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05003661 {
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05003662 png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003663
3664 if (row_info->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003665 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003666 switch (row_info->bit_depth)
Guy Schalnat0d580581995-07-20 02:43:20 -05003667 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003668 case 1:
3669 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003670 gray = (png_uint_16)((gray&0x01)*0xff);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003671 sp = row + (png_size_t)((row_width - 1) >> 3);
3672 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003673 shift = 7 - (int)((row_width + 7) & 0x07);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003674 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003675 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003676 if ((*sp >> shift) & 0x01)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003677 *dp = 0xff;
3678 else
3679 *dp = 0;
3680 if (shift == 7)
3681 {
3682 shift = 0;
3683 sp--;
3684 }
3685 else
3686 shift++;
3687
3688 dp--;
3689 }
3690 break;
3691 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003692
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003693 case 2:
3694 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003695 gray = (png_uint_16)((gray&0x03)*0x55);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003696 sp = row + (png_size_t)((row_width - 1) >> 2);
3697 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003698 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003699 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003700 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003701 value = (*sp >> shift) & 0x03;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003702 *dp = (png_byte)(value | (value << 2) | (value << 4) |
3703 (value << 6));
3704 if (shift == 6)
3705 {
3706 shift = 0;
3707 sp--;
3708 }
3709 else
3710 shift += 2;
3711
3712 dp--;
3713 }
3714 break;
3715 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003716
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003717 case 4:
3718 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003719 gray = (png_uint_16)((gray&0x0f)*0x11);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003720 sp = row + (png_size_t)((row_width - 1) >> 1);
3721 dp = row + (png_size_t)row_width - 1;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003722 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003723 for (i = 0; i < row_width; i++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003724 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06003725 value = (*sp >> shift) & 0x0f;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003726 *dp = (png_byte)(value | (value << 4));
3727 if (shift == 4)
3728 {
3729 shift = 0;
3730 sp--;
3731 }
3732 else
3733 shift = 4;
3734
3735 dp--;
3736 }
3737 break;
3738 }
3739 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003740
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003741 row_info->bit_depth = 8;
3742 row_info->pixel_depth = 8;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003743 row_info->rowbytes = row_width;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003744 }
3745
Andreas Dilger47a0c421997-05-16 02:46:07 -05003746 if (trans_value != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003747 {
3748 if (row_info->bit_depth == 8)
3749 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003750 gray = gray & 0xff;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003751 sp = row + (png_size_t)row_width - 1;
3752 dp = row + (png_size_t)(row_width << 1) - 1;
3753 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003754 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003755 if (*sp == gray)
3756 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003757 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003758 *dp-- = 0xff;
3759 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003760 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003761 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003762
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003763 else if (row_info->bit_depth == 16)
Guy Schalnat0d580581995-07-20 02:43:20 -05003764 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003765 png_byte gray_high = (gray >> 8) & 0xff;
3766 png_byte gray_low = gray & 0xff;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003767 sp = row + row_info->rowbytes - 1;
3768 dp = row + (row_info->rowbytes << 1) - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003769 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003770 {
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06003771 if (*(sp - 1) == gray_high && *(sp) == gray_low)
Guy Schalnat0d580581995-07-20 02:43:20 -05003772 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003773 *dp-- = 0;
3774 *dp-- = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003775 }
3776 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003777 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003778 *dp-- = 0xff;
3779 *dp-- = 0xff;
Guy Schalnat0d580581995-07-20 02:43:20 -05003780 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003781 *dp-- = *sp--;
3782 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003783 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003784 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003785
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003786 row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
3787 row_info->channels = 2;
3788 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003789 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
3790 row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003791 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003792 }
3793 else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
3794 {
3795 if (row_info->bit_depth == 8)
3796 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003797 png_byte red = trans_value->red & 0xff;
3798 png_byte green = trans_value->green & 0xff;
3799 png_byte blue = trans_value->blue & 0xff;
Guy Schalnat0d580581995-07-20 02:43:20 -05003800 sp = row + (png_size_t)row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003801 dp = row + (png_size_t)(row_width << 2) - 1;
3802 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003803 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003804 if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)
Guy Schalnat0d580581995-07-20 02:43:20 -05003805 *dp-- = 0;
3806 else
3807 *dp-- = 0xff;
3808 *dp-- = *sp--;
3809 *dp-- = *sp--;
3810 *dp-- = *sp--;
3811 }
3812 }
3813 else if (row_info->bit_depth == 16)
3814 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003815 png_byte red_high = (trans_value->red >> 8) & 0xff;
3816 png_byte green_high = (trans_value->green >> 8) & 0xff;
3817 png_byte blue_high = (trans_value->blue >> 8) & 0xff;
3818 png_byte red_low = trans_value->red & 0xff;
3819 png_byte green_low = trans_value->green & 0xff;
3820 png_byte blue_low = trans_value->blue & 0xff;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003821 sp = row + row_info->rowbytes - 1;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003822 dp = row + (png_size_t)(row_width << 3) - 1;
3823 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003824 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003825 if (*(sp - 5) == red_high &&
3826 *(sp - 4) == red_low &&
3827 *(sp - 3) == green_high &&
3828 *(sp - 2) == green_low &&
3829 *(sp - 1) == blue_high &&
3830 *(sp ) == blue_low)
Guy Schalnat0d580581995-07-20 02:43:20 -05003831 {
3832 *dp-- = 0;
3833 *dp-- = 0;
3834 }
3835 else
3836 {
3837 *dp-- = 0xff;
3838 *dp-- = 0xff;
3839 }
3840 *dp-- = *sp--;
3841 *dp-- = *sp--;
3842 *dp-- = *sp--;
3843 *dp-- = *sp--;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003844 *dp-- = *sp--;
Guy Schalnat0d580581995-07-20 02:43:20 -05003845 *dp-- = *sp--;
3846 }
3847 }
3848 row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
3849 row_info->channels = 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003850 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003851 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003852 }
3853 }
3854}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003855#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003856
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003857#if defined(PNG_READ_DITHER_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003858void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003859png_do_dither(png_row_infop row_info, png_bytep row,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003860 png_bytep palette_lookup, png_bytep dither_lookup)
Guy Schalnat0d580581995-07-20 02:43:20 -05003861{
Guy Schalnat6d764711995-12-19 03:22:19 -06003862 png_bytep sp, dp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003863 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003864 png_uint_32 row_width=row_info->width;
Guy Schalnat6d764711995-12-19 03:22:19 -06003865
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003866 png_debug(1, "in png_do_dither");
Guy Schalnat0d580581995-07-20 02:43:20 -05003867 {
3868 if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
3869 palette_lookup && row_info->bit_depth == 8)
3870 {
3871 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003872 sp = row;
3873 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003874 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003875 {
3876 r = *sp++;
3877 g = *sp++;
3878 b = *sp++;
3879
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003880 /* This looks real messy, but the compiler will reduce
3881 * it down to a reasonable formula. For example, with
3882 * 5 bits per color, we get:
3883 * p = (((r >> 3) & 0x1f) << 10) |
3884 * (((g >> 3) & 0x1f) << 5) |
3885 * ((b >> 3) & 0x1f);
3886 */
Guy Schalnat0d580581995-07-20 02:43:20 -05003887 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
3888 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
3889 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3890 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003891 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003892 (PNG_DITHER_BLUE_BITS)) |
3893 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3894 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3895
3896 *dp++ = palette_lookup[p];
3897 }
3898 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3899 row_info->channels = 1;
3900 row_info->pixel_depth = row_info->bit_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003901 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003902 }
3903 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
Andreas Dilger47a0c421997-05-16 02:46:07 -05003904 palette_lookup != NULL && row_info->bit_depth == 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003905 {
3906 int r, g, b, p;
Guy Schalnat0d580581995-07-20 02:43:20 -05003907 sp = row;
3908 dp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003909 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003910 {
3911 r = *sp++;
3912 g = *sp++;
3913 b = *sp++;
3914 sp++;
3915
3916 p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003917 ((1 << PNG_DITHER_RED_BITS) - 1)) <<
Guy Schalnat0d580581995-07-20 02:43:20 -05003918 (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
3919 (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
3920 ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
3921 (PNG_DITHER_BLUE_BITS)) |
3922 ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
3923 ((1 << PNG_DITHER_BLUE_BITS) - 1));
3924
3925 *dp++ = palette_lookup[p];
3926 }
3927 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
3928 row_info->channels = 1;
3929 row_info->pixel_depth = row_info->bit_depth;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003930 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003931 }
3932 else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
3933 dither_lookup && row_info->bit_depth == 8)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06003934 {
Guy Schalnat0d580581995-07-20 02:43:20 -05003935 sp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003936 for (i = 0; i < row_width; i++, sp++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003937 {
3938 *sp = dither_lookup[*sp];
3939 }
3940 }
3941 }
3942}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003943#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003944
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003945#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003946#if defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003947static PNG_CONST int png_gamma_shift[] =
3948 {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0, 0x00};
Guy Schalnat0d580581995-07-20 02:43:20 -05003949
Andreas Dilger47a0c421997-05-16 02:46:07 -05003950/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003951 * tables, we don't make a full table if we are reducing to 8-bit in
3952 * the future. Note also how the gamma_16 tables are segmented so that
3953 * we don't need to allocate > 64K chunks for a full 16-bit table.
3954 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003955void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003956png_build_gamma_table(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003957{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003958 png_debug(1, "in png_build_gamma_table");
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003959
3960 if (png_ptr->bit_depth <= 8)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003961 {
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003962 int i;
3963 double g;
Guy Schalnat0d580581995-07-20 02:43:20 -05003964
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003965 if (png_ptr->screen_gamma > .000001)
3966 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05003967
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003968 else
3969 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003970
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003971 png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
3972 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05003973
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003974 for (i = 0; i < 256; i++)
3975 {
3976 png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
3977 g) * 255.0 + .5);
3978 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003979
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003980#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003981 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
3982 if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
3983 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003984
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003985 g = 1.0 / (png_ptr->gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05003986
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003987 png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
3988 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05003989
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003990 for (i = 0; i < 256; i++)
3991 {
3992 png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
3993 g) * 255.0 + .5);
3994 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003995
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003996
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003997 png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
3998 (png_uint_32)256);
Guy Schalnat0d580581995-07-20 02:43:20 -05003999
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004000 if (png_ptr->screen_gamma > 0.000001)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004001 g = 1.0 / png_ptr->screen_gamma;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004002
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004003 else
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05004004 g = png_ptr->gamma; /* Probably doing rgb_to_gray */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004005
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004006 for (i = 0; i < 256; i++)
4007 {
4008 png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
4009 g) * 255.0 + .5);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004010
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004011 }
4012 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004013#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004014 }
4015 else
4016 {
4017 double g;
4018 int i, j, shift, num;
4019 int sig_bit;
4020 png_uint_32 ig;
Guy Schalnat0d580581995-07-20 02:43:20 -05004021
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004022 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
4023 {
4024 sig_bit = (int)png_ptr->sig_bit.red;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004025
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004026 if ((int)png_ptr->sig_bit.green > sig_bit)
4027 sig_bit = png_ptr->sig_bit.green;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004028
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004029 if ((int)png_ptr->sig_bit.blue > sig_bit)
4030 sig_bit = png_ptr->sig_bit.blue;
4031 }
4032 else
4033 {
4034 sig_bit = (int)png_ptr->sig_bit.gray;
4035 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004036
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004037 if (sig_bit > 0)
4038 shift = 16 - sig_bit;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004039
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004040 else
4041 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05004042
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004043 if (png_ptr->transformations & PNG_16_TO_8)
4044 {
4045 if (shift < (16 - PNG_MAX_GAMMA_8))
4046 shift = (16 - PNG_MAX_GAMMA_8);
4047 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004048
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004049 if (shift > 8)
4050 shift = 8;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004051
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004052 if (shift < 0)
4053 shift = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05004054
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004055 png_ptr->gamma_shift = (png_byte)shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05004056
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004057 num = (1 << (8 - shift));
Guy Schalnat0d580581995-07-20 02:43:20 -05004058
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004059 if (png_ptr->screen_gamma > .000001)
4060 g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
4061 else
4062 g = 1.0;
Guy Schalnat0d580581995-07-20 02:43:20 -05004063
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004064#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06004065 png_ptr->gamma_16_table = (png_uint_16pp)png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004066 (png_uint_32)(num * png_sizeof(png_uint_16p)));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004067#else
4068 png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
4069 (png_uint_32)(num * png_sizeof(png_uint_16p)));
Glenn Randers-Pehrsond60c8862009-06-15 21:56:14 -05004070 png_memset(png_ptr->gamma_16_table, 0, num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004071#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05004072
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004073 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
4074 {
4075 double fin, fout;
4076 png_uint_32 last, max;
Guy Schalnat0d580581995-07-20 02:43:20 -05004077
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004078 for (i = 0; i < num; i++)
4079 {
4080 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004081 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004082 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004083
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004084 g = 1.0 / g;
4085 last = 0;
4086 for (i = 0; i < 256; i++)
4087 {
4088 fout = ((double)i + 0.5) / 256.0;
4089 fin = pow(fout, g);
4090 max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
4091 while (last <= max)
4092 {
4093 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4094 [(int)(last >> (8 - shift))] = (png_uint_16)(
4095 (png_uint_16)i | ((png_uint_16)i << 8));
4096 last++;
4097 }
4098 }
4099 while (last < ((png_uint_32)num << 8))
4100 {
4101 png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
4102 [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
4103 last++;
4104 }
4105 }
4106 else
4107 {
4108 for (i = 0; i < num; i++)
4109 {
4110 png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004111 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004112
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004113 ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004114
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004115 for (j = 0; j < 256; j++)
4116 {
4117 png_ptr->gamma_16_table[i][j] =
4118 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4119 65535.0, g) * 65535.0 + .5);
4120 }
4121 }
4122 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004123
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004124#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004125 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4126 if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
4127 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004128
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004129 g = 1.0 / (png_ptr->gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -05004130
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004131#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06004132 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004133 (png_uint_32)(num * png_sizeof(png_uint_16p )));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004134#else
4135 png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
4136 (png_uint_32)(num * png_sizeof(png_uint_16p )));
Glenn Randers-Pehrsond60c8862009-06-15 21:56:14 -05004137 png_memset(png_ptr->gamma_16_to_1, 0, num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004138#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05004139
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004140 for (i = 0; i < num; i++)
4141 {
4142 png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004143 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004144
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004145 ig = (((png_uint_32)i *
4146 (png_uint_32)png_gamma_shift[shift]) >> 4);
4147 for (j = 0; j < 256; j++)
4148 {
4149 png_ptr->gamma_16_to_1[i][j] =
4150 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4151 65535.0, g) * 65535.0 + .5);
4152 }
4153 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004154
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004155 if (png_ptr->screen_gamma > 0.000001)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004156 g = 1.0 / png_ptr->screen_gamma;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004157
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004158 else
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05004159 g = png_ptr->gamma; /* Probably doing rgb_to_gray */
Guy Schalnat0d580581995-07-20 02:43:20 -05004160
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004161#ifdef PNG_CALLOC_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06004162 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_calloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004163 (png_uint_32)(num * png_sizeof(png_uint_16p)));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004164#else
4165 png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
4166 (png_uint_32)(num * png_sizeof(png_uint_16p)));
4167 png_memset(png_ptr->gamma_16_from_1, 0,
Glenn Randers-Pehrsond60c8862009-06-15 21:56:14 -05004168 num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson0ffb71a2009-02-28 06:08:20 -06004169#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05004170
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004171 for (i = 0; i < num; i++)
4172 {
4173 png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004174 (png_uint_32)(256 * png_sizeof(png_uint_16)));
Guy Schalnat0d580581995-07-20 02:43:20 -05004175
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004176 ig = (((png_uint_32)i *
4177 (png_uint_32)png_gamma_shift[shift]) >> 4);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004178
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004179 for (j = 0; j < 256; j++)
4180 {
4181 png_ptr->gamma_16_from_1[i][j] =
4182 (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
4183 65535.0, g) * 65535.0 + .5);
4184 }
4185 }
4186 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06004187#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004188 }
Guy Schalnat0d580581995-07-20 02:43:20 -05004189}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004190#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06004191/* To do: install integer version of png_build_gamma_table here */
4192#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05004193
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004194#if defined(PNG_MNG_FEATURES_SUPPORTED)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05004195/* Undoes intrapixel differencing */
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004196void /* PRIVATE */
4197png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
4198{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05004199 png_debug(1, "in png_do_read_intrapixel");
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004200 if (
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004201 (row_info->color_type & PNG_COLOR_MASK_COLOR))
4202 {
4203 int bytes_per_pixel;
4204 png_uint_32 row_width = row_info->width;
4205 if (row_info->bit_depth == 8)
4206 {
4207 png_bytep rp;
4208 png_uint_32 i;
4209
4210 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4211 bytes_per_pixel = 3;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004212
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004213 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4214 bytes_per_pixel = 4;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004215
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004216 else
4217 return;
4218
4219 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4220 {
4221 *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff);
4222 *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff);
4223 }
4224 }
4225 else if (row_info->bit_depth == 16)
4226 {
4227 png_bytep rp;
4228 png_uint_32 i;
4229
4230 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
4231 bytes_per_pixel = 6;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004232
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004233 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
4234 bytes_per_pixel = 8;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05004235
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004236 else
4237 return;
4238
4239 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
4240 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05004241 png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1);
4242 png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3);
4243 png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5);
4244 png_uint_32 red = (png_uint_32)((s0 + s1 + 65536L) & 0xffffL);
4245 png_uint_32 blue = (png_uint_32)((s2 + s1 + 65536L) & 0xffffL);
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05004246 *(rp ) = (png_byte)((red >> 8) & 0xff);
4247 *(rp+1) = (png_byte)(red & 0xff);
4248 *(rp+4) = (png_byte)((blue >> 8) & 0xff);
4249 *(rp+5) = (png_byte)(blue & 0xff);
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -06004250 }
4251 }
4252 }
4253}
4254#endif /* PNG_MNG_FEATURES_SUPPORTED */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06004255#endif /* PNG_READ_SUPPORTED */