Pre-scale loaded thumbnails, and only when needed
This commit is contained in:
parent
dbc500ae9f
commit
cdb8d852a6
121
fastiv-browser.c
121
fastiv-browser.c
|
@ -37,6 +37,8 @@ entry_free(Entry *self)
|
||||||
cairo_surface_destroy(self->thumbnail);
|
cairo_surface_destroy(self->thumbnail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const double g_row_height = 256;
|
||||||
|
|
||||||
// --- Boilerplate -------------------------------------------------------------
|
// --- Boilerplate -------------------------------------------------------------
|
||||||
|
|
||||||
struct _FastivBrowser {
|
struct _FastivBrowser {
|
||||||
|
@ -135,8 +137,6 @@ fastiv_browser_draw(GtkWidget *widget, cairo_t *cr)
|
||||||
gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0,
|
gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0,
|
||||||
allocation.width, allocation.height);
|
allocation.width, allocation.height);
|
||||||
|
|
||||||
const double row_height = 256;
|
|
||||||
|
|
||||||
gint occupied_width = 0, y = 0;
|
gint occupied_width = 0, y = 0;
|
||||||
for (guint i = 0; i < self->entries->len; i++) {
|
for (guint i = 0; i < self->entries->len; i++) {
|
||||||
const Entry *entry = &g_array_index(self->entries, Entry, i);
|
const Entry *entry = &g_array_index(self->entries, Entry, i);
|
||||||
|
@ -145,65 +145,19 @@ fastiv_browser_draw(GtkWidget *widget, cairo_t *cr)
|
||||||
|
|
||||||
int width = cairo_image_surface_get_width(entry->thumbnail);
|
int width = cairo_image_surface_get_width(entry->thumbnail);
|
||||||
int height = cairo_image_surface_get_height(entry->thumbnail);
|
int height = cairo_image_surface_get_height(entry->thumbnail);
|
||||||
|
|
||||||
double scale_x = 1;
|
|
||||||
double scale_y = 1;
|
|
||||||
if (width > 2 * height) {
|
|
||||||
scale_x = 2 * row_height / width;
|
|
||||||
scale_y = round(scale_x * height) / height;
|
|
||||||
} else {
|
|
||||||
scale_y = row_height / height;
|
|
||||||
scale_x = round(scale_y * width) / width;
|
|
||||||
}
|
|
||||||
|
|
||||||
int projected_width = round(scale_x * width);
|
|
||||||
int projected_height = round(scale_y * height);
|
|
||||||
cairo_surface_t *scaled = cairo_image_surface_create(
|
|
||||||
CAIRO_FORMAT_ARGB32, projected_width, projected_height);
|
|
||||||
|
|
||||||
// pixman can take gamma into account when scaling, unlike Cairo.
|
|
||||||
struct pixman_f_transform xform_floating;
|
|
||||||
struct pixman_transform xform;
|
|
||||||
|
|
||||||
pixman_image_t *src = pixman_image_create_bits(
|
|
||||||
PIXMAN_a8r8g8b8_sRGB, width, height,
|
|
||||||
(uint32_t *) cairo_image_surface_get_data(entry->thumbnail),
|
|
||||||
cairo_image_surface_get_stride(entry->thumbnail));
|
|
||||||
pixman_image_t *dest = pixman_image_create_bits(
|
|
||||||
PIXMAN_a8r8g8b8_sRGB,
|
|
||||||
cairo_image_surface_get_width(scaled),
|
|
||||||
cairo_image_surface_get_height(scaled),
|
|
||||||
(uint32_t *) cairo_image_surface_get_data(scaled),
|
|
||||||
cairo_image_surface_get_stride(scaled));
|
|
||||||
|
|
||||||
pixman_f_transform_init_scale(&xform_floating, scale_x, scale_y);
|
|
||||||
pixman_f_transform_invert(&xform_floating, &xform_floating);
|
|
||||||
pixman_transform_from_pixman_f_transform(&xform, &xform_floating);
|
|
||||||
pixman_image_set_transform(src, &xform);
|
|
||||||
pixman_image_set_filter(src, PIXMAN_FILTER_BILINEAR, NULL, 0);
|
|
||||||
pixman_image_set_repeat(src, PIXMAN_REPEAT_PAD);
|
|
||||||
|
|
||||||
pixman_image_composite(PIXMAN_OP_SRC, src, NULL, dest, 0, 0, 0, 0, 0, 0,
|
|
||||||
projected_width, projected_height);
|
|
||||||
pixman_image_unref(src);
|
|
||||||
pixman_image_unref(dest);
|
|
||||||
|
|
||||||
cairo_surface_mark_dirty(scaled);
|
|
||||||
|
|
||||||
if (occupied_width != 0 &&
|
if (occupied_width != 0 &&
|
||||||
occupied_width + projected_width > allocation.width) {
|
occupied_width + width > allocation.width) {
|
||||||
occupied_width = 0;
|
occupied_width = 0;
|
||||||
y += row_height;
|
y += g_row_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_save(cr);
|
cairo_save(cr);
|
||||||
cairo_translate(cr, occupied_width, y + row_height - projected_height);
|
cairo_translate(cr, occupied_width, y + g_row_height - height);
|
||||||
cairo_set_source_surface(cr, scaled, 0, 0);
|
cairo_set_source_surface(cr, entry->thumbnail, 0, 0);
|
||||||
cairo_surface_destroy(scaled);
|
|
||||||
cairo_paint(cr);
|
cairo_paint(cr);
|
||||||
cairo_restore(cr);
|
cairo_restore(cr);
|
||||||
|
|
||||||
occupied_width += projected_width;
|
occupied_width += width;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -241,6 +195,64 @@ fastiv_browser_init(FastivBrowser *self)
|
||||||
self->selected = -1;
|
self->selected = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cairo_surface_t *
|
||||||
|
rescale_thumbnail(cairo_surface_t *thumbnail)
|
||||||
|
{
|
||||||
|
if (!thumbnail)
|
||||||
|
return thumbnail;
|
||||||
|
|
||||||
|
int width = cairo_image_surface_get_width(thumbnail);
|
||||||
|
int height = cairo_image_surface_get_height(thumbnail);
|
||||||
|
|
||||||
|
double scale_x = 1;
|
||||||
|
double scale_y = 1;
|
||||||
|
if (width > 2 * height) {
|
||||||
|
scale_x = 2 * g_row_height / width;
|
||||||
|
scale_y = round(scale_x * height) / height;
|
||||||
|
} else {
|
||||||
|
scale_y = g_row_height / height;
|
||||||
|
scale_x = round(scale_y * width) / width;
|
||||||
|
}
|
||||||
|
if (scale_x == 1 && scale_y == 1)
|
||||||
|
return thumbnail;
|
||||||
|
|
||||||
|
int projected_width = round(scale_x * width);
|
||||||
|
int projected_height = round(scale_y * height);
|
||||||
|
cairo_surface_t *scaled = cairo_image_surface_create(
|
||||||
|
CAIRO_FORMAT_ARGB32, projected_width, projected_height);
|
||||||
|
|
||||||
|
// pixman can take gamma into account when scaling, unlike Cairo.
|
||||||
|
struct pixman_f_transform xform_floating;
|
||||||
|
struct pixman_transform xform;
|
||||||
|
|
||||||
|
pixman_image_t *src = pixman_image_create_bits(
|
||||||
|
PIXMAN_a8r8g8b8_sRGB, width, height,
|
||||||
|
(uint32_t *) cairo_image_surface_get_data(thumbnail),
|
||||||
|
cairo_image_surface_get_stride(thumbnail));
|
||||||
|
pixman_image_t *dest = pixman_image_create_bits(
|
||||||
|
PIXMAN_a8r8g8b8_sRGB,
|
||||||
|
cairo_image_surface_get_width(scaled),
|
||||||
|
cairo_image_surface_get_height(scaled),
|
||||||
|
(uint32_t *) cairo_image_surface_get_data(scaled),
|
||||||
|
cairo_image_surface_get_stride(scaled));
|
||||||
|
|
||||||
|
pixman_f_transform_init_scale(&xform_floating, scale_x, scale_y);
|
||||||
|
pixman_f_transform_invert(&xform_floating, &xform_floating);
|
||||||
|
pixman_transform_from_pixman_f_transform(&xform, &xform_floating);
|
||||||
|
pixman_image_set_transform(src, &xform);
|
||||||
|
pixman_image_set_filter(src, PIXMAN_FILTER_BILINEAR, NULL, 0);
|
||||||
|
pixman_image_set_repeat(src, PIXMAN_REPEAT_PAD);
|
||||||
|
|
||||||
|
pixman_image_composite(PIXMAN_OP_SRC, src, NULL, dest, 0, 0, 0, 0, 0, 0,
|
||||||
|
projected_width, projected_height);
|
||||||
|
pixman_image_unref(src);
|
||||||
|
pixman_image_unref(dest);
|
||||||
|
|
||||||
|
cairo_surface_destroy(thumbnail);
|
||||||
|
cairo_surface_mark_dirty(scaled);
|
||||||
|
return scaled;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fastiv_browser_load(FastivBrowser *self, const char *path)
|
fastiv_browser_load(FastivBrowser *self, const char *path)
|
||||||
{
|
{
|
||||||
|
@ -259,7 +271,8 @@ fastiv_browser_load(FastivBrowser *self, const char *path)
|
||||||
gchar *subpath = g_build_filename(path, filename, NULL);
|
gchar *subpath = g_build_filename(path, filename, NULL);
|
||||||
g_array_append_val(self->entries,
|
g_array_append_val(self->entries,
|
||||||
((Entry){
|
((Entry){
|
||||||
.thumbnail = fastiv_io_lookup_thumbnail(subpath),
|
.thumbnail =
|
||||||
|
rescale_thumbnail(fastiv_io_lookup_thumbnail(subpath)),
|
||||||
.filename = subpath,
|
.filename = subpath,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue