diff --git a/src/Metadata/Xmp.php b/src/Metadata/Xmp.php index fa163f7..4911045 100644 --- a/src/Metadata/Xmp.php +++ b/src/Metadata/Xmp.php @@ -158,6 +158,8 @@ public static function fromFile($fileName) } /** + * Returns the first node (element or attribute) with the given field name and namespace. + * * @param $field * @param $ns * @param bool $checkAttributes @@ -166,14 +168,15 @@ public static function fromFile($fileName) */ private function getNode($field, $ns, $checkAttributes = true) { - $rdfDesc = $this->getRDFDescription($ns); - // check for field as an element or an attribute $query = ($checkAttributes)? $field . '|@' . $field: $field; - $result = $this->xpath->query($query, $rdfDesc); - if ($result->length) { - return $result->item(0); + $rdfDescriptions = $this->getRDFDescriptions($ns); + foreach($rdfDescriptions as $rdfDesc) { + $result = $this->xpath->query($query, $rdfDesc); + if ($result->length) { + return $result->item(0); + } } return null; @@ -267,29 +270,28 @@ private function getSeq($field, $namespace) return null; } - /** + * Returns all `rdf:Description` elements with the given namespace. + * * @param $namespace * - * @return \DOMNode|null + * @return array Array of \DOMNode */ - private function getRDFDescription($namespace) + private function getRDFDescriptions($namespace) { - // element - $description = $this->xpath->query("//rdf:Description[*[namespace-uri()='$namespace']]"); - - if ($description->length > 0) { - return $description->item(0); - } + $result = []; - // attribute - $description = $this->xpath->query("//rdf:Description[@*[namespace-uri()='$namespace']]"); + $element_query = "//rdf:Description[*[namespace-uri()='$namespace']]"; + $attribute_query = "//rdf:Description[@*[namespace-uri()='$namespace']]"; + foreach([$element_query, $attribute_query] as $query) { + $description = $this->xpath->query($query); - if ($description->length > 0) { - return $description->item(0); + if ($description->length > 0) { + $result = array_merge($result, iterator_to_array($description)); + } } - return null; + return $result; } /** diff --git a/tests/Metadata/XmpTest.php b/tests/Metadata/XmpTest.php index 58ac971..b668979 100644 --- a/tests/Metadata/XmpTest.php +++ b/tests/Metadata/XmpTest.php @@ -454,6 +454,49 @@ public function testGetImageRegionFromImageResavedWithPhotoshop() ); } + /** + * @covers ::getImageRegions + * + * The RDF/XML structure might contain several instances of + * . This test validates that we + * find the image regions even when they are not located in the first + * element. + * + * See https://github.com/Frameright/php-image-metadata-parser/issues/25 + */ + public function testGetImageRegionFromImageWithMultipleRdfDescriptions() + { + // FIXME This test is disabled because we need a corresponding test fixture. + // See https://github.com/Frameright/php-image-metadata-parser/issues/25 + return true; + + $jpeg = JPEG::fromFile( + __DIR__ . '/../Fixtures/multipleRdfDesc.jpg'); + + $xmp = $jpeg->getXmp(); + + $expectedFirstRegion = new ImageRegion(); + $expectedFirstRegion->regionDefinitionId = 'definition-0dae7c70-f936-49ad-80d2-a9f0f6c0fcdb'; + $expectedFirstRegion->regionName = '1:1 Square (Common sizes)'; + $expectedFirstRegion->id = 'crop-0fd40a5b-ad5f-4b29-9ab2-43afc21b44a6'; + $expectedFirstRegion->names = null; + $expectedFirstRegion->types = null; + $expectedFirstRegion->roles = [ + 'http://cv.iptc.org/newscodes/imageregionrole/cropping', + ]; + $expectedFirstRegion->rbShape = 'rectangle'; + $expectedFirstRegion->rbUnit = 'relative'; + $expectedFirstRegion->rbXY = new Point(0.11890472618154539, 0.13225); + $expectedFirstRegion->rbRx = null; + $expectedFirstRegion->rbH = '0.4785'; + $expectedFirstRegion->rbW = '0.7179294823705926'; + + $this->assertEquals( + $expectedFirstRegion, + $xmp->getImageRegions()[0] + ); + } + /** * @param Xmp $xmp */