diff options
Diffstat (limited to 'debian/patches/0110-webp_part2.patch')
| -rw-r--r-- | debian/patches/0110-webp_part2.patch | 425 | 
1 files changed, 425 insertions, 0 deletions
diff --git a/debian/patches/0110-webp_part2.patch b/debian/patches/0110-webp_part2.patch new file mode 100644 index 0000000..175c08d --- /dev/null +++ b/debian/patches/0110-webp_part2.patch @@ -0,0 +1,425 @@ +From: Jens Georg <mail@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); ++    } ++}  | 
