summaryrefslogtreecommitdiff
path: root/src/photos/GdkSupport.vala
diff options
context:
space:
mode:
Diffstat (limited to 'src/photos/GdkSupport.vala')
-rw-r--r--src/photos/GdkSupport.vala129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/photos/GdkSupport.vala b/src/photos/GdkSupport.vala
new file mode 100644
index 0000000..4ca0893
--- /dev/null
+++ b/src/photos/GdkSupport.vala
@@ -0,0 +1,129 @@
+/* Copyright 2010-2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+public abstract class GdkReader : PhotoFileReader {
+ public GdkReader(string filepath, PhotoFileFormat file_format) {
+ base (filepath, file_format);
+ }
+
+ 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 {
+ return new Gdk.Pixbuf.from_file(get_filepath());
+ }
+
+ public override Gdk.Pixbuf scaled_read(Dimensions full, Dimensions scaled) throws Error {
+ return new Gdk.Pixbuf.from_file_at_scale(get_filepath(), scaled.width, scaled.height, false);
+ }
+}
+
+public abstract class GdkSniffer : PhotoFileSniffer {
+ private DetectedPhotoInformation detected = null;
+ private bool size_ready = false;
+ private bool area_prepared = false;
+
+ public GdkSniffer(File file, PhotoFileSniffer.Options options) {
+ base (file, options);
+ }
+
+ public override DetectedPhotoInformation? sniff() throws Error {
+ detected = new DetectedPhotoInformation();
+
+ Gdk.PixbufLoader pixbuf_loader = new Gdk.PixbufLoader();
+ pixbuf_loader.size_prepared.connect(on_size_prepared);
+ pixbuf_loader.area_prepared.connect(on_area_prepared);
+
+ // 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) {
+ uint8[]? flattened_sans_thumbnail = detected.metadata.flatten_exif(false);
+ if (flattened_sans_thumbnail != null && flattened_sans_thumbnail.length > 0)
+ detected.exif_md5 = md5_binary(flattened_sans_thumbnail, flattened_sans_thumbnail.length);
+
+ uint8[]? flattened_thumbnail = detected.metadata.flatten_exif_preview();
+ if (flattened_thumbnail != null && flattened_thumbnail.length > 0)
+ detected.thumbnail_md5 = md5_binary(flattened_thumbnail, flattened_thumbnail.length);
+ }
+
+ // 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);
+ for (;;) {
+ size_t bytes_read = fins.read(buffer, null);
+ if (bytes_read <= 0)
+ break;
+
+ count += bytes_read;
+
+ if (calc_md5)
+ md5_checksum.update(buffer, bytes_read);
+
+ // keep parsing the image until the size is discovered
+ if (!size_ready || !area_prepared)
+ pixbuf_loader.write(buffer[0:bytes_read]);
+
+ // if not searching for anything else, exit
+ if (!calc_md5 && size_ready && area_prepared)
+ break;
+ }
+
+ // PixbufLoader throws an error if you close it with an incomplete image, so trap this
+ try {
+ pixbuf_loader.close();
+ } catch (Error err) {
+ }
+
+ if (fins != null)
+ fins.close(null);
+
+ if (calc_md5)
+ detected.md5 = md5_checksum.get_string();
+
+ return detected;
+ }
+
+ private void on_size_prepared(Gdk.PixbufLoader loader, int width, int height) {
+ detected.image_dim = Dimensions(width, height);
+ size_ready = true;
+ }
+
+ private void on_area_prepared(Gdk.PixbufLoader pixbuf_loader) {
+ Gdk.Pixbuf? pixbuf = pixbuf_loader.get_pixbuf();
+ if (pixbuf == null)
+ return;
+
+ detected.colorspace = pixbuf.get_colorspace();
+ detected.channels = pixbuf.get_n_channels();
+ detected.bits_per_channel = pixbuf.get_bits_per_sample();
+
+ unowned Gdk.PixbufFormat format = pixbuf_loader.get_format();
+ detected.format_name = format.get_name();
+ detected.file_format = PhotoFileFormat.from_pixbuf_name(detected.format_name);
+
+ area_prepared = true;
+ }
+}
+