def _get_controlPointBounds(self): from fontTools.misc.transform import Transform # storage glyphRects = {} componentReferences = {} # scan loaded glyphs for glyphName, glyph in self._glyphs.items(): if glyphName in self._scheduledForDeletion: continue glyphRect = glyph.controlPointBounds if glyphRect: glyphRects[glyphName] = glyphRect # scan glyphs that have not been loaded if self._glyphSet is not None: for glyphName, fileName in self._glyphSet.contents.items(): if glyphName in self._glyphs or glyphName in self._scheduledForDeletion: continue glif = self._glyphSet.getGLIF(glyphName) points, components = _fetchControlPointBoundsData(glif) if points: glyphRects[glyphName] = calcBounds(points) for base, transformation in components: xScale, xyScale, yxScale, yScale, xOffset, yOffset = transformation if glyphName not in componentReferences: componentReferences[glyphName] = [] componentReferences[glyphName].append((base, xScale, xyScale, yxScale, yScale, xOffset, yOffset)) # get the transformed component bounding boxes and update the glyphs for glyphName, components in componentReferences.items(): glyphRect = glyphRects.get(glyphName, (None, None, None, None)) # XXX this doesn't handle nested components for base, xScale, xyScale, yxScale, yScale, xOffset, yOffset in components: # base glyph doesn't exist if base not in glyphRects: continue baseRect = glyphRects[base] # base glyph has no points if None in baseRect: continue # transform the base rect transform = Transform(xx=xScale, xy=xyScale, yx=yxScale, yy=yScale, dx=xOffset, dy=yOffset) xMin, yMin, xMax, yMax = baseRect (xMin, yMin), (xMax, yMax) = transform.transformPoints([(xMin, yMin), (xMax, yMax)]) componentRect = (xMin, yMin, xMax, yMax) # update the glyph rect if None in glyphRect: glyphRect = componentRect else: glyphRect = unionRect(glyphRect, componentRect) # store the updated rect glyphRects[glyphName] = glyphRect # work out the unified rect fontRect = None for glyphRect in glyphRects.values(): if fontRect is None: fontRect = glyphRect elif glyphRect is not None: fontRect = unionRect(fontRect, glyphRect) # done return fontRect
def unionBounds(bounds1: Optional[BoundingBox], bounds2: Optional[BoundingBox]) -> Optional[BoundingBox]: if bounds1 is None: return bounds2 if bounds2 is None: return bounds1 return BoundingBox(*unionRect(bounds1, bounds2))
def unionBounds(bounds1: BoundingBox | None, bounds2: BoundingBox | None) -> BoundingBox | None: if bounds1 is None: return bounds2 if bounds2 is None: return bounds1 return BoundingBox(*unionRect(bounds1, bounds2))
def getSelectionBounds(self): selection = self.selection bounds = [] if self.w.contoursCheckBox.get(): for contour in selection["contours"]: b = contour.bounds if b is not None: bounds.append(b) for bPoint in selection["bPoints"]: x = bPoint.anchor.x y = bPoint.anchor.y bounds.append((x, y, x, y)) if self.w.componentsCheckBox.get(): for component in selection["component"]: b = component.bounds if b is not None: bounds.append(b) if self.w.anchorsCheckBox.get(): for anchor in selection["anchors"]: x = anchor.x y = anchor.y bounds.append((x, y, x, y)) if not bounds: return None total = bounds[0] for b in bounds[1:]: total = unionRect(total, b) return total
def _qCurveToOne(self, bcp, pt): bounds = self.bounds bounds = updateBounds(bounds, pt) if not pointInRect(bcp, bounds): bounds = unionRect( bounds, calcQuadraticBounds(self._getCurrentPoint(), bcp, pt)) self.bounds = bounds
def compile(self, ttFont): if ttFont.recalcBBoxes: # For TT-flavored fonts, xMin, yMin, xMax and yMax are set in table__m_a_x_p.recalc(). if 'CFF ' in ttFont: topDict = ttFont['CFF '].cff.topDictIndex[0] self.xMin, self.yMin, self.xMax, self.yMax = intRect( topDict.FontBBox) elif 'CFF2' in ttFont: topDict = ttFont['CFF2'].cff.topDictIndex[0] charStrings = topDict.CharStrings fontBBox = None for charString in charStrings.values(): bounds = charString.calcBounds(charStrings) if bounds is not None: if fontBBox is not None: fontBBox = unionRect(fontBBox, bounds) else: fontBBox = bounds if fontBBox is not None: self.xMin, self.yMin, self.xMax, self.yMax = intRect( fontBBox) if ttFont.recalcTimestamp: self.modified = timestampNow() data = sstruct.pack(headFormat, self) return data
def getFontBounds(font): """ Get a tuple of (xMin, yMin, xMax, yMax) for all glyphs in the given *font*. """ rect = None # defcon if hasattr(font, "bounds"): rect = font.bounds # others else: for glyph in font: # robofab if hasattr(glyph,"box"): bounds = glyph.box # others else: bounds = glyph.bounds if rect is None: rect = bounds continue if rect is not None and bounds is not None: rect = unionRect(rect, bounds) if rect is None: rect = (0, 0, 0, 0) return rect
def _curveToOne(self, bcp1, bcp2, pt): bounds = self.bounds bounds = updateBounds(bounds, pt) if not pointInRect(bcp1, bounds) or not pointInRect(bcp2, bounds): bounds = unionRect(bounds, calcCubicBounds( self._getCurrentPoint(), bcp1, bcp2, pt)) self.bounds = bounds
def getFontBounds(font): """ Get a tuple of (xMin, yMin, xMax, yMax) for all glyphs in the given *font*. """ rect = None # defcon if hasattr(font, "bounds"): rect = font.bounds # others else: for glyph in font: # robofab if hasattr(glyph, "box"): bounds = glyph.box # others else: bounds = glyph.bounds if rect is None: rect = bounds continue if rect is not None and bounds is not None: rect = unionRect(rect, bounds) if rect is None: rect = (0, 0, 0, 0) return rect
def _curveToOne(self, bcp1, bcp2, pt): bounds = self.bounds bounds = updateBounds(bounds, pt) if not pointInRect(bcp1, bounds) or not pointInRect(bcp2, bounds): bounds = unionRect(bounds, calcCubicBounds( self._getCurrentPoint(), bcp1, bcp2, pt)) self.bounds = bounds
def _qCurveToOne(self, bcp, pt): bounds = self.bounds bounds = updateBounds(bounds, pt) if not pointInRect(bcp, bounds): bounds = unionRect(bounds, calcQuadraticBounds( self._getCurrentPoint(), bcp, pt)) self.bounds = bounds
def _bounds(color_glyph: ColorGlyph, quantize_factor: int = 1) -> Optional[Tuple[int, int, int, int]]: bounds = None for root in color_glyph.painted_layers: for context in root.breadth_first(): if not isinstance(context.paint, PaintGlyph): continue paint_glyph: PaintGlyph = cast(PaintGlyph, context.paint) glyph_bbox = _transformed_glyph_bounds(color_glyph.ufo, paint_glyph.glyph, context.transform) if glyph_bbox is None: continue if bounds is None: bounds = glyph_bbox else: bounds = unionRect(bounds, glyph_bbox) if bounds is None: return # before quantizing to integer values > 1, we must first round floats to # int using the same rounding function (i.e. otRound) that fontTools # glyf table's compile method will use to round any float coordinates. bounds = tuple(otRound(v) for v in bounds) if quantize_factor > 1: return _quantize_bounding_rect(*bounds, factor=quantize_factor) return bounds
def draw(surface, paths, text, features): bounds = None lines = [] y = 0 for path in paths: font = BlackRendererFont(path) buf = hb.Buffer() buf.add_str(text) buf.guess_segment_properties() hb.shape(font.hbFont, buf, features) line, rect, height = makeLine(buf, font, y) lines.append((font, line, rect, y)) if bounds is None: bounds = rect bounds = unionRect(bounds, rect) y += height with surface.canvas(bounds) as canvas: for font, line, rect, y in lines: with canvas.savedState(): # Center align the line. x = (bounds[2] - rect[2]) / 2 canvas.translate(x, y) for glyph in line: with canvas.savedState(): canvas.translate(glyph.xOffset, glyph.yOffset) font.drawGlyph(glyph.name, canvas) canvas.translate(glyph.xAdvance, glyph.yAdvance)
def _distributeSpacing(self, index, title): glyph = CurrentGlyph() if glyph is None: return rects, selectedContours, selectedBPoints = getSelectionData(glyph) if len(rects) < 3: return widths = [] heights = [] edgeRect = None for rect in rects: xMin, yMin, xMax, yMax = rect widths.append(xMax - xMin) heights.append(yMax - yMin) if edgeRect is None: edgeRect = rect else: edgeRect = unionRect(edgeRect, rect) objectWidth = sum(widths) objectHeight = sum(heights) xMin, yMin, xMax, yMax = edgeRect overallWidth = xMax - xMin overallHeight = yMax - yMin availableXSpace = overallWidth - objectWidth availableYSpace = overallHeight - objectHeight xSpace = availableXSpace / (len(rects) - 1) ySpace = availableYSpace / (len(rects) - 1) spaceBetweenObjects = (xSpace, ySpace)[index] ordered = [(bPoint.anchor[index], (bPoint.anchor[0], bPoint.anchor[1], bPoint.anchor[0], bPoint.anchor[1]), bPoint) for bPoint in selectedBPoints] ordered += [(contour.bounds[index], contour.bounds, contour) for contour in selectedContours] ordered.sort() glyph.prepareUndo(title) prevEdge = None for pos, bounds, obj in ordered[:-1]: xMin, yMin, xMax, yMax = bounds width = xMax - xMin height = yMax - yMin size = (width, height)[index] if prevEdge is None: newPos = (xMin, yMin)[index] else: newPos = prevEdge + spaceBetweenObjects d = newPos - pos print(d) if d != 0: if index == 0: obj.moveBy((d, 0)) else: obj.moveBy((0, d)) prevEdge = newPos + size for bPoint in selectedBPoints: bPoint.round() for contour in selectedContours: contour.round() glyph.changed() glyph.performUndo() UpdateCurrentGlyphView()
def _get_controlPointBounds(self): fontRect = None for glyph in self: glyphRect = glyph.controlPointBounds if glyphRect is None: continue if fontRect is None: fontRect = glyphRect else: fontRect = unionRect(fontRect, glyphRect) return fontRect
def _get_controlPointBounds(self): fontRect = None for glyph in self: glyphRect = glyph.controlPointBounds if glyphRect is None: continue if fontRect is None: fontRect = glyphRect else: fontRect = unionRect(fontRect, glyphRect) return fontRect
def glyphBoundsRepresentationFactory(glyph): bounds = None for group in (glyph, glyph.components): for obj in group: b = obj.bounds if b is not None: if bounds is None: bounds = b else: bounds = unionRect(bounds, b) return bounds
def bounds(self): bounds = None for path, colorID in self.layers: if not path.elementCount(): continue pathBounds = rectFromNSRect(path.controlPointBounds()) if bounds is None: bounds = pathBounds else: bounds = unionRect(bounds, pathBounds) return bounds
def _getContourComponentBounds(self, attr): bounds = None subObjects = [contour for contour in self] subObjects += [component for component in self.components] for subObject in subObjects: b = getattr(subObject, attr) if b is not None: if bounds is None: bounds = b else: bounds = unionRect(bounds, b) return bounds
def fromSeq(cls, seq: Sequence[Tuple[Rectangle, Any]]): if len(seq) == 0: # empty tree, pass None for bounds as a special case return cls(None, None, None, None) elif len(seq) == 1: bounds, leaf = seq[0] return cls(bounds, leaf, None, None) mid = len(seq) // 2 left = cls.fromSeq(seq[:mid]) right = cls.fromSeq(seq[mid:]) bounds = unionRect(left[0], right[0]) return cls(bounds, None, left, right)
def glyphBoundsRepresentationFactory(glyph): # base glyph pen = BoundsPen(glyph.getParent()) glyph.draw(pen) bounds = pen.bounds # components for component in glyph.components: b = component.bounds if b is not None: if bounds is None: bounds = b else: bounds = unionRect(bounds, b) return bounds
def _bbox(f, gnames, points, scale=1): gset = f.glyphSet bbox = (0, 0, 0, 0) for i, gname in enumerate(gnames): if hasattr(points, '__len__') and i == len(points): points.append((bbox[2] / scale, 0)) pt = points[i] if i < len(points) else (0, 0) g = gset[gname]._glyph if g is None or not hasattr(g, 'xMin'): gbox = (0, 0, 0, 0) else: gbox = (g.xMin * scale, g.yMin * scale, g.xMax * scale, g.yMax * scale) bbox = arrayTools.unionRect( bbox, arrayTools.offsetRect(gbox, pt[0] * scale, pt[1] * scale)) return bbox
def makeFontBoundingBox(self): """ Make a bounding box for the font. **This should not be called externally.** Subclasses may override this method to handle the bounds creation in a different way if desired. """ if not hasattr(self, "glyphBoundingBoxes"): self.glyphBoundingBoxes = self.makeGlyphsBoundingBoxes() fontBox = None for glyphName, glyphBox in self.glyphBoundingBoxes.items(): if glyphBox is None: continue if fontBox is None: fontBox = glyphBox else: fontBox = unionRect(fontBox, glyphBox) if fontBox is None: # unlikely fontBox = BoundingBox(0, 0, 0, 0) return fontBox
def unionBounds(bounds1, bounds2): if bounds1 is None: return bounds2 if bounds2 is None: return bounds1 return BoundingBox(*unionRect(bounds1, bounds2))
def union(self, otherRect): return Rect.FromMnMnMxMx(unionRect(self.mnmnmxmx(), otherRect.mnmnmxmx()))
def _get_controlPointBounds(self): from fontTools.misc.transform import Transform # storage glyphRects = {} componentReferences = {} # scan loaded glyphs for glyphName, glyph in self._glyphs.items(): if glyphName in self._scheduledForDeletion: continue glyphRect = glyph.controlPointBounds if glyphRect: glyphRects[glyphName] = glyphRect # scan glyphs that have not been loaded if self._glyphSet is not None: for glyphName, fileName in self._glyphSet.contents.items(): if glyphName in self._glyphs or glyphName in self._scheduledForDeletion: continue glif = self._glyphSet.getGLIF(glyphName) points, components = _fetchControlPointBoundsData(glif) if points: glyphRects[glyphName] = calcBounds(points) for base, transformation in components: xScale, xyScale, yxScale, yScale, xOffset, yOffset = transformation if glyphName not in componentReferences: componentReferences[glyphName] = [] componentReferences[glyphName].append( (base, xScale, xyScale, yxScale, yScale, xOffset, yOffset)) # get the transformed component bounding boxes and update the glyphs for glyphName, components in componentReferences.items(): glyphRect = glyphRects.get(glyphName, (None, None, None, None)) # XXX this doesn't handle nested components for base, xScale, xyScale, yxScale, yScale, xOffset, yOffset in components: # base glyph doesn't exist if base not in glyphRects: continue baseRect = glyphRects[base] # base glyph has no points if None in baseRect: continue # transform the base rect transform = Transform(xx=xScale, xy=xyScale, yx=yxScale, yy=yScale, dx=xOffset, dy=yOffset) xMin, yMin, xMax, yMax = baseRect (xMin, yMin), (xMax, yMax) = transform.transformPoints([ (xMin, yMin), (xMax, yMax) ]) componentRect = (xMin, yMin, xMax, yMax) # update the glyph rect if None in glyphRect: glyphRect = componentRect else: glyphRect = unionRect(glyphRect, componentRect) # store the updated rect glyphRects[glyphName] = glyphRect # work out the unified rect fontRect = None for glyphRect in glyphRects.values(): if fontRect is None: fontRect = glyphRect elif glyphRect is not None: fontRect = unionRect(fontRect, glyphRect) # done return fontRect
def test_unionRect(): assert unionRect((0, 10, 20, 30), (0, 40, 20, 50)) == (0, 10, 20, 50)
def test_unionRect(): assert unionRect((0, 10, 20, 30), (0, 40, 20, 50)) == (0, 10, 20, 50)