blob: 0dab2264de6ef3021e2ec8328b652eb3d99ed277 [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002/* png.c - location for general purpose libpng functions
3 *
Glenn Randers-Pehrson47539062011-05-05 07:32:30 -05004 * Last changed in libpng 1.5.3 [(PENDING RELEASE)]
Glenn Randers-Pehrson64b863c2011-01-04 09:57:06 -06005 * Copyright (c) 1998-2011 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-Pehrson3e61d792009-06-24 09:31:28 -05008 *
Glenn Randers-Pehrsonbfbf8652009-06-26 21:46:52 -05009 * This code is released under the libpng license.
Glenn Randers-Pehrsonc332bbc2009-06-25 13:43:50 -050010 * For conditions of distribution and use, see the disclaimer
Glenn Randers-Pehrson037023b2009-06-24 10:27:36 -050011 * and license in png.h
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060012 */
Guy Schalnat0d580581995-07-20 02:43:20 -050013
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050014#include "pngpriv.h"
Guy Schalnat0d580581995-07-20 02:43:20 -050015
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -060016/* Generate a compiler error if there is an old png.h in the search path. */
Glenn Randers-Pehrsonfb278732011-06-10 20:43:39 -050017typedef png_libpng_version_1_5_3beta11 Your_png_h_is_not_version_1_5_3beta11;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -060018
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060019/* Tells libpng that we have already handled the first "num_bytes" bytes
20 * of the PNG file signature. If the PNG data is embedded into another
21 * stream we can set num_bytes = 8 so that libpng will not attempt to read
22 * or write any of the magic bytes before it starts on the IHDR.
23 */
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -050024
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060025#ifdef PNG_READ_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050026void PNGAPI
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060027png_set_sig_bytes(png_structp png_ptr, int num_bytes)
28{
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -050029 png_debug(1, "in png_set_sig_bytes");
30
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050031 if (png_ptr == NULL)
32 return;
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -050033
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060034 if (num_bytes > 8)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050035 png_error(png_ptr, "Too many bytes for PNG signature");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060036
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -050037 png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060038}
39
40/* Checks whether the supplied bytes match the PNG signature. We allow
41 * checking less than the full 8-byte signature so that those apps that
42 * already read the first few bytes of a file to determine the file type
43 * can simply check the remaining bytes for extra assurance. Returns
44 * an integer less than, equal to, or greater than zero if sig is found,
45 * respectively, to be less than, to match, or be greater than the correct
46 * PNG signature (this is the same behaviour as strcmp, memcmp, etc).
47 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050048int PNGAPI
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -050049png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060050{
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -060051 png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -050052
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060053 if (num_to_check > 8)
54 num_to_check = 8;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -050055
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060056 else if (num_to_check < 1)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060057 return (-1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060058
Andreas Dilger47a0c421997-05-16 02:46:07 -050059 if (start > 7)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060060 return (-1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060061
62 if (start + num_to_check > 8)
63 num_to_check = 8 - start;
64
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050065 return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check)));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060066}
67
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060068#endif /* PNG_READ_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -050069
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060070#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
Glenn Randers-Pehrsonc5080812010-10-23 08:26:26 -050071/* Function to allocate memory for zlib */
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -050072PNG_FUNCTION(voidpf /* PRIVATE */,
73png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)
Guy Schalnat0d580581995-07-20 02:43:20 -050074{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050075 png_voidp ptr;
76 png_structp p=(png_structp)png_ptr;
77 png_uint_32 save_flags=p->flags;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050078 png_alloc_size_t num_bytes;
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050079
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050080 if (png_ptr == NULL)
81 return (NULL);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -050082
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050083 if (items > PNG_UINT_32_MAX/size)
84 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050085 png_warning (p, "Potential overflow in png_zalloc()");
86 return (NULL);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050087 }
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050088 num_bytes = (png_alloc_size_t)items * size;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -060089
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050090 p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK;
91 ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes);
92 p->flags=save_flags;
Guy Schalnat6d764711995-12-19 03:22:19 -060093
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050094 return ((voidpf)ptr);
95}
96
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050097/* Function to free memory for zlib */
Glenn Randers-Pehrson3f705ba2009-07-23 12:53:06 -050098void /* PRIVATE */
Guy Schalnat51f0eb41995-09-26 05:22:39 -050099png_zfree(voidpf png_ptr, voidpf ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500100{
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600101 png_free((png_structp)png_ptr, (png_voidp)ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500102}
103
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600104/* Reset the CRC variable to 32 bits of 1's. Care must be taken
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600105 * in case CRC is > 32 bits to leave the top bits 0.
106 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500107void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -0600108png_reset_crc(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500109{
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600110 png_ptr->crc = crc32(0, Z_NULL, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500111}
112
Andreas Dilger47a0c421997-05-16 02:46:07 -0500113/* Calculate the CRC over a section of data. We can only pass as
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600114 * much data to this routine as the largest single buffer size. We
115 * also check that this data will actually be used before going to the
116 * trouble of calculating it.
117 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500118void /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500119png_calculate_crc(png_structp png_ptr, png_const_bytep ptr, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500120{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500121 int need_crc = 1;
122
123 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
124 {
125 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
126 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
127 need_crc = 0;
128 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500129
Andreas Dilger47a0c421997-05-16 02:46:07 -0500130 else /* critical */
131 {
132 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
133 need_crc = 0;
134 }
135
136 if (need_crc)
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600137 png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500138}
Guy Schalnate5a37791996-06-05 15:50:50 -0500139
John Bowler88b77cc2011-05-05 06:49:55 -0500140/* Check a user supplied version number, called from both read and write
141 * functions that create a png_struct
142 */
143int
144png_user_version_check(png_structp png_ptr, png_const_charp user_png_ver)
145{
146 if (user_png_ver)
147 {
148 int i = 0;
149
150 do
151 {
152 if (user_png_ver[i] != png_libpng_ver[i])
153 png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
154 } while (png_libpng_ver[i++]);
155 }
156
157 else
158 png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
159
160 if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
161 {
162 /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
163 * we must recompile any applications that use any older library version.
164 * For versions after libpng 1.0, we will be compatible, so we need
165 * only check the first digit.
166 */
167 if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
168 (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
169 (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
170 {
171#ifdef PNG_WARNINGS_SUPPORTED
172 size_t pos = 0;
173 char m[128];
174
175 pos = png_safecat(m, sizeof m, pos, "Application built with libpng-");
176 pos = png_safecat(m, sizeof m, pos, user_png_ver);
177 pos = png_safecat(m, sizeof m, pos, " but running with ");
178 pos = png_safecat(m, sizeof m, pos, png_libpng_ver);
179
180 png_warning(png_ptr, m);
181#endif
182
183#ifdef PNG_ERROR_NUMBERS_SUPPORTED
184 png_ptr->flags = 0;
185#endif
186
187 return 0;
188 }
189 }
190
191 /* Success return. */
192 return 1;
193}
194
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600195/* Allocate the memory for an info_struct for the application. We don't
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600196 * really need the png_ptr, but it could potentially be useful in the
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500197 * future. This should be used in favour of malloc(png_sizeof(png_info))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600198 * and png_info_init() so that applications that want to use a shared
199 * libpng don't have to be recompiled if png_info changes size.
200 */
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -0500201PNG_FUNCTION(png_infop,PNGAPI
202png_create_info_struct,(png_structp png_ptr),PNG_ALLOCATED)
Guy Schalnate5a37791996-06-05 15:50:50 -0500203{
204 png_infop info_ptr;
205
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500206 png_debug(1, "in png_create_info_struct");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500207
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500208 if (png_ptr == NULL)
209 return (NULL);
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500210
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500211#ifdef PNG_USER_MEM_SUPPORTED
Glenn Randers-Pehrson5cded0b2001-11-07 07:10:08 -0600212 info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO,
213 png_ptr->malloc_fn, png_ptr->mem_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500214#else
Glenn Randers-Pehrson5cded0b2001-11-07 07:10:08 -0600215 info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500216#endif
Glenn Randers-Pehrson5cded0b2001-11-07 07:10:08 -0600217 if (info_ptr != NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500218 png_info_init_3(&info_ptr, png_sizeof(png_info));
Guy Schalnate5a37791996-06-05 15:50:50 -0500219
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600220 return (info_ptr);
Guy Schalnate5a37791996-06-05 15:50:50 -0500221}
222
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600223/* This function frees the memory associated with a single info struct.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600224 * Normally, one would use either png_destroy_read_struct() or
225 * png_destroy_write_struct() to free an info struct, but this may be
226 * useful for some applications.
227 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500228void PNGAPI
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600229png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr)
230{
231 png_infop info_ptr = NULL;
232
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500233 png_debug(1, "in png_destroy_info_struct");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500234
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500235 if (png_ptr == NULL)
236 return;
237
Andreas Dilger47a0c421997-05-16 02:46:07 -0500238 if (info_ptr_ptr != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600239 info_ptr = *info_ptr_ptr;
240
Andreas Dilger47a0c421997-05-16 02:46:07 -0500241 if (info_ptr != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600242 {
243 png_info_destroy(png_ptr, info_ptr);
244
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500245#ifdef PNG_USER_MEM_SUPPORTED
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500246 png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn,
247 png_ptr->mem_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500248#else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600249 png_destroy_struct((png_voidp)info_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500250#endif
Glenn Randers-Pehrson3f549252001-10-27 07:35:13 -0500251 *info_ptr_ptr = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600252 }
253}
254
255/* Initialize the info structure. This is now an internal function (0.89)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600256 * and applications using it are urged to use png_create_info_struct()
257 * instead.
258 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500259
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500260void PNGAPI
261png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size)
262{
263 png_infop info_ptr = *ptr_ptr;
264
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500265 png_debug(1, "in png_info_init_3");
266
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500267 if (info_ptr == NULL)
268 return;
Glenn Randers-Pehrson6b12c082006-11-14 10:53:30 -0600269
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500270 if (png_sizeof(png_info) > png_info_struct_size)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500271 {
272 png_destroy_struct(info_ptr);
273 info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
274 *ptr_ptr = info_ptr;
275 }
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500276
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500277 /* Set everything to 0 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500278 png_memset(info_ptr, 0, png_sizeof(png_info));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600279}
280
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500281void PNGAPI
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500282png_data_freer(png_structp png_ptr, png_infop info_ptr,
283 int freer, png_uint_32 mask)
284{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500285 png_debug(1, "in png_data_freer");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500286
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500287 if (png_ptr == NULL || info_ptr == NULL)
288 return;
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500289
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500290 if (freer == PNG_DESTROY_WILL_FREE_DATA)
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500291 info_ptr->free_me |= mask;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500292
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500293 else if (freer == PNG_USER_WILL_FREE_DATA)
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500294 info_ptr->free_me &= ~mask;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500295
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500296 else
297 png_warning(png_ptr,
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500298 "Unknown freer parameter in png_data_freer");
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500299}
300
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500301void PNGAPI
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500302png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
303 int num)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600304{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500305 png_debug(1, "in png_free_data");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500306
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600307 if (png_ptr == NULL || info_ptr == NULL)
308 return;
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600309
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500310#ifdef PNG_TEXT_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500311 /* Free text item num or (if num == -1) all text items */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500312 if ((mask & PNG_FREE_TEXT) & info_ptr->free_me)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600313 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500314 if (num != -1)
315 {
316 if (info_ptr->text && info_ptr->text[num].key)
317 {
318 png_free(png_ptr, info_ptr->text[num].key);
319 info_ptr->text[num].key = NULL;
320 }
321 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500322
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500323 else
324 {
325 int i;
326 for (i = 0; i < info_ptr->num_text; i++)
327 png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i);
328 png_free(png_ptr, info_ptr->text);
329 info_ptr->text = NULL;
330 info_ptr->num_text=0;
331 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600332 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600333#endif
334
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500335#ifdef PNG_tRNS_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500336 /* Free any tRNS entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500337 if ((mask & PNG_FREE_TRNS) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500338 {
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -0500339 png_free(png_ptr, info_ptr->trans_alpha);
340 info_ptr->trans_alpha = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500341 info_ptr->valid &= ~PNG_INFO_tRNS;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500342 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600343#endif
344
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500345#ifdef PNG_sCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500346 /* Free any sCAL entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500347 if ((mask & PNG_FREE_SCAL) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500348 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500349 png_free(png_ptr, info_ptr->scal_s_width);
350 png_free(png_ptr, info_ptr->scal_s_height);
351 info_ptr->scal_s_width = NULL;
352 info_ptr->scal_s_height = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500353 info_ptr->valid &= ~PNG_INFO_sCAL;
354 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600355#endif
356
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500357#ifdef PNG_pCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500358 /* Free any pCAL entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500359 if ((mask & PNG_FREE_PCAL) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500360 {
361 png_free(png_ptr, info_ptr->pcal_purpose);
362 png_free(png_ptr, info_ptr->pcal_units);
363 info_ptr->pcal_purpose = NULL;
364 info_ptr->pcal_units = NULL;
365 if (info_ptr->pcal_params != NULL)
366 {
367 int i;
368 for (i = 0; i < (int)info_ptr->pcal_nparams; i++)
369 {
370 png_free(png_ptr, info_ptr->pcal_params[i]);
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600371 info_ptr->pcal_params[i] = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500372 }
373 png_free(png_ptr, info_ptr->pcal_params);
374 info_ptr->pcal_params = NULL;
375 }
376 info_ptr->valid &= ~PNG_INFO_pCAL;
377 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600378#endif
379
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500380#ifdef PNG_iCCP_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500381 /* Free any iCCP entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500382 if ((mask & PNG_FREE_ICCP) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500383 {
384 png_free(png_ptr, info_ptr->iccp_name);
385 png_free(png_ptr, info_ptr->iccp_profile);
386 info_ptr->iccp_name = NULL;
387 info_ptr->iccp_profile = NULL;
388 info_ptr->valid &= ~PNG_INFO_iCCP;
389 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600390#endif
391
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500392#ifdef PNG_sPLT_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500393 /* Free a given sPLT entry, or (if num == -1) all sPLT entries */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500394 if ((mask & PNG_FREE_SPLT) & info_ptr->free_me)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600395 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500396 if (num != -1)
Glenn Randers-Pehrsonfc4a1432000-05-17 17:39:34 -0500397 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500398 if (info_ptr->splt_palettes)
399 {
400 png_free(png_ptr, info_ptr->splt_palettes[num].name);
401 png_free(png_ptr, info_ptr->splt_palettes[num].entries);
402 info_ptr->splt_palettes[num].name = NULL;
403 info_ptr->splt_palettes[num].entries = NULL;
404 }
405 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500406
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500407 else
408 {
409 if (info_ptr->splt_palettes_num)
410 {
411 int i;
412 for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
413 png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i);
414
415 png_free(png_ptr, info_ptr->splt_palettes);
416 info_ptr->splt_palettes = NULL;
417 info_ptr->splt_palettes_num = 0;
418 }
419 info_ptr->valid &= ~PNG_INFO_sPLT;
Glenn Randers-Pehrsonfc4a1432000-05-17 17:39:34 -0500420 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600421 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600422#endif
423
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500424#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500425 if (png_ptr->unknown_chunk.data)
426 {
427 png_free(png_ptr, png_ptr->unknown_chunk.data);
428 png_ptr->unknown_chunk.data = NULL;
429 }
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500430
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500431 if ((mask & PNG_FREE_UNKN) & info_ptr->free_me)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600432 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500433 if (num != -1)
434 {
435 if (info_ptr->unknown_chunks)
436 {
437 png_free(png_ptr, info_ptr->unknown_chunks[num].data);
438 info_ptr->unknown_chunks[num].data = NULL;
439 }
440 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500441
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500442 else
443 {
444 int i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600445
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500446 if (info_ptr->unknown_chunks_num)
447 {
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -0500448 for (i = 0; i < info_ptr->unknown_chunks_num; i++)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500449 png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600450
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500451 png_free(png_ptr, info_ptr->unknown_chunks);
452 info_ptr->unknown_chunks = NULL;
453 info_ptr->unknown_chunks_num = 0;
454 }
455 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600456 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600457#endif
458
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500459#ifdef PNG_hIST_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500460 /* Free any hIST entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500461 if ((mask & PNG_FREE_HIST) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500462 {
463 png_free(png_ptr, info_ptr->hist);
464 info_ptr->hist = NULL;
465 info_ptr->valid &= ~PNG_INFO_hIST;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500466 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600467#endif
468
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500469 /* Free any PLTE entry that was internally allocated */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500470 if ((mask & PNG_FREE_PLTE) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500471 {
472 png_zfree(png_ptr, info_ptr->palette);
473 info_ptr->palette = NULL;
474 info_ptr->valid &= ~PNG_INFO_PLTE;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500475 info_ptr->num_palette = 0;
476 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600477
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500478#ifdef PNG_INFO_IMAGE_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500479 /* Free any image bits attached to the info structure */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500480 if ((mask & PNG_FREE_ROWS) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500481 {
482 if (info_ptr->row_pointers)
483 {
484 int row;
485 for (row = 0; row < (int)info_ptr->height; row++)
486 {
487 png_free(png_ptr, info_ptr->row_pointers[row]);
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600488 info_ptr->row_pointers[row] = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500489 }
490 png_free(png_ptr, info_ptr->row_pointers);
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600491 info_ptr->row_pointers = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500492 }
493 info_ptr->valid &= ~PNG_INFO_IDAT;
494 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600495#endif
Glenn Randers-Pehrsonfc4a1432000-05-17 17:39:34 -0500496
John Bowler56a739b2010-12-19 16:33:20 -0600497 if (num != -1)
498 mask &= ~PNG_FREE_MUL;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500499
John Bowler56a739b2010-12-19 16:33:20 -0600500 info_ptr->free_me &= ~mask;
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600501}
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600502
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600503/* This is an internal routine to free any memory that the info struct is
Andreas Dilger47a0c421997-05-16 02:46:07 -0500504 * pointing to before re-using it or freeing the struct itself. Recall
505 * that png_free() checks for NULL pointers for us.
506 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500507void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600508png_info_destroy(png_structp png_ptr, png_infop info_ptr)
509{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500510 png_debug(1, "in png_info_destroy");
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600511
512 png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
Glenn Randers-Pehrsond56aca72000-11-23 11:51:42 -0600513
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500514#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600515 if (png_ptr->num_chunk_list)
516 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500517 png_free(png_ptr, png_ptr->chunk_list);
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600518 png_ptr->chunk_list = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500519 png_ptr->num_chunk_list = 0;
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600520 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600521#endif
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600522
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500523 png_info_init_3(&info_ptr, png_sizeof(png_info));
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500524}
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600525#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500526
Guy Schalnate5a37791996-06-05 15:50:50 -0500527/* This function returns a pointer to the io_ptr associated with the user
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600528 * functions. The application should free any memory associated with this
529 * pointer before png_write_destroy() or png_read_destroy() are called.
530 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500531png_voidp PNGAPI
Guy Schalnate5a37791996-06-05 15:50:50 -0500532png_get_io_ptr(png_structp png_ptr)
533{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500534 if (png_ptr == NULL)
535 return (NULL);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500536
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600537 return (png_ptr->io_ptr);
Guy Schalnate5a37791996-06-05 15:50:50 -0500538}
Andreas Dilger47a0c421997-05-16 02:46:07 -0500539
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600540#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600541# ifdef PNG_STDIO_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500542/* Initialize the default input/output functions for the PNG file. If you
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600543 * use your own read or write routines, you can call either png_set_read_fn()
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500544 * or png_set_write_fn() instead of png_init_io(). If you have defined
545 * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't
546 * necessarily available.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600547 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500548void PNGAPI
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500549png_init_io(png_structp png_ptr, png_FILE_p fp)
Guy Schalnate5a37791996-06-05 15:50:50 -0500550{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500551 png_debug(1, "in png_init_io");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500552
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500553 if (png_ptr == NULL)
554 return;
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500555
Guy Schalnate5a37791996-06-05 15:50:50 -0500556 png_ptr->io_ptr = (png_voidp)fp;
557}
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600558# endif
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500559
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600560# ifdef PNG_TIME_RFC1123_SUPPORTED
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500561/* Convert the supplied time into an RFC 1123 string suitable for use in
562 * a "Creation Time" or other text-based time string.
563 */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500564png_const_charp PNGAPI
565png_convert_to_rfc1123(png_structp png_ptr, png_const_timep ptime)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500566{
567 static PNG_CONST char short_months[12][4] =
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600568 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
569 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500570
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500571 if (png_ptr == NULL)
572 return (NULL);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500573
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500574 {
John Bowler88b77cc2011-05-05 06:49:55 -0500575 size_t pos = 0;
576 char number_buf[5]; /* enough for a four digit year */
577
578# define APPEND_STRING(string)\
579 pos = png_safecat(png_ptr->time_buffer, sizeof png_ptr->time_buffer,\
580 pos, (string))
581# define APPEND_NUMBER(format, value)\
582 APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value)))
583# define APPEND(ch)\
584 if (pos < (sizeof png_ptr->time_buffer)-1)\
585 png_ptr->time_buffer[pos++] = (ch)
Glenn Randers-Pehrsonaf855e42011-05-07 10:52:49 -0500586
John Bowlerd273ad22011-05-07 21:00:28 -0500587 APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day % 32);
John Bowler88b77cc2011-05-05 06:49:55 -0500588 APPEND(' ');
589 APPEND_STRING(short_months[(ptime->month - 1) % 12]);
590 APPEND(' ');
591 APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year);
592 APPEND(' ');
John Bowlerd273ad22011-05-07 21:00:28 -0500593 APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour % 24);
John Bowler88b77cc2011-05-05 06:49:55 -0500594 APPEND(':');
John Bowlerd273ad22011-05-07 21:00:28 -0500595 APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute % 60);
John Bowler88b77cc2011-05-05 06:49:55 -0500596 APPEND(':');
John Bowlerd273ad22011-05-07 21:00:28 -0500597 APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second % 61);
John Bowler88b77cc2011-05-05 06:49:55 -0500598 APPEND_STRING(" +0000"); /* This reliably terminates the buffer */
599
600# undef APPEND
601# undef APPEND_NUMBER
602# undef APPEND_STRING
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500603 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500604
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500605 return png_ptr->time_buffer;
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500606}
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600607# endif /* PNG_TIME_RFC1123_SUPPORTED */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600608
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600609#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600610
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500611png_const_charp PNGAPI
John Bowler0a5c9c02011-01-22 17:36:34 -0600612png_get_copyright(png_const_structp png_ptr)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600613{
Glenn Randers-Pehrsond546f432010-12-04 20:41:36 -0600614 PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500615#ifdef PNG_STRING_COPYRIGHT
Glenn Randers-Pehrsond546f432010-12-04 20:41:36 -0600616 return PNG_STRING_COPYRIGHT
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500617#else
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600618# ifdef __STDC__
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500619 return PNG_STRING_NEWLINE \
Glenn Randers-Pehrsonfb278732011-06-10 20:43:39 -0500620 "libpng version 1.5.3beta11 - June 11, 2011" PNG_STRING_NEWLINE \
Glenn Randers-Pehrson64b863c2011-01-04 09:57:06 -0600621 "Copyright (c) 1998-2011 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \
Glenn Randers-Pehrson43aaf6e2008-08-05 22:17:03 -0500622 "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
623 "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500624 PNG_STRING_NEWLINE;
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600625# else
Glenn Randers-Pehrsonfb278732011-06-10 20:43:39 -0500626 return "libpng version 1.5.3beta11 - June 11, 2011\
Glenn Randers-Pehrson64b863c2011-01-04 09:57:06 -0600627 Copyright (c) 1998-2011 Glenn Randers-Pehrson\
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500628 Copyright (c) 1996-1997 Andreas Dilger\
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500629 Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600630# endif
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500631#endif
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600632}
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -0500633
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600634/* The following return the library version as a short string in the
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500635 * format 1.0.0 through 99.99.99zz. To get the version of *.h files
636 * used with your application, print out PNG_LIBPNG_VER_STRING, which
637 * is defined in png.h.
638 * Note: now there is no difference between png_get_libpng_ver() and
639 * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard,
640 * it is guaranteed that png.c uses the correct version of png.h.
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600641 */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500642png_const_charp PNGAPI
John Bowler0a5c9c02011-01-22 17:36:34 -0600643png_get_libpng_ver(png_const_structp png_ptr)
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600644{
645 /* Version of *.c files used when building libpng */
Glenn Randers-Pehrson4c8f7262010-03-16 19:30:01 -0500646 return png_get_header_ver(png_ptr);
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600647}
648
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500649png_const_charp PNGAPI
John Bowler0a5c9c02011-01-22 17:36:34 -0600650png_get_header_ver(png_const_structp png_ptr)
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600651{
652 /* Version of *.h files used when building libpng */
Glenn Randers-Pehrsond546f432010-12-04 20:41:36 -0600653 PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500654 return PNG_LIBPNG_VER_STRING;
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600655}
656
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500657png_const_charp PNGAPI
John Bowler0a5c9c02011-01-22 17:36:34 -0600658png_get_header_version(png_const_structp png_ptr)
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600659{
660 /* Returns longer string containing both version and date */
Glenn Randers-Pehrsond546f432010-12-04 20:41:36 -0600661 PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500662#ifdef __STDC__
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500663 return PNG_HEADER_VERSION_STRING
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600664# ifndef PNG_READ_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500665 " (NO READ SUPPORT)"
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600666# endif
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500667 PNG_STRING_NEWLINE;
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500668#else
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500669 return PNG_HEADER_VERSION_STRING;
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500670#endif
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600671}
672
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600673#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600674# ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrsonc1bfe682002-03-06 22:08:00 -0600675int PNGAPI
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500676png_handle_as_unknown(png_structp png_ptr, png_const_bytep chunk_name)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600677{
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500678 /* Check chunk_name and return "keep" value if it's on the list, else 0 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600679 int i;
680 png_bytep p;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500681 if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list<=0)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600682 return 0;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500683
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500684 p = png_ptr->chunk_list + png_ptr->num_chunk_list*5 - 5;
685 for (i = png_ptr->num_chunk_list; i; i--, p -= 5)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600686 if (!png_memcmp(chunk_name, p, 4))
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500687 return ((int)*(p + 4));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600688 return 0;
689}
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600690# endif
Glenn Randers-Pehrsonf10fa3c2010-04-29 08:25:29 -0500691#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
Glenn Randers-Pehrson228bd392000-04-23 23:14:02 -0500692
Glenn Randers-Pehrsonf10fa3c2010-04-29 08:25:29 -0500693#ifdef PNG_READ_SUPPORTED
Glenn Randers-Pehrson228bd392000-04-23 23:14:02 -0500694/* This function, added to libpng-1.0.6g, is untested. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500695int PNGAPI
Glenn Randers-Pehrson228bd392000-04-23 23:14:02 -0500696png_reset_zstream(png_structp png_ptr)
697{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500698 if (png_ptr == NULL)
699 return Z_STREAM_ERROR;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500700
Glenn Randers-Pehrson228bd392000-04-23 23:14:02 -0500701 return (inflateReset(&png_ptr->zstream));
702}
Glenn Randers-Pehrson2b8bef12010-04-29 11:50:24 -0500703#endif /* PNG_READ_SUPPORTED */
Glenn Randers-Pehrson1ef65b62000-05-12 06:19:53 -0500704
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -0600705/* This function was added to libpng-1.0.7 */
Glenn Randers-Pehrson1ef65b62000-05-12 06:19:53 -0500706png_uint_32 PNGAPI
707png_access_version_number(void)
708{
709 /* Version of *.c files used when building libpng */
Glenn Randers-Pehrsond2332872010-10-12 19:19:28 -0500710 return((png_uint_32)PNG_LIBPNG_VER);
Glenn Randers-Pehrson1ef65b62000-05-12 06:19:53 -0500711}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -0600712
Glenn Randers-Pehrson1fd5fb32001-05-06 05:34:26 -0500713
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500714
715#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600716# ifdef PNG_SIZE_T
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500717/* Added at libpng version 1.2.6 */
718 PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size));
719png_size_t PNGAPI
720png_convert_size(size_t size)
Glenn Randers-Pehrson1fd5fb32001-05-06 05:34:26 -0500721{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500722 if (size > (png_size_t)-1)
723 PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500724
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500725 return ((png_size_t)size);
Glenn Randers-Pehrson1fd5fb32001-05-06 05:34:26 -0500726}
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600727# endif /* PNG_SIZE_T */
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600728
Glenn Randers-Pehrson02a5e332008-11-24 22:10:23 -0600729/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500730# ifdef PNG_CHECK_cHRM_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500731
Glenn Randers-Pehrson3f705ba2009-07-23 12:53:06 -0500732int /* PRIVATE */
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600733png_check_cHRM_fixed(png_structp png_ptr,
734 png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x,
735 png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y,
736 png_fixed_point blue_x, png_fixed_point blue_y)
737{
738 int ret = 1;
Glenn Randers-Pehrsond0c40592008-11-22 07:09:51 -0600739 unsigned long xy_hi,xy_lo,yx_hi,yx_lo;
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600740
741 png_debug(1, "in function png_check_cHRM_fixed");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500742
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600743 if (png_ptr == NULL)
744 return 0;
745
Glenn Randers-Pehrson02a5e332008-11-24 22:10:23 -0600746 if (white_x < 0 || white_y <= 0 ||
747 red_x < 0 || red_y < 0 ||
748 green_x < 0 || green_y < 0 ||
749 blue_x < 0 || blue_y < 0)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600750 {
751 png_warning(png_ptr,
752 "Ignoring attempt to set negative chromaticity value");
753 ret = 0;
754 }
Glenn Randers-Pehrsond2332872010-10-12 19:19:28 -0500755 if (white_x > (png_fixed_point)PNG_UINT_31_MAX ||
756 white_y > (png_fixed_point)PNG_UINT_31_MAX ||
757 red_x > (png_fixed_point)PNG_UINT_31_MAX ||
758 red_y > (png_fixed_point)PNG_UINT_31_MAX ||
759 green_x > (png_fixed_point)PNG_UINT_31_MAX ||
760 green_y > (png_fixed_point)PNG_UINT_31_MAX ||
761 blue_x > (png_fixed_point)PNG_UINT_31_MAX ||
762 blue_y > (png_fixed_point)PNG_UINT_31_MAX )
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600763 {
764 png_warning(png_ptr,
765 "Ignoring attempt to set chromaticity value exceeding 21474.83");
766 ret = 0;
767 }
Glenn Randers-Pehrson71a3c1f2008-11-26 12:00:38 -0600768 if (white_x > 100000L - white_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600769 {
770 png_warning(png_ptr, "Invalid cHRM white point");
771 ret = 0;
772 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500773
Glenn Randers-Pehrson71a3c1f2008-11-26 12:00:38 -0600774 if (red_x > 100000L - red_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600775 {
776 png_warning(png_ptr, "Invalid cHRM red point");
777 ret = 0;
778 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500779
Glenn Randers-Pehrson71a3c1f2008-11-26 12:00:38 -0600780 if (green_x > 100000L - green_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600781 {
782 png_warning(png_ptr, "Invalid cHRM green point");
783 ret = 0;
784 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500785
Glenn Randers-Pehrson71a3c1f2008-11-26 12:00:38 -0600786 if (blue_x > 100000L - blue_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600787 {
788 png_warning(png_ptr, "Invalid cHRM blue point");
789 ret = 0;
790 }
Glenn Randers-Pehrsond0c40592008-11-22 07:09:51 -0600791
792 png_64bit_product(green_x - red_x, blue_y - red_y, &xy_hi, &xy_lo);
793 png_64bit_product(green_y - red_y, blue_x - red_x, &yx_hi, &yx_lo);
794
795 if (xy_hi == yx_hi && xy_lo == yx_lo)
796 {
797 png_warning(png_ptr,
798 "Ignoring attempt to set cHRM RGB triangle with zero area");
799 ret = 0;
800 }
801
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600802 return ret;
803}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500804# endif /* PNG_CHECK_cHRM_SUPPORTED */
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500805
806void /* PRIVATE */
807png_check_IHDR(png_structp png_ptr,
808 png_uint_32 width, png_uint_32 height, int bit_depth,
809 int color_type, int interlace_type, int compression_type,
810 int filter_type)
811{
812 int error = 0;
813
814 /* Check for width and height valid values */
815 if (width == 0)
816 {
817 png_warning(png_ptr, "Image width is zero in IHDR");
818 error = 1;
819 }
820
821 if (height == 0)
822 {
823 png_warning(png_ptr, "Image height is zero in IHDR");
824 error = 1;
825 }
826
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600827# ifdef PNG_SET_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500828 if (width > png_ptr->user_width_max || width > PNG_USER_WIDTH_MAX)
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500829
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600830# else
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500831 if (width > PNG_USER_WIDTH_MAX)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600832# endif
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500833 {
834 png_warning(png_ptr, "Image width exceeds user limit in IHDR");
835 error = 1;
836 }
837
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600838# ifdef PNG_SET_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500839 if (height > png_ptr->user_height_max || height > PNG_USER_HEIGHT_MAX)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600840# else
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500841 if (height > PNG_USER_HEIGHT_MAX)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600842# endif
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500843 {
844 png_warning(png_ptr, "Image height exceeds user limit in IHDR");
845 error = 1;
846 }
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500847
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500848 if (width > PNG_UINT_31_MAX)
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500849 {
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500850 png_warning(png_ptr, "Invalid image width in IHDR");
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500851 error = 1;
852 }
853
Glenn Randers-Pehrsonbc363ec2010-10-12 21:17:00 -0500854 if (height > PNG_UINT_31_MAX)
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500855 {
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500856 png_warning(png_ptr, "Invalid image height in IHDR");
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500857 error = 1;
858 }
859
Glenn Randers-Pehrsonbc363ec2010-10-12 21:17:00 -0500860 if (width > (PNG_UINT_32_MAX
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500861 >> 3) /* 8-byte RGBA pixels */
Glenn Randers-Pehrsonc5080812010-10-23 08:26:26 -0500862 - 48 /* bigrowbuf hack */
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500863 - 1 /* filter byte */
864 - 7*8 /* rounding of width to multiple of 8 pixels */
865 - 8) /* extra max_pixel_depth pad */
866 png_warning(png_ptr, "Width is too large for libpng to process pixels");
867
868 /* Check other values */
869 if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
870 bit_depth != 8 && bit_depth != 16)
871 {
872 png_warning(png_ptr, "Invalid bit depth in IHDR");
873 error = 1;
874 }
875
876 if (color_type < 0 || color_type == 1 ||
877 color_type == 5 || color_type > 6)
878 {
879 png_warning(png_ptr, "Invalid color type in IHDR");
880 error = 1;
881 }
882
883 if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) ||
884 ((color_type == PNG_COLOR_TYPE_RGB ||
885 color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
886 color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
887 {
888 png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR");
889 error = 1;
890 }
891
892 if (interlace_type >= PNG_INTERLACE_LAST)
893 {
894 png_warning(png_ptr, "Unknown interlace method in IHDR");
895 error = 1;
896 }
897
898 if (compression_type != PNG_COMPRESSION_TYPE_BASE)
899 {
900 png_warning(png_ptr, "Unknown compression method in IHDR");
901 error = 1;
902 }
903
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600904# ifdef PNG_MNG_FEATURES_SUPPORTED
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500905 /* Accept filter_method 64 (intrapixel differencing) only if
906 * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
907 * 2. Libpng did not read a PNG signature (this filter_method is only
908 * used in PNG datastreams that are embedded in MNG datastreams) and
909 * 3. The application called png_permit_mng_features with a mask that
910 * included PNG_FLAG_MNG_FILTER_64 and
911 * 4. The filter_method is 64 and
912 * 5. The color_type is RGB or RGBA
913 */
914 if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) &&
915 png_ptr->mng_features_permitted)
916 png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");
917
918 if (filter_type != PNG_FILTER_TYPE_BASE)
919 {
Glenn Randers-Pehrson7ec330d2009-09-25 11:45:42 -0500920 if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500921 (filter_type == PNG_INTRAPIXEL_DIFFERENCING) &&
922 ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
923 (color_type == PNG_COLOR_TYPE_RGB ||
924 color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
Glenn Randers-Pehrson7ec330d2009-09-25 11:45:42 -0500925 {
926 png_warning(png_ptr, "Unknown filter method in IHDR");
927 error = 1;
928 }
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500929
Glenn Randers-Pehrson7ec330d2009-09-25 11:45:42 -0500930 if (png_ptr->mode & PNG_HAVE_PNG_SIGNATURE)
931 {
932 png_warning(png_ptr, "Invalid filter method in IHDR");
933 error = 1;
934 }
935 }
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500936
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600937# else
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500938 if (filter_type != PNG_FILTER_TYPE_BASE)
939 {
940 png_warning(png_ptr, "Unknown filter method in IHDR");
941 error = 1;
942 }
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600943# endif
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500944
945 if (error == 1)
946 png_error(png_ptr, "Invalid IHDR data");
947}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500948
949#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED)
950/* ASCII to fp functions */
951/* Check an ASCII formated floating point value, see the more detailed
952 * comments in pngpriv.h
953 */
954/* The following is used internally to preserve the 'valid' flag */
955#define png_fp_add(state, flags) ((state) |= (flags))
956#define png_fp_set(state, value)\
957 ((state) = (value) | ((state) & PNG_FP_WAS_VALID))
958
959/* Internal type codes: bits above the base state! */
960#define PNG_FP_SIGN 0 /* [+-] */
961#define PNG_FP_DOT 4 /* . */
962#define PNG_FP_DIGIT 8 /* [0123456789] */
963#define PNG_FP_E 12 /* [Ee] */
964
965int /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500966png_check_fp_number(png_const_charp string, png_size_t size, int *statep,
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500967 png_size_tp whereami)
968{
969 int state = *statep;
970 png_size_t i = *whereami;
971
972 while (i < size)
973 {
974 int type;
975 /* First find the type of the next character */
976 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500977 char ch = string[i];
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500978
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500979 if (ch >= 48 && ch <= 57)
980 type = PNG_FP_DIGIT;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500981
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500982 else switch (ch)
983 {
984 case 43: case 45: type = PNG_FP_SIGN; break;
985 case 46: type = PNG_FP_DOT; break;
986 case 69: case 101: type = PNG_FP_E; break;
987 default: goto PNG_FP_End;
988 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500989 }
990
991 /* Now deal with this type according to the current
992 * state, the type is arranged to not overlap the
993 * bits of the PNG_FP_STATE.
994 */
995 switch ((state & PNG_FP_STATE) + type)
996 {
997 case PNG_FP_INTEGER + PNG_FP_SIGN:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500998 if (state & PNG_FP_SAW_ANY)
999 goto PNG_FP_End; /* not a part of the number */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001000
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001001 png_fp_add(state, PNG_FP_SAW_SIGN);
1002 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001003
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001004 case PNG_FP_INTEGER + PNG_FP_DOT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001005 /* Ok as trailer, ok as lead of fraction. */
1006 if (state & PNG_FP_SAW_DOT) /* two dots */
1007 goto PNG_FP_End;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001008
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001009 else if (state & PNG_FP_SAW_DIGIT) /* trailing dot? */
1010 png_fp_add(state, PNG_FP_SAW_DOT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001011
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001012 else
1013 png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001014
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001015 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001016
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001017 case PNG_FP_INTEGER + PNG_FP_DIGIT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001018 if (state & PNG_FP_SAW_DOT) /* delayed fraction */
1019 png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001020
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001021 png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001022
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001023 break;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001024 case PNG_FP_INTEGER + PNG_FP_E:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001025 if ((state & PNG_FP_SAW_DIGIT) == 0)
1026 goto PNG_FP_End;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001027
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001028 png_fp_set(state, PNG_FP_EXPONENT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001029
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001030 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001031
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001032 /* case PNG_FP_FRACTION + PNG_FP_SIGN:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001033 goto PNG_FP_End; ** no sign in exponent */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001034
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001035 /* case PNG_FP_FRACTION + PNG_FP_DOT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001036 goto PNG_FP_End; ** Because SAW_DOT is always set */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001037
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001038 case PNG_FP_FRACTION + PNG_FP_DIGIT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001039 png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
1040 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001041
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001042 case PNG_FP_FRACTION + PNG_FP_E:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001043 /* This is correct because the trailing '.' on an
1044 * integer is handled above - so we can only get here
1045 * with the sequence ".E" (with no preceding digits).
1046 */
1047 if ((state & PNG_FP_SAW_DIGIT) == 0)
1048 goto PNG_FP_End;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001049
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001050 png_fp_set(state, PNG_FP_EXPONENT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001051
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001052 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001053
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001054 case PNG_FP_EXPONENT + PNG_FP_SIGN:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001055 if (state & PNG_FP_SAW_ANY)
1056 goto PNG_FP_End; /* not a part of the number */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001057
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001058 png_fp_add(state, PNG_FP_SAW_SIGN);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001059
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001060 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001061
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001062 /* case PNG_FP_EXPONENT + PNG_FP_DOT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001063 goto PNG_FP_End; */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001064
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001065 case PNG_FP_EXPONENT + PNG_FP_DIGIT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001066 png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001067
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001068 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001069
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001070 /* case PNG_FP_EXPONEXT + PNG_FP_E:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001071 goto PNG_FP_End; */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001072
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001073 default: goto PNG_FP_End; /* I.e. break 2 */
1074 }
1075
1076 /* The character seems ok, continue. */
1077 ++i;
1078 }
1079
1080PNG_FP_End:
1081 /* Here at the end, update the state and return the correct
1082 * return code.
1083 */
1084 *statep = state;
1085 *whereami = i;
1086
1087 return (state & PNG_FP_SAW_DIGIT) != 0;
1088}
1089
1090
1091/* The same but for a complete string. */
1092int
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001093png_check_fp_string(png_const_charp string, png_size_t size)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001094{
1095 int state=0;
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001096 png_size_t char_index=0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001097
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001098 return png_check_fp_number(string, size, &state, &char_index) &&
1099 (char_index == size || string[char_index] == 0);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001100}
1101#endif /* pCAL or sCAL */
1102
1103#ifdef PNG_READ_sCAL_SUPPORTED
1104# ifdef PNG_FLOATING_POINT_SUPPORTED
1105/* Utility used below - a simple accurate power of ten from an integral
1106 * exponent.
1107 */
1108static double
1109png_pow10(int power)
1110{
1111 int recip = 0;
1112 double d = 1;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001113
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001114 /* Handle negative exponent with a reciprocal at the end because
1115 * 10 is exact whereas .1 is inexact in base 2
1116 */
1117 if (power < 0)
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001118 {
1119 if (power < DBL_MIN_10_EXP) return 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001120 recip = 1, power = -power;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001121 }
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001122
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001123 if (power > 0)
1124 {
1125 /* Decompose power bitwise. */
1126 double mult = 10;
1127 do
1128 {
1129 if (power & 1) d *= mult;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001130 mult *= mult;
1131 power >>= 1;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001132 }
1133 while (power > 0);
1134
1135 if (recip) d = 1/d;
1136 }
1137 /* else power is 0 and d is 1 */
1138
1139 return d;
1140}
1141
1142/* Function to format a floating point value in ASCII with a given
1143 * precision.
1144 */
1145void /* PRIVATE */
1146png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001147 double fp, unsigned int precision)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001148{
1149 /* We use standard functions from math.h, but not printf because
1150 * that would require stdio. The caller must supply a buffer of
1151 * sufficient size or we will png_error. The tests on size and
1152 * the space in ascii[] consumed are indicated below.
1153 */
1154 if (precision < 1)
1155 precision = DBL_DIG;
1156
1157 /* Enforce the limit of the implementation precision too. */
1158 if (precision > DBL_DIG+1)
1159 precision = DBL_DIG+1;
1160
1161 /* Basic sanity checks */
1162 if (size >= precision+5) /* See the requirements below. */
1163 {
1164 if (fp < 0)
1165 {
1166 fp = -fp;
Glenn Randers-Pehrsonb75b2412011-04-16 19:35:05 -05001167 *ascii++ = 45; /* '-' PLUS 1 TOTAL 1 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001168 --size;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001169 }
1170
1171 if (fp >= DBL_MIN && fp <= DBL_MAX)
1172 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001173 int exp_b10; /* A base 10 exponent */
1174 double base; /* 10^exp_b10 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001175
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001176 /* First extract a base 10 exponent of the number,
1177 * the calculation below rounds down when converting
1178 * from base 2 to base 10 (multiply by log10(2) -
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001179 * 0.3010, but 77/256 is 0.3008, so exp_b10 needs to
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001180 * be increased. Note that the arithmetic shift
1181 * performs a floor() unlike C arithmetic - using a
1182 * C multiply would break the following for negative
1183 * exponents.
1184 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001185 (void)frexp(fp, &exp_b10); /* exponent to base 2 */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001186
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001187 exp_b10 = (exp_b10 * 77) >> 8; /* <= exponent to base 10 */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001188
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001189 /* Avoid underflow here. */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001190 base = png_pow10(exp_b10); /* May underflow */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001191
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001192 while (base < DBL_MIN || base < fp)
1193 {
1194 /* And this may overflow. */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001195 double test = png_pow10(exp_b10+1);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001196
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001197 if (test <= DBL_MAX)
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001198 ++exp_b10, base = test;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001199
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001200 else
1201 break;
1202 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001203
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001204 /* Normalize fp and correct exp_b10, after this fp is in the
1205 * range [.1,1) and exp_b10 is both the exponent and the digit
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001206 * *before* which the decimal point should be inserted
1207 * (starting with 0 for the first digit). Note that this
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001208 * works even if 10^exp_b10 is out of range because of the
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001209 * test on DBL_MAX above.
1210 */
1211 fp /= base;
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001212 while (fp >= 1) fp /= 10, ++exp_b10;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001213
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001214 /* Because of the code above fp may, at this point, be
1215 * less than .1, this is ok because the code below can
1216 * handle the leading zeros this generates, so no attempt
1217 * is made to correct that here.
1218 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001219
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001220 {
1221 int czero, clead, cdigits;
1222 char exponent[10];
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001223
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001224 /* Allow up to two leading zeros - this will not lengthen
1225 * the number compared to using E-n.
1226 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001227 if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001228 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001229 czero = -exp_b10; /* PLUS 2 digits: TOTAL 3 */
1230 exp_b10 = 0; /* Dot added below before first output. */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001231 }
1232 else
1233 czero = 0; /* No zeros to add */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001234
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001235 /* Generate the digit list, stripping trailing zeros and
1236 * inserting a '.' before a digit if the exponent is 0.
1237 */
1238 clead = czero; /* Count of leading zeros */
1239 cdigits = 0; /* Count of digits in list. */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001240
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001241 do
1242 {
1243 double d;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001244
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001245 fp *= 10;
1246 /* Use modf here, not floor and subtract, so that
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001247 * the separation is done in one step. At the end
1248 * of the loop don't break the number into parts so
1249 * that the final digit is rounded.
1250 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001251 if (cdigits+czero-clead+1 < (int)precision)
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001252 fp = modf(fp, &d);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001253
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001254 else
1255 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001256 d = floor(fp + .5);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001257
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001258 if (d > 9)
1259 {
1260 /* Rounding up to 10, handle that here. */
1261 if (czero > 0)
1262 {
1263 --czero, d = 1;
1264 if (cdigits == 0) --clead;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001265 }
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001266 else
1267 {
1268 while (cdigits > 0 && d > 9)
1269 {
1270 int ch = *--ascii;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001271
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001272 if (exp_b10 != (-1))
1273 ++exp_b10;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001274
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001275 else if (ch == 46)
1276 {
1277 ch = *--ascii, ++size;
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001278 /* Advance exp_b10 to '1', so that the
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001279 * decimal point happens after the
1280 * previous digit.
1281 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001282 exp_b10 = 1;
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001283 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001284
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001285 --cdigits;
1286 d = ch - 47; /* I.e. 1+(ch-48) */
1287 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001288
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001289 /* Did we reach the beginning? If so adjust the
1290 * exponent but take into account the leading
1291 * decimal point.
1292 */
1293 if (d > 9) /* cdigits == 0 */
1294 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001295 if (exp_b10 == (-1))
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001296 {
1297 /* Leading decimal point (plus zeros?), if
1298 * we lose the decimal point here it must
1299 * be reentered below.
1300 */
1301 int ch = *--ascii;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001302
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001303 if (ch == 46)
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001304 ++size, exp_b10 = 1;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001305
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001306 /* Else lost a leading zero, so 'exp_b10' is
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001307 * still ok at (-1)
1308 */
1309 }
1310 else
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001311 ++exp_b10;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001312
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001313 /* In all cases we output a '1' */
1314 d = 1;
1315 }
1316 }
1317 }
1318 fp = 0; /* Guarantees termination below. */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001319 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001320
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001321 if (d == 0)
1322 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001323 ++czero;
1324 if (cdigits == 0) ++clead;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001325 }
1326 else
1327 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001328 /* Included embedded zeros in the digit count. */
1329 cdigits += czero - clead;
1330 clead = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001331
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001332 while (czero > 0)
1333 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001334 /* exp_b10 == (-1) means we just output the decimal
1335 * place - after the DP don't adjust 'exp_b10' any
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001336 * more!
1337 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001338 if (exp_b10 != (-1))
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001339 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001340 if (exp_b10 == 0) *ascii++ = 46, --size;
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001341 /* PLUS 1: TOTAL 4 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001342 --exp_b10;
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001343 }
1344 *ascii++ = 48, --czero;
1345 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001346
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001347 if (exp_b10 != (-1))
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001348 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001349 if (exp_b10 == 0) *ascii++ = 46, --size; /* counted
1350 above */
1351 --exp_b10;
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001352 }
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001353 *ascii++ = (char)(48 + (int)d), ++cdigits;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001354 }
1355 }
1356 while (cdigits+czero-clead < (int)precision && fp > DBL_MIN);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001357
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001358 /* The total output count (max) is now 4+precision */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001359
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001360 /* Check for an exponent, if we don't need one we are
1361 * done and just need to terminate the string. At
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001362 * this point exp_b10==(-1) is effectively if flag - it got
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001363 * to '-1' because of the decrement after outputing
1364 * the decimal point above (the exponent required is
1365 * *not* -1!)
1366 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001367 if (exp_b10 >= (-1) && exp_b10 <= 2)
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001368 {
1369 /* The following only happens if we didn't output the
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001370 * leading zeros above for negative exponent, so this
1371 * doest add to the digit requirement. Note that the
1372 * two zeros here can only be output if the two leading
1373 * zeros were *not* output, so this doesn't increase
1374 * the output count.
1375 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001376 while (--exp_b10 >= 0) *ascii++ = 48;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001377
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001378 *ascii = 0;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001379
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001380 /* Total buffer requirement (including the '\0') is
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001381 * 5+precision - see check at the start.
1382 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001383 return;
1384 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001385
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001386 /* Here if an exponent is required, adjust size for
1387 * the digits we output but did not count. The total
1388 * digit output here so far is at most 1+precision - no
1389 * decimal point and no leading or trailing zeros have
1390 * been output.
1391 */
1392 size -= cdigits;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001393
Glenn Randers-Pehrsonb75b2412011-04-16 19:35:05 -05001394 *ascii++ = 69, --size; /* 'E': PLUS 1 TOTAL 2+precision */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001395 if (exp_b10 < 0)
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001396 {
1397 *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001398 exp_b10 = -exp_b10;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001399 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001400
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001401 cdigits = 0;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001402
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001403 while (exp_b10 > 0)
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001404 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001405 exponent[cdigits++] = (char)(48 + exp_b10 % 10);
1406 exp_b10 /= 10;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001407 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001408
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001409 /* Need another size check here for the exponent digits, so
1410 * this need not be considered above.
1411 */
1412 if ((int)size > cdigits)
1413 {
1414 while (cdigits > 0) *ascii++ = exponent[--cdigits];
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001415
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001416 *ascii = 0;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001417
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001418 return;
1419 }
1420 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001421 }
1422 else if (!(fp >= DBL_MIN))
1423 {
1424 *ascii++ = 48; /* '0' */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001425 *ascii = 0;
1426 return;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001427 }
1428 else
1429 {
1430 *ascii++ = 105; /* 'i' */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001431 *ascii++ = 110; /* 'n' */
1432 *ascii++ = 102; /* 'f' */
1433 *ascii = 0;
1434 return;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001435 }
1436 }
1437
1438 /* Here on buffer too small. */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001439 png_error(png_ptr, "ASCII conversion buffer too small");
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001440}
1441
1442# endif /* FLOATING_POINT */
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001443
1444# ifdef PNG_FIXED_POINT_SUPPORTED
1445/* Function to format a fixed point value in ASCII.
1446 */
1447void /* PRIVATE */
1448png_ascii_from_fixed(png_structp png_ptr, png_charp ascii, png_size_t size,
1449 png_fixed_point fp)
1450{
1451 /* Require space for 10 decimal digits, a decimal point, a minus sign and a
1452 * trailing \0, 13 characters:
1453 */
1454 if (size > 12)
1455 {
1456 png_uint_32 num;
1457
1458 /* Avoid overflow here on the minimum integer. */
1459 if (fp < 0)
1460 *ascii++ = 45, --size, num = -fp;
1461 else
1462 num = fp;
1463
1464 if (num <= 0x80000000U) /* else overflowed */
1465 {
Glenn Randers-Pehrsonb75b2412011-04-16 19:35:05 -05001466 unsigned int ndigits = 0, first = 16 /* flag value */;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001467 char digits[10];
1468
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001469 while (num)
1470 {
1471 /* Split the low digit off num: */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001472 unsigned int tmp = num/10;
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001473 num -= tmp*10;
1474 digits[ndigits++] = (char)(48 + num);
1475 /* Record the first non-zero digit, note that this is a number
1476 * starting at 1, it's not actually the array index.
1477 */
1478 if (first == 16 && num > 0)
1479 first = ndigits;
1480 num = tmp;
1481 }
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001482
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001483 if (ndigits > 0)
1484 {
1485 while (ndigits > 5) *ascii++ = digits[--ndigits];
1486 /* The remaining digits are fractional digits, ndigits is '5' or
1487 * smaller at this point. It is certainly not zero. Check for a
1488 * non-zero fractional digit:
1489 */
1490 if (first <= 5)
1491 {
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001492 unsigned int i;
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001493 *ascii++ = 46; /* decimal point */
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -05001494 /* ndigits may be <5 for small numbers, output leading zeros
1495 * then ndigits digits to first:
1496 */
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001497 i = 5;
1498 while (ndigits < i) *ascii++ = 48, --i;
1499 while (ndigits >= first) *ascii++ = digits[--ndigits];
1500 /* Don't output the trailing zeros! */
1501 }
1502 }
1503 else
1504 *ascii++ = 48;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001505
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001506 /* And null terminate the string: */
1507 *ascii = 0;
1508 return;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001509 }
1510 }
1511
1512 /* Here on buffer too small. */
1513 png_error(png_ptr, "ASCII conversion buffer too small");
1514}
1515# endif /* FIXED_POINT */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001516#endif /* READ_SCAL */
1517
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -05001518#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001519 !defined(PNG_FIXED_POINT_MACRO_SUPPORTED)
1520png_fixed_point
1521png_fixed(png_structp png_ptr, double fp, png_const_charp text)
1522{
1523 double r = floor(100000 * fp + .5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001524
Glenn Randers-Pehrson77c3bf12011-01-20 15:56:31 -06001525 if (r > 2147483647. || r < -2147483648.)
1526 png_fixed_error(png_ptr, text);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001527
Glenn Randers-Pehrson77c3bf12011-01-20 15:56:31 -06001528 return (png_fixed_point)r;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001529}
1530#endif
1531
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -05001532#if defined(PNG_READ_GAMMA_SUPPORTED) || \
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001533 defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG__READ_pHYs_SUPPORTED)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001534/* muldiv functions */
1535/* This API takes signed arguments and rounds the result to the nearest
1536 * integer (or, for a fixed point number - the standard argument - to
1537 * the nearest .00001). Overflow and divide by zero are signalled in
1538 * the result, a boolean - true on success, false on overflow.
1539 */
1540int
1541png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001542 png_int_32 divisor)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001543{
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001544 /* Return a * times / divisor, rounded. */
1545 if (divisor != 0)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001546 {
1547 if (a == 0 || times == 0)
1548 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001549 *res = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001550 return 1;
1551 }
1552 else
1553 {
1554#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001555 double r = a;
1556 r *= times;
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001557 r /= divisor;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001558 r = floor(r+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001559
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001560 /* A png_fixed_point is a 32-bit integer. */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001561 if (r <= 2147483647. && r >= -2147483648.)
1562 {
1563 *res = (png_fixed_point)r;
1564 return 1;
1565 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001566#else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001567 int negative = 0;
1568 png_uint_32 A, T, D;
Glenn Randers-Pehrson3b5d6952010-08-19 08:06:12 -05001569 png_uint_32 s16, s32, s00;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001570
1571 if (a < 0)
1572 negative = 1, A = -a;
1573 else
1574 A = a;
1575
1576 if (times < 0)
1577 negative = !negative, T = -times;
1578 else
1579 T = times;
1580
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001581 if (divisor < 0)
1582 negative = !negative, D = -divisor;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001583 else
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001584 D = divisor;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001585
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001586 /* Following can't overflow because the arguments only
1587 * have 31 bits each, however the result may be 32 bits.
1588 */
Glenn Randers-Pehrson3b5d6952010-08-19 08:06:12 -05001589 s16 = (A >> 16) * (T & 0xffff) +
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001590 (A & 0xffff) * (T >> 16);
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001591 /* Can't overflow because the a*times bit is only 30
1592 * bits at most.
1593 */
Glenn Randers-Pehrson3b5d6952010-08-19 08:06:12 -05001594 s32 = (A >> 16) * (T >> 16) + (s16 >> 16);
1595 s00 = (A & 0xffff) * (T & 0xffff);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001596
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001597 s16 = (s16 & 0xffff) << 16;
1598 s00 += s16;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001599
1600 if (s00 < s16)
1601 ++s32; /* carry */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001602
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001603 if (s32 < D) /* else overflow */
1604 {
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001605 /* s32.s00 is now the 64-bit product, do a standard
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001606 * division, we know that s32 < D, so the maximum
1607 * required shift is 31.
1608 */
1609 int bitshift = 32;
1610 png_fixed_point result = 0; /* NOTE: signed */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001611
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001612 while (--bitshift >= 0)
1613 {
1614 png_uint_32 d32, d00;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001615
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001616 if (bitshift > 0)
1617 d32 = D >> (32-bitshift), d00 = D << bitshift;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001618
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001619 else
1620 d32 = 0, d00 = D;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001621
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001622 if (s32 > d32)
1623 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001624 if (s00 < d00) --s32; /* carry */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001625 s32 -= d32, s00 -= d00, result += 1<<bitshift;
1626 }
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001627
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001628 else
1629 if (s32 == d32 && s00 >= d00)
1630 s32 = 0, s00 -= d00, result += 1<<bitshift;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001631 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001632
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001633 /* Handle the rounding. */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001634 if (s00 >= (D >> 1))
1635 ++result;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001636
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001637 if (negative)
1638 result = -result;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001639
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001640 /* Check for overflow. */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001641 if ((negative && result <= 0) || (!negative && result >= 0))
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001642 {
1643 *res = result;
1644 return 1;
1645 }
1646 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001647#endif
1648 }
1649 }
1650
1651 return 0;
1652}
1653#endif /* READ_GAMMA || INCH_CONVERSIONS */
1654
1655#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)
1656/* The following is for when the caller doesn't much care about the
1657 * result.
1658 */
1659png_fixed_point
1660png_muldiv_warn(png_structp png_ptr, png_fixed_point a, png_int_32 times,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001661 png_int_32 divisor)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001662{
1663 png_fixed_point result;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001664
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001665 if (png_muldiv(&result, a, times, divisor))
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001666 return result;
1667
1668 png_warning(png_ptr, "fixed point overflow ignored");
1669 return 0;
1670}
1671#endif
1672
1673#ifdef PNG_READ_GAMMA_SUPPORTED /* more fixed point functions for gammma */
1674/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */
1675png_fixed_point
1676png_reciprocal(png_fixed_point a)
1677{
1678#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
1679 double r = floor(1E10/a+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001680
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001681 if (r <= 2147483647. && r >= -2147483648.)
1682 return (png_fixed_point)r;
1683#else
1684 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001685
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001686 if (png_muldiv(&res, 100000, 100000, a))
1687 return res;
1688#endif
1689
1690 return 0; /* error/overflow */
1691}
1692
1693/* A local convenience routine. */
1694static png_fixed_point
1695png_product2(png_fixed_point a, png_fixed_point b)
1696{
Glenn Randers-Pehrson9c690912010-08-27 11:39:38 -05001697 /* The required result is 1/a * 1/b; the following preserves accuracy. */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001698#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
1699 double r = a * 1E-5;
1700 r *= b;
1701 r = floor(r+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001702
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001703 if (r <= 2147483647. && r >= -2147483648.)
1704 return (png_fixed_point)r;
1705#else
1706 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001707
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001708 if (png_muldiv(&res, a, b, 100000))
1709 return res;
1710#endif
1711
1712 return 0; /* overflow */
1713}
1714
1715/* The inverse of the above. */
1716png_fixed_point
1717png_reciprocal2(png_fixed_point a, png_fixed_point b)
1718{
Glenn Randers-Pehrson9c690912010-08-27 11:39:38 -05001719 /* The required result is 1/a * 1/b; the following preserves accuracy. */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001720#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
1721 double r = 1E15/a;
1722 r /= b;
1723 r = floor(r+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001724
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001725 if (r <= 2147483647. && r >= -2147483648.)
1726 return (png_fixed_point)r;
1727#else
1728 /* This may overflow because the range of png_fixed_point isn't symmetric,
1729 * but this API is only used for the product of file and screen gamma so it
1730 * doesn't matter that the smallest number it can produce is 1/21474, not
1731 * 1/100000
1732 */
1733 png_fixed_point res = png_product2(a, b);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001734
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001735 if (res != 0)
1736 return png_reciprocal(res);
1737#endif
1738
1739 return 0; /* overflow */
1740}
1741#endif /* READ_GAMMA */
1742
1743#ifdef PNG_CHECK_cHRM_SUPPORTED
1744/* Added at libpng version 1.2.34 (Dec 8, 2008) and 1.4.0 (Jan 2,
1745 * 2010: moved from pngset.c) */
1746/*
1747 * Multiply two 32-bit numbers, V1 and V2, using 32-bit
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001748 * arithmetic, to produce a 64-bit result in the HI/LO words.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001749 *
1750 * A B
1751 * x C D
1752 * ------
1753 * AD || BD
1754 * AC || CB || 0
1755 *
1756 * where A and B are the high and low 16-bit words of V1,
1757 * C and D are the 16-bit words of V2, AD is the product of
1758 * A and D, and X || Y is (X << 16) + Y.
1759*/
1760
1761void /* PRIVATE */
1762png_64bit_product (long v1, long v2, unsigned long *hi_product,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001763 unsigned long *lo_product)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001764{
1765 int a, b, c, d;
1766 long lo, hi, x, y;
1767
1768 a = (v1 >> 16) & 0xffff;
1769 b = v1 & 0xffff;
1770 c = (v2 >> 16) & 0xffff;
1771 d = v2 & 0xffff;
1772
1773 lo = b * d; /* BD */
1774 x = a * d + c * b; /* AD + CB */
1775 y = ((lo >> 16) & 0xffff) + x;
1776
1777 lo = (lo & 0xffff) | ((y & 0xffff) << 16);
1778 hi = (y >> 16) & 0xffff;
1779
1780 hi += a * c; /* AC */
1781
1782 *hi_product = (unsigned long)hi;
1783 *lo_product = (unsigned long)lo;
1784}
1785#endif /* CHECK_cHRM */
1786
1787#ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */
1788#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED
1789/* Fixed point gamma.
1790 *
1791 * To calculate gamma this code implements fast log() and exp() calls using only
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001792 * fixed point arithmetic. This code has sufficient precision for either 8-bit
1793 * or 16-bit sample values.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001794 *
1795 * The tables used here were calculated using simple 'bc' programs, but C double
1796 * precision floating point arithmetic would work fine. The programs are given
1797 * at the head of each table.
1798 *
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001799 * 8-bit log table
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001800 * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001801 * 255, so it's the base 2 logarithm of a normalized 8-bit floating point
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001802 * mantissa. The numbers are 32-bit fractions.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001803 */
1804static png_uint_32
1805png_8bit_l2[128] =
1806{
1807# if PNG_DO_BC
1808 for (i=128;i<256;++i) { .5 - l(i/255)/l(2)*65536*65536; }
1809# endif
1810 4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U,
1811 3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U,
1812 3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U,
1813 3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U,
1814 3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U,
1815 2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U,
1816 2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U,
1817 2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U,
1818 2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U,
1819 2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U,
1820 1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U,
1821 1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U,
1822 1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U,
1823 1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U,
1824 1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U,
1825 971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U,
1826 803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U,
1827 639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U,
1828 479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U,
1829 324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U,
1830 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U,
1831 24347096U, 0U
1832#if 0
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001833 /* The following are the values for 16-bit tables - these work fine for the
1834 * 8-bit conversions but produce very slightly larger errors in the 16-bit
1835 * log (about 1.2 as opposed to 0.7 absolute error in the final value). To
1836 * use these all the shifts below must be adjusted appropriately.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001837 */
1838 65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054,
1839 57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803,
1840 50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068,
1841 43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782,
1842 37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887,
1843 31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339,
1844 25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098,
1845 20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132,
1846 15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415,
1847 10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523,
1848 6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495,
1849 1119, 744, 372
1850#endif
1851};
1852
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001853static png_int_32
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001854png_log8bit(unsigned int x)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001855{
John Bowler168a4332011-01-16 19:32:22 -06001856 unsigned int lg2 = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001857 /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log,
1858 * because the log is actually negate that means adding 1. The final
1859 * returned value thus has the range 0 (for 255 input) to 7.994 (for 1
1860 * input), return 7.99998 for the overflow (log 0) case - so the result is
1861 * always at most 19 bits.
1862 */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001863 if ((x &= 0xff) == 0)
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -06001864 return 0xffffffff;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001865
1866 if ((x & 0xf0) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001867 lg2 = 4, x <<= 4;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001868
1869 if ((x & 0xc0) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001870 lg2 += 2, x <<= 2;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001871
1872 if ((x & 0x80) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001873 lg2 += 1, x <<= 1;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001874
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001875 /* result is at most 19 bits, so this cast is safe: */
John Bowler168a4332011-01-16 19:32:22 -06001876 return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001877}
1878
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001879/* The above gives exact (to 16 binary places) log2 values for 8-bit images,
1880 * for 16-bit images we use the most significant 8 bits of the 16-bit value to
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001881 * get an approximation then multiply the approximation by a correction factor
1882 * determined by the remaining up to 8 bits. This requires an additional step
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001883 * in the 16-bit case.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001884 *
1885 * We want log2(value/65535), we have log2(v'/255), where:
1886 *
1887 * value = v' * 256 + v''
1888 * = v' * f
1889 *
1890 * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128
1891 * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001892 * than 258. The final factor also needs to correct for the fact that our 8-bit
1893 * value is scaled by 255, whereas the 16-bit values must be scaled by 65535.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001894 *
1895 * This gives a final formula using a calculated value 'x' which is value/v' and
1896 * scaling by 65536 to match the above table:
1897 *
1898 * log2(x/257) * 65536
1899 *
1900 * Since these numbers are so close to '1' we can use simple linear
1901 * interpolation between the two end values 256/257 (result -368.61) and 258/257
1902 * (result 367.179). The values used below are scaled by a further 64 to give
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001903 * 16-bit precision in the interpolation:
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001904 *
1905 * Start (256): -23591
1906 * Zero (257): 0
1907 * End (258): 23499
1908 */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001909static png_int_32
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001910png_log16bit(png_uint_32 x)
1911{
John Bowler168a4332011-01-16 19:32:22 -06001912 unsigned int lg2 = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001913
1914 /* As above, but now the input has 16 bits. */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001915 if ((x &= 0xffff) == 0)
1916 return 0xffffffff;
1917
1918 if ((x & 0xff00) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001919 lg2 = 8, x <<= 8;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001920
1921 if ((x & 0xf000) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001922 lg2 += 4, x <<= 4;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001923
1924 if ((x & 0xc000) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001925 lg2 += 2, x <<= 2;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001926
1927 if ((x & 0x8000) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001928 lg2 += 1, x <<= 1;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001929
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001930 /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001931 * value.
1932 */
John Bowler168a4332011-01-16 19:32:22 -06001933 lg2 <<= 28;
1934 lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001935
1936 /* Now we need to interpolate the factor, this requires a division by the top
1937 * 8 bits. Do this with maximum precision.
1938 */
1939 x = ((x << 16) + (x >> 9)) / (x >> 8);
1940
1941 /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24,
1942 * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly
1943 * 16 bits to interpolate to get the low bits of the result. Round the
1944 * answer. Note that the end point values are scaled by 64 to retain overall
John Bowler168a4332011-01-16 19:32:22 -06001945 * precision and that 'lg2' is current scaled by an extra 12 bits, so adjust
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001946 * the overall scaling by 6-12. Round at every step.
1947 */
1948 x -= 1U << 24;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001949
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001950 if (x <= 65536U) /* <= '257' */
John Bowler168a4332011-01-16 19:32:22 -06001951 lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001952
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001953 else
John Bowler168a4332011-01-16 19:32:22 -06001954 lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001955
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001956 /* Safe, because the result can't have more than 20 bits: */
John Bowler168a4332011-01-16 19:32:22 -06001957 return (png_int_32)((lg2 + 2048) >> 12);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001958}
1959
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001960/* The 'exp()' case must invert the above, taking a 20-bit fixed point
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001961 * logarithmic value and returning a 16 or 8-bit number as appropriate. In
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001962 * each case only the low 16 bits are relevant - the fraction - since the
1963 * integer bits (the top 4) simply determine a shift.
1964 *
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001965 * The worst case is the 16-bit distinction between 65535 and 65534, this
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001966 * requires perhaps spurious accuracty in the decoding of the logarithm to
1967 * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance
1968 * of getting this accuracy in practice.
1969 *
1970 * To deal with this the following exp() function works out the exponent of the
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001971 * frational part of the logarithm by using an accurate 32-bit value from the
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001972 * top four fractional bits then multiplying in the remaining bits.
1973 */
1974static png_uint_32
1975png_32bit_exp[16] =
1976{
1977# if PNG_DO_BC
1978 for (i=0;i<16;++i) { .5 + e(-i/16*l(2))*2^32; }
1979# endif
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001980 /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001981 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U,
1982 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U,
1983 2553802834U, 2445529972U, 2341847524U, 2242560872U
1984};
1985
1986/* Adjustment table; provided to explain the numbers in the code below. */
1987#if PNG_DO_BC
1988for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"}
1989 11 44937.64284865548751208448
1990 10 45180.98734845585101160448
1991 9 45303.31936980687359311872
1992 8 45364.65110595323018870784
1993 7 45395.35850361789624614912
1994 6 45410.72259715102037508096
1995 5 45418.40724413220722311168
1996 4 45422.25021786898173001728
1997 3 45424.17186732298419044352
1998 2 45425.13273269940811464704
1999 1 45425.61317555035558641664
2000 0 45425.85339951654943850496
2001#endif
2002
2003static png_uint_32
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002004png_exp(png_fixed_point x)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002005{
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002006 if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002007 {
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002008 /* Obtain a 4-bit approximation */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002009 png_uint_32 e = png_32bit_exp[(x >> 12) & 0xf];
2010
2011 /* Incorporate the low 12 bits - these decrease the returned value by
2012 * multiplying by a number less than 1 if the bit is set. The multiplier
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002013 * is determined by the above table and the shift. Notice that the values
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002014 * converge on 45426 and this is used to allow linear interpolation of the
2015 * low bits.
2016 */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05002017 if (x & 0x800)
2018 e -= (((e >> 16) * 44938U) + 16U) >> 5;
2019
2020 if (x & 0x400)
2021 e -= (((e >> 16) * 45181U) + 32U) >> 6;
2022
2023 if (x & 0x200)
2024 e -= (((e >> 16) * 45303U) + 64U) >> 7;
2025
2026 if (x & 0x100)
2027 e -= (((e >> 16) * 45365U) + 128U) >> 8;
2028
2029 if (x & 0x080)
2030 e -= (((e >> 16) * 45395U) + 256U) >> 9;
2031
2032 if (x & 0x040)
2033 e -= (((e >> 16) * 45410U) + 512U) >> 10;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002034
2035 /* And handle the low 6 bits in a single block. */
2036 e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9;
2037
2038 /* Handle the upper bits of x. */
2039 e >>= x >> 16;
2040 return e;
2041 }
2042
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002043 /* Check for overflow */
2044 if (x <= 0)
2045 return png_32bit_exp[0];
2046
2047 /* Else underflow */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002048 return 0;
2049}
2050
2051static png_byte
John Bowler168a4332011-01-16 19:32:22 -06002052png_exp8bit(png_fixed_point lg2)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002053{
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002054 /* Get a 32-bit value: */
John Bowler168a4332011-01-16 19:32:22 -06002055 png_uint_32 x = png_exp(lg2);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002056
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002057 /* Convert the 32-bit value to 0..255 by multiplying by 256-1, note that the
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002058 * second, rounding, step can't overflow because of the first, subtraction,
2059 * step.
2060 */
2061 x -= x >> 8;
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002062 return (png_byte)((x + 0x7fffffU) >> 24);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002063}
2064
2065static png_uint_16
John Bowler168a4332011-01-16 19:32:22 -06002066png_exp16bit(png_fixed_point lg2)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002067{
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002068 /* Get a 32-bit value: */
John Bowler168a4332011-01-16 19:32:22 -06002069 png_uint_32 x = png_exp(lg2);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002070
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002071 /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002072 x -= x >> 16;
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002073 return (png_uint_16)((x + 32767U) >> 16);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002074}
2075#endif /* FLOATING_ARITHMETIC */
2076
2077png_byte
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002078png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002079{
2080 if (value > 0 && value < 255)
2081 {
2082# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002083 double r = floor(255*pow(value/255.,gamma_val*.00001)+.5);
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002084 return (png_byte)r;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002085# else
John Bowler168a4332011-01-16 19:32:22 -06002086 png_int_32 lg2 = png_log8bit(value);
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002087 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002088
John Bowler168a4332011-01-16 19:32:22 -06002089 if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1))
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002090 return png_exp8bit(res);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002091
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05002092 /* Overflow. */
2093 value = 0;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002094# endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002095 }
2096
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002097 return (png_byte)value;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002098}
2099
2100png_uint_16
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002101png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002102{
2103 if (value > 0 && value < 65535)
2104 {
2105# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002106 double r = floor(65535*pow(value/65535.,gamma_val*.00001)+.5);
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002107 return (png_uint_16)r;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002108# else
John Bowler168a4332011-01-16 19:32:22 -06002109 png_int_32 lg2 = png_log16bit(value);
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002110 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002111
John Bowler168a4332011-01-16 19:32:22 -06002112 if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1))
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002113 return png_exp16bit(res);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002114
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05002115 /* Overflow. */
2116 value = 0;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002117# endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002118 }
2119
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002120 return (png_uint_16)value;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002121}
2122
2123/* This does the right thing based on the bit_depth field of the
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002124 * png_struct, interpreting values as 8-bit or 16-bit. While the result
2125 * is nominally a 16-bit value if bit depth is 8 then the result is
2126 * 8-bit (as are the arguments.)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002127 */
2128png_uint_16 /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002129png_gamma_correct(png_structp png_ptr, unsigned int value,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002130 png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002131{
2132 if (png_ptr->bit_depth == 8)
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002133 return png_gamma_8bit_correct(value, gamma_val);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002134
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002135 else
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002136 return png_gamma_16bit_correct(value, gamma_val);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002137}
2138
2139/* This is the shared test on whether a gamma value is 'significant' - whether
2140 * it is worth doing gamma correction.
2141 */
2142int /* PRIVATE */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002143png_gamma_significant(png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002144{
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002145 return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED ||
2146 gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002147}
2148
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002149/* Internal function to build a single 16-bit table - the table consists of
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002150 * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount
2151 * to shift the input values right (or 16-number_of_signifiant_bits).
2152 *
Glenn Randers-Pehrsona774c5d2010-08-26 19:37:55 -05002153 * The caller is responsible for ensuring that the table gets cleaned up on
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002154 * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument
2155 * should be somewhere that will be cleaned.
2156 */
2157static void
2158png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002159 PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002160{
2161 /* Various values derived from 'shift': */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002162 PNG_CONST unsigned int num = 1U << (8U - shift);
2163 PNG_CONST unsigned int max = (1U << (16U - shift))-1U;
2164 PNG_CONST unsigned int max_by_2 = 1U << (15U-shift);
2165 unsigned int i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002166
2167 png_uint_16pp table = *ptable =
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002168 (png_uint_16pp)png_calloc(png_ptr, num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002169
2170 for (i = 0; i < num; i++)
2171 {
2172 png_uint_16p sub_table = table[i] =
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002173 (png_uint_16p)png_malloc(png_ptr, 256 * png_sizeof(png_uint_16));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002174
2175 /* The 'threshold' test is repeated here because it can arise for one of
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002176 * the 16-bit tables even if the others don't hit it.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002177 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002178 if (png_gamma_significant(gamma_val))
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002179 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002180 /* The old code would overflow at the end and this would cause the
2181 * 'pow' function to return a result >1, resulting in an
2182 * arithmetic error. This code follows the spec exactly; ig is
2183 * the recovered input sample, it always has 8-16 bits.
2184 *
2185 * We want input * 65535/max, rounded, the arithmetic fits in 32
2186 * bits (unsigned) so long as max <= 32767.
2187 */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002188 unsigned int j;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002189 for (j = 0; j < 256; j++)
2190 {
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002191 png_uint_32 ig = (j << (8-shift)) + i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002192# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002193 /* Inline the 'max' scaling operation: */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002194 double d = floor(65535*pow(ig/(double)max, gamma_val*.00001)+.5);
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002195 sub_table[j] = (png_uint_16)d;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002196# else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002197 if (shift)
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05002198 ig = (ig * 65535U + max_by_2)/max;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002199
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002200 sub_table[j] = png_gamma_16bit_correct(ig, gamma_val);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002201# endif
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002202 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002203 }
2204 else
2205 {
2206 /* We must still build a table, but do it the fast way. */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002207 unsigned int j;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002208
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002209 for (j = 0; j < 256; j++)
2210 {
2211 png_uint_32 ig = (j << (8-shift)) + i;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002212
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002213 if (shift)
2214 ig = (ig * 65535U + max_by_2)/max;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002215
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002216 sub_table[j] = (png_uint_16)ig;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002217 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002218 }
2219 }
2220}
2221
2222/* NOTE: this function expects the *inverse* of the overall gamma transformation
2223 * required.
2224 */
2225static void
2226png_build_16to8_table(png_structp png_ptr, png_uint_16pp *ptable,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002227 PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002228{
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002229 PNG_CONST unsigned int num = 1U << (8U - shift);
2230 PNG_CONST unsigned int max = (1U << (16U - shift))-1U;
2231 unsigned int i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002232 png_uint_32 last;
2233
2234 png_uint_16pp table = *ptable =
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002235 (png_uint_16pp)png_calloc(png_ptr, num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002236
2237 /* 'num' is the number of tables and also the number of low bits of low
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002238 * bits of the input 16-bit value used to select a table. Each table is
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002239 * itself index by the high 8 bits of the value.
2240 */
2241 for (i = 0; i < num; i++)
2242 table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002243 256 * png_sizeof(png_uint_16));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002244
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002245 /* 'gamma_val' is set to the reciprocal of the value calculated above, so
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002246 * pow(out,g) is an *input* value. 'last' is the last input value set.
2247 *
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002248 * In the loop 'i' is used to find output values. Since the output is
2249 * 8-bit there are only 256 possible values. The tables are set up to
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002250 * select the closest possible output value for each input by finding
2251 * the input value at the boundary between each pair of output values
2252 * and filling the table up to that boundary with the lower output
2253 * value.
2254 *
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002255 * The boundary values are 0.5,1.5..253.5,254.5. Since these are 9-bit
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002256 * values the code below uses a 16-bit value in i; the values start at
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002257 * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last
2258 * entries are filled with 255). Start i at 128 and fill all 'last'
2259 * table entries <= 'max'
2260 */
2261 last = 0;
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002262 for (i = 0; i < 255; ++i) /* 8-bit output value */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002263 {
2264 /* Find the corresponding maximum input value */
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002265 png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002266
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002267 /* Find the boundary value in 16 bits: */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002268 png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002269
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002270 /* Adjust (round) to (16-shift) bits: */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002271 bound = (bound * max + 32768U)/65535U + 1U;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002272
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002273 while (last < bound)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002274 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002275 table[last & (0xffU >> shift)][last >> (8U - shift)] = out;
2276 last++;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002277 }
2278 }
2279
2280 /* And fill in the final entries. */
2281 while (last < (num << 8))
2282 {
2283 table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U;
2284 last++;
2285 }
2286}
2287
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002288/* Build a single 8-bit table: same as the 16-bit case but much simpler (and
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002289 * typically much faster). Note that libpng currently does no sBIT processing
2290 * (apparently contrary to the spec) so a 256 entry table is always generated.
2291 */
2292static void
2293png_build_8bit_table(png_structp png_ptr, png_bytepp ptable,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002294 PNG_CONST png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002295{
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002296 unsigned int i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002297 png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256);
2298
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002299 if (png_gamma_significant(gamma_val)) for (i=0; i<256; i++)
2300 table[i] = png_gamma_8bit_correct(i, gamma_val);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002301
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002302 else for (i=0; i<256; ++i)
2303 table[i] = (png_byte)i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002304}
2305
2306/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
2307 * tables, we don't make a full table if we are reducing to 8-bit in
2308 * the future. Note also how the gamma_16 tables are segmented so that
2309 * we don't need to allocate > 64K chunks for a full 16-bit table.
2310 */
2311void /* PRIVATE */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002312png_build_gamma_table(png_structp png_ptr, int bit_depth)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002313{
2314 png_debug(1, "in png_build_gamma_table");
2315
2316 if (bit_depth <= 8)
2317 {
2318 png_build_8bit_table(png_ptr, &png_ptr->gamma_table,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002319 png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->gamma,
2320 png_ptr->screen_gamma) : PNG_FP_1);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002321
2322#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
John Bowlerd273ad22011-05-07 21:00:28 -05002323 defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002324 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
John Bowlerd273ad22011-05-07 21:00:28 -05002325 if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY))
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002326 {
2327 png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002328 png_reciprocal(png_ptr->gamma));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002329
2330 png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002331 png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
2332 png_ptr->gamma/* Probably doing rgb_to_gray */);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002333 }
John Bowlerd273ad22011-05-07 21:00:28 -05002334#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002335 }
2336 else
2337 {
2338 png_byte shift, sig_bit;
2339
2340 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
2341 {
2342 sig_bit = png_ptr->sig_bit.red;
2343
2344 if (png_ptr->sig_bit.green > sig_bit)
2345 sig_bit = png_ptr->sig_bit.green;
2346
2347 if (png_ptr->sig_bit.blue > sig_bit)
2348 sig_bit = png_ptr->sig_bit.blue;
2349 }
2350 else
2351 sig_bit = png_ptr->sig_bit.gray;
2352
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002353 /* 16-bit gamma code uses this equation:
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002354 *
2355 * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8]
2356 *
2357 * Where 'iv' is the input color value and 'ov' is the output value -
2358 * pow(iv, gamma).
2359 *
2360 * Thus the gamma table consists of up to 256 256 entry tables. The table
2361 * is selected by the (8-gamma_shift) most significant of the low 8 bits of
2362 * the color value then indexed by the upper 8 bits:
2363 *
2364 * table[low bits][high 8 bits]
2365 *
2366 * So the table 'n' corresponds to all those 'iv' of:
2367 *
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002368 * <all high 8-bit values><n << gamma_shift>..<(n+1 << gamma_shift)-1>
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002369 *
2370 */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002371 if (sig_bit > 0 && sig_bit < 16U)
2372 shift = (png_byte)(16U - sig_bit); /* shift == insignificant bits */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002373
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002374 else
2375 shift = 0; /* keep all 16 bits */
2376
2377 if (png_ptr->transformations & PNG_16_TO_8)
2378 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002379 /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively
2380 * the significant bits in the *input* when the output will
2381 * eventually be 8 bits. By default it is 11.
2382 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002383 if (shift < (16U - PNG_MAX_GAMMA_8))
2384 shift = (16U - PNG_MAX_GAMMA_8);
2385 }
2386
2387 if (shift > 8U)
2388 shift = 8U; /* Guarantees at least one table! */
2389
2390 png_ptr->gamma_shift = shift;
2391
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002392#ifdef PNG_16BIT_SUPPORTED
John Bowlerd273ad22011-05-07 21:00:28 -05002393 /* NOTE: prior to 1.5.3 this test used to include PNG_BACKGROUND (now
2394 * PNG_COMPOSE). This effectively smashed the background calculation for
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002395 * 16-bit output because the 8-bit table assumes the result will be reduced
John Bowlerd273ad22011-05-07 21:00:28 -05002396 * to 8 bits.
2397 */
2398 if (png_ptr->transformations & PNG_16_TO_8)
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002399#endif
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002400 png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,
2401 png_ptr->screen_gamma > 0 ? png_product2(png_ptr->gamma,
2402 png_ptr->screen_gamma) : PNG_FP_1);
2403
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002404#ifdef PNG_16BIT_SUPPORTED
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002405 else
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002406 png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,
2407 png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->gamma,
2408 png_ptr->screen_gamma) : PNG_FP_1);
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002409#endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002410
2411#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
John Bowlerd273ad22011-05-07 21:00:28 -05002412 defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002413 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
John Bowlerd273ad22011-05-07 21:00:28 -05002414 if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY))
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002415 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002416 png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002417 png_reciprocal(png_ptr->gamma));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002418
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002419 /* Notice that the '16 from 1' table should be full precision, however
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002420 * the lookup on this table still uses gamma_shift, so it can't be.
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002421 * TODO: fix this.
2422 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002423 png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002424 png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
2425 png_ptr->gamma/* Probably doing rgb_to_gray */);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002426 }
John Bowlerd273ad22011-05-07 21:00:28 -05002427#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002428 }
2429}
2430#endif /* READ_GAMMA */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002431#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */