Don't use a side buffer to load thumbnails

Undoing part of a recent commit.
This commit is contained in:
Přemysl Eric Janouch 2021-11-15 10:16:10 +01:00
parent 6f86911df6
commit e835c889a1
Signed by: p
GPG Key ID: A0420B94F92B9493
1 changed files with 25 additions and 26 deletions

View File

@ -645,12 +645,12 @@ read_spng_thumbnail(
const gchar *path, const gchar *uri, time_t mtime, GError **error) const gchar *path, const gchar *uri, time_t mtime, GError **error)
{ {
FILE *fp; FILE *fp;
cairo_surface_t *result = NULL;
if (!(fp = fopen(path, "rb"))) { if (!(fp = fopen(path, "rb"))) {
set_error(error, g_strerror(errno)); set_error(error, g_strerror(errno));
return NULL; return NULL;
} }
cairo_surface_t *result = NULL;
errno = 0; errno = 0;
spng_ctx *ctx = spng_ctx_new(0); spng_ctx *ctx = spng_ctx_new(0);
if (!ctx) { if (!ctx) {
@ -671,7 +671,22 @@ read_spng_thumbnail(
goto fail; goto fail;
} }
uint32_t *data = g_malloc0(size); struct spng_ihdr ihdr = {};
spng_get_ihdr(ctx, &ihdr);
cairo_surface_t *surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, ihdr.width, ihdr.height);
cairo_status_t surface_status = cairo_surface_status(surface);
if (surface_status != CAIRO_STATUS_SUCCESS) {
set_error(error, cairo_status_to_string(surface_status));
goto fail_data;
}
uint32_t *data = (uint32_t *) cairo_image_surface_get_data(surface);
g_assert((size_t) cairo_image_surface_get_stride(surface) *
cairo_image_surface_get_height(surface) == size);
cairo_surface_flush(surface);
if ((err = spng_decode_image(ctx, data, size, SPNG_FMT_RGBA8, if ((err = spng_decode_image(ctx, data, size, SPNG_FMT_RGBA8,
SPNG_DECODE_TRNS | SPNG_DECODE_GAMMA))) { SPNG_DECODE_TRNS | SPNG_DECODE_GAMMA))) {
set_error(error, spng_strerror(err)); set_error(error, spng_strerror(err));
@ -686,47 +701,31 @@ read_spng_thumbnail(
goto fail_data; goto fail_data;
} }
struct spng_ihdr ihdr = {};
spng_get_ihdr(ctx, &ihdr);
cairo_surface_t *surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, ihdr.width, ihdr.height);
cairo_status_t surface_status = cairo_surface_status(surface);
if (surface_status != CAIRO_STATUS_SUCCESS) {
set_error(error, cairo_status_to_string(surface_status));
cairo_surface_destroy(surface);
goto fail_data;
}
g_assert((size_t) cairo_image_surface_get_stride(surface) *
cairo_image_surface_get_height(surface) == size);
// pixman can be mildly abused to do this operation, but it won't be faster. // pixman can be mildly abused to do this operation, but it won't be faster.
uint32_t *output = (uint32_t *) cairo_image_surface_get_data(surface);
cairo_surface_flush(surface);
struct spng_trns trns = {}; struct spng_trns trns = {};
if (ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE_ALPHA || if (ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE_ALPHA ||
ihdr.color_type == SPNG_COLOR_TYPE_TRUECOLOR_ALPHA || ihdr.color_type == SPNG_COLOR_TYPE_TRUECOLOR_ALPHA ||
!spng_get_trns(ctx, &trns)) { !spng_get_trns(ctx, &trns)) {
for (size_t i = size / sizeof *output; i--; ) { for (size_t i = size / sizeof *data; i--; ) {
const uint8_t *unit = (const uint8_t *) &data[i], const uint8_t *unit = (const uint8_t *) &data[i],
a = unit[3], a = unit[3],
b = unit[2] * a / 255, b = unit[2] * a / 255,
g = unit[1] * a / 255, g = unit[1] * a / 255,
r = unit[0] * a / 255; r = unit[0] * a / 255;
output[i] = a << 24 | r << 16 | g << 8 | b; data[i] = a << 24 | r << 16 | g << 8 | b;
} }
} else { } else {
for (size_t i = size / sizeof *output; i--; ) { for (size_t i = size / sizeof *data; i--; ) {
uint32_t x = g_ntohl(data[i]); uint32_t rgba = g_ntohl(data[i]);
output[i] = x << 24 | x >> 8; data[i] = rgba << 24 | rgba >> 8;
} }
} }
cairo_surface_mark_dirty((result = surface)); cairo_surface_mark_dirty((result = surface));
fail_data: fail_data:
free(data); if (!result)
cairo_surface_destroy(surface);
fail: fail:
spng_ctx_free(ctx); spng_ctx_free(ctx);
fail_init: fail_init: