Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metadata support #56

Merged
merged 4 commits into from
Sep 13, 2012
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions wand/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand Down
44 changes: 43 additions & 1 deletion wand/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be documented. You can define an empty attribute at class-level e.g.:

#: (:class:`Metadata`) The metadata mapping of the image.  Read only.
metadata = None

Anyway how does it works well, even though there is no 'metadata' in the __slots__ list?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway how does it works well, even though there is no 'metadata' in the slots list?

Yes, but I'l add it's class-level definition, as you wrote before.

self.raise_exception()

@property
Expand Down Expand Up @@ -1422,9 +1423,50 @@ def clone(self):
return type(self)(iterator=self)


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.

"""

11 changes: 11 additions & 0 deletions wandtests/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"