def _drawGlyphMarker(self, axisName, mx, my, glyphName, fontSize, location, strokeW=2): # Middle circle context.fill(1) context.stroke(0.7) context.strokeWidth(strokeW) context.oval(mx - fontSize / 2 * self.R, my - fontSize / 2 * self.R, fontSize * self.R, fontSize * self.R) variableFont = getVariableFont(self.font, location) # Show axis name below circle marker? if self.showAxisNames and axisName is not None: fs = context.newString(axisName, style=dict(font=variableFont.installedName, fontSize=fontSize / 4, textFill=0)) tw, th = context.textSize(fs) context.text( fs, (mx - tw / 2, my - fontSize / 2 * self.R - th * 2 / 3)) glyphPathScale = fontSize / self.font.info.unitsPerEm context.drawGlyphPath(variableFont, glyphName, mx, my - fontSize / 3, s=glyphPathScale, fillColor=0)
def drawSpiral(): mx = W/2+X my = H/2+Y runs = False c.newPath() c.moveTo((mx, my)) for n in range(0, int(N), 4): dx1 = n*Sx*D dy1 = n*Sy*D dx2 = (n+1)*Sx*D dy2 = (n+1)*Sy*D dx3 = (n+2)*Sx*D dy3 = (n+2)*Sy*D dx4 = (n+3)*Sx*D dy4 = (n+3)*Sy*D #dx5 = (n+4)*Sx*D #dy5 = (n+4)*Sy*D if not runs: c.moveTo((mx, my)) else: c.curveTo((mx-dx1*Exy, my-dy1), (mx-dx1, my-dy1*Exy), (mx-dx1, my)) c.curveTo((mx-dx2, my+dy2*Exy), (mx-dx2*Exy, my+dy2), (mx, my+dy2)) c.curveTo((mx+dx3*Exy, my+dy3), (mx+dx3, my+dy3*Exy), (mx+dx3, my)) c.curveTo((mx+dx4, my-dy4*Exy), (mx+dx4*Exy, my-dy4), (mx, my-dy4)) runs = True c.fill(None) c.stroke(0) c.drawPath()
def drawString(s, px, py, fontName, color=None, gridColor=None): if fontName in FONTS: fontName = FONTS[fontName] context.font(fontName) context.fontSize(FS) context.stroke(None) if color is not None: r, g, b, t = color context.fill((r, g, b, t)) else: context.fill(color or 0) context.text(s, (px, py))
def run(): W, H = 1000, 400 c.newPage(W, H) txt = "Hello World" x, y = 10, 100 fs = c.newString(txt, style=dict(fontSize=300, font="Verdana")) # draw the text c.text(fs, (x, y)) # calculate the size of the text textWidth, textHeight = c.textSize(txt) # set a red stroke color c.stroke(1, 0, 0) # loop over all font metrics for metric in (0, fs.fontDescender(), fs.fontAscender(), fs.fontXHeight(), fs.fontCapHeight()): # draw a red line with the size of the drawn text c.line((x, y + metric), (W - 2 * x, y + metric))
def drawPageFrame(w): c.fill(1) c.stroke(0) c.newPath() c.moveTo((PADDING, H - PADDING)) c.lineTo((PADDING + w, H - PADDING)) c.lineTo((PADDING + w, H / 2 + PADDING)) c.curveTo((PADDING + w / 2, H / 2 + PADDING), (PADDING + w / 2, H / 2 + PADDING - M / 2), (PADDING, H / 2 + PADDING - M / 2)) c.closePath() c.drawPath() c.fill(None) c.stroke(0.5) c.strokeWidth(4) leading = 14 for n in range(10): c.line( (PADDING + M, H - 5 * PADDING - n * leading), (PADDING + w - M - LINE_ENDINGS[n], H - 5 * PADDING - n * leading))
def _drawGlyphMarker(self, mx, my, glyphName, markerSize, location, strokeW=2): # Middle circle c.fill(1) c.stroke(0) c.strokeWidth(strokeW) c.oval(mx - markerSize / 2, my - markerSize / 2, markerSize, markerSize) glyphPathScale = markerSize / self.font.info.unitsPerEm * 3 / 4 drawGlyphPath(self.font.ttFont, glyphName, mx, my - markerSize / 4, location, s=glyphPathScale, fillColor=0)
def _drawGlyphMarker(self, mx, my, glyphName, fontSize, location, strokeW=2): # Middle circle c.fill(1) c.stroke(0) c.strokeWidth(strokeW) c.oval(mx - fontSize * self.R, my - fontSize * self.R, fontSize * 2 * self.R, fontSize * 2 * self.R) glyphPathScale = fontSize / self.font.info.unitsPerEm drawGlyphPath(self.font.ttFont, glyphName, mx, my - fontSize / 4, location, s=glyphPathScale, fillColor=0)
def draw(w): u""" Draw 3 lines of text: the boundaries of with the width axis and the interpolated width from the slider value. If the slider goes of the extremes, then the middle line stops at the boundary width. """ d = fitVariableWidth(f, HEADLINE, w, HEADLINE_SIZE, condensedLocation, wideLocation) c.newPage(W, H) c.fill(1) c.rect(0, 0, W, H) c.text(d['condensedFs'], (PADDING, 50)) c.text(d['fs'], (PADDING, 100)) c.text(d['wideFs'], (PADDING, 150)) c.fill(None) c.stroke(0) c.line((PADDING, PADDING), (PADDING, H-PADDING)) c.line((PADDING+d['condensedWidth'], PADDING), (PADDING+d['condensedWidth'], H-PADDING)) c.line((PADDING+d['width'], PADDING), (PADDING+d['width'], H-PADDING)) c.line((PADDING+d['wideWidth'], PADDING), (PADDING+d['wideWidth'], H-PADDING)) c.stroke(None) c.fill(0) c.text('%d %0.2f' % (round(d['condensedWidth']), d['condensedLocation']['wdth']), (PADDING + d['condensedWidth'] + 5, PADDING)) c.text('%d %0.2f' % (round(d['width']), d['location']['wdth']), (PADDING + d['width'] + 5, PADDING)) c.text('%d %0.2f' % (round(d['wideWidth']), d['wideLocation']['wdth']), (PADDING + d['wideWidth'] + 5, PADDING)) c.stroke(1, 0, 0) c.line((PADDING+w, PADDING), (PADDING+w, H-PADDING)) c.stroke(None) c.fill(1, 0, 0) c.text('Column %d' % w, (PADDING+w+5, H-PADDING-5))
# This script shows the behavior of FormattedStrings in DrawBot Context. # Tracking is added after the glyphs, so the measured width of a tracked # string is wider that it looks. # To safely measure the real width of the string, the width of one "track" # needs to be subtracted. from pagebot.contexts import defaultContext as context # Create a new page w, h = 400, 100 context.newPage(w, h) # Draw vertical line in the middle of the page as reference. context.fill(None) context.strokeWeight = 0.5 context.stroke((0, 0, 0.4)) context.line((w / 2, 0), (w / 2, h)) TRACKING = 1 FONT_SIZE = 14 TRACKED_SPACE = FONT_SIZE * TRACKING # New Babel string, probably DrawBot FormattedString flavor. bs = context.newString('TRACKEDSTRING', style=dict(font='Verdana', fontSize=FONT_SIZE, rTracking=TRACKING)) # Call DrawBot textSize to determine the size of the string # including the tracking tw, th = bs.size()
def draw(self, orgX, orgY): if not self.show: return w = self.w # Width of the icon h = self.ih # Height of the icon e = self.E * self.scale # Ear size l = self.L * self.scale # Line x = self.x + orgX y = self.y + orgY path = c.newPath() c.moveTo((0, 0)) c.lineTo((0, h)) c.lineTo((w - e, h)) c.lineTo((w, h - e)) c.lineTo((w, 0)) c.lineTo((0, 0)) c.closePath() c.moveTo((w - e, h)) c.lineTo((w - e, h - e)) c.lineTo((w, h - e)) c.saveGraphicState() c.fill(1) c.stroke(0) c.strokeWidth = self.line c.moveTo((x, y)) c.drawPath(path) labelSize = e fs = c.newString(self.char, style=dict(font=self.f.installedName, textFill=0, fontSize=h * 2 / 3)) tw, th = c.textSize(fs) c.text(fs, (w / 2 - tw / 2, h / 2 - th / 3.2)) if self.title: fs = c.newString(self.title, style=dict(font=self.labelFont.installedName, textFill=0, rTracking=self.LABEL_RTRACKING, fontSize=labelSize)) tw, th = c.textSize(fs) c.text(fs, (w / 2 - tw / 2, self.ih + th / 2)) y = -self.LABEL_RLEADING * labelSize if self.name: fs = c.newString(self.name, style=dict(font=self.labelFont.installedName, textFill=0, rTracking=self.LABEL_RTRACKING, fontSize=labelSize)) tw, th = c.textSize(fs) c.text(fs, (w / 2 - tw / 2, y)) y -= self.LABEL_RLEADING * labelSize if self.label: fs = c.newString(self.label, style=dict(font=self.labelFont.installedName, textFill=0, rTracking=self.LABEL_RTRACKING, fontSize=labelSize)) tw, th = c.textSize(fs) c.text(fs, (w / 2 - tw / 2, y)) c.restoreGraphicState()
def draw(self): # Try to use TYPETR-Bitcount. Only is instsalled in the system. # See samples at https://bitcount.typenetwork.com # Order a license at: https://store.typenetwork.com/foundry/typetr/fonts/bitcount USE_BITCOUNT = True LETTERS = 'ABCEFGHIJKLMNOPQRSTUVWXYZ' Frames = 80 W = H = 500 IMAGE_PATH = '_export/HorizonWorld.gif' if not USE_BITCOUNT or not 'BitcountMonoDouble-RegularCircle' in context.installedFonts( ): fontNames = ['Georgia-Bold', 'Georgia'] else: fontNames = [] for fontName in installedFonts(): if 'BitcountMono' in fontName and not 'Italic' in fontName: fontNames.append(fontName) letters = [] for n in range(10): c = choice(LETTERS) x = 0 y = 15 z = 20 + int(random() * 500) x = 1 / z + random() * 100 - 100 cc = random() * 0.8 + 0.1, random() * 0.1, random() * 0.8 * 0.1 f = choice(fontNames) letters.append((c, f, x, y, z, cc)) for n in range(Frames): context.newPage(W, H) context.fill(0.8) context.rect(0, 0, W, H) for c, f, x, y, z, (r, g, b) in letters: #y = y/z context.fill( (r, g, b) ) # Needs tuple, instead of separate r, g, b as in DrawBot context.font(f) context.stroke(None) fSize = min(200, 40000 / z) context.fontSize(fSize) context.text(c, (x + 250, y + 250 - fSize / 2)) context.fill(None) context.strokeWidth(0.5) context.stroke(0.5) context.line((0, 250), (500, 250)) context.fill( (1, 1, 1, 0.4) ) # Needs tuple, instead of separate r, g, b as in DrawBot context.rect(0, 0, W, H / 2 - 1) for n in range(0, 500, 10): context.fill(None) context.stroke(1) y = W / 2 - 2 - n * 0.4 lineThickness = (random() * 3 + 0.5) * (H / 2 - y) / 10 context.strokeWidth(lineThickness) context.line((0, y - lineThickness / 2), (W, y - lineThickness / 2)) context.saveImage(IMAGE_PATH)
print 'List of APoints of the glyph:', g.points # Get the 4th APoint instance, that has reference back to the glyph.points[p.index] p = g.points[3] # This is the point we got. print 'glyph.points[3]:', p.x, p.y, 'Glyph:', p.glyph.name, 'Index:', p.index # Change the point position. In DrawBot this works interactive while holding cmd-drag in selected d. d = -80 p.x += d p.y += d p.onCurve = False # Now the glyph is dirty print 'Changed point:', p, 'Glyph is dirty:', g.dirty # Update the cached data, such as glyph.points, glyph.path g.update() print 'Now it is clean. Glyph is dirty:', g.dirty # Draw the changed path c.fill(None) c.stroke(0, 1) c.drawPath(g.path, (0, 0), s) # Draw the position of the points c.stroke((1, 0, 0), 2) c.fill(None) for p in g.points: if p.onCurve: R = 16 else: R = 6 c.oval(p.x * s - R / 2, p.y * s - R / 2, R, R) c.saveImage(EXPORT_PATH)
def _drawFontCircle(self, px, py): context = self.context # Get context from the parent doc. context.fill(0.9) context.stroke(None) mx = px + self.w / 2 my = py + self.h / 2 # Gray circle that defines the area of context.oval(px, py, self.w, self.h) # Draw axis spikes first, so we can cover them by the circle markers. axes = self.font.axes fontSize = self.style.get('fontSize', self.DEFAULT_FONT_SIZE) # Draw name of the font bs = context.newString(self.font.info.familyName, style=dict( font=self.style['labelFont'], fontSize=self.style['axisNameFontSize'], textFill=0)) context.text(bs, (px - fontSize / 2, py + self.h + fontSize / 2)) # Draw spokes context.fill(None) context.stroke(0) context.strokeWidth(1) context.newPath() for axisName, angle in self.angles.items(): markerX, markerY = self._angle2XY(angle, self.w / 2) context.moveTo((mx, my)) context.lineTo((mx + markerX, my + markerY)) context.drawPath() # Draw default glyph marker in middle. defaultLocation = {} self._drawGlyphIcon(mx, my, self.glyphName, fontSize, defaultLocation, strokeW=3) # Draw DeltaLocation circles. for axisName, (minValue, defaultValue, maxValue) in axes.items(): angle = self.angles[axisName] # Outside maxValue location = {axisName: maxValue} markerX, markerY = self._angle2XY(angle, self.w / 2) self._drawGlyphIcon(mx + markerX, my + markerY, self.glyphName, fontSize / 2, location) # Interpolated DeltaLocation circles. location = { axisName: minValue + (maxValue - minValue) * self.INTERPOLATION } markerX, markerY = self._angle2XY(angle, self.w / 4) self._drawGlyphIcon(mx + markerX * self.INTERPOLATION * 2, my + markerY * self.INTERPOLATION * 2, self.glyphName, fontSize / 2, location) # Draw axis names and DeltaLocation values if self.showAxisNames: for axisName, (minValue, defaultValue, maxValue) in axes.items(): angle = self.angles[axisName] location = {axisName: maxValue} valueFontSize = self.style.get('valueFontSize', 12) axisNameFontSize = self.style.get('axisNameFontSize', 12) markerX, markerY = self._angle2XY(angle, self.w / 2) bs = context.newString( self.makeAxisName(axisName), style=dict(font=self.style.get('labelFont', 'Verdana'), fontSize=axisNameFontSize, fill=self.style.get('axisNameColor', 0))) tw, th = context.textSize(bs) context.fill((0.7, 0.7, 0.7, 0.6)) context.stroke(None) context.rect( mx + markerX - tw / 2 - 4, my + markerY - axisNameFontSize / 2 - th * 1.5 - 4, tw + 8, th) context.text(bs, (mx + markerX - tw / 2, my + markerY - axisNameFontSize / 2 - th * 1.5)) # DeltaLocation master value if maxValue < 10: sMaxValue = '%0.2f' % maxValue else: sMaxValue = ` int(round(maxValue)) ` bs = context.newString( sMaxValue, style=dict(font=self.style.get('labelFont', 'Verdana'), fontSize=valueFontSize, fill=self.style.get('axisValueColor', 0))) tw, th = context.textSize(bs) context.fill((0.7, 0.7, 0.7, 0.6)) context.stroke(None) context.rect(mx + markerX - tw / 2 - 4, my + markerY + valueFontSize / 2 + th * 1.5 - 4, tw + 8, th) context.text(bs, (mx + markerX - tw / 2, my + markerY + valueFontSize / 2 + th * 1.5)) # DeltaLocation value interpolationValue = minValue + (maxValue - minValue) * self.INTERPOLATION if interpolationValue < 10: sValue = '%0.2f' % interpolationValue else: sValue = ` int(round(interpolationValue)) ` bs = context.newString( sValue, style=dict(font=self.style.get('labelFont', 'Verdana'), fontSize=valueFontSize, fill=self.style.get('axisValueColor', 0))) tw, th = context.textSize(bs) context.fill((0.7, 0.7, 0.7, 0.6)) context.stroke(None) context.rect( mx + markerX * self.INTERPOLATION - tw / 2 - 4, my + markerY * self.INTERPOLATION + valueFontSize / 2 + th * 1.5 - 4, tw + 8, th) context.text(bs, (mx + markerX * self.INTERPOLATION - tw / 2, my + markerY * self.INTERPOLATION + valueFontSize / 2 + th * 1.5)) # DeltaLocation value if minValue < 10: sValue = '%0.2f' % minValue else: sValue = ` int(round(minValue)) ` bs = context.newString( sValue, style=dict(font=self.style.get('labelFont', 'Verdana'), fontSize=valueFontSize, fill=self.style.get('axisValueColor', 0))) tw, th = context.textSize(bs) context.fill((0.7, 0.7, 0.7, 0.6)) context.stroke(None) minM = 0.2 context.rect(mx + markerX * minM - tw / 2 - 4, my + markerY * minM + th * 0.5 - 4, tw + 8, th) context.text(bs, (mx + markerX * minM - tw / 2, my + markerY * minM + th * 0.5))
glyphs = [] start = 16500 end = 16552 GLYPHS = ('e', 'H', 'O', 'Z') #GLYPHS = ('bullet', 'e','h', 'oe') #GLYPHS = sorted( cjkF.keys())[start:end] for name in GLYPHS: if name.startswith('.'): continue context.newPage(W, H) glyph = cjkF[name] context.save() context.transform((1, 0, 0, 1, 0, 150)) context.fill(None) context.stroke((0, 0, 0), 20) context.drawPath(glyph.path) context.line((0, 0), (1000, 0)) for index, p in enumerate(glyph.points): if p.onCurve: fs = context.newString('index', style=dict(fill=1, stroke=None, font='Verdana', fontSize=18)) tw, th = context.textSize(fs) context.fill(0) context.stroke(0) context.oval(p.x - 10, p.y - 10, 20, 20) context.text(fs, (p.x - tw / 2, p.y - th / 4)) else:
from pagebot.contexts.drawbotcontext import DrawBotContext from pagebot.contexts.flatcontext import FlatContext testContexts = ( (DrawBotContext(), '_export/testFlatString.pdf'), # TODO: Get this to work with Flat #(FlatContext(), '_export/testDrawBotString.pdf'), ) for context, path in testContexts: context.newPage(1000, 1000) leading = 24 for n in range(0, 1000, leading): context.stroke(1, 0, 0) context.fill(None) context.line((0, n),(1000,n)) fs1 = context.newString('') fs2 = context.newString('aaa vvv bbbbbb\nss' * 5, style=dict(fontSize=14, lineHeight=24)) appendS(fs1, fs2, 300, 24) bx, by, bw, bh = 50, 50, leading*3, 200#, leading*20 context.stroke(0) context.fill(None) context.rect(bx, by, bw, bh) Y = 100
def draw(w): u""" Draw 3 lines of text: the boundaries of with the width axis and the interpolated width from the slider value. If the slider goes of the extremes, then the middle line stops at the boundary width. """ d = fitVariableWidth(f, HEADLINE, w, HEADLINE_SIZE, condensedLocation, wideLocation) minWidth = d['condensedWidth'] maxWidth = d['wideWidth'] fixedWidth = minWidth + (maxWidth - minWidth) / 2 dFixed = fitVariableWidth(f, HEADLINE, fixedWidth, HEADLINE_SIZE, condensedLocation, wideLocation) c.newPage(W, H) y = 2 * PADDING c.fill(1) c.rect(0, 0, W, H) # Draw calculated fitting instance and the two boundary instances. c.text(d['condensedFs'], (PADDING, y + LEADING)) c.text(d['fs'], (PADDING, y + 2 * LEADING)) c.text(d['wideFs'], (PADDING, y + 3 * LEADING)) # Draw the instance choice of 3 if w < fixedWidth: c.text(d['condensedFs'], (PADDING, y)) elif w < maxWidth: c.text(dFixed['fs'], (PADDING, y)) else: c.text(d['wideFs'], (PADDING, y)) c.fill(0.5) c.fontSize(12) c.text('Variable Font Amstelvar (Maximum width)', (PADDING, y + 3 * LEADING + 40)) c.text('Variable Font Amstelvar (Calculated width)', (PADDING, y + 2 * LEADING + 40)) c.text('Variable Font Amstelvar (Minimum width)', (PADDING, y + LEADING + 40)) c.text('Traditional fixed font styles', (PADDING, y + 40)) # Draw vertical lines, marking the text headline widths and in read the # requested column width. Also draw the values of the column width and # the [wdth] axis value for that fitting location. c.fill(None) c.stroke(0) c.line((PADDING, PADDING), (PADDING, H - PADDING)) c.line((PADDING + d['condensedWidth'], PADDING), (PADDING + d['condensedWidth'], H - PADDING)) c.line((PADDING + d['width'], PADDING), (PADDING + d['width'], H - PADDING)) c.line((PADDING + d['wideWidth'], PADDING), (PADDING + d['wideWidth'], H - PADDING)) c.stroke(None) c.fill(0) c.text( '%d %0.2f' % (round(d['condensedWidth']), d['condensedLocation']['wdth']), (PADDING + d['condensedWidth'] + 5, PADDING)) c.text('%d %0.2f' % (round(d['width']), d['location']['wdth']), (PADDING + d['width'] + 5, PADDING)) c.text('%d %0.2f' % (round(d['wideWidth']), d['wideLocation']['wdth']), (PADDING + d['wideWidth'] + 5, PADDING)) c.stroke(1, 0, 0) c.line((PADDING + w, PADDING), (PADDING + w, H - PADDING)) c.stroke(None) c.fill(1, 0, 0) c.text('w=%d' % w, (PADDING + w + 5, H - PADDING - 5))
def draw(self, page, x, y): u"""Draw the circle info-graphic, showing most info about the variation font as can be interpreted from the file.""" c.fill(0.9) c.stroke(None) mx = x + self.w / 2 my = y + self.h / 2 # Gray circle that defines the area of c.oval(x, y, self.w, self.h) # Draw axis spikes first, so we can cover them by the circle markers. axes = self.font.axes fontSize = self.style.get('fontSize', self.DEFAULT_FONT_SIZE) # Calculate sorted relative angle pairs. xAngles = {} # X-ref, key is angle, value is list of axisName for axisName in axes: angle = globals()[axisName] if not angle in xAngles: # Ignore overlapping xAngles[angle] = axisName #print xAngles sortedAngles = sorted(xAngles) anglePairs = [] a1 = None for a2 in sortedAngles: if a1 is not None: if abs(a2 - a1) < 35: anglePairs.append((a1, a2)) a1 = a2 # Draw name of the font c.fill(0) c.text( c.newString(self.font.info.familyName, style=dict(font=self.style['labelFont'], fontSize=self.style['titleFontSize'])), (x - fontSize / 2, y + self.h + fontSize / 4)) # Draw spokes c.fill(None) c.stroke(0.7) c.strokeWidth(1) # Gray on full circle c.newPath() for axisName, angle in self.angles.items(): markerX, markerY = self._angle2XY(angle, self.w / 2) c.moveTo((mx - markerX, my - markerY)) c.lineTo((mx + markerX, my + markerY)) c.drawPath() # Black on range of axis. c.stroke(0) c.newPath() for axisName, angle in self.angles.items(): markerX, markerY = self._angle2XY(angle, self.w / 2) c.moveTo((mx, my)) c.lineTo((mx + markerX, my + markerY)) c.drawPath() # Pair combinations if anglePairs: c.newPath() for a1, a2 in anglePairs: markerX1, markerY1 = self._angle2XY(a1, self.w / 2) markerX2, markerY2 = self._angle2XY(a2, self.w / 2) c.moveTo((mx + markerX1, my + markerY1)) c.lineTo((mx + markerX2, my + markerY2)) c.moveTo((mx + markerX1 * INTERPOLATION, my + markerY1 * INTERPOLATION)) c.lineTo((mx + markerX2 * INTERPOLATION, my + markerY2 * INTERPOLATION)) c.stroke(0, 0, 1) c.fill(None) c.drawPath() # Draw default glyph marker in middle. glyphName = self.glyphNames[0] defaultLocation = {} self._drawGlyphMarker(mx, my, glyphName, fontSize, defaultLocation, strokeW=3) # Draw DeltaLocation circles. for axisName, (minValue, defaultValue, maxValue) in axes.items(): angle = self.angles[axisName] # Outside maxValue location = {axisName: maxValue} markerX, markerY = self._angle2XY(angle, self.w / 2) self._drawGlyphMarker(mx + markerX, my + markerY, glyphName, fontSize / 2, location) # Interpolated DeltaLocation circles. location = { axisName: minValue + (maxValue - minValue) * INTERPOLATION } markerX, markerY = self._angle2XY(angle, self.w / 4) self._drawGlyphMarker(mx + markerX * INTERPOLATION * 2, my + markerY * INTERPOLATION * 2, glyphName, fontSize / 2, location) # If there are any pairs, draw the interpolation between them #if anglePairs: # for a1, a2 in anglePairs: # axis1 = # helper function: def makeAxisName(axisName): if not axisName in ('wght', 'wdth', 'opsz'): return axisName.upper() return axisName # Draw axis names and DeltaLocation values if self.showAxisNames: for axisName, (minValue, defaultValue, maxValue) in axes.items(): angle = self.angles[axisName] location = {axisName: maxValue} valueFontSize = self.style.get('valueFontSize', 12) axisNameFontSize = self.style.get('axisNameFontSize', 12) markerX, markerY = self._angle2XY(angle, self.w / 2) fs = c.newString( makeAxisName(axisName), style=dict(font=self.style.get('labelFont', 'Verdana'), fontSize=axisNameFontSize, fill=self.style.get('axisNameColor', 0))) tw, th = c.textSize(fs) c.fill(0.7, 0.7, 0.7, 0.6) c.stroke(None) c.rect(mx + markerX - tw / 2 - 4, my + markerY - axisNameFontSize / 2 - th * 1.5 - 4, tw + 8, th) c.text(fs, (mx + markerX - tw / 2, my + markerY - axisNameFontSize / 2 - th * 1.5)) # DeltaLocation master value if maxValue < 10: sMaxValue = '%0.2f' % maxValue else: sMaxValue = ` int(round(maxValue)) ` fs = c.newString( sMaxValue, style=dict(font=self.style.get('labelFont', 'Verdana'), fontSize=valueFontSize, fill=self.style.get('axisValueColor', 0))) tw, th = c.textSize(fs) c.fill(0.7, 0.7, 0.7, 0.6) c.stroke(None) c.rect(mx + markerX - tw / 2 - 4, my + markerY + valueFontSize / 2 + th * 1.5 - 4, tw + 8, th) c.text(fs, (mx + markerX - tw / 2, my + markerY + valueFontSize / 2 + th * 1.5)) # DeltaLocation value interpolationValue = minValue + (maxValue - minValue) * INTERPOLATION if interpolationValue < 10: sValue = '%0.2f' % interpolationValue else: sValue = ` int(round(interpolationValue)) ` fs = c.newString( sValue, style=dict(font=self.style.get('labelFont', 'Verdana'), fontSize=valueFontSize, fill=self.style.get('axisValueColor', 0))) tw, th = c.textSize(fs) c.fill(0.7, 0.7, 0.7, 0.6) c.stroke(None) c.rect( mx + markerX * INTERPOLATION - tw / 2 - 4, my + markerY * INTERPOLATION + valueFontSize / 2 + th * 1.5 - 4, tw + 8, th) c.text( fs, (mx + markerX * INTERPOLATION - tw / 2, my + markerY * INTERPOLATION + valueFontSize / 2 + th * 1.5)) # DeltaLocation value if minValue < 10: sValue = '%0.2f' % minValue else: sValue = ` int(round(minValue)) ` fs = c.newString( sValue, style=dict(font=self.style.get('labelFont', 'Verdana'), fontSize=valueFontSize, fill=self.style.get('axisValueColor', 0))) tw, th = c.textSize(fs) c.fill(0.7, 0.7, 0.7, 0.6) c.stroke(None) minM = 0.2 c.rect(mx + markerX * minM - tw / 2 - 4, my + markerY * minM - 8, tw + 8, th) c.text(fs, (mx + markerX * minM - tw / 2, my + markerY * minM - 4))
def _drawFontCircle(self, px, py): fontSize = self.css('fontSize', self.DEFAULT_FONT_SIZE) markerSize = fontSize * self.R # Calculate the max square size w = self.w - markerSize h = self.h - markerSize context.fill(0.9) context.stroke(None) mx = px + self.pw / 2 my = py + self.ph / 2 # Gray circle that defines the area of the axis extremes. context.oval(px + markerSize / 2, py + markerSize / 2, w, h) # Draw axis spikes first, so we can cover them by the circle markers. axes = self.font.axes # Draw default glyph circle marker in middle. glyphName = self.glyphNames[0] #varLocation = getVarLocation(self.font, self.location) # Show neutral, unless a location is requested varLocation = self.location # = getVarLocation(self.font, self.location) # Show neutral, unless a location is requested self._drawGlyphMarker(None, mx, my, glyphName, fontSize, varLocation, strokeW=3) # Draw angle = 0 for axisName, (minValue, defaultValue, maxValue) in axes.items(): # Draw needles, depending on the axis values and the status of self.location if self.draw3D: needleStart = 0.40 # Just enough overlap with edge of neutral circle marker else: needleStart = 2 / 3 # Start at edge of neutral circle marker rStart = fontSize rEnd = w / 2 if self.location is not None and axisName in self.location: rEnd = rStart + (rEnd - rStart) * self.location[axisName] rStart = fontSize * needleStart #print rStart, rEnd startX, startY = self._angle2XY(angle, rStart) endX, endY = self._angle2XY(angle, rEnd) if (w / 2 + rStart) - rEnd - fontSize > fontSize: startX1, startY1 = self._angle2XY(angle - 180, fontSize / 2) endX1, endY1 = self._angle2XY(angle - 180, (w / 2 + rStart) - rEnd - fontSize) else: startX1 = None context.stroke(None) context.fill(0.3) context.oval(mx + startX - 2, my + startY - 2, 4, 4) context.fill(None) context.stroke(0) context.strokeWidth(1) context.newPath() context.moveTo((mx + startX, my + startY)) context.lineTo((mx + endX, my + endY)) if startX1 is not None: context.moveTo((mx + startX1, my + startY1)) context.lineTo((mx + endX1, my + endY1)) context.drawPath() # Show the glyph shape as it is at the max location of the axis. location = {axisName: maxValue} self._drawGlyphMarker(axisName, mx + endX, my + endY, glyphName, fontSize, location) angle += 360 / len(axes)
style=dict(lineHeight=1, font=f.installedName, fontSize=12)) # Create DrawBotString, inheriting from BabelString, based on view type. bs = context.newString('Hlxg', style=dict(font=f.installedName, textFill=(1, 0, 0), fontSize=300, leading=320, baselineShift=200)) M = 20 context.fill(0.9) context.rect(M, M, 1000 - 2 * M, 800 - 2 * M) Y = 1000 - M BASE = (f.info.ascender + f.info.descender + f.info.lineGap) / 2 print('%s %s %s %s' % (f.info.familyName, f.info.styleName, 'Ascender + Descender + lineGap =', BASE)) YS = (BASE, ) print YS for y in YS: context.stroke(0) context.strokeWidth(0.5) context.line((0, y), (1000, y)) context.fill(0) context.stroke(None) context.textBox(bs, (M, M, 1000 - 2 * M, 400 - 2 * M))
# P A G E B O T # # Copyright (c) 2016+ Buro Petr van Blokland + Claudia Mens & Font Bureau # www.pagebot.io # Licensed under MIT conditions # # Supporting usage of DrawBot, www.drawbot.com # Supporting usage of Flat, https://github.com/xxyxyz/flat # ----------------------------------------------------------------------------- # from pagebot.contexts import defaultContext as c c.newPage(1000, 1000) fs = c.newString("b", style=dict(lineHeight=74, font="Times", fontSize=38)) fs += c.newString("hello world ", style=dict(font="Helvetica", fontSize=10, lineHeight=12)) fs += c.newString("hi agian " * 10) r = (10, 10, 200, 200) c.textBox(fs, r) c.fill(None) c.stroke(1, 0, 0) c.rect(*r) positions = c.textBoxBaseLines(fs, r) s = 2 for x, y in positions: c.oval(x - s, y - s, s * 2, s * 2)
newPage(1000, 1000) font = Font('/Library/Fonts/Georgia.ttf') print font.analyzer print font.analyzer.name glyphH = font['ampersand'] gaH = glyphH.analyzer print gaH print 'H width:', gaH.width, gaH.glyph.width, glyphH.width print 'H bounding box:', gaH.boundingBox # X position of vertical lines also includes sides of serifs. print 'x-position of verticals:', sorted(gaH.verticals.keys()) # Y position of horizontal lines print 'y-position of horizontals:', sorted(gaH.horizontals.keys()) c.stroke(0) c.fill(None) print gaH.glyph.leftMargin x = y = 100 s = 0.25 c.drawPath(glyphH.path, (x, y), s) # Draw markers on the glyph points c.fill((1, 0, 0)) c.stroke(None) for p in glyphH.points: r = {True:5, False:3}[p.onCurve] c.rect(x+p.x*s-r/2, x+p.y*s-r/2, r, r) #c.rect(x, y, 100, 100) # Draw flattened path next to it on H-width distance. c.fill(None)
def drawFontLabel(p, varFamily, f, fIndex=None, fAxis=None): x, y = p print f.info.styleName, f.info.weightClass, f.info.widthClass glyphH = f[GLYPH] if not glyphH.width: print glyphH, 'No width' return s = 0.05 * 1000 / f.info.unitsPerEm leading = 2048 / f.info.unitsPerEm stroke(None) fill(0) save() translate(x - glyphH.width / 2 * s, y - leading - 50) scale(s) drawPath(glyphH.path) restore() y -= leading + 50 save() pathLabel = '-'.join(path2Name(f.path).split('-')[1:]) #label = path2Name(f.path) if fAxis is not None: label = '@' + fAxis elif fIndex is None: label = '' else: label = '#%d ' % fIndex label += '%s\n(%s)\n%d' % (pathLabel.replace('.ttf', '').replace( '_', '\n').replace('-', '\n'), f.info.styleName, f.info.weightClass) fs = FormattedString(label, fontSize=10, align='center') tw, th = textSize(fs) text(fs, (x - tw / 2, y - 14)) restore() y -= leading + th - 22 # Draw marker on actual position of H.stem and H.weight as green dot stemValues = f.analyzer.stems.keys() if stemValues: # Cannot find H-stem, skip this marker stem = min(stemValues) # XOPQ (counter) + H.stem == H.width - H.stem - H.lsb - H.rsb width = glyphH.width - stem - glyphH.leftMargin - glyphH.rightMargin c.fill((0, 0.5, 0)) c.stroke(None) R = 16 weightLoc, widthLoc = stem, width / 2 c.oval(weightLoc - R / 2, widthLoc - R / 2, R, R) if fAxis is not None: label = '@' + fAxis elif fIndex is None: label = '' else: label = '#%d\n' % fIndex bs = c.newString(label + ('S:%d\nW:%d\n%d' % (weightLoc, widthLoc, f.info.weightClass)), style=dict(fontSize=10, xTextAlign='center', textFill=0)) tw, th = c.textSize(bs) c.text(bs, (weightLoc - tw / 2, widthLoc - 24)) if varFamily.originFont is f: # If one of these is the guessed origin font, then draw marker c.fill(None) c.stroke((0, 0.5, 0), 2) # Stroke color and width R = 23 c.oval(weightLoc - R / 2, widthLoc - R / 2, R, R) else: pass
## https://github.com/thomgb/drawbot ## download my DrawBot: https://www.dropbox.com/s/xsu1mz89ipo5x3y/DrawBot.dmg?dl=0 from pagebot.contexts import defaultContext as context from pagebot.contributions.filibuster.blurb import Blurb #text = Blurb().getBlurb('article_ankeiler', noTags=True) text = """Considering the fact that the application allows individuals to call a phone number and leave a voice mail, which is automatically translated into a tweet with a hashtag from the country of origin.""" t = context.newString(text, style=dict(fontSize=30, hyphenationHead=4, hyphenationTail=3)) w = 554 # change width to see other hyphenations W = 1000 H = 2000 context.newPage(W, H) context.hyphenation(True) context.textBox(t, (100, 600, w, 400)) context.fill(None) context.stroke(0) context.rect(100, 600, w, 600) context.hyphenation(False) context.textBox(t, (100, 100, w, 400)) context.fill(None) context.stroke(0) context.rect(100, 100, w, 600)
def draw(self, page, x, y): u"""Draw the circle info-graphic, showing most info about the variation font as can be interpreted from the file.""" c.fill(0.9) c.stroke(None) mx = x + self.w / 2 my = y + self.h / 2 # Gray circle that defines the area of c.oval(x, y, self.w, self.h) # Draw axis spikes first, so we can cover them by the circle markers. axes = self.font.axes fontSize = self.style.get('fontSize', self.DEFAULT_FONT_SIZE) # Draw name of the font c.fill(0) c.text( c.newString(self.font.info.familyName, style=dict(font=self.style['labelFont'], fontSize=self.style['axisNameFontSize'])), (x - fontSize / 2, y + self.h + fontSize / 2)) # Draw spokes c.fill(None) c.stroke(0) c.strokeWidth(1) c.newPath() for axisName, angle in self.angles.items(): markerX, markerY = self._angle2XY(angle, self.w / 2) c.moveTo((mx, my)) c.lineTo((mx + markerX, my + markerY)) c.drawPath() # Draw default glyph marker in middle. glyphName = self.glyphNames[0] defaultLocation = {} self._drawGlyphMarker(mx, my, glyphName, fontSize, defaultLocation, strokeW=3) # Draw DeltaLocation circles. for axisName, (minValue, defaultValue, maxValue) in axes.items(): angle = self.angles[axisName] # Outside maxValue location = {axisName: maxValue} markerX, markerY = self._angle2XY(angle, self.w / 2) self._drawGlyphMarker(mx + markerX, my + markerY, glyphName, fontSize / 2, location) # Interpolated DeltaLocation circles. location = { axisName: minValue + (maxValue - minValue) * INTERPOLATION } markerX, markerY = self._angle2XY(angle, self.w / 4) self._drawGlyphMarker(mx + markerX * INTERPOLATION * 2, my + markerY * INTERPOLATION * 2, glyphName, fontSize / 2, location) # Draw axis names and DeltaLocation values if self.showAxisNames: for axisName, (minValue, defaultValue, maxValue) in axes.items(): angle = self.angles[axisName] location = {axisName: maxValue} valueFontSize = self.style.get('valueFontSize', 12) axisNameFontSize = self.style.get('axisNameFontSize', 12) markerX, markerY = self._angle2XY(angle, self.w / 2) fs = c.newString( makeAxisName(axisName), style=dict(font=self.style.get('labelFont', 'Verdana'), fontSize=axisNameFontSize, fill=self.style.get('axisNameColor', 0))) tw, th = c.textSize(fs) c.fill(0.7, 0.7, 0.7, 0.6) c.stroke(None) c.rect(mx + markerX - tw / 2 - 4, my + markerY - axisNameFontSize / 2 - th * 1.5 - 4, tw + 8, th) c.text(fs, (mx + markerX - tw / 2, my + markerY - axisNameFontSize / 2 - th * 1.5)) # DeltaLocation master value if maxValue < 10: sMaxValue = '%0.2f' % maxValue else: sMaxValue = ` int(round(maxValue)) ` fs = c.newString( sMaxValue, style=dict(font=self.style.get('labelFont', 'Verdana'), fontSize=valueFontSize, fill=self.style.get('axisValueColor', 0))) tw, th = c.textSize(fs) c.fill(0.7, 0.7, 0.7, 0.6) c.stroke(None) c.rect(mx + markerX - tw / 2 - 4, my + markerY + valueFontSize / 2 + th * 1.5 - 4, tw + 8, th) c.text(fs, (mx + markerX - tw / 2, my + markerY + valueFontSize / 2 + th * 1.5)) # DeltaLocation value interpolationValue = minValue + (maxValue - minValue) * INTERPOLATION if interpolationValue < 10: sValue = '%0.2f' % interpolationValue else: sValue = ` int(round(interpolationValue)) ` fs = c.newString( sValue, style=dict(font=self.style.get('labelFont', 'Verdana'), fontSize=valueFontSize, fill=self.style.get('axisValueColor', 0))) tw, th = c.textSize(fs) c.fill(0.7, 0.7, 0.7, 0.6) c.stroke(None) c.rect( mx + markerX * INTERPOLATION - tw / 2 - 4, my + markerY * INTERPOLATION + valueFontSize / 2 + th * 1.5 - 4, tw + 8, th) c.text( fs, (mx + markerX * INTERPOLATION - tw / 2, my + markerY * INTERPOLATION + valueFontSize / 2 + th * 1.5)) # DeltaLocation value if minValue < 10: sValue = '%0.2f' % minValue else: sValue = ` int(round(minValue)) ` fs = c.newString( sValue, style=dict(font=self.style.get('labelFont', 'Verdana'), fontSize=valueFontSize, fill=self.style.get('axisValueColor', 0))) tw, th = c.textSize(fs) c.fill(0.7, 0.7, 0.7, 0.6) c.stroke(None) minM = 0.2 c.rect(mx + markerX * minM - tw / 2 - 4, my + markerY * minM + th * 0.5 - 4, tw + 8, th) c.text(fs, (mx + markerX * minM - tw / 2, my + markerY * minM + th * 0.5))
def _drawFrame(self): c.stroke(0, 0, 1) c.fill(None) c.rect(self.x, self.y, self.w, self.h)