Source code for tmxlib.image_base

"""Image base classes
---------------------

"""

from __future__ import division

from tmxlib import helpers, fileio

[docs]class ImageBase(helpers.SizeMixin): """Provide __getitem__ and __setitem__ for images Pixel access methods with (x, y) pairs for position and (r, g, b, a) tuples for color. """ def __getitem__(self, pos): """Get the pixel at the specified (x, y) position Proxies to get_pixel. """ x, y = pos return self.get_pixel(x, y) def __setitem__(self, pos, value): """Set the pixel at the specified (x, y) position Proxies to set_pixel. """ x, y = pos r, g, b, a = value return self.set_pixel(x, y, value)
[docs]class Image(ImageBase, fileio.ReadWriteBase): """An image. Conceptually, an 2D array of pixels. .. note:: This is an abstract base class. Use :func:`tmxlib.image.open` or :data:`tmxlib.image.preferred_image_class` to get a usable subclass. init arguments that become attributes: .. autoattribute:: data .. autoattribute:: size If given in constructor, the image doesn't have to be decoded to get this information, somewhat speeding up operations that don't require pixel access. If it's given in constructor and it does not equal the actual image size, an exception will be raised as soon as the image is decoded. .. attribute:: source The file name of this image, if it is to be saved separately from maps/tilesets that use it. .. attribute:: trans A color key used for transparency (currently not implemented) Images support indexing (``img[x, y]``) as a shortcut for the get_pixel and set_pixel methods. """ # XXX: Make `trans` actually work # XXX: Make modifying and saving images work _rw_obj_type = 'image' def __init__(self, data=None, trans=None, size=None, source=None): self.trans = trans self._data = data self.source = source self._size = size self.serializer = fileio.serializer_getdefault() @property
[docs] def size(self): """Size of the image, in pixels. """ if self._size: return self._size else: self.load_image() # XXX: Not available without an image backend! return self.size
@property
[docs] def data(self): """Data of this image, as read from disk. """ if self._data: return self._data else: try: base_path = self.base_path except AttributeError: base_path = None self._data = self.serializer.load_file(self.source, base_path=base_path) return self._data
[docs] def load_image(self): """Load the image from self.data, and set self._size If self._size is already set, assert that it equals """ raise TypeError('Image data not available')
[docs] def get_pixel(self, x, y): """Get the color of the pixel at position (x, y) as a RGBA 4-tuple. Supports negative indices by wrapping around in the obvious way. """ raise TypeError('Image data not available')
[docs] def set_pixel(self, x, y, value): """Set the color of the pixel at position (x, y) to a RGBA 4-tuple Supports negative indices by wrapping around in the obvious way. """ raise TypeError('Image data not available')
[docs]class ImageRegion(ImageBase): """A rectangular region of a larger image init arguments that become attributes: .. attribute:: image The "parent" image .. attribute:: top_left The coordinates of the top-left corner of the region. Will also available as ``x`` and ``y`` attributes. .. attribute:: size The size of the region. Will also available as ``width`` and ``height`` attributes. """ def __init__(self, image, top_left, size): self.image = image self.top_left = x, y = top_left self.size = size @property def x(self): return self.top_left[0] @x.setter def x(self, value): self.top_left = value, self.top_left[1] @property def y(self): return self.top_left[1] @y.setter def y(self, value): self.top_left = self.top_left[0], value
[docs] def get_pixel(self, x, y): """Get the color of the pixel at position (x, y) as a RGBA 4-tuple. Supports negative indices by wrapping around in the obvious way. """ x, y = self._wrap_coords(x, y) assert 0 <= x < self.width assert 0 <= y < self.height return self.image.get_pixel(x + self.x, y + self.y)
[docs] def set_pixel(self, x, y, value): """Set the color of the pixel at position (x, y) to a RGBA 4-tuple Supports negative indices by wrapping around in the obvious way. """ x, y = self._wrap_coords(x, y) assert 0 <= x < self.width assert 0 <= y < self.height self.image.set_pixel(x + self.x, y + self.y, value)