aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSireesh Tripurari <sireesh.tripurari@linaro.org>2014-05-09 15:39:12 +0530
committerSireesh Tripurari <sireesh.tripurari@linaro.org>2014-05-09 12:02:04 +0000
commitb0277d0706e596e9a1dd889903f8ceb2680bcadb (patch)
treee0d91a166486805affa71e8cb1b92fa073b06776
parentb478e66e7c2621eef5f465e4629ce642db00716b (diff)
downloadandroid_external_libpng-b0277d0706e596e9a1dd889903f8ceb2680bcadb.tar.gz
android_external_libpng-b0277d0706e596e9a1dd889903f8ceb2680bcadb.tar.bz2
android_external_libpng-b0277d0706e596e9a1dd889903f8ceb2680bcadb.zip
libpng 1.6.10 - Merge seekable png patch
Change-Id: I3aa6d8775b884f719375c5aaa458a5c27c120b38
-rw-r--r--png.h18
-rw-r--r--pngpriv.h9
-rw-r--r--pngread.c167
-rw-r--r--pngrio.c25
-rw-r--r--pngrutil.c57
-rw-r--r--pngstruct.h53
6 files changed, 328 insertions, 1 deletions
diff --git a/png.h b/png.h
index 16d3299..57141d5 100644
--- a/png.h
+++ b/png.h
@@ -901,6 +901,10 @@ typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32,
typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32,
int));
+#ifdef PNG_INDEX_SUPPORTED
+typedef PNG_CALLBACK(void, *png_seek_ptr, (png_structp, png_uint_32));
+#endif
+
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
@@ -1887,6 +1891,20 @@ PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr,
PNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr,
png_inforp info_ptr, int freer, png_uint_32 mask));
+#ifdef PNG_INDEX_SUPPORTED
+/* Build image index for partial image decoding. */
+PNG_EXPORT(300, void, png_build_index, (png_structp png_ptr));
+PNG_EXPORT(301, void, png_configure_decoder,
+ (png_structp png_ptr, int *row_offset, int pass));
+/* Set the data seek function with a user supplied one.
+ * REQUIRED by partial image decode.
+ */
+PNG_EXPORT(302, void, png_set_seek_fn, (png_structp png_ptr,
+ png_seek_ptr seek_data_fn));
+/* Update the decoder status to the given pass */
+PNG_EXPORT(303, void, png_set_interlaced_pass, (png_structp png_ptr, int pass));
+#endif
+
/* Assignments for png_data_freer */
#define PNG_DESTROY_WILL_FREE_DATA 1
#define PNG_SET_WILL_FREE_DATA 1
diff --git a/pngpriv.h b/pngpriv.h
index a3fd1a4..8ced0f7 100644
--- a/pngpriv.h
+++ b/pngpriv.h
@@ -1928,6 +1928,15 @@ PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon,
(png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
#endif
+#ifdef PNG_INDEX_SUPPORTED
+PNG_INTERNAL_FUNCTION(void, png_seek_data, (png_structp png_ptr,
+ png_uint_32 length), PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(int, png_opt_crc_finish,(png_structrp png_ptr,
+ png_uint_32 skip), PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void, png_set_interlaced_pass,(png_structrp png_ptr,
+ int pass), PNG_EMPTY);
+#endif
+
/* Maintainer: Put new private prototypes here ^ */
#include "pngdebug.h"
diff --git a/pngread.c b/pngread.c
index cd9ab58..2a6ffbe 100644
--- a/pngread.c
+++ b/pngread.c
@@ -73,6 +73,10 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
* required.
*/
png_set_read_fn(png_ptr, NULL, NULL);
+
+#ifdef PNG_INDEX_SUPPORTED
+ png_ptr->index = NULL;
+#endif
}
return png_ptr;
@@ -262,6 +266,11 @@ png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
if (png_ptr != NULL)
{
+#ifdef PNG_INDEX_SUPPORTED
+ if (png_ptr->index) {
+ png_read_start_row(png_ptr);
+ }
+#endif
if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)
{
png_read_start_row(png_ptr);
@@ -272,11 +281,12 @@ png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
PNG_UNUSED(info_ptr)
# endif
}
-
+#ifndef PNG_INDEX_SUPPORTED
/* New in 1.6.0 this avoids the bug of doing the initializations twice */
else
png_app_error(png_ptr,
"png_read_update_info/png_start_read_image: duplicate call");
+#endif
}
}
@@ -671,6 +681,142 @@ png_read_rows(png_structrp png_ptr, png_bytepp row,
}
#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
+#ifdef PNG_INDEX_SUPPORTED
+#define IDAT_HEADER_SIZE 8
+
+/* Set the png read position to a new position based on idat_position and
+ * offset.
+ */
+void
+png_set_read_offset(png_structp png_ptr,
+ png_uint_32 idat_position, png_uint_32 bytes_left)
+{
+ png_seek_data(png_ptr, idat_position);
+ png_ptr->idat_size = png_read_chunk_header(png_ptr);
+
+ // We need to add back IDAT_HEADER_SIZE because in zlib's perspective,
+ // IDAT_HEADER in PNG is already stripped out.
+ png_seek_data(png_ptr, idat_position + IDAT_HEADER_SIZE + png_ptr->idat_size - bytes_left);
+ png_ptr->idat_size = bytes_left;
+}
+
+/* Configure png decoder to decode the pass starting from *row.
+ * The requested row may be adjusted to align with an indexing row.
+ * The actual row for the decoder to start its decoding will be returned in
+ * *row.
+ */
+void PNGAPI
+png_configure_decoder(png_structp png_ptr, int *row, int pass)
+{
+ png_indexp index = png_ptr->index;
+ int n = *row / index->step[pass];
+ png_line_indexp line_index = index->pass_line_index[pass][n];
+
+ // Adjust row to an indexing row.
+ *row = n * index->step[pass];
+ png_ptr->row_number = *row;
+
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+ if (png_ptr->interlaced)
+ png_set_interlaced_pass(png_ptr, pass);
+#endif
+
+ long row_byte_length =
+ PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1;
+
+ inflateEnd(&png_ptr->zstream);
+ inflateCopy(&png_ptr->zstream, line_index->z_state);
+
+ // Set the png read position to line_index.
+ png_set_read_offset(png_ptr, line_index->stream_idat_position,
+ line_index->bytes_left_in_idat);
+ memcpy(png_ptr->prev_row, line_index->prev_row, row_byte_length);
+ png_ptr->zstream.avail_in = 0;
+}
+
+/* Build the line index and store the index in png_ptr->index.
+ */
+void PNGAPI
+png_build_index(png_structp png_ptr)
+{
+ // number of rows in a 8x8 block for each interlaced pass.
+ int number_rows_in_pass[7] = {1, 1, 1, 2, 2, 4, 4};
+
+ int ret;
+ png_uint_32 i, j;
+ png_bytep rp;
+ int p, pass_number = 1;
+
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+ pass_number = png_set_interlace_handling(png_ptr);
+#endif
+
+ if (png_ptr == NULL)
+ return;
+
+ png_read_start_row(png_ptr);
+
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+ if (!png_ptr->interlaced)
+#endif
+ {
+ number_rows_in_pass[0] = 8;
+ }
+
+ rp = png_malloc(png_ptr, png_ptr->rowbytes);
+
+ png_indexp index = png_malloc(png_ptr, sizeof(png_index));
+ png_ptr->index = index;
+
+ index->stream_idat_position = png_ptr->total_data_read - IDAT_HEADER_SIZE;
+
+ // Set the default size of index in each pass to 0,
+ // so that we can free index correctly in png_destroy_read_struct.
+ for (p = 0; p < 7; p++)
+ index->size[p] = 0;
+
+ for (p = 0; p < pass_number; p++)
+ {
+ // We adjust the index step in each pass to make sure each pass
+ // has roughly the same size of index.
+ // This way, we won't consume to much memory in recording index.
+ index->step[p] = INDEX_SAMPLE_SIZE * (8 / number_rows_in_pass[p]);
+ index->size[p] =
+ (png_ptr->height + index->step[p] - 1) / index->step[p];
+ index->pass_line_index[p] =
+ png_malloc(png_ptr, index->size[p] * sizeof(png_line_indexp));
+
+ // Get the row_byte_length seen by the filter. This value may be
+ // different from the row_byte_length of a bitmap in the case of
+ // color palette mode.
+ int row_byte_length =
+ PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1;
+
+ // Now, we record index for each indexing row.
+ for (i = 0; i < index->size[p]; i++)
+ {
+ png_line_indexp line_index = png_malloc(png_ptr, sizeof(png_line_index));
+ index->pass_line_index[p][i] = line_index;
+
+ line_index->z_state = png_malloc(png_ptr, sizeof(z_stream));
+ inflateCopy(line_index->z_state, &png_ptr->zstream);
+ line_index->prev_row = png_malloc(png_ptr, row_byte_length);
+ memcpy(line_index->prev_row, png_ptr->prev_row, row_byte_length);
+ line_index->stream_idat_position = index->stream_idat_position;
+ line_index->bytes_left_in_idat = png_ptr->idat_size + png_ptr->zstream.avail_in;
+
+ // Skip the "step" number of rows to the next indexing row.
+ for (j = 0; j < index->step[p] &&
+ i * index->step[p] + j < png_ptr->height; j++)
+ {
+ png_read_row(png_ptr, rp, NULL);
+ }
+ }
+ }
+ png_free(png_ptr, rp);
+}
+#endif
+
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
/* Read the entire image. If the image has an alpha channel or a tRNS
* chunk, and you have called png_handle_alpha()[*], you will need to
@@ -954,6 +1100,25 @@ png_read_destroy(png_structrp png_ptr)
png_free(png_ptr, png_ptr->chunk_list);
#endif
+#ifdef PNG_INDEX_SUPPORTED
+ if (png_ptr->index) {
+ unsigned int i, p;
+ png_indexp index = png_ptr->index;
+ for (p = 0; p < 7; p++) {
+ for (i = 0; i < index->size[p]; i++) {
+ inflateEnd(index->pass_line_index[p][i]->z_state);
+ png_free(png_ptr, index->pass_line_index[p][i]->z_state);
+ png_free(png_ptr, index->pass_line_index[p][i]->prev_row);
+ png_free(png_ptr, index->pass_line_index[p][i]);
+ }
+ if (index->size[p] != 0) {
+ png_free(png_ptr, index->pass_line_index[p]);
+ }
+ }
+ png_free(png_ptr, index);
+ }
+#endif
+
/* NOTE: the 'setjmp' buffer may still be allocated and the memory and error
* callbacks are still set at this point. They are required to complete the
* destruction of the png_struct itself.
diff --git a/pngrio.c b/pngrio.c
index d75ac5b..429dffd 100644
--- a/pngrio.c
+++ b/pngrio.c
@@ -38,7 +38,21 @@ png_read_data(png_structrp png_ptr, png_bytep data, png_size_t length)
else
png_error(png_ptr, "Call to NULL read function");
+#ifdef PNG_INDEX_SUPPORTED
+ png_ptr->total_data_read += length;
+#endif
+}
+
+#ifdef PNG_INDEX_SUPPORTED
+void /* PRIVATE */
+png_seek_data(png_structp png_ptr, png_uint_32 offset)
+{
+ if (png_ptr->seek_data_fn != NULL)
+ (*(png_ptr->seek_data_fn))(png_ptr, offset);
+ else
+ png_error(png_ptr, "Call to NULL seek function");
}
+#endif
#ifdef PNG_STDIO_SUPPORTED
/* This is the function that does the actual reading of data. If you are
@@ -117,4 +131,15 @@ png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr,
png_ptr->output_flush_fn = NULL;
#endif
}
+
+#ifdef PNG_INDEX_SUPPORTED
+void PNGAPI
+png_set_seek_fn(png_structp png_ptr, png_seek_ptr seek_data_fn)
+{
+ if (png_ptr == NULL)
+ return;
+ png_ptr->seek_data_fn = seek_data_fn;
+}
+#endif
+
#endif /* PNG_READ_SUPPORTED */
diff --git a/pngrutil.c b/pngrutil.c
index 98e9524..9638bed 100644
--- a/pngrutil.c
+++ b/pngrutil.c
@@ -235,6 +235,33 @@ png_crc_finish(png_structrp png_ptr, png_uint_32 skip)
return (0);
}
+#ifdef PNG_INDEX_SUPPORTED
+int /* PRIVATE */
+png_opt_crc_finish(png_structrp png_ptr, png_uint_32 skip)
+{
+ while (skip > 0)
+ {
+ png_uint_32 len;
+ png_byte tmpbuf[PNG_INFLATE_BUF_SIZE];
+
+ len = (sizeof tmpbuf);
+ if (len > skip)
+ len = skip;
+ skip -= len;
+
+ png_crc_read(png_ptr, tmpbuf, len);
+ }
+
+ if (png_crc_error(png_ptr))
+ {
+ png_chunk_warning(png_ptr, "CRC error");
+ return (1);
+ }
+
+ return (0);
+}
+#endif
+
/* Compare the CRC stored in the PNG file with that calculated by libpng from
* the data it has read thus far.
*/
@@ -3957,6 +3984,12 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
while (png_ptr->idat_size == 0)
{
+#ifdef PNG_INDEX_SUPPORTED
+ if (png_ptr->index) {
+ png_opt_crc_finish(png_ptr, 0);
+ png_ptr->index->stream_idat_position = png_ptr->total_data_read;
+ } else
+#endif
png_crc_finish(png_ptr, 0);
png_ptr->idat_size = png_read_chunk_header(png_ptr);
@@ -4036,6 +4069,9 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
}
if (ret != Z_OK)
+#ifdef PNG_INDEX_SUPPORTED
+ if (png_ptr->index && png_ptr->row_number != png_ptr->height - 1)
+#endif
{
png_zstream_error(png_ptr, ret);
@@ -4111,6 +4147,27 @@ png_read_finish_IDAT(png_structrp png_ptr)
}
}
+#ifdef PNG_INDEX_SUPPORTED
+void /* PRIVATE */
+png_set_interlaced_pass(png_structp png_ptr, int pass)
+{
+ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+ /* Start of interlace block */
+ PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+ /* Offset to next interlace block */
+ PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+ /* Start of interlace block in the y direction */
+ PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+ /* Offset to next interlace block in the y direction */
+ PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+ png_ptr->pass = pass;
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+}
+#endif
+
void /* PRIVATE */
png_read_finish_row(png_structrp png_ptr)
{
diff --git a/pngstruct.h b/pngstruct.h
index d58c028..e40e17d 100644
--- a/pngstruct.h
+++ b/pngstruct.h
@@ -141,6 +141,50 @@ typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp;
#define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags))
#endif /* COLORSPACE || GAMMA */
+#ifdef PNG_INDEX_SUPPORTED
+/* png_line_index_struct records an index point, where we impose an index point
+ * to be located at the beginning of a line for simplifying the implementation.
+ */
+typedef struct png_line_index_struct
+{
+ // state of the lz decoder
+ z_streamp z_state;
+
+ // the IDAT header position of the chunk, which the index point is in
+ png_uint_32 stream_idat_position;
+
+ // we intend to record the offset of the index point in the chunk,
+ // but we record the number of remaining bytes in the chunk after the
+ // index point. That's because PNG processes a chunk this way.
+ png_uint_32 bytes_left_in_idat;
+
+ // decompressed data of the previous row
+ png_bytep prev_row;
+} png_line_index;
+typedef png_line_index FAR * png_line_indexp;
+
+typedef struct png_index_struct
+{
+ // A temporary variable used when we build the index. The variable records
+ // the IDAT header position of the last chunk read in so far.
+ png_uint_32 stream_idat_position;
+
+ // line index information about each passes
+
+ // the number of index points in each pass
+ png_uint_32 size[7];
+
+ // the line span of two index points of each pass
+ png_uint_32 step[7];
+
+ // the index points of each pass
+ png_line_indexp *pass_line_index[7];
+} png_index;
+typedef png_index FAR * png_indexp;
+
+#define INDEX_SAMPLE_SIZE 254
+#endif
+
struct png_struct_def
{
#ifdef PNG_SETJMP_SUPPORTED
@@ -156,6 +200,9 @@ struct png_struct_def
png_voidp error_ptr; /* user supplied struct for error functions */
png_rw_ptr write_data_fn; /* function for writing output data */
png_rw_ptr read_data_fn; /* function for reading input data */
+#ifdef PNG_INDEX_SUPPORTED
+ png_seek_ptr seek_data_fn; /* function for seeking input data */
+#endif
png_voidp io_ptr; /* ptr to application struct for I/O functions */
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
@@ -485,5 +532,11 @@ struct png_struct_def
png_colorspace colorspace;
#endif
#endif
+
+#ifdef PNG_INDEX_SUPPORTED
+ png_indexp index;
+ png_uint_32 total_data_read;
+#endif
+
};
#endif /* PNGSTRUCT_H */