decorators

  • renderable

    class renderable:
        def __init__(self,
            rect=(1080, 1080),
            bg=None,
            fmt="png",
            name=None,
            rasterizer=None,
            prefix=None,
            suffix=None,
            dst=None,
            custom_folder=None,
            post_preview=None,
            watch=[],
            watch_soft=[],
            watch_restart=[],
            solo=False,
            mute=False,
            rstate=False,
            preview_only=False,
            preview_scale=1,
            render_only=False,
            direct_draw=False,
            clip=False,
            composites=False,
            single_frame=True,
            interactable=False,
            cv2caps=None,
            render_bg=True,
            style="_default",
            viewBox=True,
            layer=False,
            cond=None,
            sort=0,
            hide=[],
            grid=None,
            xray=True,
            memory=None,
            reset_memory=None):
    

    Base class for any content renderable by Coldtype.

  • animation

    class animation:
        def __init__(self,
            rect=(1080, 1080),
            timeline:Timeline=10,
            show_frame=True,
            offset=0,
            overlay=True,
            audio=None,
            suffixer=None,
            clip_cursor=True,
            reset_to_zero=False,
            release=None,
            **kwargs
            ):
    

    Base class for any frame-wise animation animatable by Coldtype

classes

  • P

    class P:
        def __init__(self, *vals, **kwargs):
    

    P stands for Path (or Pen)

    • align

      def align(self,
          rect,
          x="mdx",
          y="mdy",
          th=None, # deprecated
          tv=None, # deprecated
          tx=1,
          ty=0,
          transformFrame=True,
          h=None,
          returnOffset=False
          ) 
      

      Align this pen to another rect, defaults to the center.

      • tx means true-x (i.e. will disregard any invisible ‘frame’ set on the pen (as in the case of glyphs returned from StSt/Glyphwise));
      • ty means true-y, which is the same but for the vertical dimension
    • ambit

      def ambit(self, th=None, tv=None, tx=0, ty=0, t=None) 
      

      Get the calculated rect boundary.

      • tx means (t)rue (x) (i.e. the true width/horizontal dimension (was previously th));
      • ty means (t)rue (y) (i.e. the true height/vertical dimension (was previously tv));

      Passing either ignores a non-bounds-derived frame in either dimension

    • bounds

      def bounds(self):
          """Calculate the exact bounds of this shape, using a BoundPen"""
          b = Rect(0, 0, 0, 0)
      
          if self.val_present():
              try:
                  cbp = BoundsPen(None)
                  self._val.replay(cbp)
                  mnx, mny, mxx, mxy = cbp.bounds
                  b = Rect((mnx, mny, mxx - mnx, mxy - mny))
              except:
                  pass
      
          if len(self._els) > 0:
              bs = []
              for el in self._els:
                  eb = el.bounds()
                  if eb and eb.nonzero():
                      bs.append(eb)
      
              if len(bs) > 0:
                  b = bs[0]
                  for eb in bs[1:]:
                      b = b.union(eb)
      
          return b
      

      Calculate the exact bounds of this shape, using a BoundPen

    • catmull

      def catmull(self, points, close=False) 
      

      Run a catmull spline through a series of points

    • difference

      def difference(self, otherPen=None) 
      

      Calculate and return the difference of this shape and another.

    • dots

      def dots(self, radius=4, square=False):
          """(Necessary?) Create circles at moveTo commands"""
          dp = type(self)()
          for t, pts in self.v.value:
              if t == "moveTo":
                  x, y = pts[0]
                  if square:
                      dp.rect(Rect((x-radius, y-radius, radius, radius)))
                  else:
                      dp.oval(Rect((x-radius, y-radius, radius, radius)))
          self.v.value = dp.v.value
          return self
      

      (Necessary?) Create circles at moveTo commands

    • down

      def down(self):
          return self.pen()
      

      down one level of hierarchy — unimplemented by Runon

    • explode

      def explode(self):
          """Convert all contours to individual paths"""
          for el in self._els:
              el.explode()
      
          if self.val_present():
              rp = RecordingPen()
              ep = ExplodingPen(rp)
              self.replay(ep)
      
              for p in ep._pens:
                  el = type(self)()
                  el._val.value = p
                  el._attrs = deepcopy(self._attrs)
                  self.append(el)
      
              self._val = RecordingPen()
      
          return self
      

      Convert all contours to individual paths

    • f

      def f(self, *value) 
      

      Get/set a (f)ill

    • flatten

      def flatten(self, length=10, segmentLines=True) 
      

      Runs a fontTools FlattenPen on this pen

    • glyph

      def glyph(self, glyph, glyphSet=None, layerComponents=False) 
      

      Play a glyph (like from defcon) into this pen.

    • gridlayer

      def gridlayer(self, nx, ny=None, track=0, lead=0) 
      

      Spread nx copies and then stack ny copies, w/ optional tracking & leading

    • gridlines

      def gridlines(self, rect, x=20, y=None, absolute=False) 
      

      Construct a grid in the pen using x and (optionally) y subdivisions

    • hull

      def hull(self, points) 
      

      Same as .line but calls closePath instead of endPath`

    • img

      def img(self, src=None, rect=Rect(0, 0, 500, 500), pattern=False, opacity=1.0):
          """Get/set an image fill"""
          if src:
              from coldtype.img.datimage import DATImage
              if isinstance(src, DATImage):
                  return self.attr(image=dict(src=src.src, rect=rect, pattern=pattern, opacity=opacity))
              return self.attr(image=dict(src=src, rect=rect, pattern=pattern, opacity=opacity))
          else:
              return self.attr(field="image")
      

      Get/set an image fill

    • intersection

      def intersection(self, otherPen=None) 
      

      Calculate and return the intersection of this shape and another.

    • lead

      def lead(self, leading) 
      

      Vertical spacing

    • length

      def length(self, t=1):
      
          """Get the length of the curve for time `t`"""
          cc = CurveCutter(self)
          start = 0
          tv = t * cc.calcCurveLength()
          return tv
      

      Get the length of the curve for time t

    • line

      def line(self, points, moveTo=True, endPath=True) 
      

      Syntactic sugar for moveTo+lineTo(…)+endPath; can have any number of points

    • normalize_attr_value

      def normalize_attr_value(self, k, v):
          if k == "fill" and not isinstance(v, Color):
              return normalize_color(v)
          else:
              return super().normalize_attr_value(k, v)
      

      subclass hook

    • outline

      def outline(self,
          offset=1,
          drawInner=True,
          drawOuter=True,
          cap="square",
          miterLimit=None,
          closeOpenPaths=True
          ) 
      

      AKA expandStroke

    • oval

      def oval(self, rect) 
      

      Oval primitive

    • pen

      def pen(self, frame=True):
          """collapse and combine into a single vector"""
          if len(self) == 0:
              return self
      
          _frame = self.ambit()
          self.collapse()
      
          for el in self._els:
              el._val.replay(self._val)
              #self._val.record(el._val)
      
          try:
              self._attrs = {**self._els[0]._attrs, **self._attrs}
          except IndexError:
              pass
      
          if frame:
              self.data(frame=_frame)
          self._els = []
          return self
      

      collapse and combine into a single vector

    • point_t

      def point_t(self, t=0.5):
      
          """Get point value for time `t`"""
          cc = CurveCutter(self)
          start = 0
          tv = t * cc.calcCurveLength()
          p, tangent = cc.subsegmentPoint(start=0, end=tv)
          return p, tangent
      

      Get point value for time t

    • printable_data

      def printable_data(self):
          out = {}
          exclude = ["_last_align_rect", "_notebook_shown"]
          for k, v in self._data.items():
              if k not in exclude:
                  out[k] = v
          return out
      

      subclass hook for repr

    • printable_val

      def printable_val(self):
          if self.val_present():
              return f"{len(self._val.value)}mvs"
      

      subclass hook for repr

    • record

      def record(self, pen) 
      

      Play a pen into this pen, meaning that pen will be added to this one’s value.

    • rect

      def rect(self, rect) 
      

      Rectangle primitive — moveTo/lineTo/lineTo/lineTo/closePath

    • removeOverlap

      def removeOverlap(self, use_skia_pathops_draw=True) 
      

      Remove overlaps within this shape and return itself.

    • reverse

      def reverse(self, recursive=False, winding=True):
          """Reverse elements; if pen value present, reverse the winding direction of the pen."""
          if winding and self.val_present():
              if self.unended():
                  self.closePath()
              dp = RecordingPen()
              rp = ReverseContourPen(dp)
              self.replay(rp)
              self._val.value = dp.value
              return self
      
          return super().reverse(recursive=recursive, winding=winding)
      

      Reverse elements; if pen value present, reverse the winding direction of the pen.

    • reverseDifference

      def reverseDifference(self, otherPen=None) 
      

      Calculate and return the reverseDifference of this shape and another.

    • reversePens

      def reversePens(self):
          """for backwards compatibility"""
          return self.reverse(recursive=False)
      

      for backwards compatibility

    • rotate

      def rotate(self, degrees, point=None, th=None, tv=None, tx=1, ty=1, **kwargs) 
      

      Rotate this shape by a degree (in 360-scale, counterclockwise).

    • roughen

      def roughen(self, amplitude=10, threshold=10, ignore_ends=False, seed=None) 
      

      Randomizes points in skeleton

    • round

      def round(self):
          """Round the values of this pen to integer values."""
          return self.round_to(1)
      

      Round the values of this pen to integer values.

    • round_to

      def round_to(self, rounding) 
      

      Round the values of this pen to nearest multiple of rounding.

    • roundedRect

      def roundedRect(self, rect, hr, vr=None, scale=True) 
      

      Rounded rectangle primitive

    • s

      def s(self, *value) 
      

      Get/set a (s)troke

    • scale

      def scale(self, scaleX, scaleY=None, point=None, th=None, tv=None, tx=1, ty=0, **kwargs) 
      

      Scale this shape by a percentage amount (1-scale).

    • scaleToHeight

      def scaleToHeight(self, h, shrink_only=False) 
      

      Scale this shape horizontally

    • scaleToRect

      def scaleToRect(self, rect, preserveAspect=True, shrink_only=False, tx=1, ty=0, return_number=False) 
      

      Scale this shape into a Rect.

    • scaleToWidth

      def scaleToWidth(self, w, shrink_only=False) 
      

      Scale this shape horizontally

    • sf

      def sf(self, value=None) 
      

      strokeFirst

    • sm

      def sm(self, value=None) 
      

      strokeMiter

    • spread

      def spread(self, tracking=0, tx=0, zero=False) 
      

      Horizontal distribution of elements

    • stack

      def stack(self, leading=0, ty=0, zero=False) 
      

      Vertical distribution of elements

    • strokeFirst

      def strokeFirst(self, value=None) 
      

      For a rendering engine that has to stroke and fill in two separate passes, perform the stroke before the fill (akin to an .understroke but without the duplication overhead)

    • strokeMiter

      def strokeMiter(self, value=None) 
      

      For a rendering engine that can specify stroke-miter

    • style

      def style(self, style="_default"):
          """for backwards compatibility with defaults and grouped-stroke-properties"""
          st = {**super().style(style)}
          return self.groupedStyle(st)
      

      for backwards compatibility with defaults and grouped-stroke-properties

    • subsegment

      def subsegment(self, start=0, end=1) 
      

      Return a subsegment of the pen based on t values start and end

    • sw

      def sw(self, value) 
      

      Get/set a (s)troke (w)idth

    • toGlyph

      def toGlyph(self, name=None, width=None, allow_blank=False):
      
          """
          Create a glyph (like from `defcon`) using this pen’s value.
          *Warning*: if path is unended, closedPath will be called
          """
          from defcon import Glyph
          if not allow_blank:
              if self.unended():
                  self.closePath()
          bounds = self.bounds()
          glyph = Glyph()
          glyph.name = name
          glyph.width = width or bounds.w
          try:
              sp = glyph.getPen()
              self.replay(sp)
          except AssertionError:
              if not allow_blank:
                  print(">>>blank glyph:", glyph.name)
          return glyph
      

      Create a glyph (like from defcon) using this pen’s value. Warning: if path is unended, closedPath will be called

    • track

      def track(self, t, v=False) 
      

      Track-out/distribute elements

    • track_to_rect

      def track_to_rect(self, rect, pullToEdges=False, r=0) 
      

      Distribute pens evenly within a frame

    • track_with_width

      def track_with_width(self, t) 
      

      Track-out/distribute elements

    • transform

      def transform(self, transform, transformFrame=True) 
      

      Perform an arbitrary transformation on the pen, using the fontTools Transform class.

    • translate

      def translate(self, x, y=None, transformFrame=True) 
      

      Translate this shape by x and y (pixel values).

    • union

      def union(self, otherPen=None) 
      

      Calculate and return the union of this shape and another.

    • val_present

      def val_present(self):
          return self._val is not None and len(self._val.value) > 0
      

      subclass hook

    • xor

      def xor(self, otherPen=None) 
      

      Calculate and return the XOR of this shape and another.

  • Style

    class Style:
        def __init__(self,
            font:Union[Font, str]=None,
            font_size:int=12,
            tracking=0,
            trackingMode=1,
            kern_pairs=dict(),
            space=None,
            baselineShift=0,
            xShift=None,
            rotate=0,
            reverse=False,
            removeOverlap=False,
            q2c=False,
            lang=None,
            narrower=None,
            fallback=None,
            palette=0,
            capHeight=None,
            ascender=None,
            descender=None,
            metrics="c",
            data={},
            layer=None,
            liga=True,
            kern=True,
            fill=rgb(0, 0.5, 1),
            stroke=None,
            strokeWidth=0,
            variations=dict(),
            variationLimits=dict(),
            trackingLimit=0,
            scaleVariations=True,
            rollVariations=False,
            mods=None,
            features=dict(),
            increments=dict(),
            varyFontSize=False,
            preventHwid=False,
            fitHeight=None,
            meta=dict(),
            no_shapes=False,
            show_frames=False,
            load_font=True, # should we attempt to load the font?
            tag=None, # way to differentiate in __eq__
            _stst=False,
            case=None,
            **kwargs
            ):
    

    Class for configuring font properties

    Keyword arguments

    • font: can either be a coldtype.text.Font object, a pathlib.Path, or a plain string path
    • font_size: standard point-based font-size, expressed as integer
    • tracking (aka tu): set the tracking, by default in font-source-point-size aka as if the font-size was always 1000; this means tracking is by default done relatively rather than absolutely (aka the relative tracking will not change when you change the font_size)
    • trackingMode: set to 0 to set tracking in a classic font_size-based (defaults to 1, as described just above)
    • space: set this to override the width of the standard space character (useful when setting text on a curve and the space is getting collapsed)
    • baselineShift (aka bs): if an integer, shifts glyphs by that amount in y axis; if a list, shifts glyphs at corresponding index in list by that amount in y axis
    • xShift (aka xs): if an integer, shifts glyphs by that amount in x axis; if a list, shifts glyphs at corresponding index in list by that amount in x axis
    • rotate: rotate glyphs by degree
    • reverse (aka r): reverse the order of the glyphs, so that the left-most glyph is first in when vectorized via .pens()
    • removeOverlaps (aka ro): automatically use skia-pathops to remove overlaps from the glyphs (useful when using variable ttf fonts)
    • lang: set language directly, to access language-specific alternate characters/rules

    Shorthand kwargs

    • kp for kern_pairs — a dict of glyphName->[left,right] values in font-space
    • tl for trackingLimit
    • bs for baselineShift
    • ch for capHeight — a number in font-space; not specified, read from font; specified as ‘x’, capHeight is set to xHeight as read from font
    • mod

      def mod(self, **kwargs):
          """Modify this style object to create a new
          one; kwargs can have all of the same kwargs as
          the standard `Style` constructor"""
          keyed = dict(**self.input, **self.input["kwargs"])
          del keyed["kwargs"]
          del keyed["self"]
          keyed.update(kwargs)
          return Style(**keyed)
      

      Modify this style object to create a new one; kwargs can have all of the same kwargs as the standard Style constructor

  • Rect

    class Rect:
        def __init__(self, *rect):
    

    Representation of a rectangle as (x, y, w, h), indexable

    Constructor handles multiple formats, including:

    • x, y, w, h
    • [x, y, w, h]
    • w, h (x and y default to 0, 0)

    Rect objects can be splat’d where lists are expected as individual arguments (as in drawBot), i.e. rect(*my_rect), or can be passed directly to functions expected a list representation of a rectangle.

    • FromCenter

      def FromCenter(center, w, h=None) 
      

      Create a rect given a center point and a width and height (optional, height will default to width if not specified”)

    • FromMnMnMxMx

      def FromMnMnMxMx(extents) 
      

      Create a rectangle from xmin, ymin, xmax, ymax

    • divide

      def divide(self, amount, edge, forcePixel=False) 
      

      Dividing

      Derived from the behavior of the classic Cocoa function CGRectDivide, which takes a rectangle and breaks it into two pieces, based on a pixel amount and an edge.

      A quick example: assume you have a rectangle, r, defined as such:

      r = Rect(0, 0, 300, 100)

      If you want to break that into a left-hand rectangle that’s 100 pixels wide and a right-hand rectangle that’s 200 pixels wide, you could either say:

      left, right = r.divide(100, "mnx")

      or you could say

      right, left = r.divide(200, "mxx")

      where mxx is the rightmost edge, and mnx is the leftmost edge.

      Centering

      A special use-case is if you want to break a rectangle into three rectangles, based on the center “edge”, you can do something like this:

      left, center, right = r.divide(200, "mdx")

      This will result in three rectangles, always left-to-right, where left is 50px wide, then center is 200px wide, then right is also 50px wide — anything not in the center will be evenly distributed between left and right, or top-and-bottom in the case of a Y edge.

    • grid

      def grid(self, columns=2, rows=None) 
      

      Construct a grid; if rows is None, rows = columns

    • inset

      def inset(self, dx, dy=None) 
      

      Creates padding in the amount of dx and dy. Also does expansion with negative values, or both at once

    • interp

      def interp(self, v, other) 
      

      Interpolate with another rect

    • ipos

      def ipos(self, pt, defaults=(0.5, 0.5), clamp=True) 
      

      Get scaled 0-1 bounded (optional) value from a point in a rectangle

    • mnmnmxmx

      def mnmnmxmx(self) 
      

      Return extents of rectangle as list

    • nonzero

      def nonzero(self) 
      

      is this rect not just all zeros?

    • origin

      def origin(self) 
      

      (x, y) as tuple

    • point

      def point(self, eh, ev=Edge.MinX) 
      

      Get a Point at a given compass direction, chosen from

      • C
      • W
      • NW
      • N
      • NE
      • E
      • SE
      • S
      • SW
    • rect

      def rect(self) 
      

      x,y,w,h in list

    • round

      def round(self) 
      

      round the values in the rectangle to the nearest integer

    • square

      def square(self, outside=False) 
      

      take a square from the center of this rect

    • subdivide

      def subdivide(self, amount, edge, forcePixel=False) 
      

      Like divide, but here you specify the number of equal pieces you want (like columns or rows), and then what edge to start at, i.e.

      .. code:: python

      r = Rect(0, 0, 500, 100)
      r.subdivide(5, "mxx")
      => [Rect([400.0, 0, 100.0, 100]), Rect([300.0, 0, 100.0, 100]), Rect([200.0, 0, 100.0, 100]), Rect([100.0, 0, 100.0, 100]), Rect([0, 0, 100.0, 100])]
      

      will get you five 100-px wide rectangles, right-to-left

      (N.B. Does not support center edges, as that makes no sense)

    • subdivide_with_leading

      def subdivide_with_leading(self, count, leading, edge, forcePixel=True) 
      

      Same as subdivide, but inserts leading between each subdivision

    • subdivide_with_leadings

      def subdivide_with_leadings(self, count, leadings, edge, forcePixel=True) 
      

      Same as subdivide_with_leadings, but inserts leading between each subdivision, indexing the size of the leading from a list of leadings

    • subtract

      def subtract(self, amount, edge, forcePixel=False) 
      

      The opposite of take, this will remove and not return a piece of the given amount from the given edge.

      Let’s say you have a 100px-wide square and you want to drop 10px from the right-hand side, you would do:

      Rect(100, 100).subtract(10, Edge.MaxX), which leaves you with Rect([0, 0, 90, 100])

    • take

      def take(self, amount, edge, forcePixel=False) 
      

      Like divide, but here it just returns the “first” rect from a divide call, not all the resulting pieces, i.e. you can “take” 200px from the center of a rectangle by doing this Rect(0, 0, 300, 100).take(200, "mdx") which will result in Rect([50, 0, 200, 100])

    • wh

      def wh(self) 
      

      the width and height as a tuple

    • xy

      def xy(self) 
      

      equivalent to origin

    • zero

      def zero(self) 
      

      disregard origin and set it to (0,0)

functions

  • StSt

    def StSt(text,
        font,
        font_size=24,
        rect=Rect(1080, 1080),
        strip=False,
        multiline=False,
        lead=True,
        #xa="mdx",
        **kwargs) 
    

    Set a line of text with a single Style object, passed either with it’s constituent parts (i.e. kwargs) or as an actual Style object.

    Examples:

    @renderable()
    def stst_1(r):
        # here the styling arguments are "flat"
        return (StSt("COLDTYPE", Font.ColdObvi(), 100, wdth=0)
            .align(r))
    
    @renderable()
    def stst_2(r):
        # here the styling arguments are encapsulated in the Style object
        return (StSt("COLDTYPE", Style(Font.ColdObvi(), 100, wdth=1))
            .align(r))
    
  • Glyphwise

    def Glyphwise(st:str
        , styler
        , start:int=0
        , line:int=0
        , multiline=False) 
    

    Build text by applying unique style to each glyph.

    Style is determined by a styler function (usually a lambda) that is given a GlyphwiseGlyph containing information about the glyph and its position (index, etc.); styler function must return a Style object to be used for styling

    Examples:

    @renderable()
    def glyphwise(r):
        return (Glyphwise("COLDTYPE", lambda x:
            Style(Font.ColdObvi(), 200, wdth=x.e))
            .align(r))