[gimp] Bug 769651 - Add webp file format support to gimp master
- From: Michael Natterer <mitch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] Bug 769651 - Add webp file format support to gimp master
- Date: Tue, 9 Aug 2016 19:26:35 +0000 (UTC)
commit c1021a3e3a8d4574505c8008ea619018a8fb1b69
Author: Benoit Touchette <draekko software+gimp gmail com>
Date: Mon Aug 8 16:39:30 2016 -0400
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.
configure.ac | 37 ++
plug-ins/Makefile.am | 5 +
plug-ins/file-webp/.gitignore | 7 +
plug-ins/file-webp/Makefile.am | 64 ++++
plug-ins/file-webp/file-webp-dialog.c | 287 +++++++++++++++
plug-ins/file-webp/file-webp-dialog.h | 34 ++
plug-ins/file-webp/file-webp-load.c | 275 +++++++++++++++
plug-ins/file-webp/file-webp-load.h | 31 ++
plug-ins/file-webp/file-webp-save.c | 619 +++++++++++++++++++++++++++++++++
plug-ins/file-webp/file-webp-save.h | 46 +++
plug-ins/file-webp/file-webp.c | 270 ++++++++++++++
plug-ins/file-webp/file-webp.h | 28 ++
po-plug-ins/POTFILES.in | 4 +
13 files changed, 1707 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 3d9ba74..e12baa0 100644
--- a/configure.ac
+++ b/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([intltool_required_version], [0.40.1])
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
# 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
INTLTOOL_REQUIRED_VERSION=intltool_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
AC_SUBST(GLIB_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(INTLTOOL_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)
# 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)
+################
+# 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
######################
@@ -2400,6 +2435,7 @@ plug-ins/file-jpeg/Makefile
plug-ins/file-psd/Makefile
plug-ins/file-sgi/Makefile
plug-ins/file-tiff/Makefile
+plug-ins/file-webp/Makefile
plug-ins/flame/Makefile
plug-ins/fractal-explorer/Makefile
plug-ins/fractal-explorer/examples/Makefile
@@ -2554,6 +2590,7 @@ Optional Plug-Ins:
JPEG 2000: $have_jp2
MNG: $have_libmng
OpenEXR: $have_openexr
+ WebP: $have_webp
PDF (import): $have_poppler
PDF (export): $have_cairo_pdf
Print: $enable_print
diff --git a/plug-ins/Makefile.am b/plug-ins/Makefile.am
index 8ba9a45..d60046c 100644
--- a/plug-ins/Makefile.am
+++ b/plug-ins/Makefile.am
@@ -25,6 +25,10 @@ if OS_WIN32
twain = twain
endif
+if HAVE_WEBP
+file_webp = file-webp
+endif
+
SUBDIRS = \
$(script_fu) \
$(pygimp) \
@@ -39,6 +43,7 @@ SUBDIRS = \
file-psd \
file-sgi \
file-tiff \
+ $(file_webp) \
flame \
fractal-explorer \
gfig \
diff --git a/plug-ins/file-webp/.gitignore b/plug-ins/file-webp/.gitignore
new file mode 100644
index 0000000..380c017
--- /dev/null
+++ b/plug-ins/file-webp/.gitignore
@@ -0,0 +1,7 @@
+/Makefile.in
+/Makefile
+/.deps
+/_libs
+/.libs
+/file-webp
+/file-webp.exe
diff --git a/plug-ins/file-webp/Makefile.am b/plug-ins/file-webp/Makefile.am
new file mode 100644
index 0000000..296c904
--- /dev/null
+++ b/plug-ins/file-webp/Makefile.am
@@ -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)
diff --git a/plug-ins/file-webp/file-webp-dialog.c b/plug-ins/file-webp/file-webp-dialog.c
new file mode 100644
index 0000000..96150a1
--- /dev/null
+++ b/plug-ins/file-webp/file-webp-dialog.c
@@ -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;
+}
diff --git a/plug-ins/file-webp/file-webp-dialog.h b/plug-ins/file-webp/file-webp-dialog.h
new file mode 100644
index 0000000..e0bec97
--- /dev/null
+++ b/plug-ins/file-webp/file-webp-dialog.h
@@ -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__ */
diff --git a/plug-ins/file-webp/file-webp-load.c b/plug-ins/file-webp/file-webp-load.c
new file mode 100644
index 0000000..4c40490
--- /dev/null
+++ b/plug-ins/file-webp/file-webp-load.c
@@ -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;
+}
diff --git a/plug-ins/file-webp/file-webp-load.h b/plug-ins/file-webp/file-webp-load.h
new file mode 100644
index 0000000..2622210
--- /dev/null
+++ b/plug-ins/file-webp/file-webp-load.h
@@ -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__ */
diff --git a/plug-ins/file-webp/file-webp-save.c b/plug-ins/file-webp/file-webp-save.c
new file mode 100644
index 0000000..efc0b1f
--- /dev/null
+++ b/plug-ins/file-webp/file-webp-save.c
@@ -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;
+}
diff --git a/plug-ins/file-webp/file-webp-save.h b/plug-ins/file-webp/file-webp-save.h
new file mode 100644
index 0000000..23c55e6
--- /dev/null
+++ b/plug-ins/file-webp/file-webp-save.h
@@ -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__ */
diff --git a/plug-ins/file-webp/file-webp.c b/plug-ins/file-webp/file-webp.c
new file mode 100644
index 0000000..451e80d
--- /dev/null
+++ b/plug-ins/file-webp/file-webp.c
@@ -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;
+}
diff --git a/plug-ins/file-webp/file-webp.h b/plug-ins/file-webp/file-webp.h
new file mode 100644
index 0000000..783aacf
--- /dev/null
+++ b/plug-ins/file-webp/file-webp.h
@@ -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__ */
diff --git a/po-plug-ins/POTFILES.in b/po-plug-ins/POTFILES.in
index 5de4885..5509882 100644
--- a/po-plug-ins/POTFILES.in
+++ b/po-plug-ins/POTFILES.in
@@ -122,6 +122,10 @@ plug-ins/file-sgi/sgi.c
plug-ins/file-tiff/file-tiff.c
plug-ins/file-tiff/file-tiff-load.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/fractal-explorer/fractal-explorer-dialogs.c
plug-ins/fractal-explorer/fractal-explorer.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]