Release cdecl99-1.1.
[homepage.git] / lib / imginfo.rb
1 # Nick's web site: imginfo filter.  Generate XML representation of image
2 # metadata which can be further processed into a web page.
3 #
4 # Copyright © 2020 Nick Bowler
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
18
19 class ImgInfoFilter < Nanoc::Filter
20     identifier :imginfo
21     type :binary => :text
22
23     require 'exifr/jpeg'
24     require 'fastimage'
25
26     def do_variant(xml, name, item = @item, rep: :default)
27         file = item.reps[rep].raw_path
28
29         w, h = FastImage.size(file)
30         sz = File.size(file)
31
32         xml.variant {
33             xml.name(name)
34             xml.uri(item_uri(item, rep: rep))
35             xml.width(w)
36             xml.height(h)
37             xml.filesize(human_filesize(sz))
38         }
39     end
40
41     def run(filename, params = {})
42         exif = EXIFR::JPEG.new(filename).to_hash
43
44         b = Nokogiri::XML::Builder.new do |xml|
45             xml.image {
46                 do_variant(xml, "Large", rep: :large)
47                 do_variant(xml, "Original")
48
49
50                 if @item[:description]
51                     xml.description(:xmlns => 'http://www.w3.org/1999/xhtml') {
52                         xml << @item[:description]
53                     }
54                 end
55
56                 xml.exif {
57                     exif.each do |key, value|
58                         # Convert some fields to more useful forms...
59                         case key
60                         when :f_number, :exposure_bias_value
61                             value = sprintf("%.1f", value)
62                         when :focal_length
63                             value = sprintf("%d\n", value)
64                         when :gps_version_id
65                             value = value.bytes.join(".")
66                         when :exposure_program
67                             case value
68                             when 1 then value = "Manual"
69                             when 2 then value = "Normal program"
70                             when 3 then value = "Aperture priority"
71                             when 4 then value = "Shutter priority"
72                             end
73                         when :metering_mode
74                             case value
75                             when 1 then value = "Average"
76                             when 2 then value = "Center weighted average"
77                             when 3 then value = "Spot"
78                             when 4 then value = "Multi-spot"
79                             when 5 then value = "Pattern"
80                             when 6 then vlaue = "Partial"
81                             end
82                         when :flash
83                             tmp = if value & 1 == 1 then "Yes" else "No" end
84                             case (value >> 3) & 3
85                             when 1, 2 then tmp += ", compulsory"
86                             when 3 then tmp += ", auto"
87                             end
88                             case (value >> 1) & 3
89                             when 2 then tmp += ", return light not detected"
90                             when 3 then tmp += ", return light detected"
91                             end
92                             value = tmp
93                         end
94
95                         case value
96                         when String
97                             value.delete!("\x00")
98                             value.strip!
99                         when Time
100                             # EXIF does not do timezones so don't display one
101                             value = value.strftime("%Y-%m-%d %H:%M:%S")
102                         end
103
104                         xml.send((key.to_s << "_").to_sym, value.to_s)
105                     end
106                 }
107             }
108         end
109         b.to_xml
110     end
111 end