xmp 1.0.1 → 2.0.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.
- checksums.yaml +4 -4
- data/.gitignore +9 -6
- data/.rspec +1 -0
- data/CHANGELOG.md +27 -0
- data/README.md +1 -1
- data/lib/xmp/document.rb +14 -5
- data/lib/xmp/error.rb +0 -1
- data/lib/xmp/handler/exifr_jpeg.rb +15 -0
- data/lib/xmp/handler/exifr_tiff.rb +14 -0
- data/lib/xmp/namespace.rb +2 -2
- data/lib/xmp/version.rb +1 -1
- data/lib/xmp.rb +4 -2
- data/spec/document_spec.rb +18 -0
- data/spec/exifr_jpeg_spec.rb +4 -1
- data/spec/exifr_tiff_spec.rb +4 -1
- data/spec/fixtures/no-xmp-metadata.jpg +0 -0
- data/spec/fixtures/no-xmp-metadata.tiff +0 -0
- data/spec/fixtures/xmp-with-empty-attribute.xml +240 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/xmp_spec.rb +27 -1
- data/xmp.gemspec +3 -2
- metadata +29 -5
- data/lib/xmp/handler/exifr.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '08b4db6fe980f2c71919cc1c18c5890aede35ae7314c63e3831da8acb297d631'
|
4
|
+
data.tar.gz: 1d98136da2cec12516e85fb8e7b0e70bd3fe95311c7a03c09b630e8cd7cc129a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d6f9598473a15eb47e65ce5659810576eafecafb8c399abcbecc07f8e1a6c3e64f0f386a4363830706ca4ddb2be1809406b1df4a245fefbf31076bf6c7b42b21
|
7
|
+
data.tar.gz: 3061122b945a464fe39d23ce115dfe2df0617f570f76ba8858d90a5bc12d0113de3d2a13fafaded4652eaf8f78eddcfb36644baca2505b416d1893128efee6cf
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## [Unreleased]
|
4
|
+
|
5
|
+
TBA
|
6
|
+
|
7
|
+
## 2.0.0
|
8
|
+
|
9
|
+
- `XMP.new` and `.parse` return an empty XMP::Document when a JPEG or TIFF image has no XMP metadata.
|
10
|
+
(In 0.2 and earlier, those methods returned `nil` in that case.
|
11
|
+
In 1.0 and 1.0.1 they intended to raise a custom exception, but raised `NoMethodError`.)
|
12
|
+
- Add `XMP::Document#empty?`
|
13
|
+
|
14
|
+
## 1.0.1
|
15
|
+
|
16
|
+
- Reinstate support for Ruby 2.6 (the version included with current macOS, macOS 14, Sonoma)
|
17
|
+
- Fix unintended exception, introduced in 1.0, in `XMP::Document#respond_to_missing?` and
|
18
|
+
`XMP::Namespace#respond_to_missing?`
|
19
|
+
|
20
|
+
## 1.0
|
21
|
+
|
22
|
+
- Support TIFF images
|
23
|
+
- Support standalone properties with attributes, for example `Iptc4xmpCore.CreatorContactInfo`
|
24
|
+
- Namespaces and attributes may be accessed with more Ruby-style underscore identifiers,
|
25
|
+
for example ExampleNamespace as example_namespace
|
26
|
+
- `XMP.new` and `.parse` accept `Pathname` and `File` as well as a `String` path
|
27
|
+
- Remove support for Ruby 2.6 and earlier
|
data/README.md
CHANGED
data/lib/xmp/document.rb
CHANGED
@@ -4,14 +4,23 @@ class XMP::Document
|
|
4
4
|
attr_reader :namespaces
|
5
5
|
attr_reader :xml
|
6
6
|
|
7
|
-
def initialize(doc)
|
8
|
-
|
9
|
-
|
10
|
-
@
|
11
|
-
|
7
|
+
def initialize(doc = nil)
|
8
|
+
if doc
|
9
|
+
@xml = doc.root
|
10
|
+
@namespaces = doc.collect_namespaces.map do |ns, url|
|
11
|
+
@xml.add_namespace_definition ns, url
|
12
|
+
ns[/^(?:xmlns:)?xmlns:(.+)/, 1]
|
13
|
+
end
|
14
|
+
else
|
15
|
+
@xml = nil
|
16
|
+
@namespaces = []
|
12
17
|
end
|
13
18
|
end
|
14
19
|
|
20
|
+
def empty?
|
21
|
+
@xml.nil?
|
22
|
+
end
|
23
|
+
|
15
24
|
private
|
16
25
|
|
17
26
|
def list
|
data/lib/xmp/error.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
begin
|
2
|
+
require 'exifr/jpeg'
|
3
|
+
rescue LoadError => exception
|
4
|
+
raise exception unless exception.path == 'exifr/jpeg'
|
5
|
+
end
|
6
|
+
|
7
|
+
module XMP::Handler
|
8
|
+
class ExifrJPEG
|
9
|
+
def call(object)
|
10
|
+
return unless defined?(EXIFR::JPEG) && object.is_a?(EXIFR::JPEG)
|
11
|
+
xmp_chunk = object.app1s.find { |a| a =~ %r|\Ahttp://ns.adobe.com/xap/1.0/| }
|
12
|
+
xmp_chunk ? xmp_chunk.split("\000")[1] : XMP::Document.new
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
begin
|
2
|
+
require 'exifr/tiff'
|
3
|
+
rescue LoadError => exception
|
4
|
+
raise exception unless exception.path == 'exifr/tiff'
|
5
|
+
end
|
6
|
+
|
7
|
+
module XMP::Handler
|
8
|
+
class ExifrTIFF
|
9
|
+
def call(object)
|
10
|
+
return unless defined?(EXIFR::TIFF) && object.is_a?(EXIFR::TIFF)
|
11
|
+
object.xmp || XMP::Document.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/xmp/namespace.rb
CHANGED
@@ -29,12 +29,12 @@ class XMP::Namespace
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def get_embedded(name)
|
32
|
-
|
32
|
+
element = xml.at("//rdf:Description[@#{namespace}:#{name}]")
|
33
33
|
element.attribute(name.to_s).text
|
34
34
|
end
|
35
35
|
|
36
36
|
def get_standalone(name)
|
37
|
-
|
37
|
+
attribute = xml.xpath("//#{namespace}:#{name}").first
|
38
38
|
if list = attribute.xpath("./rdf:Bag | ./rdf:Seq | ./rdf:Alt").first
|
39
39
|
return list.xpath("./rdf:li").map(&:text)
|
40
40
|
end
|
data/lib/xmp/version.rb
CHANGED
data/lib/xmp.rb
CHANGED
@@ -3,7 +3,8 @@ module XMP
|
|
3
3
|
require 'xmp/document'
|
4
4
|
require 'xmp/error'
|
5
5
|
require 'xmp/handler'
|
6
|
-
require 'xmp/handler/
|
6
|
+
require 'xmp/handler/exifr_jpeg'
|
7
|
+
require 'xmp/handler/exifr_tiff'
|
7
8
|
require 'xmp/handler/file'
|
8
9
|
require 'xmp/handler/xml'
|
9
10
|
require 'xmp/namespace'
|
@@ -14,7 +15,8 @@ module XMP
|
|
14
15
|
Handler::File.new('.jpg', '.jpeg') { |file| EXIFR::JPEG.new(file) },
|
15
16
|
Handler::File.new('.tif', '.tiff') { |file| EXIFR::TIFF.new(file) },
|
16
17
|
Handler::File.new('.xmp', '.xml') { |file| Nokogiri::XML(file) },
|
17
|
-
Handler::
|
18
|
+
Handler::ExifrJPEG.new,
|
19
|
+
Handler::ExifrTIFF.new,
|
18
20
|
Handler::XML.new
|
19
21
|
]
|
20
22
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
describe XMP::Document do
|
2
|
+
describe '.new' do
|
3
|
+
it "should convert a Nokogiri::XML::Document to an XMP::Document with the expected XML and namespaces" do
|
4
|
+
xml_doc = Nokogiri::XML(File.open('spec/fixtures/xmp.xml'))
|
5
|
+
xmp_doc = XMP::Document.new(xml_doc)
|
6
|
+
xmp_doc.xml.should eq(xml_doc.root)
|
7
|
+
xmp_doc.namespaces.should =~ %w{rdf x tiff exif xap aux Iptc4xmpCore photoshop crs dc}
|
8
|
+
xmp_doc.should_not be_empty
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should, given no args, create an empty XMP::Document" do
|
12
|
+
xmp_doc = XMP::Document.new
|
13
|
+
xmp_doc.xml.should be_nil
|
14
|
+
xmp_doc.namespaces.should be_empty
|
15
|
+
xmp_doc.should be_empty
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/spec/exifr_jpeg_spec.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require './spec/spec_helper.rb'
|
2
1
|
require 'exifr/jpeg'
|
3
2
|
|
4
3
|
describe "XMP with EXIFR::JPEG" do
|
@@ -20,4 +19,8 @@ describe "XMP with EXIFR::JPEG" do
|
|
20
19
|
xmp.should be_instance_of(XMP::Document)
|
21
20
|
xmp.namespaces.should =~ %w{dc iX pdf photoshop rdf tiff x xap xapRights}
|
22
21
|
end
|
22
|
+
|
23
|
+
it "should return an empty XMP::Document for an image without XMP metadata" do
|
24
|
+
XMP.parse('spec/fixtures/no-xmp-metadata.jpg').should be_instance_of(XMP::Document)
|
25
|
+
end
|
23
26
|
end
|
data/spec/exifr_tiff_spec.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require './spec/spec_helper.rb'
|
2
1
|
require 'exifr/tiff'
|
3
2
|
|
4
3
|
describe "XMP with EXIFR::TIFF" do
|
@@ -14,4 +13,8 @@ describe "XMP with EXIFR::TIFF" do
|
|
14
13
|
xmp.should be_instance_of(XMP::Document)
|
15
14
|
xmp.namespaces.should =~ %w{dc iX pdf photoshop rdf tiff x xap xapRights}
|
16
15
|
end
|
16
|
+
|
17
|
+
it "should return an empty XMP::Document for an image without XMP metadata" do
|
18
|
+
XMP.parse('spec/fixtures/no-xmp-metadata.tiff').should be_instance_of(XMP::Document)
|
19
|
+
end
|
17
20
|
end
|
Binary file
|
Binary file
|
@@ -0,0 +1,240 @@
|
|
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
|
+
<Iptc4xmpCore:CreatorContactInfo/>
|
196
|
+
</rdf:Description>
|
197
|
+
</rdf:RDF>
|
198
|
+
</x:xmpmeta>
|
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
|
+
|
240
|
+
<?xpacket end="w"?>
|
data/spec/spec_helper.rb
CHANGED
data/spec/xmp_spec.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
require './spec/spec_helper.rb'
|
3
2
|
|
4
3
|
describe XMP do
|
5
4
|
describe "with xmp.xml" do
|
@@ -48,6 +47,13 @@ describe XMP do
|
|
48
47
|
@xmp.photoshop['UnknownAttribute'].should eq(nil)
|
49
48
|
end
|
50
49
|
|
50
|
+
it "should raise if an attribute is called with any argument" do
|
51
|
+
lambda { XMP.new('spec/fixtures/xmp.xml').dc('Comics') }.
|
52
|
+
should raise_error(ArgumentError, "wrong number of arguments (given 1, expected 0)")
|
53
|
+
lambda { XMP.new('spec/fixtures/xmp.xml').dc.title('Amazing Stories') }.
|
54
|
+
should raise_error(ArgumentError, "wrong number of arguments (given 1, expected 0)")
|
55
|
+
end
|
56
|
+
|
51
57
|
describe "namespace 'tiff'" do
|
52
58
|
before { @namespace = @xmp.tiff }
|
53
59
|
|
@@ -125,4 +131,24 @@ describe XMP do
|
|
125
131
|
@xmp.to_h.keys.should =~ %w{Iptc4xmpExt aux crs dc exifEX mwg-rs photoshop rdf stArea stDim stEvt stRef x xmp xmpMM}
|
126
132
|
end
|
127
133
|
end
|
134
|
+
|
135
|
+
it "should read from an IO" do
|
136
|
+
xmp = XMP.new(File.open('spec/fixtures/xmp.xml'))
|
137
|
+
xmp.namespaces.should =~ %w{rdf x tiff exif xap aux Iptc4xmpCore photoshop crs dc}
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should raise if the file doesn't exist" do
|
141
|
+
nonexistent_file = 'nonexistent.xml'
|
142
|
+
lambda { XMP.new(nonexistent_file) }.should raise_error(XMP::Error, "cannot read file #{nonexistent_file}")
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should return nil for an unknown attribute" do
|
146
|
+
xmp = XMP.new('spec/fixtures/xmp-with-empty-attribute.xml')
|
147
|
+
lambda { xmp.Iptc4xmpCore.CreatorContactInfo }.
|
148
|
+
should raise_error(XMP::Error, "Don't know how to handle: \n<Iptc4xmpCore:CreatorContactInfo/>")
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should raise for an unknown input type" do
|
152
|
+
lambda { XMP.new(0) }.should raise_error(XMP::Error, "cannot handle 0")
|
153
|
+
end
|
128
154
|
end
|
data/xmp.gemspec
CHANGED
@@ -10,8 +10,8 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.email = ["wojciech.piekutowski@amberbit.com"]
|
11
11
|
s.homepage = "https://github.com/amberbit/xmp"
|
12
12
|
s.summary = %q{Extensible Metadata Platform (XMP) parser for JPEG, TIFF and raw XML files}
|
13
|
-
s.description = %q{Extensible Metadata Platform (XMP) parser extracts metadata from
|
14
|
-
s.licenses = ["
|
13
|
+
s.description = %q{Extensible Metadata Platform (XMP) parser extracts metadata from JPEG and TIFF image files. It also supports parsing raw XML files containing XMP.}
|
14
|
+
s.licenses = ["Ruby"]
|
15
15
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -28,4 +28,5 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.add_development_dependency 'rspec', '~> 3.0'
|
29
29
|
s.add_development_dependency 'logger', '~> 1.0'
|
30
30
|
s.add_development_dependency 'rake'
|
31
|
+
s.add_development_dependency 'simplecov'
|
31
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xmp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wojciech Piekutowski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -86,7 +86,21 @@ dependencies:
|
|
86
86
|
- - ">="
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '0'
|
89
|
-
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: simplecov
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
description: Extensible Metadata Platform (XMP) parser extracts metadata from JPEG
|
90
104
|
and TIFF image files. It also supports parsing raw XML files containing XMP.
|
91
105
|
email:
|
92
106
|
- wojciech.piekutowski@amberbit.com
|
@@ -99,6 +113,7 @@ files:
|
|
99
113
|
- ".rspec"
|
100
114
|
- ".tool-versions"
|
101
115
|
- ".travis.yml"
|
116
|
+
- CHANGELOG.md
|
102
117
|
- Gemfile
|
103
118
|
- README.md
|
104
119
|
- Rakefile
|
@@ -107,16 +122,21 @@ files:
|
|
107
122
|
- lib/xmp/document.rb
|
108
123
|
- lib/xmp/error.rb
|
109
124
|
- lib/xmp/handler.rb
|
110
|
-
- lib/xmp/handler/
|
125
|
+
- lib/xmp/handler/exifr_jpeg.rb
|
126
|
+
- lib/xmp/handler/exifr_tiff.rb
|
111
127
|
- lib/xmp/handler/file.rb
|
112
128
|
- lib/xmp/handler/xml.rb
|
113
129
|
- lib/xmp/namespace.rb
|
114
130
|
- lib/xmp/version.rb
|
131
|
+
- spec/document_spec.rb
|
115
132
|
- spec/exifr_jpeg_spec.rb
|
116
133
|
- spec/exifr_tiff_spec.rb
|
117
134
|
- spec/fixtures/UPPERCASE.JPG
|
118
135
|
- spec/fixtures/multiple-app1.jpg
|
119
136
|
- spec/fixtures/multiple-app1.tiff
|
137
|
+
- spec/fixtures/no-xmp-metadata.jpg
|
138
|
+
- spec/fixtures/no-xmp-metadata.tiff
|
139
|
+
- spec/fixtures/xmp-with-empty-attribute.xml
|
120
140
|
- spec/fixtures/xmp.xml
|
121
141
|
- spec/fixtures/xmp2.xml
|
122
142
|
- spec/fixtures/xmp3.xml
|
@@ -127,7 +147,7 @@ files:
|
|
127
147
|
- xmp.gemspec
|
128
148
|
homepage: https://github.com/amberbit/xmp
|
129
149
|
licenses:
|
130
|
-
-
|
150
|
+
- Ruby
|
131
151
|
metadata: {}
|
132
152
|
post_install_message:
|
133
153
|
rdoc_options: []
|
@@ -149,11 +169,15 @@ signing_key:
|
|
149
169
|
specification_version: 4
|
150
170
|
summary: Extensible Metadata Platform (XMP) parser for JPEG, TIFF and raw XML files
|
151
171
|
test_files:
|
172
|
+
- spec/document_spec.rb
|
152
173
|
- spec/exifr_jpeg_spec.rb
|
153
174
|
- spec/exifr_tiff_spec.rb
|
154
175
|
- spec/fixtures/UPPERCASE.JPG
|
155
176
|
- spec/fixtures/multiple-app1.jpg
|
156
177
|
- spec/fixtures/multiple-app1.tiff
|
178
|
+
- spec/fixtures/no-xmp-metadata.jpg
|
179
|
+
- spec/fixtures/no-xmp-metadata.tiff
|
180
|
+
- spec/fixtures/xmp-with-empty-attribute.xml
|
157
181
|
- spec/fixtures/xmp.xml
|
158
182
|
- spec/fixtures/xmp2.xml
|
159
183
|
- spec/fixtures/xmp3.xml
|
data/lib/xmp/handler/exifr.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
begin
|
2
|
-
require 'exifr/jpeg'
|
3
|
-
require 'exifr/tiff'
|
4
|
-
rescue LoadError => exception
|
5
|
-
raise exception unless exception.path == 'exifr/jpeg'
|
6
|
-
end
|
7
|
-
|
8
|
-
module XMP::Handler
|
9
|
-
class Exifr
|
10
|
-
def call(object)
|
11
|
-
return unless defined?(EXIFR::JPEG)
|
12
|
-
case object
|
13
|
-
when EXIFR::JPEG then format, xmp_data = 'jpeg', object.app1s.find { |a| a =~ %r|\Ahttp://ns.adobe.com/xap/1.0/| }&.split("\000")[1]
|
14
|
-
when EXIFR::TIFF then format, xmp_data = 'tiff', object.xmp
|
15
|
-
else return
|
16
|
-
end
|
17
|
-
|
18
|
-
raise XMP::NoXMP, "XMP section missing from #{format}" unless xmp_data
|
19
|
-
xmp_data
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|