Skip to content

Commit

Permalink
Moved Image.ping() to classmethod, and added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
emcconville committed Jul 18, 2019
1 parent 5c2530a commit 0c138b0
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 61 deletions.
5 changes: 3 additions & 2 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ Version 0.5.6

Unreleased.

- Added :meth:`Image.percent_escape() <wand.image.BaseImage.percent_escape>` helper method. [:issue:`421`]
- Added :meth:`Image.annotate() <wand.image.BaseImage.annotate>` method. [:issue:`#418`]

- Added :meth:`Image.percent_escape() <wand.image.BaseImage.percent_escape>` helper method. [:issue:`421`]
- Added :meth:`Image.ping() <wand.image.Image.ping>` class method. [:issue:`#425`]


.. _changelog-0.5.5:

Expand Down
18 changes: 18 additions & 0 deletions tests/image_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,24 @@ def test_clone(fx_asset):
img.wand


def test_ping_from_filename(fx_asset):
file_path = str(fx_asset.join('mona-lisa.jpg'))
with Image.ping(filename=file_path) as img:
assert img.size == (402, 599)


def test_ping_from_blob(fx_asset):
blob = fx_asset.join('mona-lisa.jpg').read('rb')
with Image.ping(blob=blob) as img:
assert img.size == (402, 599)


def test_ping_from_file(fx_asset):
with fx_asset.join('mona-lisa.jpg').open('rb') as fd:
with Image.ping(file=fd) as img:
assert img.size == (402, 599)


def test_save_to_filename(fx_asset):
"""Saves an image to the filename."""
savefile = os.path.join(tempfile.mkdtemp(), 'savetest.jpg')
Expand Down
137 changes: 78 additions & 59 deletions wand/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -7705,6 +7705,84 @@ def from_array(cls, array, channel_map=None, storage=None):
instance.raise_exception(cls)
return instance

@classmethod
def ping(cls, file=None, filename=None, blob=None, resolution=None,
format=None):
"""Ping image header into Image() object, but without any pixel data.
This is useful for inspecting image meta-data without decoding the
whole image.
:param blob: reads an image from the ``blob`` byte array
:type blob: :class:`bytes`
:param file: reads an image from the ``file`` object
:type file: file object
:param filename: reads an image from the ``filename`` string
:type filename: :class:`basestring`
:param resolution: set a resolution value (DPI),
useful for vector formats (like PDF)
:type resolution: :class:`collections.abc.Sequence`,
:class:`numbers.Integral`
:param format: suggest image file format when reading from a ``blob``,
or ``file`` property.
:type format: :class:`basestring`
.. versionadded:: 0.5.6
"""
r = None
instance = cls()
# Resolution must be set after image reading.
if resolution is not None:
if (isinstance(resolution, abc.Sequence) and
len(resolution) == 2):
library.MagickSetResolution(instance.wand, *resolution)
elif isinstance(resolution, numbers.Integral):
library.MagickSetResolution(instance.wand, resolution,
resolution)
else:
raise TypeError('resolution must be a (x, y) pair or an '
'integer of the same x/y')
if format:
library.MagickSetFormat(instance.wand, format)
if not filename:
library.MagickSetFilename(instance.wand,
b'buffer.' + format)
if file is not None:
if (isinstance(file, file_types) and
hasattr(libc, 'fdopen') and hasattr(file, 'mode')):
fd = libc.fdopen(file.fileno(), file.mode)
r = library.MagickPingImageFile(instance.wand, fd)
elif not callable(getattr(file, 'read', None)):
raise TypeError('file must be a readable file object'
', but the given object does not '
'have read() method')
else:
blob = file.read()
file = None
if blob is not None:
if not isinstance(blob, abc.Iterable):
raise TypeError('blob must be iterable, not ' +
repr(blob))
if not isinstance(blob, binary_type):
blob = b''.join(blob)
r = library.MagickPingImageBlob(instance.wand, blob, len(blob))
elif filename is not None:
filename = encode_filename(filename)
r = library.MagickPingImage(instance.wand, filename)
if not r:
instance.raise_exception()
msg = ('MagickPingImage returns false, but did raise ImageMagick '
'exception. This can occurs when a delegate is missing, or '
'returns EXIT_SUCCESS without generating a raster.')
raise WandRuntimeError(msg)
else:
instance.metadata = Metadata(instance)
instance.artifacts = ArtifactTree(instance)
from .sequence import Sequence
instance.sequence = Sequence(instance)
instance.profiles = ProfileDict(instance)
return instance

@classmethod
def stereogram(cls, left, right):
"""Create a new stereogram image from two existing images.
Expand Down Expand Up @@ -7906,65 +7984,6 @@ def make_blob(self, format=None):
else: # pragma: no cover
self.raise_exception()

def ping(self, file=None, filename=None, blob=None, resolution=None):
"""Ping image header into Image() object, but without any pixel data.
This is useful for inspecting image meta-data without decoding the
whole image.
:param blob: reads an image from the ``blob`` byte array
:type blob: :class:`bytes`
:param file: reads an image from the ``file`` object
:type file: file object
:param filename: reads an image from the ``filename`` string
:type filename: :class:`basestring`
:param resolution: set a resolution value (DPI),
useful for vector formats (like PDF)
:type resolution: :class:`collections.abc.Sequence`,
:class:`numbers.Integral`
.. versionadded:: 0.5.6
"""
r = None
# Resolution must be set after image reading.
if resolution is not None:
if (isinstance(resolution, abc.Sequence) and
len(resolution) == 2):
library.MagickSetResolution(self.wand, *resolution)
elif isinstance(resolution, numbers.Integral):
library.MagickSetResolution(self.wand, resolution, resolution)
else:
raise TypeError('resolution must be a (x, y) pair or an '
'integer of the same x/y')
if file is not None:
if (isinstance(file, file_types) and
hasattr(libc, 'fdopen') and hasattr(file, 'mode')):
fd = libc.fdopen(file.fileno(), file.mode)
r = library.MagickPingImageFile(self.wand, fd)
elif not callable(getattr(file, 'read', None)):
raise TypeError('file must be a readable file object'
', but the given object does not '
'have read() method')
else:
blob = file.read()
file = None
if blob is not None:
if not isinstance(blob, abc.Iterable):
raise TypeError('blob must be iterable, not ' +
repr(blob))
if not isinstance(blob, binary_type):
blob = b''.join(blob)
r = library.MagickPingImageBlob(self.wand, blob, len(blob))
elif filename is not None:
filename = encode_filename(filename)
r = library.MagickPingImage(self.wand, filename)
if not r:
self.raise_exception()
msg = ('MagickReadImage returns false, but did raise ImageMagick '
'exception. This can occurs when a delegate is missing, or '
'returns EXIT_SUCCESS without generating a raster.')
raise WandRuntimeError(msg)

def pseudo(self, width, height, pseudo='xc:'):
"""Creates a new image from ImageMagick's internal protocol coders.
Expand Down

0 comments on commit 0c138b0

Please sign in to comment.