SOLVED Image on a button from a glyph representation
-
Hi,
This is probably easier than I think! Is it possible to add a glyph preview to a vanilla image button? This is what I wrote (mostly taken from the drawbot code), but is not displaying anything:
from vanilla import Window, ImageButton import Quartz import AppKit f = CurrentFont() glyph = f['a'] nspath = glyph.naked().getRepresentation("defconAppKit.NSBezierPath") def _NSPathToCGPath(nsPath): cgPath = Quartz.CGPathCreateMutable() for i in range(nsPath.elementCount()): instruction, points = nsPath.elementAtIndex_associatedPoints_(i) if instruction == AppKit.NSMoveToBezierPathElement: Quartz.CGPathMoveToPoint(cgPath, None, points[0].x, points[0].y) elif instruction == AppKit.NSLineToBezierPathElement: Quartz.CGPathAddLineToPoint(cgPath, None, points[0].x, points[0].y) elif instruction == AppKit.NSCurveToBezierPathElement: Quartz.CGPathAddCurveToPoint( cgPath, None, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y ) elif instruction == AppKit.NSClosePathBezierPathElement: Quartz.CGPathCloseSubpath(cgPath) return cgPath mediaBox = Quartz.CGRectMake(0, 0, 300, 300) _pdfData = Quartz.CFDataCreateMutable(None, 0) dataConsumer = Quartz.CGDataConsumerCreateWithCFData(_pdfData) _pdfContext = Quartz.CGPDFContextCreate(dataConsumer, mediaBox, None) Quartz.CGContextBeginPage(_pdfContext, mediaBox) for i in range(nspath.elementCount()): instruction, points = nspath.elementAtIndex_associatedPoints_(i) if instruction == AppKit.NSMoveToBezierPathElement: Quartz.CGContextMoveToPoint(_pdfContext, points[0].x, points[0].y) elif instruction == AppKit.NSLineToBezierPathElement: Quartz.CGContextAddLineToPoint(_pdfContext, points[0].x, points[0].y) elif instruction == AppKit.NSCurveToBezierPathElement: Quartz.CGContextAddCurveToPoint(_pdfContext, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y) elif instruction == AppKit.NSClosePathBezierPathElement: Quartz.CGContextClosePath(_pdfContext) doc = Quartz.PDFDocument.alloc().initWithData_(_pdfData) class ImageButtonDemo: def __init__(self): self.w = Window((500, 500)) self.w.button = ImageButton((10, 10, 300, 300), imageObject=doc, callback=self.buttonCallback) self.w.open() def buttonCallback(self, sender): print("button hit!") ImageButtonDemo()
Thanks a million!
-
Here is a crude working version. The only drawback here is that it doesn't center the glyph on the button but it's not hard to figure out. I decomposed the glyph so I can scale it.
from fontTools.pens.cocoaPen import CocoaPen from vanilla import * import AppKit from mojo.pens import DecomposePointPen g = CurrentGlyph() def decomposeGlyph(srcGlyph): decomposedGlyph = RGlyph() decomposedGlyph.width = srcGlyph.width dstPen = decomposedGlyph.getPointPen() decomposePen = DecomposePointPen(srcGlyph.font, dstPen) srcGlyph.drawPoints(decomposePen) return decomposedGlyph def glyphImage(g, size, margin): g = decomposeGlyph(g) bottomX, bottomY, topX, topY = g.bounds g.moveBy((-bottomX, -bottomY)) w = topX - bottomX h = topY - bottomY maxDimensionGlyph = max([w, h]) maxDimensionSize = max([d-(margin*2) for d in size]) scaleFactor = maxDimensionSize / maxDimensionGlyph g.scaleBy(scaleFactor) g.moveBy((margin, margin)) pen = CocoaPen(g.layer) g.draw(pen) image = AppKit.NSImage.alloc().initWithSize_(size) image.lockFocus() if AppKit.NSApp().appearance() == AppKit.NSAppearance.appearanceNamed_(AppKit.NSAppearanceNameDarkAqua): AppKit.NSColor.whiteColor().set() else: AppKit.NSColor.blackColor().set() pen.path.fill() image.unlockFocus() return image class ImageButtonDemo: def __init__(self): self.w = Window((1000, 1000)) self.w.button = ImageButton((10, 10, 50, 50), imageObject=glyphImage(g, (50, 50), 10), callback=self.buttonCallback) self.w.open() def buttonCallback(self, sender): print("button hit!") ImageButtonDemo()
-
Actually it looks fine in terms of pixels. I just have to scale it and make it darkmode compatible. Thanks again! Will post the code here.
-
Hi!
The reason I don't want to use drawbot is that I want to make the extension to work independently (it's a simple kerning tool). Although the solution you showed is neat, it doesn't work well for a button for two reasons:
- The button doesn't change its color according to dark mode.
- The image is a raster and gets pixelated on a retina screen.
Regular tool buttons in the glyph view toolbar are more adaptive this way, I guess it's because they're PDF. Thank you Frederik. I will look more into it and will let you know if I found a solution. This could be a nice feature for people who want to make extensions that deal with multiple fonts and only want to use a glyph image as a reference/identifier for a font.
-
euh just use drawbot :)
or easier, there is no need to create a pdf context and draw into a pdf:
from fontTools.pens.cocoaPen import CocoaPen import AppKit g = CurrentGlyph() pen = CocoaPen(g.layer) g.draw(pen) image = AppKit.NSImage.alloc().initWithSize_((1000, 1000)) image.lockFocus() AppKit.NSColor.blueColor().set() pen.path.fill() image.unlockFocus() print(image)