xmp 0.1.0
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/.gitignore +4 -0
- data/.rspec +1 -0
- data/.rvmrc +34 -0
- data/Gemfile +3 -0
- data/README.rdoc +51 -0
- data/Rakefile +12 -0
- data/lib/xmp.rb +70 -0
- data/lib/xmp/namespace.rb +69 -0
- data/lib/xmp/silencer.rb +11 -0
- data/lib/xmp/version.rb +3 -0
- data/spec/exifr_jpeg_spec.rb +13 -0
- data/spec/fixtures/multiple-app1.jpg +0 -0
- data/spec/fixtures/xmp.xml +239 -0
- data/spec/fixtures/xmp2.xml +57 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/xmp_spec.rb +61 -0
- data/xmp.gemspec +28 -0
- metadata +98 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# http://rvm.beginrescueend.com/workflow/rvmrc/
|
4
|
+
|
5
|
+
ruby_string="ruby-1.9.2"
|
6
|
+
gemset_name="xmp"
|
7
|
+
|
8
|
+
if rvm list strings | grep -q "${ruby_string}" ; then
|
9
|
+
|
10
|
+
# Load or create the specified environment
|
11
|
+
if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
|
12
|
+
&& -s "${rvm_path:-$HOME/.rvm}/environments/${ruby_string}@${gemset_name}" ]] ; then
|
13
|
+
\. "${rvm_path:-$HOME/.rvm}/environments/${ruby_string}@${gemset_name}"
|
14
|
+
else
|
15
|
+
rvm --create "${ruby_string}@${gemset_name}"
|
16
|
+
fi
|
17
|
+
|
18
|
+
# (
|
19
|
+
# Ensure that Bundler is installed, install it if it is not.
|
20
|
+
if ! command -v bundle &> /dev/null; then
|
21
|
+
echo "Installing bundler and creating bundle"
|
22
|
+
gem install bundler
|
23
|
+
bundle
|
24
|
+
fi
|
25
|
+
# )&
|
26
|
+
|
27
|
+
else
|
28
|
+
|
29
|
+
# Notify the user to install the desired interpreter before proceeding.
|
30
|
+
echo "${ruby_string} was not found, please run 'rvm install ${ruby_string}' and then cd back into the project directory."
|
31
|
+
|
32
|
+
fi
|
33
|
+
|
34
|
+
|
data/Gemfile
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
= xmp - Extensible Metadata Platform (XMP) parser
|
2
|
+
|
3
|
+
XMP provides object oriented interface to XMP data (http://en.wikipedia.org/wiki/Extensible_Metadata_Platform). XMP data can be found in PDF, JPEG, GIF, PNG, and many other formats.
|
4
|
+
|
5
|
+
== Supported formats
|
6
|
+
|
7
|
+
Currently only JPEG is supported through exifr gem.
|
8
|
+
|
9
|
+
== JPEG example
|
10
|
+
|
11
|
+
# gem install xmp exifr
|
12
|
+
require 'xmp'
|
13
|
+
require 'exifr'
|
14
|
+
require 'open-uri'
|
15
|
+
|
16
|
+
img = EXIFR::JPEG.new('spec/fixtures/multiple-app1.jpg')
|
17
|
+
xmp = XMP.parse(img)
|
18
|
+
xmp.dc.subject #=> ["something interesting"]
|
19
|
+
|
20
|
+
# explore XMP data
|
21
|
+
xmp.namespaces.each do |namespace_name|
|
22
|
+
namespace = xmp.send(namespace_name)
|
23
|
+
namespace.attributes.each do |attr|
|
24
|
+
puts "#{namespace_name}.#{attr}: " + namespace.send(attr).inspect
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
== Installation
|
29
|
+
|
30
|
+
gem install xmp
|
31
|
+
# for JPEG support
|
32
|
+
gem install exifr -v ">=1.0.4"
|
33
|
+
|
34
|
+
== Requirements
|
35
|
+
|
36
|
+
* Ruby 1.8.7, 1.9.2
|
37
|
+
* Nokogiri 1.4
|
38
|
+
* EXIFR >= 1.0.4
|
39
|
+
|
40
|
+
== Development
|
41
|
+
|
42
|
+
# install development dependencies
|
43
|
+
bundle install
|
44
|
+
# run specs
|
45
|
+
rake spec
|
46
|
+
|
47
|
+
== License
|
48
|
+
|
49
|
+
Ruby's license.
|
50
|
+
|
51
|
+
Copyright (c) 2011 Wojciech Piekutowski, AmberBit (http://amberbit.com)
|
data/Rakefile
ADDED
data/lib/xmp.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'xmp/silencer'
|
2
|
+
XMP::Silencer.silently { require 'nokogiri' }
|
3
|
+
require 'xmp/namespace'
|
4
|
+
|
5
|
+
# = XMP XML parser
|
6
|
+
#
|
7
|
+
# == Example
|
8
|
+
# xmp = XMP.new(File.read('xmp.xml'))
|
9
|
+
# xmp.dc.title # => "Amazing Photo"
|
10
|
+
# xmp.photoshop.Category # => "summer"
|
11
|
+
# xmp.photoshop.SupplementalCategories # => ["morning", "sea"]
|
12
|
+
class XMP
|
13
|
+
# underlying XML content
|
14
|
+
attr_reader :xml
|
15
|
+
# available namespace names
|
16
|
+
attr_reader :namespaces
|
17
|
+
|
18
|
+
# accepts valid XMP XML
|
19
|
+
def initialize(xml)
|
20
|
+
doc = Nokogiri::XML(xml)
|
21
|
+
@xml = doc.root
|
22
|
+
|
23
|
+
available_namespaces = doc.collect_namespaces
|
24
|
+
# let nokogiri know about all namespaces
|
25
|
+
available_namespaces.each do |ns, url|
|
26
|
+
@xml.add_namespace_definition ns, url
|
27
|
+
end
|
28
|
+
|
29
|
+
# collect namespace names
|
30
|
+
@namespaces = available_namespaces.collect do |ns, _|
|
31
|
+
ns =~ /^xmlns:(.+)/
|
32
|
+
$1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def inspect
|
37
|
+
"#<XMP:@namespaces=#{@namespaces.inspect}>"
|
38
|
+
end
|
39
|
+
|
40
|
+
# returns Namespace object if namespace exists, otherwise tries to call a method
|
41
|
+
def method_missing(namespace, *args)
|
42
|
+
if has_namespace?(namespace)
|
43
|
+
Namespace.new(self, namespace)
|
44
|
+
else
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def respond_to?(method)
|
50
|
+
has_namespace?(method) or super
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.parse(doc)
|
54
|
+
case doc.class.to_s
|
55
|
+
when 'EXIFR::JPEG'
|
56
|
+
if xmp_chunk = doc.app1s.find { |a| a =~ %r|\Ahttp://ns.adobe.com/xap/1.0/| }
|
57
|
+
xmp_data = xmp_chunk.split("\000")[1]
|
58
|
+
XMP.new(xmp_data)
|
59
|
+
end
|
60
|
+
else
|
61
|
+
raise "Document not supported:\n#{doc.inspect}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def has_namespace?(namespace)
|
68
|
+
namespaces.include?(namespace.to_s)
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class XMP
|
2
|
+
class Namespace
|
3
|
+
# available attributes
|
4
|
+
attr_reader :attributes
|
5
|
+
|
6
|
+
def initialize(xmp, namespace) # :nodoc
|
7
|
+
@xmp = xmp
|
8
|
+
@namespace = namespace.to_s
|
9
|
+
|
10
|
+
@attributes = []
|
11
|
+
embedded_attributes =
|
12
|
+
xml.xpath("//rdf:Description").map { |d|
|
13
|
+
d.attributes.values.
|
14
|
+
select { |attr| attr.namespace.prefix.to_s == @namespace }.
|
15
|
+
map(&:name)
|
16
|
+
}.flatten
|
17
|
+
@attributes.concat embedded_attributes
|
18
|
+
standalone_attributes = xml.xpath("//rdf:Description/#{@namespace}:*").
|
19
|
+
map(&:name)
|
20
|
+
@attributes.concat standalone_attributes
|
21
|
+
end
|
22
|
+
|
23
|
+
def inspect
|
24
|
+
"#<XMP::Namespace:#{@namespace}>"
|
25
|
+
end
|
26
|
+
|
27
|
+
def method_missing(method, *args)
|
28
|
+
if has_attribute?(method)
|
29
|
+
embedded_attribute(method) || standalone_attribute(method)
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def respond_to?(method)
|
36
|
+
has_attribute?(method) or super
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def embedded_attribute(name)
|
42
|
+
element = xml.at("//rdf:Description[@#{@namespace}:#{name}]")
|
43
|
+
return unless element
|
44
|
+
element.attribute(name.to_s).text
|
45
|
+
end
|
46
|
+
|
47
|
+
def has_attribute?(name)
|
48
|
+
attributes.include?(name.to_s)
|
49
|
+
end
|
50
|
+
|
51
|
+
def standalone_attribute(name)
|
52
|
+
attribute_xpath = "//#{@namespace}:#{name}"
|
53
|
+
attribute = xml.xpath(attribute_xpath).first
|
54
|
+
return unless attribute
|
55
|
+
|
56
|
+
array_value = attribute.xpath("./rdf:Bag | ./rdf:Seq | ./rdf:Alt").first
|
57
|
+
if array_value
|
58
|
+
items = array_value.xpath("./rdf:li")
|
59
|
+
items.map { |i| i.text }
|
60
|
+
else
|
61
|
+
raise "Don't know how to handle: \n" + attribute.to_s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def xml
|
66
|
+
@xmp.xml
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/xmp/silencer.rb
ADDED
data/lib/xmp/version.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require './spec/spec_helper.rb'
|
2
|
+
|
3
|
+
describe "XMP with EXIFR::JPEG" do
|
4
|
+
before do
|
5
|
+
XMP::Silencer.silently { @img = EXIFR::JPEG.new('spec/fixtures/multiple-app1.jpg') }
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should parse image" do
|
9
|
+
xmp = XMP.parse(@img)
|
10
|
+
xmp.should be_instance_of(XMP)
|
11
|
+
xmp.namespaces.should =~ %w{dc iX pdf photoshop rdf tiff x xap xapRights}
|
12
|
+
end
|
13
|
+
end
|
Binary file
|
@@ -0,0 +1,239 @@
|
|
1
|
+
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
2
|
+
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.2-c020 1.124078, Tue Sep 11 2007 23:21:40 ">
|
3
|
+
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
4
|
+
<rdf:Description rdf:about=""
|
5
|
+
xmlns:tiff="http://ns.adobe.com/tiff/1.0/"
|
6
|
+
xmlns:exif="http://ns.adobe.com/exif/1.0/"
|
7
|
+
xmlns:xap="http://ns.adobe.com/xap/1.0/"
|
8
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
9
|
+
xmlns:aux="http://ns.adobe.com/exif/1.0/aux/"
|
10
|
+
xmlns:Iptc4xmpCore="http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/"
|
11
|
+
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"
|
12
|
+
xmlns:crs="http://ns.adobe.com/camera-raw-settings/1.0/"
|
13
|
+
tiff:Make="Canon"
|
14
|
+
tiff:Model="Canon EOS-1D Mark III"
|
15
|
+
tiff:ImageWidth="800"
|
16
|
+
tiff:ImageLength="533"
|
17
|
+
tiff:XResolution="72/1"
|
18
|
+
tiff:YResolution="72/1"
|
19
|
+
tiff:ResolutionUnit="2"
|
20
|
+
exif:ExifVersion="0221"
|
21
|
+
exif:ExposureTime="1/320"
|
22
|
+
exif:ShutterSpeedValue="8321928/1000000"
|
23
|
+
exif:FNumber="35/10"
|
24
|
+
exif:ApertureValue="361471/100000"
|
25
|
+
exif:ExposureProgram="1"
|
26
|
+
exif:DateTimeOriginal="2011-01-18T15:48:52.00+01:00"
|
27
|
+
exif:DateTimeDigitized="2011-01-18T15:48:52.00+01:00"
|
28
|
+
exif:ExposureBiasValue="0/1"
|
29
|
+
exif:MaxApertureValue="175/100"
|
30
|
+
exif:SubjectDistance="727/100"
|
31
|
+
exif:MeteringMode="5"
|
32
|
+
exif:FocalLength="85/1"
|
33
|
+
exif:CustomRendered="0"
|
34
|
+
exif:ExposureMode="1"
|
35
|
+
exif:WhiteBalance="0"
|
36
|
+
exif:SceneCaptureType="0"
|
37
|
+
exif:FocalPlaneXResolution="3888000/1107"
|
38
|
+
exif:FocalPlaneYResolution="2592000/736"
|
39
|
+
exif:FocalPlaneResolutionUnit="2"
|
40
|
+
exif:PixelXDimension="800"
|
41
|
+
exif:PixelYDimension="533"
|
42
|
+
xap:ModifyDate="2011-02-04T11:12:00+01:00"
|
43
|
+
xap:CreateDate="2011-01-18T15:48:52.00+01:00"
|
44
|
+
xap:CreatorTool="Adobe Photoshop Lightroom"
|
45
|
+
aux:SerialNumber="562133"
|
46
|
+
aux:LensInfo="85/1 85/1 0/0 0/0"
|
47
|
+
aux:Lens="EF85mm f/1.8 USM"
|
48
|
+
aux:LensID="155"
|
49
|
+
aux:ImageNumber="0"
|
50
|
+
aux:FlashCompensation="0/1"
|
51
|
+
aux:OwnerName="John Doe"
|
52
|
+
aux:Firmware="1.2.3"
|
53
|
+
Iptc4xmpCore:Location="Miejsce"
|
54
|
+
photoshop:Category="Kategoria"
|
55
|
+
photoshop:LegacyIPTCDigest="7220E75D669D5F417F2D6C9ADA130467"
|
56
|
+
crs:Version="6.1"
|
57
|
+
crs:ProcessVersion="5.7"
|
58
|
+
crs:WhiteBalance="As Shot"
|
59
|
+
crs:Temperature="4950"
|
60
|
+
crs:Tint="-6"
|
61
|
+
crs:Exposure="-0.75"
|
62
|
+
crs:Shadows="15"
|
63
|
+
crs:Brightness="+92"
|
64
|
+
crs:Contrast="+27"
|
65
|
+
crs:Saturation="+5"
|
66
|
+
crs:Sharpness="25"
|
67
|
+
crs:LuminanceSmoothing="0"
|
68
|
+
crs:ColorNoiseReduction="25"
|
69
|
+
crs:ChromaticAberrationR="0"
|
70
|
+
crs:ChromaticAberrationB="0"
|
71
|
+
crs:VignetteAmount="-61"
|
72
|
+
crs:VignetteMidpoint="50"
|
73
|
+
crs:ShadowTint="0"
|
74
|
+
crs:RedHue="+14"
|
75
|
+
crs:RedSaturation="+18"
|
76
|
+
crs:GreenHue="0"
|
77
|
+
crs:GreenSaturation="0"
|
78
|
+
crs:BlueHue="-7"
|
79
|
+
crs:BlueSaturation="-7"
|
80
|
+
crs:FillLight="31"
|
81
|
+
crs:Vibrance="0"
|
82
|
+
crs:HighlightRecovery="30"
|
83
|
+
crs:Clarity="+100"
|
84
|
+
crs:Defringe="0"
|
85
|
+
crs:HueAdjustmentRed="0"
|
86
|
+
crs:HueAdjustmentOrange="+33"
|
87
|
+
crs:HueAdjustmentYellow="0"
|
88
|
+
crs:HueAdjustmentGreen="0"
|
89
|
+
crs:HueAdjustmentAqua="0"
|
90
|
+
crs:HueAdjustmentBlue="0"
|
91
|
+
crs:HueAdjustmentPurple="0"
|
92
|
+
crs:HueAdjustmentMagenta="0"
|
93
|
+
crs:SaturationAdjustmentRed="-2"
|
94
|
+
crs:SaturationAdjustmentOrange="-30"
|
95
|
+
crs:SaturationAdjustmentYellow="0"
|
96
|
+
crs:SaturationAdjustmentGreen="0"
|
97
|
+
crs:SaturationAdjustmentAqua="0"
|
98
|
+
crs:SaturationAdjustmentBlue="0"
|
99
|
+
crs:SaturationAdjustmentPurple="0"
|
100
|
+
crs:SaturationAdjustmentMagenta="0"
|
101
|
+
crs:LuminanceAdjustmentRed="0"
|
102
|
+
crs:LuminanceAdjustmentOrange="0"
|
103
|
+
crs:LuminanceAdjustmentYellow="0"
|
104
|
+
crs:LuminanceAdjustmentGreen="0"
|
105
|
+
crs:LuminanceAdjustmentAqua="0"
|
106
|
+
crs:LuminanceAdjustmentBlue="0"
|
107
|
+
crs:LuminanceAdjustmentPurple="0"
|
108
|
+
crs:LuminanceAdjustmentMagenta="0"
|
109
|
+
crs:SplitToningShadowHue="0"
|
110
|
+
crs:SplitToningShadowSaturation="0"
|
111
|
+
crs:SplitToningHighlightHue="0"
|
112
|
+
crs:SplitToningHighlightSaturation="0"
|
113
|
+
crs:SplitToningBalance="+64"
|
114
|
+
crs:ParametricShadows="+60"
|
115
|
+
crs:ParametricDarks="-11"
|
116
|
+
crs:ParametricLights="+15"
|
117
|
+
crs:ParametricHighlights="+70"
|
118
|
+
crs:ParametricShadowSplit="25"
|
119
|
+
crs:ParametricMidtoneSplit="50"
|
120
|
+
crs:ParametricHighlightSplit="80"
|
121
|
+
crs:SharpenRadius="+1.0"
|
122
|
+
crs:SharpenDetail="25"
|
123
|
+
crs:SharpenEdgeMasking="0"
|
124
|
+
crs:PostCropVignetteAmount="0"
|
125
|
+
crs:GrainAmount="0"
|
126
|
+
crs:ColorNoiseReductionDetail="50"
|
127
|
+
crs:LensProfileEnable="0"
|
128
|
+
crs:LensManualDistortionAmount="0"
|
129
|
+
crs:PerspectiveVertical="0"
|
130
|
+
crs:PerspectiveHorizontal="0"
|
131
|
+
crs:PerspectiveRotate="0.0"
|
132
|
+
crs:PerspectiveScale="100"
|
133
|
+
crs:ConvertToGrayscale="False"
|
134
|
+
crs:ToneCurveName="Medium Contrast"
|
135
|
+
crs:CameraProfile="Adobe Standard"
|
136
|
+
crs:CameraProfileDigest="631F0C9CC003981496182C3DD10EF165"
|
137
|
+
crs:LensProfileSetup="LensDefaults"
|
138
|
+
crs:HasSettings="True"
|
139
|
+
crs:CropTop="0.024828"
|
140
|
+
crs:CropLeft="0.012414"
|
141
|
+
crs:CropBottom="1"
|
142
|
+
crs:CropRight="0.987586"
|
143
|
+
crs:CropAngle="0"
|
144
|
+
crs:CropConstrainToWarp="0"
|
145
|
+
crs:CropWidth="800"
|
146
|
+
crs:CropHeight="533"
|
147
|
+
crs:CropUnit="0"
|
148
|
+
crs:HasCrop="True"
|
149
|
+
crs:AlreadyApplied="True">
|
150
|
+
<exif:ISOSpeedRatings>
|
151
|
+
<rdf:Seq>
|
152
|
+
<rdf:li>100</rdf:li>
|
153
|
+
</rdf:Seq>
|
154
|
+
</exif:ISOSpeedRatings>
|
155
|
+
<dc:creator>
|
156
|
+
<rdf:Seq>
|
157
|
+
<rdf:li>John Doe</rdf:li>
|
158
|
+
</rdf:Seq>
|
159
|
+
</dc:creator>
|
160
|
+
<dc:title>
|
161
|
+
<rdf:Alt>
|
162
|
+
<rdf:li xml:lang="x-default">Tytuł zdjęcia</rdf:li>
|
163
|
+
</rdf:Alt>
|
164
|
+
</dc:title>
|
165
|
+
<dc:rights>
|
166
|
+
<rdf:Alt>
|
167
|
+
<rdf:li xml:lang="x-default">Autor</rdf:li>
|
168
|
+
</rdf:Alt>
|
169
|
+
</dc:rights>
|
170
|
+
<dc:subject>
|
171
|
+
<rdf:Bag>
|
172
|
+
<rdf:li>Słowa kluczowe i numery startowe.</rdf:li>
|
173
|
+
</rdf:Bag>
|
174
|
+
</dc:subject>
|
175
|
+
<dc:description>
|
176
|
+
<rdf:Alt>
|
177
|
+
<rdf:li xml:lang="x-default">Opis zdjęcia</rdf:li>
|
178
|
+
</rdf:Alt>
|
179
|
+
</dc:description>
|
180
|
+
<photoshop:SupplementalCategories>
|
181
|
+
<rdf:Bag>
|
182
|
+
<rdf:li>Nazwa imprezy</rdf:li>
|
183
|
+
</rdf:Bag>
|
184
|
+
</photoshop:SupplementalCategories>
|
185
|
+
<crs:ToneCurve>
|
186
|
+
<rdf:Seq>
|
187
|
+
<rdf:li>0, 0</rdf:li>
|
188
|
+
<rdf:li>32, 22</rdf:li>
|
189
|
+
<rdf:li>64, 56</rdf:li>
|
190
|
+
<rdf:li>128, 128</rdf:li>
|
191
|
+
<rdf:li>192, 196</rdf:li>
|
192
|
+
<rdf:li>255, 255</rdf:li>
|
193
|
+
</rdf:Seq>
|
194
|
+
</crs:ToneCurve>
|
195
|
+
</rdf:Description>
|
196
|
+
</rdf:RDF>
|
197
|
+
</x:xmpmeta>
|
198
|
+
|
199
|
+
|
200
|
+
|
201
|
+
|
202
|
+
|
203
|
+
|
204
|
+
|
205
|
+
|
206
|
+
|
207
|
+
|
208
|
+
|
209
|
+
|
210
|
+
|
211
|
+
|
212
|
+
|
213
|
+
|
214
|
+
|
215
|
+
|
216
|
+
|
217
|
+
|
218
|
+
|
219
|
+
|
220
|
+
|
221
|
+
|
222
|
+
|
223
|
+
|
224
|
+
|
225
|
+
|
226
|
+
|
227
|
+
|
228
|
+
|
229
|
+
|
230
|
+
|
231
|
+
|
232
|
+
|
233
|
+
|
234
|
+
|
235
|
+
|
236
|
+
|
237
|
+
|
238
|
+
|
239
|
+
<?xpacket end="w"?>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
|
2
|
+
<?adobe-xap-filters esc="CR"?>
|
3
|
+
<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='XMP toolkit 2.9-9, framework 1.6'>
|
4
|
+
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:iX='http://ns.adobe.com/iX/1.0/'>
|
5
|
+
<rdf:Description rdf:about='' xmlns:pdf='http://ns.adobe.com/pdf/1.3/'></rdf:Description>
|
6
|
+
<rdf:Description rdf:about='' xmlns:photoshop='http://ns.adobe.com/photoshop/1.0/' photoshop:Headline='DeniseTestImage' photoshop:Credit='Remco'></rdf:Description>
|
7
|
+
<rdf:Description rdf:about='' xmlns:tiff='http://ns.adobe.com/tiff/1.0/'></rdf:Description>
|
8
|
+
<rdf:Description rdf:about='' xmlns:xap='http://ns.adobe.com/xap/1.0/'></rdf:Description>
|
9
|
+
<rdf:Description rdf:about='' xmlns:xapRights='http://ns.adobe.com/xap/1.0/rights/'></rdf:Description>
|
10
|
+
<rdf:Description rdf:about='' xmlns:dc='http://purl.org/dc/elements/1.1/'>
|
11
|
+
<dc:subject><rdf:Bag><rdf:li>SAMPLEkeyworddataFromIview</rdf:li></rdf:Bag></dc:subject>
|
12
|
+
<dc:creator><rdf:Seq><rdf:li>BenjaminStorrier</rdf:li></rdf:Seq></dc:creator>
|
13
|
+
<dc:rights><rdf:Alt> <rdf:li>PublicDomain</rdf:li></rdf:Alt></dc:rights>
|
14
|
+
</rdf:Description>
|
15
|
+
</rdf:RDF>
|
16
|
+
</x:xmpmeta>
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
<?xpacket end='r'?>
|
data/spec/spec_helper.rb
ADDED
data/spec/xmp_spec.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require './spec/spec_helper.rb'
|
3
|
+
|
4
|
+
describe XMP do
|
5
|
+
describe "with xmp.xml" do
|
6
|
+
before { @xmp = XMP.new(File.read('spec/fixtures/xmp.xml')) }
|
7
|
+
|
8
|
+
it "should return all namespace names" do
|
9
|
+
@xmp.namespaces.should =~ %w{rdf x tiff exif xap aux Iptc4xmpCore photoshop crs dc}
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should return standalone attribute" do
|
13
|
+
@xmp.dc.title.should eq(['Tytuł zdjęcia'])
|
14
|
+
@xmp.dc.subject.should eq(['Słowa kluczowe i numery startowe.'])
|
15
|
+
@xmp.photoshop.SupplementalCategories.should eq(['Nazwa imprezy'])
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return embedded attribute" do
|
19
|
+
@xmp.Iptc4xmpCore.Location.should eq('Miejsce')
|
20
|
+
@xmp.photoshop.Category.should eq('Kategoria')
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should raise NoMethodError on unknown attribute" do
|
24
|
+
lambda { @xmp.photoshop.UnknownAttribute }.should raise_error(NoMethodError)
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "namespace 'tiff'" do
|
28
|
+
before { @namespace = @xmp.tiff }
|
29
|
+
|
30
|
+
it "should return all attribute names" do
|
31
|
+
@namespace.attributes.should =~ %w{Make Model ImageWidth ImageLength XResolution YResolution ResolutionUnit}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "namespace 'photoshop'" do
|
36
|
+
before { @namespace = @xmp.photoshop }
|
37
|
+
|
38
|
+
it "should return all attribute names" do
|
39
|
+
@namespace.attributes.should =~ %w{LegacyIPTCDigest Category SupplementalCategories}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "with xmp2.xml" do
|
45
|
+
before { @xmp = XMP.new(File.read('spec/fixtures/xmp2.xml')) }
|
46
|
+
|
47
|
+
it "should return all namespace names" do
|
48
|
+
@xmp.namespaces.should =~ %w{dc iX pdf photoshop rdf tiff x xap xapRights}
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should return standalone attribute" do
|
52
|
+
@xmp.dc.creator.should eq(['BenjaminStorrier'])
|
53
|
+
@xmp.dc.subject.should eq(['SAMPLEkeyworddataFromIview'])
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should return embedded attribute" do
|
57
|
+
@xmp.photoshop.Headline.should eq('DeniseTestImage')
|
58
|
+
@xmp.photoshop.Credit.should eq('Remco')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/xmp.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "xmp/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "xmp"
|
7
|
+
s.version = XMP::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Wojciech Piekutowski"]
|
10
|
+
s.email = ["wojciech.piekutowski@amberbit.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Extensible Metadata Platform (XMP) parser}
|
13
|
+
s.description = %q{Extensible Metadata Platform (XMP) parser}
|
14
|
+
|
15
|
+
s.rubyforge_project = "xmp"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.extra_rdoc_files = %w(README.rdoc)
|
23
|
+
|
24
|
+
s.add_dependency 'nokogiri', '~>1.4.0'
|
25
|
+
|
26
|
+
s.add_development_dependency 'exifr', '>=1.0.4'
|
27
|
+
s.add_development_dependency 'rspec', '~>2.0'
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xmp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Wojciech Piekutowski
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-02-26 00:00:00.000000000 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: nokogiri
|
17
|
+
requirement: &8132500 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.4.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *8132500
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: exifr
|
28
|
+
requirement: &8132000 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.4
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *8132000
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rspec
|
39
|
+
requirement: &8131540 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '2.0'
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *8131540
|
48
|
+
description: Extensible Metadata Platform (XMP) parser
|
49
|
+
email:
|
50
|
+
- wojciech.piekutowski@amberbit.com
|
51
|
+
executables: []
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files:
|
54
|
+
- README.rdoc
|
55
|
+
files:
|
56
|
+
- .gitignore
|
57
|
+
- .rspec
|
58
|
+
- .rvmrc
|
59
|
+
- Gemfile
|
60
|
+
- README.rdoc
|
61
|
+
- Rakefile
|
62
|
+
- lib/xmp.rb
|
63
|
+
- lib/xmp/namespace.rb
|
64
|
+
- lib/xmp/silencer.rb
|
65
|
+
- lib/xmp/version.rb
|
66
|
+
- spec/exifr_jpeg_spec.rb
|
67
|
+
- spec/fixtures/multiple-app1.jpg
|
68
|
+
- spec/fixtures/xmp.xml
|
69
|
+
- spec/fixtures/xmp2.xml
|
70
|
+
- spec/spec_helper.rb
|
71
|
+
- spec/xmp_spec.rb
|
72
|
+
- xmp.gemspec
|
73
|
+
has_rdoc: true
|
74
|
+
homepage: ''
|
75
|
+
licenses: []
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ! '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
requirements: []
|
93
|
+
rubyforge_project: xmp
|
94
|
+
rubygems_version: 1.5.2
|
95
|
+
signing_key:
|
96
|
+
specification_version: 3
|
97
|
+
summary: Extensible Metadata Platform (XMP) parser
|
98
|
+
test_files: []
|