Skip to content

Commit f6b4677

Browse files
committed
Refactoring: move image-region-related classes to dedicated files
1 parent c7a582d commit f6b4677

File tree

5 files changed

+341
-324
lines changed

5 files changed

+341
-324
lines changed

src/Metadata/Xmp.php

Lines changed: 6 additions & 324 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<?php
22
namespace CSD\Image\Metadata;
33

4-
use CSD\Image\Metadata\UnsupportedException;
4+
use CSD\Image\Metadata\Xmp\ImageRegion;
5+
use CSD\Image\Metadata\Xmp\RoleFilter;
6+
use CSD\Image\Metadata\Xmp\ShapeFilter;
57

68
/**
79
* Class to read XMP metadata from an image.
@@ -1403,11 +1405,10 @@ public function setFeaturedOrganisationCode($featuredOrganisationCode)
14031405
* @param string $roleFilter
14041406
*
14051407
* @return array
1406-
* @throws UnsupportedException
14071408
*/
14081409
public function getImageRegions(
1409-
$shapeFilter = XmpShapeFilter::ANY,
1410-
$roleFilter = XmpRoleFilter::ANY)
1410+
$shapeFilter = ShapeFilter::ANY,
1411+
$roleFilter = RoleFilter::ANY)
14111412
{
14121413
$imageRegionNode = $this->getNode(
14131414
'Iptc4xmpExt:ImageRegion',
@@ -1426,7 +1427,7 @@ public function getImageRegions(
14261427

14271428
$results = [];
14281429
foreach ($imageRegionBag->childNodes as $imageRegionItem) {
1429-
$imageRegion = new XmpImageRegion($this->xpath, $imageRegionItem);
1430+
$imageRegion = new ImageRegion($this->xpath, $imageRegionItem);
14301431
array_push($results, $imageRegion);
14311432
}
14321433

@@ -1451,322 +1452,3 @@ public function hasChanges()
14511452
return $this->hasChanges;
14521453
}
14531454
}
1454-
1455-
/**
1456-
* PHP5 enum.
1457-
*/
1458-
abstract class XmpShapeFilter
1459-
{
1460-
const ANY = '';
1461-
const RECTANGLE = 'rectangle';
1462-
const CIRCLE = 'circle';
1463-
const POLYGON = 'polygon';
1464-
1465-
/**
1466-
* @param string $value RECTANGLE, CIRCLE or POLYGON.
1467-
*
1468-
* @return string The corresponding value of the <Iptc4xmpExt:rbShape>
1469-
* element.
1470-
* @throws UnsupportedException
1471-
*/
1472-
public static function getXmlRbShape($value)
1473-
{
1474-
switch ($value) {
1475-
case self::RECTANGLE:
1476-
case self::CIRCLE:
1477-
case self::POLYGON:
1478-
return $value;
1479-
}
1480-
throw new UnsupportedException('Unsupported region shape');
1481-
}
1482-
}
1483-
1484-
/**
1485-
* PHP5 enum.
1486-
*/
1487-
abstract class XmpRoleFilter
1488-
{
1489-
const ANY = '';
1490-
const CROP = 'crop';
1491-
1492-
/**
1493-
* @param string $value CROP.
1494-
*
1495-
* @return array The list of <Iptc4xmpExt:rRole><Iptc4xmpExt:Name> or
1496-
* <Iptc4xmpExt:rRole><Iptc4xmpExt:Identifier> values
1497-
* that would match the filter.
1498-
* @throws UnsupportedException
1499-
*/
1500-
public static function getMatchingXmlRoles($value)
1501-
{
1502-
switch ($value) {
1503-
case self::CROP:
1504-
// See https://cv.iptc.org/newscodes/imageregionrole/
1505-
return [
1506-
'cropping',
1507-
'recommended cropping',
1508-
'landscape format cropping',
1509-
'portrait format cropping',
1510-
'square format cropping',
1511-
'http://cv.iptc.org/newscodes/imageregionrole/cropping',
1512-
'http://cv.iptc.org/newscodes/imageregionrole/recomCropping',
1513-
'http://cv.iptc.org/newscodes/imageregionrole/landscapeCropping',
1514-
'http://cv.iptc.org/newscodes/imageregionrole/portraitCropping',
1515-
'http://cv.iptc.org/newscodes/imageregionrole/squareCropping',
1516-
];
1517-
}
1518-
throw new UnsupportedException('Unsupported region role filter');
1519-
}
1520-
}
1521-
1522-
/**
1523-
* Represents an Image Region read from XMP metadata.
1524-
* See https://iptc.org/std/photometadata/specification/IPTC-PhotoMetadata#image-region
1525-
*/
1526-
class XmpImageRegion
1527-
{
1528-
/**
1529-
* @var string|null
1530-
*/
1531-
public $id;
1532-
1533-
/**
1534-
* @var array|null
1535-
*/
1536-
public $names;
1537-
1538-
/**
1539-
* @var array|null
1540-
*/
1541-
public $types;
1542-
1543-
/**
1544-
* @var array|null
1545-
*/
1546-
public $roles;
1547-
1548-
/**
1549-
* 'rectangle', 'circle' or 'polygon'.
1550-
*
1551-
* @var string|null
1552-
*/
1553-
public $rbShape;
1554-
1555-
/**
1556-
* E.g. 'relative'.
1557-
*
1558-
* @var string|null
1559-
*/
1560-
public $rbUnit;
1561-
1562-
/**
1563-
* Rectangle or circle's coordinates.
1564-
*
1565-
* @var XmpImageRegionPoint
1566-
*/
1567-
public $rbXY;
1568-
1569-
/**
1570-
* Rectangle's height.
1571-
*
1572-
* @var string|null
1573-
*/
1574-
public $rbH;
1575-
1576-
/**
1577-
* Rectangle's width.
1578-
*
1579-
* @var string|null
1580-
*/
1581-
public $rbW;
1582-
1583-
/**
1584-
* Circle's radius.
1585-
*
1586-
* @var string|null
1587-
*/
1588-
public $rbRx;
1589-
1590-
/**
1591-
* Polygon's vertices.
1592-
*
1593-
* @var array|null
1594-
*/
1595-
public $rbVertices;
1596-
1597-
/**
1598-
* @param \DOMXPath $xpath
1599-
* @param \DOMNode $node <rdf:li> node.
1600-
*/
1601-
public function __construct($xpath, $node)
1602-
{
1603-
$this->id = self::getNodeValue($xpath, 'Iptc4xmpExt:rId', $node);
1604-
$this->names = self::getNodeValues(
1605-
$xpath,
1606-
'Iptc4xmpExt:Name/rdf:Alt/rdf:li',
1607-
$node
1608-
);
1609-
$this->types = self::getEntityOrConceptValues(
1610-
$xpath,
1611-
'Iptc4xmpExt:rCtype',
1612-
$node
1613-
);
1614-
$this->roles = self::getEntityOrConceptValues(
1615-
$xpath,
1616-
'Iptc4xmpExt:rRole',
1617-
$node
1618-
);
1619-
1620-
$xpathToRb = 'Iptc4xmpExt:RegionBoundary';
1621-
1622-
foreach ([
1623-
'rbShape',
1624-
'rbUnit',
1625-
'rbH',
1626-
'rbW',
1627-
'rbRx',
1628-
] as $property) {
1629-
$this->$property = self::getNodeValue(
1630-
$xpath,
1631-
"$xpathToRb/Iptc4xmpExt:$property",
1632-
$node
1633-
);
1634-
}
1635-
1636-
$this->rbXY = new XmpImageRegionPoint(
1637-
self::getNodeValue($xpath, "$xpathToRb/Iptc4xmpExt:rbX", $node),
1638-
self::getNodeValue($xpath, "$xpathToRb/Iptc4xmpExt:rbY", $node)
1639-
);
1640-
1641-
$verticesNodes = $xpath->query(
1642-
"$xpathToRb/Iptc4xmpExt:rbVertices/rdf:Seq/rdf:li",
1643-
$node
1644-
);
1645-
if ($verticesNodes->length) {
1646-
$this->rbVertices = [];
1647-
foreach ($verticesNodes as $verticesNode) {
1648-
$point = new XmpImageRegionPoint(
1649-
self::getNodeValue($xpath, "Iptc4xmpExt:rbX", $verticesNode),
1650-
self::getNodeValue($xpath, "Iptc4xmpExt:rbY", $verticesNode)
1651-
);
1652-
array_push($this->rbVertices, $point);
1653-
}
1654-
}
1655-
}
1656-
1657-
/**
1658-
* @param string $filter One of the XmpShapeFilter constants.
1659-
*
1660-
* @return bool
1661-
*/
1662-
public function matchesShapeFilter($filter) {
1663-
return (
1664-
$filter === XmpShapeFilter::ANY ||
1665-
XmpShapeFilter::getXmlRbShape($filter) === $this->rbShape
1666-
);
1667-
}
1668-
1669-
/**
1670-
* @param string $filter One of the XmpRoleFilter constants.
1671-
*
1672-
* @return bool
1673-
*/
1674-
public function matchesRoleFilter($filter) {
1675-
return (
1676-
$filter === XmpRoleFilter::ANY ||
1677-
count(array_intersect(
1678-
XmpRoleFilter::getMatchingXmlRoles($filter),
1679-
$this->roles
1680-
)) > 0
1681-
);
1682-
}
1683-
1684-
/**
1685-
* @param \DOMXPath $xpath
1686-
* @param string $expression XPath expression leading to one single node.
1687-
* @param \DOMNode $contextNode
1688-
*
1689-
* @return string|null
1690-
*/
1691-
private static function getNodeValue($xpath, $expression, $contextNode) {
1692-
$node = $xpath->query($expression, $contextNode)->item(0);
1693-
return $node ? $node->nodeValue : null;
1694-
}
1695-
1696-
/**
1697-
* @param \DOMXPath $xpath
1698-
* @param string $expression XPath expression leading to several nodes.
1699-
* @param \DOMNode $contextNode
1700-
*
1701-
* @return array|null
1702-
*/
1703-
private static function getNodeValues($xpath, $expression, $contextNode) {
1704-
$nodes = $xpath->query($expression, $contextNode);
1705-
if (!$nodes->length) {
1706-
return null;
1707-
}
1708-
1709-
$result = [];
1710-
foreach ($nodes as $node) {
1711-
array_push($result, $node->nodeValue);
1712-
}
1713-
return $result;
1714-
}
1715-
1716-
/**
1717-
* See https://iptc.org/std/photometadata/specification/IPTC-PhotoMetadata#entity-or-concept-structure
1718-
*
1719-
* @param \DOMXPath $xpath
1720-
* @param string $expression XPath expression leading to the parent of an
1721-
* <rdf:Bag> of an Identity or Concept structure.
1722-
* @param \DOMNode $contextNode
1723-
*
1724-
* @return array|null
1725-
*/
1726-
private static function getEntityOrConceptValues(
1727-
$xpath,
1728-
$expression,
1729-
$contextNode
1730-
) {
1731-
$names = self::getNodeValues(
1732-
$xpath,
1733-
"$expression/rdf:Bag/rdf:li/Iptc4xmpExt:Name/rdf:Alt/rdf:li",
1734-
$contextNode
1735-
);
1736-
$identifiers = self::getNodeValues(
1737-
$xpath,
1738-
"$expression/rdf:Bag/rdf:li/xmp:Identifier/rdf:Bag/rdf:li",
1739-
$contextNode
1740-
);
1741-
1742-
if (!$names) {
1743-
return $identifiers;
1744-
}
1745-
if (!$identifiers) {
1746-
return $names;
1747-
}
1748-
return array_merge($names, $identifiers);
1749-
}
1750-
}
1751-
1752-
/**
1753-
* (X, Y) pair of coordinates.
1754-
*/
1755-
class XmpImageRegionPoint
1756-
{
1757-
/**
1758-
* @var string|null
1759-
*/
1760-
public $rbX;
1761-
1762-
/**
1763-
* @var string|null
1764-
*/
1765-
public $rbY;
1766-
1767-
public function __construct($x, $y)
1768-
{
1769-
$this->rbX = $x;
1770-
$this->rbY = $y;
1771-
}
1772-
}

0 commit comments

Comments
 (0)