summaryrefslogtreecommitdiff
path: root/png.c
diff options
context:
space:
mode:
authorAnas Nashif <anas.nashif@intel.com>2012-12-07 02:53:31 -0800
committerAnas Nashif <anas.nashif@intel.com>2012-12-07 02:53:31 -0800
commitcbb6286cb92020dd7ae88798ed831ed76fd2130e (patch)
tree782a01c00d5e064aa67ea3f9241a8ef1de1060c6 /png.c
downloadlinks-cbb6286cb92020dd7ae88798ed831ed76fd2130e.tar.gz
links-cbb6286cb92020dd7ae88798ed831ed76fd2130e.tar.bz2
links-cbb6286cb92020dd7ae88798ed831ed76fd2130e.zip
Imported Upstream version 2.6upstream/2.6upstream
Diffstat (limited to 'png.c')
-rw-r--r--png.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/png.c b/png.c
new file mode 100644
index 0000000..7ed1563
--- /dev/null
+++ b/png.c
@@ -0,0 +1,259 @@
+/* png.c
+ * PNG decoding
+ * (c) 2002 Karel 'Clock' Kulhavy
+ * This is a part of the Links program, released under GPL.
+ */
+#include "cfg.h"
+
+#ifdef G
+#include "links.h"
+
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#endif /* #ifdef HAVE_ENDIAN_H */
+
+#ifdef REPACK_16
+#undef REPACK_16
+#endif /* #ifdef REPACK_16 */
+
+#if SIZEOF_UNSIGNED_SHORT != 2
+#define REPACK_16
+#endif /* #if SIZEOF_UNSIGNED_SHORT != 2 */
+
+#ifndef REPACK_16
+#ifndef C_LITTLE_ENDIAN
+#ifndef C_BIG_ENDIAN
+#define REPACK_16
+#endif /* #ifndef C_BIG_ENDIAN */
+#endif /* #ifndef C_LITTLE_ENDIAN */
+#endif /* #ifndef REPACK_16 */
+
+/* Decoder structs */
+
+/* Warning for from-web PNG images */
+static void img_my_png_warning(png_structp a, png_const_charp b)
+{
+}
+
+/* Error for from-web PNG images. */
+static void img_my_png_error(png_structp png_ptr, png_const_charp error_string)
+{
+#if (PNG_LIBPNG_VER < 10500)
+ longjmp(png_ptr->jmpbuf,1);
+#else
+ png_longjmp(png_ptr,1);
+#endif
+}
+
+static void png_info_callback(png_structp png_ptr, png_infop info_ptr)
+{
+ int bit_depth, color_type, intent;
+ double gamma;
+ int bytes_per_pixel=3;
+ struct cached_image *cimg;
+
+ cimg=global_cimg;
+
+ bit_depth=png_get_bit_depth(png_ptr, info_ptr);
+ color_type=png_get_color_type(png_ptr, info_ptr);
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_expand(png_ptr);
+ if (color_type == PNG_COLOR_TYPE_GRAY &&
+ bit_depth < 8) png_set_expand(png_ptr);
+ if (png_get_valid(png_ptr, info_ptr,
+ PNG_INFO_tRNS)){
+ png_set_expand(png_ptr); /* Legacy version of
+ png_set_tRNS_to_alpha(png_ptr); */
+ bytes_per_pixel++;
+ }
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+ if (bit_depth==16){
+#ifndef REPACK_16
+#ifdef C_LITTLE_ENDIAN
+ /* We use native endianity only if unsigned short is 2-byte
+ * because otherwise we have to reassemble the buffer so we
+ * will leave in the libpng-native big endian.
+ */
+ png_set_swap(png_ptr);
+#endif /* #ifdef C_LITTLE_ENDIAN */
+#endif /* #ifndef REPACK_16 */
+ bytes_per_pixel*=sizeof(unsigned short);
+ }
+ png_set_interlace_handling(png_ptr);
+ if (color_type==PNG_COLOR_TYPE_RGB_ALPHA
+ ||color_type==PNG_COLOR_TYPE_GRAY_ALPHA){
+ if (bytes_per_pixel==3
+ ||bytes_per_pixel==3*sizeof(unsigned short))
+ bytes_per_pixel=4*bytes_per_pixel/3;
+ }
+ cimg->width=png_get_image_width(png_ptr,info_ptr);
+ cimg->height=png_get_image_height(png_ptr,info_ptr);
+ cimg->buffer_bytes_per_pixel=bytes_per_pixel;
+ if (png_get_sRGB(png_ptr, info_ptr, &intent)){
+ gamma=sRGB_gamma;
+ }
+ else
+ {
+ if (!png_get_gAMA(png_ptr, info_ptr, &gamma)){
+ gamma=sRGB_gamma;
+ }
+ }
+ cimg->red_gamma=gamma;
+ cimg->green_gamma=gamma;
+ cimg->blue_gamma=gamma;
+ png_read_update_info(png_ptr,info_ptr);
+ cimg->strip_optimized=0;
+ if (header_dimensions_known(cimg))
+ img_my_png_error(png_ptr, "bad image size");
+}
+
+#ifdef REPACK_16
+/* Converts unsigned shorts to doublechars (in big endian) */
+static void a2char_from_unsigned_short(unsigned char *chr, unsigned short *shrt, int len)
+{
+ unsigned short s;
+
+ for (;len;len--,shrt++,chr+=2){
+ s=*shrt;
+ *chr=s>>8;
+ chr[1]=s;
+ }
+}
+
+/* Converts doublechars (in big endian) to unsigned shorts */
+static void unsigned_short_from_2char(unsigned short *shrt, unsigned char *chr, int len)
+{
+ unsigned short s;
+
+ for (;len;len--,shrt++,chr+=2){
+ s=((*chr)<<8)|chr[1];
+ *shrt=s;
+ }
+}
+#endif
+
+static void png_row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32
+ row_num, int pass)
+{
+ struct cached_image *cimg;
+#ifdef REPACK_16
+ unsigned char *tmp;
+ int channels;
+#endif /* #ifdef REPACK_16 */
+
+ cimg=global_cimg;
+#ifdef REPACK_16
+ if (cimg->buffer_bytes_per_pixel>4)
+ {
+ channels=cimg->buffer_bytes_per_pixel/sizeof(unsigned
+ short);
+ if (PNG_INTERLACE_NONE==png_get_interlace_type(png_ptr,
+ ((struct png_decoder *)cimg->decoder)->info_ptr))
+ {
+ unsigned_short_from_2char((unsigned short *)(cimg->buffer+cimg
+ ->buffer_bytes_per_pixel *cimg->width
+ *row_num), new_row, cimg->width
+ *channels);
+ }else{
+ if ((unsigned)cimg->width > MAXINT / 2 / channels) overalloc();
+ tmp=mem_alloc(cimg->width*2*channels);
+ a2char_from_unsigned_short(tmp, (unsigned short *)(cimg->buffer
+ +cimg->buffer_bytes_per_pixel
+ *cimg->width*row_num), cimg->width*channels);
+ png_progressive_combine_row(png_ptr, tmp, new_row);
+ unsigned_short_from_2char((unsigned short *)(cimg->buffer
+ +cimg->buffer_bytes_per_pixel
+ *cimg->width*row_num), tmp, cimg->width*channels);
+ mem_free(tmp);
+ }
+ }else
+#endif /* #ifdef REPACK_16 */
+ {
+ png_progressive_combine_row(png_ptr,
+ cimg->buffer+cimg->buffer_bytes_per_pixel
+ *cimg->width*row_num, new_row);
+ }
+ cimg->rows_added=1;
+}
+
+static void png_end_callback(png_structp png_ptr, png_infop info)
+{
+ end_callback_hit=1;
+}
+
+/* Decoder structs */
+
+void png_start(struct cached_image *cimg)
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+ struct png_decoder *decoder;
+
+ retry1:
+ png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ NULL, img_my_png_error, img_my_png_warning);
+ if (!png_ptr) {
+ if (out_of_memory(NULL, 0)) goto retry1;
+ error("png_create_read_struct failed");
+ fatal_tty_exit();
+ exit(RET_FATAL);
+ }
+ retry2:
+ info_ptr=png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ if (out_of_memory(NULL, 0)) goto retry2;
+ error("png_create_info_struct failed");
+ fatal_tty_exit();
+ exit(RET_FATAL);
+ }
+ if (setjmp(png_jmpbuf(png_ptr))){
+error:
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ img_end(cimg);
+ return;
+ }
+ png_set_progressive_read_fn(png_ptr, NULL,
+ png_info_callback, &png_row_callback,
+ png_end_callback);
+ if (setjmp(png_jmpbuf(png_ptr))) goto error;
+ decoder=mem_alloc(sizeof(*decoder));
+ decoder->png_ptr=png_ptr;
+ decoder->info_ptr=info_ptr;
+ cimg->decoder=decoder;
+}
+
+void png_restart(struct cached_image *cimg, unsigned char *data, int length)
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+#ifdef DEBUG
+ if (!cimg->decoder)
+ internal("decoder NULL in png_restart\n");
+#endif /* #ifdef DEBUG */
+ png_ptr=((struct png_decoder *)(cimg->decoder))->png_ptr;
+ info_ptr=((struct png_decoder *)(cimg->decoder))->info_ptr;
+ end_callback_hit=0;
+ if (setjmp(png_jmpbuf(png_ptr))){
+ img_end(cimg);
+ return;
+ }
+ png_process_data(png_ptr, info_ptr, data, length);
+ if (end_callback_hit) img_end(cimg);
+}
+
+void add_png_version(unsigned char **s, int *l)
+{
+ add_to_str(s, l, "PNG (");
+#ifdef HAVE_PNG_GET_LIBPNG_VER
+ add_to_str(s, l, (unsigned char *)png_get_libpng_ver(NULL));
+#else
+ add_to_str(s, l, PNG_LIBPNG_VER_STRING);
+#endif
+ add_to_str(s, l, ")");
+}
+
+#endif /* #ifdef G */