xmp 1.0.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4275b1e67258b6a6b63a3b6c1a61bdaf9b5caf5fa6a6669008ecd6c43d58dd00
4
- data.tar.gz: 7bff3b97c76db9f79ed337c84f18177680de92bb48edcd4400f25d8888bf5779
3
+ metadata.gz: '08b4db6fe980f2c71919cc1c18c5890aede35ae7314c63e3831da8acb297d631'
4
+ data.tar.gz: 1d98136da2cec12516e85fb8e7b0e70bd3fe95311c7a03c09b630e8cd7cc129a
5
5
  SHA512:
6
- metadata.gz: 1056ea809c5e851a3c9b01778a4c6929d73a1f93df0ed592e75d0aca6bb98841156159b744aba7279b6ce4302d6af8d3486ddfae041558f29f4f2b27a3a85f41
7
- data.tar.gz: e41d39d8e28bcd2a610257207d24be0c2fd58072e013c9b6c7a1ee4b0fd4fa8a0a29f3ce9bfb0ea4878e97c924716c4c20614545ed2b8f4822e965203c12e1f4
6
+ metadata.gz: d6f9598473a15eb47e65ce5659810576eafecafb8c399abcbecc07f8e1a6c3e64f0f386a4363830706ca4ddb2be1809406b1df4a245fefbf31076bf6c7b42b21
7
+ data.tar.gz: 3061122b945a464fe39d23ce115dfe2df0617f570f76ba8858d90a5bc12d0113de3d2a13fafaded4652eaf8f78eddcfb36644baca2505b416d1893128efee6cf
data/.gitignore CHANGED
@@ -1,7 +1,11 @@
1
- *.swp
1
+ .DS_Store
2
2
  *.gem
3
- .bundle
4
- Gemfile.lock
5
- pkg/*
3
+ *.swp
4
+ /.bundle
5
+ /.idea
6
+ /.ruby-version
7
+ /Gemfile.lock
8
+ /coverage
9
+ /doc
10
+ /pkg/*
6
11
  /xmp.xml
7
- .DS_Store
data/.rspec CHANGED
@@ -1 +1,2 @@
1
1
  --color
2
+ --require spec_helper
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.3.5
data/.travis.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  rvm:
2
+ - 2.6.10
2
3
  - 2.7.8
3
4
  - 3.1.6
4
5
  - 3.2.5
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
@@ -1,6 +1,6 @@
1
1
  # xmp - Extensible Metadata Platform (XMP) parser
2
2
 
3
- MP 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.
3
+ XMP provides an 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
4
 
5
5
  ## Supported Formats
6
6
 
@@ -59,9 +59,12 @@ gem 'exifr', '~> 1.3'
59
59
  ```
60
60
 
61
61
  ## Requirements
62
- * Ruby 2 or Ruby 3
63
- * Nokogiri (1.10 or newer, gem dependency - will be installed automatically)
64
- * EXIFR (1.3 or newer) - optional
62
+ * Ruby 2 (supported on >= 2.6, though xmp may work on earlier versions) or Ruby 3
63
+ * nokogiri (>= 1.10). The xmp gem depends on this gem. It will be installed automatically.
64
+ * On Ruby 2.6, nokogiri 1.13.10 will be installed; nokogiri >= 1.14 require Ruby 2.7.
65
+ * On Ruby 2.7, nokogiri 1.15.5 will be installed; nokogiri >= 1.16 require Ruby 3.
66
+ * See https://nokogiri.org/CHANGELOG.html for nokogiri support for older or newer Ruby versions.
67
+ * exifr (>= 1.3). This gem is optional. If you need it, add it to your Gemfile.
65
68
 
66
69
  ## Development
67
70
 
@@ -73,6 +76,6 @@ $ rake spec # run specs
73
76
  ```
74
77
 
75
78
  ## License
76
- Ruby's license.
79
+ [Ruby's license.](https://www.ruby-lang.org/en/about/license.txt)
77
80
 
78
81
  Copyright (c) 2011 Wojciech Piekutowski, AmberBit (<http://amberbit.com>) and contributors.
@@ -10,7 +10,7 @@ module XMP::Convenience
10
10
  end
11
11
 
12
12
  def respond_to_missing?(method_name, include_private = false)
13
- include?(key) or super
13
+ include?(method_name) or super
14
14
  end
15
15
 
16
16
  def to_h
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
- @xml = doc.root
9
- @namespaces = doc.collect_namespaces.map do |ns, url|
10
- @xml.add_namespace_definition ns, url
11
- ns[/^(?:xmlns:)?xmlns:(.+)/, 1]
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
@@ -1,4 +1,3 @@
1
1
  module XMP
2
2
  Error = Class.new(RuntimeError)
3
- NoXMP = Class.new(Error)
4
3
  end
@@ -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
- return unless element = xml.at("//rdf:Description[@#{namespace}:#{name}]")
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
- return unless attribute = xml.xpath("//#{namespace}:#{name}").first
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
@@ -1,3 +1,3 @@
1
1
  module XMP
2
- VERSION = '1.0.0'
2
+ VERSION = '2.0.0'
3
3
  end
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/exifr'
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::Exifr.new,
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
@@ -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
@@ -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
@@ -1,3 +1,6 @@
1
+ require 'simplecov'
2
+ SimpleCov.start { enable_coverage :branch }
3
+
1
4
  require 'bundler/setup'
2
5
  Bundler.require(:development)
3
6
 
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
@@ -26,6 +25,14 @@ describe XMP do
26
25
  @xmp['photoshop']['SupplementalCategories'].should eq(['Nazwa imprezy'])
27
26
  end
28
27
 
28
+ it "should respond to standalone attributes" do
29
+ @xmp.should respond_to(:dc)
30
+ @xmp.dc.should respond_to(:title)
31
+ @xmp.should respond_to(:photoshop)
32
+ @xmp.photoshop.should respond_to(:SupplementalCategories)
33
+ @xmp.photoshop.should respond_to(:supplemental_categories)
34
+ end
35
+
29
36
  it "should return standalone attribute hash" do
30
37
  @xmp.Iptc4xmpCore.CreatorContactInfo.should eq({'CiAdrCtry' => 'Germany', 'CiAdrCity' => 'Berlin'})
31
38
  end
@@ -40,6 +47,13 @@ describe XMP do
40
47
  @xmp.photoshop['UnknownAttribute'].should eq(nil)
41
48
  end
42
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
+
43
57
  describe "namespace 'tiff'" do
44
58
  before { @namespace = @xmp.tiff }
45
59
 
@@ -117,4 +131,24 @@ describe XMP do
117
131
  @xmp.to_h.keys.should =~ %w{Iptc4xmpExt aux crs dc exifEX mwg-rs photoshop rdf stArea stDim stEvt stRef x xmp xmpMM}
118
132
  end
119
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
120
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 JPED and TIFF image files. It also supports parsing raw XML files containing XMP.}
14
- s.licenses = ["MIT"]
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")
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.extra_rdoc_files = %w(README.md)
22
22
 
23
- s.required_ruby_version = '>= 2.7.0'
23
+ s.required_ruby_version = '>= 2.6.0'
24
24
 
25
25
  s.add_dependency 'nokogiri', '~> 1.0'
26
26
 
@@ -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: 1.0.0
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-09-09 00:00:00.000000000 Z
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
- description: Extensible Metadata Platform (XMP) parser extracts metadata from JPED
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
@@ -97,7 +111,9 @@ extra_rdoc_files:
97
111
  files:
98
112
  - ".gitignore"
99
113
  - ".rspec"
114
+ - ".tool-versions"
100
115
  - ".travis.yml"
116
+ - CHANGELOG.md
101
117
  - Gemfile
102
118
  - README.md
103
119
  - Rakefile
@@ -106,16 +122,21 @@ files:
106
122
  - lib/xmp/document.rb
107
123
  - lib/xmp/error.rb
108
124
  - lib/xmp/handler.rb
109
- - lib/xmp/handler/exifr.rb
125
+ - lib/xmp/handler/exifr_jpeg.rb
126
+ - lib/xmp/handler/exifr_tiff.rb
110
127
  - lib/xmp/handler/file.rb
111
128
  - lib/xmp/handler/xml.rb
112
129
  - lib/xmp/namespace.rb
113
130
  - lib/xmp/version.rb
131
+ - spec/document_spec.rb
114
132
  - spec/exifr_jpeg_spec.rb
115
133
  - spec/exifr_tiff_spec.rb
116
134
  - spec/fixtures/UPPERCASE.JPG
117
135
  - spec/fixtures/multiple-app1.jpg
118
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
119
140
  - spec/fixtures/xmp.xml
120
141
  - spec/fixtures/xmp2.xml
121
142
  - spec/fixtures/xmp3.xml
@@ -126,7 +147,7 @@ files:
126
147
  - xmp.gemspec
127
148
  homepage: https://github.com/amberbit/xmp
128
149
  licenses:
129
- - MIT
150
+ - Ruby
130
151
  metadata: {}
131
152
  post_install_message:
132
153
  rdoc_options: []
@@ -136,7 +157,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
136
157
  requirements:
137
158
  - - ">="
138
159
  - !ruby/object:Gem::Version
139
- version: 2.7.0
160
+ version: 2.6.0
140
161
  required_rubygems_version: !ruby/object:Gem::Requirement
141
162
  requirements:
142
163
  - - ">="
@@ -148,11 +169,15 @@ signing_key:
148
169
  specification_version: 4
149
170
  summary: Extensible Metadata Platform (XMP) parser for JPEG, TIFF and raw XML files
150
171
  test_files:
172
+ - spec/document_spec.rb
151
173
  - spec/exifr_jpeg_spec.rb
152
174
  - spec/exifr_tiff_spec.rb
153
175
  - spec/fixtures/UPPERCASE.JPG
154
176
  - spec/fixtures/multiple-app1.jpg
155
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
156
181
  - spec/fixtures/xmp.xml
157
182
  - spec/fixtures/xmp2.xml
158
183
  - spec/fixtures/xmp3.xml
@@ -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