[gthumb] added ability to save images as WebP



commit ebbcf1a90e8580abc6f5685eacdb471d7656c53d
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Sun Aug 26 10:16:47 2012 +0200

    added ability to save images as WebP
    
    [new feature]

 data/org.gnome.gthumb.pixbuf-savers.gschema.xml.in |   31 ++-
 extensions/cairo_io/Makefile.am                    |    4 +-
 extensions/cairo_io/data/ui/Makefile.am            |    3 +-
 .../cairo_io/data/ui/save-options-preferences.ui   |    2 +-
 extensions/cairo_io/data/ui/tiff-options.ui        |  367 +++++++++---------
 extensions/cairo_io/data/ui/webp-options.ui        |  121 ++++++
 extensions/cairo_io/gth-image-saver-webp.c         |  397 ++++++++++++++++++++
 extensions/cairo_io/gth-image-saver-webp.h         |   56 +++
 extensions/cairo_io/main.c                         |    4 +-
 extensions/cairo_io/preferences.h                  |    7 +
 gthumb/cairo-utils.c                               |   29 +-
 gthumb/glib-utils.c                                |    5 +-
 12 files changed, 821 insertions(+), 205 deletions(-)
---
diff --git a/data/org.gnome.gthumb.pixbuf-savers.gschema.xml.in b/data/org.gnome.gthumb.pixbuf-savers.gschema.xml.in
index 8c13f56..220dae3 100644
--- a/data/org.gnome.gthumb.pixbuf-savers.gschema.xml.in
+++ b/data/org.gnome.gthumb.pixbuf-savers.gschema.xml.in
@@ -1,30 +1,31 @@
 <!--
   gThumb
- 
+
   Copyright  2011 Free Software Foundation, Inc.
- 
+
   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 2 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/>.
 -->
 <schemalist>
-    
+
   <schema id="org.gnome.gthumb.pixbuf-savers" path="/org/gnome/gthumb/pixbuf-savers/">
     <child name="jpeg" schema="org.gnome.gthumb.pixbuf-savers.jpeg" />
     <child name="png" schema="org.gnome.gthumb.pixbuf-savers.png" />
     <child name="tga" schema="org.gnome.gthumb.pixbuf-savers.tga" />
     <child name="tiff" schema="org.gnome.gthumb.pixbuf-savers.tiff" />
+    <child name="webp" schema="org.gnome.gthumb.pixbuf-savers.webp" />
   </schema>
-  
+
   <schema id="org.gnome.gthumb.pixbuf-savers.jpeg" path="/org/gnome/gthumb/pixbuf-savers/jpeg/">
     <key name="default-ext" type="s">
       <default>'jpeg'</default>
@@ -43,19 +44,19 @@
       <default>false</default>
     </key>
   </schema>
-  
+
   <schema id="org.gnome.gthumb.pixbuf-savers.png" path="/org/gnome/gthumb/pixbuf-savers/png/">
     <key name="compression-level" type="i">
       <default>6</default>
     </key>
   </schema>
-  
+
   <schema id="org.gnome.gthumb.pixbuf-savers.tga" path="/org/gnome/gthumb/pixbuf-savers/tga/">
     <key name="rle-compression" type="b">
       <default>true</default>
     </key>
   </schema>
-  
+
   <schema id="org.gnome.gthumb.pixbuf-savers.tiff" path="/org/gnome/gthumb/pixbuf-savers/tiff/">
     <key name="default-ext" type="s">
       <default>'tiff'</default>
@@ -72,4 +73,16 @@
     </key>
   </schema>
 
+  <schema id="org.gnome.gthumb.pixbuf-savers.webp" path="/org/gnome/gthumb/pixbuf-savers/webp/">
+    <key name="lossless" type="b">
+      <default>true</default>
+    </key>
+    <key name="quality" type="i">
+      <default>75</default>
+    </key>
+    <key name="method" type="i">
+      <default>4</default>
+    </key>
+  </schema>
+
 </schemalist>
diff --git a/extensions/cairo_io/Makefile.am b/extensions/cairo_io/Makefile.am
index 9e822d1..a33dacc 100644
--- a/extensions/cairo_io/Makefile.am
+++ b/extensions/cairo_io/Makefile.am
@@ -58,7 +58,9 @@ endif
 if ENABLE_LIBWEBP
 libcairo_io_la_SOURCES +=		\
 	cairo-image-surface-webp.c	\
-	cairo-image-surface-webp.h
+	cairo-image-surface-webp.h	\
+	gth-image-saver-webp.c		\
+	gth-image-saver-webp.h
 endif
 
 libcairo_io_la_CFLAGS = $(GTHUMB_CFLAGS) $(JPEG_CFLAGS) $(LIBRSVG_CFLAGS) -I$(top_srcdir) -I$(top_builddir)/gthumb
diff --git a/extensions/cairo_io/data/ui/Makefile.am b/extensions/cairo_io/data/ui/Makefile.am
index f4eede8..17d86bc 100644
--- a/extensions/cairo_io/data/ui/Makefile.am
+++ b/extensions/cairo_io/data/ui/Makefile.am
@@ -4,7 +4,8 @@ ui_DATA = 				\
 	png-options.ui			\
 	save-options-preferences.ui	\
 	tga-options.ui			\
-	tiff-options.ui
+	tiff-options.ui			\
+	webp-options.ui
 EXTRA_DIST = $(ui_DATA)
 
 -include $(top_srcdir)/git.mk
diff --git a/extensions/cairo_io/data/ui/save-options-preferences.ui b/extensions/cairo_io/data/ui/save-options-preferences.ui
index 459ac69..fb72872 100644
--- a/extensions/cairo_io/data/ui/save-options-preferences.ui
+++ b/extensions/cairo_io/data/ui/save-options-preferences.ui
@@ -16,7 +16,7 @@
     <property name="can_focus">False</property>
     <property name="border_width">12</property>
     <property name="orientation">vertical</property>
-    <property name="spacing">6</property>
+    <property name="spacing">12</property>
     <child>
       <object class="GtkLabel" id="label1">
         <property name="visible">True</property>
diff --git a/extensions/cairo_io/data/ui/tiff-options.ui b/extensions/cairo_io/data/ui/tiff-options.ui
index ebaf764..e836345 100644
--- a/extensions/cairo_io/data/ui/tiff-options.ui
+++ b/extensions/cairo_io/data/ui/tiff-options.ui
@@ -65,93 +65,98 @@
       </packing>
     </child>
     <child>
-      <object class="GtkFrame" id="frame1">
+      <object class="GtkBox" id="box5">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="label_xalign">0</property>
-        <property name="shadow_type">none</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">6</property>
         <child>
-          <object class="GtkAlignment" id="alignment1">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="top_padding">6</property>
-            <property name="left_padding">12</property>
-            <child>
-              <object class="GtkBox" id="box2">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="orientation">vertical</property>
-                <property name="spacing">6</property>
-                <child>
-                  <object class="GtkRadioButton" id="tiff_comp_none_radiobutton">
-                    <property name="label" translatable="yes">_No compression</property>
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_action_appearance">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="xalign">0</property>
-                    <property name="active">True</property>
-                    <property name="draw_indicator">True</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkRadioButton" id="tiff_comp_deflate_radiobutton">
-                    <property name="label" translatable="yes">No_rmal (Deflate)</property>
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_action_appearance">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="xalign">0</property>
-                    <property name="active">True</property>
-                    <property name="draw_indicator">True</property>
-                    <property name="group">tiff_comp_none_radiobutton</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkRadioButton" id="tiff_comp_jpeg_radiobutton">
-                    <property name="label" translatable="yes">_Loss compression (JPEG)</property>
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <property name="use_action_appearance">False</property>
-                    <property name="use_underline">True</property>
-                    <property name="xalign">0</property>
-                    <property name="active">True</property>
-                    <property name="draw_indicator">True</property>
-                    <property name="group">tiff_comp_none_radiobutton</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">2</property>
-                  </packing>
-                </child>
-              </object>
-            </child>
-          </object>
-        </child>
-        <child type="label">
           <object class="GtkLabel" id="label2">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
+            <property name="xalign">0</property>
             <property name="label" translatable="yes">Compression</property>
             <property name="use_markup">True</property>
             <attributes>
               <attribute name="weight" value="bold"/>
             </attributes>
           </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="box2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">12</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkRadioButton" id="tiff_comp_none_radiobutton">
+                <property name="label" translatable="yes">_No compression</property>
+                <property name="use_action_appearance">False</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioButton" id="tiff_comp_deflate_radiobutton">
+                <property name="label" translatable="yes">No_rmal (Deflate)</property>
+                <property name="use_action_appearance">False</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+                <property name="group">tiff_comp_none_radiobutton</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioButton" id="tiff_comp_jpeg_radiobutton">
+                <property name="label" translatable="yes">_Loss compression (JPEG)</property>
+                <property name="use_action_appearance">False</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+                <property name="group">tiff_comp_none_radiobutton</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
         </child>
       </object>
       <packing>
@@ -161,147 +166,151 @@
       </packing>
     </child>
     <child>
-      <object class="GtkFrame" id="frame2">
+      <object class="GtkBox" id="box6">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="label_xalign">0</property>
-        <property name="shadow_type">none</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">6</property>
         <child>
-          <object class="GtkAlignment" id="alignment2">
+          <object class="GtkLabel" id="label3">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="top_padding">6</property>
-            <property name="left_padding">12</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">Resolution</property>
+            <property name="use_markup">True</property>
+            <attributes>
+              <attribute name="weight" value="bold"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="grid1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">12</property>
+            <property name="row_spacing">6</property>
+            <property name="column_spacing">6</property>
+            <child>
+              <object class="GtkLabel" id="label4">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">_Horizontal:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">tiff_hdpi_spinbutton</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label5">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">_Vertical:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">tiff_vdpi_spinbutton</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
             <child>
-              <object class="GtkGrid" id="grid1">
+              <object class="GtkBox" id="box3">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="row_spacing">6</property>
-                <property name="column_spacing">6</property>
-                <property name="n_rows">2</property>
-                <property name="n_columns">2</property>
+                <property name="spacing">6</property>
                 <child>
-                  <object class="GtkLabel" id="label4">
+                  <object class="GtkSpinButton" id="tiff_hdpi_spinbutton">
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="xalign">0</property>
-                    <property name="label" translatable="yes">_Horizontal:</property>
-                    <property name="use_underline">True</property>
-                    <property name="mnemonic_widget">tiff_hdpi_spinbutton</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">â</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="adjustment">tiff_hdpi_adjustment</property>
                   </object>
                   <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">0</property>
-                    <property name="width">1</property>
-                    <property name="height">1</property>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="label5">
+                  <object class="GtkLabel" id="label6">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="xalign">0</property>
-                    <property name="label" translatable="yes">_Vertical:</property>
-                    <property name="use_underline">True</property>
-                    <property name="mnemonic_widget">tiff_vdpi_spinbutton</property>
+                    <property name="label" translatable="yes">dpi</property>
                   </object>
                   <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">1</property>
-                    <property name="width">1</property>
-                    <property name="height">1</property>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
                   </packing>
                 </child>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="box4">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="spacing">6</property>
                 <child>
-                  <object class="GtkBox" id="box3">
+                  <object class="GtkSpinButton" id="tiff_vdpi_spinbutton">
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="spacing">6</property>
-                    <child>
-                      <object class="GtkSpinButton" id="tiff_hdpi_spinbutton">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="invisible_char">â</property>
-                        <property name="adjustment">tiff_hdpi_adjustment</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="label6">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">dpi</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">â</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="adjustment">tiff_vdpi_adjustment</property>
                   </object>
                   <packing>
-                    <property name="left_attach">1</property>
-                    <property name="top_attach">0</property>
-                    <property name="width">1</property>
-                    <property name="height">1</property>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkBox" id="box4">
+                  <object class="GtkLabel" id="label7">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="spacing">6</property>
-                    <child>
-                      <object class="GtkSpinButton" id="tiff_vdpi_spinbutton">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="invisible_char">â</property>
-                        <property name="adjustment">tiff_vdpi_adjustment</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="label7">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">dpi</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
+                    <property name="label" translatable="yes">dpi</property>
                   </object>
                   <packing>
-                    <property name="left_attach">1</property>
-                    <property name="top_attach">1</property>
-                    <property name="width">1</property>
-                    <property name="height">1</property>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
                   </packing>
                 </child>
               </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">1</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
             </child>
           </object>
-        </child>
-        <child type="label">
-          <object class="GtkLabel" id="label3">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="label" translatable="yes">Resolution</property>
-            <property name="use_markup">True</property>
-            <attributes>
-              <attribute name="weight" value="bold"/>
-            </attributes>
-          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
         </child>
       </object>
       <packing>
diff --git a/extensions/cairo_io/data/ui/webp-options.ui b/extensions/cairo_io/data/ui/webp-options.ui
new file mode 100644
index 0000000..d5ae6ec
--- /dev/null
+++ b/extensions/cairo_io/data/ui/webp-options.ui
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkAdjustment" id="method_adjustment">
+    <property name="upper">6</property>
+    <property name="value">4</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">1</property>
+  </object>
+  <object class="GtkAdjustment" id="quality_adjustment">
+    <property name="upper">100</property>
+    <property name="value">75</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkBox" id="webp_options">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="border_width">6</property>
+    <property name="orientation">vertical</property>
+    <property name="spacing">12</property>
+    <child>
+      <object class="GtkGrid" id="grid1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="label2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">_Quality:</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">quality_scale</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label3">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">_Method:</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">method_scale</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="lossless_checkbutton">
+            <property name="label" translatable="yes">_Lossless</property>
+            <property name="use_action_appearance">False</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="use_action_appearance">False</property>
+            <property name="use_underline">True</property>
+            <property name="xalign">0</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+            <property name="width">2</property>
+            <property name="height">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScale" id="quality_scale">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="adjustment">quality_adjustment</property>
+            <property name="round_digits">1</property>
+            <property name="digits">0</property>
+            <property name="value_pos">left</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScale" id="method_scale">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="adjustment">method_adjustment</property>
+            <property name="round_digits">1</property>
+            <property name="digits">0</property>
+            <property name="value_pos">left</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/extensions/cairo_io/gth-image-saver-webp.c b/extensions/cairo_io/gth-image-saver-webp.c
new file mode 100644
index 0000000..0de77bd
--- /dev/null
+++ b/extensions/cairo_io/gth-image-saver-webp.c
@@ -0,0 +1,397 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ *  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 2 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 <webp/encode.h>
+#include <glib/gi18n.h>
+#include <gthumb.h>
+#include "gth-image-saver-webp.h"
+#include "preferences.h"
+
+
+#define GET_WIDGET(x) (_gtk_builder_get_widget (self->priv->builder, (x)))
+
+
+G_DEFINE_TYPE (GthImageSaverWebp, gth_image_saver_webp, GTH_TYPE_IMAGE_SAVER)
+
+
+struct _GthImageSaverWebpPrivate {
+	GtkBuilder *builder;
+	GSettings  *settings;
+};
+
+
+static void
+gth_image_saver_webp_finalize (GObject *object)
+{
+	GthImageSaverWebp *self = GTH_IMAGE_SAVER_WEBP (object);
+
+	_g_object_unref (self->priv->builder);
+	_g_object_unref (self->priv->settings);
+	G_OBJECT_CLASS (gth_image_saver_webp_parent_class)->finalize (object);
+}
+
+
+static GtkWidget *
+gth_image_saver_webp_get_control (GthImageSaver *base)
+{
+	GthImageSaverWebp *self = GTH_IMAGE_SAVER_WEBP (base);
+
+	if (self->priv->builder == NULL)
+		self->priv->builder = _gtk_builder_new_from_file ("webp-options.ui", "cairo_io");
+
+	gtk_adjustment_set_value (GTK_ADJUSTMENT (GET_WIDGET ("quality_adjustment")),
+				  g_settings_get_int (self->priv->settings, PREF_WEBP_QUALITY));
+	gtk_adjustment_set_value (GTK_ADJUSTMENT (GET_WIDGET ("method_adjustment")),
+				  g_settings_get_int (self->priv->settings, PREF_WEBP_METHOD));
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("lossless_checkbutton")),
+				      g_settings_get_boolean (self->priv->settings, PREF_WEBP_LOSSLESS));
+
+	return GET_WIDGET ("webp_options");
+}
+
+
+static void
+gth_image_saver_webp_save_options (GthImageSaver *base)
+{
+	GthImageSaverWebp *self = GTH_IMAGE_SAVER_WEBP (base);
+
+	g_settings_set_int (self->priv->settings, PREF_WEBP_QUALITY, (int) gtk_adjustment_get_value (GTK_ADJUSTMENT (GET_WIDGET ("quality_adjustment"))));
+	g_settings_set_int (self->priv->settings, PREF_WEBP_METHOD, (int) gtk_adjustment_get_value (GTK_ADJUSTMENT (GET_WIDGET ("method_adjustment"))));
+	g_settings_set_boolean (self->priv->settings, PREF_WEBP_LOSSLESS, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("lossless_checkbutton"))));
+}
+
+
+static gboolean
+gth_image_saver_webp_can_save (GthImageSaver *self,
+			      const char    *mime_type)
+{
+	return g_content_type_equals (mime_type, "image/webp");
+}
+
+
+typedef struct {
+	GError        **error;
+	GthBufferData  *buffer_data;
+	int             success;
+} CairoWebpData;
+
+
+static void
+_cairo_webp_data_destroy (CairoWebpData *cairo_webp_data)
+{
+	gth_buffer_data_free (cairo_webp_data->buffer_data, ! cairo_webp_data->success);
+	g_free (cairo_webp_data);
+}
+
+
+static int
+cairo_webp_writer_func (const uint8_t     *data,
+			size_t             data_size,
+			const WebPPicture *picture)
+{
+	CairoWebpData *cairo_webp_data = picture->custom_ptr;
+
+	cairo_webp_data->success = gth_buffer_data_write (cairo_webp_data->buffer_data,
+							  (void *) data,
+							  data_size,
+							  cairo_webp_data->error);
+
+	return cairo_webp_data->success;
+}
+
+
+static int
+_WebPPictureImportCairoSurface (WebPPicture     *const picture,
+				cairo_surface_t *image)
+{
+	int       stride;
+	guchar   *src_row;
+	uint32_t *dest_row;
+	int       y, x;
+	guchar    r, g, b, a;
+
+	if (_cairo_image_surface_get_has_alpha (image))
+		picture->colorspace |= WEBP_CSP_ALPHA_BIT;
+	else
+		picture->colorspace &= ~WEBP_CSP_ALPHA_BIT;
+
+	if (! WebPPictureAlloc (picture))
+		return 0;
+
+	stride = cairo_image_surface_get_stride (image);
+	src_row = cairo_image_surface_get_data (image);
+	dest_row = picture->argb;
+
+	for (y= 0; y < cairo_image_surface_get_height (image); y++) {
+		guchar *pixel = src_row;
+
+		for (x = 0; x < cairo_image_surface_get_width (image); x++) {
+			CAIRO_GET_RGBA (pixel, r, g, b, a);
+			dest_row[x] = ((a << 24) | (r << 16) | (g <<  8) | b);
+
+			pixel += 4;
+		}
+
+		src_row += stride;
+		dest_row += picture->argb_stride;
+	}
+
+	return 1;
+}
+
+
+static gboolean
+_cairo_surface_write_as_webp (cairo_surface_t  *image,
+			      char            **buffer,
+			      gsize            *buffer_size,
+			      char            **keys,
+			      char            **values,
+			      GError          **error)
+{
+	gboolean       lossless;
+	int            quality;
+	int            method;
+	WebPConfig     config;
+	CairoWebpData *cairo_webp_data;
+	WebPPicture    pic;
+
+	lossless = TRUE;
+	quality = 75;
+	method = 4;
+
+	if (keys && *keys) {
+		char **kiter = keys;
+		char **viter = values;
+
+		while (*kiter) {
+			if (strcmp (*kiter, "lossless") == 0) {
+				if (*viter == NULL) {
+					g_set_error (error,
+						     G_IO_ERROR,
+						     G_IO_ERROR_INVALID_DATA,
+						     "Must specify a value for the 'lossless' option");
+					return FALSE;
+				}
+
+				lossless = atoi (*viter);
+
+				if (lossless < 0 || lossless > 1) {
+					g_set_error (error,
+						     G_IO_ERROR,
+						     G_IO_ERROR_INVALID_DATA,
+						     "Invalid value set for the 'lossless' option of the WebP saver");
+					return FALSE;
+				}
+			}
+			else if (strcmp (*kiter, "quality") == 0) {
+				if (*viter == NULL) {
+					g_set_error (error,
+						     G_IO_ERROR,
+						     G_IO_ERROR_INVALID_DATA,
+						     "Must specify a quality value to the WebP saver");
+					return FALSE;
+				}
+
+				quality = atoi (*viter);
+
+				if (quality < 0 || quality > 100) {
+					g_set_error (error,
+						     G_IO_ERROR,
+						     G_IO_ERROR_INVALID_DATA,
+						     "Unsupported quality value passed to the WebP saver");
+					return FALSE;
+				}
+			}
+			else if (strcmp (*kiter, "method") == 0) {
+				if (*viter == NULL) {
+					g_set_error (error,
+						     G_IO_ERROR,
+						     G_IO_ERROR_INVALID_DATA,
+						     "Must specify a method value to the WebP saver");
+					return FALSE;
+				}
+
+				method = atoi (*viter);
+
+				if (method < 0 || method > 6) {
+					g_set_error (error,
+						     G_IO_ERROR,
+						     G_IO_ERROR_INVALID_DATA,
+						     "Unsupported method value passed to the WebP saver");
+					return FALSE;
+				}
+			}
+			else {
+				g_warning ("Bad option name '%s' passed to the WebP saver", *kiter);
+				return FALSE;
+			}
+
+			++kiter;
+			++viter;
+		}
+	}
+
+	if (! WebPConfigInit (&config)) {
+		g_set_error (error,
+			     G_IO_ERROR,
+			     G_IO_ERROR_INVALID_DATA,
+			     "Version error");
+		return FALSE;
+	}
+
+	config.lossless = lossless;
+	config.quality = quality;
+	config.method = method;
+
+	if (! WebPValidateConfig (&config)) {
+		g_set_error (error,
+			     G_IO_ERROR,
+			     G_IO_ERROR_INVALID_DATA,
+			     "Config error");
+		return FALSE;
+	}
+
+	cairo_webp_data = g_new0 (CairoWebpData, 1);
+	cairo_webp_data->error = error;
+	cairo_webp_data->buffer_data = gth_buffer_data_new ();
+	cairo_webp_data->success = FALSE;
+
+	WebPPictureInit (&pic);
+	pic.width = cairo_image_surface_get_width (image);
+	pic.height = cairo_image_surface_get_height (image);
+	pic.writer = cairo_webp_writer_func;
+	pic.custom_ptr = cairo_webp_data;
+	pic.use_argb = TRUE;
+
+	if (_WebPPictureImportCairoSurface (&pic, image)) {
+		int ok = WebPEncode (&config, &pic);
+		WebPPictureFree (&pic);
+
+		if (cairo_webp_data->success && ! ok) {
+			g_set_error (cairo_webp_data->error,
+				     G_IO_ERROR,
+				     G_IO_ERROR_INVALID_DATA,
+				     "Encoding error: %d", pic.error_code);
+			cairo_webp_data->success = FALSE;
+		}
+	}
+	else {
+		g_set_error (cairo_webp_data->error,
+			     G_IO_ERROR,
+			     G_IO_ERROR_INVALID_DATA,
+			     "Memory error");
+		cairo_webp_data->success = FALSE;
+	}
+
+	if (cairo_webp_data->success)
+		gth_buffer_data_get (cairo_webp_data->buffer_data, buffer, buffer_size);
+
+	_cairo_webp_data_destroy (cairo_webp_data);
+
+	return TRUE;
+}
+
+
+static gboolean
+gth_image_saver_webp_save_image (GthImageSaver   *base,
+				 GthImage        *image,
+				 char           **buffer,
+				 gsize           *buffer_size,
+				 const char      *mime_type,
+				 GError         **error)
+{
+	GthImageSaverWebp  *self = GTH_IMAGE_SAVER_WEBP (base);
+	cairo_surface_t    *surface;
+	char              **option_keys;
+	char              **option_values;
+	int                 i = -1;
+	int                 i_value;
+	gboolean            result;
+
+	option_keys = g_new (char *, 4);
+	option_values = g_new (char *, 4);
+
+	i++;
+	i_value = g_settings_get_boolean (self->priv->settings, PREF_WEBP_LOSSLESS);
+	option_keys[i] = g_strdup ("lossless");;
+	option_values[i] = g_strdup_printf ("%d", i_value);
+
+	i++;
+	i_value = g_settings_get_int (self->priv->settings, PREF_WEBP_QUALITY);
+	option_keys[i] = g_strdup ("quality");;
+	option_values[i] = g_strdup_printf ("%d", i_value);
+
+	i++;
+	i_value = g_settings_get_int (self->priv->settings, PREF_WEBP_METHOD);
+	option_keys[i] = g_strdup ("method");;
+	option_values[i] = g_strdup_printf ("%d", i_value);
+
+	i++;
+	option_keys[i] = NULL;
+	option_values[i] = NULL;
+
+	surface = gth_image_get_cairo_surface (image);
+	result = _cairo_surface_write_as_webp (surface,
+					       buffer,
+					       buffer_size,
+					       option_keys,
+					       option_values,
+					       error);
+
+	cairo_surface_destroy (surface);
+	g_strfreev (option_keys);
+	g_strfreev (option_values);
+
+	return result;
+}
+
+
+static void
+gth_image_saver_webp_class_init (GthImageSaverWebpClass *klass)
+{
+	GObjectClass       *object_class;
+	GthImageSaverClass *image_saver_class;
+
+	g_type_class_add_private (klass, sizeof (GthImageSaverWebpPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gth_image_saver_webp_finalize;
+
+	image_saver_class = GTH_IMAGE_SAVER_CLASS (klass);
+	image_saver_class->id = "webp";
+	image_saver_class->display_name = _("WebP");
+	image_saver_class->mime_type = "image/webp";
+	image_saver_class->extensions = "webp";
+	image_saver_class->get_default_ext = NULL;
+	image_saver_class->get_control = gth_image_saver_webp_get_control;
+	image_saver_class->save_options = gth_image_saver_webp_save_options;
+	image_saver_class->can_save = gth_image_saver_webp_can_save;
+	image_saver_class->save_image = gth_image_saver_webp_save_image;
+}
+
+
+static void
+gth_image_saver_webp_init (GthImageSaverWebp *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_IMAGE_SAVER_WEBP, GthImageSaverWebpPrivate);
+	self->priv->settings = g_settings_new (GTHUMB_IMAGE_SAVERS_WEBP_SCHEMA);
+}
diff --git a/extensions/cairo_io/gth-image-saver-webp.h b/extensions/cairo_io/gth-image-saver-webp.h
new file mode 100644
index 0000000..c353b04
--- /dev/null
+++ b/extensions/cairo_io/gth-image-saver-webp.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2012 Free Software Foundation, Inc.
+ *
+ *  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 2 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 GTH_IMAGE_SAVER_WEBP_H
+#define GTH_IMAGE_SAVER_WEBP_H
+
+#include <gtk/gtk.h>
+#include <gthumb.h>
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_IMAGE_SAVER_WEBP              (gth_image_saver_webp_get_type ())
+#define GTH_IMAGE_SAVER_WEBP(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_IMAGE_SAVER_WEBP, GthImageSaverWebp))
+#define GTH_IMAGE_SAVER_WEBP_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_IMAGE_SAVER_WEBP_TYPE, GthImageSaverWebpClass))
+#define GTH_IS_IMAGE_SAVER_WEBP(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_IMAGE_SAVER_WEBP))
+#define GTH_IS_IMAGE_SAVER_WEBP_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_IMAGE_SAVER_WEBP))
+#define GTH_IMAGE_SAVER_WEBP_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS((obj), GTH_TYPE_IMAGE_SAVER_WEBP, GthImageSaverWebpClass))
+
+typedef struct _GthImageSaverWebp         GthImageSaverWebp;
+typedef struct _GthImageSaverWebpClass    GthImageSaverWebpClass;
+typedef struct _GthImageSaverWebpPrivate  GthImageSaverWebpPrivate;
+
+struct _GthImageSaverWebp
+{
+	GthImageSaver __parent;
+	GthImageSaverWebpPrivate *priv;
+};
+
+struct _GthImageSaverWebpClass
+{
+	GthImageSaverClass __parent_class;
+};
+
+GType  gth_image_saver_webp_get_type  (void);
+
+G_END_DECLS
+
+#endif /* GTH_IMAGE_SAVER_WEBP_H */
diff --git a/extensions/cairo_io/main.c b/extensions/cairo_io/main.c
index a685ecc..27564de 100644
--- a/extensions/cairo_io/main.c
+++ b/extensions/cairo_io/main.c
@@ -30,7 +30,7 @@
 #include "gth-image-saver-png.h"
 #include "gth-image-saver-tga.h"
 #include "gth-image-saver-tiff.h"
-/*#include "gth-image-saver-webp.h"*/
+#include "gth-image-saver-webp.h"
 #include "preferences.h"
 
 
@@ -66,7 +66,7 @@ gthumb_extension_activate (void)
 					     GTH_IMAGE_FORMAT_CAIRO_SURFACE,
 					     "image/webp",
 					     NULL);
-	/*gth_main_register_type ("image-saver", GTH_TYPE_IMAGE_SAVER_WEBP);*/
+	gth_main_register_type ("image-saver", GTH_TYPE_IMAGE_SAVER_WEBP);
 #endif
 
 	gth_hook_add_callback ("dlg-preferences-construct", 30, G_CALLBACK (ci__dlg_preferences_construct_cb), NULL);
diff --git a/extensions/cairo_io/preferences.h b/extensions/cairo_io/preferences.h
index 1d48bcc..798275f 100644
--- a/extensions/cairo_io/preferences.h
+++ b/extensions/cairo_io/preferences.h
@@ -39,6 +39,7 @@ typedef enum {
 #define GTHUMB_IMAGE_SAVERS_PNG_SCHEMA    GTHUMB_IMAGE_SAVERS ".png"
 #define GTHUMB_IMAGE_SAVERS_TGA_SCHEMA    GTHUMB_IMAGE_SAVERS ".tga"
 #define GTHUMB_IMAGE_SAVERS_TIFF_SCHEMA   GTHUMB_IMAGE_SAVERS ".tiff"
+#define GTHUMB_IMAGE_SAVERS_WEBP_SCHEMA   GTHUMB_IMAGE_SAVERS ".webp"
 
 /* keys: jpeg */
 
@@ -63,6 +64,12 @@ typedef enum {
 #define  PREF_TIFF_HORIZONTAL_RES         "horizontal-resolution"
 #define  PREF_TIFF_VERTICAL_RES           "vertical-resolution"
 
+/* keys: webp */
+
+#define  PREF_WEBP_LOSSLESS               "lossless"
+#define  PREF_WEBP_QUALITY                "quality"
+#define  PREF_WEBP_METHOD                 "method"
+
 
 void ci__dlg_preferences_construct_cb (GtkWidget  *dialog,
 				       GthBrowser *browser,
diff --git a/gthumb/cairo-utils.c b/gthumb/cairo-utils.c
index d635f5e..3d78475 100644
--- a/gthumb/cairo-utils.c
+++ b/gthumb/cairo-utils.c
@@ -566,20 +566,29 @@ _cairo_image_surface_color_shift (cairo_surface_t *image,
 
 void
 _cairo_copy_line_as_rgba (guchar *dest,
-			 guchar *src,
-			 guint   width,
-			 guint   alpha)
+			  guchar *src,
+			  guint   width,
+			  guint   alpha)
 {
 	guint x;
 
-	for (x = 0; x < width; x++) {
-		*(dest++) = src[CAIRO_RED];
-		*(dest++) = src[CAIRO_GREEN];
-		*(dest++) = src[CAIRO_BLUE];
-		if (alpha)
-			*(dest++) = src[CAIRO_ALPHA];
+	if (alpha) {
+		for (x = 0; x < width; x++) {
+			CAIRO_GET_RGBA (src, dest[0], dest[1], dest[2], dest[3]);
 
-		src += 4;
+			src += 4;
+			dest += 4;
+		}
+	}
+	else {
+		for (x = 0; x < width; x++) {
+			dest[0] = src[CAIRO_RED];
+			dest[1] = src[CAIRO_GREEN];
+			dest[2] = src[CAIRO_BLUE];
+
+			src += 4;
+			dest += 3;
+		}
 	}
 }
 
diff --git a/gthumb/glib-utils.c b/gthumb/glib-utils.c
index c25df62..d380ecd 100644
--- a/gthumb/glib-utils.c
+++ b/gthumb/glib-utils.c
@@ -2877,8 +2877,9 @@ get_mime_type_from_magic_numbers (void  *buffer,
 		const struct magic * const magic = &magic_ids[i];
 
 		if ((magic->off + magic->len) > buffer_size)
-			g_warning ("buffer underrun for mime-type '%s' magic", magic->mime_type);
-		else if (! memcmp (buffer + magic->off, magic->id, magic->len))
+			continue;
+
+		if (! memcmp (buffer + magic->off, magic->id, magic->len))
 			return magic->mime_type;
 	}
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]