Patches attached.

Thank you,
Jeremy Bícha
From f7fd3f136792eb4eb0f22f91ad72c6a156ffc4f9 Mon Sep 17 00:00:00 2001
From: Jeremy Bicha <jeremy.bi...@canonical.com>
Date: Thu, 6 Apr 2023 08:32:43 -0400
Subject: [PATCH 1/3] debian/control: Build-Depend on libwebp-dev

---
 debian/control | 1 +
 1 file changed, 1 insertion(+)

diff --git a/debian/control b/debian/control
index 500616b4..2340c6f3 100644
--- a/debian/control
+++ b/debian/control
@@ -31,6 +31,7 @@ Build-Depends:
  libsqlite3-dev (>= 3.5.9),
  libunity-dev,
  libwebkit2gtk-4.0-dev,
+ libwebp-dev,
  libxml2 (>= 2.6.32),
  meson,
  ninja-build,
-- 
2.39.2

From 1ec0ee79d5b105a54fb7be6305052d53d2a4bb16 Mon Sep 17 00:00:00 2001
From: Jeremy Bicha <jeremy.bi...@canonical.com>
Date: Thu, 6 Apr 2023 08:31:48 -0400
Subject: [PATCH 3/3] Cherry-pick 2 more patches required for webp support to
 work

LP: #1993881
Closes: #1034017
---
 debian/patches/0101-webp.patch | 425 +++++++++++++++++++++++++++++++++
 debian/patches/0102-webp.patch |  22 ++
 debian/patches/series          |   2 +
 3 files changed, 449 insertions(+)
 create mode 100644 debian/patches/0101-webp.patch
 create mode 100644 debian/patches/0102-webp.patch

diff --git a/debian/patches/0101-webp.patch b/debian/patches/0101-webp.patch
new file mode 100644
index 00000000..175c08d0
--- /dev/null
+++ b/debian/patches/0101-webp.patch
@@ -0,0 +1,425 @@
+From: Jens Georg <m...@jensge.org>
+Date: Wed, 30 Aug 2017 21:46:55 +0200
+Subject: Support reading WEBP
+
+https://bugzilla.gnome.org/show_bug.cgi?id=717880
+
+Requires a gexiv2 linked against exiv2 0.26 which currently works in the
+flatpak and on F28, but NOT on Debian/Ubuntu 18.04
+
+(cherry picked from commit f032a58dca391b1833c6ea70785bb3b63abc68c7)
+---
+ meson.build                     |   3 +
+ src/meson.build                 |   3 +-
+ src/photos/PhotoFileFormat.vala |  18 ++-
+ src/photos/WebPSupport.vala     | 240 ++++++++++++++++++++++++++++++++++++++++
+ vapi/libwebp.vapi               |   5 +
+ vapi/libwebpdemux.vapi          |  43 +++++++
+ 6 files changed, 309 insertions(+), 3 deletions(-)
+ create mode 100644 src/photos/WebPSupport.vala
+ create mode 100644 vapi/libwebp.vapi
+ create mode 100644 vapi/libwebpdemux.vapi
+
+diff --git a/meson.build b/meson.build
+index 5d08d30..2316377 100644
+--- a/meson.build
++++ b/meson.build
+@@ -66,6 +66,9 @@ libexif = dependency('libexif', version : '>= 0.6.16')
+ unity = dependency('unity', required : false)
+ portal = [ dependency('libportal', version: '>= 0.5'), dependency('libportal-gtk3', version: '>= 0.5')]
+ 
++webpdemux = dependency('libwebpdemux')
++webp = dependency('libwebp')
++
+ unity_available = false
+ if unity.found() and get_option('unity-support')
+   unity_available = true
+diff --git a/src/meson.build b/src/meson.build
+index a532eec..8cab77d 100644
+--- a/src/meson.build
++++ b/src/meson.build
+@@ -29,7 +29,7 @@ face_sources = (['faces/FacesBranch.vala',
+ 
+ shotwell_deps = [gio, gee, sqlite, gtk, sqlite, posix, gphoto2,
+                  gstreamer_pbu, gio_unix, gudev, gexiv2, gmodule,
+-                 libraw, libexif, sw_plugin, portal, version]
++                 libraw, libexif, sw_plugin, portal, version, webpdemux, webp]
+ if unity_available
+     shotwell_deps += [unity]
+ endif
+@@ -73,6 +73,7 @@ executable('shotwell',
+             'photos/RawSupport.vala',
+             'photos/PngSupport.vala',
+             'photos/TiffSupport.vala',
++            'photos/WebPSupport.vala',
+             'plugins/Plugins.vala',
+             'plugins/StandardHostInterface.vala',
+             'plugins/ManifestWidget.vala',
+diff --git a/src/photos/PhotoFileFormat.vala b/src/photos/PhotoFileFormat.vala
+index e642008..94ca752 100644
+--- a/src/photos/PhotoFileFormat.vala
++++ b/src/photos/PhotoFileFormat.vala
+@@ -58,12 +58,13 @@ public enum PhotoFileFormat {
+     TIFF,
+     BMP,
+     GIF,
++    WEBP,
+     UNKNOWN;
+     
+     // This is currently listed in the order of detection, that is, the file is examined from
+     // left to right.  (See PhotoFileInterrogator.)
+     public static PhotoFileFormat[] get_supported() {
+-        return { JFIF, RAW, PNG, TIFF, BMP, GIF };
++        return { JFIF, RAW, PNG, TIFF, BMP, GIF, WEBP };
+     }
+     
+     public static PhotoFileFormat[] get_writeable() {
+@@ -141,7 +142,10 @@ public enum PhotoFileFormat {
+ 
+             case GIF:
+                 return 5;
+-            
++
++            case WEBP:
++                return 6;
++
+             case UNKNOWN:
+             default:
+                 return -1;
+@@ -169,6 +173,9 @@ public enum PhotoFileFormat {
+             case 5:
+                 return GIF;
+                             
++            case 6:
++                return WEBP;
++
+             default:
+                 return UNKNOWN;
+         }
+@@ -249,6 +256,10 @@ public enum PhotoFileFormat {
+                 Photos.GifFileFormatDriver.init();
+                 break;
+ 
++            case WEBP:
++                Photos.WebpFileFormatDriver.init();
++                break;
++
+             default:
+                 error("Unsupported file format %s", this.to_string());
+         }
+@@ -274,6 +285,9 @@ public enum PhotoFileFormat {
+             case GIF:
+                 return Photos.GifFileFormatDriver.get_instance();
+ 
++            case WEBP:
++                return Photos.WebpFileFormatDriver.get_instance();
++
+             default:
+                 error("Unsupported file format %s", this.to_string());
+         }
+diff --git a/src/photos/WebPSupport.vala b/src/photos/WebPSupport.vala
+new file mode 100644
+index 0000000..093f196
+--- /dev/null
++++ b/src/photos/WebPSupport.vala
+@@ -0,0 +1,240 @@
++/* Copyright 2016 Software Freedom Conservancy Inc.
++ *
++ * This software is licensed under the GNU LGPL (version 2.1 or later).
++ * See the COPYING file in this distribution.
++ */
++
++namespace Photos {
++
++public class WebpFileFormatDriver : PhotoFileFormatDriver {
++    private static WebpFileFormatDriver instance = null;
++
++    public static void init() {
++        instance = new WebpFileFormatDriver();
++        WebpFileFormatProperties.init();
++    }
++
++    public static WebpFileFormatDriver get_instance() {
++        return instance;
++    }
++
++    public override PhotoFileFormatProperties get_properties() {
++        return WebpFileFormatProperties.get_instance();
++    }
++
++    public override PhotoFileReader create_reader(string filepath) {
++        return new WebpReader(filepath);
++    }
++
++    public override PhotoMetadata create_metadata() {
++        return new PhotoMetadata();
++    }
++
++    public override bool can_write_image() {
++        return false;
++    }
++
++    public override bool can_write_metadata() {
++        return true;
++    }
++
++    public override PhotoFileWriter? create_writer(string filepath) {
++        return null;
++    }
++
++    public override PhotoFileMetadataWriter? create_metadata_writer(string filepath) {
++        return new WebpMetadataWriter(filepath);
++    }
++
++    public override PhotoFileSniffer create_sniffer(File file, PhotoFileSniffer.Options options) {
++        return new WebpSniffer(file, options);
++    }
++}
++
++private class WebpFileFormatProperties : PhotoFileFormatProperties {
++    private static string[] KNOWN_EXTENSIONS = {
++        "webp"
++    };
++
++    private static string[] KNOWN_MIME_TYPES = {
++        "image/webp"
++    };
++
++    private static WebpFileFormatProperties instance = null;
++
++    public static void init() {
++        instance = new WebpFileFormatProperties();
++    }
++
++    public static WebpFileFormatProperties get_instance() {
++        return instance;
++    }
++
++    public override PhotoFileFormat get_file_format() {
++        return PhotoFileFormat.WEBP;
++    }
++
++    public override PhotoFileFormatFlags get_flags() {
++        return PhotoFileFormatFlags.NONE;
++    }
++
++    public override string get_default_extension() {
++        return "webp";
++    }
++
++    public override string get_user_visible_name() {
++        return _("WebP");
++    }
++
++    public override string[] get_known_extensions() {
++        return KNOWN_EXTENSIONS;
++    }
++
++    public override string get_default_mime_type() {
++        return KNOWN_MIME_TYPES[0];
++    }
++
++    public override string[] get_mime_types() {
++        return KNOWN_MIME_TYPES;
++    }
++}
++
++private class WebpSniffer : PhotoFileSniffer {
++    private DetectedPhotoInformation detected = null;
++
++    public WebpSniffer(File file, PhotoFileSniffer.Options options) {
++        base (file, options);
++        detected = new DetectedPhotoInformation();
++    }
++
++    public override DetectedPhotoInformation? sniff(out bool is_corrupted) throws Error {
++        is_corrupted = false;
++
++        if (!is_webp(file))
++            return null;
++
++         // valac chokes on the ternary operator here
++        Checksum? md5_checksum = null;
++        if (calc_md5)
++            md5_checksum = new Checksum(ChecksumType.MD5);
++
++        detected.metadata = new PhotoMetadata();
++        try {
++            detected.metadata.read_from_file(file);
++        } catch (Error err) {
++            debug("Failed to load meta-data from file: %s", err.message);
++            // no metadata detected
++            detected.metadata = null;
++        }
++
++        if (calc_md5 && detected.metadata != null) {
++            detected.exif_md5 = detected.metadata.exif_hash();
++            detected.thumbnail_md5 = detected.metadata.thumbnail_hash();
++        }
++
++        // if no MD5, don't read as much, as the needed info will probably be gleaned
++        // in the first 8K to 16K
++        uint8[] buffer = calc_md5 ? new uint8[64 * 1024] : new uint8[8 * 1024];
++        size_t count = 0;
++
++        // loop through until all conditions we're searching for are met
++        FileInputStream fins = file.read(null);
++        var ba = new ByteArray();
++        for (;;) {
++            size_t bytes_read = fins.read(buffer, null);
++            if (bytes_read <= 0)
++                break;
++
++            ba.append(buffer[0:bytes_read]);
++
++            count += bytes_read;
++
++            if (calc_md5)
++                md5_checksum.update(buffer, bytes_read);
++
++            WebP.Data d = WebP.Data();
++            d.bytes = ba.data;
++
++            WebP.ParsingState state;
++            var demux = new WebP.Demuxer.partial(d, out state);
++
++            if (state == WebP.ParsingState.PARSE_ERROR) {
++                is_corrupted = true;
++                break;
++            }
++
++            if (state > WebP.ParsingState.PARSED_HEADER) {
++                detected.file_format = PhotoFileFormat.WEBP;
++                detected.format_name = "WebP";
++                detected.channels = 4;
++                detected.bits_per_channel = 8;
++                detected.image_dim.width = (int) demux.get(WebP.FormatFeature.CANVAS_WIDTH);
++                detected.image_dim.height = (int) demux.get(WebP.FormatFeature.CANVAS_HEIGHT);
++
++                // if not searching for anything else, exit
++                if (!calc_md5)
++                    break;
++            }
++        }
++
++        if (fins != null)
++            fins.close(null);
++
++        if (calc_md5)
++            detected.md5 = md5_checksum.get_string();
++
++        return detected;
++    }
++}
++
++private class WebpReader : PhotoFileReader {
++    public WebpReader(string filepath) {
++        base (filepath, PhotoFileFormat.WEBP);
++    }
++
++    public override PhotoMetadata read_metadata() throws Error {
++        PhotoMetadata metadata = new PhotoMetadata();
++        metadata.read_from_file(get_file());
++
++        return metadata;
++    }
++
++    public override Gdk.Pixbuf unscaled_read() throws Error {
++        uint8[] buffer;
++
++        FileUtils.get_data(this.get_filepath(), out buffer);
++        int width, height;
++        var pixdata = WebP.DecodeRGBA(buffer, out width, out height);
++        pixdata.length = width * height * 4;
++
++        return new Gdk.Pixbuf.from_data(pixdata, Gdk.Colorspace.RGB, true, 8, width, height, width * 4);
++    }
++}
++
++private class WebpMetadataWriter : PhotoFileMetadataWriter {
++    public WebpMetadataWriter(string filepath) {
++        base (filepath, PhotoFileFormat.TIFF);
++    }
++
++    public override void write_metadata(PhotoMetadata metadata) throws Error {
++        metadata.write_to_file(get_file());
++    }
++}
++
++public bool is_webp(File file, Cancellable? cancellable = null) throws Error {
++    var ins = file.read();
++
++    uint8 buffer[12];
++    try {
++        ins.read(buffer, null);
++        if (buffer[0] == 'R' && buffer[1] == 'I' && buffer[2] == 'F' && buffer[3] == 'F' &&
++            buffer[8] == 'W' && buffer[9] == 'E' && buffer[10] == 'B' && buffer[11] == 'P')
++            return true;
++    } catch (Error error) {
++        debug ("Failed to read from file %s: %s", file.get_path (), error.message);
++    }
++
++    return false;
++}
++
++}
+diff --git a/vapi/libwebp.vapi b/vapi/libwebp.vapi
+new file mode 100644
+index 0000000..a19fbcf
+--- /dev/null
++++ b/vapi/libwebp.vapi
+@@ -0,0 +1,5 @@
++[CCode (cheader_filename = "webp/decode.h")]
++namespace WebP {
++    [CCode (array_length = false, cname="WebPDecodeRGBA")]
++    public static uint8[] DecodeRGBA([CCode (array_length_pos=1)]uint8[] data, out int width, out int height);
++}
+diff --git a/vapi/libwebpdemux.vapi b/vapi/libwebpdemux.vapi
+new file mode 100644
+index 0000000..7612b42
+--- /dev/null
++++ b/vapi/libwebpdemux.vapi
+@@ -0,0 +1,43 @@
++namespace WebP {
++    [CCode (has_type_id = false)]
++    public struct Data {
++        [CCode (array_length_cname = "size")]
++        public unowned uint8[] bytes;
++
++        public size_t size;
++
++        [CCode (cname = "WebPDataClear")]
++        public void clear();
++    }
++
++    [CCode (cprefix = "WEBP_DEMUX_", cname = "WebPDemuxState")]
++    public enum ParsingState {
++        PARSE_ERROR,
++        PARSING_HEADER,
++        PARSED_HEADER,
++        DONE
++    }
++
++    [CCode (cprefix = "WEBP_FF_")]
++    public enum FormatFeature {
++        FORMAT_FLAGS,
++        CANVAS_WIDTH,
++        CANVAS_HEIGHT,
++        LOOP_COUNT,
++        BACKGROUND_COLOR,
++        FRAME_COUNT
++    }
++
++    [Compact]
++    [CCode (free_function = "WebPDemuxDelete", cname = "WebPDemuxer", cheader_filename = "webp/demux.h", has_type_id = false)]
++    public class Demuxer {
++        [CCode (cname="WebPDemux")]
++        public Demuxer(Data data);
++
++        [CCode (cname="WebPDemuxPartial")]
++        public Demuxer.partial(Data data, out ParsingState state);
++
++        [CCode (cname="WebPDemuxGetI")]
++        public uint32 get(FormatFeature feature);
++    }
++}
diff --git a/debian/patches/0102-webp.patch b/debian/patches/0102-webp.patch
new file mode 100644
index 00000000..4d992c4e
--- /dev/null
+++ b/debian/patches/0102-webp.patch
@@ -0,0 +1,22 @@
+From: Jens Georg <m...@jensge.org>
+Date: Sat, 9 Feb 2019 16:43:15 +0100
+Subject: Fix an issue with the WEBP meta-data writer
+
+(cherry picked from commit 57ab1628883e3fde5bb3eafc0197b4e17354d2a6)
+---
+ src/photos/WebPSupport.vala | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/photos/WebPSupport.vala b/src/photos/WebPSupport.vala
+index 093f196..2f4723c 100644
+--- a/src/photos/WebPSupport.vala
++++ b/src/photos/WebPSupport.vala
+@@ -213,7 +213,7 @@ private class WebpReader : PhotoFileReader {
+ 
+ private class WebpMetadataWriter : PhotoFileMetadataWriter {
+     public WebpMetadataWriter(string filepath) {
+-        base (filepath, PhotoFileFormat.TIFF);
++        base (filepath, PhotoFileFormat.WEBP);
+     }
+ 
+     public override void write_metadata(PhotoMetadata metadata) throws Error {
diff --git a/debian/patches/series b/debian/patches/series
index 5c1f40f4..a55a5841 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1,4 @@
 0100-webp.patch
 0002-gphoto2-Add-missing-cheader-attributes-of-delegate-s.patch
+0101-webp.patch
+0102-webp.patch
-- 
2.39.2

From 52a5e208ff085a6ee5860e3ba329a0ad6f235e4b Mon Sep 17 00:00:00 2001
From: Jeremy Bicha <jeremy.bi...@canonical.com>
Date: Thu, 6 Apr 2023 09:59:55 -0400
Subject: [PATCH 2/3] Bump required libgevi2-dev to 0.12.0-2~, required for
 webp support

---
 debian/control | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/debian/control b/debian/control
index 2340c6f3..ac19f923 100644
--- a/debian/control
+++ b/debian/control
@@ -15,7 +15,7 @@ Build-Depends:
  libgcr-3-dev,
  libgdata-dev,
  libgee-0.8-dev (>= 0.10),
- libgexiv2-dev (>= 0.10.4),
+ libgexiv2-dev (>= 0.12.0-2~),
  libglib2.0-dev (>= 2.40),
  libgphoto2-dev (>= 2.5.4),
  libgstreamer-plugins-base1.0-dev (>= 1.0.0),
-- 
2.39.2

Reply via email to