From d3270ed648c971b5708c84188e6d7ce184801468 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Mon, 15 Sep 2008 20:23:02 +0000 Subject: [PATCH] Add libpng support. Default to off. svn path=/trunk/netsurf/; revision=5330 --- Makefile | 3 +- Makefile.config | 6 + Makefile.sources | 2 +- content/content.c | 20 +++- content/content.h | 10 ++ image/jpeg.c | 4 +- image/mng.c | 4 +- image/png.c | 284 ++++++++++++++++++++++++++++++++++++++++++++++ image/png.h | 51 +++++++++ 9 files changed, 377 insertions(+), 7 deletions(-) create mode 100644 image/png.c create mode 100644 image/png.h diff --git a/Makefile b/Makefile index 9fa301eed..a837ac608 100644 --- a/Makefile +++ b/Makefile @@ -230,7 +230,8 @@ define pkg_config_find_and_add endef $(eval $(call feature_enabled,JPEG,-DWITH_JPEG,-ljpeg,JPEG support)) -$(eval $(call feature_enabled,MNG,-DWITH_MNG,-lmng,PNG support)) +$(eval $(call feature_enabled,MNG,-DWITH_MNG,-lmng,MNG support)) +$(eval $(call feature_enabled,PNG,-DWITH_PNG,-lpng,PNG support)) $(eval $(call feature_enabled,HARU_PDF,-DWITH_PDF_EXPORT,-lhpdf -lpng,PDF export)) $(eval $(call feature_enabled,LIBICONV_PLUG,-DLIBICONV_PLUG,,glibc internal iconv)) diff --git a/Makefile.config b/Makefile.config index 8c5946e2a..827ae5ed1 100644 --- a/Makefile.config +++ b/Makefile.config @@ -25,6 +25,12 @@ NETSURF_USE_JPEG := YES # Valid options: YES, NO NETSURF_USE_MNG := YES +# Enable NetSurf's use of libpng for displaying PNGs. If MNG and PNG +# are both enabled then NetSurf will choose libpng for PNGs, leaving +# MNGs and JNGs to libmng. +# Valid options: YES, NO +NETSURF_USE_PNG := NO + # Use libharu to enable PDF export and GTK printing support. There is no # auto-detection available for this, as it does not have a pkg-config file. # Valid options: YES, NO diff --git a/Makefile.sources b/Makefile.sources index 3f5b660c2..ce0a04d0b 100644 --- a/Makefile.sources +++ b/Makefile.sources @@ -24,7 +24,7 @@ S_COMMON := $(addprefix content/,$(S_CONTENT)) \ # S_IMAGE are sources related to image management S_IMAGE := bmp.c gif.c ico.c jpeg.c \ - mng.c nssprite.c svg.c rsvg.c + mng.c nssprite.c svg.c rsvg.c png.c S_IMAGE := $(addprefix image/,$(S_IMAGE)) # S_PDF are sources of the pdf plotter + the ones for paged-printing diff --git a/content/content.c b/content/content.c index e9bcf8c10..89de53c4b 100644 --- a/content/content.c +++ b/content/content.c @@ -75,6 +75,9 @@ #ifdef WITH_ARTWORKS #include "riscos/artworks.h" #endif +#ifdef WITH_PNG +#include "image/png.h" +#endif #include "utils/log.h" #include "utils/messages.h" #include "utils/talloc.h" @@ -144,7 +147,7 @@ static const struct mime_entry mime_map[] = { #ifdef WITH_JPEG {"image/pjpeg", CONTENT_JPEG}, #endif -#ifdef WITH_MNG +#if defined(WITH_MNG) || defined(WITH_PNG) {"image/png", CONTENT_PNG}, #endif #if defined(WITH_NS_SVG) || defined (WITH_RSVG) @@ -203,8 +206,10 @@ const char * const content_type_name[] = { "BMP", "ICO", #endif -#ifdef WITH_MNG +#if defined(WITH_MNG) || defined(WITH_PNG) "PNG", +#endif +#ifdef WITH_MNG "JNG", "MNG", #endif @@ -289,10 +294,19 @@ static const struct handler_entry handler_map[] = { {nsico_create, 0, nsico_convert, 0, nsico_destroy, 0, nsico_redraw, nsico_redraw_tiled, 0, 0, false}, #endif + +#ifdef WITH_PNG + {nspng_create, nspng_process_data, nspng_convert, + 0, nspng_destroy, 0, nspng_redraw, nspng_redraw_tiled, + 0, 0, false}, +#else #ifdef WITH_MNG {nsmng_create, nsmng_process_data, nsmng_convert, 0, nsmng_destroy, 0, nsmng_redraw, nsmng_redraw_tiled, - 0, 0, false}, + 0, 0, false}, +#endif +#endif +#ifdef WITH_MNG {nsmng_create, nsmng_process_data, nsmng_convert, 0, nsmng_destroy, 0, nsmng_redraw, nsmng_redraw_tiled, 0, 0, false}, diff --git a/content/content.h b/content/content.h index 2161a07f9..d444f6ed8 100644 --- a/content/content.h +++ b/content/content.h @@ -26,6 +26,13 @@ #ifndef _NETSURF_DESKTOP_CONTENT_H_ #define _NETSURF_DESKTOP_CONTENT_H_ +/* Irritatingly this must come first, or odd include errors + * will occur to do with setjmp.h. + */ +#ifdef WITH_PNG +#include "image/png.h" +#endif + #include #include "utils/config.h" #include "content/content_type.h" @@ -207,6 +214,9 @@ struct content { #endif #ifdef WITH_RSVG struct content_rsvg_data rsvg; +#endif +#ifdef WITH_PNG + struct content_png_data png; #endif } data; diff --git a/image/jpeg.c b/image/jpeg.c index d49d49a4c..6bc39766e 100644 --- a/image/jpeg.c +++ b/image/jpeg.c @@ -26,6 +26,9 @@ #include "utils/config.h" #ifdef WITH_JPEG +/* This must come first due to libpng issues */ +#include "content/content.h" + #include #include #include @@ -33,7 +36,6 @@ #include #define JPEG_INTERNAL_OPTIONS #include "jpeglib.h" -#include "content/content.h" #include "desktop/plotters.h" #include "image/bitmap.h" #include "image/jpeg.h" diff --git a/image/mng.c b/image/mng.c index fe0804976..6daf662ea 100644 --- a/image/mng.c +++ b/image/mng.c @@ -23,6 +23,9 @@ #include "utils/config.h" #ifdef WITH_MNG +/* This must come first due to libpng issues */ +#include "content/content.h" + #include #include #include @@ -30,7 +33,6 @@ #include #include #include -#include "content/content.h" #include "desktop/browser.h" #include "desktop/options.h" #include "desktop/plotters.h" diff --git a/image/png.c b/image/png.c new file mode 100644 index 000000000..822b3b445 --- /dev/null +++ b/image/png.c @@ -0,0 +1,284 @@ +/* + * Copyright 2004 James Bursa + * Copyright 2004 Richard Wilson + * Copyright 2008 Daniel Silverstone + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include + +#include "utils/config.h" + +#include "desktop/plotters.h" + +#include "content/content.h" + +#include "image/bitmap.h" + +#include "utils/log.h" +#include "utils/messages.h" +#include "utils/utils.h" + +#ifdef WITH_PNG + +/* I hate doing this, but without g_strdup_printf or similar, we're a tad stuck. */ +#define NSPNG_TITLE_LEN (100) + +/* libpng uses names starting png_, so use nspng_ here to avoid clashes */ + +static void info_callback(png_structp png, png_infop info); +static void row_callback(png_structp png, png_bytep new_row, + png_uint_32 row_num, int pass); +static void end_callback(png_structp png, png_infop info); + + +bool nspng_create(struct content *c, const char *params[]) +{ + union content_msg_data msg_data; + + c->data.png.png = png_create_read_struct(PNG_LIBPNG_VER_STRING, + 0, 0, 0); + c->data.png.bitmap = NULL; + if (!c->data.png.png) { + msg_data.error = messages_get("NoMemory"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + warn_user("NoMemory", 0); + return false; + } + c->data.png.info = png_create_info_struct(c->data.png.png); + if (!c->data.png.info) { + png_destroy_read_struct(&c->data.png.png, + &c->data.png.info, 0); + + msg_data.error = messages_get("NoMemory"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + warn_user("NoMemory", 0); + return false; + } + + if (setjmp(png_jmpbuf(c->data.png.png))) { + png_destroy_read_struct(&c->data.png.png, + &c->data.png.info, 0); + LOG(("Failed to set callbacks")); + c->data.png.png = NULL; + c->data.png.info = NULL; + + msg_data.error = messages_get("PNGError"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + return false; + } + + png_set_progressive_read_fn(c->data.png.png, c, + info_callback, row_callback, end_callback); + + return true; +} + + +bool nspng_process_data(struct content *c, char *data, unsigned int size) +{ + union content_msg_data msg_data; + + if (setjmp(png_jmpbuf(c->data.png.png))) { + png_destroy_read_struct(&c->data.png.png, + &c->data.png.info, 0); + LOG(("Failed to process data")); + c->data.png.png = NULL; + c->data.png.info = NULL; + if (c->data.png.bitmap != NULL) { + bitmap_destroy(c->data.png.bitmap); + c->data.png.bitmap = NULL; + } + + msg_data.error = messages_get("PNGError"); + content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + return false; + } + + png_process_data(c->data.png.png, c->data.png.info, data, size); + + return true; +} + + +/** + * info_callback -- PNG header has been completely received, prepare to process + * image data + */ + +void info_callback(png_structp png, png_infop info) +{ + int bit_depth, color_type, interlace, intent; + double gamma; + unsigned int rowbytes, sprite_size; + unsigned long width, height; + struct content *c = png_get_progressive_ptr(png); + + /* Read the PNG details */ + png_get_IHDR(png, info, &width, &height, &bit_depth, + &color_type, &interlace, 0, 0); + + /* Claim the required memory for the converted PNG */ + c->data.png.bitmap = bitmap_create(width, height, BITMAP_NEW); + c->data.png.bitbuffer = bitmap_get_buffer(c->data.png.bitmap); + c->data.png.rowstride = bitmap_get_rowstride(c->data.png.bitmap); + c->data.png.bpp = bitmap_get_bpp(c->data.png.bitmap); + + /* Set up our transformations */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png); + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_gray_1_2_4_to_8(png); + if (png_get_valid(png, info, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png); + if (bit_depth == 16) + png_set_strip_16(png); + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png); + if (!(color_type & PNG_COLOR_MASK_ALPHA)) + png_set_filler(png, 0xff, PNG_FILLER_AFTER); + /* gamma correction - we use 2.2 as our screen gamma + * this appears to be correct (at least in respect to !Browse) + * see http://www.w3.org/Graphics/PNG/all_seven.html for a test case + */ + if (png_get_sRGB(png, info, &intent)) + png_set_gamma(png, 2.2, 0.45455); + else { + if (png_get_gAMA(png, info, &gamma)) + png_set_gamma(png, 2.2, gamma); + else + png_set_gamma(png, 2.2, 0.45455); + } + + + png_read_update_info(png, info); + + c->data.png.rowbytes = png_get_rowbytes(png, info); + c->data.png.interlace = (interlace == PNG_INTERLACE_ADAM7); + c->width = width; + c->height = height; + + LOG(("size %li * %li, bpp %i, rowbytes %u", width, + height, bit_depth, c->data.png.rowbytes)); +} + + +static unsigned int interlace_start[8] = {0, 16, 0, 8, 0, 4, 0}; +static unsigned int interlace_step[8] = {28, 28, 12, 12, 4, 4, 0}; +static unsigned int interlace_row_start[8] = {0, 0, 4, 0, 2, 0, 1}; +static unsigned int interlace_row_step[8] = {8, 8, 8, 4, 4, 2, 2}; + +void row_callback(png_structp png, png_bytep new_row, + png_uint_32 row_num, int pass) +{ + struct content *c = png_get_progressive_ptr(png); + unsigned long i, j, rowbytes = c->data.png.rowbytes; + unsigned int start, step; + unsigned char *row = c->data.png.bitbuffer + (c->data.png.rowstride * row_num); + + /* Abort if we've not got any data + */ + if (new_row == 0) + return; + + /* Handle interlaced sprites using the Adam7 algorithm + */ + if (c->data.png.interlace) { + start = interlace_start[pass]; + step = interlace_step[pass]; + row_num = interlace_row_start[pass] + + interlace_row_step[pass] * row_num; + + /* Copy the data to our current row taking into consideration interlacing + */ + row = c->data.png.bitbuffer + (c->data.png.rowstride * row_num); + for (j = 0, i = start; i < rowbytes; i += step) { + row[i++] = new_row[j++]; + row[i++] = new_row[j++]; + row[i++] = new_row[j++]; + row[i++] = new_row[j++]; + } + } else { + /* Do a fast memcpy of the row data + */ + memcpy(row, new_row, rowbytes); + } +} + + +void end_callback(png_structp png, png_infop info) +{ +} + + + +bool nspng_convert(struct content *c, int width, int height) +{ + assert(c->data.png.png); + assert(c->data.png.info); + + png_destroy_read_struct(&c->data.png.png, &c->data.png.info, 0); + + c->title = malloc(NSPNG_TITLE_LEN); + + if (c->title != NULL) + snprintf(c->title, NSPNG_TITLE_LEN, messages_get("PNGTitle"), + c->width, c->height, c->source_size); + + c->size += (c->width * c->height * 4) + NSPNG_TITLE_LEN; + + c->status = CONTENT_STATUS_DONE; + c->bitmap = c->data.png.bitmap; + content_set_status(c, ""); + + return true; +} + + +void nspng_destroy(struct content *c) +{ + free(c->title); + if (c->data.png.bitmap != NULL) { + bitmap_destroy(c->data.png.bitmap); + } +} + + +bool nspng_redraw(struct content *c, int x, int y, + int width, int height, + int clip_x0, int clip_y0, int clip_x1, int clip_y1, + float scale, unsigned long background_colour) +{ + if (c->bitmap != NULL) + plot.bitmap(x, y, width, height, c->bitmap, background_colour, c); + return true; +} + +bool nspng_redraw_tiled(struct content *c, int x, int y, int width, int height, + int clip_x0, int clip_y0, int clip_x1, int clip_y1, + float scale, unsigned long background_colour, + bool repeat_x, bool repeat_y) +{ + return true; +} + +#endif diff --git a/image/png.h b/image/png.h new file mode 100644 index 000000000..5350ec61d --- /dev/null +++ b/image/png.h @@ -0,0 +1,51 @@ +/* + * Copyright 2003 James Bursa + * Copyright 2008 Daniel Silverstone + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _NETSURF_RISCOS_PNG_H_ +#define _NETSURF_RISCOS_PNG_H_ + +#include +#include + +struct content; +struct bitmap; + +struct content_png_data { + png_structp png; + png_infop info; + int interlace; + struct bitmap *bitmap; /**< Created NetSurf bitmap */ + unsigned char *bitbuffer; /**< Bitmap buffer */ + size_t rowstride, bpp; /**< Bitmap rowstride and bpp */ + size_t rowbytes; /**< Number of bytes per row */ +}; + +bool nspng_create(struct content *c, const char *params[]); +bool nspng_process_data(struct content *c, char *data, unsigned int size); +bool nspng_convert(struct content *c, int width, int height); +void nspng_destroy(struct content *c); +bool nspng_redraw(struct content *c, int x, int y, + int width, int height, + int clip_x0, int clip_y0, int clip_x1, int clip_y1, + float scale, unsigned long background_colour); +bool nspng_redraw_tiled(struct content *c, int x, int y, int width, int height, + int clip_x0, int clip_y0, int clip_x1, int clip_y1, + float scale, unsigned long background_colour, + bool repeat_x, bool repeat_y); +#endif