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 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 buildBusinessCard(w, h): for imageIndex in range(1, 5): context.newPage(w, h) y = h # Start vertical position on top of the page. # Draw one of the 4 Bitcount background images, filename indexed by imageIndex # The TYPETR Bitcount license can be purchased at: # https://store.typenetwork.com/foundry/typetr/fonts/bitcount imagePath = ROOT_PATH + '/Examples/Portfolios/images/BitcountRender%d.png' % imageIndex context.image(imagePath, (0, 0), w=w) # Set to full page width at origin # Define some style. Note thate TYPETR Upgrade is the identity typeface, which may not be installed. # Another font is selected in case TYPETR Upgrade is not available. # View more here: https://upgrade.typenetwork.com # A license can be purchased at: # https://store.typenetwork.com/foundry/typetr/fonts/upgrade style = dict(font='Upgrade-Regular', fontSize=14, textFill=1, xTextAlign=CENTER) styleTitle = dict(font='Upgrade-Italic', fontSize=10, textFill=1, xTextAlign=CENTER) styleEmail = dict(font='Upgrade-Light', fontSize=8, textFill=1, xTextAlign=CENTER, leading=10, rTracking=0.02) # Create styled BabelString for the name lines bs = context.newString('Petr van Blokland\n', style=style) bs += context.newString('Designer | Educator | Founder\n', style=styleTitle) bs += context.newString('[email protected] | @petrvanblokland', style=styleEmail) # Get the size of the text block, to position it centered tw, th = context.textSize(bs) # Draw a textbox in the contextf canvas. context.text(bs, (w/2-tw/2, h*0.55)) # Create a style for the logo. The size and tracking is hardcoded to fit the business card width. logoStyle = dict(font='Upgrade-Black', fontSize=22, textFill=1, rTracking=1.4) # Create the BabelString, containing the fitting logo with tracking. bs = context.newString(u'.TYPETR', style=logoStyle) # Get the size of the text block, to position it centered tw, th = bs.size() # Draw a textbox in the contextf canvas. context.text(bs, (w/2-tw/2-3, 2*M))
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 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
from pagebot.contexts import defaultContext as context W = 600 H = 300 HEAD_LINE = """When fonts started a new world""" TEXT = """The advent of variable fonts means doing nothing, or everything, or something in between for font users and type designers. """ newPage(W, H) bs = context.newString(HEAD_LINE + '\n', style=dict(font='Verdana', fontSize=24, textFill=0)) bs += context.newString(TEXT, style=dict(font='Verdana', fontSize=12, textFill=0)) tw, th = context.textSize(bs, w=200) print tw, th context.textBox(bs, (100, -th + H, 200, th))
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 fitVariableWidth(varFont, s, w, fontSize, condensedLocation, wideLocation, fixedSize=True, tracking=None, rTracking=None, cached=True, lazy=True): u"""Answer the font instance that makes string s width on the given width *w* for the given *fontSize*. The *condensedLocation* dictionary defines the most condensed font instance (optionally including the opsz) and the *wideLocation* dictionary defines the most wide font instance (optionally including the opsz). The string width for s is calculated with both locations and then the [wdth] value is interpolated and iterated until the location is found where the string *s* fits width *w). Note that interpolation may not be enough, as the width axis may contain non-linear masters. If the requested w outside of what is possible with two locations, then interations are performed to change the size. Again this cannot be done by simple interpolation, as the [opsz] also changes the width. It one of the axes does not exist in the font, then use the default setting of the font. """ # TODO: Adjusting by size change (if requested width is not possible with the width limits of the font) # TODO: is not yet implemented. # Get the instances for the extreme width locations. This allows the caller to define the actual range # of the [wdth] axis to be user, instead of the default minValue and maxValue. E.g. for a range of widths # in a headline, the typographer may only want a small change before the line is wrapping, instead # using the full spectrum to extreme condensed. condensedFont = getVariableFont(varFont, condensedLocation, cached=cached, lazy=lazy) wideFont = getVariableFont(varFont, wideLocation, cached=cached, lazy=lazy) # Calculate the widths of the string using these two instances. condensedFs = context.newString(s, style=dict( font=condensedFont.installedName, fontSize=fontSize, tracking=tracking, rTracking=rTracking, textFill=0)) wideFs = context.newString(s, style=dict(font=wideFont.installedName, fontSize=fontSize, tracking=tracking, rTracking=rTracking, textFill=0)) # Calculate the widths of the strings. # TODO: Handle if these lines would wrap on the given width. In that case we may want to set the wrapped # first line back to it's uncondensed value, to make the first wrapped line fit the width. condensedWidth, _ = context.textSize(condensedFs) wideWidth, _ = context.textSize(wideFs) # Check if the requested with is inside the boundaries of the font width axis if w < condensedWidth: # Requested width is smaller than was was possible using the extreme value of [wdth] axis. font = condensedFont fs = condensedFs location = condensedLocation elif w > wideWidth: # Requested width is larger than was was possible using the extreme value of [wdth] axis. font = wideFont fs = wideFs location = wideLocation else: # Inside the selected [wdth] range, now interpolation the fitting location. # TODO: Check if the width of the new string is within tolerance of the request width. # This may not be the case if the range of the [wdth] is interpolating in a non-linear way. # In that case we may need to do a number of iterations. widthRange = wideLocation['wdth'] - condensedLocation['wdth'] location = copy.copy(condensedLocation) location['wdth'] += widthRange * (w - condensedWidth) / ( wideWidth - condensedWidth) font = getVariableFont(varFont, location, cached=cached, lazy=lazy) fs = context.newString(s, style=dict(font=font.installedName, fontSize=fontSize, tracking=tracking, rTracking=rTracking, textFill=0)) # Answer the dictionary with calculated data, so the caller can reuse it, without the need to new expensive recalculations. return dict(condensendFont=condensedFont, condensedFs=condensedFs, condensedWidth=condensedWidth, condensedLocation=condensedLocation, wideFont=wideFont, wideFs=wideFs, wideWidth=wideWidth, wideLocation=wideLocation, font=font, s=fs, width=context.textSize(fs)[0], location=location)
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 fitVariableWidth(varFont, s, w, fontSize, condensedLocation, wideLocation, fixedSize=False, tracking=None, rTracking=None): u""" Answer the font instance that makes string s width on the given width *w* for the given *fontSize*. The *condensedLocation* dictionary defines the most condensed font instance (optionally including the opsz) and the *wideLocation* dictionary defines the most wide font instance (optionally including the opsz). The string width for s is calculated with both locations and then the [wdth] value is interpolated and iterated until the location is found where the string *s* fits width *w). Note that interpolation may not be enough, as the width axis may contain non-linear masters. If the requested w outside of what is possible with two locations, then interations are performed to change the size. Again this cannot be done by simple interpolation, as the [opsz] also changes the width. It one of the axes does not exist in the font, then use the default setting of the font. """ condFont = getVariableFont(varFont, condensedLocation) condensedFs = c.newString(s, style=dict(font=condFont.installedName, fontSize=fontSize, tracking=tracking, rTracking=rTracking, textFill=0)) condWidth, _ = c.textSize(condensedFs) wideFont = getVariableFont(varFont, wideLocation) wideFs = c.newString(s, style=dict(font=wideFont.installedName, fontSize=fontSize, tracking=tracking, rTracking=rTracking, textFill=0)) wideWidth, _ = c.textSize(wideFs) # Check if the requested with is inside the boundaries of the font width axis if w < condWidth: font = condFont fs = condensedFs location = condensedLocation elif w > wideWidth: font = wideFont fs = wideFs location = wideLocation else: # Now interpolation the fitting location widthRange = wideLocation['wdth'] - condensedLocation['wdth'] location = copy.copy(condensedLocation) location['wdth'] += widthRange*(w-condWidth)/(wideWidth-condWidth) font = getVariableFont(varFont, location) fs = c.newString(s, style=dict(font=font.installedName, fontSize=fontSize, tracking=tracking, rTracking=rTracking, textFill=0)) return dict(condensendFont=condFont, condensedFs=condensedFs, condWidth=condWidth, condensedLocation=condensedLocation, wideFont=wideFont, wideFs=wideFs, wideWidth=wideWidth, wideLocation=wideLocation, font=font, fs=fs, width=c.textSize(fs)[0], location=location)
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: bs = context.newString('index', style=dict(fill=(1, 1, 0), stroke=None, font='Verdana', fontSize=18)) tw, th = context.textSize(bs) context.fill(0.4) context.stroke((0.4, 0.4, 0.4, 0.9)) context.oval(p.x - 10, p.y - 10, 20, 20) context.text(fs, (p.x - tw / 2, p.y - th / 4))
fs += c.newString(('This an example of TextLines and TextRuns' ' and more and more. '), style=dict(font='Verdana', fontSize=14, lineHeight=22)) fs += c.newString('=== Find this. === ', style=dict(font='Georgia-Bold', fontSize=16, lineHeight=22)) fs += c.newString('This an example of larger TextLines and TextRuns. ', style=dict(font='Georgia', fontSize=16, lineHeight=22)) fs += c.newString('=== Find this. === ', style=dict(font='Georgia-Bold', fontSize=16, lineHeight=22)) fs += c.newString('This an example of TextLines and TextRuns. ', style=dict(font='Verdana', fontSize=14, lineHeight=22)) fittingWord = c.newString('Word\n', style=dict(font='Georgia', align='left', fontSize=500)) w, _ = c.textSize(fittingWord) fittingSize = W/w*500 fittingWord = c.newString('Word\n', style=dict(font='Georgia', align='left', fontSize=fittingSize, lineHeight=fittingSize*1.2)) fs += fittingWord fittingWord = c.newString('ABC\n', style=dict(font='BitcountMonoDouble-RegularCircle', align='left', fontSize=500)) w, _ = c.textSize(fittingWord) fittingSize = W/w*500 fittingWord = c.newString('ABC\n', style=dict(font='BitcountMonoDouble-RegularCircle',
def makeCoverTemplate(imagePath, w, h): bleed = 0 textColor = 1 # Make styles # TODO: Make this fit, using size/wdth axis combination of Amstelvar coverTitleSize = 160 # Not optical size yet. Play more with the axes coverTitleFont = getVariableFont(FONT_PATH, dict(wght=0.9, wdth=0.02)) #, opsz=coverTitleSize)) coverTitleStyle = dict(font=coverTitleFont.installedName, fontSize=coverTitleSize, textShadow=shadow, textFill=textColor, tracking=-3) coverSubTitleSize = 80 # Not optical size yet. Play more with the axes coverSubTitleFont = getVariableFont(FONT_PATH, dict( wght=0.6, wdth=0.02)) #opsz=coverSubTitleSize)) coverSubTitleStyle = dict(font=coverSubTitleFont.installedName, fontSize=coverSubTitleSize, textFill=(1, 1, 1, 0.3), tracking=0) # Cover coverTemplate = Template( w=w, h=h, padding=PADDING) # Cover template of the magazine. newImage(imagePath, parent=coverTemplate, conditions=[Fit2WidthSides(), Bottom2BottomSide()]) # Title of the magazine cover. coverTitle = context.newString('Fashion', style=coverTitleStyle) # Calculate width if single "F" for now, to align "Slow" # TODO: Change in example to go through the coverTitle to get positions and widths. FWidth, _ = context.textSize(context.newString('F', style=coverTitleStyle)) coversubTitle = context.newString('Slow', style=coverSubTitleStyle) newTextBox(coversubTitle, parent=coverTemplate, pl=FWidth * 0.5, conditions=[Left2Left(), Fit2Width(), Top2TopSide()]) tw, th = context.textSize(coverTitle) newText(coverTitle, parent=coverTemplate, z=20, h=th * 0.4, textShadow=shadow, conditions=[Fit2Width(), Top2TopSide()]) # Make actual date in top-right with magazine title. Draw a bit transparant on background photo. dt = datetime.now() d = dt.strftime("%B %Y") fs = context.newString(d, style=dict(font=MEDIUM.installedName, fontSize=17, textFill=(1, 1, 1, 0.6), tracking=0.5)) # TODO: padding righ could come from right stem of the "n" newTextBox(fs, parent=coverTemplate, xTextAlign=RIGHT, pr=10, pt=6, conditions=[Top2Top(), Right2Right()]) # Titles could come automatic from chapters in the magazine. fs = context.newString('$6.95', style=dict(font=BOOK.installedName, fontSize=12, textFill=textColor, tracking=1, leading=12)) newText(fs, parent=coverTemplate, mt=8, conditions=[Top2Bottom(), Right2Right()]) makeCoverTitles(coverTemplate) return coverTemplate
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))