Extract a function
This commit is contained in:
@@ -393,6 +393,87 @@ struct load_wuffs_frame_context {
|
||||
FivIoImage *restore_previous; ///< Canvas before the previous frame
|
||||
};
|
||||
|
||||
static bool
|
||||
load_wuffs_frame_compose(struct load_wuffs_frame_context *ctx,
|
||||
FivIoImage **image, const wuffs_base__frame_config *fc, GError **error)
|
||||
{
|
||||
// Copy the previous frame to a new image.
|
||||
FivIoImage *prev = ctx->result_tail, *canvas = fiv_io_image_new(
|
||||
prev->format, prev->width, prev->height);
|
||||
if (!canvas) {
|
||||
set_error(error, "image allocation failure");
|
||||
return false;
|
||||
}
|
||||
|
||||
FivIoImage *base = ctx->restore_previous ? ctx->restore_previous : prev;
|
||||
memcpy(canvas->data, base->data, base->stride * base->height);
|
||||
g_clear_pointer(&ctx->restore_previous, fiv_io_image_unref);
|
||||
|
||||
// Apply that frame's disposal method.
|
||||
// XXX: We do not expect opaque pictures to receive holes this way.
|
||||
wuffs_base__rect_ie_u32 bounds =
|
||||
wuffs_base__frame_config__bounds(&ctx->last_fc);
|
||||
// TODO(p): This field needs to be colour-managed.
|
||||
wuffs_base__color_u32_argb_premul bg =
|
||||
wuffs_base__frame_config__background_color(&ctx->last_fc);
|
||||
|
||||
double a = (bg >> 24) / 255., r = 0, g = 0, b = 0;
|
||||
if (a) {
|
||||
r = (uint8_t) (bg >> 16) / 255. / a;
|
||||
g = (uint8_t) (bg >> 8) / 255. / a;
|
||||
b = (uint8_t) (bg) / 255. / a;
|
||||
}
|
||||
|
||||
cairo_surface_t *surface = fiv_io_image_to_surface_noref(canvas);
|
||||
cairo_t *cr = cairo_create(surface);
|
||||
cairo_surface_destroy(surface);
|
||||
if (wuffs_base__frame_config__disposal(&ctx->last_fc) ==
|
||||
WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_BACKGROUND) {
|
||||
cairo_rectangle(cr, bounds.min_incl_x, bounds.min_incl_y,
|
||||
bounds.max_excl_x - bounds.min_incl_x,
|
||||
bounds.max_excl_y - bounds.min_incl_y);
|
||||
cairo_set_source_rgba(cr, r, g, b, a);
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_fill(cr);
|
||||
}
|
||||
|
||||
if (wuffs_base__frame_config__disposal(fc) ==
|
||||
WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS) {
|
||||
ctx->restore_previous = fiv_io_image_new(
|
||||
canvas->format, canvas->width, canvas->height);
|
||||
if (!ctx->restore_previous) {
|
||||
cairo_destroy(cr);
|
||||
fiv_io_image_unref(canvas);
|
||||
set_error(error, "image allocation failure");
|
||||
return false;
|
||||
}
|
||||
memcpy(ctx->restore_previous->data, canvas->data,
|
||||
canvas->stride * canvas->height);
|
||||
}
|
||||
|
||||
// Paint the current frame over that, within its bounds.
|
||||
bounds = wuffs_base__frame_config__bounds(fc);
|
||||
cairo_rectangle(cr, bounds.min_incl_x, bounds.min_incl_y,
|
||||
bounds.max_excl_x - bounds.min_incl_x,
|
||||
bounds.max_excl_y - bounds.min_incl_y);
|
||||
cairo_clip(cr);
|
||||
|
||||
cairo_set_operator(cr,
|
||||
wuffs_base__frame_config__overwrite_instead_of_blend(fc)
|
||||
? CAIRO_OPERATOR_SOURCE
|
||||
: CAIRO_OPERATOR_OVER);
|
||||
|
||||
surface = fiv_io_image_to_surface_noref(*image);
|
||||
cairo_set_source_surface(cr, surface, 0, 0);
|
||||
cairo_surface_destroy(surface);
|
||||
cairo_paint(cr);
|
||||
cairo_destroy(cr);
|
||||
|
||||
fiv_io_image_unref(*image);
|
||||
*image = canvas;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
load_wuffs_frame(struct load_wuffs_frame_context *ctx, GError **error)
|
||||
{
|
||||
@@ -491,84 +572,9 @@ load_wuffs_frame(struct load_wuffs_frame_context *ctx, GError **error)
|
||||
}
|
||||
|
||||
// Single-frame images get a fast path, animations are are handled slowly:
|
||||
if (wuffs_base__frame_config__index(&fc) > 0) {
|
||||
// Copy the previous frame to a new image.
|
||||
FivIoImage *prev = ctx->result_tail, *canvas = fiv_io_image_new(
|
||||
prev->format, prev->width, prev->height);
|
||||
if (!canvas) {
|
||||
set_error(error, "image allocation failure");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
FivIoImage *base = ctx->restore_previous
|
||||
? ctx->restore_previous
|
||||
: prev;
|
||||
memcpy(canvas->data, base->data, base->stride * base->height);
|
||||
g_clear_pointer(&ctx->restore_previous, fiv_io_image_unref);
|
||||
|
||||
// Apply that frame's disposal method.
|
||||
// XXX: We do not expect opaque pictures to receive holes this way.
|
||||
wuffs_base__rect_ie_u32 bounds =
|
||||
wuffs_base__frame_config__bounds(&ctx->last_fc);
|
||||
// TODO(p): This field needs to be colour-managed.
|
||||
wuffs_base__color_u32_argb_premul bg =
|
||||
wuffs_base__frame_config__background_color(&ctx->last_fc);
|
||||
|
||||
double a = (bg >> 24) / 255., r = 0, g = 0, b = 0;
|
||||
if (a) {
|
||||
r = (uint8_t) (bg >> 16) / 255. / a;
|
||||
g = (uint8_t) (bg >> 8) / 255. / a;
|
||||
b = (uint8_t) (bg) / 255. / a;
|
||||
}
|
||||
|
||||
cairo_surface_t *surface = fiv_io_image_to_surface_noref(canvas);
|
||||
cairo_t *cr = cairo_create(surface);
|
||||
cairo_surface_destroy(surface);
|
||||
if (wuffs_base__frame_config__disposal(&ctx->last_fc) ==
|
||||
WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_BACKGROUND) {
|
||||
cairo_rectangle(cr, bounds.min_incl_x, bounds.min_incl_y,
|
||||
bounds.max_excl_x - bounds.min_incl_x,
|
||||
bounds.max_excl_y - bounds.min_incl_y);
|
||||
cairo_set_source_rgba(cr, r, g, b, a);
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_fill(cr);
|
||||
}
|
||||
|
||||
if (wuffs_base__frame_config__disposal(&fc) ==
|
||||
WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS) {
|
||||
ctx->restore_previous = fiv_io_image_new(
|
||||
canvas->format, canvas->width, canvas->height);
|
||||
if (!ctx->restore_previous) {
|
||||
cairo_destroy(cr);
|
||||
fiv_io_image_unref(canvas);
|
||||
set_error(error, "image allocation failure");
|
||||
goto fail;
|
||||
}
|
||||
memcpy(ctx->restore_previous->data, canvas->data,
|
||||
canvas->stride * canvas->height);
|
||||
}
|
||||
|
||||
// Paint the current frame over that, within its bounds.
|
||||
bounds = wuffs_base__frame_config__bounds(&fc);
|
||||
cairo_rectangle(cr, bounds.min_incl_x, bounds.min_incl_y,
|
||||
bounds.max_excl_x - bounds.min_incl_x,
|
||||
bounds.max_excl_y - bounds.min_incl_y);
|
||||
cairo_clip(cr);
|
||||
|
||||
cairo_set_operator(cr,
|
||||
wuffs_base__frame_config__overwrite_instead_of_blend(&fc)
|
||||
? CAIRO_OPERATOR_SOURCE
|
||||
: CAIRO_OPERATOR_OVER);
|
||||
|
||||
surface = fiv_io_image_to_surface_noref(image);
|
||||
cairo_set_source_surface(cr, surface, 0, 0);
|
||||
cairo_surface_destroy(surface);
|
||||
cairo_paint(cr);
|
||||
cairo_destroy(cr);
|
||||
|
||||
fiv_io_image_unref(image);
|
||||
image = canvas;
|
||||
}
|
||||
if (wuffs_base__frame_config__index(&fc) > 0 &&
|
||||
!load_wuffs_frame_compose(ctx, &image, &fc, error))
|
||||
goto fail;
|
||||
|
||||
if (ctx->meta_exif)
|
||||
image->exif = g_bytes_ref(ctx->meta_exif);
|
||||
|
||||
Reference in New Issue
Block a user