Source code for fontParts.base.image

from fontTools.misc import transform
from fontParts.base.base import (
    BaseObject,
    TransformationMixin,
    PointPositionMixin,
    SelectionMixin,
    dynamicProperty,
    reference
)
from fontParts.base import normalizers
from fontParts.base.color import Color
from fontParts.base.deprecated import DeprecatedImage, RemovedImage


[docs]class BaseImage( BaseObject, TransformationMixin, PointPositionMixin, SelectionMixin, DeprecatedImage, RemovedImage ): copyAttributes = ( "transformation", "color", "data" ) def _reprContents(self): contents = [ "offset='({x}, {y})'".format(x=self.offset[0], y=self.offset[1]), ] if self.color: contents.append("color=%r" % str(self.color)) if self.glyph is not None: contents.append("in glyph") contents += self.glyph._reprContents() return contents def __bool__(self): if self.data is None: return False elif len(self.data) == 0: return False else: return True __nonzero__ = __bool__ # ------- # Parents # ------- # Glyph _glyph = None glyph = dynamicProperty("glyph", "The image's parent :class:`BaseGlyph`.") def _get_glyph(self): if self._glyph is None: return None return self._glyph() def _set_glyph(self, glyph): if self._glyph is not None: raise AssertionError("glyph for image already set") if glyph is not None: glyph = reference(glyph) self._glyph = glyph # Layer layer = dynamicProperty("layer", "The image's parent :class:`BaseLayer`.") def _get_layer(self): if self._glyph is None: return None return self.glyph.layer # Font font = dynamicProperty("font", "The image's parent :class:`BaseFont`.") def _get_font(self): if self._glyph is None: return None return self.glyph.font # ---------- # Attributes # ---------- # Transformation transformation = dynamicProperty( "base_transformation", """ The image's :ref:`type-transformation`. This defines the image's position, scale, and rotation. :: >>> image.transformation (1, 0, 0, 1, 0, 0) >>> image.transformation = (2, 0, 0, 2, 100, -50) """ ) def _get_base_transformation(self): value = self._get_transformation() value = normalizers.normalizeTransformationMatrix(value) return value def _set_base_transformation(self, value): value = normalizers.normalizeTransformationMatrix(value) self._set_transformation(value)
[docs] def _get_transformation(self): """ Subclasses must override this method. """ self.raiseNotImplementedError()
[docs] def _set_transformation(self, value): """ Subclasses must override this method. """ self.raiseNotImplementedError()
offset = dynamicProperty( "base_offset", """ The image's offset. This is a shortcut to the offset values in :attr:`transformation`. This must be an iterable containing two :ref:`type-int-float` values defining the x and y values to offset the image by. :: >>> image.offset (0, 0) >>> image.offset = (100, -50) """ ) def _get_base_offset(self): value = self._get_offset() value = normalizers.normalizeTransformationOffset(value) return value def _set_base_offset(self, value): value = normalizers.normalizeTransformationOffset(value) self._set_offset(value)
[docs] def _get_offset(self): """ Subclasses may override this method. """ sx, sxy, syx, sy, ox, oy = self.transformation return (ox, oy)
[docs] def _set_offset(self, value): """ Subclasses may override this method. """ sx, sxy, syx, sy, ox, oy = self.transformation ox, oy = value self.transformation = (sx, sxy, syx, sy, ox, oy)
scale = dynamicProperty( "base_scale", """ The image's scale. This is a shortcut to the scale values in :attr:`transformation`. This must be an iterable containing two :ref:`type-int-float` values defining the x and y values to scale the image by. :: >>> image.scale (1, 1) >>> image.scale = (2, 2) """ ) def _get_base_scale(self): value = self._get_scale() value = normalizers.normalizeTransformationScale(value) return value def _set_base_scale(self, value): value = normalizers.normalizeTransformationScale(value) self._set_scale(value)
[docs] def _get_scale(self): """ Subclasses may override this method. """ sx, sxy, syx, sy, ox, oy = self.transformation return (sx, sy)
[docs] def _set_scale(self, value): """ Subclasses may override this method. """ sx, sxy, syx, sy, ox, oy = self.transformation sx, sy = value self.transformation = (sx, sxy, syx, sy, ox, oy)
# Color color = dynamicProperty( "base_color", """ The image's color. This will be a :ref:`type-color` or ``None``. :: >>> image.color None >>> image.color = (1, 0, 0, 0.5) """ ) def _get_base_color(self): value = self._get_color() if value is not None: value = normalizers.normalizeColor(value) value = Color(value) return value def _set_base_color(self, value): if value is not None: value = normalizers.normalizeColor(value) self._set_color(value)
[docs] def _get_color(self): """ Return the color value as a color tuple or None. Subclasses must override this method. """ self.raiseNotImplementedError()
[docs] def _set_color(self, value): """ value will be a color tuple or None. Subclasses must override this method. """ self.raiseNotImplementedError()
# Data data = dynamicProperty( "data", """ The image's raw byte data. The possible formats are defined by each environment. """ ) def _get_base_data(self): return self._get_data() def _set_base_data(self, value): self._set_data(value)
[docs] def _get_data(self): """ This must return raw byte data. Subclasses must override this method. """ self.raiseNotImplementedError()
[docs] def _set_data(self, value): """ value will be raw byte data. Subclasses must override this method. """ self.raiseNotImplementedError()
# -------------- # Transformation # --------------
[docs] def _transformBy(self, matrix, **kwargs): """ Subclasses may override this method. """ t = transform.Transform(*matrix) transformation = t.transform(self.transformation) self.transformation = tuple(transformation)
# ------------- # Normalization # -------------
[docs] def round(self): """ Round offset coordinates. """ self._round()
[docs] def _round(self): """ Subclasses may override this method. """ x, y = self.offset x = normalizers.normalizeVisualRounding(x) y = normalizers.normalizeVisualRounding(y) self.offset = (x, y)