Skip to content

Commit

Permalink
Merge pull request #302 from jim-easterbrook/devel
Browse files Browse the repository at this point in the history
Devel
  • Loading branch information
jim-easterbrook authored Dec 17, 2024
2 parents 18784c0 + 1f29cbf commit 335cc5a
Show file tree
Hide file tree
Showing 7 changed files with 451 additions and 117 deletions.
54 changes: 27 additions & 27 deletions src/photini/cv.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,101 +7,101 @@
# http://cv.iptc.org/newscodes/imageregiontype/
image_region_types = \
({'data': {'Iptc4xmpExt:Name': {'en-GB': 'animal'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/animal']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/animal',)},
'definition': {'en-GB': 'A living organism different from humans or flora'},
'name': {'en-GB': 'animal'},
'note': {},
'qcode': 'imgregtype:animal'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'artwork'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/artwork']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/artwork',)},
'definition': {'en-GB': 'Artistic work'},
'name': {'en-GB': 'artwork'},
'note': {},
'qcode': 'imgregtype:artwork'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'dividing line'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/dividingLine']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/dividingLine',)},
'definition': {'en-GB': 'A line expressing a visual division of the image, '
'such as a horizon'},
'name': {'en-GB': 'dividing line'},
'note': {},
'qcode': 'imgregtype:dividingLine'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'plant'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/plant']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/plant',)},
'definition': {'en-GB': 'A living organism different from humans and '
'animals'},
'name': {'en-GB': 'plant'},
'note': {},
'qcode': 'imgregtype:plant'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'geographic area'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/geoArea']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/geoArea',)},
'definition': {'en-GB': 'A named area on the surface of the planet earth'},
'name': {'en-GB': 'geographic area'},
'note': {'en-GB': 'Specific details of the area can be expressed by other '
'metadata'},
'qcode': 'imgregtype:geoArea'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'graphic'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/graphic']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/graphic',)},
'definition': {'en-GB': 'A graphic representation of information'},
'name': {'en-GB': 'graphic'},
'note': {},
'qcode': 'imgregtype:graphic'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'machine-readable code'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/machineCode']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/machineCode',)},
'definition': {'en-GB': 'Optical label such as barcode or QR code'},
'name': {'en-GB': 'machine-readable code'},
'note': {},
'qcode': 'imgregtype:machineCode'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'human'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/human']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/human',)},
'definition': {'en-GB': 'A human being'},
'name': {'en-GB': 'human'},
'note': {},
'qcode': 'imgregtype:human'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'product'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/product']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/product',)},
'definition': {'en-GB': 'A thing that was produced and can be handed over'},
'name': {'en-GB': 'product'},
'note': {},
'qcode': 'imgregtype:product'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'text'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/text']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/text',)},
'definition': {'en-GB': 'Human readable script of any language'},
'name': {'en-GB': 'text'},
'note': {},
'qcode': 'imgregtype:text'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'building'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/building']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/building',)},
'definition': {'en-GB': 'A structure with walls and roof in most cases'},
'name': {'en-GB': 'building'},
'note': {},
'qcode': 'imgregtype:building'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'vehicle'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/vehicle']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/vehicle',)},
'definition': {'en-GB': 'An object used for transporting something, like '
'car, train, ship, plane or bike'},
'name': {'en-GB': 'vehicle'},
'note': {},
'qcode': 'imgregtype:vehicle'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'food'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/food']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/food',)},
'definition': {'en-GB': 'Substances providing nutrition for a living body'},
'name': {'en-GB': 'food'},
'note': {},
'qcode': 'imgregtype:food'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'clothing'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/clothing']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/clothing',)},
'definition': {'en-GB': 'Something worn to cover the body'},
'name': {'en-GB': 'clothing'},
'note': {},
'qcode': 'imgregtype:clothing'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'rock formation'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/rockFormation']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/rockFormation',)},
'definition': {'en-GB': 'A special formation of stone mass'},
'name': {'en-GB': 'rock formation'},
'note': {},
'qcode': 'imgregtype:rockFormation'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'body of water'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregiontype/bodyOfWater']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregiontype/bodyOfWater',)},
'definition': {'en-GB': 'A significant accumulation of water'},
'name': {'en-GB': 'body of water'},
'note': {'en-GB': 'Including a waterfall, a geyser and other phenomena of '
Expand Down Expand Up @@ -132,75 +132,75 @@
# http://cv.iptc.org/newscodes/imageregionrole/
image_region_roles = \
({'data': {'Iptc4xmpExt:Name': {'en-GB': 'cropping'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregionrole/cropping']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregionrole/cropping',)},
'definition': {'en-GB': 'Image region can be used for any cropping'},
'name': {'en-GB': 'cropping'},
'note': {},
'qcode': 'imgregrole:cropping'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'recommended cropping'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregionrole/recomCropping']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregionrole/recomCropping',)},
'definition': {'en-GB': 'Image region is recommended for cropping'},
'name': {'en-GB': 'recommended cropping'},
'note': {},
'qcode': 'imgregrole:recomCropping'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'landscape format cropping'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregionrole/landscapeCropping']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregionrole/landscapeCropping',)},
'definition': {'en-GB': 'Image region suggested for cropping in landscape '
'format'},
'name': {'en-GB': 'landscape format cropping'},
'note': {'en-GB': 'Use for images of non-landscape format'},
'qcode': 'imgregrole:landscapeCropping'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'portrait format cropping'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregionrole/portraitCropping']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregionrole/portraitCropping',)},
'definition': {'en-GB': 'Image region suggested for cropping in portrait '
'format'},
'name': {'en-GB': 'portrait format cropping'},
'note': {'en-GB': 'Use for images of non-portrait format'},
'qcode': 'imgregrole:portraitCropping'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'square format cropping'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregionrole/squareCropping']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregionrole/squareCropping',)},
'definition': {'en-GB': 'Image region suggested for cropping in square '
'format'},
'name': {'en-GB': 'square format cropping'},
'note': {},
'qcode': 'imgregrole:squareCropping'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'composite image item'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregionrole/compositeImageItem']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregionrole/compositeImageItem',)},
'definition': {'en-GB': 'Image region of an item in a composite image'},
'name': {'en-GB': 'composite image item'},
'note': {},
'qcode': 'imgregrole:compositeImageItem'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'copyright region'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregionrole/copyrightRegion']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregionrole/copyrightRegion',)},
'definition': {'en-GB': 'Image region with a copyright different from the '
'copyright of the whole picture'},
'name': {'en-GB': 'copyright region'},
'note': {},
'qcode': 'imgregrole:copyrightRegion'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'subject area'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregionrole/subjectArea']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregionrole/subjectArea',)},
'definition': {'en-GB': 'Image region contains a subject in the overall '
'scene.'},
'name': {'en-GB': 'subject area'},
'note': {'en-GB': 'Multiple regions of an image may be set as subject area.'},
'qcode': 'imgregrole:subjectArea'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'main subject area'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregionrole/mainSubjectArea']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregionrole/mainSubjectArea',)},
'definition': {'en-GB': 'Image region contains the main subject in the '
'overall scene. Same as the Exif SubjectArea.'},
'name': {'en-GB': 'main subject area'},
'note': {'en-GB': 'Only a single region of an image may be set as main '
'subject area.'},
'qcode': 'imgregrole:mainSubjectArea'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'area of interest'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregionrole/areaOfInterest']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregionrole/areaOfInterest',)},
'definition': {'en-GB': 'Image region contains a thing of special interest '
'to the viewer'},
'name': {'en-GB': 'area of interest'},
'note': {},
'qcode': 'imgregrole:areaOfInterest'},
{'data': {'Iptc4xmpExt:Name': {'en-GB': 'business use'},
'xmp:Identifier': ['http://cv.iptc.org/newscodes/imageregionrole/businessUse']},
'xmp:Identifier': ('http://cv.iptc.org/newscodes/imageregionrole/businessUse',)},
'definition': {'en-GB': 'Image region is dedicated to a specific business '
'use'},
'name': {'en-GB': 'business use'},
Expand Down
12 changes: 10 additions & 2 deletions src/photini/exiv2.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Photini - a simple photo metadata editor.
## http://github.com/jim-easterbrook/Photini
## Copyright (C) 2012-23 Jim Easterbrook jim@jim-easterbrook.me.uk
## Copyright (C) 2012-24 Jim Easterbrook jim@jim-easterbrook.me.uk
##
## This program is free software: you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
Expand Down Expand Up @@ -486,7 +486,7 @@ def set_item(self, result, key, value):
else:
result[root] = value

def get_xmp_value(self, tag):
def get_xmp_value(self, tag, see_also_count=2):
# XMP has a nested structure of arbitrary depth. Exiv2 converts
# this to "flat" tag names. This method converts back to nested
# dicts and lists.
Expand All @@ -511,6 +511,14 @@ def get_xmp_value(self, tag):
array_type = value.xmpArrayType()
if array_type == exiv2.XmpValue.XmpArrayType.xaNone:
value = str(value)
if key.endswith('/rdfs:seeAlso'):
if see_also_count > 0:
sub_key = 'Xmp.' + value.replace(':', '.')
sub_key = sub_key.replace('Iptc4xmpExt', 'iptcExt')
value = {value: self.get_xmp_value(
sub_key, see_also_count=see_also_count-1)}
else:
value = {}
else:
value = []
type_id = {
Expand Down
3 changes: 2 additions & 1 deletion src/photini/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,8 @@ def get_all_tags(self):
'headline' : (('WA', 'Xmp.photoshop.Headline'),
('WA', 'Iptc.Application2.Headline')),
'image_region' : (('WN', 'Exif.Photo.SubjectArea'),
('WA', 'Xmp.iptcExt.ImageRegion')),
('WA', 'Xmp.iptcExt.ImageRegion'),
('WA', 'Xmp.mwg-rs.Regions')),
'instructions' : (('WA', 'Xmp.photoshop.Instructions'),
('WA', 'Iptc.Application2.SpecialInstructions')),
'keywords' : (('WA', 'Xmp.dc.subject'),
Expand Down
4 changes: 2 additions & 2 deletions src/photini/pyqt.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,12 @@
else:
qt_version_info = namedtuple(
'qt_version_info', ('major', 'minor', 'micro'))._make(
map(int, QtCore.QT_VERSION_STR.split('.')))
map(int, QtCore.QT_VERSION_STR.split('.')[:3]))
qt_version = 'PyQt {}, Qt {}'.format(
QtCore.PYQT_VERSION_STR, QtCore.QT_VERSION_STR)
pyqt_version_info = namedtuple(
'pyqt_version_info', ('major', 'minor', 'micro'))._make(
map(int, QtCore.PYQT_VERSION_STR.split('.')))
map(int, QtCore.PYQT_VERSION_STR.split('.')[:3]))
if pyqt_version_info < (5, 11):
raise ImportError(
'PyQt version {}.{}.{} is less than 5.11'.format(*pyqt_version_info))
Expand Down
Loading

0 comments on commit 335cc5a

Please # to comment.