def test_reloadFont(self): src = pathlib.Path( __file__).resolve().parent / "data" / "MutatorSans.ttf" assert src.exists() with tempfile.NamedTemporaryFile(suffix=".ttf") as ff: ff.write(src.read_bytes()) firstModTime = os.stat(ff.name).st_mtime drawBot.newDrawing() drawBot.font(ff.name) self.assertEqual(ff.name, drawBot.fontFilePath()) path = drawBot.BezierPath() path.text("E", font=ff.name, fontSize=1000) self.assertEqual((60.0, 0.0, 340.0, 700.0), path.bounds()) ff.seek(0) ttf = TTFont(ff) ttf["glyf"]["E"].coordinates[0] = (400, 800) ff.seek(0) ttf.save(ff) secondModTime = os.stat(ff.name).st_mtime assert firstModTime != secondModTime, (firstModTime, secondModTime) drawBot.newDrawing() # to clear the memoize cache in baseContext drawBot.font(ff.name) self.assertEqual(ff.name, drawBot.fontFilePath()) path = drawBot.BezierPath() path.text("E", font=ff.name, fontSize=1000) self.assertEqual((60.0, 0.0, 400.0, 800.0), path.bounds())
def test_booleanoperationListIntersections(self): expected = [(75, 150), (150, 75)] import drawBot path1 = drawBot.BezierPath() path1.rect(50, 50, 100, 100) path2 = drawBot.BezierPath() path2.rect(75, 75, 100, 100) result = path1.intersectionPoints(path2) self.assertEqual(sorted(result), sorted(expected)) path1.appendPath(path2) result = path1.intersectionPoints() self.assertEqual(sorted(result), sorted(expected))
def test_instructionStack(self): expected = [ "reset None", "newPage 200 200", "save", "clipPath moveTo 5.0 5.0 lineTo 15.0 5.0 lineTo 15.0 15.0 lineTo 5.0 15.0 closePath", "restore", "image Image Object 10 10 0.5 None", "blendMode saturation", "transform 1 0 0 1 10 10", "drawPath moveTo 10.0 10.0 lineTo 110.0 10.0 lineTo 110.0 110.0 lineTo 10.0 110.0 closePath", "textBox foo bar 72.48291015625 84.0 55.0341796875 26.0 center", "frameDuration 10", "saveImage * {'myExtraAgrument': True}" ] with StdOutCollector() as output: import drawBot drawBot.newDrawing() drawBot.size(200, 200) drawBot.save() path = drawBot.BezierPath() path.rect(5, 5, 10, 10) drawBot.clipPath(path) drawBot.restore() im = drawBot.ImageObject() with im: drawBot.size(20, 20) drawBot.rect(5, 5, 10, 10) drawBot.image(im, (10, 10), alpha=.5) drawBot.blendMode("saturation") drawBot.translate(10, 10) drawBot.rect(10, 10, 100, 100) drawBot.text("foo bar", (100, 100), align="center") drawBot.frameDuration(10) drawBot.saveImage("*", myExtraAgrument=True) drawBot.endDrawing() self.assertEqual(output.lines(), expected)
def drawContour(self): color = self.colorScheme.colorsRGB['contour'] drawBot.save() drawBot.fontSize(self.captionSize) drawBot.font(self.captionFont) for char in self.txt: uni = ord(char) glyphName = UV2AGL.get(uni) # interpolate g1 = self.font[glyphName].getLayer('regular') g2 = self.font[glyphName].getLayer('bold') glyph = RGlyph() glyph.name = g1.name glyph.unicode = g1.unicode glyph.interpolate(self.interpolationFactor, g1, g2) # draw contours drawBot.stroke(*color) drawBot.strokeWidth(self.contourStrokeWidth) drawBot.fill(None) B = drawBot.BezierPath() for contour in glyph.contours: contour.draw(B) drawBot.drawPath(B) # done glyph drawBot.translate(glyph.width, 0) drawBot.restore()
def newPath(self): """Answer a new empty drawBot.BezierPath. >>> context = DrawBotContext() >>> context.newPath() <BezierPath> """ return drawBot.BezierPath()
def drawGlyph(self): color = self.colorScheme.colorsRGB['glyph'] drawBot.save() drawBot.fontSize(self.captionSize) drawBot.font(self.captionFont) for char in self.txt: uni = ord(char) glyphName = UV2AGL.get(uni) # interpolate g1 = self.font[glyphName].getLayer('regular') g2 = self.font[glyphName].getLayer('bold') glyph = RGlyph() glyph.name = g1.name glyph.unicode = g1.unicode glyph.interpolate(self.interpolationFactor, g1, g2) # contours drawBot.fill(*color) B = drawBot.BezierPath() for contour in glyph.contours: contour.draw(B) drawBot.drawPath(B) # advance width if self.glyphWidthDraw: drawBot.save() drawBot.strokeWidth(self.glyphWidthStrokeWidth) drawBot.stroke(*color) drawBot.line((0, self.yBottom), (0, self.yTop)) drawBot.restore() # glyph data if self.glyphDataDraw: h = self.captionSize * 1.5 m = 40 w = glyph.width - m * 2 drawBot.save() drawBot.stroke(None) drawBot.fill(*color) y = self.yTop - h drawBot.textBox(glyph.name, (m, y, w, h)) drawBot.textBox(str(glyph.unicode), (m, y, w, h), align='right') y = self.yBottom drawBot.textBox(str(int(glyph.width)), (m, y, w, h), align='center') drawBot.restore() # done glyph drawBot.translate(glyph.width, 0) # last margin if self.glyphWidthDraw: drawBot.strokeWidth(self.glyphWidthStrokeWidth) drawBot.stroke(*color) drawBot.line((0, self.yBottom), (0, self.yTop)) # done drawBot.restore()
def drawGlyph(g): # Get glyph outline f = g.font pen = CocoaPen(f) g.draw(pen) bezierPath = pen.path # Draw with db.savedState(): db.translate(-g.width * 0.5, 450) # Center the glyph path = db.BezierPath() path.setNSBezierPath(bezierPath) db.drawPath(path)
def shadow(self, clip=None, radius=10, alpha=0.3, color=Color.from_rgb(0,0,0,1)): if clip: cp = DATPen(fill=None).rect(clip) bp = db.BezierPath() cp.replay(bp) db.clipPath(bp) #elif self.rect: # cp = DATPen(fill=None).rect(self.rect).xor(self.dat) # bp = db.BezierPath() # cp.replay(bp) # db.clipPath(bp) db.shadow((0, 0), radius*3, list(color.with_alpha(alpha)))
def draw(txt="a", variations={}, caption=""): db.newPage(w * scale, h * scale) db.scale(scale) db.fill(*BACKCOL) db.rect(0, 0, w, h) txt = db.FormattedString(txt, font="Handjet-Regular", fontSize=500, fontVariations=variations) db.fill(*TEXTCOL) db.stroke(None) path = db.BezierPath() path.text(txt, (w / 2, 95), align="center") db.drawPath(path) txt = db.FormattedString(caption, font="AdapterMonoPE-Regular", fontSize=11, fill=TEXTCOL) db.text(txt, (w / 2, 40), align="center")
def drawArrow(sf, a): x, y, ang = a.x, a.y, a.angle path = d.BezierPath() path.moveTo((50, 40)) path.lineTo((0, 0)) path.lineTo((50, -40)) path.moveTo((0, 0)) path.lineTo((120, 0)) path.closePath() path.scale(sf) d.lineCap("round") d.lineJoin("round") path.rotate(ang, center=(0, 0)) path.translate(x, y) d.fill(None) d.stroke(1, 0, 0, 0.5) d.strokeWidth(annoThickness / sf) d.drawPath(path)
def drawPlusMinus(sf, a): x, y = a.x, a.y x, y, ang = a.x, a.y, a.angle path = d.BezierPath() path.moveTo((-50, 0)) path.lineTo((50, 0)) if a.type == PLUS: path.moveTo((0, 50)) path.lineTo((0, -50)) path.closePath() path.scale(sf) d.lineCap("round") d.lineJoin("round") path.translate(x, y) d.fill(None) d.stroke(1, 0, 0, 0.5) d.strokeWidth(annoThickness / sf) d.drawPath(path)
def drawComponent(self): color = self.colorScheme.colorsRGB['component'] tempName = '_tmp_' drawBot.save() for char in self.txt: uni = ord(char) glyphName = UV2AGL.get(uni) glyph = self.font[glyphName] drawBot.fill(*color + (0.5,)) drawBot.stroke(*color) if len(glyph.components): B = drawBot.BezierPath() for component in glyph.components: component.draw(B) drawBot.drawPath(B) # done glyph drawBot.translate(glyph.width, 0) drawBot.restore()
def pixelBounds(fs): """Answers the pixel-bounds rectangle of the text. NOTE that @by can be a negative value, if there is text (e.g. overshoot) below the baseline. @bh is the amount of pixels above the baseline. For the total height of the pixel-map, calculate @ph - @py. For the total width of the pixel-map, calculate @pw - @px.""" if not fs: return pt(0, 0, 0, 0) p = drawBotBuilder.BezierPath() p.text(fs, (0, 0)) # OS X answers bw and bh as difference with bx and by. That is not really # intuitive, as the the total (width, height) then always needs to be # calculated by the caller. So, instead, the width and height answered is # the complete bounding box, and the (x, y) is the position of the bounding # box, compared to the (0, 0) of the string origin. bx, by, bw, bh = p.bounds() return pt(bx, by, bw - bx, bh - by)
def draw(gn="a", variations={}, caption=""): db.newPage(w * scale, h * scale) db.scale(scale) db.fill(*BACKCOL) db.rect(0, 0, w, h) fs = db.FormattedString() fs.font("Handjet-Regular") fs.fontSize(200) fs.appendGlyph(gn) db.fill(*TEXTCOL) db.stroke(None) path = db.BezierPath() path.text(fs, (w / 2, 145), align="center") db.drawPath(path) fs = db.FormattedString(caption, font="AdapterMonoPE-Regular", fontSize=10, fill=TEXTCOL) db.text(fs, (w / 2, 40), align="center")
def make_box(box_size, box_depth): box = db.BezierPath() box.moveTo((box_size[0], 0)) box.lineTo((0, 0)) box.lineTo((0, box_size[1])) box.lineTo((box_size[0], box_size[1])) box.closePath() box.moveTo((0, 0)) box.lineTo((box_depth[0], box_depth[1])) box.lineTo((box_depth[0], box_size[1] + box_depth[1])) box.lineTo((0, box_size[1])) box.closePath() box.moveTo((box_depth[0], box_size[1] + box_depth[1])) box.lineTo((box_size[0] + box_depth[0], box_size[1] + box_depth[1])) box.lineTo((box_size[0], box_size[1])) box.lineTo((0, box_size[1])) box.closePath() return box
def drawLayer(self): steps = 3 alpha = 0.2 + 0.8 / (steps + 1) color = self.colorScheme.colorsRGB['layer'] drawBot.save() # drawBot.fill(None) # drawBot.stroke(*color) # drawBot.strokeWidth(self.layerStrokeWidth) color += (alpha,) drawBot.fill(*color) drawBot.stroke(None) for char in self.txt: uni = ord(char) glyphName = UV2AGL.get(uni) g1 = self.font[glyphName].getLayer('regular') g2 = self.font[glyphName].getLayer('bold') layerGlyphs = [] for i in range(steps): factor = i * 1.0 / (steps - 1) g3 = RGlyph() g3.name = g1.name g3.unicode = g1.unicode g3.interpolate(factor, g1, g2) layerGlyphs.append(g3) for g in layerGlyphs: B = drawBot.BezierPath() g.draw(B) drawBot.drawPath(B) drawBot.translate(g2.width, 0) drawBot.restore()
def test_export_SVG_mixin(self): expectedPath = os.path.join(testDataDir, "expected_svgMixin.svg") drawBot.newDrawing() drawBot.newPage(100, 100) path = drawBot.BezierPath() path.svgID = "hello" path.svgClass = "foo bar" path.svgLink = "drawbot.com" path.rect(0, 0, 20, 20) drawBot.drawPath(path) txt = drawBot.FormattedString() txt += "world" txt.svgID = "hello" txt.svgClass = "foo bar" txt.svgLink = "drawbot.com" drawBot.text(txt, (20, 20)) with TempFile(suffix=".svg") as tmp: drawBot.saveImage(tmp.path) self.assertEqual( readData(tmp.path), readData(expectedPath), "Files %r and %s are not the same" % (tmp.path, expectedPath))
def drawSegment(self): color = self.colorScheme.colorsRGB['segment'] r = self.bPointSize * 0.5 drawBot.save() drawBot.fontSize(self.captionSize) drawBot.font(self.captionFont) for char in self.txt: uni = ord(char) glyphName = UV2AGL.get(uni) # interpolate g1 = self.font[glyphName].getLayer('regular') g2 = self.font[glyphName].getLayer('bold') glyph = RGlyph() glyph.name = g1.name glyph.unicode = g1.unicode glyph.interpolate(self.interpolationFactor, g1, g2) # draw segment contours drawBot.stroke(*color) drawBot.strokeWidth(self.segmentStrokeWidth) drawBot.fill(None) B = drawBot.BezierPath() glyph.draw(B) drawBot.drawPath(B) # draw segment points drawBot.stroke(None) drawBot.fill(*color) for x, y in B.onCurvePoints: drawBot.oval(x - r, y - r, r * 2, r * 2) drawBot.translate(glyph.width, 0) drawBot.restore()
def draw(txt="a", variations={}, caption=""): db.newPage(w * scale, h * scale) db.scale(scale) db.fill(*BACKCOL) db.stroke(None) db.rect(0, 0, w, h) fs = db.FormattedString(txt, font="Handjet-Regular", fontSize=4600, fontVariations=variations) path = db.BezierPath() path.text(fs, (w / 2, 1.58 * h), align="center") path_optim = path.copy() # remove overlaps when drawing the fill # but use the original contour when drawing the nodes path_optim.removeOverlap() path_optim.optimizePath() # draw the fill db.fill(*TEXTCOL) db.drawPath(path_optim) # draw nodes if path.contours: # drawing just the first contour is enough for s in path.contours[0]: for x, y in s: if (x, y) in path.onCurvePoints: db.fill(*NODECOL) db.stroke(*TEXTCOL) db.strokeWidth(1) db.oval(x - 4, y - 4, 8, 8) # draw caption fs = db.FormattedString(caption, font="AdapterMonoPE-Regular", fontSize=10, fill=TEXTCOL) if caption: db.text(fs, (w / 2, 40), align="center")
W = H = 600 M = 50 TW = 20 # Triangle size TH = 18 # Create a new page canvas of 1000 x 1000 px drawBot.newPage(W, H) # Fill page with white background drawBot.fill(1) drawBot.rect(0, 0, W, H) for n in range(200): # Random position within the page range x = M + random() * (W - M - M - TW) y = M + random() * (H - M - M - TW) # Set a random color drawBot.fill(random(), random(), random()) path = drawBot.BezierPath() path.moveTo((x, y)) path.lineTo((x + TW, y)) path.lineTo((x + TW / 2, y + TH)) path.closePath() drawBot.drawPath(path) # Check is the _export/ folder exists, otherwise create it. # We want to save exported files there, to avoid that those files get # committed to Github everytime a new one is exported. if not os.path.exists('_export'): os.path.mkdir('_export/') # Export as png file in created _export folder (that does not sync in Github) drawBot.saveImage('_export/0016-ManyTriangles.png')
def __init__(self, dat, rect=None): super().__init__() self.rect = rect self.dat = dat self.bp = db.BezierPath() self.dat.replay(self.bp)
import drawBot drawBot.newDrawing() drawBot.size(200, 200) testData = [ ((25, 25, 50, 50), "rotate", (20,), (25, 25)), ((125, 25, 50, 50), "skew", (10, 10), (175, 25)), ((25, 125, 50, 50), "scale", (1.2, 1.4), (25, 175)), ] for r, op, args, center in testData: drawBot.fill(0) bez = drawBot.BezierPath() bez.rect(*r) drawBot.drawPath(bez) with drawBot.savedState(): drawBot.fill(1, 0, 0, 0.5) bez = drawBot.BezierPath() bez.rect(*r) getattr(bez, op)(*args, center=center) drawBot.drawPath(bez)
def makeInstance(self, axes, gname, glyph): nbAxes = maxNbAxes = len(axes) # steps = [1, 2] # maxNbAxes = max(steps) # for nbAxes in steps: speeds = [1 for i in range(nbAxes)] # LCM = self.ilcm(speeds) LCM = 60 # print(LCM) # while ((LCM < 600 or LCM > 1200) or self.checkEqual(speeds)): # speeds = [int(10/nbAxes + random.random()*60/nbAxes) for i in range(nbAxes)] # LCM = self.ilcm(speeds) # print(speeds, LCM, (LCM < 600 or LCM > 1200)) alpha = 2 * math.pi / maxNbAxes ld = [{'Axis': l, 'PreviewValue': 0} for l in axes] # glyph.preview.computeDeepComponentsPreview(ld) origineGlyph = RGlyph() for atomicInstance in glyph.preview(): atomicInstance = atomicInstance.glyph atomicInstance.draw(origineGlyph.getPen()) # origineGlyph = glyph.preview.variationPreview.copy() origineGlyph.name = "interpo" db.newDrawing() for k in range(nbAxes): start = time.time() ld = [{ 'Axis': l, 'PreviewValue': j == k } for j, l in enumerate(axes)] # glyph.preview.computeDeepComponentsPreview(ld) for g in range(LCM): H = 700 W = 700 db.newPage(W * 2.5, H) db.frameDuration(1 / 30) db.fill(1) db.rect(0, 0, W * 2.5, H) r = W / 3 ainc = 0 lines = [] rands = [] values = [] for i in range(nbAxes): path = db.BezierPath() path.moveTo((H / 2, W / 2)) line = (r * math.sin(ainc), r * math.cos(ainc)) path.lineTo((H / 2 + line[0], W / 2 + line[1])) dx = line[0] * .05 dy = line[1] * .05 path.moveTo((H / 2 + line[0] - dy, W / 2 + line[1] + dx)) path.lineTo((H / 2 + line[0] + dy, W / 2 + line[1] - dx)) db.stroke(.2) db.strokeWidth(1.5) db.fill(None) db.drawPath(path) ainc += alpha lines.append((line, axes[i]["sourceName"])) # v = getValueForAxeAtFrame(i, g, nbAxes, LCM, speeds[i]) # values.append(v) if i == k: rands.append([ 1000 * abs( math.sin(math.pi * (speeds[i] * c / LCM + speeds[i]))) for c in range(LCM) ]) else: rands.append([0 for c in range(LCM)]) db.fill(1) db.oval(H / 2 - H * .01, W / 2 - W * .01, H * .02, W * .02) patharea = db.BezierPath() patharea.moveTo((H / 2, W / 2)) patharea.lineTo((H / 2 + lines[0][0][0] * rands[0][g] / 1000, W / 2 + lines[0][0][1] * rands[0][g] / 1000)) db.fill(0, 0, 0, .1) db.stroke(None) for c, (line, lineName) in enumerate(lines): patharea.lineTo((H / 2 + line[0] * rands[c][g] / 1000, W / 2 + line[1] * rands[c][g] / 1000)) patharea.lineTo((H / 2 + lines[0][0][0] * rands[0][g] / 1000, W / 2 + lines[0][0][1] * rands[0][g] / 1000)) patharea.lineTo((H / 2, W / 2)) db.drawPath(patharea) for c, (line, lineName) in enumerate(lines): db.fill(0) #1-rands[c] db.stroke(.2) db.strokeWidth(1) db.oval(H / 2 + line[0] * rands[c][g] / 1000 - 4.5, W / 2 + line[1] * rands[c][g] / 1000 - 4.5, 9, 9) db.fill(.2) ftxt = db.FormattedString(txt=lineName, font="GrtskZetta-Light", fontSize=14, align="center") db.textBox(ftxt, (H / 2 + line[0] * 1.3 - 30, W / 2 + line[1] * 1.3 - 10, 60, 20)) ######### db.save() # ld = [] # for j, l in enumerate(axes): # ld.append({'Axis': l, 'PreviewValue':rands[j][g]/1000}) # # d = {l:rands[j][g]/1000 for (j, l) in enumerate(axes)} # # glyph = interpolation(NewFont().newGlyph('temp'), ufo[gname], layersInfo = d) # # glyph = self.RCJKI.currentFont.get(gname) # glyph.preview.computeDeepComponentsPreview(ld) ######### # print(glyph) db.translate(W * 1.3, H * .15) db.scale(.7 * H / 1000) db.stroke(.5) db.fill(None) db.rect(0, 0, 1000, 1000) db.fill(0) db.stroke(None) db.save() db.translate(0, 120) ratioX = ratioY = (rands[k][g]) / 1000 resultGlyph = RGlyph() locations = {} for e in ld: locations[e["Axis"]["sourceName"]] = e["PreviewValue"] for c in glyph.preview(locations): c = c.glyph c.draw(resultGlyph.getPen()) interpoGlyph = interpolation.interpol_glyph_glyph_ratioX_ratioY_scaleX_scaleY( origineGlyph, resultGlyph, ratioX, ratioY, 1, 1, NewFont(showUI=False)) db.drawGlyph(interpoGlyph) # for aes in glyph.preview: # # axis2layerName = {axisName:layerName for axisName, layerName in self.RCJKI.currentFont[aes['name']].lib['robocjk.atomicElement.glyphVariations'].items()} # # lInfos = {axis2layerName[axisName]:v for axisName, v in aes['coord'].items()} # # print(ae['coord']) # for ae in aes.values(): # glyph = ae[0] # print(glyph) # db.save() # self._drawGlyph(glyph) # db.restore() db.restore() db.restore() caption = db.FormattedString(txt='%s-axis' % (nbAxes), font="GrtskMega-Medium", fontSize=14, align="left") db.textBox(caption, (10, 10, W - 20, 20)) stop = time.time() print(stop - start, "seconde for axis") pdfData = db.pdfImage()
def __init__(self): self.fill = (0, 0, 0, 1) self.bp = db.BezierPath()
(10, 10 - padding - pathPadding)) drawBot.image(path, (0, 0)) drawBot.image(localPath, (w, 0)) im1 = Image.open(path) im2 = Image.open(localPath) diff = ImageChops.difference(im1, im2) with tempfile.NamedTemporaryFile("wb", suffix=".png") as f: diff.save(f, "png") imDiff = drawBot.ImageObject(f.name) drawBot.image(imDiff, (w * 2, 0)) hist = diff.histogram() redPath = drawBot.BezierPath() greenPath = drawBot.BezierPath() bluePath = drawBot.BezierPath() alphaPath = drawBot.BezierPath() reds = hist[0:256] greens = hist[256:512] blues = hist[512:768] alphas = hist[768:1024] redPath.moveTo((0, 0)) greenPath.moveTo((0, 0)) bluePath.moveTo((0, 0)) alphaPath.moveTo((0, 0)) for i in range(256): x = w * (i / 255) redPath.lineTo((x, h * (reds[i] / 255)))
def doExport(self, f, savePath): # Export an image of the glyphs # Collect the glyph names from this font glyphNames = [] glyphChoice = self.w.exportBox.glyphChoice.get() if glyphChoice == 0: glyphNames = list(f.selection) elif glyphChoice == 1: if 'public.glyphOrder' in f.lib.keys(): allNames = f.lib['public.glyphOrder'] else: allNames = list(f.keys()) allNames.sort() # Only keep glyphs that have art for gn in allNames: g = f[gn] if len(g.contours): glyphNames.append(gn) # Find the maximum glyph bounds, to figure out the grid spacing xMax = 0 yMax = 0 for gn in glyphNames: g = f[gn] bounds = g.bounds if bounds: thisXMax = bounds[2] - bounds[0] thisYMax = bounds[3] - bounds[1] if thisXMax > xMax: xMax = thisXMax if thisYMax > yMax: yMax = thisYMax xMax = int(math.ceil(xMax)) * self.pageScale yMax = int(math.ceil(yMax)) * self.pageScale # Figure out how many rows of glyphs we'll need, to lay them out in a square grid if len(glyphNames) < 1: rowCount = 1 else: rowCount = math.ceil(math.sqrt(len(glyphNames))) colCount = math.ceil(len(glyphNames) / rowCount) # Work out the page dimensions, with glyphs centered up on a grid of xMax and yMax with a buffer to give a little space to work with pageWidth = ((colCount + 1) * xMax * self.bufferFactor) pageHeight = ((rowCount + 1) * yMax * self.bufferFactor) # Start drawing, keeping track of where each glyph was placed glyphLocations = [] db.newDrawing() db.newPage(pageWidth, pageHeight) gIdx = 0 for rowNumber in range(rowCount): for colNumber in range(colCount): if gIdx < len(glyphNames): gridID = "%s-%s" % (colNumber, rowNumber) gName = glyphNames[gIdx] glyph = f[gName] # Find the position to draw the glyph # The glyph will be drawn centered on the center of each grid location locX = ((colNumber * xMax * self.bufferFactor) + xMax * self.bufferFactor) locY = (pageHeight - (rowNumber * yMax * self.bufferFactor) - (yMax * self.bufferFactor)) # Adjust the grid location to center the glyph drawing locX += -glyph.width * 0.5 * self.pageScale locY += -yMax * 0.5 glyphLocations.append((gName, gridID)) # Draw the glyph with db.savedState(): db.translate(locX, locY) db.scale(self.pageScale, self.pageScale) pen = CocoaPen(f) glyph.draw(pen) glyphPath = pen.path path = db.BezierPath() path.setNSBezierPath(glyphPath) db.drawPath(path) # Draw the glyph bounding box, for testing if False: db.fill(None) db.stroke(0) db.strokeWidth(10) db.rect(0, 0, xMax, yMax) gIdx += 1 # Prepare a settings document to save, with the number of rows, columns, spacing, scale, and glyph positions drawingData = {} drawingData["pageScale"] = self.pageScale drawingData["bufferFactor"] = self.bufferFactor drawingData["pageWidth"] = pageWidth drawingData["pageHeight"] = pageHeight drawingData["xMax"] = xMax drawingData["yMax"] = yMax drawingData["rowCount"] = rowCount drawingData["colCount"] = colCount drawingData["glyphLocations"] = glyphLocations # Save db.saveImage(savePath) plistPath = os.path.splitext(savePath)[0] + ".plist" with open(plistPath, "wb") as plistFile: dump(drawingData, plistFile)
xh = db.fontXHeight() while xh < h / 6: fontsize += 1 db.fontSize(fontsize) xh = db.fontXHeight() print(fontname, "Calculated font size:", fontsize) target_dir = os.path.join(what, code) if not os.path.exists(target_dir): os.makedirs(target_dir) with open(path, mode="r") as f: for sample in f.readlines(): sample = sample.strip() if sample != "": db.newDrawing() db.newPage(w, h) p = db.BezierPath() db.fill(1) db.stroke(None) db.rect(0, 0, w, h) db.fill(0) # produce SVGs with the text converted # to outlines fs = db.FormattedString(sample, font=fontname, fontSize=fontsize) p.text(fs, (w / 2, h_offset), align="center") db.drawPath(p) db.saveImage(os.path.join(target_dir, sample + ".svg")) tw, _ = db.textSize(fs) if tw > (w - 2 * margin): print("Text '%s' in typeface %s is too wide." %
import drawBot drawBot.newDrawing() drawBot.size(600, 100) p1 = drawBot.BezierPath() p1.oval(5, 5, 70, 70) p2 = drawBot.BezierPath() p2.rect(25, 25, 70, 70) drawBot.fill(0, 0.3) drawBot.stroke(0) drawBot.drawPath(p1) drawBot.drawPath(p2) pUnion = p1 | p2 pIntersection = p1 & p2 pXor = p1 ^ p2 pDiff1 = p1 % p2 pDiff2 = p2 % p1 for p in [pUnion, pIntersection, pXor, pDiff1, pDiff2]: drawBot.translate(100, 0) drawBot.drawPath(p)
def drawOutline(outline): bez = db.BezierPath() outline.drawPoints(bez) db.drawPath(bez)
try: style_name = ttfont.getName(*entry).toStr() break except: pass else: style_name = " " return style_name for i, word in enumerate(args.words): key = lower_file_name(word) fontSize = 1000 font = fonts[i%len(fonts)] sub_folder = font.parent.stem bez = db.BezierPath() db.fontSize(fontSize) db.font(font) s = db.FormattedString(word, fontSize=fontSize, font=font) content_width, content_height = db.textSize(word) space = db.textSize(" ")[0] bez.text(s, (0, 0)) yShift = abs(db.fontDescender())+50 bez.translate(0, yShift) bez_left, bez_bottom, bez_right, bez_top = bez.bounds() canvas_width = content_width canvas_height = db.fontAscender() + abs(db.fontDescender()) + 100