cul_image_props 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
|