PDF adding pages to existing file
-
Hello,
I'm currently using Drawbot to generate a character set of the current font. The problem is that when saves the PDF it doesn't generate a new file but it keeps adding pages to an existing PDF in the directory.
I'm not sure how much would help to have the whole script but for now I'm sharing the block of code that I think is causing this problem. I guess it is the way I'm saving the PDF.
# ----------------------------------------------------- # Accessing the directory of the file fDirectory = os.path.dirname(f.filepath) # Directory fName = os.path.basename(f.filepath) # Only the name fNameParts = os.path.splitext(fName) # Split parts fPath = f.filepath # ----------------------------------------------------- # Generating a file with the character set NewfName = fNameParts[0] + ' - Character set.pdf' # Change extension NewfPath = os.path.join(fDirectory, NewfName) # Saving the .pdf saveImage(NewfPath)
Thanks beforehand for any help!
-
hello @RicardGarcia,
from the problem description, it sounds like you鈥檙e saving the pdf inside a loop, for example after making each page. usually what you want to do instead is create pages with a loop, and then save the pdf at the end outside the loop.
(the snippet you posted is not related to the problem, I think)
hope this helps!
-
ps. see also this character set proof example using the DrawBot extension in RoboFont.
-
Thanks for the answer, @gferreira. I'm actually saving the pdf at the very end of the script outside the loop that creates the pages.
I'm using Drawbot inside Glyphs and, just to test it, I've run the script both using Drawbot as a module (which generates the problem) and running it with the UI inside Glyphs and it works fine.
I still don't fully get what's going on there, do you have any idea? I could share the code if you want.
Thanks again for your help and the link.
-
outside the app DrawBot, when using DrawBot as a module, you have to call
drawBot.newDrawing()
to reset the drawing stack.see https://www.drawbot.com/content/canvas/pages.html#drawBot.newDrawing
its also adviced to call
drawBot.endDrawing()
when you are done.see https://www.drawbot.com/content/canvas/pages.html#drawBot.endDrawing
-
Thanks @frederik! This was what I was missing and now it works just as I expected.
-
Hello again,
I'm again using DrawBot as a module to use it inside Glyphs and, while ths script works inside Drawbot's plugin in Glyphs, it doesn't generate the same output when I'm using it as a script.
I'm using
newDrawing()
andendDrawing()
but still it doesn't work.Any idea what it could be?
Thanks!
-
euh, nope, you will need to provide more info
do you have a sample script?
and how is the output different?thanks
-
Hi @frederik, I'm posting the script itself (even though it's a bit long) but before, maybe this will help knowing what's happening. So I'm doing an animation out of different frames and each frame has a glyph drawn in it. When I'm using Drawbot inside Glyphs its drawing both frame (red background) and the glyph in white.
When it comes to run the script outside Drawbot (inside Glyphs), it keeps drawing the red background and each frame but it is no longer drawing the glyph. I guess it could have to do with
completeBezierPath
from Glyphs but I've used before and it works in other scripts.Here the script:
# --------------------- # Modules # --------------------- from GlyphsApp import * from drawBot import * from AppKit import NSColor import vanilla, math import textwrap import os # --------------------- # Empty stack for Drawbot newDrawing() # --------------------- # Clear log in Macro Panel Glyphs.clearLog() class singleGlyphsAnimation( object ): """GUI generating an animation with all selected characters in the Font level""" def __init__( self ): # Window sizes windowW = 350 windowH = 320 # UI elements linePos = 20 margin = 20 lineHeight = 23 columnLine = 140 #print(columnLine) # Building window self.w = vanilla.FloatingWindow( ( windowW, windowH ), "Animation generator" ) # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 # Title self.w.descriptionText = vanilla.TextBox( (margin, linePos-5, -margin, lineHeight), "Select the characters you want in the animation", sizeStyle = "small") # Opening the window self.w.open() # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 linePos += lineHeight*1.4 #self.w.line0 = HorizontalLine((margin, int(linePos+4), -margin, 1)) #linePos += lineHeight # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 # Page format (in pixels) self.w.pageFormatTitle = vanilla.TextBox((margin, linePos, -margin, lineHeight), "Set frame format (px):", sizeStyle = "small") # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 # ColorWell self.w.ColorWellTitle = vanilla.TextBox((columnLine + 40, linePos, 200, lineHeight), "Set colors:", sizeStyle = "small") # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 linePos += lineHeight # Width self.w.widthTitle = vanilla.TextBox((margin*3, linePos+2, 100, lineHeight), "Width", sizeStyle = "small") self.w.widthUser = vanilla.EditText((110, linePos, 50, 20), "1920", sizeStyle = "small") #print(int(str(self.w.widthUser.get()))) # Foreground color self.w.fgColorTitle = vanilla.TextBox((columnLine + margin*3, linePos+2, 100, lineHeight), "Foreground", sizeStyle = "small") self.w.fgColorWell = vanilla.ColorWell((columnLine + 20 + 120, linePos, 50, 20), color = NSColor.colorWithCalibratedRed_green_blue_alpha_(255/255, 255/255, 255/255, 1)) #print(self.w.fgColorWell.get()) linePos += lineHeight # Height self.w.heightTitle = vanilla.TextBox((margin*3, linePos+2, 100, lineHeight), "Height", sizeStyle = "small") self.w.heightUser = vanilla.EditText((110, linePos, 50, 20), "1200", sizeStyle = "small") # Background color self.w.bgColorTitle = vanilla.TextBox((columnLine + margin*3, linePos+2, 100, lineHeight), "Background", sizeStyle = "small") self.w.bgColorWell = vanilla.ColorWell((columnLine + 20 + 120, linePos, 50, 20), color = NSColor.colorWithCalibratedRed_green_blue_alpha_(0/255, 0/255, 0/255, 1)) #print(self.w.bgColorWell.get()) # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 linePos += lineHeight +3 self.w.line = vanilla.HorizontalLine((margin, int(linePos+12), columnLine, 1)) self.w.line2 = vanilla.HorizontalLine((columnLine + 40, int(linePos+12), -margin, 1)) linePos += lineHeight # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 # Frame duration title self.w.frameDurationTitle = vanilla.TextBox((margin, linePos+2, 200, lineHeight), "Set frame duration:", sizeStyle = "small") # Enable show nodes self.w.showNodes = vanilla.CheckBox((columnLine + 40, linePos-2, -margin, lineHeight), "Show nodes", value = False, sizeStyle = "small") #print(self.w.showNodes.get()) self.w.showNodes.getNSButton().setToolTip_("If enabled, it will show the nodes and handles instead of a filled version of the characters.") # Frame duration edit linePos += lineHeight self.w.frameTextEdit = vanilla.TextBox((margin*3, linePos+2, 100, lineHeight), "Fps", sizeStyle = "small") self.w.frameDurationUser = vanilla.EditText((110, linePos, 50, 20), "10", sizeStyle = "small") # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 linePos += lineHeight self.w.line3 = vanilla.HorizontalLine((margin, int(linePos+15), -margin, 1)) linePos += lineHeight # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 # Saving file format self.w.savingFormatTitle = vanilla.TextBox((margin, int(linePos+10), columnLine, lineHeight), "Select the file format:", sizeStyle = "small") self.w.popUpFormat = vanilla.PopUpButton((columnLine+10, linePos+7, -margin, 20), [".gif", ".mov", ".jpg", ".pdf"]) # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 linePos += lineHeight * 3 # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 # Generate button self.w.generateAnimation = vanilla.Button((margin, linePos, -margin, lineHeight), "Generate animation", sizeStyle = "small", callback = self.generateAnimation) # Test button def testButton( self, sender ): print("Test") # Main button used to generate the animation def generateAnimation( self, sender ): print("Animation!") # --------------------- # Variables # --------------------- # Font object f = Glyphs.font #print(f.selectedLayers) # Selection selection = f.selection #print(selection) # Frame duration fDuration = int(self.w.frameDurationUser.get()) # Scale scaleUser = 60 s = scaleUser/100 # Current master ID masterID = f.selectedFontMaster.id # Randomize master's index #masterIndexRandom = random.randint(0,len(f.masters)) #print(masterIndexRandom) # Get the selected layer layer = Glyphs.font.selectedLayers[f.masterIndex] # String userString = f.selection # Amount of frames #frames = len(f.selection) # Frame duration #fDuration = self.w.frameTextEdit.get() # Page format (pixels) w, h = int(str(self.w.widthUser.get())), int(str(self.w.heightUser.get())) # Set visible nodes nodesActive = True # Background color (CMYK) bgColor = [0, .90, .86, 0] # TR Red # Lettershapes colours (CMYK) fgColor = [0, 0, 0, .2] # --------------------- # Functions # --------------------- # Centered glyph def centeredGlyph(layer, scaleFactor, pageWidth, pageHeight): with savedState(): scale(scaleFactor) layerW = layer.bounds.size.width layerH = layer.bounds.size.height newOriginX = ( pageWidth - layerW ) / 2 newOriginY = ( pageHeight - layerH ) / 2 #print(newOriginX, newOriginY) return(newOriginX, newOriginY) # Drawing the nodes of each character def drawNodes(layer, diameter, color): radius = diameter / 2 for j, path in enumerate(layer.paths): #print(i, path) for i, node in enumerate(path.nodes): xNode, yNode = node.position if node.type == "offcurve": cmykFill(*bgColor) strokeWidth(1) stroke(1) oval( xNode - radius, yNode - radius, diameter, diameter ) cmykFill(*fgColor) elif node.type == "curve": fill(1) oval( xNode - radius, yNode - radius, diameter, diameter ) cmykFill(*fgColor) # Previous 3rd point p3X, p3Y = path.nodes[i-3].position # Previous 2nd point p2X, p2Y = path.nodes[i-2].position # Previous point p1X, p1Y = path.nodes[i-1].position stroke(1) line( (p3X, p3Y), (p2X, p2Y) ) line( (p1X, p1Y), (xNode, yNode) ) stroke(None) else: fill(1) oval( xNode - radius, yNode - radius, diameter, diameter ) cmykFill(*fgColor) for g in selection: newPage(w, h) frameDuration(1/fDuration) # Background cmykFill(*bgColor) rect(0,0,w,h) layer = g.layers[f.masterIndex] #print(layer.parent) # Generating a new page/frame #fill(1) print(layer.parent.name) #print( layer.bounds.origin.x, layer.bounds.origin.y) X, Y = centeredGlyph(layer, s, w, h) with savedState(): #oval(width()/2, height()/2, 20, 20) scale(s, center =(width()/2, height()/2)) translate(X-layer.bounds.origin.x , Y- layer.bounds.origin.y + layer.bounds.size.height * .06) if self.w.showNodes.get() == 1: drawNodes(layer, 10, (0)) strokeWidth(1) cmykStroke(0,0,0,.2) cmykFill(None) drawPath(layer.completeBezierPath) print("nodes") #for c in layer.components: #drawPath(c.completeBezierPath) elif self.w.showNodes.get() == 0: cmykFill(0,0,0,.2) strokeWidth(1) cmykStroke(None) drawPath(layer.completeBezierPath) print("not-nodes") else: print("Nodes problem") pass # --------------------- # Telling Drawbot the drawing is done endDrawing() # Closing the window self.w.close() # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 # Saving process # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 # ----------------------------------- # Accessing the directory of the file fDirectory = os.path.dirname(f.filepath) # Only the directory fName = os.path.basename(f.filepath) # Only the name fNameParts = os.path.splitext(fName) # Split parts fPath = f.filepath # -------------------------------------- # Generating a text file with the report # Assigning a format self.w.popUpFormat.get() listOfFormats = [".gif", ".mov", ".jpg", ".pdf"] NewfName = fNameParts[0] + ' - Glyphs animation%s' % (listOfFormats[self.w.popUpFormat.get()]) # Change extension NewfPath = os.path.join(fDirectory, NewfName) # Change extension # Saving the .pdf saveImage(NewfPath) # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 # Glyphs' notification # 路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路路 Glyphs.showNotification('Animation generator', 'Generated animation from selection in the current font') # --------------------- # Test # --------------------- print("Done") # Calling the object singleGlyphsAnimation()
-
could you provide a simpler example... by eliminating all imports and functionality which is not default (like
from GylphsApp
)And every drawing should be wrapped in
newDrawing()
andendDrawing
. You are doing this now at the top of the script (once).
-
Hi, Frederik. The point now is that it is using some functionalities I don't know how to translate into a more generic context using
currentFont()
, for instance. Now I'm using a function inside Glyph's API calledcompleteBezierPath
which draws what's inside a glyph cell. I've been making the script much simpler but still I have this small details. Is there something similar to this GLyphs function that I could use?
-
I only wanted to teach you how to narrow down the problem, by elimenating parts :), make the problem as small as possible and fix the smallest problems first.
All the Glyhps callback are not the issue:
When you draw physically: you would start a drawing by first taking some paper, picking up a pencil, put the pencil down and draw, finish the drawing by framing it and hanging it on the wall!
Translating your code: you are drawing on the same paper over and over again, and only saving the image after you hang it to the wall...
I will let you try some more
good luck!!
-
Thanks Frederik! I think I've managed to have what I wanted to. Thanks a lot for bringing the whole problem to a more easy approach.