From 676aa16d08aa05fb228e45fe77fbb5b51ca32f40 Mon Sep 17 00:00:00 2001 From: Michael Elovskikh Date: Thu, 13 Sep 2012 18:13:19 +0600 Subject: [PATCH 1/4] Added `Image` metadata support Added dict-like `metadata` property to `Image` class. It allows to iterate metadata properties and get their values. --- wand/api.py | 13 +++++++++++++ wand/image.py | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/wand/api.py b/wand/api.py index bbe083ed..a3c87545 100644 --- a/wand/api.py +++ b/wand/api.py @@ -129,6 +129,19 @@ class MagickPixelPacket(ctypes.Structure): library.MagickGetImageSignature.argtypes = [ctypes.c_void_p] library.MagickGetImageSignature.restype = ctypes.c_char_p + library.MagickGetImageProperty.argtypes = [ctypes.c_void_p, ctypes.c_char_p] + library.MagickGetImageProperty.restype = ctypes.c_char_p + + library.MagickGetImageProperties.argtypes = [ctypes.c_void_p, + ctypes.c_char_p, + ctypes.POINTER(ctypes.c_size_t)] + library.MagickGetImageProperties.restype = ctypes.POINTER(ctypes.c_char_p) + + library.MagickSetImageProperty.argtypes = [ctypes.c_void_p, ctypes.c_char_p, + ctypes.c_char_p] + + library.MagickDeleteImageProperty.argtypes = [ctypes.c_void_p, + ctypes.c_char_p] library.MagickGetImageBackgroundColor.argtypes = [ctypes.c_void_p, ctypes.c_void_p] diff --git a/wand/image.py b/wand/image.py index 830fe70b..19d2092f 100644 --- a/wand/image.py +++ b/wand/image.py @@ -460,6 +460,7 @@ def __init__(self, image=None, blob=None, file=None, filename=None, read = True if not read: raise TypeError('invalid argument(s)') + self.metadata = Metadata(self) self.raise_exception() @property @@ -1421,10 +1422,54 @@ def clone(self): """ return type(self)(iterator=self) +import UserDict + + + +class Metadata(collections.Mapping): + """Class that implements dict-like read-only access to image metadata like + EXIF or IPTC headers. + + :param image: An `Image` instance + :type image: :class:`Image` + """ + def __init__(self, image): + if not isinstance(image, Image): + raise TypeError('expected a wand.image.Image instance, ' + 'not ' + repr(image)) + self.image = image + + def __getitem__(self, k): + """ + :param k: Metadata header name string. + :type k: :class:`basestring` + :returns: a header value string + :rtype: :class:`str` + """ + if not isinstance(k, basestring): + raise TypeError('k must be a string, not ' + repr(format)) + + v = library.MagickGetImageProperty(self.image.wand, k) + if v is None: + raise KeyError + return v + + def __iter__(self): + num = ctypes.c_size_t() + props_p = library.MagickGetImageProperties(self.image.wand, '', num) + props = [props_p[i] for i in xrange(num.value)] + library.MagickRelinquishMemory(props_p) + return iter(props) + + def __len__(self): + num = ctypes.c_size_t() + props_p = library.MagickGetImageProperties(self.image.wand, '', num) + library.MagickRelinquishMemory(props_p) + return num.value + class ClosedImageError(DestroyedResourceError): """An error that rises when some code tries access to an already closed image. """ - From ec5b29d2471ef6ecf696614da7d971885f77b3e7 Mon Sep 17 00:00:00 2001 From: Michael Elovskikh Date: Thu, 13 Sep 2012 18:40:33 +0600 Subject: [PATCH 2/4] Metadata support tests --- wandtests/image.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/wandtests/image.py b/wandtests/image.py index 25dd0fac..5db5d318 100644 --- a/wandtests/image.py +++ b/wandtests/image.py @@ -773,3 +773,14 @@ def reset_coords(): msg = 'img = {0!r}, control = {1!r}'.format( img.signature, sig) assert img.signature == sig, msg + + +@tests.test +def metadata(): + """Test metadata api""" + with Image(filename=asset('beach.jpg')) as img: + assert len(img.metadata) == 52 + assert 'exif:ApertureValue' in img.metadata + assert 'exif:UnknownValue' not in img.metadata + assert img.metadata['exif:ApertureValue'] == '192/32' + assert img.metadata.get('exif:UnknownValue', "IDK") == "IDK" From fa6e873e818350614b1dbd0ab99a770650082874 Mon Sep 17 00:00:00 2001 From: Michael Elovskikh Date: Fri, 14 Sep 2012 00:29:23 +0600 Subject: [PATCH 3/4] Unused import fix --- wand/image.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/wand/image.py b/wand/image.py index 19d2092f..cf8300a3 100644 --- a/wand/image.py +++ b/wand/image.py @@ -1422,9 +1422,6 @@ def clone(self): """ return type(self)(iterator=self) -import UserDict - - class Metadata(collections.Mapping): """Class that implements dict-like read-only access to image metadata like From e7709100d577c8ae938c728fd49ab2ad841ec3a2 Mon Sep 17 00:00:00 2001 From: Michael Elovskikh Date: Fri, 14 Sep 2012 00:50:41 +0600 Subject: [PATCH 4/4] Class-level property definition --- wand/image.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wand/image.py b/wand/image.py index cf8300a3..eed73711 100644 --- a/wand/image.py +++ b/wand/image.py @@ -368,6 +368,9 @@ class Image(Resource): """ + #: (:class:`Metadata`) The metadata mapping of the image. Read only. + metadata = None + c_is_resource = library.IsMagickWand c_destroy_resource = library.DestroyMagickWand c_get_exception = library.MagickGetException