X-Git-Url: https://scm.cri.ensmp.fr/git/Photo.git/blobdiff_plain/b0a7e10b4f32cf74864bb53268ca4d3080f23bc0..6c41809185e322ce2d30e98234f71144f78f06c0:/xmputils.py diff --git a/xmputils.py b/xmputils.py deleted file mode 100755 index 37b3e6a..0000000 --- a/xmputils.py +++ /dev/null @@ -1,354 +0,0 @@ -# -*- coding: utf-8 -*- -####################################################################################### -# Photo is a part of Plinn - http://plinn.org # -# Copyright (C) 2008 Benoît PIN # -# # -# This program is free software; you can redistribute it and/or # -# modify it under the terms of the GNU General Public License # -# as published by the Free Software Foundation; either version 2 # -# of the License, or (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program; if not, write to the Free Software # -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # -####################################################################################### -""" XMP generation utilities. - - - -""" - -from libxml2 import newNode, parseDoc, treeError -# prefix <-> namespaces mappings as defined in the official xmp documentation -from standards.xmp import namespaces as xmpNs2Prefix -from standards.xmp import prefix2Ns as xmpPrefix2Ns - -TIFF_ORIENTATIONS = {1 : (0, False) - ,2 : (0, True) - ,3 : (180, False) - ,4 : (180, True) - ,5 : (90, True) - ,6 : (90, False) - ,7 : (270, True) - ,8 : (270, False)} - -def _getRDFArrayValues(node, arrayType): - values = [] - for element in iterElementChilds(node): - if element.name == arrayType and element.ns().content == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' : - for value in iterElementChilds(element): - if value.name == 'li': - values.append(value.content) - return tuple(values) - else : - raise ValueError("No %s found" % arrayType ) - -def getBagValues(node): - return _getRDFArrayValues(node, 'Bag') - -def getSeqValues(node): - return _getRDFArrayValues(node, 'Seq') - - -def createRDFAlt(surrounded, defaultText, rootIndex): - """ - returns (as libxml2 node): - - - defaultText - - - """ - docNs = rootIndex.getDocumentNs() - rdfPrefix = docNs['http://www.w3.org/1999/02/22-rdf-syntax-ns#'] - normalizedPrefix, name = surrounded.split(':') - ns = xmpPrefix2Ns[normalizedPrefix] - actualPrefix = docNs[ns] - - surrounded = newNode('%s:%s' % (actualPrefix, name)) - alt = newNode('%s:Alt' % rdfPrefix) - li = newNode('%s:li' % rdfPrefix) - li.newProp('xml:lang', 'x-default') - li.setContent(defaultText) - - reduce(lambda a, b: a.addChild(b), (surrounded, alt, li)) - - return surrounded - - -def createRDFBag(surrounded, values, rootIndex): - """ - returns (as libxml2 node): - - - values[0] - ... - values[n] - - - """ - return _createRDFArray(surrounded, values, False, rootIndex) - -def createRDFSeq(surrounded, values, rootIndex): - """ - returns (as libxml2 node): - - - values[0] - ... - values[n] - - - """ - return _createRDFArray(surrounded, values, True, rootIndex) - -def _createRDFArray(surrounded, values, ordered, rootIndex): - docNs = rootIndex.getDocumentNs() - rdfPrefix = docNs['http://www.w3.org/1999/02/22-rdf-syntax-ns#'] - normalizedPrefix, name = surrounded.split(':') - ns = xmpPrefix2Ns[normalizedPrefix] - actualPrefix = docNs[ns] - - - surrounded = newNode('%s:%s' % (actualPrefix, name)) - if ordered is True : - array = newNode('%s:Seq' % rdfPrefix) - elif ordered is False : - array = newNode('%s:Bag' % rdfPrefix) - else : - raise ValueError("'ordered' parameter must be a boolean value") - - surrounded.addChild(array) - - for v in values : - li = newNode('%s:li' % rdfPrefix) - li.setContent(v) - array.addChild(li) - - return surrounded - -def createEmptyXmpDoc() : - emptyDocument = """ - - - - - - """ - d = parseDoc(emptyDocument) - return d - -def getPathIndex(doc) : - root = doc.getRootElement() - index = PathIndex(root) - return index - - -class PathIndex : - """\ - Class used to provide a convenient tree access to xmp properties by paths. - Issues about namespaces and prefixes are normalized during the object - instanciation. Ns prefixes used to access elements are those recommended in the - official xmp documentation from Adobe. - """ - - def __init__(self, element, parent=None) : - self.unique = True - self.element = element - self.parent = parent - - elementNs = element.ns().content - elementPrefix = element.ns().name - recommendedPrefix = xmpNs2Prefix.get(elementNs, elementPrefix) - - self.name = '%s:%s' % (recommendedPrefix, element.name) - self.namespace = elementNs - self.prefix = elementPrefix - self._index = {} - - for prop in iterElementProperties(element) : - self.addChildIndex(prop) - - for child in iterElementChilds(element) : - self.addChildIndex(child) - - if self.parent is None: - self.nsDeclarations = self._namespaceDeclarations() - - def addChildIndex(self, child) : - ns = child.ns() - if not ns : - return - - childNs = ns.content - childPrefix = ns.name - childRecommendedPrefix = xmpNs2Prefix.get(childNs, childPrefix) - childName = '%s:%s' % (childRecommendedPrefix, child.name) - - if not self._index.has_key(childName) : - self._index[childName] = PathIndex(child, parent=self) - else : - childIndex = self._index[childName] - childIndex.unique = False - for prop in iterElementProperties(child) : - childIndex.addChildIndex(prop) - - for c in iterElementChilds(child) : - childIndex.addChildIndex(c) - - self._index[childName].parent = self - return self._index[childName] - - def _namespaceDeclarations(self) : - """\ - returns ns / prefix pairs as found in xmp packet - """ - namespaces = {} - namespaces[self.namespace] = self.prefix - for child in self._index.values() : - for namespace, prefix in child._namespaceDeclarations().items() : - if namespaces.has_key(namespace) : - assert namespaces[namespace] == prefix, \ - "using several prefix for the same namespace is forbidden "\ - "in this implementation" - else : - namespaces[namespace] = prefix - return namespaces - - def getDocumentNs(self) : - root = self.getRootIndex() - return root.nsDeclarations - - def exists(self, path) : - o = self - for part in path.split('/') : - if o._index.has_key(part) : - o = o._index[part] - else : - return False - return True - - def __getitem__(self, path) : - o = self - try : - for part in path.split('/') : - if part == '.' : - continue - elif part == '..' : - o = o.parent - o = o._index[part] - except ValueError : - raise KeyError, path - return o - - def get(self, path, default=None) : - try : - return self[path] - except KeyError : - return default - - def getRootIndex(self) : - root = self - while root.parent is not None : - root = root.parent - return root - - def createChildAndIndex(self, name, rdfType, nsDeclarationElement) : - recommandedPrefix, name = name.split(':', 1) - - if rdfType == 'prop' : - try : - node = self.element.newProp(name, '') - except treeError : - raise ValueError, (self.element, name) - else : - node = newNode(name) - self.element.addChild(node) - - # bind namespace to new node - uri = xmpPrefix2Ns[recommandedPrefix] - docNamespaces = self.getDocumentNs() - if not docNamespaces.has_key(uri) : - try : - ns = nsDeclarationElement.newNs(uri, recommandedPrefix) - except treeError : - raise ValueError, (uri, prefix, self.element, list(nsDeclarationElement.nsDefs())) - docNamespaces[uri] = recommandedPrefix - else : - actualPrefix = docNamespaces[uri] - try : - ns = self.element.searchNs(None, actualPrefix) - except treeError: - # cas d'un xmp verbeux : le nouvel élément n'est pas ajouté - # dans le rdf:Description du ns correspondant - # (après tout, ce n'est pas une obligation) - # => on ajoute le ns - ns = nsDeclarationElement.newNs(uri, actualPrefix) - - - node.setNs(ns) - return self.addChildIndex(node) - - def getOrCreate(self, path, rdfType, preferedNsDeclaration='rdf:RDF/rdf:Description') : - parts = path.split('/') - - if not parts : - return self - - name = parts[-1] - parts = parts[:-1] - root = self.getRootIndex() - nsDeclarationElement = root[preferedNsDeclaration].element - - parent = self - for p in parts : - child = parent._index.get(p, None) - if child is None : - child = parent.createChildAndIndex(p, None, nsDeclarationElement) - parent = child - - child = parent._index.get(name, None) - if child is None : - child = parent.createChildAndIndex(name, rdfType, nsDeclarationElement) - - return child - - def __str__(self) : - out = [] - pr = out.append - path = [self.name] - parent = self.parent - while parent : - path.append(parent.name) - parent = parent.parent - path.reverse() - path = '/'.join(path) - pr(path) - pr(self.name) - pr(self.namespace) - pr(str(self.unique)) - pr('-------') - - for child in self._index.values() : - pr(str(child)) - - return '\n'.join(out) - -def iterElementChilds(parent) : - child = parent.children - while child : - if child.type == 'element' : - yield child - child = child.next - -def iterElementProperties(element) : - prop = element.properties - while prop : - if prop.type == 'attribute' : - yield prop - prop = prop.next