mirror of
https://gitlab.gnome.org/GNOME/gimp.git
synced 2025-07-04 09:53:25 +00:00
Bug 769651 - Add webp file format support to gimp master
Patch to add webp file format support. Includes supports for loading/saving, icc profiles, exif, and xmp data. Co-authored with Nathan Osman.
This commit is contained in:
parent
98e43b9452
commit
c1021a3e3a
13 changed files with 1707 additions and 0 deletions
37
configure.ac
37
configure.ac
|
@ -75,6 +75,9 @@ m4_define([openexr_required_version], [1.6.1])
|
||||||
m4_define([gtk_mac_integration_required_version], [2.0.0])
|
m4_define([gtk_mac_integration_required_version], [2.0.0])
|
||||||
m4_define([intltool_required_version], [0.40.1])
|
m4_define([intltool_required_version], [0.40.1])
|
||||||
m4_define([python2_required_version], [2.5.0])
|
m4_define([python2_required_version], [2.5.0])
|
||||||
|
m4_define([webp_required_version], [0.5.1])
|
||||||
|
m4_define([webpmux_required_version], [0.5.1])
|
||||||
|
m4_define([webpdemux_required_version], [0.5.1])
|
||||||
|
|
||||||
# Current test considers only 2 version numbers. If we update the recommended
|
# Current test considers only 2 version numbers. If we update the recommended
|
||||||
# version of gettext with more version numbers, please update the tests.
|
# version of gettext with more version numbers, please update the tests.
|
||||||
|
@ -158,6 +161,9 @@ POPPLER_DATA_REQUIRED_VERSION=poppler_data_required_version
|
||||||
OPENEXR_REQUIRED_VERSION=openexr_required_version
|
OPENEXR_REQUIRED_VERSION=openexr_required_version
|
||||||
INTLTOOL_REQUIRED_VERSION=intltool_required_version
|
INTLTOOL_REQUIRED_VERSION=intltool_required_version
|
||||||
PYTHON2_REQUIRED_VERSION=python2_required_version
|
PYTHON2_REQUIRED_VERSION=python2_required_version
|
||||||
|
WEBP_REQUIRED_VERSION=webp_required_version
|
||||||
|
WEBPMUX_REQUIRED_VERSION=webpmux_required_version
|
||||||
|
WEBPDEMUX_REQUIRED_VERSION=webpdemux_required_version
|
||||||
XGETTEXT_RECOMMENDED_VERSION=xgettext_recommended_version
|
XGETTEXT_RECOMMENDED_VERSION=xgettext_recommended_version
|
||||||
AC_SUBST(GLIB_REQUIRED_VERSION)
|
AC_SUBST(GLIB_REQUIRED_VERSION)
|
||||||
AC_SUBST(GDK_PIXBUF_REQUIRED_VERSION)
|
AC_SUBST(GDK_PIXBUF_REQUIRED_VERSION)
|
||||||
|
@ -185,6 +191,9 @@ AC_SUBST(POPPLER_DATA_REQUIRED_VERSION)
|
||||||
AC_SUBST(OPENEXR_REQUIRED_VERSION)
|
AC_SUBST(OPENEXR_REQUIRED_VERSION)
|
||||||
AC_SUBST(INTLTOOL_REQUIRED_VERSION)
|
AC_SUBST(INTLTOOL_REQUIRED_VERSION)
|
||||||
AC_SUBST(PYTHON2_REQUIRED_VERSION)
|
AC_SUBST(PYTHON2_REQUIRED_VERSION)
|
||||||
|
AC_SUBST(WEBP_REQUIRED_VERSION)
|
||||||
|
AC_SUBST(WEBPMUX_REQUIRED_VERSION)
|
||||||
|
AC_SUBST(WEBPDEMUX_REQUIRED_VERSION)
|
||||||
AC_SUBST(XGETTEXT_RECOMMENDED_VERSION)
|
AC_SUBST(XGETTEXT_RECOMMENDED_VERSION)
|
||||||
|
|
||||||
# The symbol GIMP_UNSTABLE is defined above for substitution in
|
# The symbol GIMP_UNSTABLE is defined above for substitution in
|
||||||
|
@ -1548,6 +1557,32 @@ AC_SUBST(FILE_EXR)
|
||||||
AM_CONDITIONAL(HAVE_OPENEXR, test "x$have_openexr" = xyes)
|
AM_CONDITIONAL(HAVE_OPENEXR, test "x$have_openexr" = xyes)
|
||||||
|
|
||||||
|
|
||||||
|
################
|
||||||
|
# Check for WebP
|
||||||
|
################
|
||||||
|
|
||||||
|
AC_ARG_WITH(webp, [ --without-webp build without WebP support])
|
||||||
|
|
||||||
|
have_webp=no
|
||||||
|
if test "x$with_webp" != xno; then
|
||||||
|
have_webp=yes
|
||||||
|
PKG_CHECK_MODULES(WEBP, libwebp >= webp_required_version,,
|
||||||
|
[have_webp="no (WebP not found)"])
|
||||||
|
|
||||||
|
PKG_CHECK_MODULES(WEBPMUX, libwebpmux >= webpmux_required_version,,
|
||||||
|
[have_webp="no (WebP not found)"])
|
||||||
|
|
||||||
|
PKG_CHECK_MODULES(WEBPDEMUX, libwebpdemux >= webpdemux_required_version,,
|
||||||
|
[have_webp="no (WebP not found)"])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x$have_webp" = xyes; then
|
||||||
|
MIME_TYPES="$MIME_TYPES;image/x-webp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AM_CONDITIONAL(HAVE_WEBP, test "x$have_webp" = xyes)
|
||||||
|
|
||||||
|
|
||||||
######################
|
######################
|
||||||
# Check for libmypaint
|
# Check for libmypaint
|
||||||
######################
|
######################
|
||||||
|
@ -2400,6 +2435,7 @@ plug-ins/file-jpeg/Makefile
|
||||||
plug-ins/file-psd/Makefile
|
plug-ins/file-psd/Makefile
|
||||||
plug-ins/file-sgi/Makefile
|
plug-ins/file-sgi/Makefile
|
||||||
plug-ins/file-tiff/Makefile
|
plug-ins/file-tiff/Makefile
|
||||||
|
plug-ins/file-webp/Makefile
|
||||||
plug-ins/flame/Makefile
|
plug-ins/flame/Makefile
|
||||||
plug-ins/fractal-explorer/Makefile
|
plug-ins/fractal-explorer/Makefile
|
||||||
plug-ins/fractal-explorer/examples/Makefile
|
plug-ins/fractal-explorer/examples/Makefile
|
||||||
|
@ -2554,6 +2590,7 @@ Optional Plug-Ins:
|
||||||
JPEG 2000: $have_jp2
|
JPEG 2000: $have_jp2
|
||||||
MNG: $have_libmng
|
MNG: $have_libmng
|
||||||
OpenEXR: $have_openexr
|
OpenEXR: $have_openexr
|
||||||
|
WebP: $have_webp
|
||||||
PDF (import): $have_poppler
|
PDF (import): $have_poppler
|
||||||
PDF (export): $have_cairo_pdf
|
PDF (export): $have_cairo_pdf
|
||||||
Print: $enable_print
|
Print: $enable_print
|
||||||
|
|
|
@ -25,6 +25,10 @@ if OS_WIN32
|
||||||
twain = twain
|
twain = twain
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if HAVE_WEBP
|
||||||
|
file_webp = file-webp
|
||||||
|
endif
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
$(script_fu) \
|
$(script_fu) \
|
||||||
$(pygimp) \
|
$(pygimp) \
|
||||||
|
@ -39,6 +43,7 @@ SUBDIRS = \
|
||||||
file-psd \
|
file-psd \
|
||||||
file-sgi \
|
file-sgi \
|
||||||
file-tiff \
|
file-tiff \
|
||||||
|
$(file_webp) \
|
||||||
flame \
|
flame \
|
||||||
fractal-explorer \
|
fractal-explorer \
|
||||||
gfig \
|
gfig \
|
||||||
|
|
7
plug-ins/file-webp/.gitignore
vendored
Normal file
7
plug-ins/file-webp/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
/Makefile.in
|
||||||
|
/Makefile
|
||||||
|
/.deps
|
||||||
|
/_libs
|
||||||
|
/.libs
|
||||||
|
/file-webp
|
||||||
|
/file-webp.exe
|
64
plug-ins/file-webp/Makefile.am
Normal file
64
plug-ins/file-webp/Makefile.am
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
## Process this file with automake to produce Makefile.in
|
||||||
|
|
||||||
|
libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
|
||||||
|
libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la
|
||||||
|
libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
|
||||||
|
libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
|
||||||
|
libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
|
||||||
|
libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
|
||||||
|
libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la
|
||||||
|
|
||||||
|
if OS_WIN32
|
||||||
|
mwindows = -mwindows
|
||||||
|
endif
|
||||||
|
|
||||||
|
if HAVE_WINDRES
|
||||||
|
include $(top_srcdir)/build/windows/gimprc-plug-ins.rule
|
||||||
|
file_webp_RC = file-webp.rc.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
AM_LDFLAGS = $(mwindows)
|
||||||
|
|
||||||
|
libexecdir = $(gimpplugindir)/plug-ins
|
||||||
|
|
||||||
|
AM_CPPFLAGS = \
|
||||||
|
-I$(top_srcdir) \
|
||||||
|
$(GTK_CFLAGS) \
|
||||||
|
$(EXIF_CFLAGS) \
|
||||||
|
$(GEGL_CFLAGS) \
|
||||||
|
$(GEXIV2_CFLAGS) \
|
||||||
|
$(WEBP_CFLAGS) \
|
||||||
|
$(WEBPMUX_CFLAGS) \
|
||||||
|
$(WEBPDEMUX_CFLAGS) \
|
||||||
|
-I$(includedir)
|
||||||
|
|
||||||
|
libexec_PROGRAMS = file-webp
|
||||||
|
|
||||||
|
file_webp_SOURCES = \
|
||||||
|
file-webp.c \
|
||||||
|
file-webp.h \
|
||||||
|
file-webp-dialog.c \
|
||||||
|
file-webp-dialog.h \
|
||||||
|
file-webp-load.c \
|
||||||
|
file-webp-load.h \
|
||||||
|
file-webp-save.c \
|
||||||
|
file-webp-save.h
|
||||||
|
|
||||||
|
file_webp_LDADD = \
|
||||||
|
$(libgimpui) \
|
||||||
|
$(libgimpwidgets) \
|
||||||
|
$(libgimpconfig) \
|
||||||
|
$(libgimp) \
|
||||||
|
$(libgimpcolor) \
|
||||||
|
$(libgimpmath) \
|
||||||
|
$(libgimpbase) \
|
||||||
|
$(webp_LIBS) \
|
||||||
|
$(GTK_LIBS) \
|
||||||
|
$(GEGL_LIBS) \
|
||||||
|
$(GEXIV2_LIBS) \
|
||||||
|
$(WEBP_LIBS) \
|
||||||
|
$(WEBPMUX_LIBS) \
|
||||||
|
$(WEBPDEMUX_LIBS) \
|
||||||
|
$(RT_LIBS) \
|
||||||
|
$(INTLLIBS) \
|
||||||
|
$(file_webp_RC)
|
287
plug-ins/file-webp/file-webp-dialog.c
Normal file
287
plug-ins/file-webp/file-webp-dialog.c
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
/* GIMP - The GNU Image Manipulation Program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* file-webp - WebP file format plug-in for the GIMP
|
||||||
|
* Copyright (C) 2015 Nathan Osman
|
||||||
|
* Copyright (C) 2016 Ben Touchette
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <libgimp/gimp.h>
|
||||||
|
#include <libgimp/gimpui.h>
|
||||||
|
|
||||||
|
#include "file-webp.h"
|
||||||
|
#include "file-webp-dialog.h"
|
||||||
|
|
||||||
|
#include "libgimp/stdplugins-intl.h"
|
||||||
|
|
||||||
|
|
||||||
|
void save_dialog_response (GtkWidget *widget,
|
||||||
|
gint response_id,
|
||||||
|
gpointer data);
|
||||||
|
GtkListStore * save_dialog_presets (void);
|
||||||
|
void save_dialog_set_preset (GtkWidget *widget,
|
||||||
|
gpointer data);
|
||||||
|
void save_dialog_toggle_scale (GtkWidget *widget,
|
||||||
|
gpointer data);
|
||||||
|
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
const gchar *id;
|
||||||
|
const gchar *label;
|
||||||
|
} presets[] =
|
||||||
|
{
|
||||||
|
{ "default", "Default" },
|
||||||
|
{ "picture", "Picture" },
|
||||||
|
{ "photo", "Photo" },
|
||||||
|
{ "drawing", "Drawing" },
|
||||||
|
{ "icon", "Icon" },
|
||||||
|
{ "text", "Text" },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
save_dialog_response (GtkWidget *widget,
|
||||||
|
gint response_id,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
/* Store the response */
|
||||||
|
*(GtkResponseType *)data = response_id;
|
||||||
|
|
||||||
|
/* Close the dialog */
|
||||||
|
gtk_widget_destroy (widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkListStore *
|
||||||
|
save_dialog_presets (void)
|
||||||
|
{
|
||||||
|
GtkListStore *list_store;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Create the model */
|
||||||
|
list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
|
||||||
|
|
||||||
|
/* Insert the entries */
|
||||||
|
for (i = 0; presets[i].id; ++i)
|
||||||
|
{
|
||||||
|
gtk_list_store_insert_with_values (list_store,
|
||||||
|
NULL,
|
||||||
|
-1,
|
||||||
|
0, presets[i].id,
|
||||||
|
1, presets[i].label,
|
||||||
|
-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list_store;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
save_dialog_set_preset (GtkWidget *widget,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
*(gchar **) data =
|
||||||
|
gimp_string_combo_box_get_active (GIMP_STRING_COMBO_BOX (widget));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
save_dialog_toggle_scale (GtkWidget *widget,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
gimp_scale_entry_set_sensitive (GTK_OBJECT (data),
|
||||||
|
! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkResponseType
|
||||||
|
save_dialog (WebPSaveParams *params,
|
||||||
|
gint32 image_ID,
|
||||||
|
gint32 nLayers)
|
||||||
|
{
|
||||||
|
GtkWidget *dialog;
|
||||||
|
GtkWidget *vbox;
|
||||||
|
GtkWidget *label;
|
||||||
|
GtkWidget *table;
|
||||||
|
GtkWidget *preset_label;
|
||||||
|
GtkListStore *preset_list;
|
||||||
|
GtkWidget *preset_combo;
|
||||||
|
GtkWidget *lossless_checkbox;
|
||||||
|
GtkWidget *animation_checkbox;
|
||||||
|
GtkWidget *loop_anim_checkbox;
|
||||||
|
GtkObject *quality_scale;
|
||||||
|
GtkObject *alpha_quality_scale;
|
||||||
|
GtkResponseType response;
|
||||||
|
gboolean animation_supported = FALSE;
|
||||||
|
int slider1 , slider2;
|
||||||
|
|
||||||
|
animation_supported = nLayers > 1;
|
||||||
|
|
||||||
|
/* Create the dialog */
|
||||||
|
dialog = gimp_export_dialog_new (_("WebP"),BINARY_NAME,
|
||||||
|
SAVE_PROCEDURE);
|
||||||
|
|
||||||
|
/* Store the response when the dialog is closed */
|
||||||
|
g_signal_connect (dialog, "response",
|
||||||
|
G_CALLBACK (save_dialog_response),
|
||||||
|
&response);
|
||||||
|
|
||||||
|
/* Quit the main loop when the dialog is closed */
|
||||||
|
g_signal_connect (dialog, "destroy",
|
||||||
|
G_CALLBACK (gtk_main_quit),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Create the vbox */
|
||||||
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
||||||
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
|
||||||
|
gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
|
||||||
|
vbox, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (vbox);
|
||||||
|
|
||||||
|
/* Create the descriptive label at the top */
|
||||||
|
label = gtk_label_new (_("Use the options below to customize the image."));
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (label);
|
||||||
|
|
||||||
|
/* Create the table */
|
||||||
|
table = gtk_table_new (4, 5, FALSE);
|
||||||
|
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
|
||||||
|
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (table);
|
||||||
|
|
||||||
|
/* Create the label for the selecting a preset */
|
||||||
|
preset_label = gtk_label_new (_("Preset:"));
|
||||||
|
gtk_table_attach (GTK_TABLE (table), preset_label,
|
||||||
|
0, 1, 0, 1,
|
||||||
|
0, 0, 0, 0);
|
||||||
|
gtk_widget_show (preset_label);
|
||||||
|
|
||||||
|
/* Create the combobox containing the presets */
|
||||||
|
preset_list = save_dialog_presets ();
|
||||||
|
preset_combo = gimp_string_combo_box_new (GTK_TREE_MODEL (preset_list), 0, 1);
|
||||||
|
g_object_unref (preset_list);
|
||||||
|
|
||||||
|
gimp_string_combo_box_set_active (GIMP_STRING_COMBO_BOX (preset_combo),
|
||||||
|
params->preset);
|
||||||
|
gtk_table_attach (GTK_TABLE (table), preset_combo,
|
||||||
|
1, 3, 0, 1,
|
||||||
|
GTK_FILL, GTK_FILL, 0, 0);
|
||||||
|
gtk_widget_show (preset_combo);
|
||||||
|
|
||||||
|
g_signal_connect (preset_combo, "changed",
|
||||||
|
G_CALLBACK (save_dialog_set_preset),
|
||||||
|
¶ms->preset);
|
||||||
|
|
||||||
|
/* Create the lossless checkbox */
|
||||||
|
lossless_checkbox = gtk_check_button_new_with_label (_("Lossless"));
|
||||||
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lossless_checkbox),
|
||||||
|
params->lossless);
|
||||||
|
gtk_table_attach (GTK_TABLE (table), lossless_checkbox,
|
||||||
|
1, 3, 1, 2,
|
||||||
|
GTK_FILL, GTK_FILL, 0, 0);
|
||||||
|
gtk_widget_show (lossless_checkbox);
|
||||||
|
|
||||||
|
g_signal_connect (lossless_checkbox, "toggled",
|
||||||
|
G_CALLBACK (gimp_toggle_button_update),
|
||||||
|
¶ms->lossless);
|
||||||
|
|
||||||
|
slider1 = 2;
|
||||||
|
slider2 = 3;
|
||||||
|
if (animation_supported)
|
||||||
|
{
|
||||||
|
slider1 = 4;
|
||||||
|
slider2 = 5;
|
||||||
|
|
||||||
|
/* Create the animation checkbox */
|
||||||
|
animation_checkbox = gtk_check_button_new_with_label (_("Use animation"));
|
||||||
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (animation_checkbox),
|
||||||
|
params->animation);
|
||||||
|
gtk_table_attach (GTK_TABLE (table), animation_checkbox,
|
||||||
|
1, 3, 2, 3,
|
||||||
|
GTK_FILL, GTK_FILL, 0, 0);
|
||||||
|
gtk_widget_show (animation_checkbox);
|
||||||
|
|
||||||
|
g_signal_connect (animation_checkbox, "toggled",
|
||||||
|
G_CALLBACK (gimp_toggle_button_update),
|
||||||
|
¶ms->animation);
|
||||||
|
|
||||||
|
/* Create the loop animation checkbox */
|
||||||
|
loop_anim_checkbox = gtk_check_button_new_with_label (_("Loop infinitely"));
|
||||||
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (loop_anim_checkbox),
|
||||||
|
params->loop);
|
||||||
|
gtk_table_attach (GTK_TABLE (table), loop_anim_checkbox,
|
||||||
|
1, 3, 3, 4,
|
||||||
|
GTK_FILL, GTK_FILL, 0, 0);
|
||||||
|
gtk_widget_show (loop_anim_checkbox);
|
||||||
|
|
||||||
|
g_signal_connect (loop_anim_checkbox, "toggled",
|
||||||
|
G_CALLBACK (gimp_toggle_button_update),
|
||||||
|
¶ms->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the slider for image quality */
|
||||||
|
quality_scale = gimp_scale_entry_new (GTK_TABLE (table),
|
||||||
|
0, slider1,
|
||||||
|
_("Image quality:"),
|
||||||
|
125,
|
||||||
|
0,
|
||||||
|
params->quality,
|
||||||
|
0.0, 100.0,
|
||||||
|
1.0, 10.0,
|
||||||
|
0, TRUE,
|
||||||
|
0.0, 0.0,
|
||||||
|
_("Image quality"),
|
||||||
|
NULL);
|
||||||
|
gimp_scale_entry_set_sensitive (quality_scale, ! params->lossless);
|
||||||
|
|
||||||
|
g_signal_connect (quality_scale, "value-changed",
|
||||||
|
G_CALLBACK (gimp_float_adjustment_update),
|
||||||
|
¶ms->quality);
|
||||||
|
|
||||||
|
/* Create the slider for alpha channel quality */
|
||||||
|
alpha_quality_scale = gimp_scale_entry_new (GTK_TABLE (table),
|
||||||
|
0, slider2,
|
||||||
|
_("Alpha quality:"),
|
||||||
|
125,
|
||||||
|
0,
|
||||||
|
params->alpha_quality,
|
||||||
|
0.0, 100.0,
|
||||||
|
1.0, 10.0,
|
||||||
|
0, TRUE,
|
||||||
|
0.0, 0.0,
|
||||||
|
_("Alpha channel quality"),
|
||||||
|
NULL);
|
||||||
|
gimp_scale_entry_set_sensitive (alpha_quality_scale, ! params->lossless);
|
||||||
|
|
||||||
|
g_signal_connect (alpha_quality_scale, "value-changed",
|
||||||
|
G_CALLBACK (gimp_float_adjustment_update),
|
||||||
|
¶ms->alpha_quality);
|
||||||
|
|
||||||
|
/* Enable and disable the sliders when the lossless option is selected */
|
||||||
|
g_signal_connect (lossless_checkbox, "toggled",
|
||||||
|
G_CALLBACK (save_dialog_toggle_scale),
|
||||||
|
quality_scale);
|
||||||
|
g_signal_connect (lossless_checkbox, "toggled",
|
||||||
|
G_CALLBACK (save_dialog_toggle_scale),
|
||||||
|
alpha_quality_scale);
|
||||||
|
|
||||||
|
/* Display the dialog and enter the main event loop */
|
||||||
|
gtk_widget_show (dialog);
|
||||||
|
gtk_main ();
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
34
plug-ins/file-webp/file-webp-dialog.h
Normal file
34
plug-ins/file-webp/file-webp-dialog.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/* GIMP - The GNU Image Manipulation Program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* file-webp - WebP file format plug-in for the GIMP
|
||||||
|
* Copyright (C) 2015 Nathan Osman
|
||||||
|
* Copyright (C) 2016 Ben Touchette
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WEBP_DIALOG_H__
|
||||||
|
#define __WEBP_DIALOG_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include "file-webp-save.h"
|
||||||
|
|
||||||
|
|
||||||
|
GtkResponseType save_dialog (WebPSaveParams *params,
|
||||||
|
gint32 image_ID,
|
||||||
|
gint32 nLayers);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __WEBP_DIALOG_H__ */
|
275
plug-ins/file-webp/file-webp-load.c
Normal file
275
plug-ins/file-webp/file-webp-load.c
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
/* GIMP - The GNU Image Manipulation Program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* file-webp - WebP file format plug-in for the GIMP
|
||||||
|
* Copyright (C) 2015 Nathan Osman
|
||||||
|
* Copyright (C) 2016 Ben Touchette
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <gegl.h>
|
||||||
|
|
||||||
|
#include <libgimp/gimp.h>
|
||||||
|
#include <libgimp/gimpui.h>
|
||||||
|
|
||||||
|
#include <webp/decode.h>
|
||||||
|
#include <webp/demux.h>
|
||||||
|
#include <webp/mux.h>
|
||||||
|
|
||||||
|
#include "file-webp-load.h"
|
||||||
|
|
||||||
|
#include "libgimp/stdplugins-intl.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
create_layer (gint32 image_ID,
|
||||||
|
uint8_t *layer_data,
|
||||||
|
gint32 position,
|
||||||
|
gchar *name,
|
||||||
|
gint width,
|
||||||
|
gint height,
|
||||||
|
gint32 offsetx,
|
||||||
|
gint32 offsety)
|
||||||
|
{
|
||||||
|
gint32 layer_ID;
|
||||||
|
GeglBuffer *geglbuffer;
|
||||||
|
GeglRectangle extent;
|
||||||
|
|
||||||
|
layer_ID = gimp_layer_new (image_ID, name,
|
||||||
|
width, height,
|
||||||
|
GIMP_RGBA_IMAGE,
|
||||||
|
100,
|
||||||
|
GIMP_NORMAL_MODE);
|
||||||
|
|
||||||
|
gimp_image_insert_layer (image_ID, layer_ID, -1, position);
|
||||||
|
|
||||||
|
if (offsetx > 0 || offsety > 0)
|
||||||
|
{
|
||||||
|
gimp_layer_set_offsets (layer_ID, offsetx, offsety);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retrieve the buffer for the layer */
|
||||||
|
geglbuffer = gimp_drawable_get_buffer (layer_ID);
|
||||||
|
|
||||||
|
/* Copy the image data to the region */
|
||||||
|
gegl_rectangle_set (&extent, 0, 0, width, height);
|
||||||
|
gegl_buffer_set (geglbuffer, &extent, 0, NULL, layer_data,
|
||||||
|
GEGL_AUTO_ROWSTRIDE);
|
||||||
|
|
||||||
|
/* Flush the drawable and detach */
|
||||||
|
gegl_buffer_flush (geglbuffer);
|
||||||
|
|
||||||
|
if (geglbuffer)
|
||||||
|
g_object_unref (geglbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
gint32
|
||||||
|
load_image (const gchar *filename,
|
||||||
|
gboolean interactive,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
uint8_t *indata = NULL;
|
||||||
|
uint8_t *outdata;
|
||||||
|
gsize indatalen;
|
||||||
|
gint width;
|
||||||
|
gint height;
|
||||||
|
gint32 image_ID;
|
||||||
|
GFile *file;
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
WebPMux *mux;
|
||||||
|
WebPBitstreamFeatures features;
|
||||||
|
WebPData wp_data;
|
||||||
|
uint32_t flag;
|
||||||
|
int animation = FALSE;
|
||||||
|
int icc = FALSE;
|
||||||
|
int exif = FALSE;
|
||||||
|
int xmp = FALSE;
|
||||||
|
int frames = 0;
|
||||||
|
gchar *name;
|
||||||
|
|
||||||
|
/* Attempt to read the file contents from disk */
|
||||||
|
if (! g_file_get_contents (filename,
|
||||||
|
(gchar **) &indata,
|
||||||
|
&indatalen,
|
||||||
|
error))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_printerr ("Loading WebP file %s\n", filename);
|
||||||
|
|
||||||
|
/* Validate WebP data */
|
||||||
|
if (! WebPGetInfo (indata, indatalen, &width, &height))
|
||||||
|
{
|
||||||
|
g_printerr ("Invalid WebP file\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gegl_init (NULL, NULL);
|
||||||
|
|
||||||
|
wp_data.bytes = indata;
|
||||||
|
wp_data.size = indatalen;
|
||||||
|
|
||||||
|
mux = WebPMuxCreate (&wp_data, 1);
|
||||||
|
if (! mux)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
WebPMuxGetFeatures (mux, &flag);
|
||||||
|
if (flag == 0)
|
||||||
|
{
|
||||||
|
animation = FALSE;
|
||||||
|
icc = FALSE;
|
||||||
|
exif = FALSE;
|
||||||
|
xmp = FALSE;
|
||||||
|
frames = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (flag & ANIMATION_FLAG)
|
||||||
|
animation = TRUE;
|
||||||
|
|
||||||
|
if (flag & ICCP_FLAG)
|
||||||
|
icc = TRUE;
|
||||||
|
|
||||||
|
if (flag & EXIF_FLAG)
|
||||||
|
exif = TRUE;
|
||||||
|
|
||||||
|
if (flag & XMP_FLAG)
|
||||||
|
xmp = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: decode the image in "chunks" or "tiles" */
|
||||||
|
/* TODO: check if an alpha channel is present */
|
||||||
|
|
||||||
|
/* Create the new image and associated layer */
|
||||||
|
image_ID = gimp_image_new (width, height, GIMP_RGB);
|
||||||
|
|
||||||
|
if (! animation)
|
||||||
|
{
|
||||||
|
/* Attempt to decode the data as a WebP image */
|
||||||
|
outdata = WebPDecodeRGBA (indata, indatalen, &width, &height);
|
||||||
|
|
||||||
|
/* Free the original compressed data */
|
||||||
|
g_free (indata);
|
||||||
|
|
||||||
|
/* Check to ensure the image data was loaded correctly */
|
||||||
|
if (! outdata)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
create_layer (image_ID, outdata, 0, _("Background"),
|
||||||
|
width, height, 0, 0);
|
||||||
|
|
||||||
|
/* Free the image data */
|
||||||
|
free (outdata);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const WebPChunkId id = WEBP_CHUNK_ANMF;
|
||||||
|
WebPMuxAnimParams params;
|
||||||
|
gint loop;
|
||||||
|
|
||||||
|
WebPMuxGetAnimationParams (mux, ¶ms);
|
||||||
|
WebPMuxNumChunks (mux, id, &frames);
|
||||||
|
|
||||||
|
/* Attempt to decode the data as a WebP animation image */
|
||||||
|
for (loop = 0; loop < frames; loop++)
|
||||||
|
{
|
||||||
|
WebPMuxFrameInfo thisframe;
|
||||||
|
gint i = loop;
|
||||||
|
|
||||||
|
if (WebPMuxGetFrame (mux, i, &thisframe) == WEBP_MUX_OK)
|
||||||
|
{
|
||||||
|
WebPGetFeatures (thisframe.bitstream.bytes,
|
||||||
|
thisframe.bitstream.size, &features);
|
||||||
|
|
||||||
|
outdata = WebPDecodeRGBA (thisframe.bitstream.bytes,
|
||||||
|
thisframe.bitstream.size,
|
||||||
|
&width, &height);
|
||||||
|
|
||||||
|
if (! outdata)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
name = g_strdup_printf (_("Frame %d"), loop + 1);
|
||||||
|
create_layer (image_ID, outdata, 0,
|
||||||
|
name, width, height,
|
||||||
|
thisframe.x_offset,
|
||||||
|
thisframe.y_offset);
|
||||||
|
g_free (name);
|
||||||
|
|
||||||
|
/* Free the image data */
|
||||||
|
free (outdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
WebPDataClear (&thisframe.bitstream);
|
||||||
|
}
|
||||||
|
|
||||||
|
WebPDataClear (&wp_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icc)
|
||||||
|
{
|
||||||
|
WebPData icc_profile;
|
||||||
|
GimpColorProfile *profile;
|
||||||
|
|
||||||
|
WebPMuxGetChunk (mux, "ICCP", &icc_profile);
|
||||||
|
profile = gimp_color_profile_new_from_icc_profile (icc_profile.bytes,
|
||||||
|
icc_profile.size, NULL);
|
||||||
|
if (profile)
|
||||||
|
{
|
||||||
|
gimp_image_set_color_profile (image_ID, profile);
|
||||||
|
g_object_unref (profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exif || xmp)
|
||||||
|
{
|
||||||
|
if (exif)
|
||||||
|
{
|
||||||
|
WebPData exif;
|
||||||
|
|
||||||
|
WebPMuxGetChunk (mux, "EXIF", &exif);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmp)
|
||||||
|
{
|
||||||
|
WebPData xmp;
|
||||||
|
|
||||||
|
WebPMuxGetChunk (mux, "XMP ", &xmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
file = g_file_new_for_path (filename);
|
||||||
|
metadata = gimp_image_metadata_load_prepare (image_ID, "image/webp",
|
||||||
|
file, NULL);
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
gimp_image_metadata_load_finish (image_ID, "image/webp",
|
||||||
|
metadata, GIMP_METADATA_LOAD_ALL,
|
||||||
|
interactive);
|
||||||
|
g_object_unref (metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (file);
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_image_set_filename (image_ID, filename);
|
||||||
|
|
||||||
|
return image_ID;
|
||||||
|
}
|
31
plug-ins/file-webp/file-webp-load.h
Normal file
31
plug-ins/file-webp/file-webp-load.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/* GIMP - The GNU Image Manipulation Program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* file-webp - WebP file format plug-in for the GIMP
|
||||||
|
* Copyright (C) 2015 Nathan Osman
|
||||||
|
* Copyright (C) 2016 Ben Touchette
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WEBP_LOAD_H__
|
||||||
|
#define __WEBP_LOAD_H__
|
||||||
|
|
||||||
|
|
||||||
|
gint32 load_image (const gchar *filename,
|
||||||
|
gboolean interactive,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __WEBP_LOAD_H__ */
|
619
plug-ins/file-webp/file-webp-save.c
Normal file
619
plug-ins/file-webp/file-webp-save.c
Normal file
|
@ -0,0 +1,619 @@
|
||||||
|
/* GIMP - The GNU Image Manipulation Program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* file-webp - WebP file format plug-in for the GIMP
|
||||||
|
* Copyright (C) 2015 Nathan Osman
|
||||||
|
* Copyright (C) 2016 Ben Touchette
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <gegl.h>
|
||||||
|
|
||||||
|
#include <libgimp/gimp.h>
|
||||||
|
#include <libgimp/gimpui.h>
|
||||||
|
|
||||||
|
#include <webp/encode.h>
|
||||||
|
#include <webp/mux.h>
|
||||||
|
|
||||||
|
#include "file-webp-save.h"
|
||||||
|
|
||||||
|
#include "libgimp/stdplugins-intl.h"
|
||||||
|
|
||||||
|
|
||||||
|
WebPPreset webp_preset_by_name (gchar *name);
|
||||||
|
int webp_anim_file_writer (FILE *outfile,
|
||||||
|
const uint8_t *data,
|
||||||
|
size_t data_size);
|
||||||
|
int webp_file_writer (const uint8_t *data,
|
||||||
|
size_t data_size,
|
||||||
|
const WebPPicture *picture);
|
||||||
|
int webp_file_progress (int percent,
|
||||||
|
const WebPPicture *picture);
|
||||||
|
const gchar * webp_error_string (WebPEncodingError error_code);
|
||||||
|
|
||||||
|
gboolean save_layer (const gchar *filename,
|
||||||
|
gint32 nLayers,
|
||||||
|
gint32 image_ID,
|
||||||
|
gint32 drawable_ID,
|
||||||
|
WebPSaveParams *params,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
gboolean save_animation (const gchar *filename,
|
||||||
|
gint32 nLayers,
|
||||||
|
gint32 *allLayers,
|
||||||
|
gint32 image_ID,
|
||||||
|
gint32 drawable_ID,
|
||||||
|
WebPSaveParams *params,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
|
||||||
|
WebPPreset
|
||||||
|
webp_preset_by_name (gchar *name)
|
||||||
|
{
|
||||||
|
if( ! strcmp (name, "picture"))
|
||||||
|
{
|
||||||
|
return WEBP_PRESET_PICTURE;
|
||||||
|
}
|
||||||
|
else if (! strcmp (name, "photo"))
|
||||||
|
{
|
||||||
|
return WEBP_PRESET_PHOTO;
|
||||||
|
}
|
||||||
|
else if (! strcmp (name, "drawing"))
|
||||||
|
{
|
||||||
|
return WEBP_PRESET_DRAWING;
|
||||||
|
}
|
||||||
|
else if (! strcmp (name, "icon"))
|
||||||
|
{
|
||||||
|
return WEBP_PRESET_ICON;
|
||||||
|
}
|
||||||
|
else if (! strcmp (name, "text"))
|
||||||
|
{
|
||||||
|
return WEBP_PRESET_TEXT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return WEBP_PRESET_DEFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
webp_anim_file_writer (FILE *outfile,
|
||||||
|
const uint8_t *data,
|
||||||
|
size_t data_size)
|
||||||
|
{
|
||||||
|
int ok = 0;
|
||||||
|
|
||||||
|
if (data == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ok = (fwrite (data, data_size, 1, outfile) == 1);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
webp_file_writer (const uint8_t *data,
|
||||||
|
size_t data_size,
|
||||||
|
const WebPPicture *picture)
|
||||||
|
{
|
||||||
|
FILE *outfile;
|
||||||
|
|
||||||
|
/* Obtain the FILE* and write the data to the file */
|
||||||
|
outfile = (FILE *) picture->custom_ptr;
|
||||||
|
|
||||||
|
return fwrite (data, sizeof (uint8_t), data_size, outfile) == data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
webp_file_progress (int percent,
|
||||||
|
const WebPPicture *picture)
|
||||||
|
{
|
||||||
|
return gimp_progress_update (percent / 100.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const gchar *
|
||||||
|
webp_error_string (WebPEncodingError error_code)
|
||||||
|
{
|
||||||
|
switch (error_code)
|
||||||
|
{
|
||||||
|
case VP8_ENC_ERROR_OUT_OF_MEMORY:
|
||||||
|
return _("out of memory");
|
||||||
|
case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
|
||||||
|
return _("not enough memory to flush bits");
|
||||||
|
case VP8_ENC_ERROR_NULL_PARAMETER:
|
||||||
|
return _("NULL parameter");
|
||||||
|
case VP8_ENC_ERROR_INVALID_CONFIGURATION:
|
||||||
|
return _("invalid configuration");
|
||||||
|
case VP8_ENC_ERROR_BAD_DIMENSION:
|
||||||
|
return _("bad image dimensions");
|
||||||
|
case VP8_ENC_ERROR_PARTITION0_OVERFLOW:
|
||||||
|
return _("partition is bigger than 512K");
|
||||||
|
case VP8_ENC_ERROR_PARTITION_OVERFLOW:
|
||||||
|
return _("partition is bigger than 16M");
|
||||||
|
case VP8_ENC_ERROR_BAD_WRITE:
|
||||||
|
return _("unable to flush bytes");
|
||||||
|
case VP8_ENC_ERROR_FILE_TOO_BIG:
|
||||||
|
return _("file is larger than 4GiB");
|
||||||
|
case VP8_ENC_ERROR_USER_ABORT:
|
||||||
|
return _("user aborted encoding");
|
||||||
|
case VP8_ENC_ERROR_LAST:
|
||||||
|
return _("list terminator");
|
||||||
|
default:
|
||||||
|
return _("unknown error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
save_layer (const gchar *filename,
|
||||||
|
gint32 nLayers,
|
||||||
|
gint32 image_ID,
|
||||||
|
gint32 drawable_ID,
|
||||||
|
WebPSaveParams *params,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean status = FALSE;
|
||||||
|
FILE *outfile = NULL;
|
||||||
|
WebPConfig config = {0};
|
||||||
|
WebPPicture picture = {0};
|
||||||
|
guchar *buffer = NULL;
|
||||||
|
gint w, h;
|
||||||
|
gint bpp;
|
||||||
|
GimpColorProfile *profile;
|
||||||
|
GimpImageType drawable_type;
|
||||||
|
GeglBuffer *geglbuffer = NULL;
|
||||||
|
GeglRectangle extent;
|
||||||
|
gchar *indata;
|
||||||
|
gsize indatalen;
|
||||||
|
struct stat stsz;
|
||||||
|
int fd_outfile;
|
||||||
|
WebPData chunk;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
/* The do...while() loop is a neat little trick that makes it easier
|
||||||
|
* to jump to error handling code while still ensuring proper
|
||||||
|
* cleanup
|
||||||
|
*/
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Begin displaying export progress */
|
||||||
|
gimp_progress_init_printf (_("Saving '%s'"),
|
||||||
|
gimp_filename_to_utf8(filename));
|
||||||
|
|
||||||
|
/* Attempt to open the output file */
|
||||||
|
if ((outfile = g_fopen (filename, "wb+")) == NULL)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_FILE_ERROR,
|
||||||
|
g_file_error_from_errno (errno),
|
||||||
|
_("Unable to open '%s' for writing"),
|
||||||
|
gimp_filename_to_utf8 (filename));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Obtain the drawable type */
|
||||||
|
drawable_type = gimp_drawable_type (drawable_ID);
|
||||||
|
|
||||||
|
/* Retrieve the buffer for the layer */
|
||||||
|
geglbuffer = gimp_drawable_get_buffer (drawable_ID);
|
||||||
|
extent = *gegl_buffer_get_extent (geglbuffer);
|
||||||
|
bpp = gimp_drawable_bpp (drawable_ID);
|
||||||
|
w = extent.width;
|
||||||
|
h = extent.height;
|
||||||
|
|
||||||
|
/* Initialize the WebP configuration with a preset and fill in the
|
||||||
|
* remaining values */
|
||||||
|
WebPConfigPreset (&config,
|
||||||
|
webp_preset_by_name (params->preset),
|
||||||
|
params->quality);
|
||||||
|
|
||||||
|
config.lossless = params->lossless;
|
||||||
|
config.method = 6; /* better quality */
|
||||||
|
config.alpha_quality = params->alpha_quality;
|
||||||
|
|
||||||
|
/* Prepare the WebP structure */
|
||||||
|
WebPPictureInit (&picture);
|
||||||
|
picture.use_argb = 1;
|
||||||
|
picture.width = w;
|
||||||
|
picture.height = h;
|
||||||
|
picture.writer = webp_file_writer;
|
||||||
|
picture.custom_ptr = outfile;
|
||||||
|
picture.progress_hook = webp_file_progress;
|
||||||
|
|
||||||
|
/* Attempt to allocate a buffer of the appropriate size */
|
||||||
|
buffer = (guchar *) g_malloc (w * h * bpp);
|
||||||
|
if(! buffer)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Read the region into the buffer */
|
||||||
|
gegl_buffer_get (geglbuffer, &extent, 1.0, NULL, buffer,
|
||||||
|
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||||
|
|
||||||
|
/* Use the appropriate function to import the data from the buffer */
|
||||||
|
if (drawable_type == GIMP_RGB_IMAGE)
|
||||||
|
{
|
||||||
|
WebPPictureImportRGB (&picture, buffer, w * bpp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WebPPictureImportRGBA (&picture, buffer, w * bpp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the actual encode */
|
||||||
|
if (! WebPEncode (&config, &picture))
|
||||||
|
{
|
||||||
|
g_printerr ("WebP error: '%s'",
|
||||||
|
webp_error_string (picture.error_code));
|
||||||
|
g_set_error (error, G_FILE_ERROR,
|
||||||
|
picture.error_code,
|
||||||
|
_("WebP error: '%s'"),
|
||||||
|
webp_error_string (picture.error_code));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The cleanup stuff still needs to run but indicate that everything
|
||||||
|
* completed successfully
|
||||||
|
*/
|
||||||
|
status = TRUE;
|
||||||
|
|
||||||
|
}
|
||||||
|
while (0);
|
||||||
|
|
||||||
|
/* Flush the drawable and detach */
|
||||||
|
if (geglbuffer)
|
||||||
|
{
|
||||||
|
gegl_buffer_flush (geglbuffer);
|
||||||
|
g_object_unref (geglbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fflush (outfile);
|
||||||
|
fd_outfile = fileno (outfile);
|
||||||
|
fstat (fd_outfile, &stsz);
|
||||||
|
indatalen = stsz.st_size;
|
||||||
|
if (indatalen > 0)
|
||||||
|
{
|
||||||
|
indata = (gchar*) g_malloc (indatalen);
|
||||||
|
rewind (outfile);
|
||||||
|
res = fread (indata, 1, indatalen, outfile);
|
||||||
|
if (res > 0)
|
||||||
|
{
|
||||||
|
WebPMux *mux;
|
||||||
|
WebPData wp_data;
|
||||||
|
|
||||||
|
wp_data.bytes = (uint8_t*) indata;
|
||||||
|
wp_data.size = indatalen;
|
||||||
|
mux = WebPMuxCreate (&wp_data, 1);
|
||||||
|
|
||||||
|
if (mux)
|
||||||
|
{
|
||||||
|
gboolean saved = FALSE;
|
||||||
|
|
||||||
|
/* Save ICC data */
|
||||||
|
profile = gimp_image_get_color_profile (image_ID);
|
||||||
|
if (profile)
|
||||||
|
{
|
||||||
|
const guint8 *icc_data;
|
||||||
|
gsize icc_data_size;
|
||||||
|
|
||||||
|
saved = TRUE;
|
||||||
|
|
||||||
|
icc_data = gimp_color_profile_get_icc_profile (profile,
|
||||||
|
&icc_data_size);
|
||||||
|
chunk.bytes = icc_data;
|
||||||
|
chunk.size = icc_data_size;
|
||||||
|
WebPMuxSetChunk(mux, "ICCP", &chunk, 1);
|
||||||
|
g_object_unref (profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (saved == TRUE)
|
||||||
|
{
|
||||||
|
WebPMuxAssemble (mux, &wp_data);
|
||||||
|
rewind (outfile);
|
||||||
|
webp_anim_file_writer (outfile, wp_data.bytes, wp_data.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_printerr ("ERROR: Cannot create mux. Can't save features update.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
WebPDataClear (&wp_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_printerr ("ERROR: No data read for features. Can't save features update.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_printerr ("ERROR: No data for features. Can't save features update.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free any resources */
|
||||||
|
if (outfile)
|
||||||
|
fclose (outfile);
|
||||||
|
|
||||||
|
if (buffer)
|
||||||
|
free (buffer);
|
||||||
|
|
||||||
|
WebPPictureFree (&picture);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
save_animation (const gchar *filename,
|
||||||
|
gint32 nLayers,
|
||||||
|
gint32 *allLayers,
|
||||||
|
gint32 image_ID,
|
||||||
|
gint32 drawable_ID,
|
||||||
|
WebPSaveParams *params,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean status = FALSE;
|
||||||
|
FILE *outfile = NULL;
|
||||||
|
guchar *buffer = NULL;
|
||||||
|
gint w, h, bpp;
|
||||||
|
GimpImageType drawable_type;
|
||||||
|
GimpColorProfile *profile;
|
||||||
|
WebPAnimEncoderOptions enc_options;
|
||||||
|
WebPData webp_data;
|
||||||
|
int frame_timestamp = 0;
|
||||||
|
WebPAnimEncoder *enc;
|
||||||
|
WebPMux *mux;
|
||||||
|
WebPMuxAnimParams anim_params = {0};
|
||||||
|
|
||||||
|
if (nLayers < 1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
gint loop;
|
||||||
|
|
||||||
|
/* Begin displaying export progress */
|
||||||
|
gimp_progress_init_printf (_("Saving '%s'"),
|
||||||
|
gimp_filename_to_utf8 (filename));
|
||||||
|
|
||||||
|
/* Attempt to open the output file */
|
||||||
|
if ((outfile = g_fopen (filename, "wb")) == NULL)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_FILE_ERROR,
|
||||||
|
g_file_error_from_errno (errno),
|
||||||
|
_("Unable to open '%s' for writing"),
|
||||||
|
gimp_filename_to_utf8 (filename));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebPDataInit (&webp_data);
|
||||||
|
if (! WebPAnimEncoderOptionsInit (&enc_options))
|
||||||
|
{
|
||||||
|
g_printerr ("ERROR: verion mismatch\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (loop = 0; loop < nLayers; loop++)
|
||||||
|
{
|
||||||
|
GeglBuffer *geglbuffer;
|
||||||
|
GeglRectangle extent;
|
||||||
|
WebPConfig config;
|
||||||
|
WebPPicture picture;
|
||||||
|
WebPMemoryWriter mw = { 0 };
|
||||||
|
|
||||||
|
/* Obtain the drawable type */
|
||||||
|
drawable_type = gimp_drawable_type (allLayers[loop]);
|
||||||
|
|
||||||
|
/* Retrieve the buffer for the layer */
|
||||||
|
geglbuffer = gimp_drawable_get_buffer (allLayers[loop]);
|
||||||
|
extent = *gegl_buffer_get_extent (geglbuffer);
|
||||||
|
bpp = gimp_drawable_bpp (allLayers[loop]);
|
||||||
|
w = extent.width;
|
||||||
|
h = extent.height;
|
||||||
|
|
||||||
|
if (loop == 0)
|
||||||
|
{
|
||||||
|
enc = WebPAnimEncoderNew (w, h, &enc_options);
|
||||||
|
if (! enc)
|
||||||
|
{
|
||||||
|
g_printerr ("ERROR: enc == null\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attempt to allocate a buffer of the appropriate size */
|
||||||
|
buffer = (guchar *) g_malloc (w * h * bpp);
|
||||||
|
if(! buffer)
|
||||||
|
{
|
||||||
|
g_printerr ("Buffer error: 'buffer null'\n");
|
||||||
|
status = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebPConfigInit (&config);
|
||||||
|
WebPConfigPreset (&config,
|
||||||
|
webp_preset_by_name (params->preset),
|
||||||
|
params->quality);
|
||||||
|
|
||||||
|
config.lossless = params->lossless;
|
||||||
|
config.method = 6; /* better quality */
|
||||||
|
config.alpha_quality = params->alpha_quality;
|
||||||
|
config.exact = 1;
|
||||||
|
|
||||||
|
WebPMemoryWriterInit (&mw);
|
||||||
|
|
||||||
|
/* Prepare the WebP structure */
|
||||||
|
WebPPictureInit (&picture);
|
||||||
|
picture.use_argb = 1;
|
||||||
|
picture.argb_stride = w * bpp;
|
||||||
|
picture.width = w;
|
||||||
|
picture.height = h;
|
||||||
|
picture.custom_ptr = &mw;
|
||||||
|
picture.writer = WebPMemoryWrite;
|
||||||
|
picture.progress_hook = webp_file_progress;
|
||||||
|
|
||||||
|
/* Read the region into the buffer */
|
||||||
|
gegl_buffer_get (geglbuffer, &extent, 1.0, NULL, buffer,
|
||||||
|
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||||
|
|
||||||
|
/* Use the appropriate function to import the data from the buffer */
|
||||||
|
if (drawable_type == GIMP_RGB_IMAGE)
|
||||||
|
{
|
||||||
|
WebPPictureImportRGB (&picture, buffer, w * bpp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WebPPictureImportRGBA (&picture, buffer, w * bpp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the actual encode */
|
||||||
|
if (! WebPAnimEncoderAdd (enc, &picture, frame_timestamp, &config))
|
||||||
|
{
|
||||||
|
g_printerr ("ERROR[%d]: %s\n",
|
||||||
|
picture.error_code,
|
||||||
|
webp_error_string (picture.error_code));
|
||||||
|
}
|
||||||
|
|
||||||
|
WebPMemoryWriterClear (&mw);
|
||||||
|
WebPPictureFree (&picture);
|
||||||
|
|
||||||
|
if (buffer)
|
||||||
|
free (buffer);
|
||||||
|
|
||||||
|
/* Flush the drawable and detach */
|
||||||
|
gegl_buffer_flush (geglbuffer);
|
||||||
|
g_object_unref (geglbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
WebPAnimEncoderAdd (enc, NULL, frame_timestamp, NULL);
|
||||||
|
|
||||||
|
if (! WebPAnimEncoderAssemble (enc, &webp_data))
|
||||||
|
{
|
||||||
|
g_printerr ("ERROR: %s\n",
|
||||||
|
WebPAnimEncoderGetError (enc));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set animations parameters */
|
||||||
|
mux = WebPMuxCreate (&webp_data, 1);
|
||||||
|
|
||||||
|
anim_params.loop_count = 0;
|
||||||
|
if (params->loop == FALSE)
|
||||||
|
{
|
||||||
|
anim_params.loop_count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebPMuxSetAnimationParams (mux, &anim_params);
|
||||||
|
|
||||||
|
/* Save ICC data */
|
||||||
|
profile = gimp_image_get_color_profile (image_ID);
|
||||||
|
if (profile)
|
||||||
|
{
|
||||||
|
WebPData chunk;
|
||||||
|
const guint8 *icc_data;
|
||||||
|
gsize icc_data_size;
|
||||||
|
|
||||||
|
icc_data = gimp_color_profile_get_icc_profile (profile, &icc_data_size);
|
||||||
|
chunk.bytes = icc_data;
|
||||||
|
chunk.size = icc_data_size;
|
||||||
|
WebPMuxSetChunk (mux, "ICCP", &chunk, 1);
|
||||||
|
g_object_unref (profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
WebPMuxAssemble (mux, &webp_data);
|
||||||
|
|
||||||
|
webp_anim_file_writer (outfile, webp_data.bytes, webp_data.size);
|
||||||
|
|
||||||
|
WebPDataClear (&webp_data);
|
||||||
|
WebPAnimEncoderDelete (enc);
|
||||||
|
|
||||||
|
status = TRUE;
|
||||||
|
}
|
||||||
|
while (0);
|
||||||
|
|
||||||
|
/* Free any resources */
|
||||||
|
if (outfile)
|
||||||
|
fclose (outfile);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
save_image (const gchar *filename,
|
||||||
|
gint32 nLayers,
|
||||||
|
gint32 *allLayers,
|
||||||
|
gint32 image_ID,
|
||||||
|
gint32 drawable_ID,
|
||||||
|
WebPSaveParams *params,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GimpMetadata *metadata;
|
||||||
|
GimpMetadataSaveFlags metadata_flags;
|
||||||
|
gboolean status = FALSE;
|
||||||
|
GFile *file;
|
||||||
|
|
||||||
|
if (nLayers == 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
gegl_init (NULL, NULL);
|
||||||
|
|
||||||
|
g_printerr("Saving WebP file %s\n", filename);
|
||||||
|
|
||||||
|
if (nLayers == 1)
|
||||||
|
{
|
||||||
|
status = save_layer (filename, nLayers, image_ID, drawable_ID, params,
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (! params->animation)
|
||||||
|
{
|
||||||
|
status = save_layer (filename,
|
||||||
|
nLayers, image_ID, drawable_ID, params,
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = save_animation (filename,
|
||||||
|
nLayers, allLayers, image_ID, drawable_ID,
|
||||||
|
params, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata = gimp_image_metadata_save_prepare (image_ID,
|
||||||
|
"image/webp",
|
||||||
|
&metadata_flags);
|
||||||
|
|
||||||
|
if (metadata)
|
||||||
|
{
|
||||||
|
gimp_metadata_set_bits_per_sample (metadata, 8);
|
||||||
|
file = g_file_new_for_path (filename);
|
||||||
|
gimp_image_metadata_save_finish (image_ID,
|
||||||
|
"image/webp",
|
||||||
|
metadata, metadata_flags,
|
||||||
|
file, NULL);
|
||||||
|
g_object_unref (file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the status */
|
||||||
|
return status;
|
||||||
|
}
|
46
plug-ins/file-webp/file-webp-save.h
Normal file
46
plug-ins/file-webp/file-webp-save.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/* GIMP - The GNU Image Manipulation Program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* file-webp - WebP file format plug-in for the GIMP
|
||||||
|
* Copyright (C) 2015 Nathan Osman
|
||||||
|
* Copyright (C) 2016 Ben Touchette
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WEBP_SAVE_H__
|
||||||
|
#define __WEBP_SAVE_H__
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
gchar *preset;
|
||||||
|
gboolean lossless;
|
||||||
|
gboolean animation;
|
||||||
|
gboolean loop;
|
||||||
|
gfloat quality;
|
||||||
|
gfloat alpha_quality;
|
||||||
|
} WebPSaveParams;
|
||||||
|
|
||||||
|
|
||||||
|
gboolean save_image (const gchar *filename,
|
||||||
|
gint32 nLayers,
|
||||||
|
gint32 *allLayers,
|
||||||
|
gint32 image_ID,
|
||||||
|
gint32 drawable_ID,
|
||||||
|
WebPSaveParams *params,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __WEBP_SAVE_H__ */
|
270
plug-ins/file-webp/file-webp.c
Normal file
270
plug-ins/file-webp/file-webp.c
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
/* GIMP - The GNU Image Manipulation Program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* file-webp - WebP file format plug-in for the GIMP
|
||||||
|
* Copyright (C) 2015 Nathan Osman
|
||||||
|
* Copyright (C) 2016 Ben Touchette
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <libgimp/gimp.h>
|
||||||
|
#include <libgimp/gimpui.h>
|
||||||
|
|
||||||
|
#include <webp/encode.h>
|
||||||
|
|
||||||
|
#include "file-webp-dialog.h"
|
||||||
|
#include "file-webp-load.h"
|
||||||
|
#include "file-webp-save.h"
|
||||||
|
#include "file-webp.h"
|
||||||
|
|
||||||
|
#include "libgimp/stdplugins-intl.h"
|
||||||
|
|
||||||
|
|
||||||
|
const char BINARY_NAME[] = "file-webp";
|
||||||
|
const char LOAD_PROCEDURE[] = "file-webp-load";
|
||||||
|
const char SAVE_PROCEDURE[] = "file-webp-save";
|
||||||
|
|
||||||
|
/* Predeclare our entrypoints. */
|
||||||
|
static void query (void);
|
||||||
|
static void run (const gchar *,
|
||||||
|
gint,
|
||||||
|
const GimpParam *,
|
||||||
|
gint *,
|
||||||
|
GimpParam **);
|
||||||
|
|
||||||
|
/* Declare our plugin entry points. */
|
||||||
|
GimpPlugInInfo PLUG_IN_INFO =
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
query,
|
||||||
|
run
|
||||||
|
};
|
||||||
|
|
||||||
|
MAIN()
|
||||||
|
|
||||||
|
/* This function registers our load and save handlers. */
|
||||||
|
static void
|
||||||
|
query (void)
|
||||||
|
{
|
||||||
|
static const GimpParamDef load_arguments[] =
|
||||||
|
{
|
||||||
|
{ GIMP_PDB_INT32, "run-mode", "Interactive, non-interactive" },
|
||||||
|
{ GIMP_PDB_STRING, "filename", "The name of the file to load" },
|
||||||
|
{ GIMP_PDB_STRING, "raw-filename", "The name entered" }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const GimpParamDef load_return_values[] =
|
||||||
|
{
|
||||||
|
{ GIMP_PDB_IMAGE, "image", "Output image" }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const GimpParamDef save_arguments[] =
|
||||||
|
{
|
||||||
|
{ GIMP_PDB_INT32, "run-mode", "Interactive, non-interactive" },
|
||||||
|
{ GIMP_PDB_IMAGE, "image", "Input image" },
|
||||||
|
{ GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
|
||||||
|
{ GIMP_PDB_STRING, "filename", "The name of the file to save the image to" },
|
||||||
|
{ GIMP_PDB_STRING, "raw-filename", "The name entered" },
|
||||||
|
{ GIMP_PDB_STRING, "preset", "Name of preset to use" },
|
||||||
|
{ GIMP_PDB_INT32, "lossless", "Use lossless encoding (0/1)" },
|
||||||
|
{ GIMP_PDB_FLOAT, "quality", "Quality of the image (0 <= quality <= 100)" },
|
||||||
|
{ GIMP_PDB_FLOAT, "alpha-quality", "Quality of the image's alpha channel (0 <= alpha-quality <= 100)" },
|
||||||
|
{ GIMP_PDB_INT32, "animation", "Use layers for animation (0/1)" },
|
||||||
|
{ GIMP_PDB_INT32, "anim-loop", "Loop animation infinitely (0/1)" }
|
||||||
|
};
|
||||||
|
|
||||||
|
gimp_install_procedure (LOAD_PROCEDURE,
|
||||||
|
"Loads images in the WebP file format",
|
||||||
|
"Loads images in the WebP file format",
|
||||||
|
"Nathan Osman, Ben Touchette",
|
||||||
|
"(C) 2015-2016 Nathan Osman, (C) 2016 Ben Touchette",
|
||||||
|
"2015,2016",
|
||||||
|
N_("WebP image"),
|
||||||
|
NULL,
|
||||||
|
GIMP_PLUGIN,
|
||||||
|
G_N_ELEMENTS (load_arguments),
|
||||||
|
G_N_ELEMENTS (load_return_values),
|
||||||
|
load_arguments,
|
||||||
|
load_return_values);
|
||||||
|
|
||||||
|
gimp_register_file_handler_mime (LOAD_PROCEDURE, "image/webp");
|
||||||
|
gimp_register_load_handler (LOAD_PROCEDURE, "webp", "");
|
||||||
|
gimp_register_magic_load_handler (LOAD_PROCEDURE,
|
||||||
|
"webp",
|
||||||
|
"",
|
||||||
|
"8,string,WEBP");
|
||||||
|
|
||||||
|
gimp_install_procedure (SAVE_PROCEDURE,
|
||||||
|
"Saves files in the WebP image format",
|
||||||
|
"Saves files in the WebP image format",
|
||||||
|
"Nathan Osman, Ben Touchette",
|
||||||
|
"(C) 2015-2016 Nathan Osman, (C) 2016 Ben Touchette",
|
||||||
|
"2015,2016",
|
||||||
|
N_("WebP image"),
|
||||||
|
"RGB*",
|
||||||
|
GIMP_PLUGIN,
|
||||||
|
G_N_ELEMENTS (save_arguments),
|
||||||
|
0,
|
||||||
|
save_arguments,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
gimp_register_file_handler_mime (SAVE_PROCEDURE, "image/webp");
|
||||||
|
gimp_register_save_handler (SAVE_PROCEDURE, "webp", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
run (const gchar *name,
|
||||||
|
gint nparams,
|
||||||
|
const GimpParam *param,
|
||||||
|
gint *nreturn_vals,
|
||||||
|
GimpParam **return_vals)
|
||||||
|
{
|
||||||
|
static GimpParam values[2];
|
||||||
|
GimpRunMode run_mode;
|
||||||
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
||||||
|
gint32 image_ID;
|
||||||
|
gint32 drawable_ID;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
/* Determine the current run mode */
|
||||||
|
run_mode = param[0].data.d_int32;
|
||||||
|
|
||||||
|
/* Fill in the return values */
|
||||||
|
*nreturn_vals = 1;
|
||||||
|
*return_vals = values;
|
||||||
|
values[0].type = GIMP_PDB_STATUS;
|
||||||
|
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
|
||||||
|
|
||||||
|
/* Determine which procedure is being invoked */
|
||||||
|
if (! strcmp (name, LOAD_PROCEDURE))
|
||||||
|
{
|
||||||
|
/* No need to determine whether the plugin is being invoked
|
||||||
|
* interactively here since we don't need a UI for loading
|
||||||
|
*/
|
||||||
|
image_ID = load_image (param[1].data.d_string, FALSE, &error);
|
||||||
|
|
||||||
|
if(image_ID != -1)
|
||||||
|
{
|
||||||
|
/* Return the new image that was loaded */
|
||||||
|
*nreturn_vals = 2;
|
||||||
|
values[1].type = GIMP_PDB_IMAGE;
|
||||||
|
values[1].data.d_image = image_ID;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = GIMP_PDB_EXECUTION_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (! strcmp (name, SAVE_PROCEDURE))
|
||||||
|
{
|
||||||
|
WebPSaveParams params;
|
||||||
|
GimpExportReturn export_ret = GIMP_EXPORT_CANCEL;
|
||||||
|
gint32 *layers;
|
||||||
|
gint32 n_layers;
|
||||||
|
|
||||||
|
/* Initialize the parameters to their defaults */
|
||||||
|
params.preset = "default";
|
||||||
|
params.lossless = FALSE;
|
||||||
|
params.animation = FALSE;
|
||||||
|
params.loop = TRUE;
|
||||||
|
params.quality = 90.0f;
|
||||||
|
params.alpha_quality = 100.0f;
|
||||||
|
|
||||||
|
/* Load the image and drawable IDs */
|
||||||
|
image_ID = param[1].data.d_int32;
|
||||||
|
drawable_ID = param[2].data.d_int32;
|
||||||
|
|
||||||
|
layers = gimp_image_get_layers (image_ID, &n_layers);
|
||||||
|
|
||||||
|
/* What happens next depends on the run mode */
|
||||||
|
switch (run_mode)
|
||||||
|
{
|
||||||
|
case GIMP_RUN_INTERACTIVE:
|
||||||
|
case GIMP_RUN_WITH_LAST_VALS:
|
||||||
|
|
||||||
|
gimp_ui_init (BINARY_NAME, FALSE);
|
||||||
|
|
||||||
|
/* Attempt to export the image */
|
||||||
|
export_ret = gimp_export_image (&image_ID,
|
||||||
|
&drawable_ID,
|
||||||
|
"WEBP",
|
||||||
|
GIMP_EXPORT_CAN_HANDLE_RGB |
|
||||||
|
GIMP_EXPORT_CAN_HANDLE_ALPHA);
|
||||||
|
|
||||||
|
/* Return immediately if canceled */
|
||||||
|
if (export_ret == GIMP_EXPORT_CANCEL)
|
||||||
|
{
|
||||||
|
values[0].data.d_status = GIMP_PDB_CANCEL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Display the dialog */
|
||||||
|
if (save_dialog (¶ms, image_ID, n_layers) != GTK_RESPONSE_OK)
|
||||||
|
{
|
||||||
|
values[0].data.d_status = GIMP_PDB_CANCEL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GIMP_RUN_NONINTERACTIVE:
|
||||||
|
|
||||||
|
/* Ensure the correct number of parameters were supplied */
|
||||||
|
if (nparams != 10)
|
||||||
|
{
|
||||||
|
status = GIMP_PDB_CALLING_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load the parameters */
|
||||||
|
params.preset = param[5].data.d_string;
|
||||||
|
params.lossless = param[6].data.d_int32;
|
||||||
|
params.quality = param[7].data.d_float;
|
||||||
|
params.alpha_quality = param[8].data.d_float;
|
||||||
|
params.animation = param[9].data.d_int32;
|
||||||
|
params.loop = param[10].data.d_int32;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attempt to save the image */
|
||||||
|
if (! save_image (param[3].data.d_string,
|
||||||
|
n_layers, layers,
|
||||||
|
image_ID,
|
||||||
|
drawable_ID,
|
||||||
|
¶ms,
|
||||||
|
&error))
|
||||||
|
{
|
||||||
|
status = GIMP_PDB_EXECUTION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (layers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If an error was supplied, include it in the return values */
|
||||||
|
if (status != GIMP_PDB_SUCCESS && error)
|
||||||
|
{
|
||||||
|
*nreturn_vals = 2;
|
||||||
|
values[1].type = GIMP_PDB_STRING;
|
||||||
|
values[1].data.d_string = error->message;
|
||||||
|
}
|
||||||
|
|
||||||
|
values[0].data.d_status = status;
|
||||||
|
}
|
28
plug-ins/file-webp/file-webp.h
Normal file
28
plug-ins/file-webp/file-webp.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/* GIMP - The GNU Image Manipulation Program
|
||||||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||||
|
*
|
||||||
|
* file-webp - WebP file format plug-in for the GIMP
|
||||||
|
* Copyright (C) 2015 Nathan Osman
|
||||||
|
* Copyright (C) 2016 Ben Touchette
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WEBP_H__
|
||||||
|
#define __WEBP_H__
|
||||||
|
|
||||||
|
extern const char BINARY_NAME[];
|
||||||
|
extern const char SAVE_PROCEDURE[];
|
||||||
|
|
||||||
|
#endif /* __WEBP_H__ */
|
|
@ -122,6 +122,10 @@ plug-ins/file-sgi/sgi.c
|
||||||
plug-ins/file-tiff/file-tiff.c
|
plug-ins/file-tiff/file-tiff.c
|
||||||
plug-ins/file-tiff/file-tiff-load.c
|
plug-ins/file-tiff/file-tiff-load.c
|
||||||
plug-ins/file-tiff/file-tiff-save.c
|
plug-ins/file-tiff/file-tiff-save.c
|
||||||
|
plug-ins/file-webp/file-webp.c
|
||||||
|
plug-ins/file-webp/file-webp-dialog.c
|
||||||
|
plug-ins/file-webp/file-webp-load.c
|
||||||
|
plug-ins/file-webp/file-webp-save.c
|
||||||
plug-ins/flame/flame.c
|
plug-ins/flame/flame.c
|
||||||
plug-ins/fractal-explorer/fractal-explorer-dialogs.c
|
plug-ins/fractal-explorer/fractal-explorer-dialogs.c
|
||||||
plug-ins/fractal-explorer/fractal-explorer.c
|
plug-ins/fractal-explorer/fractal-explorer.c
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue