Skip to content

Commit 7acf46c

Browse files
committed
Support multiple <rdf:Description> elements
1 parent 4374d54 commit 7acf46c

File tree

4 files changed

+63
-19
lines changed

4 files changed

+63
-19
lines changed

src/Metadata/Xmp.php

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ public static function fromFile($fileName)
158158
}
159159

160160
/**
161+
* Returns the first node (element or attribute) with the given field name and namespace.
162+
*
161163
* @param $field
162164
* @param $ns
163165
* @param bool $checkAttributes
@@ -166,14 +168,15 @@ public static function fromFile($fileName)
166168
*/
167169
private function getNode($field, $ns, $checkAttributes = true)
168170
{
169-
$rdfDesc = $this->getRDFDescription($ns);
170-
171171
// check for field as an element or an attribute
172172
$query = ($checkAttributes)? $field . '|@' . $field: $field;
173-
$result = $this->xpath->query($query, $rdfDesc);
174173

175-
if ($result->length) {
176-
return $result->item(0);
174+
$rdfDescriptions = $this->getRDFDescriptions($ns);
175+
foreach($rdfDescriptions as $rdfDesc) {
176+
$result = $this->xpath->query($query, $rdfDesc);
177+
if ($result->length) {
178+
return $result->item(0);
179+
}
177180
}
178181

179182
return null;
@@ -267,29 +270,28 @@ private function getSeq($field, $namespace)
267270

268271
return null;
269272
}
270-
271273
/**
274+
* Returns all `rdf:Description` elements with the given namespace.
275+
*
272276
* @param $namespace
273277
*
274-
* @return \DOMNode|null
278+
* @return array Array of \DOMNode
275279
*/
276-
private function getRDFDescription($namespace)
280+
private function getRDFDescriptions($namespace)
277281
{
278-
// element
279-
$description = $this->xpath->query("//rdf:Description[*[namespace-uri()='$namespace']]");
280-
281-
if ($description->length > 0) {
282-
return $description->item(0);
283-
}
282+
$result = [];
284283

285-
// attribute
286-
$description = $this->xpath->query("//rdf:Description[@*[namespace-uri()='$namespace']]");
284+
$element_query = "//rdf:Description[*[namespace-uri()='$namespace']]";
285+
$attribute_query = "//rdf:Description[@*[namespace-uri()='$namespace']]";
286+
foreach([$element_query, $attribute_query] as $query) {
287+
$description = $this->xpath->query($query);
287288

288-
if ($description->length > 0) {
289-
return $description->item(0);
289+
if ($description->length > 0) {
290+
$result = array_merge($result, iterator_to_array($description));
291+
}
290292
}
291293

292-
return null;
294+
return $result;
293295
}
294296

295297
/**

tests/Fixtures/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@
66
open standard
77
- [`skaterphotoshop.jpg`](skaterphotoshop.jpg), authored by
88
[Marina Ekroos](http://marinaekroos.com/)
9+
- [`multipleRdfDesc.jpg`](multipleRdfDesc.jpg), provided by
10+
[Kari Laari](https://github.com/klaari) for
11+
[testing purposes](https://github.com/Frameright/php-image-metadata-parser/issues/25)

tests/Fixtures/multipleRdfDesc.jpg

5 MB
Loading

tests/Metadata/XmpTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,45 @@ public function testGetImageRegionFromImageResavedWithPhotoshop()
454454
);
455455
}
456456

457+
/**
458+
* @covers ::getImageRegions
459+
*
460+
* The RDF/XML structure might contain several instances of
461+
* <rdf:Description xmlns:Iptc4xmpExt="...">. This test validates that we
462+
* find the image regions even when they are not located in the first
463+
* <rdf:Description> element.
464+
*
465+
* See https://github.com/Frameright/php-image-metadata-parser/issues/25
466+
*/
467+
public function testGetImageRegionFromImageWithMultipleRdfDescriptions()
468+
{
469+
$jpeg = JPEG::fromFile(
470+
__DIR__ . '/../Fixtures/multipleRdfDesc.jpg');
471+
472+
$xmp = $jpeg->getXmp();
473+
474+
$expectedFirstRegion = new ImageRegion();
475+
$expectedFirstRegion->regionDefinitionId = 'definition-0dae7c70-f936-49ad-80d2-a9f0f6c0fcdb';
476+
$expectedFirstRegion->regionName = '1:1 Square (Common sizes)';
477+
$expectedFirstRegion->id = 'crop-0fd40a5b-ad5f-4b29-9ab2-43afc21b44a6';
478+
$expectedFirstRegion->names = null;
479+
$expectedFirstRegion->types = null;
480+
$expectedFirstRegion->roles = [
481+
'http://cv.iptc.org/newscodes/imageregionrole/cropping',
482+
];
483+
$expectedFirstRegion->rbShape = 'rectangle';
484+
$expectedFirstRegion->rbUnit = 'relative';
485+
$expectedFirstRegion->rbXY = new Point(0.11890472618154539, 0.13225);
486+
$expectedFirstRegion->rbRx = null;
487+
$expectedFirstRegion->rbH = '0.4785';
488+
$expectedFirstRegion->rbW = '0.7179294823705926';
489+
490+
$this->assertEquals(
491+
$expectedFirstRegion,
492+
$xmp->getImageRegions()[0]
493+
);
494+
}
495+
457496
/**
458497
* @param Xmp $xmp
459498
*/

0 commit comments

Comments
 (0)