blob: 5d0f41e4971c6fc45d0c604ae42f06b2ab5e5012 [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-Pehrson9c690912010-08-27 11:39:38 -05004 * Last changed in libpng 1.5.0 [August 27, 2010]
Glenn Randers-Pehrsone69b55d2010-01-01 10:29:06 -06005 * Copyright (c) 1998-2010 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-Pehrsonbe6f0c22010-08-26 07:09:33 -050017typedef version_1_5_0beta46 Your_png_h_is_not_version_1_5_0beta46;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -060018
Andreas Dilger47a0c421997-05-16 02:46:07 -050019/* Version information for C files. This had better match the version
Glenn Randers-Pehrson5ade7ed2009-09-30 15:11:49 -050020 * string defined in png.h.
21 */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -060022
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060023/* Tells libpng that we have already handled the first "num_bytes" bytes
24 * of the PNG file signature. If the PNG data is embedded into another
25 * stream we can set num_bytes = 8 so that libpng will not attempt to read
26 * or write any of the magic bytes before it starts on the IHDR.
27 */
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -050028
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060029#ifdef PNG_READ_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050030void PNGAPI
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060031png_set_sig_bytes(png_structp png_ptr, int num_bytes)
32{
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -050033 png_debug(1, "in png_set_sig_bytes");
34
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050035 if (png_ptr == NULL)
36 return;
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -050037
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060038 if (num_bytes > 8)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050039 png_error(png_ptr, "Too many bytes for PNG signature");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060040
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -050041 png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060042}
43
44/* Checks whether the supplied bytes match the PNG signature. We allow
45 * checking less than the full 8-byte signature so that those apps that
46 * already read the first few bytes of a file to determine the file type
47 * can simply check the remaining bytes for extra assurance. Returns
48 * an integer less than, equal to, or greater than zero if sig is found,
49 * respectively, to be less than, to match, or be greater than the correct
50 * PNG signature (this is the same behaviour as strcmp, memcmp, etc).
51 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050052int PNGAPI
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -050053png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060054{
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -060055 png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -050056
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060057 if (num_to_check > 8)
58 num_to_check = 8;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -050059
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060060 else if (num_to_check < 1)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060061 return (-1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060062
Andreas Dilger47a0c421997-05-16 02:46:07 -050063 if (start > 7)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060064 return (-1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060065
66 if (start + num_to_check > 8)
67 num_to_check = 8 - start;
68
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050069 return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check)));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060070}
71
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060072#endif /* PNG_READ_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -050073
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060074#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050075/* Function to allocate memory for zlib and clear it to 0. */
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -050076PNG_FUNCTION(voidpf /* PRIVATE */,
77png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)
Guy Schalnat0d580581995-07-20 02:43:20 -050078{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050079 png_voidp ptr;
80 png_structp p=(png_structp)png_ptr;
81 png_uint_32 save_flags=p->flags;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050082 png_alloc_size_t num_bytes;
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050083
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050084 if (png_ptr == NULL)
85 return (NULL);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -050086
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050087 if (items > PNG_UINT_32_MAX/size)
88 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050089 png_warning (p, "Potential overflow in png_zalloc()");
90 return (NULL);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050091 }
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050092 num_bytes = (png_alloc_size_t)items * size;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -060093
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050094 p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK;
95 ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes);
96 p->flags=save_flags;
Guy Schalnat6d764711995-12-19 03:22:19 -060097
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050098 return ((voidpf)ptr);
99}
100
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500101/* Function to free memory for zlib */
Glenn Randers-Pehrson3f705ba2009-07-23 12:53:06 -0500102void /* PRIVATE */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500103png_zfree(voidpf png_ptr, voidpf ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500104{
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600105 png_free((png_structp)png_ptr, (png_voidp)ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500106}
107
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600108/* Reset the CRC variable to 32 bits of 1's. Care must be taken
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600109 * in case CRC is > 32 bits to leave the top bits 0.
110 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500111void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -0600112png_reset_crc(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500113{
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600114 png_ptr->crc = crc32(0, Z_NULL, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500115}
116
Andreas Dilger47a0c421997-05-16 02:46:07 -0500117/* Calculate the CRC over a section of data. We can only pass as
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600118 * much data to this routine as the largest single buffer size. We
119 * also check that this data will actually be used before going to the
120 * trouble of calculating it.
121 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500122void /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500123png_calculate_crc(png_structp png_ptr, png_const_bytep ptr, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500124{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500125 int need_crc = 1;
126
127 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
128 {
129 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
130 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
131 need_crc = 0;
132 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500133
Andreas Dilger47a0c421997-05-16 02:46:07 -0500134 else /* critical */
135 {
136 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
137 need_crc = 0;
138 }
139
140 if (need_crc)
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600141 png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500142}
Guy Schalnate5a37791996-06-05 15:50:50 -0500143
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600144/* Allocate the memory for an info_struct for the application. We don't
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600145 * really need the png_ptr, but it could potentially be useful in the
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500146 * future. This should be used in favour of malloc(png_sizeof(png_info))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600147 * and png_info_init() so that applications that want to use a shared
148 * libpng don't have to be recompiled if png_info changes size.
149 */
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -0500150PNG_FUNCTION(png_infop,PNGAPI
151png_create_info_struct,(png_structp png_ptr),PNG_ALLOCATED)
Guy Schalnate5a37791996-06-05 15:50:50 -0500152{
153 png_infop info_ptr;
154
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500155 png_debug(1, "in png_create_info_struct");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500156
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500157 if (png_ptr == NULL)
158 return (NULL);
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500159
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500160#ifdef PNG_USER_MEM_SUPPORTED
Glenn Randers-Pehrson5cded0b2001-11-07 07:10:08 -0600161 info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO,
162 png_ptr->malloc_fn, png_ptr->mem_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500163#else
Glenn Randers-Pehrson5cded0b2001-11-07 07:10:08 -0600164 info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500165#endif
Glenn Randers-Pehrson5cded0b2001-11-07 07:10:08 -0600166 if (info_ptr != NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500167 png_info_init_3(&info_ptr, png_sizeof(png_info));
Guy Schalnate5a37791996-06-05 15:50:50 -0500168
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600169 return (info_ptr);
Guy Schalnate5a37791996-06-05 15:50:50 -0500170}
171
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600172/* This function frees the memory associated with a single info struct.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600173 * Normally, one would use either png_destroy_read_struct() or
174 * png_destroy_write_struct() to free an info struct, but this may be
175 * useful for some applications.
176 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500177void PNGAPI
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600178png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr)
179{
180 png_infop info_ptr = NULL;
181
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500182 png_debug(1, "in png_destroy_info_struct");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500183
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500184 if (png_ptr == NULL)
185 return;
186
Andreas Dilger47a0c421997-05-16 02:46:07 -0500187 if (info_ptr_ptr != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600188 info_ptr = *info_ptr_ptr;
189
Andreas Dilger47a0c421997-05-16 02:46:07 -0500190 if (info_ptr != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600191 {
192 png_info_destroy(png_ptr, info_ptr);
193
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500194#ifdef PNG_USER_MEM_SUPPORTED
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500195 png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn,
196 png_ptr->mem_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500197#else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600198 png_destroy_struct((png_voidp)info_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500199#endif
Glenn Randers-Pehrson3f549252001-10-27 07:35:13 -0500200 *info_ptr_ptr = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600201 }
202}
203
204/* Initialize the info structure. This is now an internal function (0.89)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600205 * and applications using it are urged to use png_create_info_struct()
206 * instead.
207 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500208
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500209void PNGAPI
210png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size)
211{
212 png_infop info_ptr = *ptr_ptr;
213
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500214 png_debug(1, "in png_info_init_3");
215
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500216 if (info_ptr == NULL)
217 return;
Glenn Randers-Pehrson6b12c082006-11-14 10:53:30 -0600218
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500219 if (png_sizeof(png_info) > png_info_struct_size)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500220 {
221 png_destroy_struct(info_ptr);
222 info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
223 *ptr_ptr = info_ptr;
224 }
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500225
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500226 /* Set everything to 0 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500227 png_memset(info_ptr, 0, png_sizeof(png_info));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600228}
229
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500230void PNGAPI
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500231png_data_freer(png_structp png_ptr, png_infop info_ptr,
232 int freer, png_uint_32 mask)
233{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500234 png_debug(1, "in png_data_freer");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500235
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500236 if (png_ptr == NULL || info_ptr == NULL)
237 return;
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500238
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500239 if (freer == PNG_DESTROY_WILL_FREE_DATA)
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500240 info_ptr->free_me |= mask;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500241
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500242 else if (freer == PNG_USER_WILL_FREE_DATA)
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500243 info_ptr->free_me &= ~mask;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500244
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500245 else
246 png_warning(png_ptr,
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500247 "Unknown freer parameter in png_data_freer");
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500248}
249
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500250void PNGAPI
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500251png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
252 int num)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600253{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500254 png_debug(1, "in png_free_data");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500255
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600256 if (png_ptr == NULL || info_ptr == NULL)
257 return;
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600258
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500259#ifdef PNG_TEXT_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500260 /* Free text item num or (if num == -1) all text items */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500261 if ((mask & PNG_FREE_TEXT) & info_ptr->free_me)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600262 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500263 if (num != -1)
264 {
265 if (info_ptr->text && info_ptr->text[num].key)
266 {
267 png_free(png_ptr, info_ptr->text[num].key);
268 info_ptr->text[num].key = NULL;
269 }
270 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500271
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500272 else
273 {
274 int i;
275 for (i = 0; i < info_ptr->num_text; i++)
276 png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i);
277 png_free(png_ptr, info_ptr->text);
278 info_ptr->text = NULL;
279 info_ptr->num_text=0;
280 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600281 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600282#endif
283
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500284#ifdef PNG_tRNS_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500285 /* Free any tRNS entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500286 if ((mask & PNG_FREE_TRNS) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500287 {
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -0500288 png_free(png_ptr, info_ptr->trans_alpha);
289 info_ptr->trans_alpha = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500290 info_ptr->valid &= ~PNG_INFO_tRNS;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500291 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600292#endif
293
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500294#ifdef PNG_sCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500295 /* Free any sCAL entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500296 if ((mask & PNG_FREE_SCAL) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500297 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600298#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500299 png_free(png_ptr, info_ptr->scal_s_width);
300 png_free(png_ptr, info_ptr->scal_s_height);
301 info_ptr->scal_s_width = NULL;
302 info_ptr->scal_s_height = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600303#endif
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500304 info_ptr->valid &= ~PNG_INFO_sCAL;
305 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600306#endif
307
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500308#ifdef PNG_pCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500309 /* Free any pCAL entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500310 if ((mask & PNG_FREE_PCAL) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500311 {
312 png_free(png_ptr, info_ptr->pcal_purpose);
313 png_free(png_ptr, info_ptr->pcal_units);
314 info_ptr->pcal_purpose = NULL;
315 info_ptr->pcal_units = NULL;
316 if (info_ptr->pcal_params != NULL)
317 {
318 int i;
319 for (i = 0; i < (int)info_ptr->pcal_nparams; i++)
320 {
321 png_free(png_ptr, info_ptr->pcal_params[i]);
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600322 info_ptr->pcal_params[i] = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500323 }
324 png_free(png_ptr, info_ptr->pcal_params);
325 info_ptr->pcal_params = NULL;
326 }
327 info_ptr->valid &= ~PNG_INFO_pCAL;
328 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600329#endif
330
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500331#ifdef PNG_iCCP_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500332 /* Free any iCCP entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500333 if ((mask & PNG_FREE_ICCP) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500334 {
335 png_free(png_ptr, info_ptr->iccp_name);
336 png_free(png_ptr, info_ptr->iccp_profile);
337 info_ptr->iccp_name = NULL;
338 info_ptr->iccp_profile = NULL;
339 info_ptr->valid &= ~PNG_INFO_iCCP;
340 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600341#endif
342
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500343#ifdef PNG_sPLT_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500344 /* Free a given sPLT entry, or (if num == -1) all sPLT entries */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500345 if ((mask & PNG_FREE_SPLT) & info_ptr->free_me)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600346 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500347 if (num != -1)
Glenn Randers-Pehrsonfc4a1432000-05-17 17:39:34 -0500348 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500349 if (info_ptr->splt_palettes)
350 {
351 png_free(png_ptr, info_ptr->splt_palettes[num].name);
352 png_free(png_ptr, info_ptr->splt_palettes[num].entries);
353 info_ptr->splt_palettes[num].name = NULL;
354 info_ptr->splt_palettes[num].entries = NULL;
355 }
356 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500357
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500358 else
359 {
360 if (info_ptr->splt_palettes_num)
361 {
362 int i;
363 for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
364 png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i);
365
366 png_free(png_ptr, info_ptr->splt_palettes);
367 info_ptr->splt_palettes = NULL;
368 info_ptr->splt_palettes_num = 0;
369 }
370 info_ptr->valid &= ~PNG_INFO_sPLT;
Glenn Randers-Pehrsonfc4a1432000-05-17 17:39:34 -0500371 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600372 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600373#endif
374
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500375#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500376 if (png_ptr->unknown_chunk.data)
377 {
378 png_free(png_ptr, png_ptr->unknown_chunk.data);
379 png_ptr->unknown_chunk.data = NULL;
380 }
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500381
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500382 if ((mask & PNG_FREE_UNKN) & info_ptr->free_me)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600383 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500384 if (num != -1)
385 {
386 if (info_ptr->unknown_chunks)
387 {
388 png_free(png_ptr, info_ptr->unknown_chunks[num].data);
389 info_ptr->unknown_chunks[num].data = NULL;
390 }
391 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500392
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500393 else
394 {
395 int i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600396
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500397 if (info_ptr->unknown_chunks_num)
398 {
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -0500399 for (i = 0; i < info_ptr->unknown_chunks_num; i++)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500400 png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600401
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500402 png_free(png_ptr, info_ptr->unknown_chunks);
403 info_ptr->unknown_chunks = NULL;
404 info_ptr->unknown_chunks_num = 0;
405 }
406 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600407 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600408#endif
409
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500410#ifdef PNG_hIST_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500411 /* Free any hIST entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500412 if ((mask & PNG_FREE_HIST) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500413 {
414 png_free(png_ptr, info_ptr->hist);
415 info_ptr->hist = NULL;
416 info_ptr->valid &= ~PNG_INFO_hIST;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500417 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600418#endif
419
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500420 /* Free any PLTE entry that was internally allocated */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500421 if ((mask & PNG_FREE_PLTE) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500422 {
423 png_zfree(png_ptr, info_ptr->palette);
424 info_ptr->palette = NULL;
425 info_ptr->valid &= ~PNG_INFO_PLTE;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500426 info_ptr->num_palette = 0;
427 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600428
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500429#ifdef PNG_INFO_IMAGE_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500430 /* Free any image bits attached to the info structure */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500431 if ((mask & PNG_FREE_ROWS) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500432 {
433 if (info_ptr->row_pointers)
434 {
435 int row;
436 for (row = 0; row < (int)info_ptr->height; row++)
437 {
438 png_free(png_ptr, info_ptr->row_pointers[row]);
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600439 info_ptr->row_pointers[row] = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500440 }
441 png_free(png_ptr, info_ptr->row_pointers);
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600442 info_ptr->row_pointers = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500443 }
444 info_ptr->valid &= ~PNG_INFO_IDAT;
445 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600446#endif
Glenn Randers-Pehrsonfc4a1432000-05-17 17:39:34 -0500447
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500448 if (num == -1)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500449 info_ptr->free_me &= ~mask;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500450
Glenn Randers-Pehrsonec61c232000-05-16 06:17:36 -0500451 else
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500452 info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL);
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600453}
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600454
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600455/* This is an internal routine to free any memory that the info struct is
Andreas Dilger47a0c421997-05-16 02:46:07 -0500456 * pointing to before re-using it or freeing the struct itself. Recall
457 * that png_free() checks for NULL pointers for us.
458 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500459void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600460png_info_destroy(png_structp png_ptr, png_infop info_ptr)
461{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500462 png_debug(1, "in png_info_destroy");
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600463
464 png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
Glenn Randers-Pehrsond56aca72000-11-23 11:51:42 -0600465
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500466#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600467 if (png_ptr->num_chunk_list)
468 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500469 png_free(png_ptr, png_ptr->chunk_list);
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600470 png_ptr->chunk_list = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500471 png_ptr->num_chunk_list = 0;
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600472 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600473#endif
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600474
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500475 png_info_init_3(&info_ptr, png_sizeof(png_info));
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500476}
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600477#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500478
Guy Schalnate5a37791996-06-05 15:50:50 -0500479/* This function returns a pointer to the io_ptr associated with the user
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600480 * functions. The application should free any memory associated with this
481 * pointer before png_write_destroy() or png_read_destroy() are called.
482 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500483png_voidp PNGAPI
Guy Schalnate5a37791996-06-05 15:50:50 -0500484png_get_io_ptr(png_structp png_ptr)
485{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500486 if (png_ptr == NULL)
487 return (NULL);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500488
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600489 return (png_ptr->io_ptr);
Guy Schalnate5a37791996-06-05 15:50:50 -0500490}
Andreas Dilger47a0c421997-05-16 02:46:07 -0500491
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600492#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600493# ifdef PNG_STDIO_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500494/* Initialize the default input/output functions for the PNG file. If you
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600495 * use your own read or write routines, you can call either png_set_read_fn()
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500496 * or png_set_write_fn() instead of png_init_io(). If you have defined
497 * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't
498 * necessarily available.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600499 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500500void PNGAPI
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500501png_init_io(png_structp png_ptr, png_FILE_p fp)
Guy Schalnate5a37791996-06-05 15:50:50 -0500502{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500503 png_debug(1, "in png_init_io");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500504
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500505 if (png_ptr == NULL)
506 return;
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500507
Guy Schalnate5a37791996-06-05 15:50:50 -0500508 png_ptr->io_ptr = (png_voidp)fp;
509}
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600510# endif
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500511
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600512# ifdef PNG_TIME_RFC1123_SUPPORTED
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500513/* Convert the supplied time into an RFC 1123 string suitable for use in
514 * a "Creation Time" or other text-based time string.
515 */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500516png_const_charp PNGAPI
517png_convert_to_rfc1123(png_structp png_ptr, png_const_timep ptime)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500518{
519 static PNG_CONST char short_months[12][4] =
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600520 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
521 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500522
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500523 if (png_ptr == NULL)
524 return (NULL);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500525
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500526 if (png_ptr->time_buffer == NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500527 {
528 png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29*
529 png_sizeof(char)));
530 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500531
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600532# ifdef USE_FAR_KEYWORD
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500533 {
534 char near_time_buf[29];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500535 png_snprintf6(near_time_buf, 29, "%d %s %d %02d:%02d:%02d +0000",
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500536 ptime->day % 32, short_months[(ptime->month - 1) % 12],
537 ptime->year, ptime->hour % 24, ptime->minute % 60,
538 ptime->second % 61);
539 png_memcpy(png_ptr->time_buffer, near_time_buf,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500540 29*png_sizeof(char));
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500541 }
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600542# else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500543 png_snprintf6(png_ptr->time_buffer, 29, "%d %s %d %02d:%02d:%02d +0000",
Glenn Randers-Pehrsone1eff582001-04-14 20:15:41 -0500544 ptime->day % 32, short_months[(ptime->month - 1) % 12],
545 ptime->year, ptime->hour % 24, ptime->minute % 60,
546 ptime->second % 61);
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600547# endif
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500548 return png_ptr->time_buffer;
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500549}
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600550# endif /* PNG_TIME_RFC1123_SUPPORTED */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600551
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600552#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600553
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500554png_const_charp PNGAPI
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600555png_get_copyright(png_structp png_ptr)
556{
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500557 png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500558#ifdef PNG_STRING_COPYRIGHT
559 return PNG_STRING_COPYRIGHT
560#else
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600561# ifdef __STDC__
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500562 return PNG_STRING_NEWLINE \
Glenn Randers-Pehrson9c690912010-08-27 11:39:38 -0500563 "libpng version 1.5.0beta46 - August 27, 2010" PNG_STRING_NEWLINE \
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600564 "Copyright (c) 1998-2010 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \
Glenn Randers-Pehrson43aaf6e2008-08-05 22:17:03 -0500565 "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
566 "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500567 PNG_STRING_NEWLINE;
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600568# else
Glenn Randers-Pehrson9c690912010-08-27 11:39:38 -0500569 return "libpng version 1.5.0beta46 - August 27, 2010\
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600570 Copyright (c) 1998-2010 Glenn Randers-Pehrson\
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500571 Copyright (c) 1996-1997 Andreas Dilger\
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500572 Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600573# endif
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500574#endif
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600575}
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -0500576
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600577/* The following return the library version as a short string in the
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500578 * format 1.0.0 through 99.99.99zz. To get the version of *.h files
579 * used with your application, print out PNG_LIBPNG_VER_STRING, which
580 * is defined in png.h.
581 * Note: now there is no difference between png_get_libpng_ver() and
582 * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard,
583 * it is guaranteed that png.c uses the correct version of png.h.
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600584 */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500585png_const_charp PNGAPI
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600586png_get_libpng_ver(png_structp png_ptr)
587{
588 /* Version of *.c files used when building libpng */
Glenn Randers-Pehrson4c8f7262010-03-16 19:30:01 -0500589 return png_get_header_ver(png_ptr);
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600590}
591
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500592png_const_charp PNGAPI
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600593png_get_header_ver(png_structp png_ptr)
594{
595 /* Version of *.h files used when building libpng */
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500596 png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500597 return PNG_LIBPNG_VER_STRING;
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600598}
599
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500600png_const_charp PNGAPI
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600601png_get_header_version(png_structp png_ptr)
602{
603 /* Returns longer string containing both version and date */
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500604 png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500605#ifdef __STDC__
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500606 return PNG_HEADER_VERSION_STRING
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600607# ifndef PNG_READ_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500608 " (NO READ SUPPORT)"
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600609# endif
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500610 PNG_STRING_NEWLINE;
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500611#else
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500612 return PNG_HEADER_VERSION_STRING;
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500613#endif
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600614}
615
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600616#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600617# ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrsonc1bfe682002-03-06 22:08:00 -0600618int PNGAPI
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500619png_handle_as_unknown(png_structp png_ptr, png_const_bytep chunk_name)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600620{
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500621 /* Check chunk_name and return "keep" value if it's on the list, else 0 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600622 int i;
623 png_bytep p;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500624 if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list<=0)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600625 return 0;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500626
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500627 p = png_ptr->chunk_list + png_ptr->num_chunk_list*5 - 5;
628 for (i = png_ptr->num_chunk_list; i; i--, p -= 5)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600629 if (!png_memcmp(chunk_name, p, 4))
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500630 return ((int)*(p + 4));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600631 return 0;
632}
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600633# endif
Glenn Randers-Pehrsonf10fa3c2010-04-29 08:25:29 -0500634#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
Glenn Randers-Pehrson228bd392000-04-23 23:14:02 -0500635
Glenn Randers-Pehrsonf10fa3c2010-04-29 08:25:29 -0500636#ifdef PNG_READ_SUPPORTED
Glenn Randers-Pehrson228bd392000-04-23 23:14:02 -0500637/* This function, added to libpng-1.0.6g, is untested. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500638int PNGAPI
Glenn Randers-Pehrson228bd392000-04-23 23:14:02 -0500639png_reset_zstream(png_structp png_ptr)
640{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500641 if (png_ptr == NULL)
642 return Z_STREAM_ERROR;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500643
Glenn Randers-Pehrson228bd392000-04-23 23:14:02 -0500644 return (inflateReset(&png_ptr->zstream));
645}
Glenn Randers-Pehrson2b8bef12010-04-29 11:50:24 -0500646#endif /* PNG_READ_SUPPORTED */
Glenn Randers-Pehrson1ef65b62000-05-12 06:19:53 -0500647
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -0600648/* This function was added to libpng-1.0.7 */
Glenn Randers-Pehrson1ef65b62000-05-12 06:19:53 -0500649png_uint_32 PNGAPI
650png_access_version_number(void)
651{
652 /* Version of *.c files used when building libpng */
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500653 return((png_uint_32) PNG_LIBPNG_VER);
Glenn Randers-Pehrson1ef65b62000-05-12 06:19:53 -0500654}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -0600655
Glenn Randers-Pehrson1fd5fb32001-05-06 05:34:26 -0500656
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500657
658#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600659# ifdef PNG_SIZE_T
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500660/* Added at libpng version 1.2.6 */
661 PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size));
662png_size_t PNGAPI
663png_convert_size(size_t size)
Glenn Randers-Pehrson1fd5fb32001-05-06 05:34:26 -0500664{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500665 if (size > (png_size_t)-1)
666 PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500667
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500668 return ((png_size_t)size);
Glenn Randers-Pehrson1fd5fb32001-05-06 05:34:26 -0500669}
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600670# endif /* PNG_SIZE_T */
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600671
Glenn Randers-Pehrson02a5e332008-11-24 22:10:23 -0600672/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500673# ifdef PNG_CHECK_cHRM_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500674
Glenn Randers-Pehrson3f705ba2009-07-23 12:53:06 -0500675int /* PRIVATE */
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600676png_check_cHRM_fixed(png_structp png_ptr,
677 png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x,
678 png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y,
679 png_fixed_point blue_x, png_fixed_point blue_y)
680{
681 int ret = 1;
Glenn Randers-Pehrsond0c40592008-11-22 07:09:51 -0600682 unsigned long xy_hi,xy_lo,yx_hi,yx_lo;
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600683
684 png_debug(1, "in function png_check_cHRM_fixed");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500685
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600686 if (png_ptr == NULL)
687 return 0;
688
Glenn Randers-Pehrson02a5e332008-11-24 22:10:23 -0600689 if (white_x < 0 || white_y <= 0 ||
690 red_x < 0 || red_y < 0 ||
691 green_x < 0 || green_y < 0 ||
692 blue_x < 0 || blue_y < 0)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600693 {
694 png_warning(png_ptr,
695 "Ignoring attempt to set negative chromaticity value");
696 ret = 0;
697 }
698 if (white_x > (png_fixed_point) PNG_UINT_31_MAX ||
699 white_y > (png_fixed_point) PNG_UINT_31_MAX ||
700 red_x > (png_fixed_point) PNG_UINT_31_MAX ||
701 red_y > (png_fixed_point) PNG_UINT_31_MAX ||
702 green_x > (png_fixed_point) PNG_UINT_31_MAX ||
703 green_y > (png_fixed_point) PNG_UINT_31_MAX ||
704 blue_x > (png_fixed_point) PNG_UINT_31_MAX ||
705 blue_y > (png_fixed_point) PNG_UINT_31_MAX )
706 {
707 png_warning(png_ptr,
708 "Ignoring attempt to set chromaticity value exceeding 21474.83");
709 ret = 0;
710 }
Glenn Randers-Pehrson71a3c1f2008-11-26 12:00:38 -0600711 if (white_x > 100000L - white_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600712 {
713 png_warning(png_ptr, "Invalid cHRM white point");
714 ret = 0;
715 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500716
Glenn Randers-Pehrson71a3c1f2008-11-26 12:00:38 -0600717 if (red_x > 100000L - red_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600718 {
719 png_warning(png_ptr, "Invalid cHRM red point");
720 ret = 0;
721 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500722
Glenn Randers-Pehrson71a3c1f2008-11-26 12:00:38 -0600723 if (green_x > 100000L - green_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600724 {
725 png_warning(png_ptr, "Invalid cHRM green point");
726 ret = 0;
727 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500728
Glenn Randers-Pehrson71a3c1f2008-11-26 12:00:38 -0600729 if (blue_x > 100000L - blue_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600730 {
731 png_warning(png_ptr, "Invalid cHRM blue point");
732 ret = 0;
733 }
Glenn Randers-Pehrsond0c40592008-11-22 07:09:51 -0600734
735 png_64bit_product(green_x - red_x, blue_y - red_y, &xy_hi, &xy_lo);
736 png_64bit_product(green_y - red_y, blue_x - red_x, &yx_hi, &yx_lo);
737
738 if (xy_hi == yx_hi && xy_lo == yx_lo)
739 {
740 png_warning(png_ptr,
741 "Ignoring attempt to set cHRM RGB triangle with zero area");
742 ret = 0;
743 }
744
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600745 return ret;
746}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500747# endif /* PNG_CHECK_cHRM_SUPPORTED */
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500748
749void /* PRIVATE */
750png_check_IHDR(png_structp png_ptr,
751 png_uint_32 width, png_uint_32 height, int bit_depth,
752 int color_type, int interlace_type, int compression_type,
753 int filter_type)
754{
755 int error = 0;
756
757 /* Check for width and height valid values */
758 if (width == 0)
759 {
760 png_warning(png_ptr, "Image width is zero in IHDR");
761 error = 1;
762 }
763
764 if (height == 0)
765 {
766 png_warning(png_ptr, "Image height is zero in IHDR");
767 error = 1;
768 }
769
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600770# ifdef PNG_SET_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500771 if (width > png_ptr->user_width_max || width > PNG_USER_WIDTH_MAX)
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500772
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600773# else
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500774 if (width > PNG_USER_WIDTH_MAX)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600775# endif
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500776 {
777 png_warning(png_ptr, "Image width exceeds user limit in IHDR");
778 error = 1;
779 }
780
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600781# ifdef PNG_SET_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500782 if (height > png_ptr->user_height_max || height > PNG_USER_HEIGHT_MAX)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600783# else
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500784 if (height > PNG_USER_HEIGHT_MAX)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600785# endif
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500786 {
787 png_warning(png_ptr, "Image height exceeds user limit in IHDR");
788 error = 1;
789 }
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500790
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500791 if (width > PNG_UINT_31_MAX)
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500792 {
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500793 png_warning(png_ptr, "Invalid image width in IHDR");
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500794 error = 1;
795 }
796
797 if ( height > PNG_UINT_31_MAX)
798 {
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500799 png_warning(png_ptr, "Invalid image height in IHDR");
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500800 error = 1;
801 }
802
803 if ( width > (PNG_UINT_32_MAX
804 >> 3) /* 8-byte RGBA pixels */
805 - 64 /* bigrowbuf hack */
806 - 1 /* filter byte */
807 - 7*8 /* rounding of width to multiple of 8 pixels */
808 - 8) /* extra max_pixel_depth pad */
809 png_warning(png_ptr, "Width is too large for libpng to process pixels");
810
811 /* Check other values */
812 if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
813 bit_depth != 8 && bit_depth != 16)
814 {
815 png_warning(png_ptr, "Invalid bit depth in IHDR");
816 error = 1;
817 }
818
819 if (color_type < 0 || color_type == 1 ||
820 color_type == 5 || color_type > 6)
821 {
822 png_warning(png_ptr, "Invalid color type in IHDR");
823 error = 1;
824 }
825
826 if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) ||
827 ((color_type == PNG_COLOR_TYPE_RGB ||
828 color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
829 color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
830 {
831 png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR");
832 error = 1;
833 }
834
835 if (interlace_type >= PNG_INTERLACE_LAST)
836 {
837 png_warning(png_ptr, "Unknown interlace method in IHDR");
838 error = 1;
839 }
840
841 if (compression_type != PNG_COMPRESSION_TYPE_BASE)
842 {
843 png_warning(png_ptr, "Unknown compression method in IHDR");
844 error = 1;
845 }
846
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600847# ifdef PNG_MNG_FEATURES_SUPPORTED
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500848 /* Accept filter_method 64 (intrapixel differencing) only if
849 * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
850 * 2. Libpng did not read a PNG signature (this filter_method is only
851 * used in PNG datastreams that are embedded in MNG datastreams) and
852 * 3. The application called png_permit_mng_features with a mask that
853 * included PNG_FLAG_MNG_FILTER_64 and
854 * 4. The filter_method is 64 and
855 * 5. The color_type is RGB or RGBA
856 */
857 if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) &&
858 png_ptr->mng_features_permitted)
859 png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");
860
861 if (filter_type != PNG_FILTER_TYPE_BASE)
862 {
Glenn Randers-Pehrson7ec330d2009-09-25 11:45:42 -0500863 if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500864 (filter_type == PNG_INTRAPIXEL_DIFFERENCING) &&
865 ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
866 (color_type == PNG_COLOR_TYPE_RGB ||
867 color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
Glenn Randers-Pehrson7ec330d2009-09-25 11:45:42 -0500868 {
869 png_warning(png_ptr, "Unknown filter method in IHDR");
870 error = 1;
871 }
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500872
Glenn Randers-Pehrson7ec330d2009-09-25 11:45:42 -0500873 if (png_ptr->mode & PNG_HAVE_PNG_SIGNATURE)
874 {
875 png_warning(png_ptr, "Invalid filter method in IHDR");
876 error = 1;
877 }
878 }
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500879
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600880# else
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500881 if (filter_type != PNG_FILTER_TYPE_BASE)
882 {
883 png_warning(png_ptr, "Unknown filter method in IHDR");
884 error = 1;
885 }
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600886# endif
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500887
888 if (error == 1)
889 png_error(png_ptr, "Invalid IHDR data");
890}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500891
892#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED)
893/* ASCII to fp functions */
894/* Check an ASCII formated floating point value, see the more detailed
895 * comments in pngpriv.h
896 */
897/* The following is used internally to preserve the 'valid' flag */
898#define png_fp_add(state, flags) ((state) |= (flags))
899#define png_fp_set(state, value)\
900 ((state) = (value) | ((state) & PNG_FP_WAS_VALID))
901
902/* Internal type codes: bits above the base state! */
903#define PNG_FP_SIGN 0 /* [+-] */
904#define PNG_FP_DOT 4 /* . */
905#define PNG_FP_DIGIT 8 /* [0123456789] */
906#define PNG_FP_E 12 /* [Ee] */
907
908int /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500909png_check_fp_number(png_const_charp string, png_size_t size, int *statep,
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500910 png_size_tp whereami)
911{
912 int state = *statep;
913 png_size_t i = *whereami;
914
915 while (i < size)
916 {
917 int type;
918 /* First find the type of the next character */
919 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500920 char ch = string[i];
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500921
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500922 if (ch >= 48 && ch <= 57)
923 type = PNG_FP_DIGIT;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500924
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500925 else switch (ch)
926 {
927 case 43: case 45: type = PNG_FP_SIGN; break;
928 case 46: type = PNG_FP_DOT; break;
929 case 69: case 101: type = PNG_FP_E; break;
930 default: goto PNG_FP_End;
931 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500932 }
933
934 /* Now deal with this type according to the current
935 * state, the type is arranged to not overlap the
936 * bits of the PNG_FP_STATE.
937 */
938 switch ((state & PNG_FP_STATE) + type)
939 {
940 case PNG_FP_INTEGER + PNG_FP_SIGN:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500941 if (state & PNG_FP_SAW_ANY)
942 goto PNG_FP_End; /* not a part of the number */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500943
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500944 png_fp_add(state, PNG_FP_SAW_SIGN);
945 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500946
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500947 case PNG_FP_INTEGER + PNG_FP_DOT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500948 /* Ok as trailer, ok as lead of fraction. */
949 if (state & PNG_FP_SAW_DOT) /* two dots */
950 goto PNG_FP_End;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500951
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500952 else if (state & PNG_FP_SAW_DIGIT) /* trailing dot? */
953 png_fp_add(state, PNG_FP_SAW_DOT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500954
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500955 else
956 png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500957
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500958 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500959
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500960 case PNG_FP_INTEGER + PNG_FP_DIGIT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500961 if (state & PNG_FP_SAW_DOT) /* delayed fraction */
962 png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500963
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500964 png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500965
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500966 break;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500967 case PNG_FP_INTEGER + PNG_FP_E:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500968 if ((state & PNG_FP_SAW_DIGIT) == 0)
969 goto PNG_FP_End;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500970
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500971 png_fp_set(state, PNG_FP_EXPONENT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500972
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500973 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500974
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500975 /* case PNG_FP_FRACTION + PNG_FP_SIGN:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500976 goto PNG_FP_End; ** no sign in exponent */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500977
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500978 /* case PNG_FP_FRACTION + PNG_FP_DOT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500979 goto PNG_FP_End; ** Because SAW_DOT is always set */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500980
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500981 case PNG_FP_FRACTION + PNG_FP_DIGIT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500982 png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
983 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500984
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500985 case PNG_FP_FRACTION + PNG_FP_E:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500986 /* This is correct because the trailing '.' on an
987 * integer is handled above - so we can only get here
988 * with the sequence ".E" (with no preceding digits).
989 */
990 if ((state & PNG_FP_SAW_DIGIT) == 0)
991 goto PNG_FP_End;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500992
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500993 png_fp_set(state, PNG_FP_EXPONENT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500994
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500995 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500996
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500997 case PNG_FP_EXPONENT + PNG_FP_SIGN:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500998 if (state & PNG_FP_SAW_ANY)
999 goto PNG_FP_End; /* not a part of the number */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001000
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001001 png_fp_add(state, PNG_FP_SAW_SIGN);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001002
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001003 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001004
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001005 /* case PNG_FP_EXPONENT + PNG_FP_DOT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001006 goto PNG_FP_End; */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001007
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001008 case PNG_FP_EXPONENT + PNG_FP_DIGIT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001009 png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001010
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001011 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001012
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001013 /* case PNG_FP_EXPONEXT + PNG_FP_E:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001014 goto PNG_FP_End; */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001015
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001016 default: goto PNG_FP_End; /* I.e. break 2 */
1017 }
1018
1019 /* The character seems ok, continue. */
1020 ++i;
1021 }
1022
1023PNG_FP_End:
1024 /* Here at the end, update the state and return the correct
1025 * return code.
1026 */
1027 *statep = state;
1028 *whereami = i;
1029
1030 return (state & PNG_FP_SAW_DIGIT) != 0;
1031}
1032
1033
1034/* The same but for a complete string. */
1035int
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001036png_check_fp_string(png_const_charp string, png_size_t size)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001037{
1038 int state=0;
1039 png_size_t index=0;
1040
1041 return png_check_fp_number(string, size, &state, &index) &&
1042 (index == size || string[index] == 0);
1043}
1044#endif /* pCAL or sCAL */
1045
1046#ifdef PNG_READ_sCAL_SUPPORTED
1047# ifdef PNG_FLOATING_POINT_SUPPORTED
1048/* Utility used below - a simple accurate power of ten from an integral
1049 * exponent.
1050 */
1051static double
1052png_pow10(int power)
1053{
1054 int recip = 0;
1055 double d = 1;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001056
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001057 /* Handle negative exponent with a reciprocal at the end because
1058 * 10 is exact whereas .1 is inexact in base 2
1059 */
1060 if (power < 0)
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001061 {
1062 if (power < DBL_MIN_10_EXP) return 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001063 recip = 1, power = -power;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001064 }
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001065
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001066 if (power > 0)
1067 {
1068 /* Decompose power bitwise. */
1069 double mult = 10;
1070 do
1071 {
1072 if (power & 1) d *= mult;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001073 mult *= mult;
1074 power >>= 1;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001075 }
1076 while (power > 0);
1077
1078 if (recip) d = 1/d;
1079 }
1080 /* else power is 0 and d is 1 */
1081
1082 return d;
1083}
1084
1085/* Function to format a floating point value in ASCII with a given
1086 * precision.
1087 */
1088void /* PRIVATE */
1089png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001090 double fp, unsigned int precision)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001091{
1092 /* We use standard functions from math.h, but not printf because
1093 * that would require stdio. The caller must supply a buffer of
1094 * sufficient size or we will png_error. The tests on size and
1095 * the space in ascii[] consumed are indicated below.
1096 */
1097 if (precision < 1)
1098 precision = DBL_DIG;
1099
1100 /* Enforce the limit of the implementation precision too. */
1101 if (precision > DBL_DIG+1)
1102 precision = DBL_DIG+1;
1103
1104 /* Basic sanity checks */
1105 if (size >= precision+5) /* See the requirements below. */
1106 {
1107 if (fp < 0)
1108 {
1109 fp = -fp;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001110 *ascii++ = 45; /* '-' PLUS 1 TOTAL 1*/
1111 --size;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001112 }
1113
1114 if (fp >= DBL_MIN && fp <= DBL_MAX)
1115 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001116 int exp; /* A base 10 exponent */
1117 double base; /* 10^exp */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001118
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001119 /* First extract a base 10 exponent of the number,
1120 * the calculation below rounds down when converting
1121 * from base 2 to base 10 (multiply by log10(2) -
1122 * 0.3010, but 77/256 is 0.3008, so exp needs to
1123 * be increased. Note that the arithmetic shift
1124 * performs a floor() unlike C arithmetic - using a
1125 * C multiply would break the following for negative
1126 * exponents.
1127 */
1128 (void)frexp(fp, &exp); /* exponent to base 2 */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001129
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001130 exp = (exp * 77) >> 8; /* <= exponent to base 10 */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001131
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001132 /* Avoid underflow here. */
1133 base = png_pow10(exp); /* May underflow */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001134
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001135 while (base < DBL_MIN || base < fp)
1136 {
1137 /* And this may overflow. */
1138 double test = png_pow10(exp+1);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001139
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001140 if (test <= DBL_MAX)
1141 ++exp, base = test;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001142
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001143 else
1144 break;
1145 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001146
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001147 /* Normalize fp and correct exp, after this fp is in the
1148 * range [.1,1) and exp is both the exponent and the digit
1149 * *before* which the decimal point should be inserted
1150 * (starting with 0 for the first digit). Note that this
1151 * works even if 10^exp is out of range because of the
1152 * test on DBL_MAX above.
1153 */
1154 fp /= base;
1155 while (fp >= 1) fp /= 10, ++exp;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001156
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001157 /* Because of the code above fp may, at this point, be
1158 * less than .1, this is ok because the code below can
1159 * handle the leading zeros this generates, so no attempt
1160 * is made to correct that here.
1161 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001162
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001163 {
1164 int czero, clead, cdigits;
1165 char exponent[10];
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001166
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001167 /* Allow up to two leading zeros - this will not lengthen
1168 * the number compared to using E-n.
1169 */
1170 if (exp < 0 && exp > -3) /* PLUS 3 TOTAL 4 */
1171 {
1172 czero = -exp; /* PLUS 2 digits: TOTAL 3 */
1173 exp = 0; /* Dot added below before first output. */
1174 }
1175 else
1176 czero = 0; /* No zeros to add */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001177
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001178 /* Generate the digit list, stripping trailing zeros and
1179 * inserting a '.' before a digit if the exponent is 0.
1180 */
1181 clead = czero; /* Count of leading zeros */
1182 cdigits = 0; /* Count of digits in list. */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001183
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001184 do
1185 {
1186 double d;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001187
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001188 fp *= 10;
1189 /* Use modf here, not floor and subtract, so that
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001190 * the separation is done in one step. At the end
1191 * of the loop don't break the number into parts so
1192 * that the final digit is rounded.
1193 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001194 if (cdigits+czero-clead+1 < (int)precision)
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001195 fp = modf(fp, &d);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001196
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001197 else
1198 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001199 d = floor(fp + .5);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001200
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001201 if (d > 9)
1202 {
1203 /* Rounding up to 10, handle that here. */
1204 if (czero > 0)
1205 {
1206 --czero, d = 1;
1207 if (cdigits == 0) --clead;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001208 }
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001209 else
1210 {
1211 while (cdigits > 0 && d > 9)
1212 {
1213 int ch = *--ascii;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001214
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001215 if (exp != (-1))
1216 ++exp;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001217
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001218 else if (ch == 46)
1219 {
1220 ch = *--ascii, ++size;
1221 /* Advance exp to '1', so that the
1222 * decimal point happens after the
1223 * previous digit.
1224 */
1225 exp = 1;
1226 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001227
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001228 --cdigits;
1229 d = ch - 47; /* I.e. 1+(ch-48) */
1230 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001231
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001232 /* Did we reach the beginning? If so adjust the
1233 * exponent but take into account the leading
1234 * decimal point.
1235 */
1236 if (d > 9) /* cdigits == 0 */
1237 {
1238 if (exp == (-1))
1239 {
1240 /* Leading decimal point (plus zeros?), if
1241 * we lose the decimal point here it must
1242 * be reentered below.
1243 */
1244 int ch = *--ascii;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001245
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001246 if (ch == 46)
1247 ++size, exp = 1;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001248
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001249 /* Else lost a leading zero, so 'exp' is
1250 * still ok at (-1)
1251 */
1252 }
1253 else
1254 ++exp;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001255
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001256 /* In all cases we output a '1' */
1257 d = 1;
1258 }
1259 }
1260 }
1261 fp = 0; /* Guarantees termination below. */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001262 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001263
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001264 if (d == 0)
1265 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001266 ++czero;
1267 if (cdigits == 0) ++clead;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001268 }
1269 else
1270 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001271 /* Included embedded zeros in the digit count. */
1272 cdigits += czero - clead;
1273 clead = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001274
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001275 while (czero > 0)
1276 {
1277 /* exp == (-1) means we just output the decimal
1278 * place - after the DP don't adjust 'exp' any
1279 * more!
1280 */
1281 if (exp != (-1))
1282 {
1283 if (exp == 0) *ascii++ = 46, --size;
1284 /* PLUS 1: TOTAL 4 */
1285 --exp;
1286 }
1287 *ascii++ = 48, --czero;
1288 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001289
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001290 if (exp != (-1))
1291 {
1292 if (exp == 0) *ascii++ = 46, --size; /* counted above */
1293 --exp;
1294 }
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001295 *ascii++ = (char)(48 + (int)d), ++cdigits;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001296 }
1297 }
1298 while (cdigits+czero-clead < (int)precision && fp > DBL_MIN);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001299
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001300 /* The total output count (max) is now 4+precision */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001301
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001302 /* Check for an exponent, if we don't need one we are
1303 * done and just need to terminate the string. At
1304 * this point exp==(-1) is effectively if flag - it got
1305 * to '-1' because of the decrement after outputing
1306 * the decimal point above (the exponent required is
1307 * *not* -1!)
1308 */
1309 if (exp >= (-1) && exp <= 2)
1310 {
1311 /* The following only happens if we didn't output the
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001312 * leading zeros above for negative exponent, so this
1313 * doest add to the digit requirement. Note that the
1314 * two zeros here can only be output if the two leading
1315 * zeros were *not* output, so this doesn't increase
1316 * the output count.
1317 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001318 while (--exp >= 0) *ascii++ = 48;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001319
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001320 *ascii = 0;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001321
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001322 /* Total buffer requirement (including the '\0') is
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001323 * 5+precision - see check at the start.
1324 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001325 return;
1326 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001327
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001328 /* Here if an exponent is required, adjust size for
1329 * the digits we output but did not count. The total
1330 * digit output here so far is at most 1+precision - no
1331 * decimal point and no leading or trailing zeros have
1332 * been output.
1333 */
1334 size -= cdigits;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001335
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001336 *ascii++ = 69, --size; /* 'E': PLUS 1 TOTAL 2+precision*/
1337 if (exp < 0)
1338 {
1339 *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */
1340 exp = -exp;
1341 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001342
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001343 cdigits = 0;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001344
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001345 while (exp > 0)
1346 {
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001347 exponent[cdigits++] = (char)(48 + exp % 10);
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001348 exp /= 10;
1349 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001350
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001351 /* Need another size check here for the exponent digits, so
1352 * this need not be considered above.
1353 */
1354 if ((int)size > cdigits)
1355 {
1356 while (cdigits > 0) *ascii++ = exponent[--cdigits];
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001357
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001358 *ascii = 0;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001359
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001360 return;
1361 }
1362 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001363 }
1364 else if (!(fp >= DBL_MIN))
1365 {
1366 *ascii++ = 48; /* '0' */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001367 *ascii = 0;
1368 return;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001369 }
1370 else
1371 {
1372 *ascii++ = 105; /* 'i' */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001373 *ascii++ = 110; /* 'n' */
1374 *ascii++ = 102; /* 'f' */
1375 *ascii = 0;
1376 return;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001377 }
1378 }
1379
1380 /* Here on buffer too small. */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001381 png_error(png_ptr, "ASCII conversion buffer too small");
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001382}
1383
1384# endif /* FLOATING_POINT */
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001385
1386# ifdef PNG_FIXED_POINT_SUPPORTED
1387/* Function to format a fixed point value in ASCII.
1388 */
1389void /* PRIVATE */
1390png_ascii_from_fixed(png_structp png_ptr, png_charp ascii, png_size_t size,
1391 png_fixed_point fp)
1392{
1393 /* Require space for 10 decimal digits, a decimal point, a minus sign and a
1394 * trailing \0, 13 characters:
1395 */
1396 if (size > 12)
1397 {
1398 png_uint_32 num;
1399
1400 /* Avoid overflow here on the minimum integer. */
1401 if (fp < 0)
1402 *ascii++ = 45, --size, num = -fp;
1403 else
1404 num = fp;
1405
1406 if (num <= 0x80000000U) /* else overflowed */
1407 {
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001408 unsigned int ndigits = 0, first = 16/*flag value*/;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001409 char digits[10];
1410
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001411 while (num)
1412 {
1413 /* Split the low digit off num: */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001414 unsigned int tmp = num/10;
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001415 num -= tmp*10;
1416 digits[ndigits++] = (char)(48 + num);
1417 /* Record the first non-zero digit, note that this is a number
1418 * starting at 1, it's not actually the array index.
1419 */
1420 if (first == 16 && num > 0)
1421 first = ndigits;
1422 num = tmp;
1423 }
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001424
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001425 if (ndigits > 0)
1426 {
1427 while (ndigits > 5) *ascii++ = digits[--ndigits];
1428 /* The remaining digits are fractional digits, ndigits is '5' or
1429 * smaller at this point. It is certainly not zero. Check for a
1430 * non-zero fractional digit:
1431 */
1432 if (first <= 5)
1433 {
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001434 unsigned int i;
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001435 *ascii++ = 46; /* decimal point */
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -05001436 /* ndigits may be <5 for small numbers, output leading zeros
1437 * then ndigits digits to first:
1438 */
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001439 i = 5;
1440 while (ndigits < i) *ascii++ = 48, --i;
1441 while (ndigits >= first) *ascii++ = digits[--ndigits];
1442 /* Don't output the trailing zeros! */
1443 }
1444 }
1445 else
1446 *ascii++ = 48;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001447
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001448 /* And null terminate the string: */
1449 *ascii = 0;
1450 return;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001451 }
1452 }
1453
1454 /* Here on buffer too small. */
1455 png_error(png_ptr, "ASCII conversion buffer too small");
1456}
1457# endif /* FIXED_POINT */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001458#endif /* READ_SCAL */
1459
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -05001460#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001461 !defined(PNG_FIXED_POINT_MACRO_SUPPORTED)
1462png_fixed_point
1463png_fixed(png_structp png_ptr, double fp, png_const_charp text)
1464{
1465 double r = floor(100000 * fp + .5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001466
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001467 if (r <= 2147483647. && r >= -2147483648.)
1468 return (png_fixed_point)r;
1469
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001470 png_fixed_error(png_ptr, text);
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -05001471 /*NOT REACHED*/
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001472}
1473#endif
1474
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -05001475#if defined(PNG_READ_GAMMA_SUPPORTED) || \
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001476 defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG__READ_pHYs_SUPPORTED)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001477/* muldiv functions */
1478/* This API takes signed arguments and rounds the result to the nearest
1479 * integer (or, for a fixed point number - the standard argument - to
1480 * the nearest .00001). Overflow and divide by zero are signalled in
1481 * the result, a boolean - true on success, false on overflow.
1482 */
1483int
1484png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001485 png_int_32 div)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001486{
1487 /* Return a * times / div, rounded. */
1488 if (div != 0)
1489 {
1490 if (a == 0 || times == 0)
1491 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001492 *res = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001493 return 1;
1494 }
1495 else
1496 {
1497#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001498 double r = a;
1499 r *= times;
1500 r /= div;
1501 r = floor(r+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001502
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001503 /* A png_fixed_point is a 32 bit integer. */
1504 if (r <= 2147483647. && r >= -2147483648.)
1505 {
1506 *res = (png_fixed_point)r;
1507 return 1;
1508 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001509#else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001510 int negative = 0;
1511 png_uint_32 A, T, D;
Glenn Randers-Pehrson3b5d6952010-08-19 08:06:12 -05001512 png_uint_32 s16, s32, s00;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001513
1514 if (a < 0)
1515 negative = 1, A = -a;
1516 else
1517 A = a;
1518
1519 if (times < 0)
1520 negative = !negative, T = -times;
1521 else
1522 T = times;
1523
1524 if (div < 0)
1525 negative = !negative, D = -div;
1526 else
1527 D = div;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001528
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001529 /* Following can't overflow because the arguments only
1530 * have 31 bits each, however the result may be 32 bits.
1531 */
Glenn Randers-Pehrson3b5d6952010-08-19 08:06:12 -05001532 s16 = (A >> 16) * (T & 0xffff) +
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001533 (A & 0xffff) * (T >> 16);
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001534 /* Can't overflow because the a*times bit is only 30
1535 * bits at most.
1536 */
Glenn Randers-Pehrson3b5d6952010-08-19 08:06:12 -05001537 s32 = (A >> 16) * (T >> 16) + (s16 >> 16);
1538 s00 = (A & 0xffff) * (T & 0xffff);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001539
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001540 s16 = (s16 & 0xffff) << 16;
1541 s00 += s16;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001542
1543 if (s00 < s16)
1544 ++s32; /* carry */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001545
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001546 if (s32 < D) /* else overflow */
1547 {
1548 /* s32.s00 is now the 64 bit product, do a standard
1549 * division, we know that s32 < D, so the maximum
1550 * required shift is 31.
1551 */
1552 int bitshift = 32;
1553 png_fixed_point result = 0; /* NOTE: signed */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001554
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001555 while (--bitshift >= 0)
1556 {
1557 png_uint_32 d32, d00;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001558
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001559 if (bitshift > 0)
1560 d32 = D >> (32-bitshift), d00 = D << bitshift;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001561
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001562 else
1563 d32 = 0, d00 = D;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001564
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001565 if (s32 > d32)
1566 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001567 if (s00 < d00) --s32; /* carry */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001568 s32 -= d32, s00 -= d00, result += 1<<bitshift;
1569 }
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001570
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001571 else
1572 if (s32 == d32 && s00 >= d00)
1573 s32 = 0, s00 -= d00, result += 1<<bitshift;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001574 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001575
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001576 /* Handle the rounding. */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001577 if (s00 >= (D >> 1))
1578 ++result;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001579
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001580 if (negative)
1581 result = -result;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001582
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001583 /* Check for overflow. */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001584 if ((negative && result <= 0) || (!negative && result >= 0))
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001585 {
1586 *res = result;
1587 return 1;
1588 }
1589 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001590#endif
1591 }
1592 }
1593
1594 return 0;
1595}
1596#endif /* READ_GAMMA || INCH_CONVERSIONS */
1597
1598#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)
1599/* The following is for when the caller doesn't much care about the
1600 * result.
1601 */
1602png_fixed_point
1603png_muldiv_warn(png_structp png_ptr, png_fixed_point a, png_int_32 times,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001604 png_int_32 div)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001605{
1606 png_fixed_point result;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001607
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001608 if (png_muldiv(&result, a, times, div))
1609 return result;
1610
1611 png_warning(png_ptr, "fixed point overflow ignored");
1612 return 0;
1613}
1614#endif
1615
1616#ifdef PNG_READ_GAMMA_SUPPORTED /* more fixed point functions for gammma */
1617/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */
1618png_fixed_point
1619png_reciprocal(png_fixed_point a)
1620{
1621#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
1622 double r = floor(1E10/a+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001623
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001624 if (r <= 2147483647. && r >= -2147483648.)
1625 return (png_fixed_point)r;
1626#else
1627 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001628
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001629 if (png_muldiv(&res, 100000, 100000, a))
1630 return res;
1631#endif
1632
1633 return 0; /* error/overflow */
1634}
1635
1636/* A local convenience routine. */
1637static png_fixed_point
1638png_product2(png_fixed_point a, png_fixed_point b)
1639{
Glenn Randers-Pehrson9c690912010-08-27 11:39:38 -05001640 /* The required result is 1/a * 1/b; the following preserves accuracy. */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001641#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
1642 double r = a * 1E-5;
1643 r *= b;
1644 r = floor(r+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001645
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001646 if (r <= 2147483647. && r >= -2147483648.)
1647 return (png_fixed_point)r;
1648#else
1649 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001650
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001651 if (png_muldiv(&res, a, b, 100000))
1652 return res;
1653#endif
1654
1655 return 0; /* overflow */
1656}
1657
1658/* The inverse of the above. */
1659png_fixed_point
1660png_reciprocal2(png_fixed_point a, png_fixed_point b)
1661{
Glenn Randers-Pehrson9c690912010-08-27 11:39:38 -05001662 /* The required result is 1/a * 1/b; the following preserves accuracy. */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001663#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
1664 double r = 1E15/a;
1665 r /= b;
1666 r = floor(r+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001667
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001668 if (r <= 2147483647. && r >= -2147483648.)
1669 return (png_fixed_point)r;
1670#else
1671 /* This may overflow because the range of png_fixed_point isn't symmetric,
1672 * but this API is only used for the product of file and screen gamma so it
1673 * doesn't matter that the smallest number it can produce is 1/21474, not
1674 * 1/100000
1675 */
1676 png_fixed_point res = png_product2(a, b);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001677
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001678 if (res != 0)
1679 return png_reciprocal(res);
1680#endif
1681
1682 return 0; /* overflow */
1683}
1684#endif /* READ_GAMMA */
1685
1686#ifdef PNG_CHECK_cHRM_SUPPORTED
1687/* Added at libpng version 1.2.34 (Dec 8, 2008) and 1.4.0 (Jan 2,
1688 * 2010: moved from pngset.c) */
1689/*
1690 * Multiply two 32-bit numbers, V1 and V2, using 32-bit
1691 * arithmetic, to produce a 64 bit result in the HI/LO words.
1692 *
1693 * A B
1694 * x C D
1695 * ------
1696 * AD || BD
1697 * AC || CB || 0
1698 *
1699 * where A and B are the high and low 16-bit words of V1,
1700 * C and D are the 16-bit words of V2, AD is the product of
1701 * A and D, and X || Y is (X << 16) + Y.
1702*/
1703
1704void /* PRIVATE */
1705png_64bit_product (long v1, long v2, unsigned long *hi_product,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001706 unsigned long *lo_product)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001707{
1708 int a, b, c, d;
1709 long lo, hi, x, y;
1710
1711 a = (v1 >> 16) & 0xffff;
1712 b = v1 & 0xffff;
1713 c = (v2 >> 16) & 0xffff;
1714 d = v2 & 0xffff;
1715
1716 lo = b * d; /* BD */
1717 x = a * d + c * b; /* AD + CB */
1718 y = ((lo >> 16) & 0xffff) + x;
1719
1720 lo = (lo & 0xffff) | ((y & 0xffff) << 16);
1721 hi = (y >> 16) & 0xffff;
1722
1723 hi += a * c; /* AC */
1724
1725 *hi_product = (unsigned long)hi;
1726 *lo_product = (unsigned long)lo;
1727}
1728#endif /* CHECK_cHRM */
1729
1730#ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */
1731#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED
1732/* Fixed point gamma.
1733 *
1734 * To calculate gamma this code implements fast log() and exp() calls using only
1735 * fixed point arithmetic. This code has sufficient precision for either 8 or
1736 * 16 bit sample values.
1737 *
1738 * The tables used here were calculated using simple 'bc' programs, but C double
1739 * precision floating point arithmetic would work fine. The programs are given
1740 * at the head of each table.
1741 *
1742 * 8 bit log table
1743 * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to
1744 * 255, so it's the base 2 logarithm of a normalized 8 bit floating point
1745 * mantissa. The numbers are 32 bit fractions.
1746 */
1747static png_uint_32
1748png_8bit_l2[128] =
1749{
1750# if PNG_DO_BC
1751 for (i=128;i<256;++i) { .5 - l(i/255)/l(2)*65536*65536; }
1752# endif
1753 4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U,
1754 3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U,
1755 3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U,
1756 3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U,
1757 3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U,
1758 2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U,
1759 2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U,
1760 2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U,
1761 2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U,
1762 2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U,
1763 1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U,
1764 1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U,
1765 1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U,
1766 1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U,
1767 1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U,
1768 971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U,
1769 803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U,
1770 639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U,
1771 479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U,
1772 324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U,
1773 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U,
1774 24347096U, 0U
1775#if 0
1776 /* The following are the values for 16 bit tables - these work fine for the 8
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001777 * bit conversions but produce very slightly larger errors in the 16 bit log
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001778 * (about 1.2 as opposed to 0.7 absolute error in the final value). To use
1779 * these all the shifts below must be adjusted appropriately.
1780 */
1781 65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054,
1782 57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803,
1783 50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068,
1784 43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782,
1785 37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887,
1786 31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339,
1787 25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098,
1788 20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132,
1789 15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415,
1790 10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523,
1791 6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495,
1792 1119, 744, 372
1793#endif
1794};
1795
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001796static png_int_32
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001797png_log8bit(unsigned int x)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001798{
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001799 unsigned int log = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001800 /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log,
1801 * because the log is actually negate that means adding 1. The final
1802 * returned value thus has the range 0 (for 255 input) to 7.994 (for 1
1803 * input), return 7.99998 for the overflow (log 0) case - so the result is
1804 * always at most 19 bits.
1805 */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001806 if ((x &= 0xff) == 0)
1807 return 0xffffffff;
1808
1809 if ((x & 0xf0) == 0)
1810 log = 4, x <<= 4;
1811
1812 if ((x & 0xc0) == 0)
1813 log += 2, x <<= 2;
1814
1815 if ((x & 0x80) == 0)
1816 log += 1, x <<= 1;
1817
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001818 /* result is at most 19 bits, so this cast is safe: */
1819 return (png_int_32)((log << 16) + ((png_8bit_l2[x-128]+32768)>>16));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001820}
1821
1822/* The above gives exact (to 16 binary places) log2 values for 8 bit images,
1823 * for 16 bit images we use the most significant 8 bits of the 16 bit value to
1824 * get an approximation then multiply the approximation by a correction factor
1825 * determined by the remaining up to 8 bits. This requires an additional step
1826 * in the 16 bit case.
1827 *
1828 * We want log2(value/65535), we have log2(v'/255), where:
1829 *
1830 * value = v' * 256 + v''
1831 * = v' * f
1832 *
1833 * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128
1834 * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less
1835 * than 258. The final factor also needs to correct for the fact that our 8 bit
1836 * value is scaled by 255, whereas the 16 bit values must be scaled by 65535.
1837 *
1838 * This gives a final formula using a calculated value 'x' which is value/v' and
1839 * scaling by 65536 to match the above table:
1840 *
1841 * log2(x/257) * 65536
1842 *
1843 * Since these numbers are so close to '1' we can use simple linear
1844 * interpolation between the two end values 256/257 (result -368.61) and 258/257
1845 * (result 367.179). The values used below are scaled by a further 64 to give
1846 * 16 bit precision in the interpolation:
1847 *
1848 * Start (256): -23591
1849 * Zero (257): 0
1850 * End (258): 23499
1851 */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001852static png_int_32
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001853png_log16bit(png_uint_32 x)
1854{
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001855 unsigned int log = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001856
1857 /* As above, but now the input has 16 bits. */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001858 if ((x &= 0xffff) == 0)
1859 return 0xffffffff;
1860
1861 if ((x & 0xff00) == 0)
1862 log = 8, x <<= 8;
1863
1864 if ((x & 0xf000) == 0)
1865 log += 4, x <<= 4;
1866
1867 if ((x & 0xc000) == 0)
1868 log += 2, x <<= 2;
1869
1870 if ((x & 0x8000) == 0)
1871 log += 1, x <<= 1;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001872
1873 /* Calculate the base logarithm from the top 8 bits as a 28 bit fractional
1874 * value.
1875 */
1876 log <<= 28;
1877 log += (png_8bit_l2[(x>>8)-128]+8) >> 4;
1878
1879 /* Now we need to interpolate the factor, this requires a division by the top
1880 * 8 bits. Do this with maximum precision.
1881 */
1882 x = ((x << 16) + (x >> 9)) / (x >> 8);
1883
1884 /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24,
1885 * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly
1886 * 16 bits to interpolate to get the low bits of the result. Round the
1887 * answer. Note that the end point values are scaled by 64 to retain overall
1888 * precision and that 'log' is current scaled by an extra 12 bits, so adjust
1889 * the overall scaling by 6-12. Round at every step.
1890 */
1891 x -= 1U << 24;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001892
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001893 if (x <= 65536U) /* <= '257' */
1894 log += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001895
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001896 else
1897 log -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12);
1898
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001899 /* Safe, because the result can't have more than 20 bits: */
1900 return (png_int_32)((log + 2048) >> 12);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001901}
1902
1903/* The 'exp()' case must invert the above, taking a 20 bit fixed point
1904 * logarithmic value and returning a 16 or 8 bit number as appropriate. In
1905 * each case only the low 16 bits are relevant - the fraction - since the
1906 * integer bits (the top 4) simply determine a shift.
1907 *
1908 * The worst case is the 16 bit distinction between 65535 and 65534, this
1909 * requires perhaps spurious accuracty in the decoding of the logarithm to
1910 * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance
1911 * of getting this accuracy in practice.
1912 *
1913 * To deal with this the following exp() function works out the exponent of the
1914 * frational part of the logarithm by using an accurate 32 bit value from the
1915 * top four fractional bits then multiplying in the remaining bits.
1916 */
1917static png_uint_32
1918png_32bit_exp[16] =
1919{
1920# if PNG_DO_BC
1921 for (i=0;i<16;++i) { .5 + e(-i/16*l(2))*2^32; }
1922# endif
1923 /* NOTE: the first entry is deliberately set to the maximum 32 bit value. */
1924 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U,
1925 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U,
1926 2553802834U, 2445529972U, 2341847524U, 2242560872U
1927};
1928
1929/* Adjustment table; provided to explain the numbers in the code below. */
1930#if PNG_DO_BC
1931for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"}
1932 11 44937.64284865548751208448
1933 10 45180.98734845585101160448
1934 9 45303.31936980687359311872
1935 8 45364.65110595323018870784
1936 7 45395.35850361789624614912
1937 6 45410.72259715102037508096
1938 5 45418.40724413220722311168
1939 4 45422.25021786898173001728
1940 3 45424.17186732298419044352
1941 2 45425.13273269940811464704
1942 1 45425.61317555035558641664
1943 0 45425.85339951654943850496
1944#endif
1945
1946static png_uint_32
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001947png_exp(png_fixed_point x)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001948{
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001949 if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001950 {
1951 /* Obtain a 4 bit approximation */
1952 png_uint_32 e = png_32bit_exp[(x >> 12) & 0xf];
1953
1954 /* Incorporate the low 12 bits - these decrease the returned value by
1955 * multiplying by a number less than 1 if the bit is set. The multiplier
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001956 * is determined by the above table and the shift. Notice that the values
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001957 * converge on 45426 and this is used to allow linear interpolation of the
1958 * low bits.
1959 */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001960 if (x & 0x800)
1961 e -= (((e >> 16) * 44938U) + 16U) >> 5;
1962
1963 if (x & 0x400)
1964 e -= (((e >> 16) * 45181U) + 32U) >> 6;
1965
1966 if (x & 0x200)
1967 e -= (((e >> 16) * 45303U) + 64U) >> 7;
1968
1969 if (x & 0x100)
1970 e -= (((e >> 16) * 45365U) + 128U) >> 8;
1971
1972 if (x & 0x080)
1973 e -= (((e >> 16) * 45395U) + 256U) >> 9;
1974
1975 if (x & 0x040)
1976 e -= (((e >> 16) * 45410U) + 512U) >> 10;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001977
1978 /* And handle the low 6 bits in a single block. */
1979 e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9;
1980
1981 /* Handle the upper bits of x. */
1982 e >>= x >> 16;
1983 return e;
1984 }
1985
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001986 /* Check for overflow */
1987 if (x <= 0)
1988 return png_32bit_exp[0];
1989
1990 /* Else underflow */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001991 return 0;
1992}
1993
1994static png_byte
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001995png_exp8bit(png_fixed_point log)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001996{
1997 /* Get a 32 bit value: */
1998 png_uint_32 x = png_exp(log);
1999
2000 /* Convert the 32 bit value to 0..255 by multiplying by 256-1, note that the
2001 * second, rounding, step can't overflow because of the first, subtraction,
2002 * step.
2003 */
2004 x -= x >> 8;
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002005 return (png_byte)((x + 0x7fffffU) >> 24);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002006}
2007
2008static png_uint_16
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002009png_exp16bit(png_fixed_point log)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002010{
2011 /* Get a 32 bit value: */
2012 png_uint_32 x = png_exp(log);
2013
2014 /* Convert the 32 bit value to 0..65535 by multiplying by 65536-1: */
2015 x -= x >> 16;
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002016 return (png_uint_16)((x + 32767U) >> 16);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002017}
2018#endif /* FLOATING_ARITHMETIC */
2019
2020png_byte
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002021png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002022{
2023 if (value > 0 && value < 255)
2024 {
2025# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002026 double r = floor(255*pow(value/255.,gamma*.00001)+.5);
2027 return (png_byte)r;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002028# else
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002029 png_int_32 log = png_log8bit(value);
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002030 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002031
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002032 if (png_muldiv(&res, gamma, log, PNG_FP_1))
2033 return png_exp8bit(res);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002034
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05002035 /* Overflow. */
2036 value = 0;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002037# endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002038 }
2039
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002040 return (png_byte)value;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002041}
2042
2043png_uint_16
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002044png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002045{
2046 if (value > 0 && value < 65535)
2047 {
2048# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002049 double r = floor(65535*pow(value/65535.,gamma*.00001)+.5);
2050 return (png_uint_16)r;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002051# else
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002052 png_int_32 log = png_log16bit(value);
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002053 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002054
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002055 if (png_muldiv(&res, gamma, log, PNG_FP_1))
2056 return png_exp16bit(res);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002057
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05002058 /* Overflow. */
2059 value = 0;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002060# endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002061 }
2062
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002063 return (png_uint_16)value;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002064}
2065
2066/* This does the right thing based on the bit_depth field of the
2067 * png_struct, interpreting values as 8 or 16 bit. While the result
2068 * is nominally a 16 bit value if bit depth is 8 then the result is
2069 * 8 bit (as are the arguments.)
2070 */
2071png_uint_16 /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002072png_gamma_correct(png_structp png_ptr, unsigned int value,
2073 png_fixed_point gamma)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002074{
2075 if (png_ptr->bit_depth == 8)
2076 return png_gamma_8bit_correct(value, gamma);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002077
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002078 else
2079 return png_gamma_16bit_correct(value, gamma);
2080}
2081
2082/* This is the shared test on whether a gamma value is 'significant' - whether
2083 * it is worth doing gamma correction.
2084 */
2085int /* PRIVATE */
2086png_gamma_significant(png_fixed_point gamma)
2087{
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002088 return gamma < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED ||
2089 gamma > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002090}
2091
2092/* Internal function to build a single 16 bit table - the table consists of
2093 * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount
2094 * to shift the input values right (or 16-number_of_signifiant_bits).
2095 *
Glenn Randers-Pehrsona774c5d2010-08-26 19:37:55 -05002096 * The caller is responsible for ensuring that the table gets cleaned up on
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002097 * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument
2098 * should be somewhere that will be cleaned.
2099 */
2100static void
2101png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable,
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002102 PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002103{
2104 /* Various values derived from 'shift': */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002105 PNG_CONST unsigned int num = 1U << (8U - shift);
2106 PNG_CONST unsigned int max = (1U << (16U - shift))-1U;
2107 PNG_CONST unsigned int max_by_2 = 1U << (15U-shift);
2108 unsigned int i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002109
2110 png_uint_16pp table = *ptable =
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002111 (png_uint_16pp)png_calloc(png_ptr, num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002112
2113 for (i = 0; i < num; i++)
2114 {
2115 png_uint_16p sub_table = table[i] =
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002116 (png_uint_16p)png_malloc(png_ptr, 256 * png_sizeof(png_uint_16));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002117
2118 /* The 'threshold' test is repeated here because it can arise for one of
2119 * the 16 bit tables even if the others don't hit it.
2120 */
2121 if (png_gamma_significant(gamma))
2122 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002123 /* The old code would overflow at the end and this would cause the
2124 * 'pow' function to return a result >1, resulting in an
2125 * arithmetic error. This code follows the spec exactly; ig is
2126 * the recovered input sample, it always has 8-16 bits.
2127 *
2128 * We want input * 65535/max, rounded, the arithmetic fits in 32
2129 * bits (unsigned) so long as max <= 32767.
2130 */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002131 unsigned int j;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002132 for (j = 0; j < 256; j++)
2133 {
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002134 png_uint_32 ig = (j << (8-shift)) + i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002135# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002136 /* Inline the 'max' scaling operation: */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002137 double d = floor(65535*pow(ig/(double)max, gamma*.00001)+.5);
2138 sub_table[j] = (png_uint_16)d;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002139# else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002140 if (shift)
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05002141 ig = (ig * 65535U + max_by_2)/max;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002142
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002143 sub_table[j] = png_gamma_16bit_correct(ig, gamma);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002144# endif
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002145 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002146 }
2147 else
2148 {
2149 /* We must still build a table, but do it the fast way. */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002150 unsigned int j;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002151
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002152 for (j = 0; j < 256; j++)
2153 {
2154 png_uint_32 ig = (j << (8-shift)) + i;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002155
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002156 if (shift)
2157 ig = (ig * 65535U + max_by_2)/max;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002158
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002159 sub_table[j] = (png_uint_16)ig;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002160 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002161 }
2162 }
2163}
2164
2165/* NOTE: this function expects the *inverse* of the overall gamma transformation
2166 * required.
2167 */
2168static void
2169png_build_16to8_table(png_structp png_ptr, png_uint_16pp *ptable,
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002170 PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002171{
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002172 PNG_CONST unsigned int num = 1U << (8U - shift);
2173 PNG_CONST unsigned int max = (1U << (16U - shift))-1U;
2174 unsigned int i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002175 png_uint_32 last;
2176
2177 png_uint_16pp table = *ptable =
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002178 (png_uint_16pp)png_calloc(png_ptr, num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002179
2180 /* 'num' is the number of tables and also the number of low bits of low
2181 * bits of the input 16 bit value used to select a table. Each table is
2182 * itself index by the high 8 bits of the value.
2183 */
2184 for (i = 0; i < num; i++)
2185 table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002186 256 * png_sizeof(png_uint_16));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002187
2188 /* 'gamma' is set to the reciprocal of the value calculated above, so
2189 * pow(out,g) is an *input* value. 'last' is the last input value set.
2190 *
2191 * In the loop 'i' is used to find output values. Since the output is 8
2192 * bit there are only 256 possible values. The tables are set up to
2193 * select the closest possible output value for each input by finding
2194 * the input value at the boundary between each pair of output values
2195 * and filling the table up to that boundary with the lower output
2196 * value.
2197 *
2198 * The boundary values are 0.5,1.5..253.5,254.5. Since these are 9 bit
2199 * values the code below uses a 16 bit value in i; the values start at
2200 * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last
2201 * entries are filled with 255). Start i at 128 and fill all 'last'
2202 * table entries <= 'max'
2203 */
2204 last = 0;
2205 for (i = 0; i < 255; ++i) /* 8 bit output value */
2206 {
2207 /* Find the corresponding maximum input value */
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002208 png_uint_16 out = (png_uint_16)(i * 257U); /* 16 bit output value */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002209
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002210 /* Find the boundary value in 16 bits: */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002211 png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002212
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002213 /* Adjust (round) to (16-shift) bits: */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002214 bound = (bound * max + 32768U)/65535U + 1U;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002215
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002216 while (last < bound)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002217 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002218 table[last & (0xffU >> shift)][last >> (8U - shift)] = out;
2219 last++;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002220 }
2221 }
2222
2223 /* And fill in the final entries. */
2224 while (last < (num << 8))
2225 {
2226 table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U;
2227 last++;
2228 }
2229}
2230
2231/* Build a single 8 bit table: same as the 16 bit case but much simpler (and
2232 * typically much faster). Note that libpng currently does no sBIT processing
2233 * (apparently contrary to the spec) so a 256 entry table is always generated.
2234 */
2235static void
2236png_build_8bit_table(png_structp png_ptr, png_bytepp ptable,
2237 PNG_CONST png_fixed_point gamma)
2238{
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002239 unsigned int i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002240 png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256);
2241
2242 if (png_gamma_significant(gamma)) for (i=0; i<256; i++)
2243 table[i] = png_gamma_8bit_correct(i, gamma);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002244
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002245 else for (i=0; i<256; ++i)
2246 table[i] = (png_byte)i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002247}
2248
2249/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
2250 * tables, we don't make a full table if we are reducing to 8-bit in
2251 * the future. Note also how the gamma_16 tables are segmented so that
2252 * we don't need to allocate > 64K chunks for a full 16-bit table.
2253 */
2254void /* PRIVATE */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002255png_build_gamma_table(png_structp png_ptr, int bit_depth)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002256{
2257 png_debug(1, "in png_build_gamma_table");
2258
2259 if (bit_depth <= 8)
2260 {
2261 png_build_8bit_table(png_ptr, &png_ptr->gamma_table,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002262 png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->gamma,
2263 png_ptr->screen_gamma) : PNG_FP_1);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002264
2265#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
2266 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
2267 if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
2268 {
2269 png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002270 png_reciprocal(png_ptr->gamma));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002271
2272 png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002273 png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
2274 png_ptr->gamma/* Probably doing rgb_to_gray */);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002275 }
2276#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
2277 }
2278 else
2279 {
2280 png_byte shift, sig_bit;
2281
2282 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
2283 {
2284 sig_bit = png_ptr->sig_bit.red;
2285
2286 if (png_ptr->sig_bit.green > sig_bit)
2287 sig_bit = png_ptr->sig_bit.green;
2288
2289 if (png_ptr->sig_bit.blue > sig_bit)
2290 sig_bit = png_ptr->sig_bit.blue;
2291 }
2292 else
2293 sig_bit = png_ptr->sig_bit.gray;
2294
2295 /* 16 bit gamma code uses this equation:
2296 *
2297 * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8]
2298 *
2299 * Where 'iv' is the input color value and 'ov' is the output value -
2300 * pow(iv, gamma).
2301 *
2302 * Thus the gamma table consists of up to 256 256 entry tables. The table
2303 * is selected by the (8-gamma_shift) most significant of the low 8 bits of
2304 * the color value then indexed by the upper 8 bits:
2305 *
2306 * table[low bits][high 8 bits]
2307 *
2308 * So the table 'n' corresponds to all those 'iv' of:
2309 *
2310 * <all high 8 bit values><n << gamma_shift>..<(n+1 << gamma_shift)-1>
2311 *
2312 */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002313 if (sig_bit > 0 && sig_bit < 16U)
2314 shift = (png_byte)(16U - sig_bit); /* shift == insignificant bits */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002315
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002316 else
2317 shift = 0; /* keep all 16 bits */
2318
2319 if (png_ptr->transformations & PNG_16_TO_8)
2320 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002321 /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively
2322 * the significant bits in the *input* when the output will
2323 * eventually be 8 bits. By default it is 11.
2324 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002325 if (shift < (16U - PNG_MAX_GAMMA_8))
2326 shift = (16U - PNG_MAX_GAMMA_8);
2327 }
2328
2329 if (shift > 8U)
2330 shift = 8U; /* Guarantees at least one table! */
2331
2332 png_ptr->gamma_shift = shift;
2333
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002334#ifdef PNG_16BIT_SUPPORTED
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002335 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002336#endif
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002337 png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,
2338 png_ptr->screen_gamma > 0 ? png_product2(png_ptr->gamma,
2339 png_ptr->screen_gamma) : PNG_FP_1);
2340
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002341#ifdef PNG_16BIT_SUPPORTED
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002342 else
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002343 png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,
2344 png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->gamma,
2345 png_ptr->screen_gamma) : PNG_FP_1);
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002346#endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002347
2348#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
2349 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
2350 if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
2351 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002352 png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002353 png_reciprocal(png_ptr->gamma));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002354
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002355 /* Notice that the '16 from 1' table should be full precision, however
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002356 * the lookup on this table still uses gamma_shift, so it can't be.
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002357 * TODO: fix this.
2358 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002359 png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002360 png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
2361 png_ptr->gamma/* Probably doing rgb_to_gray */);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002362 }
2363#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
2364 }
2365}
2366#endif /* READ_GAMMA */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002367#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */