Avoid double CM in saved WebPs
This commit is contained in:
parent
e37acf365a
commit
e5b1a1861c
|
@ -5,8 +5,8 @@ fastiv
|
||||||
raw photos, HEIC, AVIF, WebP, SVG, X11 cursors and TIFF, or whatever gdk-pixbuf
|
raw photos, HEIC, AVIF, WebP, SVG, X11 cursors and TIFF, or whatever gdk-pixbuf
|
||||||
loads.
|
loads.
|
||||||
|
|
||||||
Its development status can be summarized as '`beta`'. E.g., colour management
|
Its development status can be summarized as '`beta`'.
|
||||||
is a bit incomplete, and certain GIFs animate wrong.
|
E.g., certain GIFs animate wrong.
|
||||||
|
|
||||||
Non-goals
|
Non-goals
|
||||||
---------
|
---------
|
||||||
|
|
42
fiv-io.c
42
fiv-io.c
|
@ -206,6 +206,24 @@ fiv_io_profile_new_from_bytes(GBytes *bytes)
|
||||||
return fiv_io_profile_new(p, len);
|
return fiv_io_profile_new(p, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GBytes *
|
||||||
|
fiv_io_profile_to_bytes(FivIoProfile profile)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LCMS2
|
||||||
|
cmsUInt32Number len = 0;
|
||||||
|
(void) cmsSaveProfileToMem(profile, NULL, &len);
|
||||||
|
gchar *data = g_malloc0(len);
|
||||||
|
if (!cmsSaveProfileToMem(profile, data, &len)) {
|
||||||
|
g_free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return g_bytes_new_take(data, len);
|
||||||
|
#else
|
||||||
|
(void) profile;
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fiv_io_profile_free(FivIoProfile self)
|
fiv_io_profile_free(FivIoProfile self)
|
||||||
{
|
{
|
||||||
|
@ -2490,10 +2508,8 @@ encode_webp_animation(WebPMux *mux, cairo_surface_t *page)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
transfer_metadata(WebPMux *mux, const char *fourcc, cairo_surface_t *page,
|
set_metadata(WebPMux *mux, const char *fourcc, GBytes *data)
|
||||||
const cairo_user_data_key_t *kind)
|
|
||||||
{
|
{
|
||||||
GBytes *data = cairo_surface_get_user_data(page, kind);
|
|
||||||
if (!data)
|
if (!data)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -2504,8 +2520,8 @@ transfer_metadata(WebPMux *mux, const char *fourcc, cairo_surface_t *page,
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
fiv_io_save(cairo_surface_t *page, cairo_surface_t *frame, const gchar *path,
|
fiv_io_save(cairo_surface_t *page, cairo_surface_t *frame, FivIoProfile target,
|
||||||
GError **error)
|
const gchar *path, GError **error)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail(page != NULL, FALSE);
|
g_return_val_if_fail(page != NULL, FALSE);
|
||||||
g_return_val_if_fail(path != NULL, FALSE);
|
g_return_val_if_fail(path != NULL, FALSE);
|
||||||
|
@ -2519,9 +2535,16 @@ fiv_io_save(cairo_surface_t *page, cairo_surface_t *frame, const gchar *path,
|
||||||
else
|
else
|
||||||
ok = encode_webp_animation(mux, page);
|
ok = encode_webp_animation(mux, page);
|
||||||
|
|
||||||
ok = ok && transfer_metadata(mux, "EXIF", page, &fiv_io_key_exif);
|
ok = ok && set_metadata(mux, "EXIF",
|
||||||
ok = ok && transfer_metadata(mux, "ICCP", page, &fiv_io_key_icc);
|
cairo_surface_get_user_data(page, &fiv_io_key_exif));
|
||||||
ok = ok && transfer_metadata(mux, "XMP ", page, &fiv_io_key_xmp);
|
ok = ok && set_metadata(mux, "ICCP",
|
||||||
|
cairo_surface_get_user_data(page, &fiv_io_key_icc));
|
||||||
|
ok = ok && set_metadata(mux, "XMP ",
|
||||||
|
cairo_surface_get_user_data(page, &fiv_io_key_xmp));
|
||||||
|
|
||||||
|
GBytes *iccp = NULL;
|
||||||
|
if (ok && target && (iccp = fiv_io_profile_to_bytes(target)))
|
||||||
|
ok = set_metadata(mux, "ICCP", iccp);
|
||||||
|
|
||||||
WebPData assembled = {};
|
WebPData assembled = {};
|
||||||
WebPDataInit(&assembled);
|
WebPDataInit(&assembled);
|
||||||
|
@ -2531,6 +2554,9 @@ fiv_io_save(cairo_surface_t *page, cairo_surface_t *frame, const gchar *path,
|
||||||
ok = g_file_set_contents(
|
ok = g_file_set_contents(
|
||||||
path, (const gchar *) assembled.bytes, assembled.size, error);
|
path, (const gchar *) assembled.bytes, assembled.size, error);
|
||||||
|
|
||||||
|
if (iccp)
|
||||||
|
g_bytes_unref(iccp);
|
||||||
|
|
||||||
WebPMuxDelete(mux);
|
WebPMuxDelete(mux);
|
||||||
WebPDataClear(&assembled);
|
WebPDataClear(&assembled);
|
||||||
return ok;
|
return ok;
|
||||||
|
|
2
fiv-io.h
2
fiv-io.h
|
@ -79,7 +79,7 @@ int fiv_io_filecmp(GFile *f1, GFile *f2);
|
||||||
/// Requires libwebp.
|
/// Requires libwebp.
|
||||||
/// If no exact frame is specified, this potentially creates an animation.
|
/// If no exact frame is specified, this potentially creates an animation.
|
||||||
gboolean fiv_io_save(cairo_surface_t *page, cairo_surface_t *frame,
|
gboolean fiv_io_save(cairo_surface_t *page, cairo_surface_t *frame,
|
||||||
const gchar *path, GError **error);
|
FivIoProfile target, const gchar *path, GError **error);
|
||||||
|
|
||||||
// --- Metadata ----------------------------------------------------------------
|
// --- Metadata ----------------------------------------------------------------
|
||||||
|
|
||||||
|
|
17
fiv-view.c
17
fiv-view.c
|
@ -779,9 +779,18 @@ print(FivView *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
save_as(FivView *self, gboolean frame)
|
save_as(FivView *self, cairo_surface_t *frame)
|
||||||
{
|
{
|
||||||
GtkWindow *window = get_toplevel(GTK_WIDGET(self));
|
GtkWindow *window = get_toplevel(GTK_WIDGET(self));
|
||||||
|
FivIoProfile target = NULL;
|
||||||
|
if (self->enable_cms && (target = self->screen_cms_profile)) {
|
||||||
|
GtkWidget *dialog = gtk_message_dialog_new(window, GTK_DIALOG_MODAL,
|
||||||
|
GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, "%s",
|
||||||
|
"Color management overrides attached color profiles.");
|
||||||
|
gtk_dialog_run(GTK_DIALOG(dialog));
|
||||||
|
gtk_widget_destroy(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
GtkWidget *dialog = gtk_file_chooser_dialog_new(
|
GtkWidget *dialog = gtk_file_chooser_dialog_new(
|
||||||
frame ? "Save frame as" : "Save page as",
|
frame ? "Save frame as" : "Save page as",
|
||||||
window, GTK_FILE_CHOOSER_ACTION_SAVE,
|
window, GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||||
|
@ -834,7 +843,7 @@ save_as(FivView *self, gboolean frame)
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
#ifdef HAVE_LIBWEBP
|
#ifdef HAVE_LIBWEBP
|
||||||
if (gtk_file_chooser_get_filter(chooser) == webp_filter)
|
if (gtk_file_chooser_get_filter(chooser) == webp_filter)
|
||||||
fiv_io_save(self->page, frame ? self->frame : NULL, path, &error);
|
fiv_io_save(self->page, frame, target, path, &error);
|
||||||
else
|
else
|
||||||
#endif // HAVE_LIBWEBP
|
#endif // HAVE_LIBWEBP
|
||||||
fiv_io_save_metadata(self->page, path, &error);
|
fiv_io_save_metadata(self->page, path, &error);
|
||||||
|
@ -1027,7 +1036,7 @@ fiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event)
|
||||||
case GDK_KEY_s:
|
case GDK_KEY_s:
|
||||||
return command(self, FIV_VIEW_COMMAND_SAVE_PAGE);
|
return command(self, FIV_VIEW_COMMAND_SAVE_PAGE);
|
||||||
case GDK_KEY_S:
|
case GDK_KEY_S:
|
||||||
return save_as(self, TRUE);
|
return save_as(self, self->frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state == GDK_MOD1_MASK) {
|
if (state == GDK_MOD1_MASK) {
|
||||||
|
@ -1320,7 +1329,7 @@ fiv_view_command(FivView *self, FivViewCommand command)
|
||||||
break; case FIV_VIEW_COMMAND_PRINT:
|
break; case FIV_VIEW_COMMAND_PRINT:
|
||||||
print(self);
|
print(self);
|
||||||
break; case FIV_VIEW_COMMAND_SAVE_PAGE:
|
break; case FIV_VIEW_COMMAND_SAVE_PAGE:
|
||||||
save_as(self, FALSE);
|
save_as(self, NULL);
|
||||||
break; case FIV_VIEW_COMMAND_INFO:
|
break; case FIV_VIEW_COMMAND_INFO:
|
||||||
info(self);
|
info(self);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue