[shotwell/wip/webp: 30/30] wip: Actually decode WebP
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [shotwell/wip/webp: 30/30] wip: Actually decode WebP
- Date: Wed, 28 Mar 2018 18:08:28 +0000 (UTC)
commit 3bba3dbf3ef5b923a2d9ed13b642ed119b8d8652
Author: Jens Georg <mail jensge org>
Date: Thu Aug 31 22:25:49 2017 +0200
wip: Actually decode WebP
meson.build | 3 +
src/meson.build | 2 +-
src/photos/WebPSupport.vala | 86 +++++++++++++++++++++++++++++++++++++++----
vapi/libwebp.vapi | 5 ++
vapi/libwebpdemux.vapi | 43 +++++++++++++++++++++
5 files changed, 130 insertions(+), 9 deletions(-)
---
diff --git a/meson.build b/meson.build
index 072ad0a..448dfe2 100644
--- a/meson.build
+++ b/meson.build
@@ -57,6 +57,9 @@ libraw = dependency('libraw', version : '>= 0.13.2')
libexif = dependency('libexif', version : '>= 0.6.16')
unity = dependency('unity', required : false)
+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 dea0273..62d3866 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -19,7 +19,7 @@ processor = executable('shotwell-graphics-processor',
shotwell_deps = [gio, gee, sqlite, gtk, sqlite, posix, gphoto2,
gstreamer_pbu, gio_unix, gudev, gexiv2, gmodule,
- libraw, libexif, sw_plugin]
+ libraw, libexif, sw_plugin, webpdemux, webp]
if unity_available
shotwell_deps += [unity]
endif
diff --git a/src/photos/WebPSupport.vala b/src/photos/WebPSupport.vala
index 22eeaeb..abaa01d 100644
--- a/src/photos/WebPSupport.vala
+++ b/src/photos/WebPSupport.vala
@@ -101,8 +101,11 @@ private class WebpFileFormatProperties : PhotoFileFormatProperties {
}
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 {
@@ -112,14 +115,74 @@ private class WebpSniffer : PhotoFileSniffer {
if (!is_webp(file))
return null;
- var info = new DetectedPhotoInformation();
- info.file_format = PhotoFileFormat.WEBP;
- info.format_name = "WebP";
- info.channels = 4;
- info.bits_per_channel = 8;
- info.image_dim = new Dimensions(32, 32);
-
- return info;
+ // 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) {
+ // 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.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();
+
+ // if size and area are not ready, treat as corrupted file (entire file was read)
+ is_corrupted = false; //!size_ready || !area_prepared;
+
+ return detected;
}
}
@@ -136,7 +199,14 @@ private class WebpReader : PhotoFileReader {
}
public override Gdk.Pixbuf unscaled_read() throws Error {
- return new Gdk.Pixbuf(Gdk.Colorspace.RGB, true, 8, 32, 32);
+ 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);
}
}
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);
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]