def findFont(fontPath, default=None, lazy=True): """Answers the font the has name fontName. >>> roboto = findFont('Roboto-Regular') >>> roboto <Font Roboto-Regular> >>> f = findFont('Skia-cannot-be-found') >>> f is None True >>> f = findFont('Skia-cannot-be-found', default=roboto) # Default is a font. >>> f is roboto True >>> f = findFont('Skia-cannot-be-found', default='Roboto-Regular') # Default is a name. >>> f <Font Roboto-Regular> """ from pagebot.fonttoolbox.fontpaths import getFontPaths fontPaths = getFontPaths() if fontPath in fontPaths: return getFont(fontPaths[fontPath], lazy=lazy) # There ia a default defined. If it is a string, try to find it. if isinstance(default, str) and default != fontPath: # Avoid circular calls return findFont(default, lazy=lazy) assert default is None or isinstance(default, Font) return default # Otherwise assume it is a Font instance or None
def getFamilyPaths(useFontInfo=True, useFileName=True, force=False): """Construct a dictionary of familyName-->[fontPath, fontPath, ...]. If omitted, then create the families from all avaible font paths found by the context. The flag useFontInfo defines if the familyName, styleName) should be taken from the font.info or just guessed from the font file name. >>> familyPaths = getFamilyPaths() >>> len(familyPaths['Roboto']) 38 >>> len(familyPaths['Bungee']) 5 """ global FAMILY_PATHS if force: FAMILY_PATHS = {} if not FAMILY_PATHS: # If forced or not initialized yet for fontPath in getFontPaths().values(): familyName = None if useFontInfo: font = getFont(fontPath) if font is not None: familyName = font.info.familyName if not familyName and useFileName: familyName = path2FamilyName(fontPath) if familyName is not None: if familyName not in FAMILY_PATHS: FAMILY_PATHS[familyName] = [] FAMILY_PATHS[familyName].append(fontPath) return FAMILY_PATHS
def findFonts(pattern, lazy=True): """Answers a list of Font instances where the pattern fits the font path. If pattern is a list, all parts should have a match. # TODO: make case insensitive """ """ >>> findFonts('Roboto-Thi') [<Font Roboto-Thin>, <Font Roboto-ThinItalic>] >>> # Select on family and name parts. >>> findFonts(('Robo', 'Ita', 'Thi')) [<Font Roboto-ThinItalic>] >>> # Select on style parts only. >>> findFonts(('Ita', 'Bol', 'Con')) [<Font RobotoCondensed-BoldItalic>] """ fontPaths = getFontPaths() fonts = [] if not isinstance(pattern, (list, tuple)): pattern = [pattern] for fontPath in fontPaths: found = True for match in pattern: if not match in fontPath: found = False break if found: fonts.append(findFont(fontPath, lazy=lazy)) return fonts
def findFont(fontPath, lazy=True): u"""Answer the font the has name fontName. >>> findFont('Roboto-Regular') <Font Roboto-Regular> """ from pagebot.fonttoolbox.fontpaths import getFontPaths fontPaths = getFontPaths() if fontPath in fontPaths: return getFont(fontPaths[fontPath]) return None
def __init__(self): """Connects main window and output window for errors.""" for path in getFontPaths(): name = path.split('/')[-1] self.FONTS.append(name) self.font = findFont(self.FONTS[0]) self.context = getContext() self.window = Window((800, 600), minSize=(1, 1), closable=True) self.window.drawView = DrawView((0, 32, -0, -0)) self.outputWindow = Window((400, 300), minSize=(1, 1), closable=True) self.outputWindow.outputView = OutPutEditor((0, 0, -0, -0), readOnly=True) self.initialize() self.window.open() self.outputWindow.open()
def findFont(fontPath, default=None, lazy=True): """Answers the font the has name fontName. >>> f = findFont('Roboto-Regular') >>> f <Font Roboto-Regular> >>> notSkiaFont = findFont('Skia-cannot-be-found') >>> notSkiaFont is None True >>> # Default is a font. >>> # Set RobotoFont as default. >>> notSkiaFont = findFont('Skia-cannot-be-found', default=f) >>> notSkiaFont is f # Found robotoFont instead True >>> # Default is a name. >>> f = findFont('Skia-cannot-be-found', default='Roboto-Regular') # Found default RobotoFont instead >>> f <Font Roboto-Regular> """ if isinstance(fontPath, Font): # It's already a Font instance, just answer it. return fontPath fontPaths = getFontPaths() # Otherwise, let's see if we can find it by name. if fontPath in fontPaths: font = getFont(fontPaths[fontPath], lazy=lazy) if font is not None: return font font = getFont(fontPath) if font is not None: return font # A default is defined. If it's a string, try to find it. Avoid c76ircular # calls. if isinstance(default, str) and default != fontPath: return findFont(default, lazy=lazy) assert default is None or isinstance(default, Font) # Otherwise assume it is a Font instance or None. return default
def getFamilies(familyPaths=None, useFontInfo=True, useFileName=True, force=False): u"""Construct a dictionary of Family instances from dictionary familyPaths. If omitted, then create the families from all aviable font paths found in the by the context. The flag useFontInfo defines if the familyName, styleName) should be taken from the font.info or guess from the font file name. >>> families = getFamilies() >>> 'Roboto' in families True >>> 'Bungee' in families True >>> families = getFamilies(useFontInfo=False, force=True) # Forced to look an fileName only, Roboto is a family >>> 'Roboto' in families True >>> families = getFamilies(useFileName=False, force=True) # Looking into font.info, Roboto is the family name. >>> 'Roboto' in families True >>> #families = getFamilies(useFontInfo=False, useFileName=False) finds nothing """ global FAMILIES if force: FAMILIES = {} if not FAMILIES: # If forced or not initialized yet for fontPath in getFontPaths().values(): font = getFont(fontPath) if font is not None: #print(font.path.split('/')[-1], repr(font.info.familyName), repr(font.info.styleName)) familyName = None if useFontInfo: familyName = font.info.familyName if not familyName and useFileName: familyName = path2FamilyName(font.path) if familyName: if familyName not in FAMILIES: FAMILIES[familyName] = Family(familyName) FAMILIES[familyName].addFont(font) return FAMILIES
y3 = y + d context.stroke(r, g, b) line((x0, y0), (x1, y1)) line((x2, y2), (x3, y3)) W, H = 1750, 2250 X0 = 75 Y0 = 500 C = 0.5 F = 2 / 3 glyphName = 'Q' x = 50 context.newPage(W, H) DBFont('LucidaGrande', 24) PATH = getFontPaths()['Roboto-Black'] font = Font(PATH) glyph = font[glyphName] path = BezierPath() contours = [] contour = None coordinates = glyph.ttGlyph.coordinates context.fill((0, 1, 1, 0.2)) # Move glyph up so we can see results below descender level. translate(X0, Y0) # Draws the glyph. c = glyph.contours pbSegments = glyph._segments context.stroke((0, 0.3, 0.3)) context.drawGlyphPath(glyph)
# # P A G E B O T # # Copyright (c) 2016+ Buro Petr van Blokland + Claudia Mens # www.pagebot.io # Licensed under MIT conditions # # Supporting DrawBot, www.drawbot.com # Supporting Flat, xxyxyz.org/flat # ----------------------------------------------------------------------------- # # UseProofing.py # # from pagebot.contexts.platform import getContext from pagebot.toolbox.units import * from pagebot.publications.proofing.pagewide import PageWide from pagebot.constants import A3 from pagebot.fonttoolbox.objects.font import findFont from pagebot.fonttoolbox.fontpaths import getFontPaths print(sorted(getFontPaths().keys())) font = findFont('BungeeOutline-Regular') HEIGHT, WIDTH = A3 context = getContext() context.newPage(pt(WIDTH), pt(HEIGHT)) proof = PageWide(context) SIZE = 54 context.translate(SIZE, HEIGHT - SIZE) proof.draw(font, 'abcdefghijklmnopqrstuvwxyz', SIZE)
def draw(): W, H = 1750, 2250 X0 = 75 Y0 = 500 C = 0.5 F = 2 / 3 glyphName = 'Q' x = 50 context.newPage(W, H) DBFont('LucidaGrande', 24) PATH = getFontPaths()['Roboto-Black'] font = Font(PATH) glyph = font[glyphName] path = BezierPath() contours = [] contour = None coordinates = glyph.ttGlyph.coordinates context.fill((0, 1, 1, 0.2)) # Move glyph up so we can see results below descender level. translate(X0, Y0) # Draws the glyph. c = glyph.contours pbSegments = glyph._segments context.stroke((0, 0.3, 0.3)) context.drawGlyphPath(glyph) context.stroke(None) context.fill(0) # Converts coordinates to PageBot Points and assigns points # to contours. for i, (x, y) in enumerate(coordinates): start = i - 1 in glyph.endPtsOfContours p = Point(x, y, glyph.flags[i]) if i == 0: contour = [p] elif start: contour.append(contour[0]) contours.append(contour) contour = [p] else: contour.append(p) if i == len(coordinates) - 1: contour.append(contour[0]) contours.append(contour) d = 15 x += d y += d context.text('%d' % i, (x, y)) segments = [] implied = [] cps = [] for n, contour in enumerate(contours): point = contour[0] segment = [point] path.moveTo((point.x, point.y)) for i, point in enumerate(contour[1:]): if point.onCurve: segment.append(point) segments.append(segment) segment = [point] else: segment.append(point) for j, segment in enumerate(segments): # Lets this script calculate and draw implied points and derived cubic # control points. Optionally draw path itself later by calling # drawPath(path) (see below.) drawSegment(path, segment, implied, cps) # Draws oncurve points and offcurve control points. for contour in contours: for i, point in enumerate(contour): x = point.x y = point.y if point.onCurve: context.fill(ONCURVE_COLOR) context.circle(x, y, ONCURVE_SIZE) else: # Quadratic offcurves. context.fill(QUADRATIC_CONTROLPOINT_COLOR) context.circle(x, y, QUADRATIC_CONTROLPOINT_SIZE) x = 500 y = 400 d = 30 context.fill(0.2) context.stroke((1, 0, 0)) context.line((0, 0), (W -2*X0, 0)) x = 0 y = -100 + 24 context.line((x, y), (x, y - 114)) x += 30 y = -100 + ONCURVE_SIZE context.stroke(None) context.fill(ONCURVE_COLOR) context.circle(x, y, ONCURVE_SIZE) y -= 30 context.fill(IMPLIED_ONCURVE_COLOR) context.circle(x, y, IMPLIED_ONCURVE_SIZE) y -= 30 context.fill(CUBIC_CONTROLPOINT_COLOR) context.circle(x, y, CUBIC_CONTROLPOINT_SIZE) y -= 30 context.fill(QUADRATIC_CONTROLPOINT_COLOR) context.circle(x, y, QUADRATIC_CONTROLPOINT_SIZE) context.fill(0) x += 30 y = -100 context.text('On-curve point', (x, y)) y -= 30 context.text('Implied on-curve point', (x, y)) y -= 30 context.text('Cubic control point', (x, y)) y -= 30 context.text('Quadratic control point', (x, y))
def draw(context): W, H = 1750, 2250 X0 = 75 Y0 = 500 C = 0.5 F = 2 / 3 glyphName = 'Q' x = 50 context.newPage(W, H) PATH = getFontPaths()['Roboto-Black'] font = Font(PATH) print(font) st = dict(font=font, fontSize=40, textFill=(1, 0, 0)) # FIXME: seem to yield wrong value in DrawBot Context, # FIXME: float value errors in Flat now. #, leading=1.4) glyph = font[glyphName] print(glyph) path = BezierPath() contours = [] contour = None coordinates = glyph.ttGlyph.coordinates context.fill((0, 1, 1, 0.2)) # Move glyph up so we can see results below descender level. context.translate(X0, Y0) # Draws the glyph. c = glyph.contours pbSegments = glyph._segments context.stroke((0, 0.3, 0.3)) context.drawGlyphPath(glyph) context.stroke(None) context.fill(0) # Converts coordinates to PageBot Points and assigns points # to contours. for i, (x, y) in enumerate(coordinates): start = i - 1 in glyph.endPtsOfContours p = Point(x, y, onCurve=glyph.flags[i]) if i == 0: contour = [p] elif start: contour.append(contour[0]) contours.append(contour) contour = [p] else: contour.append(p) if i == len(coordinates) - 1: contour.append(contour[0]) contours.append(contour) d = 15 x += d y += d t = context.newString('%d' % i, style=st) context.text(t, (x, y)) segments = [] implied = [] cps = [] for n, contour in enumerate(contours): point = contour[0] segment = [point] path.moveTo((point.x, point.y)) for i, point in enumerate(contour[1:]): if point.onCurve: segment.append(point) segments.append(segment) segment = [point] else: segment.append(point) for j, segment in enumerate(segments): # Lets this script calculate and draw implied points and derived cubic # control points. Optionally draw path itself later by calling # drawPath(path) (see below.) drawSegment(path, segment, implied, cps) # Draws oncurve points and offcurve control points. for contour in contours: for i, point in enumerate(contour): x = point.x y = point.y if point.onCurve: context.fill(ONCURVE_COLOR) context.circle(x, y, ONCURVE_SIZE) else: # Quadratic offcurves. context.fill(QUADRATIC_CONTROLPOINT_COLOR) context.circle(x, y, QUADRATIC_CONTROLPOINT_SIZE) x = 500 y = 400 d = 30 context.fill(0.2) context.stroke((1, 0, 0)) context.line((0, 0), (W - 2 * X0, 0)) x = 0 y = -100 + 24 context.line((x, y), (x, y - 114)) x += 30 y = -100 + ONCURVE_SIZE context.stroke(None) context.fill(ONCURVE_COLOR) context.circle(x, y, ONCURVE_SIZE) y -= 30 context.fill(IMPLIED_ONCURVE_COLOR) context.circle(x, y, IMPLIED_ONCURVE_SIZE) y -= 30 context.fill(CUBIC_CONTROLPOINT_COLOR) context.circle(x, y, CUBIC_CONTROLPOINT_SIZE) y -= 30 context.fill(QUADRATIC_CONTROLPOINT_COLOR) context.circle(x, y, QUADRATIC_CONTROLPOINT_SIZE) context.fill(0) x += 30 y = -100 t = context.newString('On-curve point', style=st) context.text(t, (x, y)) y -= 30 t = context.newString('Implied on-curve point', style=st) context.text(t, (x, y)) y -= 30 t = context.newString('Cubic control point', style=st) context.text(t, (x, y)) y -= 30 t = context.newString('Quadratic control point', style=st) context.text(t, (x, y)) try: path = '_export/DrawQuadGlyph%s.pdf' % context.name context.saveImage(path) except: print(traceback.format_exc()) '''