blob: ca9dfd7c1b5d945baef203e251e63ff9df8ed83d [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-Pehrson413138a2011-06-13 22:07:37 -05004 * Last changed in libpng 1.5.4 [(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-Pehrson3fb7c072011-06-16 09:24:02 -050017typedef png_libpng_version_1_5_4beta05 Your_png_h_is_not_version_1_5_4beta05;
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-Pehrsonab63dd02011-06-17 20:04:17 -0500620 "libpng version 1.5.4beta05 - June 18, 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-Pehrsonab63dd02011-06-17 20:04:17 -0500626 return "libpng version 1.5.4beta05 - June 18, 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
John Bowlerd2f0bc22011-06-11 06:42:06 -0500746 /* (x,y,z) values are first limited to 0..100000 (PNG_FP_1), the white
747 * y must also be greater than 0. To test for the upper limit calculate
748 * (PNG_FP_1-y) - x must be <= to this for z to be >= 0 (and the expression
749 * cannot overflow.) At this point we know x and y are >= 0 and (x+y) is
750 * <= PNG_FP_1. The previous test on PNG_MAX_UINT_31 is removed because it
751 * pointless (and it produces compiler warnings!)
752 */
Glenn Randers-Pehrson02a5e332008-11-24 22:10:23 -0600753 if (white_x < 0 || white_y <= 0 ||
754 red_x < 0 || red_y < 0 ||
755 green_x < 0 || green_y < 0 ||
756 blue_x < 0 || blue_y < 0)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600757 {
758 png_warning(png_ptr,
759 "Ignoring attempt to set negative chromaticity value");
760 ret = 0;
761 }
John Bowlerd2f0bc22011-06-11 06:42:06 -0500762 /* And (x+y) must be <= PNG_FP_1 (so z is >= 0) */
763 if (white_x > PNG_FP_1 - white_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600764 {
765 png_warning(png_ptr, "Invalid cHRM white point");
766 ret = 0;
767 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500768
John Bowlerd2f0bc22011-06-11 06:42:06 -0500769 if (red_x > PNG_FP_1 - red_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600770 {
771 png_warning(png_ptr, "Invalid cHRM red point");
772 ret = 0;
773 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500774
John Bowlerd2f0bc22011-06-11 06:42:06 -0500775 if (green_x > PNG_FP_1 - green_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600776 {
777 png_warning(png_ptr, "Invalid cHRM green point");
778 ret = 0;
779 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500780
John Bowlerd2f0bc22011-06-11 06:42:06 -0500781 if (blue_x > PNG_FP_1 - blue_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600782 {
783 png_warning(png_ptr, "Invalid cHRM blue point");
784 ret = 0;
785 }
Glenn Randers-Pehrsond0c40592008-11-22 07:09:51 -0600786
787 png_64bit_product(green_x - red_x, blue_y - red_y, &xy_hi, &xy_lo);
788 png_64bit_product(green_y - red_y, blue_x - red_x, &yx_hi, &yx_lo);
789
790 if (xy_hi == yx_hi && xy_lo == yx_lo)
791 {
792 png_warning(png_ptr,
793 "Ignoring attempt to set cHRM RGB triangle with zero area");
794 ret = 0;
795 }
796
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600797 return ret;
798}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500799# endif /* PNG_CHECK_cHRM_SUPPORTED */
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500800
801void /* PRIVATE */
802png_check_IHDR(png_structp png_ptr,
803 png_uint_32 width, png_uint_32 height, int bit_depth,
804 int color_type, int interlace_type, int compression_type,
805 int filter_type)
806{
807 int error = 0;
808
809 /* Check for width and height valid values */
810 if (width == 0)
811 {
812 png_warning(png_ptr, "Image width is zero in IHDR");
813 error = 1;
814 }
815
816 if (height == 0)
817 {
818 png_warning(png_ptr, "Image height is zero in IHDR");
819 error = 1;
820 }
821
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600822# ifdef PNG_SET_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrsonb7040362011-06-11 14:20:22 -0500823 if (width > png_ptr->user_width_max)
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500824
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600825# else
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500826 if (width > PNG_USER_WIDTH_MAX)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600827# endif
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500828 {
829 png_warning(png_ptr, "Image width exceeds user limit in IHDR");
830 error = 1;
831 }
832
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600833# ifdef PNG_SET_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrsonb7040362011-06-11 14:20:22 -0500834 if (height > png_ptr->user_height_max)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600835# else
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500836 if (height > PNG_USER_HEIGHT_MAX)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600837# endif
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500838 {
839 png_warning(png_ptr, "Image height exceeds user limit in IHDR");
840 error = 1;
841 }
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500842
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500843 if (width > PNG_UINT_31_MAX)
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500844 {
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500845 png_warning(png_ptr, "Invalid image width in IHDR");
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500846 error = 1;
847 }
848
Glenn Randers-Pehrsonbc363ec2010-10-12 21:17:00 -0500849 if (height > PNG_UINT_31_MAX)
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500850 {
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500851 png_warning(png_ptr, "Invalid image height in IHDR");
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500852 error = 1;
853 }
854
Glenn Randers-Pehrsonbc363ec2010-10-12 21:17:00 -0500855 if (width > (PNG_UINT_32_MAX
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500856 >> 3) /* 8-byte RGBA pixels */
Glenn Randers-Pehrsonc5080812010-10-23 08:26:26 -0500857 - 48 /* bigrowbuf hack */
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500858 - 1 /* filter byte */
859 - 7*8 /* rounding of width to multiple of 8 pixels */
860 - 8) /* extra max_pixel_depth pad */
861 png_warning(png_ptr, "Width is too large for libpng to process pixels");
862
863 /* Check other values */
864 if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
865 bit_depth != 8 && bit_depth != 16)
866 {
867 png_warning(png_ptr, "Invalid bit depth in IHDR");
868 error = 1;
869 }
870
871 if (color_type < 0 || color_type == 1 ||
872 color_type == 5 || color_type > 6)
873 {
874 png_warning(png_ptr, "Invalid color type in IHDR");
875 error = 1;
876 }
877
878 if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) ||
879 ((color_type == PNG_COLOR_TYPE_RGB ||
880 color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
881 color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
882 {
883 png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR");
884 error = 1;
885 }
886
887 if (interlace_type >= PNG_INTERLACE_LAST)
888 {
889 png_warning(png_ptr, "Unknown interlace method in IHDR");
890 error = 1;
891 }
892
893 if (compression_type != PNG_COMPRESSION_TYPE_BASE)
894 {
895 png_warning(png_ptr, "Unknown compression method in IHDR");
896 error = 1;
897 }
898
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600899# ifdef PNG_MNG_FEATURES_SUPPORTED
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500900 /* Accept filter_method 64 (intrapixel differencing) only if
901 * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
902 * 2. Libpng did not read a PNG signature (this filter_method is only
903 * used in PNG datastreams that are embedded in MNG datastreams) and
904 * 3. The application called png_permit_mng_features with a mask that
905 * included PNG_FLAG_MNG_FILTER_64 and
906 * 4. The filter_method is 64 and
907 * 5. The color_type is RGB or RGBA
908 */
909 if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) &&
910 png_ptr->mng_features_permitted)
911 png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");
912
913 if (filter_type != PNG_FILTER_TYPE_BASE)
914 {
Glenn Randers-Pehrson7ec330d2009-09-25 11:45:42 -0500915 if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500916 (filter_type == PNG_INTRAPIXEL_DIFFERENCING) &&
917 ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
918 (color_type == PNG_COLOR_TYPE_RGB ||
919 color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
Glenn Randers-Pehrson7ec330d2009-09-25 11:45:42 -0500920 {
921 png_warning(png_ptr, "Unknown filter method in IHDR");
922 error = 1;
923 }
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500924
Glenn Randers-Pehrson7ec330d2009-09-25 11:45:42 -0500925 if (png_ptr->mode & PNG_HAVE_PNG_SIGNATURE)
926 {
927 png_warning(png_ptr, "Invalid filter method in IHDR");
928 error = 1;
929 }
930 }
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500931
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600932# else
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500933 if (filter_type != PNG_FILTER_TYPE_BASE)
934 {
935 png_warning(png_ptr, "Unknown filter method in IHDR");
936 error = 1;
937 }
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600938# endif
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500939
940 if (error == 1)
941 png_error(png_ptr, "Invalid IHDR data");
942}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500943
944#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED)
945/* ASCII to fp functions */
946/* Check an ASCII formated floating point value, see the more detailed
947 * comments in pngpriv.h
948 */
949/* The following is used internally to preserve the 'valid' flag */
950#define png_fp_add(state, flags) ((state) |= (flags))
951#define png_fp_set(state, value)\
952 ((state) = (value) | ((state) & PNG_FP_WAS_VALID))
953
954/* Internal type codes: bits above the base state! */
955#define PNG_FP_SIGN 0 /* [+-] */
956#define PNG_FP_DOT 4 /* . */
957#define PNG_FP_DIGIT 8 /* [0123456789] */
958#define PNG_FP_E 12 /* [Ee] */
959
960int /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500961png_check_fp_number(png_const_charp string, png_size_t size, int *statep,
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500962 png_size_tp whereami)
963{
964 int state = *statep;
965 png_size_t i = *whereami;
966
967 while (i < size)
968 {
969 int type;
970 /* First find the type of the next character */
971 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500972 char ch = string[i];
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500973
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500974 if (ch >= 48 && ch <= 57)
975 type = PNG_FP_DIGIT;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500976
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500977 else switch (ch)
978 {
979 case 43: case 45: type = PNG_FP_SIGN; break;
980 case 46: type = PNG_FP_DOT; break;
981 case 69: case 101: type = PNG_FP_E; break;
982 default: goto PNG_FP_End;
983 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500984 }
985
986 /* Now deal with this type according to the current
987 * state, the type is arranged to not overlap the
988 * bits of the PNG_FP_STATE.
989 */
990 switch ((state & PNG_FP_STATE) + type)
991 {
992 case PNG_FP_INTEGER + PNG_FP_SIGN:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500993 if (state & PNG_FP_SAW_ANY)
994 goto PNG_FP_End; /* not a part of the number */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500995
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500996 png_fp_add(state, PNG_FP_SAW_SIGN);
997 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500998
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500999 case PNG_FP_INTEGER + PNG_FP_DOT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001000 /* Ok as trailer, ok as lead of fraction. */
1001 if (state & PNG_FP_SAW_DOT) /* two dots */
1002 goto PNG_FP_End;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001003
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001004 else if (state & PNG_FP_SAW_DIGIT) /* trailing dot? */
1005 png_fp_add(state, PNG_FP_SAW_DOT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001006
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001007 else
1008 png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001009
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001010 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001011
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001012 case PNG_FP_INTEGER + PNG_FP_DIGIT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001013 if (state & PNG_FP_SAW_DOT) /* delayed fraction */
1014 png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001015
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001016 png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001017
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001018 break;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001019 case PNG_FP_INTEGER + PNG_FP_E:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001020 if ((state & PNG_FP_SAW_DIGIT) == 0)
1021 goto PNG_FP_End;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001022
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001023 png_fp_set(state, PNG_FP_EXPONENT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001024
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001025 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001026
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001027 /* case PNG_FP_FRACTION + PNG_FP_SIGN:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001028 goto PNG_FP_End; ** no sign in exponent */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001029
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001030 /* case PNG_FP_FRACTION + PNG_FP_DOT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001031 goto PNG_FP_End; ** Because SAW_DOT is always set */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001032
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001033 case PNG_FP_FRACTION + PNG_FP_DIGIT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001034 png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
1035 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001036
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001037 case PNG_FP_FRACTION + PNG_FP_E:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001038 /* This is correct because the trailing '.' on an
1039 * integer is handled above - so we can only get here
1040 * with the sequence ".E" (with no preceding digits).
1041 */
1042 if ((state & PNG_FP_SAW_DIGIT) == 0)
1043 goto PNG_FP_End;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001044
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001045 png_fp_set(state, PNG_FP_EXPONENT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001046
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001047 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001048
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001049 case PNG_FP_EXPONENT + PNG_FP_SIGN:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001050 if (state & PNG_FP_SAW_ANY)
1051 goto PNG_FP_End; /* not a part of the number */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001052
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001053 png_fp_add(state, PNG_FP_SAW_SIGN);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001054
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001055 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001056
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001057 /* case PNG_FP_EXPONENT + PNG_FP_DOT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001058 goto PNG_FP_End; */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001059
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001060 case PNG_FP_EXPONENT + PNG_FP_DIGIT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001061 png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001062
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001063 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001064
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001065 /* case PNG_FP_EXPONEXT + PNG_FP_E:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001066 goto PNG_FP_End; */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001067
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001068 default: goto PNG_FP_End; /* I.e. break 2 */
1069 }
1070
1071 /* The character seems ok, continue. */
1072 ++i;
1073 }
1074
1075PNG_FP_End:
1076 /* Here at the end, update the state and return the correct
1077 * return code.
1078 */
1079 *statep = state;
1080 *whereami = i;
1081
1082 return (state & PNG_FP_SAW_DIGIT) != 0;
1083}
1084
1085
1086/* The same but for a complete string. */
1087int
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001088png_check_fp_string(png_const_charp string, png_size_t size)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001089{
1090 int state=0;
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001091 png_size_t char_index=0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001092
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001093 return png_check_fp_number(string, size, &state, &char_index) &&
1094 (char_index == size || string[char_index] == 0);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001095}
1096#endif /* pCAL or sCAL */
1097
1098#ifdef PNG_READ_sCAL_SUPPORTED
1099# ifdef PNG_FLOATING_POINT_SUPPORTED
1100/* Utility used below - a simple accurate power of ten from an integral
1101 * exponent.
1102 */
1103static double
1104png_pow10(int power)
1105{
1106 int recip = 0;
1107 double d = 1;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001108
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001109 /* Handle negative exponent with a reciprocal at the end because
1110 * 10 is exact whereas .1 is inexact in base 2
1111 */
1112 if (power < 0)
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001113 {
1114 if (power < DBL_MIN_10_EXP) return 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001115 recip = 1, power = -power;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001116 }
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001117
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001118 if (power > 0)
1119 {
1120 /* Decompose power bitwise. */
1121 double mult = 10;
1122 do
1123 {
1124 if (power & 1) d *= mult;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001125 mult *= mult;
1126 power >>= 1;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001127 }
1128 while (power > 0);
1129
1130 if (recip) d = 1/d;
1131 }
1132 /* else power is 0 and d is 1 */
1133
1134 return d;
1135}
1136
1137/* Function to format a floating point value in ASCII with a given
1138 * precision.
1139 */
1140void /* PRIVATE */
1141png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001142 double fp, unsigned int precision)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001143{
1144 /* We use standard functions from math.h, but not printf because
1145 * that would require stdio. The caller must supply a buffer of
1146 * sufficient size or we will png_error. The tests on size and
1147 * the space in ascii[] consumed are indicated below.
1148 */
1149 if (precision < 1)
1150 precision = DBL_DIG;
1151
1152 /* Enforce the limit of the implementation precision too. */
1153 if (precision > DBL_DIG+1)
1154 precision = DBL_DIG+1;
1155
1156 /* Basic sanity checks */
1157 if (size >= precision+5) /* See the requirements below. */
1158 {
1159 if (fp < 0)
1160 {
1161 fp = -fp;
Glenn Randers-Pehrsonb75b2412011-04-16 19:35:05 -05001162 *ascii++ = 45; /* '-' PLUS 1 TOTAL 1 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001163 --size;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001164 }
1165
1166 if (fp >= DBL_MIN && fp <= DBL_MAX)
1167 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001168 int exp_b10; /* A base 10 exponent */
1169 double base; /* 10^exp_b10 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001170
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001171 /* First extract a base 10 exponent of the number,
1172 * the calculation below rounds down when converting
1173 * from base 2 to base 10 (multiply by log10(2) -
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001174 * 0.3010, but 77/256 is 0.3008, so exp_b10 needs to
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001175 * be increased. Note that the arithmetic shift
1176 * performs a floor() unlike C arithmetic - using a
1177 * C multiply would break the following for negative
1178 * exponents.
1179 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001180 (void)frexp(fp, &exp_b10); /* exponent to base 2 */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001181
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001182 exp_b10 = (exp_b10 * 77) >> 8; /* <= exponent to base 10 */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001183
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001184 /* Avoid underflow here. */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001185 base = png_pow10(exp_b10); /* May underflow */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001186
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001187 while (base < DBL_MIN || base < fp)
1188 {
1189 /* And this may overflow. */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001190 double test = png_pow10(exp_b10+1);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001191
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001192 if (test <= DBL_MAX)
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001193 ++exp_b10, base = test;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001194
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001195 else
1196 break;
1197 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001198
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001199 /* Normalize fp and correct exp_b10, after this fp is in the
1200 * range [.1,1) and exp_b10 is both the exponent and the digit
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001201 * *before* which the decimal point should be inserted
1202 * (starting with 0 for the first digit). Note that this
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001203 * works even if 10^exp_b10 is out of range because of the
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001204 * test on DBL_MAX above.
1205 */
1206 fp /= base;
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001207 while (fp >= 1) fp /= 10, ++exp_b10;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001208
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001209 /* Because of the code above fp may, at this point, be
1210 * less than .1, this is ok because the code below can
1211 * handle the leading zeros this generates, so no attempt
1212 * is made to correct that here.
1213 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001214
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001215 {
1216 int czero, clead, cdigits;
1217 char exponent[10];
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001218
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001219 /* Allow up to two leading zeros - this will not lengthen
1220 * the number compared to using E-n.
1221 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001222 if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001223 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001224 czero = -exp_b10; /* PLUS 2 digits: TOTAL 3 */
1225 exp_b10 = 0; /* Dot added below before first output. */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001226 }
1227 else
1228 czero = 0; /* No zeros to add */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001229
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001230 /* Generate the digit list, stripping trailing zeros and
1231 * inserting a '.' before a digit if the exponent is 0.
1232 */
1233 clead = czero; /* Count of leading zeros */
1234 cdigits = 0; /* Count of digits in list. */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001235
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001236 do
1237 {
1238 double d;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001239
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001240 fp *= 10;
1241 /* Use modf here, not floor and subtract, so that
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001242 * the separation is done in one step. At the end
1243 * of the loop don't break the number into parts so
1244 * that the final digit is rounded.
1245 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001246 if (cdigits+czero-clead+1 < (int)precision)
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001247 fp = modf(fp, &d);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001248
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001249 else
1250 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001251 d = floor(fp + .5);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001252
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001253 if (d > 9)
1254 {
1255 /* Rounding up to 10, handle that here. */
1256 if (czero > 0)
1257 {
1258 --czero, d = 1;
1259 if (cdigits == 0) --clead;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001260 }
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001261 else
1262 {
1263 while (cdigits > 0 && d > 9)
1264 {
1265 int ch = *--ascii;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001266
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001267 if (exp_b10 != (-1))
1268 ++exp_b10;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001269
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001270 else if (ch == 46)
1271 {
1272 ch = *--ascii, ++size;
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001273 /* Advance exp_b10 to '1', so that the
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001274 * decimal point happens after the
1275 * previous digit.
1276 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001277 exp_b10 = 1;
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001278 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001279
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001280 --cdigits;
1281 d = ch - 47; /* I.e. 1+(ch-48) */
1282 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001283
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001284 /* Did we reach the beginning? If so adjust the
1285 * exponent but take into account the leading
1286 * decimal point.
1287 */
1288 if (d > 9) /* cdigits == 0 */
1289 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001290 if (exp_b10 == (-1))
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001291 {
1292 /* Leading decimal point (plus zeros?), if
1293 * we lose the decimal point here it must
1294 * be reentered below.
1295 */
1296 int ch = *--ascii;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001297
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001298 if (ch == 46)
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001299 ++size, exp_b10 = 1;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001300
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001301 /* Else lost a leading zero, so 'exp_b10' is
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001302 * still ok at (-1)
1303 */
1304 }
1305 else
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001306 ++exp_b10;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001307
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001308 /* In all cases we output a '1' */
1309 d = 1;
1310 }
1311 }
1312 }
1313 fp = 0; /* Guarantees termination below. */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001314 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001315
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001316 if (d == 0)
1317 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001318 ++czero;
1319 if (cdigits == 0) ++clead;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001320 }
1321 else
1322 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001323 /* Included embedded zeros in the digit count. */
1324 cdigits += czero - clead;
1325 clead = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001326
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001327 while (czero > 0)
1328 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001329 /* exp_b10 == (-1) means we just output the decimal
1330 * place - after the DP don't adjust 'exp_b10' any
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001331 * more!
1332 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001333 if (exp_b10 != (-1))
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001334 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001335 if (exp_b10 == 0) *ascii++ = 46, --size;
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001336 /* PLUS 1: TOTAL 4 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001337 --exp_b10;
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001338 }
1339 *ascii++ = 48, --czero;
1340 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001341
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001342 if (exp_b10 != (-1))
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001343 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001344 if (exp_b10 == 0) *ascii++ = 46, --size; /* counted
1345 above */
1346 --exp_b10;
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001347 }
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001348 *ascii++ = (char)(48 + (int)d), ++cdigits;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001349 }
1350 }
1351 while (cdigits+czero-clead < (int)precision && fp > DBL_MIN);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001352
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001353 /* The total output count (max) is now 4+precision */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001354
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001355 /* Check for an exponent, if we don't need one we are
1356 * done and just need to terminate the string. At
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001357 * this point exp_b10==(-1) is effectively if flag - it got
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001358 * to '-1' because of the decrement after outputing
1359 * the decimal point above (the exponent required is
1360 * *not* -1!)
1361 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001362 if (exp_b10 >= (-1) && exp_b10 <= 2)
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001363 {
1364 /* The following only happens if we didn't output the
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001365 * leading zeros above for negative exponent, so this
1366 * doest add to the digit requirement. Note that the
1367 * two zeros here can only be output if the two leading
1368 * zeros were *not* output, so this doesn't increase
1369 * the output count.
1370 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001371 while (--exp_b10 >= 0) *ascii++ = 48;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001372
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001373 *ascii = 0;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001374
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001375 /* Total buffer requirement (including the '\0') is
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001376 * 5+precision - see check at the start.
1377 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001378 return;
1379 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001380
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001381 /* Here if an exponent is required, adjust size for
1382 * the digits we output but did not count. The total
1383 * digit output here so far is at most 1+precision - no
1384 * decimal point and no leading or trailing zeros have
1385 * been output.
1386 */
1387 size -= cdigits;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001388
Glenn Randers-Pehrsonb75b2412011-04-16 19:35:05 -05001389 *ascii++ = 69, --size; /* 'E': PLUS 1 TOTAL 2+precision */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001390 if (exp_b10 < 0)
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001391 {
1392 *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001393 exp_b10 = -exp_b10;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001394 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001395
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001396 cdigits = 0;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001397
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001398 while (exp_b10 > 0)
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001399 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001400 exponent[cdigits++] = (char)(48 + exp_b10 % 10);
1401 exp_b10 /= 10;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001402 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001403
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001404 /* Need another size check here for the exponent digits, so
1405 * this need not be considered above.
1406 */
1407 if ((int)size > cdigits)
1408 {
1409 while (cdigits > 0) *ascii++ = exponent[--cdigits];
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001410
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001411 *ascii = 0;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001412
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001413 return;
1414 }
1415 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001416 }
1417 else if (!(fp >= DBL_MIN))
1418 {
1419 *ascii++ = 48; /* '0' */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001420 *ascii = 0;
1421 return;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001422 }
1423 else
1424 {
1425 *ascii++ = 105; /* 'i' */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001426 *ascii++ = 110; /* 'n' */
1427 *ascii++ = 102; /* 'f' */
1428 *ascii = 0;
1429 return;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001430 }
1431 }
1432
1433 /* Here on buffer too small. */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001434 png_error(png_ptr, "ASCII conversion buffer too small");
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001435}
1436
1437# endif /* FLOATING_POINT */
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001438
1439# ifdef PNG_FIXED_POINT_SUPPORTED
1440/* Function to format a fixed point value in ASCII.
1441 */
1442void /* PRIVATE */
1443png_ascii_from_fixed(png_structp png_ptr, png_charp ascii, png_size_t size,
1444 png_fixed_point fp)
1445{
1446 /* Require space for 10 decimal digits, a decimal point, a minus sign and a
1447 * trailing \0, 13 characters:
1448 */
1449 if (size > 12)
1450 {
1451 png_uint_32 num;
1452
1453 /* Avoid overflow here on the minimum integer. */
1454 if (fp < 0)
1455 *ascii++ = 45, --size, num = -fp;
1456 else
1457 num = fp;
1458
1459 if (num <= 0x80000000U) /* else overflowed */
1460 {
Glenn Randers-Pehrsonb75b2412011-04-16 19:35:05 -05001461 unsigned int ndigits = 0, first = 16 /* flag value */;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001462 char digits[10];
1463
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001464 while (num)
1465 {
1466 /* Split the low digit off num: */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001467 unsigned int tmp = num/10;
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001468 num -= tmp*10;
1469 digits[ndigits++] = (char)(48 + num);
1470 /* Record the first non-zero digit, note that this is a number
1471 * starting at 1, it's not actually the array index.
1472 */
1473 if (first == 16 && num > 0)
1474 first = ndigits;
1475 num = tmp;
1476 }
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001477
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001478 if (ndigits > 0)
1479 {
1480 while (ndigits > 5) *ascii++ = digits[--ndigits];
1481 /* The remaining digits are fractional digits, ndigits is '5' or
1482 * smaller at this point. It is certainly not zero. Check for a
1483 * non-zero fractional digit:
1484 */
1485 if (first <= 5)
1486 {
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001487 unsigned int i;
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001488 *ascii++ = 46; /* decimal point */
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -05001489 /* ndigits may be <5 for small numbers, output leading zeros
1490 * then ndigits digits to first:
1491 */
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001492 i = 5;
1493 while (ndigits < i) *ascii++ = 48, --i;
1494 while (ndigits >= first) *ascii++ = digits[--ndigits];
1495 /* Don't output the trailing zeros! */
1496 }
1497 }
1498 else
1499 *ascii++ = 48;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001500
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001501 /* And null terminate the string: */
1502 *ascii = 0;
1503 return;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001504 }
1505 }
1506
1507 /* Here on buffer too small. */
1508 png_error(png_ptr, "ASCII conversion buffer too small");
1509}
1510# endif /* FIXED_POINT */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001511#endif /* READ_SCAL */
1512
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -05001513#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001514 !defined(PNG_FIXED_POINT_MACRO_SUPPORTED)
1515png_fixed_point
1516png_fixed(png_structp png_ptr, double fp, png_const_charp text)
1517{
1518 double r = floor(100000 * fp + .5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001519
Glenn Randers-Pehrson77c3bf12011-01-20 15:56:31 -06001520 if (r > 2147483647. || r < -2147483648.)
1521 png_fixed_error(png_ptr, text);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001522
Glenn Randers-Pehrson77c3bf12011-01-20 15:56:31 -06001523 return (png_fixed_point)r;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001524}
1525#endif
1526
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -05001527#if defined(PNG_READ_GAMMA_SUPPORTED) || \
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001528 defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG__READ_pHYs_SUPPORTED)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001529/* muldiv functions */
1530/* This API takes signed arguments and rounds the result to the nearest
1531 * integer (or, for a fixed point number - the standard argument - to
1532 * the nearest .00001). Overflow and divide by zero are signalled in
1533 * the result, a boolean - true on success, false on overflow.
1534 */
1535int
1536png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001537 png_int_32 divisor)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001538{
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001539 /* Return a * times / divisor, rounded. */
1540 if (divisor != 0)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001541 {
1542 if (a == 0 || times == 0)
1543 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001544 *res = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001545 return 1;
1546 }
1547 else
1548 {
1549#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001550 double r = a;
1551 r *= times;
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001552 r /= divisor;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001553 r = floor(r+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001554
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001555 /* A png_fixed_point is a 32-bit integer. */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001556 if (r <= 2147483647. && r >= -2147483648.)
1557 {
1558 *res = (png_fixed_point)r;
1559 return 1;
1560 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001561#else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001562 int negative = 0;
1563 png_uint_32 A, T, D;
Glenn Randers-Pehrson3b5d6952010-08-19 08:06:12 -05001564 png_uint_32 s16, s32, s00;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001565
1566 if (a < 0)
1567 negative = 1, A = -a;
1568 else
1569 A = a;
1570
1571 if (times < 0)
1572 negative = !negative, T = -times;
1573 else
1574 T = times;
1575
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001576 if (divisor < 0)
1577 negative = !negative, D = -divisor;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001578 else
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001579 D = divisor;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001580
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001581 /* Following can't overflow because the arguments only
1582 * have 31 bits each, however the result may be 32 bits.
1583 */
Glenn Randers-Pehrson3b5d6952010-08-19 08:06:12 -05001584 s16 = (A >> 16) * (T & 0xffff) +
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001585 (A & 0xffff) * (T >> 16);
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001586 /* Can't overflow because the a*times bit is only 30
1587 * bits at most.
1588 */
Glenn Randers-Pehrson3b5d6952010-08-19 08:06:12 -05001589 s32 = (A >> 16) * (T >> 16) + (s16 >> 16);
1590 s00 = (A & 0xffff) * (T & 0xffff);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001591
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001592 s16 = (s16 & 0xffff) << 16;
1593 s00 += s16;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001594
1595 if (s00 < s16)
1596 ++s32; /* carry */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001597
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001598 if (s32 < D) /* else overflow */
1599 {
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001600 /* s32.s00 is now the 64-bit product, do a standard
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001601 * division, we know that s32 < D, so the maximum
1602 * required shift is 31.
1603 */
1604 int bitshift = 32;
1605 png_fixed_point result = 0; /* NOTE: signed */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001606
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001607 while (--bitshift >= 0)
1608 {
1609 png_uint_32 d32, d00;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001610
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001611 if (bitshift > 0)
1612 d32 = D >> (32-bitshift), d00 = D << bitshift;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001613
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001614 else
1615 d32 = 0, d00 = D;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001616
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001617 if (s32 > d32)
1618 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001619 if (s00 < d00) --s32; /* carry */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001620 s32 -= d32, s00 -= d00, result += 1<<bitshift;
1621 }
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001622
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001623 else
1624 if (s32 == d32 && s00 >= d00)
1625 s32 = 0, s00 -= d00, result += 1<<bitshift;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001626 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001627
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001628 /* Handle the rounding. */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001629 if (s00 >= (D >> 1))
1630 ++result;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001631
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001632 if (negative)
1633 result = -result;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001634
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001635 /* Check for overflow. */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001636 if ((negative && result <= 0) || (!negative && result >= 0))
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001637 {
1638 *res = result;
1639 return 1;
1640 }
1641 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001642#endif
1643 }
1644 }
1645
1646 return 0;
1647}
1648#endif /* READ_GAMMA || INCH_CONVERSIONS */
1649
1650#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)
1651/* The following is for when the caller doesn't much care about the
1652 * result.
1653 */
1654png_fixed_point
1655png_muldiv_warn(png_structp png_ptr, png_fixed_point a, png_int_32 times,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001656 png_int_32 divisor)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001657{
1658 png_fixed_point result;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001659
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001660 if (png_muldiv(&result, a, times, divisor))
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001661 return result;
1662
1663 png_warning(png_ptr, "fixed point overflow ignored");
1664 return 0;
1665}
1666#endif
1667
1668#ifdef PNG_READ_GAMMA_SUPPORTED /* more fixed point functions for gammma */
1669/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */
1670png_fixed_point
1671png_reciprocal(png_fixed_point a)
1672{
1673#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
1674 double r = floor(1E10/a+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001675
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001676 if (r <= 2147483647. && r >= -2147483648.)
1677 return (png_fixed_point)r;
1678#else
1679 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001680
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001681 if (png_muldiv(&res, 100000, 100000, a))
1682 return res;
1683#endif
1684
1685 return 0; /* error/overflow */
1686}
1687
1688/* A local convenience routine. */
1689static png_fixed_point
1690png_product2(png_fixed_point a, png_fixed_point b)
1691{
Glenn Randers-Pehrson9c690912010-08-27 11:39:38 -05001692 /* The required result is 1/a * 1/b; the following preserves accuracy. */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001693#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
1694 double r = a * 1E-5;
1695 r *= b;
1696 r = floor(r+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001697
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001698 if (r <= 2147483647. && r >= -2147483648.)
1699 return (png_fixed_point)r;
1700#else
1701 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001702
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001703 if (png_muldiv(&res, a, b, 100000))
1704 return res;
1705#endif
1706
1707 return 0; /* overflow */
1708}
1709
1710/* The inverse of the above. */
1711png_fixed_point
1712png_reciprocal2(png_fixed_point a, png_fixed_point b)
1713{
Glenn Randers-Pehrson9c690912010-08-27 11:39:38 -05001714 /* The required result is 1/a * 1/b; the following preserves accuracy. */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001715#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
1716 double r = 1E15/a;
1717 r /= b;
1718 r = floor(r+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001719
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001720 if (r <= 2147483647. && r >= -2147483648.)
1721 return (png_fixed_point)r;
1722#else
1723 /* This may overflow because the range of png_fixed_point isn't symmetric,
1724 * but this API is only used for the product of file and screen gamma so it
1725 * doesn't matter that the smallest number it can produce is 1/21474, not
1726 * 1/100000
1727 */
1728 png_fixed_point res = png_product2(a, b);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001729
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001730 if (res != 0)
1731 return png_reciprocal(res);
1732#endif
1733
1734 return 0; /* overflow */
1735}
1736#endif /* READ_GAMMA */
1737
1738#ifdef PNG_CHECK_cHRM_SUPPORTED
1739/* Added at libpng version 1.2.34 (Dec 8, 2008) and 1.4.0 (Jan 2,
1740 * 2010: moved from pngset.c) */
1741/*
1742 * Multiply two 32-bit numbers, V1 and V2, using 32-bit
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001743 * arithmetic, to produce a 64-bit result in the HI/LO words.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001744 *
1745 * A B
1746 * x C D
1747 * ------
1748 * AD || BD
1749 * AC || CB || 0
1750 *
1751 * where A and B are the high and low 16-bit words of V1,
1752 * C and D are the 16-bit words of V2, AD is the product of
1753 * A and D, and X || Y is (X << 16) + Y.
1754*/
1755
1756void /* PRIVATE */
1757png_64bit_product (long v1, long v2, unsigned long *hi_product,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001758 unsigned long *lo_product)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001759{
1760 int a, b, c, d;
1761 long lo, hi, x, y;
1762
1763 a = (v1 >> 16) & 0xffff;
1764 b = v1 & 0xffff;
1765 c = (v2 >> 16) & 0xffff;
1766 d = v2 & 0xffff;
1767
1768 lo = b * d; /* BD */
1769 x = a * d + c * b; /* AD + CB */
1770 y = ((lo >> 16) & 0xffff) + x;
1771
1772 lo = (lo & 0xffff) | ((y & 0xffff) << 16);
1773 hi = (y >> 16) & 0xffff;
1774
1775 hi += a * c; /* AC */
1776
1777 *hi_product = (unsigned long)hi;
1778 *lo_product = (unsigned long)lo;
1779}
1780#endif /* CHECK_cHRM */
1781
1782#ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */
1783#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED
1784/* Fixed point gamma.
1785 *
1786 * To calculate gamma this code implements fast log() and exp() calls using only
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001787 * fixed point arithmetic. This code has sufficient precision for either 8-bit
1788 * or 16-bit sample values.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001789 *
1790 * The tables used here were calculated using simple 'bc' programs, but C double
1791 * precision floating point arithmetic would work fine. The programs are given
1792 * at the head of each table.
1793 *
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001794 * 8-bit log table
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001795 * 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 -05001796 * 255, so it's the base 2 logarithm of a normalized 8-bit floating point
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001797 * mantissa. The numbers are 32-bit fractions.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001798 */
1799static png_uint_32
1800png_8bit_l2[128] =
1801{
1802# if PNG_DO_BC
1803 for (i=128;i<256;++i) { .5 - l(i/255)/l(2)*65536*65536; }
1804# endif
1805 4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U,
1806 3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U,
1807 3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U,
1808 3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U,
1809 3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U,
1810 2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U,
1811 2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U,
1812 2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U,
1813 2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U,
1814 2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U,
1815 1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U,
1816 1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U,
1817 1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U,
1818 1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U,
1819 1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U,
1820 971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U,
1821 803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U,
1822 639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U,
1823 479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U,
1824 324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U,
1825 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U,
1826 24347096U, 0U
1827#if 0
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001828 /* The following are the values for 16-bit tables - these work fine for the
1829 * 8-bit conversions but produce very slightly larger errors in the 16-bit
1830 * log (about 1.2 as opposed to 0.7 absolute error in the final value). To
1831 * use these all the shifts below must be adjusted appropriately.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001832 */
1833 65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054,
1834 57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803,
1835 50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068,
1836 43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782,
1837 37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887,
1838 31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339,
1839 25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098,
1840 20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132,
1841 15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415,
1842 10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523,
1843 6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495,
1844 1119, 744, 372
1845#endif
1846};
1847
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001848static png_int_32
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001849png_log8bit(unsigned int x)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001850{
John Bowler168a4332011-01-16 19:32:22 -06001851 unsigned int lg2 = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001852 /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log,
1853 * because the log is actually negate that means adding 1. The final
1854 * returned value thus has the range 0 (for 255 input) to 7.994 (for 1
1855 * input), return 7.99998 for the overflow (log 0) case - so the result is
1856 * always at most 19 bits.
1857 */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001858 if ((x &= 0xff) == 0)
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -06001859 return 0xffffffff;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001860
1861 if ((x & 0xf0) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001862 lg2 = 4, x <<= 4;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001863
1864 if ((x & 0xc0) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001865 lg2 += 2, x <<= 2;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001866
1867 if ((x & 0x80) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001868 lg2 += 1, x <<= 1;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001869
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001870 /* result is at most 19 bits, so this cast is safe: */
John Bowler168a4332011-01-16 19:32:22 -06001871 return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001872}
1873
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001874/* The above gives exact (to 16 binary places) log2 values for 8-bit images,
1875 * 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 -05001876 * get an approximation then multiply the approximation by a correction factor
1877 * determined by the remaining up to 8 bits. This requires an additional step
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001878 * in the 16-bit case.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001879 *
1880 * We want log2(value/65535), we have log2(v'/255), where:
1881 *
1882 * value = v' * 256 + v''
1883 * = v' * f
1884 *
1885 * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128
1886 * 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 -05001887 * than 258. The final factor also needs to correct for the fact that our 8-bit
1888 * value is scaled by 255, whereas the 16-bit values must be scaled by 65535.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001889 *
1890 * This gives a final formula using a calculated value 'x' which is value/v' and
1891 * scaling by 65536 to match the above table:
1892 *
1893 * log2(x/257) * 65536
1894 *
1895 * Since these numbers are so close to '1' we can use simple linear
1896 * interpolation between the two end values 256/257 (result -368.61) and 258/257
1897 * (result 367.179). The values used below are scaled by a further 64 to give
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001898 * 16-bit precision in the interpolation:
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001899 *
1900 * Start (256): -23591
1901 * Zero (257): 0
1902 * End (258): 23499
1903 */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001904static png_int_32
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001905png_log16bit(png_uint_32 x)
1906{
John Bowler168a4332011-01-16 19:32:22 -06001907 unsigned int lg2 = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001908
1909 /* As above, but now the input has 16 bits. */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001910 if ((x &= 0xffff) == 0)
1911 return 0xffffffff;
1912
1913 if ((x & 0xff00) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001914 lg2 = 8, x <<= 8;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001915
1916 if ((x & 0xf000) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001917 lg2 += 4, x <<= 4;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001918
1919 if ((x & 0xc000) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001920 lg2 += 2, x <<= 2;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001921
1922 if ((x & 0x8000) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001923 lg2 += 1, x <<= 1;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001924
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001925 /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001926 * value.
1927 */
John Bowler168a4332011-01-16 19:32:22 -06001928 lg2 <<= 28;
1929 lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001930
1931 /* Now we need to interpolate the factor, this requires a division by the top
1932 * 8 bits. Do this with maximum precision.
1933 */
1934 x = ((x << 16) + (x >> 9)) / (x >> 8);
1935
1936 /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24,
1937 * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly
1938 * 16 bits to interpolate to get the low bits of the result. Round the
1939 * answer. Note that the end point values are scaled by 64 to retain overall
John Bowler168a4332011-01-16 19:32:22 -06001940 * precision and that 'lg2' is current scaled by an extra 12 bits, so adjust
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001941 * the overall scaling by 6-12. Round at every step.
1942 */
1943 x -= 1U << 24;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001944
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001945 if (x <= 65536U) /* <= '257' */
John Bowler168a4332011-01-16 19:32:22 -06001946 lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001947
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001948 else
John Bowler168a4332011-01-16 19:32:22 -06001949 lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001950
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001951 /* Safe, because the result can't have more than 20 bits: */
John Bowler168a4332011-01-16 19:32:22 -06001952 return (png_int_32)((lg2 + 2048) >> 12);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001953}
1954
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001955/* The 'exp()' case must invert the above, taking a 20-bit fixed point
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001956 * logarithmic value and returning a 16 or 8-bit number as appropriate. In
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001957 * each case only the low 16 bits are relevant - the fraction - since the
1958 * integer bits (the top 4) simply determine a shift.
1959 *
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05001960 * The worst case is the 16-bit distinction between 65535 and 65534, this
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001961 * requires perhaps spurious accuracty in the decoding of the logarithm to
1962 * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance
1963 * of getting this accuracy in practice.
1964 *
1965 * To deal with this the following exp() function works out the exponent of the
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001966 * frational part of the logarithm by using an accurate 32-bit value from the
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001967 * top four fractional bits then multiplying in the remaining bits.
1968 */
1969static png_uint_32
1970png_32bit_exp[16] =
1971{
1972# if PNG_DO_BC
1973 for (i=0;i<16;++i) { .5 + e(-i/16*l(2))*2^32; }
1974# endif
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05001975 /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001976 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U,
1977 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U,
1978 2553802834U, 2445529972U, 2341847524U, 2242560872U
1979};
1980
1981/* Adjustment table; provided to explain the numbers in the code below. */
1982#if PNG_DO_BC
1983for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"}
1984 11 44937.64284865548751208448
1985 10 45180.98734845585101160448
1986 9 45303.31936980687359311872
1987 8 45364.65110595323018870784
1988 7 45395.35850361789624614912
1989 6 45410.72259715102037508096
1990 5 45418.40724413220722311168
1991 4 45422.25021786898173001728
1992 3 45424.17186732298419044352
1993 2 45425.13273269940811464704
1994 1 45425.61317555035558641664
1995 0 45425.85339951654943850496
1996#endif
1997
1998static png_uint_32
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001999png_exp(png_fixed_point x)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002000{
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002001 if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002002 {
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002003 /* Obtain a 4-bit approximation */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002004 png_uint_32 e = png_32bit_exp[(x >> 12) & 0xf];
2005
2006 /* Incorporate the low 12 bits - these decrease the returned value by
2007 * multiplying by a number less than 1 if the bit is set. The multiplier
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002008 * is determined by the above table and the shift. Notice that the values
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002009 * converge on 45426 and this is used to allow linear interpolation of the
2010 * low bits.
2011 */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05002012 if (x & 0x800)
2013 e -= (((e >> 16) * 44938U) + 16U) >> 5;
2014
2015 if (x & 0x400)
2016 e -= (((e >> 16) * 45181U) + 32U) >> 6;
2017
2018 if (x & 0x200)
2019 e -= (((e >> 16) * 45303U) + 64U) >> 7;
2020
2021 if (x & 0x100)
2022 e -= (((e >> 16) * 45365U) + 128U) >> 8;
2023
2024 if (x & 0x080)
2025 e -= (((e >> 16) * 45395U) + 256U) >> 9;
2026
2027 if (x & 0x040)
2028 e -= (((e >> 16) * 45410U) + 512U) >> 10;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002029
2030 /* And handle the low 6 bits in a single block. */
2031 e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9;
2032
2033 /* Handle the upper bits of x. */
2034 e >>= x >> 16;
2035 return e;
2036 }
2037
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002038 /* Check for overflow */
2039 if (x <= 0)
2040 return png_32bit_exp[0];
2041
2042 /* Else underflow */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002043 return 0;
2044}
2045
2046static png_byte
John Bowler168a4332011-01-16 19:32:22 -06002047png_exp8bit(png_fixed_point lg2)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002048{
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002049 /* Get a 32-bit value: */
John Bowler168a4332011-01-16 19:32:22 -06002050 png_uint_32 x = png_exp(lg2);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002051
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002052 /* Convert the 32-bit value to 0..255 by multiplying by 256-1, note that the
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002053 * second, rounding, step can't overflow because of the first, subtraction,
2054 * step.
2055 */
2056 x -= x >> 8;
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002057 return (png_byte)((x + 0x7fffffU) >> 24);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002058}
2059
2060static png_uint_16
John Bowler168a4332011-01-16 19:32:22 -06002061png_exp16bit(png_fixed_point lg2)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002062{
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002063 /* Get a 32-bit value: */
John Bowler168a4332011-01-16 19:32:22 -06002064 png_uint_32 x = png_exp(lg2);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002065
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002066 /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002067 x -= x >> 16;
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002068 return (png_uint_16)((x + 32767U) >> 16);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002069}
2070#endif /* FLOATING_ARITHMETIC */
2071
2072png_byte
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002073png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002074{
2075 if (value > 0 && value < 255)
2076 {
2077# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002078 double r = floor(255*pow(value/255.,gamma_val*.00001)+.5);
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002079 return (png_byte)r;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002080# else
John Bowler168a4332011-01-16 19:32:22 -06002081 png_int_32 lg2 = png_log8bit(value);
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002082 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002083
John Bowler168a4332011-01-16 19:32:22 -06002084 if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1))
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002085 return png_exp8bit(res);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002086
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05002087 /* Overflow. */
2088 value = 0;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002089# endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002090 }
2091
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002092 return (png_byte)value;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002093}
2094
2095png_uint_16
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002096png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002097{
2098 if (value > 0 && value < 65535)
2099 {
2100# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002101 double r = floor(65535*pow(value/65535.,gamma_val*.00001)+.5);
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002102 return (png_uint_16)r;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002103# else
John Bowler168a4332011-01-16 19:32:22 -06002104 png_int_32 lg2 = png_log16bit(value);
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002105 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002106
John Bowler168a4332011-01-16 19:32:22 -06002107 if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1))
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002108 return png_exp16bit(res);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002109
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05002110 /* Overflow. */
2111 value = 0;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002112# endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002113 }
2114
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002115 return (png_uint_16)value;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002116}
2117
2118/* This does the right thing based on the bit_depth field of the
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002119 * png_struct, interpreting values as 8-bit or 16-bit. While the result
2120 * is nominally a 16-bit value if bit depth is 8 then the result is
2121 * 8-bit (as are the arguments.)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002122 */
2123png_uint_16 /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002124png_gamma_correct(png_structp png_ptr, unsigned int value,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002125 png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002126{
2127 if (png_ptr->bit_depth == 8)
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002128 return png_gamma_8bit_correct(value, gamma_val);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002129
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002130 else
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002131 return png_gamma_16bit_correct(value, gamma_val);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002132}
2133
2134/* This is the shared test on whether a gamma value is 'significant' - whether
2135 * it is worth doing gamma correction.
2136 */
2137int /* PRIVATE */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002138png_gamma_significant(png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002139{
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002140 return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED ||
2141 gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002142}
2143
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002144/* Internal function to build a single 16-bit table - the table consists of
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002145 * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount
2146 * to shift the input values right (or 16-number_of_signifiant_bits).
2147 *
Glenn Randers-Pehrsona774c5d2010-08-26 19:37:55 -05002148 * The caller is responsible for ensuring that the table gets cleaned up on
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002149 * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument
2150 * should be somewhere that will be cleaned.
2151 */
2152static void
2153png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002154 PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002155{
2156 /* Various values derived from 'shift': */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002157 PNG_CONST unsigned int num = 1U << (8U - shift);
2158 PNG_CONST unsigned int max = (1U << (16U - shift))-1U;
2159 PNG_CONST unsigned int max_by_2 = 1U << (15U-shift);
2160 unsigned int i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002161
2162 png_uint_16pp table = *ptable =
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002163 (png_uint_16pp)png_calloc(png_ptr, num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002164
2165 for (i = 0; i < num; i++)
2166 {
2167 png_uint_16p sub_table = table[i] =
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002168 (png_uint_16p)png_malloc(png_ptr, 256 * png_sizeof(png_uint_16));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002169
2170 /* The 'threshold' test is repeated here because it can arise for one of
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002171 * the 16-bit tables even if the others don't hit it.
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002172 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002173 if (png_gamma_significant(gamma_val))
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002174 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002175 /* The old code would overflow at the end and this would cause the
2176 * 'pow' function to return a result >1, resulting in an
2177 * arithmetic error. This code follows the spec exactly; ig is
2178 * the recovered input sample, it always has 8-16 bits.
2179 *
2180 * We want input * 65535/max, rounded, the arithmetic fits in 32
2181 * bits (unsigned) so long as max <= 32767.
2182 */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002183 unsigned int j;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002184 for (j = 0; j < 256; j++)
2185 {
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002186 png_uint_32 ig = (j << (8-shift)) + i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002187# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002188 /* Inline the 'max' scaling operation: */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002189 double d = floor(65535*pow(ig/(double)max, gamma_val*.00001)+.5);
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002190 sub_table[j] = (png_uint_16)d;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002191# else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002192 if (shift)
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05002193 ig = (ig * 65535U + max_by_2)/max;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002194
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002195 sub_table[j] = png_gamma_16bit_correct(ig, gamma_val);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002196# endif
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002197 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002198 }
2199 else
2200 {
2201 /* We must still build a table, but do it the fast way. */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002202 unsigned int j;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002203
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002204 for (j = 0; j < 256; j++)
2205 {
2206 png_uint_32 ig = (j << (8-shift)) + i;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002207
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002208 if (shift)
2209 ig = (ig * 65535U + max_by_2)/max;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002210
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002211 sub_table[j] = (png_uint_16)ig;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002212 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002213 }
2214 }
2215}
2216
2217/* NOTE: this function expects the *inverse* of the overall gamma transformation
2218 * required.
2219 */
2220static void
2221png_build_16to8_table(png_structp png_ptr, png_uint_16pp *ptable,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002222 PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002223{
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002224 PNG_CONST unsigned int num = 1U << (8U - shift);
2225 PNG_CONST unsigned int max = (1U << (16U - shift))-1U;
2226 unsigned int i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002227 png_uint_32 last;
2228
2229 png_uint_16pp table = *ptable =
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002230 (png_uint_16pp)png_calloc(png_ptr, num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002231
2232 /* 'num' is the number of tables and also the number of low bits of low
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002233 * bits of the input 16-bit value used to select a table. Each table is
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002234 * itself index by the high 8 bits of the value.
2235 */
2236 for (i = 0; i < num; i++)
2237 table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002238 256 * png_sizeof(png_uint_16));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002239
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002240 /* 'gamma_val' is set to the reciprocal of the value calculated above, so
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002241 * pow(out,g) is an *input* value. 'last' is the last input value set.
2242 *
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002243 * In the loop 'i' is used to find output values. Since the output is
2244 * 8-bit there are only 256 possible values. The tables are set up to
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002245 * select the closest possible output value for each input by finding
2246 * the input value at the boundary between each pair of output values
2247 * and filling the table up to that boundary with the lower output
2248 * value.
2249 *
Glenn Randers-Pehrson8a7ec522011-05-17 07:14:30 -05002250 * 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 -05002251 * values the code below uses a 16-bit value in i; the values start at
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002252 * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last
2253 * entries are filled with 255). Start i at 128 and fill all 'last'
2254 * table entries <= 'max'
2255 */
2256 last = 0;
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002257 for (i = 0; i < 255; ++i) /* 8-bit output value */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002258 {
2259 /* Find the corresponding maximum input value */
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002260 png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002261
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002262 /* Find the boundary value in 16 bits: */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002263 png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002264
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002265 /* Adjust (round) to (16-shift) bits: */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002266 bound = (bound * max + 32768U)/65535U + 1U;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002267
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002268 while (last < bound)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002269 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002270 table[last & (0xffU >> shift)][last >> (8U - shift)] = out;
2271 last++;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002272 }
2273 }
2274
2275 /* And fill in the final entries. */
2276 while (last < (num << 8))
2277 {
2278 table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U;
2279 last++;
2280 }
2281}
2282
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002283/* Build a single 8-bit table: same as the 16-bit case but much simpler (and
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002284 * typically much faster). Note that libpng currently does no sBIT processing
2285 * (apparently contrary to the spec) so a 256 entry table is always generated.
2286 */
2287static void
2288png_build_8bit_table(png_structp png_ptr, png_bytepp ptable,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002289 PNG_CONST png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002290{
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002291 unsigned int i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002292 png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256);
2293
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002294 if (png_gamma_significant(gamma_val)) for (i=0; i<256; i++)
2295 table[i] = png_gamma_8bit_correct(i, gamma_val);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002296
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002297 else for (i=0; i<256; ++i)
2298 table[i] = (png_byte)i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002299}
2300
2301/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
2302 * tables, we don't make a full table if we are reducing to 8-bit in
2303 * the future. Note also how the gamma_16 tables are segmented so that
2304 * we don't need to allocate > 64K chunks for a full 16-bit table.
2305 */
2306void /* PRIVATE */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002307png_build_gamma_table(png_structp png_ptr, int bit_depth)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002308{
2309 png_debug(1, "in png_build_gamma_table");
2310
2311 if (bit_depth <= 8)
2312 {
2313 png_build_8bit_table(png_ptr, &png_ptr->gamma_table,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002314 png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->gamma,
2315 png_ptr->screen_gamma) : PNG_FP_1);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002316
2317#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
John Bowlerd273ad22011-05-07 21:00:28 -05002318 defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002319 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
John Bowlerd273ad22011-05-07 21:00:28 -05002320 if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY))
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002321 {
2322 png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002323 png_reciprocal(png_ptr->gamma));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002324
2325 png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002326 png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
2327 png_ptr->gamma/* Probably doing rgb_to_gray */);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002328 }
John Bowlerd273ad22011-05-07 21:00:28 -05002329#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002330 }
2331 else
2332 {
2333 png_byte shift, sig_bit;
2334
2335 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
2336 {
2337 sig_bit = png_ptr->sig_bit.red;
2338
2339 if (png_ptr->sig_bit.green > sig_bit)
2340 sig_bit = png_ptr->sig_bit.green;
2341
2342 if (png_ptr->sig_bit.blue > sig_bit)
2343 sig_bit = png_ptr->sig_bit.blue;
2344 }
2345 else
2346 sig_bit = png_ptr->sig_bit.gray;
2347
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002348 /* 16-bit gamma code uses this equation:
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002349 *
2350 * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8]
2351 *
2352 * Where 'iv' is the input color value and 'ov' is the output value -
2353 * pow(iv, gamma).
2354 *
2355 * Thus the gamma table consists of up to 256 256 entry tables. The table
2356 * is selected by the (8-gamma_shift) most significant of the low 8 bits of
2357 * the color value then indexed by the upper 8 bits:
2358 *
2359 * table[low bits][high 8 bits]
2360 *
2361 * So the table 'n' corresponds to all those 'iv' of:
2362 *
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002363 * <all high 8-bit values><n << gamma_shift>..<(n+1 << gamma_shift)-1>
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002364 *
2365 */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002366 if (sig_bit > 0 && sig_bit < 16U)
2367 shift = (png_byte)(16U - sig_bit); /* shift == insignificant bits */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002368
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002369 else
2370 shift = 0; /* keep all 16 bits */
2371
Glenn Randers-Pehrsonab63dd02011-06-17 20:04:17 -05002372 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8))
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002373 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002374 /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively
2375 * the significant bits in the *input* when the output will
2376 * eventually be 8 bits. By default it is 11.
2377 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002378 if (shift < (16U - PNG_MAX_GAMMA_8))
2379 shift = (16U - PNG_MAX_GAMMA_8);
2380 }
2381
2382 if (shift > 8U)
2383 shift = 8U; /* Guarantees at least one table! */
2384
2385 png_ptr->gamma_shift = shift;
2386
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002387#ifdef PNG_16BIT_SUPPORTED
Glenn Randers-Pehrsonef217b72011-06-15 12:58:27 -05002388 /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now
John Bowlerd273ad22011-05-07 21:00:28 -05002389 * PNG_COMPOSE). This effectively smashed the background calculation for
Glenn Randers-Pehrson55fbff32011-05-17 06:49:32 -05002390 * 16-bit output because the 8-bit table assumes the result will be reduced
John Bowlerd273ad22011-05-07 21:00:28 -05002391 * to 8 bits.
2392 */
Glenn Randers-Pehrsonab63dd02011-06-17 20:04:17 -05002393 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8))
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002394#endif
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002395 png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,
2396 png_ptr->screen_gamma > 0 ? png_product2(png_ptr->gamma,
2397 png_ptr->screen_gamma) : PNG_FP_1);
2398
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002399#ifdef PNG_16BIT_SUPPORTED
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002400 else
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002401 png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,
2402 png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->gamma,
2403 png_ptr->screen_gamma) : PNG_FP_1);
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002404#endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002405
2406#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
John Bowlerd273ad22011-05-07 21:00:28 -05002407 defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002408 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
John Bowlerd273ad22011-05-07 21:00:28 -05002409 if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY))
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002410 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002411 png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002412 png_reciprocal(png_ptr->gamma));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002413
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002414 /* Notice that the '16 from 1' table should be full precision, however
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002415 * the lookup on this table still uses gamma_shift, so it can't be.
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002416 * TODO: fix this.
2417 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002418 png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002419 png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
2420 png_ptr->gamma/* Probably doing rgb_to_gray */);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002421 }
John Bowlerd273ad22011-05-07 21:00:28 -05002422#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002423 }
2424}
2425#endif /* READ_GAMMA */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002426#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */