📄 img_png.c
字号:
/******************************************************************************* * * img_png.h * * Original code from dillo http://dillo.sourceforge.net * * Hacked by Garett Spencley for Cheetah Web Browser * * Copyright (C) 1999 Geoff Lane <zzassgl@twirl.mcc.ac.uk> * Copyright (C) 2000 Luca Rota, Jorge Arellano Cid, Eric Gaudet * Copyright (C) 2001 Garett Spencley <gspen@home.com> * * This program 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; either version 2, or (at your option) * any later version. * * This program 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, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *******************************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <gtk/gtk.h>#include <png.h>#include "img_png.h"#include "debug.h"#define DATASIZE (png->ipbufsize - png->ipbufstart)#define BLACK 0#define WHITE 255enum prog_state { IS_finished, IS_init, IS_nextdata};/* * This holds the data that must be saved between calls to this module. * Each time it is called it is supplied with a vector of data bytes * obtained from the web server. The module can process any amount of the * supplied data. The next time the module is called, the vector may be * extended with additional data bytes to be processed. The module must * keep track of the current start and cursor position of the input data * vector. As complete output rasters are determined they are sent out of * the module for additional processing. * * NOTE: There is no external control of the splitting of the input data * vector (only this module understands PNG format data.) This means that * the complete state of a PNG image being processed must be held in the * structure below so that processing can be suspended or resumed at any * point within an input image. * * In the case of the libpng library, it maintains it's own state in * png_ptr and into_ptr so the FSM is very simple - much simpler than the * ones for XBM and PNM are. */struct _PngImage { ImageData *Image; /* Image meta data */ double display_exponent; /* gamma correction */ gulong width; /* png image width */ gulong height; /* png image height */ png_structp png_ptr; /* libpng private data */ png_infop info_ptr; /* libpng private info */ guchar *image_data; /* decoded image data */ guchar **row_pointers; /* pntr to row starts */ jmp_buf jmpbuf; /* png error processing */ gint error; /* error flag */ gint rowbytes; /* No. bytes in image row */ short passes; short channels; /* No. image channels *//* * 0 last byte * +-------+-+-----------------------------------+-+ * | | | -- data to be processed -- | | * +-------+-+-----------------------------------+-+ * ^ ^ ^ * ipbuf ipbufstart ipbufsize */ guchar *ipbuf; /* image data in buffer */ gint ipbufstart; /* first valid image byte */ gint ipbufsize; /* size of valid data in */ enum prog_state state; /* FSM current state */ guchar *linebuf; /* o/p raster data */};static void Png_error_handling(png_structp png_ptr, png_const_charp msg){ PngImage *png; g_print("Png_error_handling: %s\n", msg); png = png_get_error_ptr(png_ptr); png->error = 1; png->state = IS_finished; longjmp(png->jmpbuf, 1);}static void Png_datainfo_callback(png_structp png_ptr, png_infop info_ptr){ PngImage *png; gint color_type; gint bit_depth; gint interlace_type; guint i; char *buf; double gamma; debug_print("Png_datainfo_callback:\n"); png = png_get_progressive_ptr(png_ptr); g_return_if_fail(png != NULL); png_get_IHDR(png_ptr, info_ptr, &png->width, &png->height, &bit_depth, &color_type, &interlace_type, NULL, NULL); debug_print("Png_datainfo_callback: png->width = %ld\n", png->width); debug_print("Png_datainfo_callback: png->height = %ld\n", png->height); /* we need RGB/RGBA in the end */ if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) { /* Convert indexed images to RGB */ png_set_expand (png_ptr); } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { /* Convert grayscale to RGB */ png_set_expand (png_ptr); } else if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) { /* We have transparency header, convert it to alpha channel */ png_set_expand(png_ptr); } else if (bit_depth < 8) { png_set_expand(png_ptr); } if (bit_depth == 16) png_set_strip_16(png_ptr); /* Get and set gamma information. Beware: gamma correction 2.2 will only work on PC's. todo: select screen gamma correction for other platforms. */ if (png_get_gAMA(png_ptr, info_ptr, &gamma)) png_set_gamma(png_ptr, 2.2, gamma); /* Convert gray scale to RGB */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } /* Interlaced */ if (interlace_type != PNG_INTERLACE_NONE) png->passes = png_set_interlace_handling(png_ptr); /* get libpng to update it's state */ png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &png->width, &png->height, &bit_depth, &color_type, &interlace_type, NULL, NULL); png->rowbytes = png_get_rowbytes(png_ptr, info_ptr); png->channels = png_get_channels(png_ptr, info_ptr); /* init Dillo specifics */ debug_print("Png_datainfo_callback: rowbytes = %d\n", png->rowbytes); debug_print("Png_datainfo_callback: width = %ld\n", png->width); debug_print("Png_datainfo_callback: height = %ld\n", png->height); png->image_data = (guchar *) g_malloc(png->rowbytes * png->height); png->row_pointers = (guchar **) g_malloc(png->height * sizeof(guchar *)); for (i = 0; i < png->height; i++) png->row_pointers[i] = png->image_data + (i * png->rowbytes); png->linebuf = g_malloc(3 * png->width); buf = g_malloc(png->width * png->height * 3); Image_set_parms(png->Image, buf, png->width, png->height, IMG_TYPE_RGB);}static void Png_datarow_callback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, gint pass){ PngImage *png; guint i; if (!new_row) /* work to do? */ return; png = png_get_progressive_ptr(png_ptr); png_progressive_combine_row(png_ptr, png->row_pointers[row_num], new_row); switch (png->channels) { case 3: Image_write(png->Image, png->image_data + (row_num * png->rowbytes), row_num, TRUE); break; case 4: { /* todo: get the backgound color from the parent * of the image widget -- Livio. */ gint a, bg_red, bg_green, bg_blue; guchar *pl = png->linebuf; guchar *data = png->image_data + (row_num * png->rowbytes); /* todo: maybe change prefs.bg_color to `a_Dw_widget_get_bg_color`, * when background colors are correctly implementated */ /* bg_blue = (prefs.bg_color) & 0xFF; bg_green = (prefs.bg_color >> 8) & 0xFF; bg_red = (prefs.bg_color >> 16) & 0xFF; */ bg_blue = DW_PAINT_DEFAULT_BGND & 0xFF; bg_green = (DW_PAINT_DEFAULT_BGND >> 8) & 0xFF; bg_red = (DW_PAINT_DEFAULT_BGND >> 16) & 0xFF; for (i = 0; i < png->width; i++) { a = *(data + 3); if (a == 255) { *(pl++) = *(data++); *(pl++) = *(data++); *(pl++) = *(data++); data++; } else if (a == 0) { *(pl++) = bg_red; *(pl++) = bg_green; *(pl++) = bg_blue; data += 4; } else { png_composite(*(pl++), *(data++), a, bg_red); png_composite(*(pl++), *(data++), a, bg_green); png_composite(*(pl++), *(data++), a, bg_blue); data++; } } Image_write(png->Image, png->linebuf, row_num, TRUE); break; } default: g_print("Png_datarow_callback: unexpected number of channels = %d\n", png->channels); abort(); }}static void Png_dataend_callback(png_structp png_ptr, png_infop info_ptr){ PngImage *png; debug_print("Png_dataend_callback..."); png = png_get_progressive_ptr(png_ptr); png->state = IS_finished;}void Png_close(PngImage *png){ if(!png) return; if (png->image_data != NULL) g_free(png->image_data); if (png->row_pointers != NULL) g_free(png->row_pointers); if (png->linebuf != NULL) g_free(png->linebuf); if (setjmp(png->jmpbuf)) png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL); g_free(png);}void Png_write(PngImage *png, void *Buf, size_t Size){ /* Let's make some sound if we have been called with no data */ g_return_if_fail(Buf != NULL && Size > 0); debug_print("Png_write: BufSize = %d", Size); /* Keep local copies so we don't have to pass multiple args to * a number of functions. */ png->ipbuf = Buf; png->ipbufsize = Size; /* start/resume the FSM here */ while (png->state != IS_finished && DATASIZE) { switch (png->state) { case IS_init: if(DATASIZE < 8) return; /* need MORE data */ /* check the image signature - DON'T update ipbufstart! */ if (!png_check_sig(png->ipbuf, DATASIZE)) { /* you lied to me about it being a PNG image */ png->state = IS_finished; break; } /* OK, it looks like a PNG image, lets do some set up stuff */ png->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png, (png_error_ptr) Png_error_handling, (png_error_ptr) Png_error_handling); g_return_if_fail(png->png_ptr != NULL); png->info_ptr = png_create_info_struct(png->png_ptr); g_return_if_fail(png->png_ptr != NULL); setjmp(png->jmpbuf); if (!png->error) { png_set_progressive_read_fn(png->png_ptr, png, Png_datainfo_callback, /* performs local init functions */ Png_datarow_callback, /* performs per row action */ Png_dataend_callback); /* performs cleanup actions */ png->state = IS_nextdata; } break; case IS_nextdata: if (setjmp(png->jmpbuf)) { png->state = IS_finished; } else if (!png->error) { png_process_data(png->png_ptr, png->info_ptr, png->ipbuf + png->ipbufstart, DATASIZE); png->ipbufstart += DATASIZE; } break; default: g_warning("PNG decoder: bad state = %d\n", png->state); abort(); } }}/* * Create the image state data that must be kept between calls */PngImage *Png_new(ImageData * Image){ PngImage *png = g_malloc(sizeof(PngImage)); png->Image = Image; png->state = IS_init; png->error = 0; png->ipbuf = NULL; png->ipbufstart = 0; png->ipbufsize = 0; png->linebuf = NULL; png->linebuf = NULL; png->row_pointers = NULL; png->image_data = NULL; return png;}/* * MIME handler for "image/png" type * (Sets Png_callback or a_Dicache_callback as the cache-client) */DwWidget *a_Png_image(const char *Type, ImageData *image, void **Data){/* * Type: MIME type * Ptr: points to a Web structure * Call: Dillo calls this with more data/eod * Data: raw image data */ debug_print("a_Png_image: Type = %s", Type); debug_print("a_Png_image: libpng - Compiled %s; using %s.", PNG_LIBPNG_VER_STRING, png_libpng_ver); debug_print("a_Png_image: zlib - Compiled %s; using %s.\n", ZLIB_VERSION, zlib_version); if(!image) image = Image_new(0, 0, NULL, DW_PAINT_DEFAULT_BGND); *Data = image; return DW_WIDGET(image);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -