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

📄 pixbuf-renderer.c

📁 Gqview,Linux下基于GTK+库写成的轻量级而能丰富的图像浏览程序。
💻 C
📖 第 1 页 / 共 5 页
字号:
	while (work && pr->tile_cache_size + space > tile_max)		{		ImageTile *needle;		needle = work->data;		work = work->prev;		if (needle != it &&		    ((!needle->qd && !needle->qd2) || !pr_tile_is_visible(pr, needle))) pr_tile_remove(pr, needle);		}}static void pr_tile_invalidate_all(PixbufRenderer *pr){	GList *work;	work = pr->tiles;	while (work)		{		ImageTile *it;		it = work->data;		work = work->next;		it->render_done = TILE_RENDER_NONE;		it->render_todo = TILE_RENDER_ALL;		it->blank = FALSE;		it->w = MIN(pr->tile_width, pr->width - it->x);		it->h = MIN(pr->tile_height, pr->height - it->y);		}}static void pr_tile_invalidate_region(PixbufRenderer *pr, gint x, gint y, gint w, gint h){	gint x1, x2;	gint y1, y2;	GList *work;	x1 = (gint)floor(x / pr->tile_width) * pr->tile_width;	x2 = (gint)ceil((x + w) / pr->tile_width) * pr->tile_width;	y1 = (gint)floor(y / pr->tile_height) * pr->tile_height;	y2 = (gint)ceil((y + h) / pr->tile_height) * pr->tile_height;	work = pr->tiles;	while (work)		{		ImageTile *it;		it = work->data;		work = work->next;		if (it->x < x2 && it->x + it->w > x1 &&		    it->y < y2 && it->y + it->h > y1)			{			it->render_done = TILE_RENDER_NONE;			it->render_todo = TILE_RENDER_ALL;			}		}}static ImageTile *pr_tile_get(PixbufRenderer *pr, gint x, gint y, gint only_existing){	GList *work;	work = pr->tiles;	while (work)		{		ImageTile *it;		it = work->data;		if (it->x == x && it->y == y)			{			pr->tiles = g_list_delete_link(pr->tiles, work);			pr->tiles = g_list_prepend(pr->tiles, it);			return it;			}		work = work->next;		}	if (only_existing) return NULL;	return pr_tile_add(pr, x, y);}static void pr_tile_prepare(PixbufRenderer *pr, ImageTile *it){	if (!it->pixmap)		{		GdkPixmap *pixmap;		guint size;		pixmap = gdk_pixmap_new(((GtkWidget *)pr)->window, pr->tile_width, pr->tile_height, -1);		size = pixmap_calc_size(pixmap);		pr_tile_free_space(pr, size, it);		it->pixmap = pixmap;		it->size += size;		pr->tile_cache_size += size;		}		if ((pr->zoom != 1.0 || pr->source_tiles_enabled || (pr->pixbuf && gdk_pixbuf_get_has_alpha(pr->pixbuf)) ) &&	    !it->pixbuf)		{		GdkPixbuf *pixbuf;		guint size;		if (pr->pixbuf)			{			pixbuf = gdk_pixbuf_new(gdk_pixbuf_get_colorspace(pr->pixbuf),						gdk_pixbuf_get_has_alpha(pr->pixbuf),						gdk_pixbuf_get_bits_per_sample(pr->pixbuf),						pr->tile_width, pr->tile_height);			}		else			{			pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, pr->tile_width, pr->tile_height);			}		size = gdk_pixbuf_get_rowstride(pixbuf) * pr->tile_height;		pr_tile_free_space(pr, size, it);		it->pixbuf = pixbuf;		it->size += size;		pr->tile_cache_size += size;		}}/* *------------------------------------------------------------------- * drawing *------------------------------------------------------------------- */static void pr_tile_render(PixbufRenderer *pr, ImageTile *it,			   gint x, gint y, gint w, gint h,			   gint new_data, gint fast){	GtkWidget *box;	gint has_alpha;	gint draw = FALSE;	if (it->render_todo == TILE_RENDER_NONE && it->pixmap && !new_data) return;	if (it->render_done != TILE_RENDER_ALL)		{		x = 0;		y = 0;		w = it->w;		h = it->h;		if (!fast) it->render_done = TILE_RENDER_ALL;		}	else if (it->render_todo != TILE_RENDER_AREA)		{		if (!fast) it->render_todo = TILE_RENDER_NONE;		return;		}	if (!fast) it->render_todo = TILE_RENDER_NONE;	if (new_data) it->blank = FALSE;	pr_tile_prepare(pr, it);	has_alpha = (pr->pixbuf && gdk_pixbuf_get_has_alpha(pr->pixbuf));	box = GTK_WIDGET(pr);	/* FIXME checker colors for alpha should be configurable,	 * also should be drawn for blank = TRUE	 */	if (it->blank)		{		/* no data, do fast rect fill */		gdk_draw_rectangle(it->pixmap, box->style->black_gc, TRUE,				   0, 0, it->w, it->h);		}	else if (pr->source_tiles_enabled)		{		draw = pr_source_tile_render(pr, it, x, y, w, h, new_data, fast);		}	else if (pr->zoom == 1.0 || pr->scale == 1.0)		{		if (has_alpha)			{			gdk_pixbuf_composite_color(pr->pixbuf, it->pixbuf, x, y, w, h,					 (double) 0.0 - it->x,					 (double) 0.0 - it->y,					 1.0, 1.0, GDK_INTERP_NEAREST,					 255, it->x + x, it->y + y,					 PR_ALPHA_CHECK_SIZE, PR_ALPHA_CHECK1, PR_ALPHA_CHECK2);			draw = TRUE;			}		else			{			/* faster, simple */			gdk_draw_pixbuf(it->pixmap,					box->style->fg_gc[GTK_WIDGET_STATE(box)],					pr->pixbuf,					it->x + x, it->y + y,					x, y,					w, h,					pr->dither_quality, it->x + x, it->y + y);			}		}	else		{		double scale_x, scale_y;		if (pr->image_width == 0 || pr->image_height == 0) return;		scale_x = (double)pr->width / pr->image_width;		scale_y = (double)pr->height / pr->image_height;		/* HACK: The pixbuf scalers get kinda buggy(crash) with extremely		 * small sizes for anything but GDK_INTERP_NEAREST		 */		if (pr->width < PR_MIN_SCALE_SIZE || pr->height < PR_MIN_SCALE_SIZE) fast = TRUE;		if (!has_alpha)			{			gdk_pixbuf_scale(pr->pixbuf, it->pixbuf, x, y, w, h,					 (double) 0.0 - it->x,					 (double) 0.0 - it->y,					 scale_x, scale_y,					 (fast) ? GDK_INTERP_NEAREST : pr->zoom_quality);			}		else			{			gdk_pixbuf_composite_color(pr->pixbuf, it->pixbuf, x, y, w, h,					 (double) 0.0 - it->x,					 (double) 0.0 - it->y,					 scale_x, scale_y,					 (fast) ? GDK_INTERP_NEAREST : pr->zoom_quality,					 255, it->x + x, it->y + y,					 PR_ALPHA_CHECK_SIZE, PR_ALPHA_CHECK1, PR_ALPHA_CHECK2);			}		draw = TRUE;		}	if (draw && it->pixbuf && !it->blank)		{		gdk_draw_pixbuf(it->pixmap,				box->style->fg_gc[GTK_WIDGET_STATE(box)],				it->pixbuf,				x, y,				x, y,				w, h,				pr->dither_quality, it->x + x, it->y + y);		}}static void pr_tile_expose(PixbufRenderer *pr, ImageTile *it,			   gint x, gint y, gint w, gint h,			   gint new_data, gint fast){	GtkWidget *box;	pr_tile_render(pr, it, x, y, w, h, new_data, fast);	box = GTK_WIDGET(pr);	gdk_draw_drawable(box->window, box->style->fg_gc[GTK_WIDGET_STATE(box)],			  it->pixmap, x, y,			  pr->x_offset + (it->x - pr->x_scroll) + x, pr->y_offset + (it->y - pr->y_scroll) + y, w, h);	if (pr->overlay_list)		{		pr_overlay_draw(pr, pr->x_offset + (it->x - pr->x_scroll) + x,				pr->y_offset + (it->y - pr->y_scroll) + y,				w, h);		}}static gint pr_tile_is_visible(PixbufRenderer *pr, ImageTile *it){	return (it->x + it->w >= pr->x_scroll && it->x < pr->x_scroll + pr->vis_width &&		it->y + it->h >= pr->y_scroll && it->y < pr->y_scroll + pr->vis_height);}/* *------------------------------------------------------------------- * draw queue *------------------------------------------------------------------- */static gint pr_queue_draw_idle_cb(gpointer data){	PixbufRenderer *pr = data;	QueueData *qd;	gint fast;	if ((!pr->pixbuf && !pr->source_tiles_enabled) ||	    (!pr->draw_queue && !pr->draw_queue_2pass) ||	    pr->draw_idle_id == -1)		{		pr_render_complete_signal(pr);		pr->draw_idle_id = -1;		return FALSE;		}	if (pr->draw_queue)		{		qd = pr->draw_queue->data;		fast = (pr->zoom_2pass && pr->zoom_quality != GDK_INTERP_NEAREST && pr->scale != 1.0);		}	else		{		if (pr->loading)			{			/* still loading, wait till done (also drops the higher priority) */			pr->draw_idle_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,							   pr_queue_draw_idle_cb, pr, NULL);			pr->draw_idle_high = FALSE;			return FALSE;			}		qd = pr->draw_queue_2pass->data;		fast = FALSE;		}	if (GTK_WIDGET_REALIZED(pr))		{		if (pr_tile_is_visible(pr, qd->it))			{			pr_tile_expose(pr, qd->it, qd->x, qd->y, qd->w, qd->h, qd->new_data, fast);			}		else if (qd->new_data)			{			/* if new pixel data, and we already have a pixmap, update the tile */			qd->it->blank = FALSE;			if (qd->it->pixmap && qd->it->render_done == TILE_RENDER_ALL)				{				pr_tile_render(pr, qd->it, qd->x, qd->y, qd->w, qd->h, qd->new_data, fast);				}			}		}	if (pr->draw_queue)		{		qd->it->qd = NULL;		pr->draw_queue = g_list_remove(pr->draw_queue, qd);		if (fast)			{			if (qd->it->qd2)				{				pr_queue_merge(qd->it->qd2, qd);				g_free(qd);				}			else				{				qd->it->qd2 = qd;				pr->draw_queue_2pass = g_list_append(pr->draw_queue_2pass, qd);				}			}		else			{			g_free(qd);			}		}	else		{		qd->it->qd2 = NULL;		pr->draw_queue_2pass = g_list_remove(pr->draw_queue_2pass, qd);		g_free(qd);		}	if (!pr->draw_queue && !pr->draw_queue_2pass)		{		pr_render_complete_signal(pr);		pr->draw_idle_id = -1;		return FALSE;		}	return TRUE;}static void pr_queue_list_free(GList *list){	GList *work;	work = list;	while (work)		{		QueueData *qd;		qd = work->data;		work = work->next;		qd->it->qd = NULL;		qd->it->qd2 = NULL;		g_free(qd);		}	g_list_free(list);}static void pr_queue_clear(PixbufRenderer *pr){	pr_queue_list_free(pr->draw_queue);	pr->draw_queue = NULL;	pr_queue_list_free(pr->draw_queue_2pass);	pr->draw_queue_2pass = NULL;	if (pr->draw_idle_id != -1) g_source_remove(pr->draw_idle_id);	pr->draw_idle_id = -1;}static void pr_queue_merge(QueueData *parent, QueueData *qd){	if (parent->x + parent->w < qd->x + qd->w)		{		parent->w += (qd->x + qd->w) - (parent->x + parent->w);		}	if (parent->x > qd->x)		{		parent->w += parent->x - qd->x;		parent->x = qd->x;		}	if (parent->y + parent->h < qd->y + qd->h)		{		parent->h += (qd->y + qd->h) - (parent->y + parent->h);		}	if (parent->y > qd->y)		{		parent->h += parent->y - qd->y;		parent->y = qd->y;		}	parent->new_data |= qd->new_data;}static gint pr_clamp_to_visible(PixbufRenderer *pr, gint *x, gint *y, gint *w, gint *h){	gint nx, ny;	gint nw, nh;	gint vx, vy;	gint vw, vh;	vw = pr->vis_width;	vh = pr->vis_height;	vx = pr->x_scroll;	vy = pr->y_scroll;	if (*x + *w < vx || *x > vx + vw || *y + *h < vy || *y > vy + vh) return FALSE;	/* now clamp it */	nx = CLAMP(*x, vx, vx + vw);	nw = CLAMP(*w - (nx - *x), 1, vw);	ny = CLAMP(*y, vy, vy + vh);	nh = CLAMP(*h - (ny - *y), 1, vh);	*x = nx;	*y = ny;	*w = nw;	*h = nh;	return TRUE;}static gint pr_queue_to_tiles(PixbufRenderer *pr, gint x, gint y, gint w, gint h,			      gint clamp, ImageTileRenderType render, gint new_data, gint only_existing){	gint i, j;	gint x1, x2;	gint y1, y2;	if (clamp && !pr_clamp_to_visible(pr, &x, &y, &w, &h)) return FALSE;	x1 = (gint)floor(x / pr->tile_width) * pr->tile_width;	x2 = (gint)ceil((x + w) / pr->tile_width) * pr->tile_width;	y1 = (gint)floor(y / pr->tile_height) * pr->tile_height;	y2 = (gint)ceil((y + h) / pr->tile_height) * pr->tile_height;	for (j = y1; j <= y2; j += pr->tile_height)		{		for (i = x1; i <= x2; i += pr->tile_width)			{			ImageTile *it;			it = pr_tile_get(pr, i, j,					 (only_existing &&					  (i + pr->tile_width < pr->x_scroll ||					   i > pr->x_scroll + pr->vis_width ||					   j + pr->tile_height < pr->y_scroll ||					   j > pr->y_scroll + pr->vis_height)));			if (it)				{				QueueData *qd;				if ((render == TILE_RENDER_ALL && it->render_done != TILE_RENDER_ALL) ||				    (render == TILE_RENDER_AREA && it->render_todo != TILE_RENDER_ALL))					{					it->render_todo = render;					}				qd = g_new(QueueData, 1);				qd->it = it;				qd->new_data = new_data;				if (i < x)					{					qd->x = x - i;					}				else					{					qd->x = 0;					}				qd->w = x + w - i - qd->x;				if (qd->x + qd->w > pr->tile_width) qd->w = pr->tile_width - qd->x;				if (j < y)					{					qd->y = y - j;					}				else					{					qd->y = 0;					}				qd->h = y + h - j - qd->y;				if (qd->y + qd->h > pr->tile_height) qd->h = pr->tile_height - qd->y;				if (qd->w < 1 || qd->h < 1)					{					g_free(qd);					}				else if (it->qd)					{					pr_queue_merge(it->qd, qd);					g_free(qd);					}				else					{					it->qd = qd;					pr->draw_queue = g_list_append(pr->draw_queue, qd);					}				}			}		}	return TRUE;}static void pr_queue(PixbufRenderer *pr, gint x, gint y, gint w, gint h,		     gint clamp, ImageTileRenderType render, gint new_data, gint only_existing){	gint nx, ny;	nx = CLAMP(x, 0, pr->width - 1);	ny = CLAMP(y, 0, pr->height - 1);	w -= (nx - x);	h -= (ny - y);	w = CLAMP(w, 0, pr->width - nx);	h = CLAMP(h, 0, pr->height - ny);	if (w < 1 || h < 1) return;	if (pr_queue_to_tiles(pr, nx, ny, w, h, clamp, render, new_data, only_existing) &&	    ((!pr->draw_queue && !pr->draw_queue_2pass) || pr->draw_idle_id == -1 || !pr->draw_idle_high))		{		if (pr->draw_idle_id != -1) g_source_remove(pr->draw_idle_id);		pr->draw_idle_id = g_idle_add_full(GDK_PRIORITY_REDRAW,						   pr_queue_draw_idle_cb, pr, NULL);		pr->draw_idle_high = TRUE;		}}static void pr_redraw(PixbufRenderer *pr, gint new_data){	pr_queue_clear(pr);

⌨️ 快捷键说明

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