From 6b85c2896b7999560d28d14d340c8cd656cfbe1c Mon Sep 17 00:00:00 2001 From: Jason Hearne-McGuiness Date: Wed, 4 Sep 2013 03:16:16 +0100 Subject: [PATCH 1/2] Added ability to read some PNG chunk data from PNG files and display it in the file property dialog in the image tab. --- configure.ac.in | 5 + plugins/thunar-apr/Makefile.am | 2 + plugins/thunar-apr/thunar-apr-image-page.c | 86 +++- plugins/thunar-apr/thunar-apr-png-read-data.c | 539 ++++++++++++++++++++++++++ plugins/thunar-apr/thunar-apr-png-read-data.h | 113 ++++++ 5 files changed, 742 insertions(+), 3 deletions(-) create mode 100644 plugins/thunar-apr/thunar-apr-png-read-data.c create mode 100644 plugins/thunar-apr/thunar-apr-png-read-data.h diff --git a/configure.ac.in b/configure.ac.in index cc5bcba..573bd10 100644 --- a/configure.ac.in +++ b/configure.ac.in @@ -186,6 +186,11 @@ dnl ************************************** XDT_CHECK_OPTIONAL_PACKAGE([LIBNOTIFY], [libnotify], [0.4.0], [notifications], [Mount notification support], [yes]) +dnl ************************************** +dnl *** Optional support for libpng *** +dnl ************************************** +XDT_CHECK_OPTIONAL_PACKAGE([PNG], [libpng], [1.5], [png], [PNG Support], [yes]) + dnl ************************* dnl *** Check for gtk-doc *** dnl ************************* diff --git a/plugins/thunar-apr/Makefile.am b/plugins/thunar-apr/Makefile.am index 472228a..2f5affb 100644 --- a/plugins/thunar-apr/Makefile.am +++ b/plugins/thunar-apr/Makefile.am @@ -20,6 +20,8 @@ thunar_apr_la_SOURCES = \ thunar-apr-desktop-page.h \ thunar-apr-image-page.c \ thunar-apr-image-page.h \ + thunar-apr-png-read-data.c \ + thunar-apr-png-read-data.h \ thunar-apr-plugin.c \ thunar-apr-private.c \ thunar-apr-private.h \ diff --git a/plugins/thunar-apr/thunar-apr-image-page.c b/plugins/thunar-apr/thunar-apr-image-page.c index 50be5eb..cdc3b43 100644 --- a/plugins/thunar-apr/thunar-apr-image-page.c +++ b/plugins/thunar-apr/thunar-apr-image-page.c @@ -25,6 +25,9 @@ #include #include +#ifdef HAVE_PNG +#include "thunar-apr-png-read-data.h" +#endif #ifdef HAVE_EXIF #include @@ -75,6 +78,9 @@ struct _ThunarAprImagePage #ifdef HAVE_EXIF GtkWidget *exif_labels[G_N_ELEMENTS (TAIP_EXIF)]; #endif +#ifdef HAVE_PNG + GtkWidget *png_labels[number_of_png_chunks]; +#endif }; @@ -94,8 +100,43 @@ thunar_apr_image_page_class_init (ThunarAprImagePageClass *klass) thunarapr_abstract_page_class->file_changed = thunar_apr_image_page_file_changed; } +#ifdef HAVE_PNG +void +thunar_apr_image_page_init_png(ThunarAprImagePage *image_page, GtkWidget *table); + +void +thunar_apr_image_page_init_png(ThunarAprImagePage *image_page, GtkWidget *table) +{ + GtkWidget *cont; + GtkWidget *png_table; + unsigned short n; + + cont = gtk_scrolled_window_new (NULL, NULL); + png_table = gtk_table_new (1, 1, FALSE); + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(cont), png_table); + + gtk_table_set_row_spacings (GTK_TABLE (png_table), 0); + gtk_table_attach (GTK_TABLE (table), cont, 0, 2, 3+G_N_ELEMENTS (TAIP_EXIF), 4+G_N_ELEMENTS (TAIP_EXIF), GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 3); + gtk_widget_show (cont); + gtk_widget_show (png_table); + + /* add labels for the PNG info */ + for (n = 0; n < number_of_png_chunks; ++n) + { + image_page->png_labels[n] = gtk_label_new (""); + gtk_label_set_selectable (GTK_LABEL (image_page->png_labels[n]), TRUE); + gtk_misc_set_alignment (GTK_MISC (image_page->png_labels[n]), 0.0f, 0.5f); + gtk_label_set_single_line_mode (GTK_LABEL (image_page->png_labels[n]), FALSE); + gtk_label_set_line_wrap (GTK_LABEL (image_page->png_labels[n]), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (image_page->png_labels[n]), TRUE); + gtk_label_set_line_wrap_mode (GTK_LABEL (image_page->png_labels[n]), PANGO_WRAP_WORD); +// TODO gtk_label_set_ellipsize (GTK_LABEL (image_page->png_labels[n]), PANGO_ELLIPSIZE_END); + gtk_table_attach (GTK_TABLE (png_table), image_page->png_labels[n], 0, 1, n, n + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 3); + gtk_widget_show (image_page->png_labels[n]); + } +} +#endif - static void thunar_apr_image_page_init (ThunarAprImagePage *image_page) { @@ -120,12 +161,12 @@ thunar_apr_image_page_init (ThunarAprImagePage *image_page) attribute->end_index = -1; pango_attr_list_insert (attr_list, attribute); - table = gtk_table_new (3, 2, FALSE); + table = gtk_table_new (4, 2, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 12); gtk_table_set_row_spacings (GTK_TABLE (table), 0); gtk_container_add (GTK_CONTAINER (image_page), table); gtk_widget_show (table); - + label = gtk_label_new (_("Image Type:")); gtk_misc_set_alignment (GTK_MISC (label), 1.0f, 0.5f); gtk_label_set_attributes (GTK_LABEL (label), attr_list); @@ -197,6 +238,10 @@ thunar_apr_image_page_init (ThunarAprImagePage *image_page) } #endif +#ifdef HAVE_PNG + thunar_apr_image_page_init_png(image_page, table); +#endif + /* release shared bold Pango attributes */ pango_attr_list_unref (attr_list); } @@ -220,6 +265,9 @@ thunar_apr_image_page_file_changed (ThunarAprAbstractPage *abstract_page, gchar exif_buffer[1024]; guint n; #endif +#ifdef HAVE_PNG + png_read_data_ptr_t png_read_data=NULL; +#endif /* determine the URI for the file */ uri = thunarx_file_info_get_uri (file); @@ -278,6 +326,33 @@ thunar_apr_image_page_file_changed (ThunarAprAbstractPage *abstract_page, exif_data_free (exif_data); } #endif +#ifdef HAVE_PNG + /* hide all PNG labels (will be shown again if data is available) */ + for (n = 0; n < number_of_png_chunks; ++n) + gtk_widget_hide (image_page->png_labels[n]); + + png_read_data=png_read_data_from_file(filename); + if (G_LIKELY (png_read_data != NULL)) + { + png_chunk_details_ptr_t png_chunks=png_read_data_get_chunk_ptrs(png_read_data); + if (G_LIKELY (png_chunks != NULL)) + { + n=0; + do + { + if (G_LIKELY (png_chunks->data != NULL)) + { + gtk_label_set_text (GTK_LABEL (image_page->png_labels[n]), png_chunks->data); + /* show the label */ + gtk_widget_show (image_page->png_labels[n]); + ++n; + } + } + while (G_LIKELY ((png_chunks=png_read_data_next_item(png_chunks)) != NULL)); + } + png_read_data_free_ptr(png_read_data); + } +#endif } else { @@ -290,6 +365,11 @@ thunar_apr_image_page_file_changed (ThunarAprAbstractPage *abstract_page, for (n = 0; n < G_N_ELEMENTS (TAIP_EXIF); ++n) gtk_widget_hide (image_page->exif_labels[n]); #endif +#ifdef HAVE_PNG + /* hide all PNG labels */ + for (n = 0; n < number_of_png_chunks; ++n) + gtk_widget_hide (image_page->png_labels[n]); +#endif } } diff --git a/plugins/thunar-apr/thunar-apr-png-read-data.c b/plugins/thunar-apr/thunar-apr-png-read-data.c new file mode 100644 index 0000000..afd6037 --- /dev/null +++ b/plugins/thunar-apr/thunar-apr-png-read-data.c @@ -0,0 +1,539 @@ +/* $Id$ */ +/*- + * Copyright (c) 2013 Jason Hearne-McGuiness + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_PNG + +#ifdef DEBUG +# ifndef PNG_DEBUG +# define PNG_DEBUG 1 +# endif +#else +# undef PNG_DEBUG +#endif + +#include "thunar-apr-png-read-data.h" + +/** + * Don't use any path as on my system a version is included in the path, which might be different on other machines. + */ +#include + +#include +#include +#include +#include + +/** + * The list of valid chunk names. + * From http://www.libpng.org/pub/png/spec/register/pngreg-1.3.0-pdg.html + */ +char const * const png_chunk_names[number_of_png_chunks]={ + "IHDR", + "tIME", + "PLTE", + "bKGD", + "cHRM", + "fRAc", + "gAMA", + "gIFg", + "gIFt", + "gIFx", + "hIST", + "iCCP", + "iTXt", + "oFFs", + "pCAL", + "pHYs", + "sBIT", + "sCAL", + "sPLT", + "sRGB", + "sTER", + "tEXt", + "tRNS", + "zTXt" +}; + +/** + * Not all of these are representable data. + * Convenience:: make it easier whilst constructing the private_png_read_data_ptr_t to index into it and the collection of png_chunk_details. + * These must be in the same order as png_chunk_names. + */ +typedef enum { + png_chunk_names_IHDR=0, + png_chunk_names_tIME, + png_chunk_names_PLTE, + png_chunk_names_bKGD, + png_chunk_names_cHRM, + png_chunk_names_fRAc, + png_chunk_names_gAMA, + png_chunk_names_gIFg, + png_chunk_names_gIFt, + png_chunk_names_gIFx, + png_chunk_names_hIST, + png_chunk_names_iCCP, + png_chunk_names_iTXt, + png_chunk_names_oFFs, + png_chunk_names_pCAL, + png_chunk_names_pHYs, + png_chunk_names_sBIT, + png_chunk_names_sCAL, + png_chunk_names_sPLT, + png_chunk_names_sRGB, + png_chunk_names_sTER, + png_chunk_names_tEXt, + png_chunk_names_tRNS, + png_chunk_names_zTXt +} png_chunk_names_enum; + +typedef struct +{ + char const *name; ///< A chunk name from png_chunk_names. + char const *fmt_str; ///< The format string for converting the raw data into human-readable form. +} png_chunk_fmt_t; + +/** + * These must be in the same order as png_chunk_names. + */ +static const png_chunk_fmt_t png_chunk_details[number_of_png_chunks]={ + {"IHDR", "Width=%u, height=%u, bit depth=%i, colour type: %s, interlace type: %s"}, + {"tIME", "Modification time: %hu/%hhu/%hhu %02hhu:%02hhu:%02hhu"}, ///< In ISO format, because Linux is international. + {"PLTE", "Number of entries in the palette=%i, RGB=(%hhu, %hhu, %hhu)"}, + {"bKGD", "Palette index=%hhu, RGB=(%hu, %hu, %hu), gray=%hu"}, + {"cHRM", ""}, ///< TODO Need to complete representing this. + {"fRAc", ""}, ///< No specification in PNG spec. + {"gAMA", "Gamma factor=%f"}, + {"gIFg", ""}, ///< TODO Need to complete representing this. + {"gIFt", ""}, ///< TODO Need to complete representing this. + {"gIFx", ""}, ///< TODO Need to complete representing this. + {"hIST", "Histogram=%hu"}, + {"iCCP", ""}, ///< TODO Need to complete representing this. + {"iTXt", ""}, ///< TODO Need to complete representing this. + {"oFFs", "Offset: (%i, %i) %s"}, + {"pCAL", ""}, ///< TODO Need to complete representing this. + {"pHYs", "Resolution: (%u, %u) %s"}, + {"sBIT", ""}, ///< TODO Need to complete representing this. + {"sCAL", ""}, ///< TODO Need to complete representing this. + {"sPLT", ""}, ///< TODO Need to complete representing this. + {"sRGB", "Intent: %s"}, + {"sTER", ""}, ///< TODO Need to complete representing this. + {"tEXt", "%s"}, ///< Format specifier not used, as the various components are concatenated in the code. Just here to symbolically indicate that this has been implemented. + {"tRNS", ""}, ///< TODO Need to complete representing this. + {"zTXt", ""} ///< TODO Need to complete representing this. +}; + +// Mr.compiler you are a liar: see this is constant. +typedef enum { + number_of_png_chunks_enum_hack=sizeof(png_chunk_names)/sizeof(png_chunk_names[0]) +} number_of_png_chunks_enum_hack_t; + +const unsigned short sizeof_of_png_chunk_details=sizeof(png_chunk_details_t)*number_of_png_chunks_enum_hack; + +/// The size of the PNG signature to check in the file. +const unsigned short PNG_BYTES_TO_CHECK=8; + +int +check_if_png(const char * const file_name, FILE ** const fp); + +private_png_read_data_ptr_t +init_png_data(void); + +private_png_read_data_ptr_t +read_png_data_from_file(FILE *fp); + +char const * +last_png_chunk_detail_item(void); + +private_png_read_data_ptr_t +init_png_data(void) +{ + private_png_read_data_ptr_t png_data=malloc(sizeof_of_png_chunk_details); + if (png_data) + { + unsigned short i; + // Make sure that unread chunks are NULL, as per the interface. + memset(png_data, 0, sizeof_of_png_chunk_details); + // Make sure the chunk names are set correctly, as per the interface. + for(i=0; iindex, image_background->red, image_background->green, image_background->blue, image_background->gray); + if (error<0) + { + png_data_read[png_chunk_names_bKGD].data=0; + } + } + } + + { + int intent=0; + if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_sRGB) && png_get_sRGB(read_ptr, read_info_ptr, &intent)) + { + int error; + switch (intent) + { + case PNG_sRGB_INTENT_PERCEPTUAL: + error=asprintf(&png_data_read[png_chunk_names_sRGB].data, png_chunk_details[png_chunk_names_sRGB].fmt_str, "perpetual"); + break; + case PNG_sRGB_INTENT_RELATIVE: + error=asprintf(&png_data_read[png_chunk_names_sRGB].data, png_chunk_details[png_chunk_names_sRGB].fmt_str, "relative"); + break; + case PNG_sRGB_INTENT_SATURATION: + error=asprintf(&png_data_read[png_chunk_names_sRGB].data, png_chunk_details[png_chunk_names_sRGB].fmt_str, "saturation"); + break; + case PNG_sRGB_INTENT_ABSOLUTE: + error=asprintf(&png_data_read[png_chunk_names_sRGB].data, png_chunk_details[png_chunk_names_sRGB].fmt_str, "absolute"); + break; + default: + error=asprintf(&png_data_read[png_chunk_names_sRGB].data, png_chunk_details[png_chunk_names_sRGB].fmt_str, "unknown"); + }; + if (error<0) + { + png_data_read[png_chunk_names_sRGB].data=0; + } + } + } + { + double image_gamma=0; + if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_gAMA) && png_get_gAMA(read_ptr, read_info_ptr, &image_gamma)) + { + const int error=asprintf(&png_data_read[png_chunk_names_gAMA].data, png_chunk_details[png_chunk_names_gAMA].fmt_str, image_gamma); + if (error<0) + { + png_data_read[png_chunk_names_gAMA].data=0; + } + } + } + { + int num_palette=0; + png_colorp palette=NULL; + /* This reduces the image to the application supplied palette. */ + if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_PLTE) && png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) + { + const int error=asprintf(&png_data_read[png_chunk_names_PLTE].data, png_chunk_details[png_chunk_names_PLTE].fmt_str, num_palette, palette->red, palette->green, palette->blue); + if (error<0) + { + png_data_read[png_chunk_names_PLTE].data=0; + } + } + } + { + /* This reduces the image to the palette supplied in the file. */ + png_uint_16p histogram=NULL; + if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_hIST) && png_get_hIST(read_ptr, read_info_ptr, &histogram)) + { + const int error=asprintf(&png_data_read[png_chunk_names_hIST].data, png_chunk_details[png_chunk_names_hIST].fmt_str, *histogram); + if (error<0) + { + png_data_read[png_chunk_names_hIST].data=0; + } + } + } + { + png_timep mod_time=NULL; + if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_tIME) && png_get_tIME(read_ptr, read_info_ptr, &mod_time)) + { + const int error=asprintf(&png_data_read[png_chunk_names_tIME].data, png_chunk_details[png_chunk_names_tIME].fmt_str, mod_time->year, mod_time->month, mod_time->day, mod_time->hour, mod_time->minute, mod_time->second); + if (error<0) + { + png_data_read[png_chunk_names_tIME].data=0; + } + } + } + { + png_uint_32 res_x=0, res_y=0; + int unit_type=PNG_RESOLUTION_UNKNOWN; + if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_pHYs) && png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type)) + { + const int error=asprintf(&png_data_read[png_chunk_names_pHYs].data, png_chunk_details[png_chunk_names_pHYs].fmt_str, res_x, res_y, unit_type==PNG_RESOLUTION_UNKNOWN ? "unknown" : "pixels/meter"); + if (error<0) + { + png_data_read[png_chunk_names_pHYs].data=0; + } + } + } + { + png_int_32 offset_x=0, offset_y=0; + int unit_type=PNG_OFFSET_LAST; + if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_oFFs) && png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y, &unit_type)) + { + const int error=asprintf(&png_data_read[png_chunk_names_oFFs].data, png_chunk_details[png_chunk_names_oFFs].fmt_str, offset_x, offset_y, unit_type==PNG_OFFSET_PIXEL ? "pixel" : "micrometer"); + if (error<0) + { + png_data_read[png_chunk_names_oFFs].data=0; + } + } + } + + // Attempt to read in the text blocks in case the rest fails, so that at least we get the description bit. + { + const char key_separator[]=": "; + const char text_separator[]="\n"; + const unsigned short max_key_size=79; + png_textp text_ptr=NULL; + int num_text=0; + if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text)) + { + size_t total_size=(max_key_size+sizeof(key_separator)+sizeof(text_separator))*num_text; + int i; + for(i=0; ichunk_name, last_png_chunk_detail_item())!=0) + { + return ++png_chunk_data; + } + else + { + return (png_chunk_details_ptr_t)NULL;; + } + } + else + { + return (png_chunk_details_ptr_t)NULL; + } +} + +#endif diff --git a/plugins/thunar-apr/thunar-apr-png-read-data.h b/plugins/thunar-apr/thunar-apr-png-read-data.h new file mode 100644 index 0000000..8fc032b --- /dev/null +++ b/plugins/thunar-apr/thunar-apr-png-read-data.h @@ -0,0 +1,113 @@ +/* $Id$ */ +/*- + * Copyright (c) 2013 Jason Hearne-McGuiness + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_PNG + +/** + * The list of valid chunk names. + * From http://www.libpng.org/pub/png/spec/register/pngreg-1.3.0-pdg.html + */ +extern char const * const png_chunk_names[]; +/* From the source file, to assist with identifying the chunks in the png_chunk_details_t collection. +={ + "IHDR", + "tIME", + "PLTE", + "bKGD", + "cHRM", // Not yet implemented. + "fRAc", // No specification in PNG spec. + "gAMA", + "gIFg", // Not yet implemented. + "gIFt", // Not yet implemented. + "gIFx", // Not yet implemented. + "hIST", + "iCCP", // Not yet implemented. + "iTXt", // Not yet implemented. + "oFFs", + "pCAL", // Not yet implemented. + "pHYs", + "sBIT", // Not yet implemented. + "sCAL", // Not yet implemented. + "sPLT", // Not yet implemented. + "sRGB", + "sTER", // Not yet implemented. + "tEXt", + "tRNS", // Not yet implemented. + "zTXt" // Not yet implemented. +};*/ + +enum { + number_of_png_chunks=24 +}; + +/** + * TODO This should really be private... + */ +typedef struct +{ + char const *name; ///< A chunk name from png_chunk_names. + char *data; ///< The converted, human-readable data, if the chunk in the PNG file was present and read correctly, otherwise NULL. +} private_png_chunk_details_t; + +/** + * TODO This should really be private... + */ +typedef private_png_chunk_details_t* private_png_read_data_ptr_t; + +/// A pointer to the PNG data that has been read from the file. (TODO Would be nice it it was opaque, i.e. a void *.) +typedef private_png_chunk_details_t const * png_read_data_ptr_t; + +/// The structure that maps the name of the chunk to the data it contains. +typedef struct +{ + char const *chunk_name; ///< A chunk name from png_chunk_names. + char const *data; ///< The converted, human-readable data, if the chunk in the PNG file was present and read correctly, otherwise NULL. +} png_chunk_details_t; + +typedef png_chunk_details_t const * png_chunk_details_ptr_t; + +/// Returns an opaque pointer to the PNG data that has been read from the file. +/** + * \param filename The name of the file to be read, possibly in PNG format. The pointer can be NULL or an empty string. + * \return NULL if the PNG data could not be read from the input file. + */ +png_read_data_ptr_t png_read_data_from_file(char const *filename); + +/// Free any data allocated by png_read_data_from_file(). +/** + * \param png_data A pointer allocated by png_read_data_from_file(). NULL values are permitted to be passed. + */ +void png_read_data_free_ptr(png_read_data_ptr_t png_data); + +/// Get at the chunk data from the opaque pointer returned by png_read_data_from_file(). NULL values are permitted to be passed. +/** + * \param png_data The opaque pointer returned by png_read_data_from_file(). NULL values are permitted to be passed. + * \return A pointer the item at the beginning of the collection of png_chunk_details_t obtained from the PNG file, or NULL if invalid. + */ +png_chunk_details_ptr_t png_read_data_get_chunk_ptrs(png_read_data_ptr_t png_data); + +/// Get the next png_chunk_details_t from the collection of png_chunk_details_t returned from png_read_data_get_chunk_ptrs(). +/** + * \param png_chunk_data A pointer to an item in the collection of png_chunk_details_t returned by png_read_data_get_chunk_ptrs(). NULL values are permitted to be passed. + * \return A pointer to the next png_chunk_details_t in the collection, or NULL if the end of the collection has been reached or invalid. + */ +png_chunk_details_ptr_t png_read_data_next_item(png_chunk_details_ptr_t png_chunk_data); + +#endif -- 1.8.1.5