pngread.c 25.4 KB
Newer Older
G
Guy Schalnat 已提交
1

A
Andreas Dilger 已提交
2
/* pngread.c - read a PNG file
3
 *
4
 * libpng 0.98
5 6 7
 * For conditions of distribution and use, see copyright notice in png.h
 * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
 * Copyright (c) 1996, 1997 Andreas Dilger
8
 * Copyright (c) 1998, Glenn Randers-Pehrson
9
 * January 16, 1998
10 11 12 13
 *
 * This file contains routines that an application calls directly to
 * read a PNG file or stream.
 */
G
Guy Schalnat 已提交
14 15 16 17

#define PNG_INTERNAL
#include "png.h"

A
Andreas Dilger 已提交
18
/* Create a PNG structure for reading, and allocate any memory needed. */
G
Guy Schalnat 已提交
19
png_structp
20
png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr,
A
Andreas Dilger 已提交
21
   png_error_ptr error_fn, png_error_ptr warn_fn)
G
Guy Schalnat 已提交
22 23
{
   png_structp png_ptr;
A
Andreas Dilger 已提交
24 25 26
#ifdef USE_FAR_KEYWORD
   jmp_buf jmpbuf;
#endif
A
Andreas Dilger 已提交
27
   png_debug(1, "in png_create_read_struct\n");
G
Guy Schalnat 已提交
28 29 30 31
   if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
   {
      return (png_structp)NULL;
   }
A
Andreas Dilger 已提交
32 33 34
#ifdef USE_FAR_KEYWORD
   if (setjmp(jmpbuf))
#else
G
Guy Schalnat 已提交
35
   if (setjmp(png_ptr->jmpbuf))
A
Andreas Dilger 已提交
36
#endif
G
Guy Schalnat 已提交
37
   {
A
Andreas Dilger 已提交
38
      png_free(png_ptr, png_ptr->zbuf);
G
Guy Schalnat 已提交
39 40 41
      png_destroy_struct(png_ptr);
      return (png_structp)NULL;
   }
A
Andreas Dilger 已提交
42 43 44 45 46
#ifdef USE_FAR_KEYWORD
   png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
#endif
   png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);

A
Andreas Dilger 已提交
47 48 49 50 51 52 53
   /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
    * we must recompile any applications that use any older library version.
    * For versions after libpng 1.0, we will be compatible, so we need
    * only check the first digit.
    */
   if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
       (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
G
Guy Schalnat 已提交
54
   {
A
Andreas Dilger 已提交
55
      png_error(png_ptr,
A
Andreas Dilger 已提交
56
         "Incompatible libpng version in application and library");
G
Guy Schalnat 已提交
57 58 59 60
   }

   /* initialize zbuf - compression buffer */
   png_ptr->zbuf_size = PNG_ZBUF_SIZE;
A
Andreas Dilger 已提交
61 62 63 64
   png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
   png_ptr->zstream.zalloc = png_zalloc;
   png_ptr->zstream.zfree = png_zfree;
   png_ptr->zstream.opaque = (voidpf)png_ptr;
G
Guy Schalnat 已提交
65

A
Andreas Dilger 已提交
66
   switch (inflateInit(&png_ptr->zstream))
G
Guy Schalnat 已提交
67 68 69 70 71 72 73 74
   {
     case Z_OK: /* Do nothing */ break;
     case Z_MEM_ERROR:
     case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break;
     case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); break;
     default: png_error(png_ptr, "Unknown zlib error");
   }

A
Andreas Dilger 已提交
75 76
   png_ptr->zstream.next_out = png_ptr->zbuf;
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
77 78 79 80 81 82

   png_set_read_fn(png_ptr, NULL, NULL);

   return (png_ptr);
}

A
Andreas Dilger 已提交
83
/* Initialize PNG structure for reading, and allocate any memory needed.
A
Andreas Dilger 已提交
84 85
   This interface is depreciated in favour of the png_create_read_struct(),
   and it will eventually disappear. */
G
Guy Schalnat 已提交
86
void
G
Guy Schalnat 已提交
87
png_read_init(png_structp png_ptr)
G
Guy Schalnat 已提交
88
{
G
Guy Schalnat 已提交
89
   jmp_buf tmp_jmp;  /* to save current jump buffer */
G
Guy Schalnat 已提交
90

A
Andreas Dilger 已提交
91
   png_debug(1, "in png_read_init\n");
G
Guy Schalnat 已提交
92
   /* save jump buffer and error functions */
G
Guy Schalnat 已提交
93
   png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
G
Guy Schalnat 已提交
94

G
Guy Schalnat 已提交
95
   /* reset all variables to 0 */
G
Guy Schalnat 已提交
96
   png_memset(png_ptr, 0, sizeof (png_struct));
G
Guy Schalnat 已提交
97

G
Guy Schalnat 已提交
98
   /* restore jump buffer */
G
Guy Schalnat 已提交
99
   png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
G
Guy Schalnat 已提交
100

G
Guy Schalnat 已提交
101
   /* initialize zbuf - compression buffer */
G
Guy Schalnat 已提交
102
   png_ptr->zbuf_size = PNG_ZBUF_SIZE;
A
Andreas Dilger 已提交
103 104 105 106
   png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
   png_ptr->zstream.zalloc = png_zalloc;
   png_ptr->zstream.zfree = png_zfree;
   png_ptr->zstream.opaque = (voidpf)png_ptr;
G
Guy Schalnat 已提交
107

A
Andreas Dilger 已提交
108
   switch (inflateInit(&png_ptr->zstream))
G
Guy Schalnat 已提交
109 110 111 112 113 114 115 116
   {
     case Z_OK: /* Do nothing */ break;
     case Z_MEM_ERROR:
     case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory"); break;
     case Z_VERSION_ERROR: png_error(png_ptr, "zlib version"); break;
     default: png_error(png_ptr, "Unknown zlib error");
   }

A
Andreas Dilger 已提交
117 118
   png_ptr->zstream.next_out = png_ptr->zbuf;
   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
G
Guy Schalnat 已提交
119 120

   png_set_read_fn(png_ptr, NULL, NULL);
G
Guy Schalnat 已提交
121 122
}

A
Andreas Dilger 已提交
123 124 125 126 127 128 129 130
/* Read the information before the actual image data.  This has been
 * changed in v0.90 to allow reading a file which already has the magic
 * bytes read from the stream.  You can tell libpng how many bytes have
 * been read from the beginning of the stream (up to the maxumum of 8)
 * via png_set_sig_bytes(), and we will only check the remaining bytes
 * here.  The application can then have access to the signature bytes we
 * read if it is determined that this isn't a valid PNG file.
 */
G
Guy Schalnat 已提交
131
void
A
Andreas Dilger 已提交
132
png_read_info(png_structp png_ptr, png_infop info_ptr)
G
Guy Schalnat 已提交
133
{
A
Andreas Dilger 已提交
134 135
   png_debug(1, "in png_read_info\n");
   /* save jump buffer and error functions */
A
Andreas Dilger 已提交
136 137
   /* If we haven't checked all of the PNG signature bytes, do so now. */
   if (png_ptr->sig_bytes < 8)
G
Guy Schalnat 已提交
138
   {
A
Andreas Dilger 已提交
139 140
      png_size_t num_checked = png_ptr->sig_bytes,
                 num_to_check = 8 - num_checked;
A
Andreas Dilger 已提交
141

A
Andreas Dilger 已提交
142
      png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);
A
Andreas Dilger 已提交
143 144 145 146 147 148 149 150 151 152
      png_ptr->sig_bytes = 8;

      if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
      {
         if (num_checked < 4 &&
             png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
            png_error(png_ptr, "Not a PNG file");
         else
            png_error(png_ptr, "PNG file corrupted by ASCII conversion");
      }
G
Guy Schalnat 已提交
153
   }
G
Guy Schalnat 已提交
154 155 156

   while (1)
   {
A
Andreas Dilger 已提交
157 158
      png_byte chunk_length[4];
      png_uint_32 length;
G
Guy Schalnat 已提交
159

A
Andreas Dilger 已提交
160 161
      png_read_data(png_ptr, chunk_length, 4);
      length = png_get_uint_32(chunk_length);
G
Guy Schalnat 已提交
162

A
Andreas Dilger 已提交
163 164 165
      png_reset_crc(png_ptr);
      png_crc_read(png_ptr, png_ptr->chunk_name, 4);

A
Andreas Dilger 已提交
166 167 168 169 170
      png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name);

      /* This should be a binary subdivision search or a hash for
       * matching the chunk name rather than a linear search.
       */
A
Andreas Dilger 已提交
171 172 173 174 175 176
      if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
         png_handle_IHDR(png_ptr, info_ptr, length);
      else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
         png_handle_PLTE(png_ptr, info_ptr, length);
      else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
         png_handle_IEND(png_ptr, info_ptr, length);
A
Andreas Dilger 已提交
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
      else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
      {
         if (!(png_ptr->mode & PNG_HAVE_IHDR))
            png_error(png_ptr, "Missing IHDR before IDAT");
         else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
                  !(png_ptr->mode & PNG_HAVE_PLTE))
            png_error(png_ptr, "Missing PLTE before IDAT");

         png_ptr->idat_size = length;
         png_ptr->mode |= PNG_HAVE_IDAT;
         break;
      }
#if defined(PNG_READ_bKGD_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
         png_handle_bKGD(png_ptr, info_ptr, length);
G
Guy Schalnat 已提交
192 193
#endif
#if defined(PNG_READ_cHRM_SUPPORTED)
A
Andreas Dilger 已提交
194 195
      else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
         png_handle_cHRM(png_ptr, info_ptr, length);
G
Guy Schalnat 已提交
196
#endif
A
Andreas Dilger 已提交
197 198 199
#if defined(PNG_READ_gAMA_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
         png_handle_gAMA(png_ptr, info_ptr, length);
G
Guy Schalnat 已提交
200 201
#endif
#if defined(PNG_READ_hIST_SUPPORTED)
A
Andreas Dilger 已提交
202 203
      else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
         png_handle_hIST(png_ptr, info_ptr, length);
G
Guy Schalnat 已提交
204
#endif
A
Andreas Dilger 已提交
205 206 207 208 209 210 211 212
#if defined(PNG_READ_oFFs_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
         png_handle_oFFs(png_ptr, info_ptr, length);
#endif
#if defined(PNG_READ_pCAL_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
         png_handle_pCAL(png_ptr, info_ptr, length);
#endif
G
Guy Schalnat 已提交
213
#if defined(PNG_READ_pHYs_SUPPORTED)
A
Andreas Dilger 已提交
214 215
      else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
         png_handle_pHYs(png_ptr, info_ptr, length);
G
Guy Schalnat 已提交
216
#endif
A
Andreas Dilger 已提交
217 218 219 220
#if defined(PNG_READ_sBIT_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
         png_handle_sBIT(png_ptr, info_ptr, length);
#endif
221 222 223 224
#if defined(PNG_READ_sRGB_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
         png_handle_sRGB(png_ptr, info_ptr, length);
#endif
A
Andreas Dilger 已提交
225 226 227
#if defined(PNG_READ_tEXt_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
         png_handle_tEXt(png_ptr, info_ptr, length);
G
Guy Schalnat 已提交
228 229
#endif
#if defined(PNG_READ_tIME_SUPPORTED)
A
Andreas Dilger 已提交
230 231
      else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
         png_handle_tIME(png_ptr, info_ptr, length);
G
Guy Schalnat 已提交
232
#endif
A
Andreas Dilger 已提交
233 234 235
#if defined(PNG_READ_tRNS_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
         png_handle_tRNS(png_ptr, info_ptr, length);
G
Guy Schalnat 已提交
236 237
#endif
#if defined(PNG_READ_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
238 239
      else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
         png_handle_zTXt(png_ptr, info_ptr, length);
G
Guy Schalnat 已提交
240
#endif
A
Andreas Dilger 已提交
241 242
      else
         png_handle_unknown(png_ptr, info_ptr, length);
G
Guy Schalnat 已提交
243 244 245
   }
}

A
Andreas Dilger 已提交
246
/* optional call to update the users info_ptr structure */
G
Guy Schalnat 已提交
247
void
A
Andreas Dilger 已提交
248
png_read_update_info(png_structp png_ptr, png_infop info_ptr)
G
Guy Schalnat 已提交
249
{
A
Andreas Dilger 已提交
250 251
   png_debug(1, "in png_read_update_info\n");
   /* save jump buffer and error functions */
G
Guy Schalnat 已提交
252
   if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
G
Guy Schalnat 已提交
253
      png_read_start_row(png_ptr);
A
Andreas Dilger 已提交
254
   png_read_transform_info(png_ptr, info_ptr);
G
Guy Schalnat 已提交
255 256
}

257 258 259 260 261
/* Initialize palette, background, etc, after transformations
 * are set, but before any reading takes place.  This allows
 * the user to obtail a gamma corrected palette, for example.
 * If the user doesn't call this, we will do it ourselves.
 */
G
Guy Schalnat 已提交
262
void
G
Guy Schalnat 已提交
263
png_start_read_image(png_structp png_ptr)
G
Guy Schalnat 已提交
264
{
A
Andreas Dilger 已提交
265 266
   png_debug(1, "in png_start_read_image\n");
   /* save jump buffer and error functions */
G
Guy Schalnat 已提交
267
   if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
G
Guy Schalnat 已提交
268
      png_read_start_row(png_ptr);
G
Guy Schalnat 已提交
269 270 271
}

void
G
Guy Schalnat 已提交
272
png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
G
Guy Schalnat 已提交
273 274
{
   int ret;
A
Andreas Dilger 已提交
275 276 277
   png_debug2(1, "in png_read_row (row %d, pass %d)\n",
      png_ptr->row_number, png_ptr->pass);
   /* save jump buffer and error functions */
G
Guy Schalnat 已提交
278
   if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
G
Guy Schalnat 已提交
279 280
      png_read_start_row(png_ptr);

G
Guy Schalnat 已提交
281
#if defined(PNG_READ_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
282 283 284 285 286 287 288 289
   /* if interlaced and we do not need a new row, combine row and return */
   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
   {
      switch (png_ptr->pass)
      {
         case 0:
            if (png_ptr->row_number & 7)
            {
A
Andreas Dilger 已提交
290
               if (dsp_row != NULL)
G
Guy Schalnat 已提交
291 292
                  png_combine_row(png_ptr, dsp_row,
                     png_pass_dsp_mask[png_ptr->pass]);
G
Guy Schalnat 已提交
293
               png_read_finish_row(png_ptr);
G
Guy Schalnat 已提交
294 295 296 297 298 299
               return;
            }
            break;
         case 1:
            if ((png_ptr->row_number & 7) || png_ptr->width < 5)
            {
A
Andreas Dilger 已提交
300
               if (dsp_row != NULL)
G
Guy Schalnat 已提交
301 302 303 304 305 306 307 308 309
                  png_combine_row(png_ptr, dsp_row,
                     png_pass_dsp_mask[png_ptr->pass]);
               png_read_finish_row(png_ptr);
               return;
            }
            break;
         case 2:
            if ((png_ptr->row_number & 7) != 4)
            {
A
Andreas Dilger 已提交
310
               if (dsp_row != NULL && (png_ptr->row_number & 4))
G
Guy Schalnat 已提交
311
                  png_combine_row(png_ptr, dsp_row,
G
Guy Schalnat 已提交
312 313 314 315 316 317 318 319
                     png_pass_dsp_mask[png_ptr->pass]);
               png_read_finish_row(png_ptr);
               return;
            }
            break;
         case 3:
            if ((png_ptr->row_number & 3) || png_ptr->width < 3)
            {
A
Andreas Dilger 已提交
320
               if (dsp_row != NULL)
G
Guy Schalnat 已提交
321 322 323 324 325 326 327 328
                  png_combine_row(png_ptr, dsp_row,
                     png_pass_dsp_mask[png_ptr->pass]);
               png_read_finish_row(png_ptr);
               return;
            }
            break;
         case 4:
            if ((png_ptr->row_number & 3) != 2)
G
Guy Schalnat 已提交
329
            {
A
Andreas Dilger 已提交
330
               if (dsp_row != NULL && (png_ptr->row_number & 2))
G
Guy Schalnat 已提交
331 332 333 334 335 336 337 338 339
                  png_combine_row(png_ptr, dsp_row,
                     png_pass_dsp_mask[png_ptr->pass]);
               png_read_finish_row(png_ptr);
               return;
            }
            break;
         case 5:
            if ((png_ptr->row_number & 1) || png_ptr->width < 2)
            {
A
Andreas Dilger 已提交
340
               if (dsp_row != NULL)
G
Guy Schalnat 已提交
341 342 343 344 345 346
                  png_combine_row(png_ptr, dsp_row,
                     png_pass_dsp_mask[png_ptr->pass]);
               png_read_finish_row(png_ptr);
               return;
            }
            break;
G
Guy Schalnat 已提交
347
         case 6:
G
Guy Schalnat 已提交
348 349 350 351 352 353 354 355
            if (!(png_ptr->row_number & 1))
            {
               png_read_finish_row(png_ptr);
               return;
            }
            break;
      }
   }
G
Guy Schalnat 已提交
356
#endif
G
Guy Schalnat 已提交
357

G
Guy Schalnat 已提交
358 359
   if (!(png_ptr->mode & PNG_HAVE_IDAT))
      png_error(png_ptr, "Invalid attempt to read row data");
G
Guy Schalnat 已提交
360

A
Andreas Dilger 已提交
361 362
   png_ptr->zstream.next_out = png_ptr->row_buf;
   png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
G
Guy Schalnat 已提交
363 364
   do
   {
A
Andreas Dilger 已提交
365
      if (!(png_ptr->zstream.avail_in))
G
Guy Schalnat 已提交
366 367 368
      {
         while (!png_ptr->idat_size)
         {
A
Andreas Dilger 已提交
369
            png_byte chunk_length[4];
G
Guy Schalnat 已提交
370

A
Andreas Dilger 已提交
371
            png_crc_finish(png_ptr, 0);
G
Guy Schalnat 已提交
372

A
Andreas Dilger 已提交
373 374
            png_read_data(png_ptr, chunk_length, 4);
            png_ptr->idat_size = png_get_uint_32(chunk_length);
G
Guy Schalnat 已提交
375

A
Andreas Dilger 已提交
376 377 378 379
            png_reset_crc(png_ptr);
            png_crc_read(png_ptr, png_ptr->chunk_name, 4);
            if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
               png_error(png_ptr, "Not enough image data");
G
Guy Schalnat 已提交
380
         }
A
Andreas Dilger 已提交
381 382
         png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
         png_ptr->zstream.next_in = png_ptr->zbuf;
G
Guy Schalnat 已提交
383
         if (png_ptr->zbuf_size > png_ptr->idat_size)
A
Andreas Dilger 已提交
384
            png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
A
Andreas Dilger 已提交
385 386
         png_crc_read(png_ptr, png_ptr->zbuf,
            (png_size_t)png_ptr->zstream.avail_in);
A
Andreas Dilger 已提交
387
         png_ptr->idat_size -= png_ptr->zstream.avail_in;
G
Guy Schalnat 已提交
388
      }
A
Andreas Dilger 已提交
389
      ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
G
Guy Schalnat 已提交
390 391
      if (ret == Z_STREAM_END)
      {
A
Andreas Dilger 已提交
392
         if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in ||
G
Guy Schalnat 已提交
393
            png_ptr->idat_size)
G
Guy Schalnat 已提交
394
            png_error(png_ptr, "Extra compressed data");
A
Andreas Dilger 已提交
395
         png_ptr->mode |= PNG_AFTER_IDAT;
G
Guy Schalnat 已提交
396
         png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
G
Guy Schalnat 已提交
397
         break;
G
Guy Schalnat 已提交
398 399
      }
      if (ret != Z_OK)
A
Andreas Dilger 已提交
400
         png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
G
Guy Schalnat 已提交
401
                   "Decompression error");
A
Andreas Dilger 已提交
402 403

   } while (png_ptr->zstream.avail_out);
G
Guy Schalnat 已提交
404 405 406 407 408 409 410 411 412

   png_ptr->row_info.color_type = png_ptr->color_type;
   png_ptr->row_info.width = png_ptr->iwidth;
   png_ptr->row_info.channels = png_ptr->channels;
   png_ptr->row_info.bit_depth = png_ptr->bit_depth;
   png_ptr->row_info.pixel_depth = png_ptr->pixel_depth;
   png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
      (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);

G
Guy Schalnat 已提交
413 414 415
   png_read_filter_row(png_ptr, &(png_ptr->row_info),
      png_ptr->row_buf + 1, png_ptr->prev_row + 1,
      (int)(png_ptr->row_buf[0]));
G
Guy Schalnat 已提交
416

A
Andreas Dilger 已提交
417
   png_memcpy(png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1);
G
Guy Schalnat 已提交
418 419 420 421

   if (png_ptr->transformations)
      png_do_read_transformations(png_ptr);

G
Guy Schalnat 已提交
422
#if defined(PNG_READ_INTERLACING_SUPPORTED)
G
Guy Schalnat 已提交
423 424 425 426 427 428
   /* blow up interlaced rows to full size */
   if (png_ptr->interlaced &&
      (png_ptr->transformations & PNG_INTERLACE))
   {
      if (png_ptr->pass < 6)
         png_do_read_interlace(&(png_ptr->row_info),
A
Andreas Dilger 已提交
429
            png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
G
Guy Schalnat 已提交
430

A
Andreas Dilger 已提交
431
      if (dsp_row != NULL)
G
Guy Schalnat 已提交
432 433
         png_combine_row(png_ptr, dsp_row,
            png_pass_dsp_mask[png_ptr->pass]);
A
Andreas Dilger 已提交
434
      if (row != NULL)
G
Guy Schalnat 已提交
435 436 437 438
         png_combine_row(png_ptr, row,
            png_pass_mask[png_ptr->pass]);
   }
   else
G
Guy Schalnat 已提交
439
#endif
G
Guy Schalnat 已提交
440
   {
A
Andreas Dilger 已提交
441
      if (row != NULL)
G
Guy Schalnat 已提交
442
         png_combine_row(png_ptr, row, 0xff);
A
Andreas Dilger 已提交
443
      if (dsp_row != NULL)
G
Guy Schalnat 已提交
444 445 446 447 448
         png_combine_row(png_ptr, dsp_row, 0xff);
   }
   png_read_finish_row(png_ptr);
}

A
Andreas Dilger 已提交
449
/* Read one or more rows of image data.  If the image is interlaced,
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
 * and png_set_interlace_handling() has been called, the rows need to
 * contain the contents of the rows from the previous pass.  If the
 * image has alpha or transparency, and png_handle_alpha() has been
 * called, the rows contents must be initialized to the contents of the
 * screen.
 * 
 * "row" holds the actual image, and pixels are placed in it
 * as they arrive.  If the image is displayed after each pass, it will
 * appear to "sparkle" in.  "display_row" can be used to display a
 * "chunky" progressive image, with finer detail added as it becomes
 * available.  If you do not want this "chunky" display, you may pass
 * NULL for display_row.  If you do not want the sparkle display, and
 * you have not called png_handle_alpha(), you may pass NULL for rows.
 * If you have called png_handle_alpha(), and the image has either an
 * alpha channel or a transparency chunk, you must provide a buffer for
 * rows.  In this case, you do not have to provide a display_row buffer
 * also, but you may.  If the image is not interlaced, or if you have
 * not called png_set_interlace_handling(), the display_row buffer will
 * be ignored, so pass NULL to it.
 */
G
Guy Schalnat 已提交
470

G
Guy Schalnat 已提交
471
void
G
Guy Schalnat 已提交
472
png_read_rows(png_structp png_ptr, png_bytepp row,
G
Guy Schalnat 已提交
473
   png_bytepp display_row, png_uint_32 num_rows)
G
Guy Schalnat 已提交
474
{
G
Guy Schalnat 已提交
475 476 477
   png_uint_32 i;
   png_bytepp rp;
   png_bytepp dp;
G
Guy Schalnat 已提交
478

A
Andreas Dilger 已提交
479 480
   png_debug(1, "in png_read_rows\n");
   /* save jump buffer and error functions */
G
Guy Schalnat 已提交
481 482 483 484
   rp = row;
   dp = display_row;
   for (i = 0; i < num_rows; i++)
   {
G
Guy Schalnat 已提交
485 486
      png_bytep rptr;
      png_bytep dptr;
G
Guy Schalnat 已提交
487

A
Andreas Dilger 已提交
488
      if (rp != NULL)
G
Guy Schalnat 已提交
489 490 491
         rptr = *rp;
      else
         rptr = NULL;
A
Andreas Dilger 已提交
492
      if (dp != NULL)
G
Guy Schalnat 已提交
493 494 495 496
         dptr = *dp;
      else
         dptr = NULL;
      png_read_row(png_ptr, rptr, dptr);
A
Andreas Dilger 已提交
497
      if (row != NULL)
G
Guy Schalnat 已提交
498
         rp++;
A
Andreas Dilger 已提交
499
      if (display_row != NULL)
G
Guy Schalnat 已提交
500 501
         dp++;
   }
G
Guy Schalnat 已提交
502 503
}

A
Andreas Dilger 已提交
504
/* Read the entire image.  If the image has an alpha channel or a tRNS
505 506 507 508 509 510 511 512 513
 * chunk, and you have called png_handle_alpha(), you will need to
 * initialize the image to the current image that PNG will be overlaying.
 * We set the num_rows again here, in case it was incorrectly set in
 * png_read_start_row() by a call to png_read_update_info() or
 * png_start_read_image() if png_set_interlace_handling() wasn't called
 * prior to either of these functions like it should have been.  You can
 * only call this function once.  If you desire to have an image for
 * each pass of a interlaced image, use png_read_rows() instead.
 */
G
Guy Schalnat 已提交
514
void
G
Guy Schalnat 已提交
515
png_read_image(png_structp png_ptr, png_bytepp image)
G
Guy Schalnat 已提交
516 517 518
{
   png_uint_32 i;
   int pass, j;
G
Guy Schalnat 已提交
519
   png_bytepp rp;
G
Guy Schalnat 已提交
520

A
Andreas Dilger 已提交
521 522
   png_debug(1, "in png_read_image\n");
   /* save jump buffer and error functions */
G
Guy Schalnat 已提交
523
   pass = png_set_interlace_handling(png_ptr);
G
Guy Schalnat 已提交
524 525 526

   png_ptr->num_rows = png_ptr->height; /* Make sure this is set correctly */

G
Guy Schalnat 已提交
527 528 529 530 531 532 533 534 535 536 537
   for (j = 0; j < pass; j++)
   {
      rp = image;
      for (i = 0; i < png_ptr->height; i++)
      {
         png_read_row(png_ptr, *rp, NULL);
         rp++;
      }
   }
}

A
Andreas Dilger 已提交
538
/* Read the end of the PNG file.  Will not read past the end of the
539 540 541
 * file, will verify the end is accurate, and will read any comments
 * or time information at the end of the file, if info is not NULL.
 */
G
Guy Schalnat 已提交
542
void
A
Andreas Dilger 已提交
543
png_read_end(png_structp png_ptr, png_infop info_ptr)
G
Guy Schalnat 已提交
544
{
A
Andreas Dilger 已提交
545
   png_byte chunk_length[4];
G
Guy Schalnat 已提交
546 547
   png_uint_32 length;

A
Andreas Dilger 已提交
548 549 550
   png_debug(1, "in png_read_end\n");
   /* save jump buffer and error functions */
   png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */
G
Guy Schalnat 已提交
551 552 553

   do
   {
A
Andreas Dilger 已提交
554 555
      png_read_data(png_ptr, chunk_length, 4);
      length = png_get_uint_32(chunk_length);
G
Guy Schalnat 已提交
556

A
Andreas Dilger 已提交
557 558 559
      png_reset_crc(png_ptr);
      png_crc_read(png_ptr, png_ptr->chunk_name, 4);

A
Andreas Dilger 已提交
560 561
      png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name);

A
Andreas Dilger 已提交
562 563
      if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
         png_handle_IHDR(png_ptr, info_ptr, length);
A
Andreas Dilger 已提交
564 565 566 567 568 569 570 571 572 573
      else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
      {
         /* Zero length IDATs are legal after the last IDAT has been
          * read, but not after other chunks have been read.
          */
         if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT)
            png_error(png_ptr, "Too many IDAT's found");
         else
            png_crc_finish(png_ptr, 0);
      }
A
Andreas Dilger 已提交
574 575
      else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
         png_handle_PLTE(png_ptr, info_ptr, length);
A
Andreas Dilger 已提交
576 577 578
      else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
         png_handle_IEND(png_ptr, info_ptr, length);
#if defined(PNG_READ_bKGD_SUPPORTED)
A
Andreas Dilger 已提交
579 580
      else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
         png_handle_bKGD(png_ptr, info_ptr, length);
A
Andreas Dilger 已提交
581 582 583 584 585 586 587 588 589 590
#endif
#if defined(PNG_READ_cHRM_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
         png_handle_cHRM(png_ptr, info_ptr, length);
#endif
#if defined(PNG_READ_gAMA_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
         png_handle_gAMA(png_ptr, info_ptr, length);
#endif
#if defined(PNG_READ_hIST_SUPPORTED)
A
Andreas Dilger 已提交
591 592
      else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
         png_handle_hIST(png_ptr, info_ptr, length);
A
Andreas Dilger 已提交
593 594
#endif
#if defined(PNG_READ_oFFs_SUPPORTED)
A
Andreas Dilger 已提交
595 596
      else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
         png_handle_oFFs(png_ptr, info_ptr, length);
A
Andreas Dilger 已提交
597 598 599 600 601 602 603 604 605 606 607 608
#endif
#if defined(PNG_READ_pCAL_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
         png_handle_pCAL(png_ptr, info_ptr, length);
#endif
#if defined(PNG_READ_pHYs_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
         png_handle_pHYs(png_ptr, info_ptr, length);
#endif
#if defined(PNG_READ_sBIT_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
         png_handle_sBIT(png_ptr, info_ptr, length);
G
Guy Schalnat 已提交
609
#endif
610 611 612 613
#if defined(PNG_READ_sRGB_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
         png_handle_sRGB(png_ptr, info_ptr, length);
#endif
G
Guy Schalnat 已提交
614
#if defined(PNG_READ_tEXt_SUPPORTED)
A
Andreas Dilger 已提交
615 616
      else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
         png_handle_tEXt(png_ptr, info_ptr, length);
G
Guy Schalnat 已提交
617
#endif
A
Andreas Dilger 已提交
618 619 620 621 622 623 624 625
#if defined(PNG_READ_tIME_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
         png_handle_tIME(png_ptr, info_ptr, length);
#endif
#if defined(PNG_READ_tRNS_SUPPORTED)
      else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
         png_handle_tRNS(png_ptr, info_ptr, length);
#endif
G
Guy Schalnat 已提交
626
#if defined(PNG_READ_zTXt_SUPPORTED)
A
Andreas Dilger 已提交
627 628
      else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
         png_handle_zTXt(png_ptr, info_ptr, length);
G
Guy Schalnat 已提交
629
#endif
G
Guy Schalnat 已提交
630
      else
A
Andreas Dilger 已提交
631 632
         png_handle_unknown(png_ptr, info_ptr, length);
   } while (!(png_ptr->mode & PNG_HAVE_IEND));
G
Guy Schalnat 已提交
633 634 635 636
}

/* free all memory used by the read */
void
G
Guy Schalnat 已提交
637
png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr,
A
Andreas Dilger 已提交
638
   png_infopp end_info_ptr_ptr)
G
Guy Schalnat 已提交
639 640
{
   png_structp png_ptr = NULL;
A
Andreas Dilger 已提交
641
   png_infop info_ptr = NULL, end_info_ptr = NULL;
G
Guy Schalnat 已提交
642

A
Andreas Dilger 已提交
643 644 645
   png_debug(1, "in png_destroy_read_struct\n");
   /* save jump buffer and error functions */
   if (png_ptr_ptr != NULL)
G
Guy Schalnat 已提交
646 647
      png_ptr = *png_ptr_ptr;

A
Andreas Dilger 已提交
648
   if (info_ptr_ptr != NULL)
G
Guy Schalnat 已提交
649 650
      info_ptr = *info_ptr_ptr;

A
Andreas Dilger 已提交
651
   if (end_info_ptr_ptr != NULL)
A
Andreas Dilger 已提交
652
      end_info_ptr = *end_info_ptr_ptr;
G
Guy Schalnat 已提交
653

A
Andreas Dilger 已提交
654
   png_read_destroy(png_ptr, info_ptr, end_info_ptr);
G
Guy Schalnat 已提交
655

A
Andreas Dilger 已提交
656
   if (info_ptr != NULL)
G
Guy Schalnat 已提交
657
   {
658 659 660
#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
      png_free(png_ptr, info_ptr->text);
#endif
A
Andreas Dilger 已提交
661
      png_destroy_struct((png_voidp)info_ptr);
G
Guy Schalnat 已提交
662 663 664
      *info_ptr_ptr = (png_infop)NULL;
   }

A
Andreas Dilger 已提交
665
   if (end_info_ptr != NULL)
G
Guy Schalnat 已提交
666
   {
667 668 669
#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
      png_free(png_ptr, info_ptr->text);
#endif
A
Andreas Dilger 已提交
670 671
      png_destroy_struct((png_voidp)end_info_ptr);
      *end_info_ptr_ptr = (png_infop)NULL;
G
Guy Schalnat 已提交
672 673
   }

A
Andreas Dilger 已提交
674
   if (png_ptr != NULL)
G
Guy Schalnat 已提交
675
   {
A
Andreas Dilger 已提交
676
      png_destroy_struct((png_voidp)png_ptr);
G
Guy Schalnat 已提交
677 678 679 680
      *png_ptr_ptr = (png_structp)NULL;
   }
}

A
Andreas Dilger 已提交
681
/* free all memory used by the read (old method) */
G
Guy Schalnat 已提交
682
void
A
Andreas Dilger 已提交
683
png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr)
G
Guy Schalnat 已提交
684 685
{
   jmp_buf tmp_jmp;
G
Guy Schalnat 已提交
686 687 688
   png_error_ptr error_fn;
   png_error_ptr warning_fn;
   png_voidp error_ptr;
G
Guy Schalnat 已提交
689

A
Andreas Dilger 已提交
690 691 692
   png_debug(1, "in png_read_destroy\n");
   /* save jump buffer and error functions */
   if (info_ptr != NULL)
A
Andreas Dilger 已提交
693
      png_info_destroy(png_ptr, info_ptr);
G
Guy Schalnat 已提交
694

A
Andreas Dilger 已提交
695
   if (end_info_ptr != NULL)
A
Andreas Dilger 已提交
696
      png_info_destroy(png_ptr, end_info_ptr);
G
Guy Schalnat 已提交
697

A
Andreas Dilger 已提交
698 699 700
   png_free(png_ptr, png_ptr->zbuf);
   png_free(png_ptr, png_ptr->row_buf);
   png_free(png_ptr, png_ptr->prev_row);
G
Guy Schalnat 已提交
701
#if defined(PNG_READ_DITHER_SUPPORTED)
A
Andreas Dilger 已提交
702 703
   png_free(png_ptr, png_ptr->palette_lookup);
   png_free(png_ptr, png_ptr->dither_index);
G
Guy Schalnat 已提交
704 705
#endif
#if defined(PNG_READ_GAMMA_SUPPORTED)
A
Andreas Dilger 已提交
706
   png_free(png_ptr, png_ptr->gamma_table);
G
Guy Schalnat 已提交
707 708
#endif
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
A
Andreas Dilger 已提交
709 710
   png_free(png_ptr, png_ptr->gamma_from_1);
   png_free(png_ptr, png_ptr->gamma_to_1);
G
Guy Schalnat 已提交
711
#endif
A
Andreas Dilger 已提交
712 713
   if (png_ptr->flags & PNG_FLAG_FREE_PALETTE)
      png_free(png_ptr, png_ptr->palette);
G
Guy Schalnat 已提交
714
#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_bKGD_SUPPORTED)
A
Andreas Dilger 已提交
715 716
   if (png_ptr->flags & PNG_FLAG_FREE_TRANS)
      png_free(png_ptr, png_ptr->trans);
G
Guy Schalnat 已提交
717 718
#endif
#if defined(PNG_READ_hIST_SUPPORTED)
A
Andreas Dilger 已提交
719 720
   if (png_ptr->flags & PNG_FLAG_FREE_HIST)
      png_free(png_ptr, png_ptr->hist);
G
Guy Schalnat 已提交
721 722
#endif
#if defined(PNG_READ_GAMMA_SUPPORTED)
A
Andreas Dilger 已提交
723
   if (png_ptr->gamma_16_table != NULL)
G
Guy Schalnat 已提交
724
   {
725
      int i;
G
Guy Schalnat 已提交
726 727
      for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
      {
A
Andreas Dilger 已提交
728
         png_free(png_ptr, png_ptr->gamma_16_table[i]);
G
Guy Schalnat 已提交
729
      }
G
Guy Schalnat 已提交
730
   }
G
Guy Schalnat 已提交
731 732
#endif
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
A
Andreas Dilger 已提交
733
   png_free(png_ptr, png_ptr->gamma_16_table);
A
Andreas Dilger 已提交
734
   if (png_ptr->gamma_16_from_1 != NULL)
G
Guy Schalnat 已提交
735
   {
736
      int i;
G
Guy Schalnat 已提交
737
      for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
G
Guy Schalnat 已提交
738
      {
A
Andreas Dilger 已提交
739
         png_free(png_ptr, png_ptr->gamma_16_from_1[i]);
G
Guy Schalnat 已提交
740 741
      }
   }
A
Andreas Dilger 已提交
742
   png_free(png_ptr, png_ptr->gamma_16_from_1);
A
Andreas Dilger 已提交
743
   if (png_ptr->gamma_16_to_1 != NULL)
G
Guy Schalnat 已提交
744
   {
745
      int i;
G
Guy Schalnat 已提交
746 747
      for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
      {
A
Andreas Dilger 已提交
748
         png_free(png_ptr, png_ptr->gamma_16_to_1[i]);
G
Guy Schalnat 已提交
749
      }
G
Guy Schalnat 已提交
750
   }
A
Andreas Dilger 已提交
751
   png_free(png_ptr, png_ptr->gamma_16_to_1);
G
Guy Schalnat 已提交
752
#endif
G
Guy Schalnat 已提交
753

A
Andreas Dilger 已提交
754
   inflateEnd(&png_ptr->zstream);
G
Guy Schalnat 已提交
755
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
A
Andreas Dilger 已提交
756
   png_free(png_ptr, png_ptr->save_buffer);
G
Guy Schalnat 已提交
757
#endif
G
Guy Schalnat 已提交
758 759 760 761

   /* Save the important info out of the png_struct, in case it is
    * being used again.
    */
G
Guy Schalnat 已提交
762
   png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
G
Guy Schalnat 已提交
763 764 765 766 767

   error_fn = png_ptr->error_fn;
   warning_fn = png_ptr->warning_fn;
   error_ptr = png_ptr->error_ptr;

G
Guy Schalnat 已提交
768
   png_memset(png_ptr, 0, sizeof (png_struct));
G
Guy Schalnat 已提交
769 770 771 772 773

   png_ptr->error_fn = error_fn;
   png_ptr->warning_fn = warning_fn;
   png_ptr->error_ptr = error_ptr;

G
Guy Schalnat 已提交
774
   png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
G
Guy Schalnat 已提交
775
}