iptc 0.0.2
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.
- data/LICENSE +5 -0
- data/README.md +11 -0
- data/lib/iptc.rb +3 -0
- data/lib/iptc/jpeg/image.rb +100 -0
- data/lib/iptc/jpeg/marker.rb +97 -0
- data/lib/iptc/jpeg/marker_headers.rb +67 -0
- data/lib/iptc/jpeg/markers.rb +190 -0
- data/lib/iptc/marker.rb +18 -0
- data/lib/iptc/marker_nomenclature.rb +49 -0
- data/lib/iptc/multiple_hash.rb +54 -0
- data/lib/iptc/version.rb +3 -0
- metadata +79 -0
data/LICENSE
ADDED
data/README.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Ruby IPTC metadata parser
|
2
|
+
|
3
|
+
This library can be used to read the metadata of a jpeg file.
|
4
|
+
|
5
|
+
It reads the IPTC informations embedded and allows to access this information
|
6
|
+
Read IPTC::JPEG::Image for more information.
|
7
|
+
|
8
|
+
The IPTC library parses the APP13 JPEG Tag and generates a hash of properties for a given file.
|
9
|
+
|
10
|
+
Original code from http://raa.ruby-lang.org/project/jpeg-jfif-iptc/
|
11
|
+
Gemified, reorganized and modified in 2010 by Jens Kraemer.
|
data/lib/iptc.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
require 'iptc/multiple_hash'
|
4
|
+
require 'iptc/jpeg/marker_headers'
|
5
|
+
|
6
|
+
module IPTC
|
7
|
+
module JPEG
|
8
|
+
class Image
|
9
|
+
attr_reader :values
|
10
|
+
# creates a JPEG image from a file and does a "quick" load (Only the metadata
|
11
|
+
# are loaded, not the whole file).
|
12
|
+
def initialize filename, quick=true
|
13
|
+
@logger = Logger.new(STDOUT)
|
14
|
+
@logger.datetime_format = "%H:%M:%S"
|
15
|
+
@logger.level = $DEBUG?(Logger::DEBUG):(Logger::INFO)
|
16
|
+
|
17
|
+
@filename = filename
|
18
|
+
@position = 0
|
19
|
+
@content = File.open(@filename).binmode.read
|
20
|
+
|
21
|
+
|
22
|
+
if MARKERS[read(2)]!="SOI"
|
23
|
+
raise NotJPEGFileException.new("Not a JPEG file: #{@filename}")
|
24
|
+
end
|
25
|
+
|
26
|
+
@markers = Array.new()
|
27
|
+
|
28
|
+
begin
|
29
|
+
|
30
|
+
catch(:end_of_metadata) do
|
31
|
+
while true
|
32
|
+
@markers << read_marker
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
rescue Exception=>e
|
37
|
+
@logger.info "Exception in file #{@filename}:\n"+e.to_s
|
38
|
+
raise e
|
39
|
+
end
|
40
|
+
# Markers all read
|
41
|
+
# move back
|
42
|
+
seek(-2)
|
43
|
+
|
44
|
+
# in full mode, read the rest
|
45
|
+
if !quick
|
46
|
+
@data = read_rest
|
47
|
+
end
|
48
|
+
|
49
|
+
@values = MultipleHash.new
|
50
|
+
|
51
|
+
@markers.each do |marker|
|
52
|
+
# puts "processing marker: #{marker.inspect}"
|
53
|
+
marker.parse
|
54
|
+
# puts marker.valid?
|
55
|
+
@values.add(marker, marker.values)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def read(count)
|
60
|
+
@position += count
|
61
|
+
return @content[@position-count...@position]
|
62
|
+
end
|
63
|
+
def seek(count)
|
64
|
+
@position += count
|
65
|
+
end
|
66
|
+
|
67
|
+
def l message
|
68
|
+
@logger.debug message
|
69
|
+
end
|
70
|
+
|
71
|
+
# write the image to the disk
|
72
|
+
def write filename
|
73
|
+
f = File.open(filename,"wb+")
|
74
|
+
f.print "\xFF\xD8"
|
75
|
+
|
76
|
+
@markers.each do |marker|
|
77
|
+
f.print marker.to_binary
|
78
|
+
end
|
79
|
+
f.print @data.to_binary
|
80
|
+
f.close
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
def read_marker
|
85
|
+
type = read(2)
|
86
|
+
# finished reading all the metadata
|
87
|
+
throw :end_of_metadata if MARKERS[type]=='SOS'
|
88
|
+
size = read(2)
|
89
|
+
data = read(size.unpack('n')[0]-2)
|
90
|
+
|
91
|
+
return Marker.NewMarker(MARKERS[type], type+size+data, @logger)
|
92
|
+
end
|
93
|
+
def read_rest
|
94
|
+
rest = @content[@position..-1]
|
95
|
+
return Marker.new("BIN",rest)
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module IPTC
|
4
|
+
module JPEG
|
5
|
+
# == Marker
|
6
|
+
# A Jpeg marker, generic class used by all others markers
|
7
|
+
class Marker
|
8
|
+
attr_reader :prefix
|
9
|
+
attr_reader :values
|
10
|
+
|
11
|
+
@@missing = []
|
12
|
+
|
13
|
+
# The NewMarker constructor method.
|
14
|
+
# Inspect the object space in order to find something usable later
|
15
|
+
def Marker.NewMarker(type,data, logger)
|
16
|
+
marker_class = "#{type}Marker"
|
17
|
+
if JPEG::Markers.constants.include?(marker_class.to_sym)
|
18
|
+
return JPEG::Markers.const_get(marker_class).new(type, data)
|
19
|
+
else
|
20
|
+
if !@@missing.include?(type)
|
21
|
+
logger.debug "Marker #{type+"Marker"} not found." if logger!=nil
|
22
|
+
@@missing << type
|
23
|
+
end
|
24
|
+
end
|
25
|
+
return Marker.new(type,data)
|
26
|
+
end
|
27
|
+
|
28
|
+
def l message
|
29
|
+
@logger.debug message
|
30
|
+
end
|
31
|
+
|
32
|
+
# binary serialization
|
33
|
+
# transform the marker to its final form
|
34
|
+
def to_binary data=nil
|
35
|
+
if data!=nil
|
36
|
+
return @type+[data.length+2].pack('n')+data
|
37
|
+
else
|
38
|
+
return @original_content
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize(type,data)
|
43
|
+
@logger = Logger.new(STDOUT)
|
44
|
+
@logger.datetime_format = "%H:%M:%S"
|
45
|
+
@logger.level = $DEBUG?(Logger::DEBUG):(Logger::INFO)
|
46
|
+
|
47
|
+
@original_content = data
|
48
|
+
|
49
|
+
@content = StringIO.new(data)
|
50
|
+
@type = @content.read(2)
|
51
|
+
@size = @content.read(2).unpack('n')[0]-2
|
52
|
+
|
53
|
+
if !valid?
|
54
|
+
raise InvalidBlockException.new("In block #{self.class}: invalid marker\n#{@content.read(20)}")
|
55
|
+
end
|
56
|
+
|
57
|
+
@prefix = self.class.to_s
|
58
|
+
|
59
|
+
@prefix = @prefix[@prefix.rindex("::")+2..-7]
|
60
|
+
if @prefix==""
|
61
|
+
@prefix= 'Marker'
|
62
|
+
end
|
63
|
+
|
64
|
+
@values = Hash.new
|
65
|
+
end
|
66
|
+
def read count
|
67
|
+
return @content.read(count)
|
68
|
+
end
|
69
|
+
def valid?
|
70
|
+
return true
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
# parse the data
|
75
|
+
def parse
|
76
|
+
return []
|
77
|
+
end
|
78
|
+
|
79
|
+
# returns the available properties for the given tag
|
80
|
+
def properties
|
81
|
+
return []
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# This is not a JPEG file.
|
86
|
+
class NotJPEGFileException < Exception; end
|
87
|
+
|
88
|
+
# The end of the metadata has occured too early
|
89
|
+
class EndOfMetaDataException < Exception; end
|
90
|
+
|
91
|
+
# The block is invalide
|
92
|
+
class InvalidBlockException < Exception; end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module IPTC
|
2
|
+
module JPEG
|
3
|
+
MARKERS = {
|
4
|
+
"\xFF\xD8" => 'SOI',
|
5
|
+
"\xFF\xc0" => 'SOF0',
|
6
|
+
"\xFF\xc1" => 'SOF1',
|
7
|
+
"\xFF\xc2" => 'SOF2',
|
8
|
+
"\xFF\xc3" => 'SOF3',
|
9
|
+
|
10
|
+
"\xFF\xc5" => 'SOF5',
|
11
|
+
"\xFF\xc6" => 'SOF6',
|
12
|
+
"\xFF\xc7" => 'SOF7',
|
13
|
+
|
14
|
+
"\xFF\xc8" => 'JPG',
|
15
|
+
"\xFF\xc9" => 'SOF9',
|
16
|
+
"\xFF\xca" => 'SOF10',
|
17
|
+
"\xFF\xcb" => 'SOF11',
|
18
|
+
|
19
|
+
"\xFF\xcd" => 'SOF13',
|
20
|
+
"\xFF\xce" => 'SOF14',
|
21
|
+
"\xFF\xcf" => 'SOF15',
|
22
|
+
|
23
|
+
"\xFF\xc4" => 'DHT',
|
24
|
+
|
25
|
+
"\xFF\xcc" => 'DAC',
|
26
|
+
|
27
|
+
"\xFF\xd0" => 'RST0',
|
28
|
+
"\xFF\xd1" => 'RST1',
|
29
|
+
"\xFF\xd2" => 'RST2',
|
30
|
+
"\xFF\xd3" => 'RST3',
|
31
|
+
"\xFF\xd4" => 'RST4',
|
32
|
+
"\xFF\xd5" => 'RST5',
|
33
|
+
"\xFF\xd6" => 'RST6',
|
34
|
+
"\xFF\xd7" => 'RST7',
|
35
|
+
|
36
|
+
"\xFF\xd8" => 'SOI',
|
37
|
+
"\xFF\xd9" => 'EOI',
|
38
|
+
"\xFF\xda" => 'SOS',
|
39
|
+
"\xFF\xdb" => 'DQT',
|
40
|
+
"\xFF\xdc" => 'DNL',
|
41
|
+
"\xFF\xdd" => 'DRI',
|
42
|
+
"\xFF\xde" => 'DHP',
|
43
|
+
"\xFF\xdf" => 'EXP',
|
44
|
+
|
45
|
+
"\xFF\xe0" => 'APP0',
|
46
|
+
"\xFF\xe1" => 'APP1',
|
47
|
+
"\xFF\xe2" => 'APP2',
|
48
|
+
"\xFF\xe3" => 'APP3',
|
49
|
+
"\xFF\xe4" => 'APP4',
|
50
|
+
"\xFF\xe5" => 'APP5',
|
51
|
+
"\xFF\xe6" => 'APP6',
|
52
|
+
"\xFF\xe7" => 'APP7',
|
53
|
+
"\xFF\xe8" => 'APP8',
|
54
|
+
"\xFF\xe9" => 'APP9',
|
55
|
+
"\xFF\xea" => 'APP10',
|
56
|
+
"\xFF\xeb" => 'APP11',
|
57
|
+
"\xFF\xec" => 'APP12',
|
58
|
+
"\xFF\xed" => 'APP13',
|
59
|
+
"\xFF\xee" => 'APP14',
|
60
|
+
"\xFF\xef" => 'APP15',
|
61
|
+
"\xFF\xf0" => 'JPG0',
|
62
|
+
"\xFF\xfd" => 'JPG13',
|
63
|
+
"\xFF\xfe" => 'COM',
|
64
|
+
"\xFF\x01" => 'TEM'
|
65
|
+
}
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
require 'iptc/marker'
|
4
|
+
require 'iptc/marker_nomenclature'
|
5
|
+
require 'iptc/jpeg/marker'
|
6
|
+
|
7
|
+
module IPTC
|
8
|
+
|
9
|
+
module JPEG
|
10
|
+
# == Markers
|
11
|
+
# All the known JPEG markers
|
12
|
+
module Markers
|
13
|
+
# == SOIMarker
|
14
|
+
# The Start Of Image Marker
|
15
|
+
class SOIMarker < Marker
|
16
|
+
def valid?
|
17
|
+
return read(5)=="JFIF\0"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
# == APP1Marker
|
21
|
+
# The APP1 Marker, Exif container
|
22
|
+
class APP1Marker < Marker
|
23
|
+
def valid?
|
24
|
+
xap = 'http://ns.adobe.com/xap/1.0/'
|
25
|
+
header = read(xap.size)
|
26
|
+
return header == xap || header.start_with?("Exif\0\0")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
# == COMMarker
|
30
|
+
# The COM Marker, contains comments
|
31
|
+
class COMMarker < Marker
|
32
|
+
attr_reader :content
|
33
|
+
def parse
|
34
|
+
l "COM Marker Parsed"
|
35
|
+
@content = read(@size)
|
36
|
+
@dirty = false
|
37
|
+
|
38
|
+
@values['COM/COM']=@content
|
39
|
+
end
|
40
|
+
# def []=(key,value)
|
41
|
+
# if @content != value
|
42
|
+
# @content = value
|
43
|
+
# @dirty = true
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
def [](item)
|
47
|
+
return @content
|
48
|
+
end
|
49
|
+
end
|
50
|
+
# == The APP13Marker
|
51
|
+
# The APP13 marker, know as the IPTC Marker
|
52
|
+
# See also the IPTC::MarkerNomenclature.
|
53
|
+
class APP13Marker < Marker
|
54
|
+
def initialize(type, data)
|
55
|
+
@header = "Photoshop 3.0\0008BIM"
|
56
|
+
|
57
|
+
super(type, data)
|
58
|
+
@prefix = "iptc"
|
59
|
+
|
60
|
+
end
|
61
|
+
def valid?
|
62
|
+
return read(@header.length)==@header
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse
|
66
|
+
l "APP13 marker parsed"
|
67
|
+
@markers = Array.new
|
68
|
+
|
69
|
+
|
70
|
+
@bim_type = read(2)
|
71
|
+
@bim_dummy = read(4)
|
72
|
+
size = read(2)
|
73
|
+
|
74
|
+
content = StringIO.new(read(size.unpack('n')[0]))
|
75
|
+
|
76
|
+
while !content.eof?
|
77
|
+
|
78
|
+
header = content.read(2)
|
79
|
+
|
80
|
+
# http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
|
81
|
+
case header
|
82
|
+
when "\x1c\x01"
|
83
|
+
# skip the envelope
|
84
|
+
while !content.eof?
|
85
|
+
if content.read(1) == "\x1c"
|
86
|
+
content.pos = content.pos - 1
|
87
|
+
break
|
88
|
+
end
|
89
|
+
end
|
90
|
+
when "\x1c\x02"
|
91
|
+
|
92
|
+
type = content.read(1).unpack('c')[0]
|
93
|
+
size = content.read(2)
|
94
|
+
value = content.read(size.unpack('n')[0])
|
95
|
+
|
96
|
+
l "Found marker #{type}"
|
97
|
+
marker = IPTC::Marker.new(type, value)
|
98
|
+
@values[@prefix+"/"+IPTC::MarkerNomenclature.markers(type.to_i).name] ||= []
|
99
|
+
@values[@prefix+"/"+IPTC::MarkerNomenclature.markers(type.to_i).name] << value
|
100
|
+
@markers << marker
|
101
|
+
|
102
|
+
else
|
103
|
+
# raise InvalidBlockException.new("Invalid BIM segment #{header.inspect} in marker\n#{@original_content.inspect}")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
return @values
|
107
|
+
end
|
108
|
+
|
109
|
+
def [](item)
|
110
|
+
return @values[item]
|
111
|
+
end
|
112
|
+
def to_binary
|
113
|
+
marker = ""
|
114
|
+
@markers.each do |value|
|
115
|
+
marker += value.to_binary
|
116
|
+
end
|
117
|
+
|
118
|
+
marker = @header+@bim_type+@bim_dummy+[marker.length].pack('n')+marker
|
119
|
+
|
120
|
+
# build the complete marker
|
121
|
+
marker = super(marker)
|
122
|
+
|
123
|
+
return marker
|
124
|
+
end
|
125
|
+
def properties
|
126
|
+
return IPTC::TAGS.values.sort
|
127
|
+
end
|
128
|
+
def set(property, value)
|
129
|
+
numerical_tag = IPTC::TAGS.index(property)
|
130
|
+
if numerical_tag!=nil
|
131
|
+
else
|
132
|
+
throw InvalidPropertyException.new("Invalid property #{property} for IPTC marker")
|
133
|
+
end
|
134
|
+
marker = IPTC::Marker.new(numerical_tag, value)
|
135
|
+
@markers << marker
|
136
|
+
end
|
137
|
+
end
|
138
|
+
class InvalidPropertyException < Exception
|
139
|
+
end
|
140
|
+
# == The APP0Marker
|
141
|
+
# Contains some useful JFIF informations about the current
|
142
|
+
# image.
|
143
|
+
class APP0Marker < Marker
|
144
|
+
def initialize type, data
|
145
|
+
super type, data
|
146
|
+
end
|
147
|
+
def valid?
|
148
|
+
if read(5)!="JFIF\0"
|
149
|
+
return false
|
150
|
+
end
|
151
|
+
return true
|
152
|
+
end
|
153
|
+
def parse
|
154
|
+
|
155
|
+
@values = {
|
156
|
+
'APP1/revision'=>read(2).unpack('n')[0],
|
157
|
+
'APP1/unit' => read(1),
|
158
|
+
'APP1/xdensity' => read(2).unpack('n')[0],
|
159
|
+
'APP1/ydensity' => read(2).unpack('n')[0],
|
160
|
+
'APP1/xthumbnail' => read(1).unpack('c')[0],
|
161
|
+
'APP1/ythumbnail' => read(1).unpack('c')[0]
|
162
|
+
}
|
163
|
+
end
|
164
|
+
def [](item)
|
165
|
+
return @values[item]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
if $0 == __FILE__
|
173
|
+
if ARGV[0]==nil
|
174
|
+
puts "No file given. Aborting."
|
175
|
+
exit
|
176
|
+
end
|
177
|
+
|
178
|
+
require 'iptc/jpeg/image'
|
179
|
+
|
180
|
+
|
181
|
+
# read the image
|
182
|
+
im = IPTC::JPEG::Image.new(ARGV[0])
|
183
|
+
|
184
|
+
puts "Done reading #{ARGV[0]}"
|
185
|
+
|
186
|
+
im.values.each do |item|
|
187
|
+
puts "#{item.key}\t#{item.value}"
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
data/lib/iptc/marker.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module IPTC
|
2
|
+
# == Marker
|
3
|
+
# A simple IPTC Marker
|
4
|
+
class Marker
|
5
|
+
attr_accessor :value
|
6
|
+
def initialize(type, value)
|
7
|
+
@type = type
|
8
|
+
@value = value
|
9
|
+
end
|
10
|
+
def to_s
|
11
|
+
self.value
|
12
|
+
end
|
13
|
+
def to_binary
|
14
|
+
"\x1c\x02"+[@type, @value.length].pack('cn')+@value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'iptc/marker'
|
3
|
+
|
4
|
+
module IPTC
|
5
|
+
class MarkerNomenclature
|
6
|
+
include Singleton
|
7
|
+
def MarkerNomenclature.markers(id)
|
8
|
+
return MarkerNomenclature.instance.markers(id)
|
9
|
+
end
|
10
|
+
|
11
|
+
def markers(id)
|
12
|
+
if @markers.has_key?(id)
|
13
|
+
return @markers[id]
|
14
|
+
else
|
15
|
+
return @markers[-1]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def populate
|
20
|
+
@markers = {}
|
21
|
+
begin
|
22
|
+
fullpath = nil
|
23
|
+
|
24
|
+
[File.dirname(__FILE__), $:].flatten.each { |path|
|
25
|
+
break if File.exists?(fullpath = File.join(path, "iptc"))
|
26
|
+
}
|
27
|
+
content = File.open(fullpath).read
|
28
|
+
rescue Exception=>e
|
29
|
+
raise "Load failed for \"iptc\" file\nWith $:=#{$:.inspect}\n\n"+e
|
30
|
+
end
|
31
|
+
marker = Struct.new(:iid, :name, :description)
|
32
|
+
|
33
|
+
m = marker.new
|
34
|
+
m.name = "Unknow marker"
|
35
|
+
m.iid = -1
|
36
|
+
@markers[-1] = m
|
37
|
+
|
38
|
+
content.each_line do |line|
|
39
|
+
tags = line.split(/\t/)
|
40
|
+
m = marker.new
|
41
|
+
m[:name] = tags[0]
|
42
|
+
m[:description] = tags[1]
|
43
|
+
m[:iid] = tags[2].to_i
|
44
|
+
@markers[m.iid] = m
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
MarkerNomenclature.instance.populate
|
49
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module IPTC
|
2
|
+
|
3
|
+
|
4
|
+
# a MultipleHash associate a String key, a Marker Object and a String value
|
5
|
+
# this object
|
6
|
+
class MultipleHash
|
7
|
+
def initialize()
|
8
|
+
@internal = Hash.new
|
9
|
+
end
|
10
|
+
def add marker, hash
|
11
|
+
hash.each do |key,value|
|
12
|
+
@internal[key] ||= []
|
13
|
+
@internal[key] << MultipleHashItem.new(marker,key,value)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
def has_key?(key)
|
17
|
+
return @internal.has_key?(key)
|
18
|
+
end
|
19
|
+
# Returns one or more values for a given key
|
20
|
+
# if there is only one value, do not send an array back
|
21
|
+
# but send the value instead.
|
22
|
+
def [](key)
|
23
|
+
if has_key?(key)
|
24
|
+
if @internal[key].length == 1
|
25
|
+
return @internal[key][0]
|
26
|
+
else
|
27
|
+
return @internal[key]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
def each
|
32
|
+
@internal.each do |key, values|
|
33
|
+
values.each do |value|
|
34
|
+
yield value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class MultipleHashItem
|
41
|
+
attr_reader :key
|
42
|
+
def initialize marker, key, value
|
43
|
+
@marker = marker
|
44
|
+
@key = key
|
45
|
+
end
|
46
|
+
def value=(value)
|
47
|
+
@marker[@key]=value
|
48
|
+
end
|
49
|
+
def value
|
50
|
+
return @marker[@key]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/iptc/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: iptc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Pierre Baillet
|
13
|
+
- Jens Kraemer
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-09-06 00:00:00 +02:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Original code from http://raa.ruby-lang.org/project/jpeg-jfif-iptc/, gemified and updated by Jens Kraemer
|
23
|
+
email:
|
24
|
+
- jk@jkraemer.net
|
25
|
+
executables: []
|
26
|
+
|
27
|
+
extensions: []
|
28
|
+
|
29
|
+
extra_rdoc_files: []
|
30
|
+
|
31
|
+
files:
|
32
|
+
- lib/iptc/jpeg/image.rb
|
33
|
+
- lib/iptc/jpeg/marker.rb
|
34
|
+
- lib/iptc/jpeg/marker_headers.rb
|
35
|
+
- lib/iptc/jpeg/markers.rb
|
36
|
+
- lib/iptc/marker.rb
|
37
|
+
- lib/iptc/marker_nomenclature.rb
|
38
|
+
- lib/iptc/multiple_hash.rb
|
39
|
+
- lib/iptc/version.rb
|
40
|
+
- lib/iptc.rb
|
41
|
+
- LICENSE
|
42
|
+
- README.md
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://github.com/jkraemer/ruby-iptc
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: -1405560905508476106
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
segments:
|
67
|
+
- 1
|
68
|
+
- 3
|
69
|
+
- 6
|
70
|
+
version: 1.3.6
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project: ruby-iptc
|
74
|
+
rubygems_version: 1.3.7
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: Pure ruby IPTC metadata reader
|
78
|
+
test_files: []
|
79
|
+
|