xmp 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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