⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 img.c

📁 ELinks is an advanced and well-established feature-rich text mode web (HTTP/FTP/..) browser. ELinks
💻 C
📖 第 1 页 / 共 3 页
字号:
/* img.c * Generic image decoding and PNG and JPG decoders. * (c) 2002 Karel 'Clock' Kulhavy * This is a part of the Links program, released under GPL.  * Used in graphics mode of Links only TODO: odstranit zbytecne ditherovani z strip_optimized header_dimensions_known,       protoze pozadi obrazku musi byt stejne jako pozadi stranky, a to se nikdy       neditheruje, protoze je to vzdy jednolita barva. Kdyz uz to nepujde       odstranit tak tam aspon dat fixne zaokrouhlovani. TODO: pouzit get_filled_bitmap az bude napsany k optimalizaci zadavani       grafickych dat do X serveru z hlediska zaalokovane pameti. TODO: dodelat stripy do jpegu a png a tiff. */#include "links.h"#ifdef G#ifdef HAVE_ENDIAN_H/* Max von Sydow */#include <endian.h>#endif#ifdef HAVE_JPEG#include <jpeglib.h>#endifstruct decoded_image {	int bla;};#define RESTART_SIZE 8192/* Size of biggest chunk of compressed data that is processed in one run *//* End of decoder structs */struct g_object_image *global_goi;struct cached_image *global_cimg;int end_callback_hit;#endif /* #ifdef G */int dither_images=1;#ifdef G/* prototypes */int is_image_size_sane(int x, int y);void destroy_decoder (struct cached_image *);void img_destruct_image(struct g_object *);int img_scale_h(unsigned scale, int);int img_scale_v(unsigned scale, int);unsigned short *buffer_to_16(unsigned short *, struct cached_image *, unsigned char *, int);void r3l0ad(struct cached_image *, struct g_object_image *);void type(struct cached_image *, unsigned char *);int img_process_download(struct g_object_image *, struct f_data_c *);int get_foreground(int);void draw_frame_mark (struct graphics_driver *, struct graphics_device *, int, int, int, int, long, long, int);void update_bitmap(struct cached_image *);void img_draw_image (struct f_data_c *, struct g_object_image *, int, int);void find_or_make_cached_image(struct g_object_image *, unsigned char *, int);void buffer_to_bitmap(struct cached_image *);int is_image_size_sane(int x, int y){	unsigned a = (unsigned)x * (unsigned)y * 6;	if (y && a / (unsigned)y / 6 != (unsigned)x) return 0;	return a < MAXINT;}/* This is a dummy */void img_draw_decoded_image(struct graphics_device *dev, struct decoded_image *d, int x, int y, int xw, int yw, int xo, int yo){}/* This is a dummy */void img_release_decoded_image(struct decoded_image *d){	mem_free(d);}/* mem_free(cimg->decoder) */void destroy_decoder (struct cached_image *cimg){#ifdef HAVE_JPEG	struct jpg_decoder *jd;#endif /* #ifdef HAVE_JPEG */	struct png_decoder *pd;#ifdef HAVE_TIFF	struct tiff_decoder *td;#endif /* #ifdef HAVE_TIFF */	if (cimg->decoder){		switch(cimg->image_type){		case IM_PNG:			pd=(struct png_decoder *)cimg->decoder;			png_destroy_read_struct(				&pd->png_ptr,				&pd->info_ptr,				NULL);			break;#ifdef HAVE_JPEG		case IM_JPG:			jd=(struct jpg_decoder *)cimg->decoder;			jpeg_destroy_decompress(jd->cinfo);			mem_free(jd->cinfo);			mem_free(jd->jerr);			if (jd->jdata) mem_free(jd->jdata);			break;#endif /* #ifdef HAVE_JPEG */		case IM_GIF:			gif_destroy_decoder(cimg);			break;		case IM_XBM:			/* do nothing */			break;#ifdef HAVE_TIFF		case IM_TIFF:			td=(struct tiff_decoder *)cimg->decoder;			if (td->tiff_open)			{				if (td->tiff_data)mem_free(td->tiff_data);				td->tiff_open=0;			}			break;#endif		}		mem_free(cimg->decoder);	}}void img_destruct_image(struct g_object *object){	struct g_object_image *goi=(struct g_object_image *)object;		if (goi->orig_src)mem_free(goi->orig_src);	if (goi->alt)mem_free(goi->alt);	if (goi->name)mem_free(goi->name);	if (goi->src)mem_free(goi->src);	release_image_map(goi->map);	if (goi->image_list.next)del_from_list(&goi->image_list);	if (goi->xw&&goi->yw){		 /* At least one dimension is zero */		goi->cimg->refcount--;	}	mem_free(goi);}/* Frees all data allocated by cached_image including cached image itself */void img_destruct_cached_image(struct cached_image *cimg){	switch (cimg->state){		case 0:		case 1:		case 2:		case 3:		case 9:		case 11:		break;				case 12:		case 14:		if (cimg->gamma_table) mem_free(cimg->gamma_table);		if (cimg->bmp.user){			drv->unregister_bitmap(&(cimg->bmp));		}		if (cimg->strip_optimized){			if (cimg->dregs) mem_free(cimg->dregs);		}else{			mem_free(cimg->buffer);		}		case 8:		case 10:		destroy_decoder(cimg);		break;		case 13:		case 15:		drv->unregister_bitmap(&(cimg->bmp));		break;		#ifdef DEBUG		default:		fprintf(stderr,"img_destruct_cached_image: state=%d\n",cimg->state);		internal("Invalid state in struct cached_image");#endif /* #ifdef DEBUG */	}	mem_free(cimg->url);	mem_free(cimg);}/* You throw in a vertical dimension of image and it returns * new dimension according to the aspect ratio and user-set image * scaling factor. When scaling factor is 100% and screen pixels * are non-square, the picture will be always in one dimension * untouched and in the second _ENLARGED_. So that no information * in the picture will be lost. * Input may be <0. In this case output=input * Input may be 0. In this case output=0. * If input is >0 the output is also >0. */int img_scale_h(unsigned scale, int in){	int out;	/* We assume unsigned long holds at least 32 bits */	unsigned long pre;	if (in<=0) return in;	pre=((unsigned long)(aspect<65536UL?65536UL:aspect)*scale+128)>>8;	out=((unsigned long)in*pre+12800UL)/25600UL;	if (out<1) out=1;	return out;}int img_scale_v(unsigned scale, int in){	int out;	unsigned long divisor;	if (in<=0) return in;	divisor=(100*(aspect>=65536UL?65536UL:aspect)+128)>>8;	out=((unsigned long)in*(scale*256)+(divisor>>1))/divisor;	if (out<1) out=1;	return out;}/* Returns height (pixels) for prescribed width (pixels). Honours aspect. */static int width2height(float width_px, float width_mm, float height_mm){	int height_px;	if (width_px<=0) return width_px;	height_px=(height_mm*width_px*65536)/(aspect*width_mm);	if (height_px<1) height_px=1;	return height_px;}/* Returns width (pixels) for prescribed height (pixels). Honours aspect. */static int height2width(float height_px, float width_mm, float height_mm){	int width_px;	if (height_px<=0) return height_px;	width_px=(width_mm*height_px*aspect)/(65536*height_mm);	if (width_px<1) width_px=1;	return width_px;}/* Compute 8-bit background for filling buffer with cimg->*_gamma * (performs rounding) */void compute_background_8(unsigned char *rgb, struct cached_image *cimg){	unsigned short red, green, blue;	round_color_sRGB_to_48(&red, &green, &blue		, cimg->background_color);	rgb[0]=apply_gamma_single_16_to_8(red		,cimg->red_gamma/user_gamma);	rgb[1]=apply_gamma_single_16_to_8(green		,cimg->green_gamma/user_gamma);	rgb[2]=apply_gamma_single_16_to_8(blue		,cimg->blue_gamma/user_gamma);}/* updates cimg state when header dimensions are know. Only allowed to be called * in state 8 and 10. * Allocates right amount of memory into buffer, formats it (with background or * zeroes, depens on buffer_bytes_per_pixel). Updates dimensions (xww and yww) * according to newly known header dimensions. Fills in gamma_stamp, bmp.user * (NULL because we not bother with generating bitmap here) * and rows_added. * Resets strip_optimized if image will be scaled or  * Allocates dregs if on exit strip_optimized is nonzero. * Allocates and computes gamma_table, otherwise * 	sets gamma_table to NULL. Also doesn't make gamma table if image contains less * 	than 1024 pixels (it would be probably a waste of time). * Output state is always 12 (from input state 8) or 14 (from input state 10). * * The caller must have set the following elements of cimg: *	width *	height *	buffer_bytes_per_pixel *	red_gamma *	green_gamma *	blue_gamma *	strip_optimized */void header_dimensions_known(struct cached_image *cimg){	unsigned short red, green, blue;#ifdef DEBUG	if ((cimg->state^8)&13){		fprintf(stderr,"cimg->state=%d\n",cimg->state);		internal("Invalid state in header_dimensions_known");	}	if (cimg->width<1||cimg->height<1){		fprintf(stderr,"width=%d height=%d\n",cimg->width, cimg->height);		internal("Zero dimensions in header_dimensions_known");	}#endif /* #ifdef DEBUG */	if (cimg->wanted_xw<0){		/* Unspecified width */		if (cimg->wanted_yw<0){			/* Unspecified neither width nor height */			cimg->xww=img_scale_h(cimg->scale, cimg->width);			cimg->yww=img_scale_v(cimg->scale, cimg->height);		}else{			/* Unspecified width specified height */			cimg->xww=height2width(cimg->yww,					cimg->width, cimg->height);			if (cimg->xww<=0) cimg->xww=1;					}	}else{		/* Specified width */		if (cimg->wanted_yw<0){			/* Unspecified height, specified width */			cimg->yww=width2height(cimg->xww,					cimg->width, cimg->height);			if (cimg->yww<=0) cimg->yww=1;		}else if (cimg->wanted_xyw_meaning==MEANING_AUTOSCALE){			/* Specified height and width and autoscale meant */			/* Try first to nail the height */			cimg->yww=cimg->wanted_yw;			cimg->xww=height2width(cimg->yww,					cimg->width, cimg->height);			if (cimg->xww>cimg->wanted_xw)			{				/* Width too much, we nail the width */				cimg->xww=cimg->wanted_xw;				cimg->yww=width2height(cimg->xww,						cimg->width, cimg->height);			}						/* Some sanity checks */			if (cimg->xww<=0) cimg->xww=1;			if (cimg->yww<=0) cimg->yww=1;		}	}	if (!is_image_size_sane(cimg->xww, cimg->yww)) {		cimg->xww = cimg->width;		cimg->yww = cimg->height;	}	if (cimg->width!=cimg->xww||cimg->height!=cimg->yww) cimg->strip_optimized=0;	cimg->gamma_stamp=gamma_stamp;	if (cimg->strip_optimized){		struct bitmap tmpbmp;		unsigned short *buf_16;		int i;		tmpbmp.x=cimg->width;		tmpbmp.y=1;		/* No buffer, bitmap is valid from the very beginning */		cimg->bmp.x=cimg->width;		cimg->bmp.y=cimg->height;		drv->get_empty_bitmap(&(cimg->bmp));		if ((unsigned)cimg->width > MAXINT / sizeof(*buf_16) / 3) overalloc();		buf_16=mem_alloc(sizeof(*buf_16)*3*cimg->width);		round_color_sRGB_to_48(&red, &green, &blue			, cimg->background_color);		mix_one_color_48(buf_16,cimg->width, red, green, blue);#ifdef DEBUG		if (cimg->height<=0){			fprintf(stderr,"cimg->height=%d\n",cimg->height);			internal("Invalid cimg->height in strip_optimized section of\ header_dimensions_known");		}#endif /* #ifdef DEBUG */		/* The skip is uninitialized here and is read by dither_start		 * but is not used in any malicious way so it doesn't matter		 */		tmpbmp.data=cimg->bmp.data;		cimg->dregs=dither_images?dither_start(buf_16,&tmpbmp):NULL;		tmpbmp.data=(unsigned char *)tmpbmp.data+cimg->bmp.skip;		if (cimg->dregs)			for (i=cimg->height-1;i;i--){				dither_restart(buf_16,&tmpbmp,cimg->dregs);				tmpbmp.data=(unsigned char *)tmpbmp.data+cimg->bmp.skip;			}		else			for (i=cimg->height-1;i;i--){				(*round_fn)(buf_16,&tmpbmp);				tmpbmp.data=(unsigned char *)tmpbmp.data+cimg->bmp.skip;			}		mem_free(buf_16);		drv->register_bitmap(&(cimg->bmp));		if(cimg->dregs) memset(cimg->dregs,0,cimg->width*sizeof(*cimg->dregs)*3);		cimg->bmp.user=(void *)&end_callback_hit; /* Nonzero value */		/* This ensures the dregs are none and because strip		 * optimization is unusable in interlaced pictures,		 * this saves the zeroing out at the beginning of the		 * decoder itself.		 */	}else {		cimg->rows_added=1;		cimg->bmp.user=NULL;		if (cimg->width && (unsigned)cimg->width * (unsigned)cimg->height / (unsigned)cimg->width != (unsigned)cimg->height) overalloc();		if ((unsigned)cimg->width * (unsigned)cimg->height > (unsigned)MAXINT / cimg->buffer_bytes_per_pixel) overalloc();		cimg->buffer=mem_alloc(cimg->width*cimg->height			*cimg->buffer_bytes_per_pixel);		if (cimg->buffer_bytes_per_pixel==4			 	||cimg->buffer_bytes_per_pixel==4				*sizeof(unsigned short))			{				/* Make the buffer contain full transparency */			memset(cimg->buffer,0,cimg->width*cimg->height				*cimg->buffer_bytes_per_pixel);		}else{			/* Fill the buffer with background color */			if (cimg->buffer_bytes_per_pixel>4){				/* 16-bit */				unsigned short red, green, blue;				round_color_sRGB_to_48(&red, &green, &blue					, cimg->background_color);				red=apply_gamma_single_16_to_16(red					,cimg->red_gamma/user_gamma);				green=apply_gamma_single_16_to_16(green					,cimg->green_gamma/user_gamma);				blue=apply_gamma_single_16_to_16(blue					,cimg->blue_gamma / user_gamma);				mix_one_color_48((unsigned short *)cimg->buffer					,cimg->width*cimg->height,red					,green, blue);			}else{				unsigned char rgb[3];								/* 8-bit */				compute_background_8(rgb,cimg);				mix_one_color_24(cimg->buffer					,cimg->width*cimg->height					,rgb[0],rgb[1],rgb[2]);			}		}	}	if (cimg->buffer_bytes_per_pixel<=4&&cimg->width*cimg->height>=1024){		make_gamma_table(cimg);	}else if (cimg->buffer_bytes_per_pixel>=6&&cimg->width*cimg->height>=262144){		make_gamma_table(cimg);	}else cimg->gamma_table=NULL;	cimg->state|=4; /* Update state */}/* Fills "tmp" buffer with the resulting data and does not free the input * buffer. May be called only in states 12 and 14 of cimg */unsigned short *buffer_to_16(unsigned short *tmp, struct cached_image *cimg	,unsigned char *buffer, int height){	unsigned short red, green,blue;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -