+# Nick's web site: imginfo filter. Generate XML representation of image
+# metadata which can be further processed into a web page.
+#
+# Copyright © 2020 Nick Bowler
+#
+# 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 3 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 <https://www.gnu.org/licenses/>.
+
+class ImgInfoFilter < Nanoc::Filter
+ identifier :imginfo
+ type :binary => :text
+
+ require 'exifr/jpeg'
+ require 'fastimage'
+
+ def do_variant(xml, name, item = @item, rep: :default)
+ file = item.reps[rep].raw_path
+
+ w, h = FastImage.size(file)
+ sz = File.size(file)
+
+ xml.variant {
+ xml.name(name)
+ xml.uri(item_uri(item, rep: rep))
+ xml.width(w)
+ xml.height(h)
+ xml.filesize(human_filesize(sz))
+ }
+ end
+
+ def run(filename, params = {})
+ exif = EXIFR::JPEG.new(filename).to_hash
+
+ b = Nokogiri::XML::Builder.new do |xml|
+ xml.image {
+ do_variant(xml, "Large", rep: :large)
+ do_variant(xml, "Original")
+
+
+ if @item[:description]
+ xml.description(:xmlns => 'http://www.w3.org/1999/xhtml') {
+ xml << @item[:description]
+ }
+ end
+
+ xml.exif {
+ exif.each do |key, value|
+ # Convert some fields to more useful forms...
+ case key
+ when :f_number, :exposure_bias_value
+ value = sprintf("%.1f", value)
+ when :focal_length
+ value = sprintf("%d\n", value)
+ when :gps_version_id
+ value = value.bytes.join(".")
+ when :exposure_program
+ case value
+ when 1 then value = "Manual"
+ when 2 then value = "Normal program"
+ when 3 then value = "Aperture priority"
+ when 4 then value = "Shutter priority"
+ end
+ when :metering_mode
+ case value
+ when 1 then value = "Average"
+ when 2 then value = "Center weighted average"
+ when 3 then value = "Spot"
+ when 4 then value = "Multi-spot"
+ when 5 then value = "Pattern"
+ when 6 then vlaue = "Partial"
+ end
+ when :flash
+ tmp = if value & 1 == 1 then "Yes" else "No" end
+ case (value >> 3) & 3
+ when 1, 2 then tmp += ", compulsory"
+ when 3 then tmp += ", auto"
+ end
+ case (value >> 1) & 3
+ when 2 then tmp += ", return light not detected"
+ when 3 then tmp += ", return light detected"
+ end
+ value = tmp
+ end
+
+ case value
+ when String
+ value.delete!("\x00")
+ value.strip!
+ when Time
+ # EXIF does not do timezones so don't display one
+ value = value.strftime("%Y-%m-%d %H:%M:%S")
+ end
+
+ xml.send((key.to_s << "_").to_sym, value.to_s)
+ end
+ }
+ }
+ end
+ b.to_xml
+ end
+end