cul_image_props 0.3.2 → 0.3.3
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.
@@ -5,33 +5,45 @@ module Properties
|
|
5
5
|
module Exif
|
6
6
|
|
7
7
|
# Don't throw an exception when given an out of range character.
|
8
|
-
def self.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
seq.each_byte &filter
|
18
|
-
else # must be a byte array, right?
|
19
|
-
seq.each &filter
|
8
|
+
def self.ascii_bytes_to_filtered_string(seq)
|
9
|
+
if seq.is_a? String
|
10
|
+
seq = seq.unpack('C*')
|
11
|
+
end
|
12
|
+
str = ''
|
13
|
+
seq.each { |c|
|
14
|
+
# Screen out non-printing characters
|
15
|
+
unless c.is_a? Fixnum
|
16
|
+
raise "Expected an array of ASCII8BIT bytes, got an array value #{c.class}: #{field_type.inspect}"
|
20
17
|
end
|
21
|
-
|
22
|
-
|
23
|
-
return seq
|
18
|
+
if 32 <= c and c < 256
|
19
|
+
str += c.chr
|
24
20
|
end
|
25
|
-
|
21
|
+
}
|
22
|
+
return str
|
26
23
|
end
|
27
24
|
# Special version to deal with the code in the first 8 bytes of a user comment.
|
28
25
|
# First 8 bytes gives coding system e.g. ASCII vs. JIS vs Unicode
|
29
|
-
def self.
|
30
|
-
|
31
|
-
|
32
|
-
#
|
33
|
-
|
34
|
-
|
26
|
+
def self.filter_encoded_string(seq)
|
27
|
+
if seq.is_a? String
|
28
|
+
bytes = seq.unpack('C*')
|
29
|
+
else # array of bytes
|
30
|
+
bytes = seq
|
31
|
+
end
|
32
|
+
code = bytes[0, 8]
|
33
|
+
seq = bytes[8 ... bytes.length].pack('C*')
|
34
|
+
if code == TAG_ENCODING[:ASCII]
|
35
|
+
return ascii_bytes_to_filtered_string(bytes[8 ... bytes.length])
|
36
|
+
end
|
37
|
+
if code == TAG_ENCODING[:UNICODE]
|
38
|
+
seq = seq.force_encoding('utf-8') # I see some docs indicating UCS-2 here?
|
39
|
+
return seq.gsub(/\p{Cntrl}/,'').gsub(/\P{ASCII}/,'')
|
40
|
+
end
|
41
|
+
if code == TAG_ENCODING[:JIS]
|
42
|
+
# to be implemented
|
43
|
+
return "JIS String Value"
|
44
|
+
end
|
45
|
+
# Fall back to ASCII
|
46
|
+
return ascii_bytes_to_filtered_string(bytes[8 ... bytes.length])
|
35
47
|
end
|
36
48
|
|
37
49
|
# decode Olympus SpecialMode tag in MakerNote
|
@@ -106,6 +118,12 @@ def self.nikon_ev_bias(seq)
|
|
106
118
|
return ret_str
|
107
119
|
end
|
108
120
|
|
121
|
+
TAG_ENCODING = {
|
122
|
+
:ASCII => [0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00],
|
123
|
+
:JIS => [0x4A, 0x49, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00],
|
124
|
+
:UNICODE => [0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00],
|
125
|
+
:UNDEFINED => [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
|
126
|
+
}
|
109
127
|
|
110
128
|
# field type descriptions as (length, abbreviation, full name) tuples
|
111
129
|
FIELD_TYPES = [
|
@@ -181,7 +199,7 @@ EXIF_TAGS = {
|
|
181
199
|
0x011A => TagName.new('XResolution'),
|
182
200
|
0x011B => TagName.new('YResolution'),
|
183
201
|
0x011C => TagName.new('PlanarConfiguration'),
|
184
|
-
0x011D => TagName.new('PageName', self.method(:
|
202
|
+
0x011D => TagName.new('PageName', self.method(:ascii_bytes_to_filtered_string)),
|
185
203
|
0x0128 => TagName.new('ResolutionUnit',
|
186
204
|
{ 1 => 'Not Absolute',
|
187
205
|
2 => 'Pixels/Inch',
|
@@ -228,7 +246,7 @@ EXIF_TAGS = {
|
|
228
246
|
0x8825 => TagName.new('GPSInfo'),
|
229
247
|
0x8827 => TagName.new('ISOSpeedRatings'),
|
230
248
|
0x8828 => TagName.new('OECF'),
|
231
|
-
0x9000 => TagName.new('ExifVersion', self.method(:
|
249
|
+
0x9000 => TagName.new('ExifVersion', self.method(:ascii_bytes_to_filtered_string)),
|
232
250
|
0x9003 => TagName.new('DateTimeOriginal'),
|
233
251
|
0x9004 => TagName.new('DateTimeDigitized'),
|
234
252
|
0x9101 => TagName.new('ComponentsConfiguration',
|
@@ -289,7 +307,7 @@ EXIF_TAGS = {
|
|
289
307
|
0x920A => TagName.new('FocalLength'),
|
290
308
|
0x9214 => TagName.new('SubjectArea'),
|
291
309
|
0x927C => TagName.new('MakerNote'),
|
292
|
-
0x9286 => TagName.new('UserComment', self.method(:
|
310
|
+
0x9286 => TagName.new('UserComment', self.method(:filter_encoded_string)),
|
293
311
|
0x9290 => TagName.new('SubSecTime'),
|
294
312
|
0x9291 => TagName.new('SubSecTimeOriginal'),
|
295
313
|
0x9292 => TagName.new('SubSecTimeDigitized'),
|
@@ -301,7 +319,7 @@ EXIF_TAGS = {
|
|
301
319
|
0x9C9E => TagName.new('XPKeywords'),
|
302
320
|
0x9C9F => TagName.new('XPSubject'),
|
303
321
|
|
304
|
-
0xA000 => TagName.new('FlashPixVersion', self.method(:
|
322
|
+
0xA000 => TagName.new('FlashPixVersion', self.method(:ascii_bytes_to_filtered_string)),
|
305
323
|
0xA001 => TagName.new('ColorSpace',
|
306
324
|
{1 => 'sRGB',
|
307
325
|
2 => 'Adobe RGB',
|
@@ -409,7 +427,7 @@ MAKERNOTE_OLYMPUS_TAGS = {
|
|
409
427
|
0x0206 => TagName.new('LensDistortionParams'),
|
410
428
|
0x0207 => TagName.new('SoftwareRelease'),
|
411
429
|
0x0208 => TagName.new('PictureInfo'),
|
412
|
-
0x0209 => TagName.new('CameraID', self.method(:
|
430
|
+
0x0209 => TagName.new('CameraID', self.method(:ascii_bytes_to_filtered_string)), # print as string
|
413
431
|
0x0F00 => TagName.new('DataDump'),
|
414
432
|
0x0300 => TagName.new('PreCaptureFrames'),
|
415
433
|
0x0404 => TagName.new('SerialNumber'),
|
@@ -683,7 +701,7 @@ MAKERNOTE_CASIO_TAGS={
|
|
683
701
|
}
|
684
702
|
|
685
703
|
MAKERNOTE_FUJIFILM_TAGS={
|
686
|
-
0x0000 => TagName.new('NoteVersion', self.method(:
|
704
|
+
0x0000 => TagName.new('NoteVersion', self.method(:ascii_bytes_to_filtered_string)),
|
687
705
|
0x1000 => TagName.new('Quality'),
|
688
706
|
0x1001 => TagName.new('Sharpness',
|
689
707
|
{1 => 'Soft',
|
@@ -897,8 +915,8 @@ MAKERNOTE_CANON_TAG_0x004 = {
|
|
897
915
|
|
898
916
|
# Nikon E99x MakerNote Tags
|
899
917
|
MAKERNOTE_NIKON_NEWER_TAGS={
|
900
|
-
0x0001 => TagName.new('MakernoteVersion', self.method(:
|
901
|
-
0x0002 => TagName.new('ISOSetting', self.method(:
|
918
|
+
0x0001 => TagName.new('MakernoteVersion', self.method(:ascii_bytes_to_filtered_string)), # Sometimes binary
|
919
|
+
0x0002 => TagName.new('ISOSetting', self.method(:ascii_bytes_to_filtered_string)),
|
902
920
|
0x0003 => TagName.new('ColorMode'),
|
903
921
|
0x0004 => TagName.new('Quality'),
|
904
922
|
0x0005 => TagName.new('Whitebalance'),
|
@@ -127,7 +127,7 @@ class EXIF_header
|
|
127
127
|
x = 0
|
128
128
|
l = src.length
|
129
129
|
if l == 1
|
130
|
-
return src[0]
|
130
|
+
return src.unpack('C')[0]
|
131
131
|
elsif l == 2
|
132
132
|
return src.unpack('n')[0]
|
133
133
|
elsif l == 4
|
@@ -284,10 +284,10 @@ class EXIF_header
|
|
284
284
|
# sometimes gets too big to fit in int value
|
285
285
|
if count != 0 and count < (2**31)
|
286
286
|
@file.seek(@offset + field_offset)
|
287
|
-
values = @file.read(count)
|
287
|
+
values = @file.read(count) # ascii string of count bytes
|
288
288
|
#print values
|
289
289
|
# Drop any garbage after a null.
|
290
|
-
values = values.split(X00, 1)[0]
|
290
|
+
values = values.split(X00, 1)[0] # a null-terminated string
|
291
291
|
else
|
292
292
|
values = ''
|
293
293
|
end
|
@@ -311,29 +311,33 @@ class EXIF_header
|
|
311
311
|
}
|
312
312
|
end
|
313
313
|
end
|
314
|
+
|
314
315
|
# now 'values' is either a string or an array
|
315
|
-
if count == 1 and field_type != 2
|
316
|
-
printable=values[0].to_s
|
317
|
-
elsif count > 50 and values.length > 20
|
318
|
-
printable= (field_type == 2) ? (values[0...20] + '...') : ("[" + values[0...20].join(',') + ", ... ]")
|
319
|
-
else
|
320
|
-
printable=values.inspect
|
321
|
-
end
|
322
316
|
# compute printable version of values
|
323
317
|
if tag_entry
|
324
318
|
if tag_entry.value
|
325
319
|
# optional 2nd tag element is present
|
326
320
|
if tag_entry.value.respond_to? :call
|
327
321
|
# call mapping function
|
322
|
+
puts "tag_name: #{tag_name}"
|
323
|
+
puts "field_type: #{field_type}"
|
324
|
+
puts "count: #{count}"
|
328
325
|
printable = tag_entry.value.call(values)
|
326
|
+
puts "printable: #{printable}"
|
329
327
|
else
|
330
328
|
printable = ''
|
331
329
|
values.each { |i|
|
332
330
|
# use lookup table for this tag
|
333
|
-
printable += (tag_entry.value.include? i)?tag_entry.value[i] : i.inspect
|
331
|
+
printable += (tag_entry.value.include? i) ? tag_entry.value[i] : i.inspect
|
334
332
|
}
|
335
333
|
end
|
336
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
|
337
341
|
end
|
338
342
|
self.tags[ifd_name + ' ' + tag_name] = IFD_Tag.new(printable, tag_id,
|
339
343
|
field_type,
|
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.3
|
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-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -101,7 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
101
101
|
requirements:
|
102
102
|
- - ! '>='
|
103
103
|
- !ruby/object:Gem::Version
|
104
|
-
version:
|
104
|
+
version: 1.9.3
|
105
105
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
106
|
none: false
|
107
107
|
requirements:
|