X-Git-Url: https://scm.cri.minesparis.psl.eu/git/Photo.git/blobdiff_plain/b0a7e10b4f32cf74864bb53268ca4d3080f23bc0..6c41809185e322ce2d30e98234f71144f78f06c0:/xmp.py?ds=inline diff --git a/xmp.py b/xmp.py deleted file mode 100755 index 8738e50..0000000 --- a/xmp.py +++ /dev/null @@ -1,189 +0,0 @@ -# -*- coding: utf-8 -*- -####################################################################################### -# Photo is a part of Plinn - http://plinn.org # -# Copyright © 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. # -####################################################################################### -# -# - -from types import StringTypes -from logging import getLogger -import re -console = getLogger('Photo.xmp') - -class XMP(object) : - XMP_HEADER = u'' - XMP_HEADER_PATTERN = u'''<\?xpacket begin=['"]\ufeff['"] id=['"]W5M0MpCehiHzreSzNTczkc9d['"][^\?]*\?>''' - XMP_PADDING_LINE = u'\u0020' * 63 + u'\n' - XMP_TRAILER = u'' - - _readers = {} - _writers = {} - - - - def __init__(self, file, content_type='image/jpeg', encoding='utf-8') : - try : - self.reader = self._readers[content_type] - except KeyError: - raise NotImplementedError, "%r content type not supported by XMP" % content_type - - try : - self.writer = self._writers[content_type] - except KeyError : - self.writer = None - console.info('XMP file opened on read-only mode.') - - self.file = file - self.encoding = encoding - self.xmp = None - self._open() - - - def __del__(self) : - try : - self.file.close() - except : - pass - - - def _open(self) : - - if type(self.file) in StringTypes : - self.file = file(self.file) - - packet = self.reader(self.file) - - if packet is not None : - # tests / unwrap - reEncodedHeader = re.compile(self.XMP_HEADER_PATTERN.encode(self.encoding)) - m = reEncodedHeader.match(packet) - if m is None : - console.warn('XMP packet wrapper not found') - self.xmp = packet - return - - xmp = packet[m.end():] - trailer = self.XMP_TRAILER[:-6].encode(self.encoding) # TODO handle read-only mode - trailerPos = xmp.find(trailer) - assert trailerPos != -1, "No xmp trailer found" - - xmp = xmp[:trailerPos] - xmp = xmp.strip() - self.xmp = xmp - else : - self.xmp = None - - def save(self, f=None): - original = self.file - if f : - if type(f) in StringTypes : - new = file(f, 'w') - else : - new = f - elif f is None : - new = self.file - - self.writer(original, new, self.xmp) - - - def getXMP(self) : - return self.xmp - - - def setXMP(self, xmp) : - self.xmp = xmp - - # - # xmp utils - # - - @staticmethod - def getXmpPadding(size) : - # size of trailer in kB - return (XMP.XMP_PADDING_LINE * 32 * size) - - - @staticmethod - def genXMPPacket(uXmpData, paddingSize): - packet = u'' - - packet += XMP.XMP_HEADER - packet += uXmpData - packet += XMP.getXmpPadding(paddingSize) - packet += XMP.XMP_TRAILER - - return packet - - - - # - # content type registry stuff - # - - - @classmethod - def registerReader(cls, content_type, reader) : - cls._readers[content_type] = reader - - @classmethod - def registerWriter(cls, content_type, writer) : - cls._writers[content_type] = writer - - @classmethod - def registerWrapper(cls, content_type, wrapper) : - """ Registers specific wrapper to prepare data - for embedding xmp into specific content_type file. - """ - pass - - - -def test() : - from xml.dom.minidom import parse - data = parse('new.xmp').documentElement.toxml() - - def test1() : - original = 'original.jpg' - modified = 'modified.jpg' - - x = XMP(original) - x.setXMP(data) - x.save(modified) - - def test2() : - from cStringIO import StringIO - sio = StringIO() - sio.write(file('modified.jpg').read()) - sio.seek(0) - - x = XMP(sio) - x.setXMP(data) - x.save() - - f2 = open('modified2.jpg', 'w') - f2.write(sio.read()) - f2.close() - - - test1() - test2() - - - -if __name__ == '__main__' : - test()