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

📄 pixbuf-renderer.c

📁 Gqview,Linux下基于GTK+库写成的轻量级而能丰富的图像浏览程序。
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * GQview * (C) 2005 John Ellis * * Author: John Ellis * * This software is released under the GNU General Public License (GNU GPL). * Please read the included file COPYING for more information. * This software comes with no warranty of any kind, use at your own risk! */#include <stdio.h>#include <stdlib.h>#include <math.h>#include "pixbuf-renderer.h"#include "intl.h"#include <gtk/gtk.h>/* comment this out if not using this from within GQview * defining GQVIEW_BUILD does these things: *   - Sets the shift-click scroller pixbuf to a nice icon instead of a black box */#define GQVIEW_BUILD 1#ifdef GQVIEW_BUILD	#include "pixbuf_util.h"#endif/* size to use when breaking up image pane for rendering */#define PR_TILE_SIZE 128/* default size of tile cache (mb) */#define PR_CACHE_SIZE_DEFAULT 8/* default min and max zoom */#define PR_ZOOM_MIN -32.0#define PR_ZOOM_MAX 32.0/* distance to drag mouse to disable image flip */#define PR_DRAG_SCROLL_THRESHHOLD 4/* increase pan rate when holding down shift */#define PR_PAN_SHIFT_MULTIPLIER 6/* scroller config */#define PR_SCROLLER_UPDATES_PER_SEC 30#define PR_SCROLLER_DEAD_ZONE 6/* alpha channel checkerboard background (same as gimp) */#define PR_ALPHA_CHECK1 0x00999999#define PR_ALPHA_CHECK2 0x00666666#define PR_ALPHA_CHECK_SIZE 16/* when scaling image to below this size, use nearest pixel for scaling * (below about 4, the other scale types become slow generating their conversion tables) */#define PR_MIN_SCALE_SIZE 8typedef enum {	TILE_RENDER_NONE = 0,	/* do nothing */	TILE_RENDER_AREA,	/* render an area of the tile */	TILE_RENDER_ALL		/* render the whole tile */} ImageTileRenderType;typedef struct _ImageTile ImageTile;typedef struct _QueueData QueueData;struct _ImageTile{	GdkPixmap *pixmap;	/* off screen buffer */	GdkPixbuf *pixbuf;	/* pixbuf area for zooming */	gint x;			/* x offset into image */	gint y;			/* y offset into image */	gint w;			/* width that is visible (may be less if at edge of image) */	gint h;			/* height '' */	gboolean blank;/* render_todo: (explanation)	NONE	do nothing	AREA	render area of tile, usually only used when loading an image		note: will jump to an ALL if render_done is not ALL.	ALL	render entire tile, if never done before w/ ALL, for expose events *only**/	ImageTileRenderType render_todo;	/* what to do (see above) */	ImageTileRenderType render_done;	/* highest that has been done before on tile */	QueueData *qd;	QueueData *qd2;	guint size;		/* est. memory used by pixmap and pixbuf */};struct _QueueData{	ImageTile *it;	gint x;	gint y;	gint w;	gint h;	gboolean new_data;};typedef struct _SourceTile SourceTile;struct _SourceTile{	gint x;	gint y;	GdkPixbuf *pixbuf;	gboolean blank;};typedef struct _OverlayData OverlayData;struct _OverlayData{	gint id;	GdkPixbuf *pixbuf;	gint x;	gint y;	gint relative;	/* x,y coordinates are relative, negative values start bottom right */	gint visible;	gint always;	/* hide temporarily when scrolling */};enum {	SIGNAL_ZOOM = 0,	SIGNAL_CLICKED,	SIGNAL_SCROLL_NOTIFY,	SIGNAL_RENDER_COMPLETE,	SIGNAL_COUNT};enum {	PROP_0,	PROP_ZOOM_MIN,	PROP_ZOOM_MAX,	PROP_ZOOM_QUALITY,	PROP_ZOOM_2PASS,	PROP_ZOOM_EXPAND,	PROP_DITHER_QUALITY,	PROP_SCROLL_RESET,	PROP_DELAY_FLIP,	PROP_LOADING,	PROP_COMPLETE,	PROP_CACHE_SIZE_DISPLAY,	PROP_CACHE_SIZE_TILES,	PROP_WINDOW_FIT,	PROP_WINDOW_LIMIT,	PROP_WINDOW_LIMIT_VALUE};static guint signals[SIGNAL_COUNT] = { 0 };static GtkEventBoxClass *parent_class = NULL;static void pixbuf_renderer_class_init(PixbufRendererClass *class);static void pixbuf_renderer_init(PixbufRenderer *pr);static void pixbuf_renderer_finalize(GObject *object);static void pixbuf_renderer_set_property(GObject *object, guint prop_id,					 const GValue *value, GParamSpec *pspec);static void pixbuf_renderer_get_property(GObject *object, guint prop_id,					 GValue *value, GParamSpec *pspec);static gint pixbuf_renderer_expose(GtkWidget *widget, GdkEventExpose *event);static void pr_render_complete_signal(PixbufRenderer *pr);static void pr_overlay_list_clear(PixbufRenderer *pr);static void pr_scroller_timer_set(PixbufRenderer *pr, gint start);static void pr_border_draw(PixbufRenderer *pr, gint x, gint y, gint w, gint h);static void pr_source_tile_free_all(PixbufRenderer *pr);static void pr_tile_free_all(PixbufRenderer *pr);static void pr_tile_invalidate_region(PixbufRenderer *pr, gint x, gint y, gint w, gint h);static gint pr_tile_is_visible(PixbufRenderer *pr, ImageTile *it);static void pr_queue_clear(PixbufRenderer *pr);static void pr_queue_merge(QueueData *parent, QueueData *qd);static void pr_queue(PixbufRenderer *pr, gint x, gint y, gint w, gint h,		     gint clamp, ImageTileRenderType render, gint new_data, gint only_existing);static void pr_redraw(PixbufRenderer *pr, gint new_data);static void pr_zoom_sync(PixbufRenderer *pr, gdouble zoom,			 gint force, gint blank, gint new,			 gint center_point, gint px, gint py);static void pr_signals_connect(PixbufRenderer *pr);static void pr_size_cb(GtkWidget *widget, GtkAllocation *allocation, gpointer data);static void pixbuf_renderer_paint(PixbufRenderer *pr, GdkRectangle *area);/* *------------------------------------------------------------------- * Pixbuf Renderer object *------------------------------------------------------------------- */GType pixbuf_renderer_get_type(void){	static GType pixbuf_renderer_type = 0;	if (!pixbuf_renderer_type)		{		static const GTypeInfo pixbuf_renderer_info =			{			sizeof(PixbufRendererClass),			NULL,		/* base_init */			NULL,		/* base_finalize */			(GClassInitFunc)pixbuf_renderer_class_init,			NULL,		/* class_finalize */			NULL,		/* class_data */			sizeof(PixbufRenderer),			0,		/* n_preallocs */			(GInstanceInitFunc)pixbuf_renderer_init,			};		pixbuf_renderer_type = g_type_register_static(GTK_TYPE_EVENT_BOX, "PixbufRenderer",							      &pixbuf_renderer_info, 0);		}	return pixbuf_renderer_type;}static void pixbuf_renderer_class_init(PixbufRendererClass *class){	GObjectClass *gobject_class = G_OBJECT_CLASS(class);	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class);	parent_class = g_type_class_peek_parent(class);	gobject_class->set_property = pixbuf_renderer_set_property;	gobject_class->get_property = pixbuf_renderer_get_property;	gobject_class->finalize = pixbuf_renderer_finalize;	widget_class->expose_event = pixbuf_renderer_expose;	g_object_class_install_property(gobject_class,					PROP_ZOOM_MIN,					g_param_spec_double("zoom_min",							    "Zoom minimum",							    NULL,							    -1000.0,							    1000.0,							    PR_ZOOM_MIN,							    G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_ZOOM_MAX,					g_param_spec_double("zoom_max",							    "Zoom maximum",							    NULL,							    -1000.0,							    1000.0,							    PR_ZOOM_MIN,							    G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_ZOOM_QUALITY,					g_param_spec_uint("zoom_quality",							  "Zoom quality",							  NULL,							  GDK_INTERP_NEAREST,							  GDK_INTERP_HYPER,							  GDK_INTERP_BILINEAR,							  G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_ZOOM_2PASS,					g_param_spec_boolean("zoom_2pass",							     "2 pass zoom",							     NULL,							     TRUE,							     G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_ZOOM_EXPAND,					g_param_spec_boolean("zoom_expand",							     "Expand image in autozoom.",							     NULL,							     FALSE,							     G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_DITHER_QUALITY,					g_param_spec_uint("dither_quality",							  "Dither quality",							  NULL,							  GDK_RGB_DITHER_NONE,							  GDK_RGB_DITHER_MAX,							  GDK_RGB_DITHER_NORMAL,							  G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_SCROLL_RESET,					g_param_spec_uint("scroll_reset",							  "New image scroll reset",							  NULL,							  PR_SCROLL_RESET_TOPLEFT,							  PR_SCROLL_RESET_NOCHANGE,							  PR_SCROLL_RESET_TOPLEFT,							  G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_DELAY_FLIP,					g_param_spec_boolean("delay_flip",							     "Delay image update",							     NULL,							     FALSE,							     G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_LOADING,					g_param_spec_boolean("loading",							     "Image actively loading",							     NULL,							     FALSE,							     G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_COMPLETE,					g_param_spec_boolean("complete",							     "Image rendering complete",							     NULL,							     FALSE,							     G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_CACHE_SIZE_DISPLAY,					g_param_spec_uint("cache_display",							  "Display cache size MB",							  NULL,							  0,							  128,							  PR_CACHE_SIZE_DEFAULT,							  G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_CACHE_SIZE_TILES,					g_param_spec_uint("cache_tiles",							  "Tile cache count",							  "Number of tiles to retain in memory at any one time.",							  0,							  256,							  PR_CACHE_SIZE_DEFAULT,							  G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_WINDOW_FIT,					g_param_spec_boolean("window_fit",							     "Fit window to image size",							     NULL,							     FALSE,							     G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_WINDOW_LIMIT,					g_param_spec_boolean("window_limit",							     "Limit size of parent window",							     NULL,							     FALSE,							     G_PARAM_READABLE | G_PARAM_WRITABLE));	g_object_class_install_property(gobject_class,					PROP_WINDOW_LIMIT_VALUE,					g_param_spec_uint("window_limit_value",							  "Size limit of parent window",							  NULL,							  10,							  150,							  100,							  G_PARAM_READABLE | G_PARAM_WRITABLE));	signals[SIGNAL_ZOOM] = 		g_signal_new("zoom",			     G_OBJECT_CLASS_TYPE(gobject_class),			     G_SIGNAL_RUN_LAST,			     G_STRUCT_OFFSET(PixbufRendererClass, zoom),			     NULL, NULL,			     g_cclosure_marshal_VOID__DOUBLE,			     G_TYPE_NONE, 1,			     G_TYPE_DOUBLE);	signals[SIGNAL_CLICKED] = 		g_signal_new("clicked",			     G_OBJECT_CLASS_TYPE(gobject_class),			     G_SIGNAL_RUN_LAST,			     G_STRUCT_OFFSET(PixbufRendererClass, clicked),			     NULL, NULL,			     g_cclosure_marshal_VOID__BOXED,			     G_TYPE_NONE, 1,			     GDK_TYPE_EVENT);	signals[SIGNAL_SCROLL_NOTIFY] = 		g_signal_new("scroll-notify",			     G_OBJECT_CLASS_TYPE(gobject_class),			     G_SIGNAL_RUN_LAST,			     G_STRUCT_OFFSET(PixbufRendererClass, scroll_notify),			     NULL, NULL,			     g_cclosure_marshal_VOID__VOID,			     G_TYPE_NONE, 0);	signals[SIGNAL_RENDER_COMPLETE] = 		g_signal_new("render-complete",			     G_OBJECT_CLASS_TYPE(gobject_class),			     G_SIGNAL_RUN_LAST,			     G_STRUCT_OFFSET(PixbufRendererClass, render_complete),			     NULL, NULL,			     g_cclosure_marshal_VOID__VOID,			     G_TYPE_NONE, 0);}static void pixbuf_renderer_init(PixbufRenderer *pr){	GtkWidget *box;	box = GTK_WIDGET(pr);	pr->zoom_min = PR_ZOOM_MIN;	pr->zoom_max = PR_ZOOM_MAX;	pr->zoom_quality = GDK_INTERP_BILINEAR;	pr->zoom_2pass = FALSE;	pr->zoom = 1.0;	pr->scale = 1.0;	pr->dither_quality = GDK_RGB_DITHER_NORMAL;	pr->scroll_reset = PR_SCROLL_RESET_TOPLEFT;	pr->draw_idle_id = -1;	pr->tile_width = PR_TILE_SIZE;	pr->tile_height = PR_TILE_SIZE;	pr->tiles = NULL;	pr->tile_cache_size = 0;	pr->tile_cache_max = PR_CACHE_SIZE_DEFAULT;	pr->scroller_id = -1;	pr->scroller_overlay = -1;	pr->source_tiles_enabled = FALSE;	pr->source_tiles = NULL;	gtk_widget_set_double_buffered(box, FALSE);	g_signal_connect_after(G_OBJECT(box), "size_allocate",			       G_CALLBACK(pr_size_cb), pr);	pr_signals_connect(pr);}static void pixbuf_renderer_finalize(GObject *object){	PixbufRenderer *pr;	pr = PIXBUF_RENDERER(object);	pr_queue_clear(pr);	pr_tile_free_all(pr);	if (pr->pixbuf) g_object_unref(pr->pixbuf);	pr_scroller_timer_set(pr, FALSE);	pr_overlay_list_clear(pr);	pr_source_tile_free_all(pr);}PixbufRenderer* pixbuf_renderer_new(void){	return g_object_new(TYPE_PIXBUF_RENDERER, NULL);}static void pixbuf_renderer_set_property(GObject *object, guint prop_id,					 const GValue *value, GParamSpec *pspec){	PixbufRenderer *pr;	pr = PIXBUF_RENDERER(object);	switch (prop_id)		{		case PROP_ZOOM_MIN:			pr->zoom_min = g_value_get_double(value);			break;		case PROP_ZOOM_MAX:			pr->zoom_max = g_value_get_double(value);			break;		case PROP_ZOOM_QUALITY:			pr->zoom_quality = g_value_get_uint(value);			break;		case PROP_ZOOM_2PASS:			pr->zoom_2pass = g_value_get_boolean(value);			break;		case PROP_ZOOM_EXPAND:			pr->zoom_expand = g_value_get_boolean(value);			break;		case PROP_DITHER_QUALITY:			pr->dither_quality = g_value_get_uint(value);			break;		case PROP_SCROLL_RESET:			pr->scroll_reset = g_value_get_uint(value);			break;		case PROP_DELAY_FLIP:			pr->delay_flip = g_value_get_boolean(value);			break;		case PROP_LOADING:			pr->loading = g_value_get_boolean(value);			break;		case PROP_COMPLETE:			pr->complete = g_value_get_boolean(value);			break;		case PROP_CACHE_SIZE_DISPLAY:			pr->tile_cache_max = g_value_get_uint(value);			break;		case PROP_CACHE_SIZE_TILES:			pr->source_tiles_cache_size = g_value_get_uint(value);			break;		case PROP_WINDOW_FIT:			pr->window_fit = g_value_get_boolean(value);			break;		case PROP_WINDOW_LIMIT:			pr->window_limit = g_value_get_boolean(value);			break;		case PROP_WINDOW_LIMIT_VALUE:			pr->window_limit_size = g_value_get_uint(value);			break;		default:			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);			break;		}}static void pixbuf_renderer_get_property(GObject *object, guint prop_id,					 GValue *value, GParamSpec *pspec){	PixbufRenderer *pr;	pr = PIXBUF_RENDERER(object);	switch (prop_id)		{		case PROP_ZOOM_MIN:			g_value_set_double(value, pr->zoom_min);			break;		case PROP_ZOOM_MAX:			g_value_set_double(value, pr->zoom_max);			break;		case PROP_ZOOM_QUALITY:			g_value_set_uint(value, pr->zoom_quality);			break;		case PROP_ZOOM_2PASS:			g_value_set_boolean(value, pr->zoom_2pass);			break;		case PROP_ZOOM_EXPAND:			g_value_set_boolean(value, pr->zoom_expand);			break;		case PROP_DITHER_QUALITY:			g_value_set_uint(value, pr->dither_quality);			break;		case PROP_SCROLL_RESET:			g_value_set_uint(value, pr->scroll_reset);			break;		case PROP_DELAY_FLIP:			g_value_set_boolean(value, pr->delay_flip);			break;		case PROP_LOADING:

⌨️ 快捷键说明

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