📄 pixbuf-renderer.c
字号:
pr_border_draw(pr, 0, 0, pr->window_width, pr->window_height);}void pixbuf_renderer_set_color(PixbufRenderer *pr, GdkColor *color){ GtkStyle *style; GtkWidget *widget; g_return_if_fail(IS_PIXBUF_RENDERER(pr)); widget = GTK_WIDGET(pr); style = gtk_style_copy(gtk_widget_get_style(widget)); g_object_ref(G_OBJECT(style)); if (color) { GdkColor *slot; slot = &style->bg[GTK_STATE_NORMAL]; slot->red = color->red; slot->green = color->green; slot->blue = color->blue; } gtk_widget_set_style(widget, style); g_object_unref(G_OBJECT(style)); if (GTK_WIDGET_VISIBLE(widget)) pr_border_clear(pr);}void pixbuf_renderer_set_black(PixbufRenderer *pr, gint black){ GdkColor color = { 0, 0, 0, 0}; pixbuf_renderer_set_color(pr, &color);}/* *------------------------------------------------------------------- * source tiles *------------------------------------------------------------------- */static void pr_source_tile_free(SourceTile *st){ if (!st) return; if (st->pixbuf) g_object_unref(st->pixbuf); g_free(st);}static void pr_source_tile_free_all(PixbufRenderer *pr){ GList *work; work = pr->source_tiles; while (work) { SourceTile *st; st = work->data; work = work->next; pr_source_tile_free(st); } g_list_free(pr->source_tiles); pr->source_tiles = NULL;}static void pr_source_tile_unset(PixbufRenderer *pr){ pr_source_tile_free_all(pr); pr->source_tiles_enabled = FALSE;}static gint pr_source_tile_visible(PixbufRenderer *pr, SourceTile *st){ gint x1, y1, x2, y2; if (!st) return FALSE; x1 = (pr->x_scroll / pr->tile_width) * pr->tile_width; y1 = (pr->y_scroll / pr->tile_height) * pr->tile_height; x2 = ((pr->x_scroll + pr->vis_width) / pr->tile_width) * pr->tile_width + pr->tile_width; y2 = ((pr->y_scroll + pr->vis_height) / pr->tile_height) * pr->tile_height + pr->tile_height; return !((double)st->x * pr->scale > (double)x2 || (double)(st->x + pr->source_tile_width) * pr->scale < (double)x1 || (double)st->y * pr->scale > (double)y2 || (double)(st->y + pr->source_tile_height) * pr->scale < (double)y1);}static SourceTile *pr_source_tile_new(PixbufRenderer *pr, gint x, gint y){ SourceTile *st = NULL; gint count; g_return_val_if_fail(pr->source_tile_width >= 1 && pr->source_tile_height >= 1, NULL); if (pr->source_tiles_cache_size < 4) pr->source_tiles_cache_size = 4; count = g_list_length(pr->source_tiles); if (count >= pr->source_tiles_cache_size) { GList *work; work = g_list_last(pr->source_tiles); while (work && count >= pr->source_tiles_cache_size) { SourceTile *needle; needle = work->data; work = work->prev; if (!pr_source_tile_visible(pr, needle)) { pr->source_tiles = g_list_remove(pr->source_tiles, needle); if (pr->func_tile_dispose) { pr->func_tile_dispose(pr, needle->x, needle->y, pr->source_tile_width, pr->source_tile_height, needle->pixbuf, pr->func_tile_data); } if (!st) { st = needle; } else { pr_source_tile_free(needle); } count--; } } } if (!st) { st = g_new0(SourceTile, 1); st->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, pr->source_tile_width, pr->source_tile_height); } st->x = (x / pr->source_tile_width) * pr->source_tile_width; st->y = (y / pr->source_tile_height) * pr->source_tile_height; st->blank = TRUE; pr->source_tiles = g_list_prepend(pr->source_tiles, st); return st;}static SourceTile *pr_source_tile_request(PixbufRenderer *pr, gint x, gint y){ SourceTile *st; st = pr_source_tile_new(pr, x, y); if (!st) return NULL; if (pr->func_tile_request && pr->func_tile_request(pr, st->x, st->y, pr->source_tile_width, pr->source_tile_height, st->pixbuf, pr->func_tile_data)) { st->blank = FALSE; } pr_tile_invalidate_region(pr, st->x * pr->scale, st->y * pr->scale, pr->source_tile_width * pr->scale, pr->source_tile_height * pr->scale); return st;}static SourceTile *pr_source_tile_find(PixbufRenderer *pr, gint x, gint y){ GList *work; work = pr->source_tiles; while (work) { SourceTile *st = work->data; if (x >= st->x && x < st->x + pr->source_tile_width && y >= st->y && y < st->y + pr->source_tile_height) { if (work != pr->source_tiles) { pr->source_tiles = g_list_remove_link(pr->source_tiles, work); pr->source_tiles = g_list_concat(work, pr->source_tiles); } return st; } work = work->next; } return NULL;}static GList *pr_source_tile_compute_region(PixbufRenderer *pr, gint x, gint y, gint w, gint h, gint request){ gint x1, y1; GList *list = NULL; gint sx, sy; if (x < 0) x = 0; if (y < 0) y = 0; if (w > pr->image_width) w = pr->image_width; if (h > pr->image_height) h = pr->image_height; sx = (x / pr->source_tile_width) * pr->source_tile_width; sy = (y / pr->source_tile_height) * pr->source_tile_height; for (x1 = sx; x1 < x + w; x1+= pr->source_tile_width) { for (y1 = sy; y1 < y + h; y1 += pr->source_tile_height) { SourceTile *st; st = pr_source_tile_find(pr, x1, y1); if (!st && request) st = pr_source_tile_request(pr, x1, y1); if (st) list = g_list_prepend(list, st); } } return g_list_reverse(list);}static void pr_source_tile_changed(PixbufRenderer *pr, gint x, gint y, gint width, gint height){ GList *work; work = pr->source_tiles; while (work) { SourceTile *st; gint rx, ry, rw, rh; st = work->data; work = work->next; if (pr_clip_region(st->x, st->y, pr->source_tile_width, pr->source_tile_height, x, y, width, height, &rx, &ry, &rw, &rh)) { GdkPixbuf *pixbuf; pixbuf = gdk_pixbuf_new_subpixbuf(st->pixbuf, rx - st->x, ry - st->y, rw, rh); if (pr->func_tile_request && pr->func_tile_request(pr, rx, ry, rw, rh, pixbuf, pr->func_tile_data)) { pr_tile_invalidate_region(pr, rx * pr->scale, ry * pr->scale, rw * pr->scale, rh * pr->scale); } g_object_unref(pixbuf); } }}static gint pr_source_tile_render(PixbufRenderer *pr, ImageTile *it, gint x, gint y, gint w, gint h, gint new_data, gint fast){ GtkWidget *box; GList *list; GList *work; gint draw = FALSE; box = GTK_WIDGET(pr); if (pr->zoom == 1.0 || pr->scale == 1.0) { list = pr_source_tile_compute_region(pr, it->x + x, it->y + y, w, h, TRUE); work = list; while (work) { SourceTile *st; gint rx, ry, rw, rh; st = work->data; work = work->next; if (pr_clip_region(st->x, st->y, pr->source_tile_width, pr->source_tile_height, it->x + x, it->y + y, w, h, &rx, &ry, &rw, &rh)) { if (st->blank) { gdk_draw_rectangle(it->pixmap, box->style->black_gc, TRUE, rx - st->x, ry - st->y, rw, rh); } else /* (pr->zoom == 1.0 || pr->scale == 1.0) */ { gdk_draw_pixbuf(it->pixmap, box->style->fg_gc[GTK_WIDGET_STATE(box)], st->pixbuf, rx - st->x, ry - st->y, rx - it->x, ry - it->y, rw, rh, pr->dither_quality, rx, ry); } } } } else { double scale_x, scale_y; gint sx, sy, sw, sh; if (pr->image_width == 0 || pr->image_height == 0) return FALSE; scale_x = (double)pr->width / pr->image_width; scale_y = (double)pr->height / pr->image_height; sx = (double)(it->x + x) / scale_x; sy = (double)(it->y + y) / scale_y; sw = (double)w / scale_x; sh = (double)h / scale_y; if (pr->width < PR_MIN_SCALE_SIZE || pr->height < PR_MIN_SCALE_SIZE) fast = TRUE;#if 0 /* draws red over draw region, to check for leaks (regions not filled) */ pixbuf_set_rect_fill(it->pixbuf, x, y, w, h, 255, 0, 0, 255);#endif list = pr_source_tile_compute_region(pr, sx, sy, sw, sh, TRUE); work = list; while (work) { SourceTile *st; gint rx, ry, rw, rh; gint stx, sty, stw, sth; st = work->data; work = work->next; stx = floor((double)st->x * scale_x); sty = floor((double)st->y * scale_y); stw = ceil ((double)(st->x + pr->source_tile_width) * scale_x) - stx; sth = ceil ((double)(st->y + pr->source_tile_height) * scale_y) - sty; if (pr_clip_region(stx, sty, stw, sth, it->x + x, it->y + y, w, h, &rx, &ry, &rw, &rh)) { if (st->blank) { gdk_draw_rectangle(it->pixmap, box->style->black_gc, TRUE, rx - st->x, ry - st->y, rw, rh); } else { double offset_x; double offset_y; /* may need to use unfloored stx,sty values here */ offset_x = (double)(stx - it->x); offset_y = (double)(sty - it->y); gdk_pixbuf_scale(st->pixbuf, it->pixbuf, rx - it->x, ry - it->y, rw, rh, (double) 0.0 + offset_x, (double) 0.0 + offset_y, scale_x, scale_y, (fast) ? GDK_INTERP_NEAREST : pr->zoom_quality); draw = TRUE; } } } } g_list_free(list); return draw;}void pixbuf_renderer_set_tiles(PixbufRenderer *pr, gint width, gint height, gint tile_width, gint tile_height, gint cache_size, PixbufRendererTileRequestFunc func_request, PixbufRendererTileDisposeFunc func_dispose, gpointer user_data, gdouble zoom){ g_return_if_fail(IS_PIXBUF_RENDERER(pr)); g_return_if_fail(tile_width >= 32 && tile_width >= 32); g_return_if_fail(width >= 32 && height > 32); g_return_if_fail(func_request != NULL); if (pr->pixbuf) g_object_unref(pr->pixbuf); pr->pixbuf = NULL; pr_source_tile_unset(pr); if (cache_size < 4) cache_size = 4; pr->source_tiles_enabled = TRUE; pr->source_tiles_cache_size = cache_size; pr->source_tile_width = tile_width; pr->source_tile_height = tile_height; pr->image_width = width; pr->image_height = height; pr->func_tile_request = func_request; pr->func_tile_dispose = func_dispose; pr->func_tile_data = user_data; pr_zoom_sync(pr, zoom, TRUE, FALSE, TRUE, FALSE, 0, 0); pr_redraw(pr, TRUE);}gint pixbuf_renderer_get_tiles(PixbufRenderer *pr){ g_return_val_if_fail(IS_PIXBUF_RENDERER(pr), FALSE); return pr->source_tiles_enabled;}static void pr_zoom_adjust_real(PixbufRenderer *pr, gdouble increment, gint center_point, gint x, gint y){ gdouble zoom = pr->zoom; if (increment == 0.0) return; if (zoom == 0.0) { if (pr->scale < 1.0) { zoom = 0.0 - 1.0 / pr->scale; } else { zoom = pr->scale; } } if (increment < 0.0) { if (zoom >= 1.0 && zoom + increment < 1.0) { zoom = zoom + increment - 2.0; } else { zoom = zoom + increment; } } else { if (zoom <= -1.0 && zoom + increment > -1.0) { zoom = zoom + increment + 2.0; } else { zoom = zoom + increment; } } pr_zoom_sync(pr, zoom, FALSE, FALSE, FALSE, center_point, x, y);}/* *------------------------------------------------------------------- * display tiles *------------------------------------------------------------------- */static ImageTile *pr_tile_new(gint x, gint y, gint width, gint height){ ImageTile *it; it = g_new0(ImageTile, 1); it->x = x; it->y = y; it->w = width; it->h = height; it->render_done = TILE_RENDER_NONE; return it;}static void pr_tile_free(ImageTile *it){ if (!it) return; if (it->pixbuf) gdk_pixbuf_unref(it->pixbuf); if (it->pixmap) g_object_unref(it->pixmap); g_free(it);}static void pr_tile_free_all(PixbufRenderer *pr){ GList *work; work = pr->tiles; while (work) { ImageTile *it; it = work->data; work = work->next; pr_tile_free(it); } g_list_free(pr->tiles); pr->tiles = NULL; pr->tile_cache_size = 0;}static ImageTile *pr_tile_add(PixbufRenderer *pr, gint x, gint y){ ImageTile *it; it = pr_tile_new(x, y, pr->tile_width, pr->tile_height); if (it->x + it->w > pr->width) it->w = pr->width - it->x; if (it->y + it->h > pr->height) it->h = pr->height - it->y; pr->tiles = g_list_prepend(pr->tiles, it); pr->tile_cache_size += it->size; return it;}static void pr_tile_remove(PixbufRenderer *pr, ImageTile *it){ if (it->qd) { QueueData *qd = it->qd; it->qd = NULL; pr->draw_queue = g_list_remove(pr->draw_queue, qd); g_free(qd); } if (it->qd2) { QueueData *qd = it->qd2; it->qd2 = NULL; pr->draw_queue_2pass = g_list_remove(pr->draw_queue_2pass, qd); g_free(qd); } pr->tiles = g_list_remove(pr->tiles, it); pr->tile_cache_size -= it->size; pr_tile_free(it);}static void pr_tile_free_space(PixbufRenderer *pr, guint space, ImageTile *it){ GList *work; gint tile_max; work = g_list_last(pr->tiles); if (pr->source_tiles_enabled && pr->scale < 1.0) { gint tiles; tiles = (pr->vis_width / pr->tile_width + 1) * (pr->vis_height / pr->tile_height + 1); tile_max = MAX(tiles * pr->tile_width * pr->tile_height * 3, (gint)((double)pr->tile_cache_max * 1048576.0 * pr->scale)); } else { tile_max = pr->tile_cache_max * 1048576; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -