cul_image_props 0.3.3 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
@@ -26,19 +26,39 @@ end
|
|
26
26
|
|
27
27
|
# first element of tuple is tag name, optional second element is
|
28
28
|
# another dictionary giving names to values
|
29
|
-
class
|
29
|
+
class TagEntry
|
30
30
|
attr_accessor :name, :value
|
31
31
|
def initialize(name, value=false)
|
32
32
|
@name = name
|
33
33
|
@value = value
|
34
34
|
end
|
35
|
+
|
36
|
+
def translates?
|
37
|
+
return (not ( @value.nil? or @value == false ))
|
38
|
+
end
|
39
|
+
|
40
|
+
def translate(values)
|
41
|
+
if @value
|
42
|
+
if @value.respond_to? :call
|
43
|
+
# value was a proc
|
44
|
+
@value.call(values)
|
45
|
+
else
|
46
|
+
# value was a dictionary
|
47
|
+
trans = ''
|
48
|
+
values.each {|i| trans += (@value.include? i) ? @value[i] : i.inspect }
|
49
|
+
trans
|
50
|
+
end
|
51
|
+
else
|
52
|
+
values.inspect
|
53
|
+
end
|
54
|
+
end
|
35
55
|
end
|
36
56
|
|
37
57
|
class Ratio
|
38
58
|
# ratio object that eventually will be able to reduce itself to lowest
|
39
59
|
# common denominator for printing
|
40
60
|
attr_accessor :num, :den
|
41
|
-
def gcd(a, b)
|
61
|
+
def self.gcd(a, b)
|
42
62
|
if b == 1 or a == 1
|
43
63
|
return 1
|
44
64
|
elsif b == 0
|
@@ -62,7 +82,7 @@ class Ratio
|
|
62
82
|
end
|
63
83
|
|
64
84
|
def reduce
|
65
|
-
div = gcd(@num, @den)
|
85
|
+
div = Ratio.gcd(@num, @den)
|
66
86
|
if div > 1
|
67
87
|
@num = @num / div
|
68
88
|
@den = @den / div
|
@@ -72,36 +92,52 @@ end
|
|
72
92
|
|
73
93
|
# for ease of dealing with tags
|
74
94
|
class IFD_Tag
|
75
|
-
attr_accessor :
|
76
|
-
def initialize(
|
77
|
-
# printable version of data
|
78
|
-
@printable = printable
|
95
|
+
attr_accessor :tag, :field_type, :values, :field_offset, :field_length
|
96
|
+
def initialize( tag_id, field_type, tag_entry, values, field_offset, count)
|
79
97
|
# tag ID number
|
80
|
-
@tag =
|
98
|
+
@tag = tag_id
|
81
99
|
# field type as index into FIELD_TYPES
|
82
100
|
@field_type = field_type
|
101
|
+
# the TagEntry looked up for this tag_id
|
102
|
+
@tag_entry = tag_entry
|
83
103
|
# offset of start of field in bytes from beginning of IFD
|
84
104
|
@field_offset = field_offset
|
85
105
|
# length of data field in bytes
|
86
|
-
@
|
106
|
+
@count = count
|
107
|
+
typelen = FIELD_TYPES[@field_type].length
|
108
|
+
@field_length = count * typelen
|
87
109
|
# either a string or array of data items
|
88
110
|
@values = values
|
89
111
|
end
|
90
112
|
|
113
|
+
def printable
|
114
|
+
@printable ||= begin
|
115
|
+
if @tag_entry.translates?
|
116
|
+
@tag_entry.translate @values
|
117
|
+
elsif @count == 1 and @field_type != 2
|
118
|
+
@values[0].to_s
|
119
|
+
elsif @count > 50 and @values.length > 20
|
120
|
+
(field_type == 2) ? (@values[0...20] + '...') : ("[" + @values[0...20].join(',') + ", ... ]")
|
121
|
+
else
|
122
|
+
@values.inspect
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
91
127
|
def to_s
|
92
|
-
|
128
|
+
printable
|
93
129
|
end
|
94
130
|
|
95
131
|
def inspect
|
96
132
|
begin
|
97
133
|
s= format("(0x%04X) %s=%s @ %d", @tag,
|
98
|
-
FIELD_TYPES[@field_type]
|
99
|
-
|
134
|
+
FIELD_TYPES[@field_type].name,
|
135
|
+
printable,
|
100
136
|
@field_offset)
|
101
137
|
rescue
|
102
138
|
s= format("(%s) %s=%s @ %s", @tag.to_s,
|
103
|
-
FIELD_TYPES[@field_type]
|
104
|
-
|
139
|
+
FIELD_TYPES[@field_type].name,
|
140
|
+
printable,
|
105
141
|
@field_offset.to_s)
|
106
142
|
end
|
107
143
|
return s
|
@@ -123,39 +159,39 @@ class EXIF_header
|
|
123
159
|
end
|
124
160
|
|
125
161
|
# extract multibyte integer in Motorola format (big/network endian)
|
126
|
-
def s2n_motorola(src)
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
162
|
+
def self.s2n_motorola(src)
|
163
|
+
x = 0
|
164
|
+
l = src.bytesize
|
165
|
+
if l == 1
|
166
|
+
return src.unpack('C')[0]
|
167
|
+
elsif l == 2
|
168
|
+
return src.unpack('n')[0]
|
169
|
+
elsif l == 4
|
170
|
+
return src.unpack('N')[0]
|
171
|
+
else
|
172
|
+
raise "Unexpected packed Fixnum length: " + l.to_s
|
173
|
+
end
|
138
174
|
end
|
139
175
|
# extract multibyte integer in Intel format (little endian)
|
140
|
-
def s2n_intel(src)
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
end
|
176
|
+
def self.s2n_intel(src)
|
177
|
+
x = 0
|
178
|
+
l = src.bytesize
|
179
|
+
if l == 1
|
180
|
+
return src.unpack('C')[0]
|
181
|
+
elsif l == 2
|
182
|
+
return src.unpack('v')[0]
|
183
|
+
elsif l == 4
|
184
|
+
return src.unpack('V')[0]
|
185
|
+
else
|
186
|
+
raise "Unexpected packed Fixnum length: " + l.to_s
|
152
187
|
end
|
188
|
+
end
|
153
189
|
|
154
190
|
def unpack_number(src, signed=false)
|
155
191
|
if @endian == 'I'
|
156
|
-
val=s2n_intel(src)
|
192
|
+
val = EXIF_header.s2n_intel(src)
|
157
193
|
else
|
158
|
-
val=s2n_motorola(src)
|
194
|
+
val = EXIF_header.s2n_motorola(src)
|
159
195
|
end
|
160
196
|
# Sign extension ?
|
161
197
|
if signed
|
@@ -239,12 +275,7 @@ class EXIF_header
|
|
239
275
|
tag_id = unpack_number(@file.read(2))
|
240
276
|
|
241
277
|
# get tag name early to avoid errors, help debug
|
242
|
-
tag_entry = dict[tag_id]
|
243
|
-
if tag_entry
|
244
|
-
tag_name = tag_entry.name
|
245
|
-
else
|
246
|
-
tag_name = 'Tag 0x%04X' % tag_id
|
247
|
-
end
|
278
|
+
tag_entry = dict[tag_id] || TagEntry.new('Tag 0x%04X' % tag_id)
|
248
279
|
|
249
280
|
# ignore certain tags for faster processing
|
250
281
|
if not (not @detail and IGNORE_TAGS.include? tag_id)
|
@@ -261,7 +292,7 @@ class EXIF_header
|
|
261
292
|
raise format("unknown type %d in tag 0x%04X", field_type, tag)
|
262
293
|
end
|
263
294
|
end
|
264
|
-
typelen = FIELD_TYPES[field_type]
|
295
|
+
typelen = FIELD_TYPES[field_type].length
|
265
296
|
count = unpack_number(@file.read(4))
|
266
297
|
|
267
298
|
# If the value exceeds 4 bytes, it is a pointer to values.
|
@@ -297,7 +328,7 @@ class EXIF_header
|
|
297
328
|
|
298
329
|
# @todo investigate
|
299
330
|
# some entries get too big to handle could be malformed file
|
300
|
-
if count < 1000 or
|
331
|
+
if count < 1000 or tag_entry.name == 'MakerNote'
|
301
332
|
@file.seek(@offset + field_offset)
|
302
333
|
count.times {
|
303
334
|
if field_type == 5 or field_type == 10
|
@@ -312,39 +343,12 @@ class EXIF_header
|
|
312
343
|
end
|
313
344
|
end
|
314
345
|
|
315
|
-
|
316
|
-
|
317
|
-
if tag_entry
|
318
|
-
if tag_entry.value
|
319
|
-
# optional 2nd tag element is present
|
320
|
-
if tag_entry.value.respond_to? :call
|
321
|
-
# call mapping function
|
322
|
-
puts "tag_name: #{tag_name}"
|
323
|
-
puts "field_type: #{field_type}"
|
324
|
-
puts "count: #{count}"
|
325
|
-
printable = tag_entry.value.call(values)
|
326
|
-
puts "printable: #{printable}"
|
327
|
-
else
|
328
|
-
printable = ''
|
329
|
-
values.each { |i|
|
330
|
-
# use lookup table for this tag
|
331
|
-
printable += (tag_entry.value.include? i) ? tag_entry.value[i] : i.inspect
|
332
|
-
}
|
333
|
-
end
|
334
|
-
end
|
335
|
-
elsif count == 1 and field_type != 2
|
336
|
-
printable=values[0].to_s
|
337
|
-
elsif count > 50 and values.length > 20
|
338
|
-
printable= (field_type == 2) ? (values[0...20] + '...') : ("[" + values[0...20].join(',') + ", ... ]")
|
339
|
-
else
|
340
|
-
printable=values.inspect
|
341
|
-
end
|
342
|
-
self.tags[ifd_name + ' ' + tag_name] = IFD_Tag.new(printable, tag_id,
|
343
|
-
field_type,
|
346
|
+
self.tags[ifd_name + ' ' + tag_entry.name] = IFD_Tag.new(tag_id,
|
347
|
+
field_type, tag_entry,
|
344
348
|
values, field_offset,
|
345
|
-
count
|
349
|
+
count)
|
346
350
|
end
|
347
|
-
if
|
351
|
+
if tag_entry.name == stop_tag
|
348
352
|
break
|
349
353
|
end
|
350
354
|
}
|
@@ -370,7 +374,7 @@ class EXIF_header
|
|
370
374
|
entry = thumb_ifd + 2 + 12 * i
|
371
375
|
tag = self.s2n(entry, 2)
|
372
376
|
field_type = self.s2n(entry+2, 2)
|
373
|
-
typelen = FIELD_TYPES[field_type]
|
377
|
+
typelen = FIELD_TYPES[field_type].length
|
374
378
|
count = self.s2n(entry+4, 4)
|
375
379
|
oldoff = self.s2n(entry+8, 4)
|
376
380
|
# start of the 4-byte pointer area in entry
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cul_image_props
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|