Hi,
i was very exited about the new Drawing PDF export API function, since this will bring more automation to our internal workflow.
But my first attempts to use it where quite unsuccessful.
Not sure how to properly access the functionality.
Starting point:
What i want to do:
Sounds simple, right?
So far it seems i have some technical issues to do that.
app = adsk.core.Application.get()
active = app.activeDocument
drawingDataFile = active.dataFile.parentReferences.item(0)
drawingDocument = app.documents.open(drawingDataFile)
Now i am honestly out of ideas.
Maybe i am missing some fundamental understanding of how this is supposed to work?
Can anybody share an example that works or maybe point me in the right direction?
Thanks in advance.
BR
Solved! Go to Solution.
Solved by kandennti. Go to Solution.
Hi @JuergenGe .
I also noticed that two more were added the other day.
I didn't notice that it had been added to "What's New".
I was able to export the PDF successfully.
#Fusion360API Python script
import adsk.core, adsk.fusion, traceback
import adsk.drawing
_app = adsk.core.Application.cast(None)
_ui = adsk.core.UserInterface.cast(None)
def run(context):
expPDFpath = r'c:/tmp/test.pdf'
try:
global _app, _ui
_app = adsk.core.Application.get()
_ui = _app.userInterface
drawDoc :adsk.drawing.DrawingDocument = _app.activeDocument
draw :adsk.drawing.Drawing = drawDoc.drawing
pdfExpMgr :adsk.drawing.DrawingExportManager = draw.exportManager
pdfExpOpt :adsk.drawing.DrawingExportOptions = pdfExpMgr.createPDFExportOptions(expPDFpath)
pdfExpOpt.openPDF = True
pdfExpOpt.useLineWeights = True
pdfExpMgr.execute(pdfExpOpt)
except:
if _ui:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
It's pretty easy to do.
However, the personal license did not work because of its limitations.
I would like to see a function to check the license and some sample code.
Hi @kandennti
thank you for your answer and your example code.
I think it is always good to have some sample implementation from somebody who knows what he/she is doing.
As far as i can see from your example, you are also opening the active document, implying, that the Drawing is already open in the UI, correct?
drawDoc :adsk.drawing.DrawingDocument = _app.activeDocument
My initial idea was to open a 3D file and then export the linked drawing (without the user having to open the drawing first). This might not be a necessary function, but now i am kind of knee deep on the issue. 😄
I can manage to identify the linked drawing and opening it, but no PDF file gets created.
I have tried some more and there is in fact a race condition.
drawingDoc = app.documents.open(drawingDataFile)
drExpMgr = drawingDoc.drawing.exportManager
pdfOptions = drExpMgr.createPDFExportOptions(<path>)
result = drExpMgr.execute(pdfOptions)
The only way i found to enforce the complete loading of the drawing file is to open a UI messagebox after opening the datafile.
ui.messageBox('Sorry...you gotta wait until the drawing is loaded...', '', 0, 2) # necessary, because fusion does not wait on the file to be completely opened, except for messageBox
For some reason, the OK button can only be pressed once the drawing is fully loaded. Then the export is fired and also generates the desired PDF file. But this is quite a hacky workaround.
I did, however, not find a way to get the same signal... but i am also not the greatest programmer 🙂
What do you think? Can you see similar behavior?
I'm sorry, I completely misunderstood.
I've also tried documentOpened Event, but it's definitely not reliable.
The only other thing I'm aware of is the text command
Application.ListIdleTasks
you can see what tasks Fusion360 is doing.
I created a script like this to try it out.
#Fusion360API Python script
import adsk.core, adsk.fusion, traceback
import adsk.drawing
import time
_app = adsk.core.Application.cast(None)
_ui = adsk.core.UserInterface.cast(None)
def run(context):
try:
global _app, _ui
_app = adsk.core.Application.get()
_ui = _app.userInterface
# msg
dumpMsg(_app.executeTextCommand(u'Application.ListIdleTasks'))
dumpMsg(' -- document open -- ')
# open doc
# Please check and change the datafile.id beforehand.
df = _app.data.activeProject.rootFolder.dataFiles.itemById('urn:adsk.wipprod:dm.lineage:aMijhRAqRlylyP8bFVGJXg')
docs = _app.documents
docs.open(df)
# show task
for _ in range(100):
adsk.doEvents()
dumpMsg(_app.executeTextCommand(u'Application.ListIdleTasks'))
time.sleep(0.1)
except:
if _ui:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
def dumpMsg(msg :str):
_ui.palettes.itemById('TextCommands').writeText(str(msg))
I can't see it clearly, but I think this is the timing when the document is completely loaded and ready for operation.
I need to look into the details, but I think it will work if I get the DrawingDocument at the timing when the "InvalidateCommandsTask" disappears.
However, there are times when the "InvalidateCommandsTask" does not occur, so I feel that some more logic is needed.
I tested it and it worked.
First, I modified it to make it a little easier to see the increase/decrease of tasks.
It opens the first F2D file in the root folder of the active project and dumps the tasks and events.
# Fusion360API Python script
# Dump the task of opening f2d files.
# ' << ' : Increased Tasks
# ' >> ' : IDecreased tasks
# '***' : Checked delimiters
import adsk.core, adsk.fusion, traceback
import adsk.drawing
import time
_app = adsk.core.Application.cast(None)
_ui = adsk.core.UserInterface.cast(None)
handlers = []
def run(context):
try:
global _app, _ui
_app = adsk.core.Application.get()
_ui = _app.userInterface
# add event
onDocumentOpened = MyDocumentOpenedHandler()
_app.documentOpened.add(onDocumentOpened)
handlers.append(onDocumentOpened)
onDocumentOpening = MyDocumentOpeningHandler()
_app.documentOpening.add(onDocumentOpening)
handlers.append(onDocumentOpening)
# msg
dumpMsg(_app.executeTextCommand(u'Application.ListIdleTasks'))
dumpMsg(' -- document open -- ')
# get f2d datafile
datafile = None
for df in _app.data.activeProject.rootFolder.dataFiles:
if df.fileExtension == 'f2d':
datafile = df
# check datafile
if not datafile:
_ui.messageBox('Abort because the "f2d" file cannot be found in the rootFolder of activeProject.')
return
# open doc
docs = _app.documents
docs.open(datafile)
# show task
state = []
for _ in range(80):
adsk.doEvents()
tasks = _app.executeTextCommand(u'Application.ListIdleTasks').split('\n')
now = [s.strip() for s in tasks[2:-1]]
addTask = list(set(now) - set (state))
[dumpMsg(' << {}'.format(s)) for s in addTask]
delTask = list(set(state) - set (now))
[dumpMsg(' >> {}'.format(s)) for s in delTask]
dumpMsg('***')
state = now
time.sleep(0.1)
# remove event
_app.documentOpened.remove(onDocumentOpened)
_app.documentOpening.remove(onDocumentOpening)
except:
if _ui:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
def dumpMsg(msg :str):
_ui.palettes.itemById('TextCommands').writeText(str(msg))
class MyDocumentOpenedHandler(adsk.core.DocumentEventHandler):
def __init__(self):
super().__init__()
def notify(self, args):
dumpMsg('--- Document Opened Event ---')
class MyDocumentOpeningHandler(adsk.core.DocumentEventHandler):
def __init__(self):
super().__init__()
def notify(self, args):
dumpMsg('--- Document Opening Event ---')
The timing of the events is disappointing.
We decided to assume that the file was completely opened by the following four tasks disappearing in sequence.
'DocumentFullyOpenedTask'
'Nu::AnalyticsTask'
'CheckValidationTask'
'InvalidateCommandsTask'
With this in mind, the process of exporting the PDF file works well here.
# Fusion360API Python script
# Sample of exporting a PDF file from an unopened F2D file
import adsk.core, adsk.fusion, traceback
import adsk.drawing
import time
_app = adsk.core.Application.cast(None)
_ui = adsk.core.UserInterface.cast(None)
handlers = []
_exportPDFFolder = r'c:/tmp/'
def run(context):
try:
global _app, _ui
_app = adsk.core.Application.get()
_ui = _app.userInterface
# get f2d datafile
datafile = None
for df in _app.data.activeProject.rootFolder.dataFiles:
if df.fileExtension == 'f2d':
datafile = df
# check datafile
if not datafile:
_ui.messageBox('Abort because the "f2d" file cannot be found in the rootFolder of activeProject.')
return
# open doc
docs = _app.documents
drawDoc :adsk.drawing.DrawingDocument = docs.open(datafile)
# Tasks to be checked.
targetTasks = [
'DocumentFullyOpenedTask',
'Nu::AnalyticsTask',
'CheckValidationTask',
'InvalidateCommandsTask'
]
# check start task
if not targetTasks[0] in getTaskList():
_ui.messageBox('Task not found : {}'.format(targetTasks[0]))
return
# Check the task and determine if the Document is Open.
for targetTask in targetTasks:
while True:
time.sleep(0.1)
if not targetTask in getTaskList():
break
# export PDF
expPDFpath = _exportPDFFolder + drawDoc.name + '.pdf'
draw :adsk.drawing.Drawing = drawDoc.drawing
pdfExpMgr :adsk.drawing.DrawingExportManager = draw.exportManager
pdfExpOpt :adsk.drawing.DrawingExportOptions = pdfExpMgr.createPDFExportOptions(expPDFpath)
pdfExpOpt.openPDF = True
pdfExpOpt.useLineWeights = True
pdfExpMgr.execute(pdfExpOpt)
# close doc
drawDoc.close(False)
except:
if _ui:
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
def getTaskList():
adsk.doEvents()
tasks = _app.executeTextCommand(u'Application.ListIdleTasks').split('\n')
return [s.strip() for s in tasks[2:-1]]
There may be a better way.
I may need to change the tasks to be checked in the future.
Also, I have not considered how to find the F2D file from the F3D file.
@kandennti Wow i am impressed!
Thank you so much for your detailed analysis and dedication 👍
I would have never managed to find that out.
This is really great.
I will try it as soon as i have capacity to do so and will give you feedback. But looking at all your analysis, i now have much more then i would have ever expected!
Thank you so much! This is probably the best help i have ever gotten from a forum entry.
BR
Works like a charm! Thank you for your support. I will implement this workaround in my script for the time being.
BR
Has something changed since 2020? I copied the proposed code but it is throwing an error
@engineeringQCQFN wrote:
I copied the proposed code but it is throwing an error
@engineeringQCQFN Did you save the design before running the script?
Jérôme Briot, Freelance engineer - Mechanical design and prototyping
3D Print Plus / Pro | IDF Import | GitHub To Fusion 360 | Tube Bending Data Exchanger | Slice Data Export
Memory Used | Basic Calculator | Check Computer Specifications | Import spline from any CSV file
I was unable to reproduce the error.
However, in many cases, the PDF file could not be exported correctly.
I still don't know how to know that the document has been fully opened.
Can't find what you're looking for? Ask the community or share your knowledge.