Archi-lab Print to PDF FIX TO PRINT SETTINGS AND COMBINED!

So after a bunch of searching on the forum for issues with the print pdf node I saw everyone end up at the same conclusion “the combined option is broken” and “the print settings don’t apply” and everyone seemed to kind of accept that as fact.
tenor

Well ladies and gents, after many many many hours last night I figured out the problem. The issue was how the code decided which print method to run based on whether you inserted a list of views and a list of print settings or any variation of such.

Lets begin with the print setting issue because it is simple. The usual error that would happen would be something along the lines of “cannot do something because element changed in revit database.” I double checked the api and the code seemed correct the issue however after some fiddling around with where I moved the code was that if it was put into its own transaction it would work perfectly. I also had to unwrap the print setting element.

So these are the line you want to delete/modify:
image

And this is what you want to insert instead.
image

TransactionManager.Instance.EnsureInTransaction(doc)
printSetup = printManager.PrintSetup
printSetup.CurrentPrintSetting = UnwrapElement(printSetting)
printManager.Apply()	
TransactionManager.Instance.TransactionTaskDone()

Now to toggle the combined problem.
image
Here are the 3 print cases. First one being you inserted a list of views and a list of print settings. Second, you inserted a list of views and not a list of print settings. And last, you inserted not a list of views and not a list of print settings. Now no matter how hard you try and play around with the lacing and levels you will notice that when you select combined the pdfs will still print sheet by sheet. To figure out what was wrong I put in a message box for each print setting to see which choice was running and I noticed that when I fed a list of views and a single print setting (because I only need to use one) which would be case 2 the script cycles each sheet as you can see in the code where there is a for loop. If you go back up to the code and look at
image
you will see that it is trying to insert the list of views into the view set which it cant because the viewset insert only accepts views. So what ends up happening with the loop is that you are inserting each sheet one by one and therefore instead of making a combined file its printing each separately. To fix this adjust the code as such so the loop is for the insertion of views to make a true viewset with many views in it. image

Now you need to edit the print option portion of the code ( the one with 3 cases). The fix is to essentially make option 3’s line of code run. So I deleted the 3 if statements and just made it run the code for option 3 as such. image

Now you should be able to print view sets as combined with working print settings. In my case I feed in the list of view for the view set and just one print setting. I haven’t bothered with the other cases but I’m sure with some slight code changes you can get it to work.

Hope this helps everyone who tried to use the node and maybe the code can be changed and cleaned up to work for all cases and uploaded to the package :grinning:

5 Likes

Thank you for verifying the code! I did the changes you mention and I still can’t get it to work…

1 Like

What version of the archi-lab package are you using? It’s possible it could have been updated since. Also it depends on exactly what list structure you are feeding into the print node. It’s been a while since I’ve looked at this code but if you post your graph and show what the inputs are it would help.

Hello! Thank you for the prompt response! Lets see, I want to use as an input an Excel file, and export this to different formats. I’m still working on the code, and I found useful your approach but my knowledge of Python is not enough to decipher what’s next.

I mixed some stuff I found around, as you will see. My Archi-lab version is 2019.2.25.

#Copyright(c) 2015, Konrad K Sobon
# @arch_laboratory, http://archi-lab.net

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# Import Element wrapper extension methods
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)

# Import geometry conversion extension methods
clr.ImportExtensions(Revit.GeometryConversion)

# Import DocumentManager and TransactionManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application

# Import RevitAPI
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

import sys
pyt_path = r'C:\Program Files (x86)\IronPython 2.7\Lib'
sys.path.append(pyt_path)
import System

#The inputs to this node will be stored as a list in the IN variable.
dataEnteringNode = IN

sheets = IN[0]
pRange = System.Enum.Parse(Autodesk.Revit.DB.PrintRange, IN[1])
combined = IN[2]
printerName = IN[3]
printSetting = IN[4]
filePath = IN[5]
runIt = IN[6]

if isinstance(sheets, list):
	viewSheets = []
	for i in sheets:
		viewSheets.append(UnwrapElement(i))
else:
	viewSheets = UnwrapElement(sheets)

def PrintView(doc, sheet, pRange, printerName, combined, filePath, printSetting):
	# create view set 
	viewSet = ViewSet()
	viewSet.Insert(sheet)
	# determine print range
	printManager = doc.PrintManager
	printManager.PrintRange = pRange
	printManager.Apply()
	# make new view set current
	viewSheetSetting = printManager.ViewSheetSetting
	viewSheetSetting.CurrentViewSheetSet.Views = viewSet
	# set printer
	printManager.SelectNewPrintDriver(printerName)
	printManager.Apply()
	# set combined and print to file
	if printManager.IsVirtual:
		printManager.CombinedFile = combined
		printManager.Apply()
		printManager.PrintToFile = True
		printManager.Apply()
	else:
		printManager.CombinedFile = combined
		printManager.Apply()
		printManager.PrintToFile = False
		printManager.Apply()
	# set file path
	printManager.PrintToFileName = filePath
	printManager.Apply()
	# apply print setting
	try:
		printSetup = printManager.PrintSetup
		printSetup.CurrentPrintSetting = printSetting
		printManager.Apply()
	except:
		pass
	# save settings and submit print
	TransactionManager.Instance.EnsureInTransaction(doc)
	viewSheetSetting.SaveAs("tempSetName")
	printManager.Apply()
	printManager.SubmitPrint()
	viewSheetSetting.Delete()
	TransactionManager.Instance.TransactionTaskDone()
	
	return True

try:
	viewSets = FilteredElementCollector(doc).OfClass(ViewSheetSet)
	for i in viewSets:
		if i.Name == "tempSetName":
			TransactionManager.Instance.EnsureInTransaction(doc)
			doc.Delete(i.Id)
			TransactionManager.Instance.ForceCloseTransaction()
		else:
			continue
		
	errorReport = None
	message = "Success"
	if runIt:
		if isinstance(viewSheets, list) and isinstance(printSetting, list):
			for i, j in zip(viewSheets, printSetting):
				PrintView(doc, i, pRange, printerName, combined, filePath, j)
		elif isinstance(viewSheets, list) and not isinstance(printSetting, list):
			for i in viewSheets:
				PrintView(doc, i, pRange, printerName, combined, filePath, printSetting)
		elif not isinstance(viewSheets, list) and not isinstance(printSetting, list):
			PrintView(doc, viewSheets, pRange, printerName, combined, filePath, printSetting)
	else:
		message = "Set RunIt to True"
except:
	# if error accurs anywhere in the process catch it
	import traceback
	errorReport = traceback.format_exc()
	
#Assign your output to the OUT variable
if errorReport == None:
	OUT = message
else:
	OUT = errorReport

It looks like you did not make the edits? specifically the edit to #apply print settings. Here is my code. I think it should fix your problem.

#Copyright(c) 2015, Konrad K Sobon
# @arch_laboratory, http://archi-lab.net

import clr
import msvcrt

clr.AddReference("RevitAPIUI")
from  Autodesk.Revit.UI import *

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# Import Element wrapper extension methods
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)

# Import geometry conversion extension methods
clr.ImportExtensions(Revit.GeometryConversion)

# Import DocumentManager and TransactionManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application

# Import RevitAPI
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

import sys
pyt_path = r'C:\Program Files (x86)\IronPython 2.7\Lib'
sys.path.append(pyt_path)
import System

#The inputs to this node will be stored as a list in the IN variable.
dataEnteringNode = IN

sheets = IN[0]
pRange = System.Enum.Parse(Autodesk.Revit.DB.PrintRange, IN[1])
combined = IN[2]
printerName = IN[3]
printSetting = IN[4]
filePath = IN[5]
runIt = IN[6]

if isinstance(sheets, list):
	viewSheets = []
	for i in sheets:
		viewSheets.append(UnwrapElement(i))
else:
	viewSheets = UnwrapElement(sheets)

def PrintView(doc, sheet, pRange, printerName, combined, filePath, printSetting):
	# create view set 
	viewSet = ViewSet()
	#viewSet.Insert(sheet)
	for i in viewSheets:
		viewSet.Insert(i)

	
	# determine print range
	printManager = doc.PrintManager
	printManager.PrintRange = pRange
	printManager.Apply()
	# make new view set current
	viewSheetSetting = printManager.ViewSheetSetting
	viewSheetSetting.CurrentViewSheetSet.Views = viewSet
	# set printer
	printManager.SelectNewPrintDriver(printerName)
	printManager.Apply()
	
	TransactionManager.Instance.EnsureInTransaction(doc)
	printManager.CombinedFile = True
	printManager.Apply()
	printManager.PrintToFile = True
	printManager.Apply()
	TransactionManager.Instance.TransactionTaskDone()
	
	# set combined and print to file
	#if printManager.IsVirtual:
	#	printManager.CombinedFile = combined
	#	printManager.Apply()
	#	printManager.PrintToFile = True
	#	printManager.Apply()
	#else:
	#	printManager.CombinedFile = combined
	#	printManager.Apply()
	#	printManager.PrintToFile = False
	#	printManager.Apply()
		
	# set file path
	printManager.PrintToFileName = filePath
	printManager.Apply()
	# apply print setting
	TransactionManager.Instance.EnsureInTransaction(doc)
	printSetup = printManager.PrintSetup
	printSetup.CurrentPrintSetting = UnwrapElement(printSetting)
	printManager.Apply()	
	TransactionManager.Instance.TransactionTaskDone()	
	# save settings and submit print
	TransactionManager.Instance.EnsureInTransaction(doc)
	viewSheetSetting.SaveAs("tempSetName")
	printManager.Apply()
	printManager.SubmitPrint()
	viewSheetSetting.Delete()
	TransactionManager.Instance.TransactionTaskDone()
	return True
try:
	viewSets = FilteredElementCollector(doc).OfClass(ViewSheetSet)
	for i in viewSets:
		if i.Name == "tempSetName":
			TransactionManager.Instance.EnsureInTransaction(doc)
			doc.Delete(i.Id)
			TransactionManager.Instance.ForceCloseTransaction()
		else:
			continue
	errorReport = None
	message = True
	if runIt:
		PrintView(doc, viewSheets, pRange, printerName, combined, filePath, printSetting)
	else:
		message = "Set RunIt to True"
except:
	# if error accurs anywhere in the process catch it
	import traceback
	errorReport = traceback.format_exc()
	
#Assign your output to the OUT variable
if errorReport == None:
	OUT = message
else:
	OUT = errorReport

You’re amazing, thank you for posting this!

Hello. Thank you for your code and modification but I’ve still got a message error.
line 103 and 127
TypeError : expected IPrintSetting, got List(object)
is it possible to make a list of print settings for a list of sheets?

Yes but you would have to tweak the way the code is formatted. Since you want to feed a list of print settings (I assume each one being different) you would have to tweak the loops of the code to print a sheet(s) under one loop with one print setting and so on. This may not be the most clear explanation but I can try to describe it further if need be.

felixowns, I attempted to use the code you provided above, but I get an error that says “expected str, got list”
I’ve tried all types of Lacing (Auto, Shortest. Longest, Cross Product)
What am I doing wrong?
Thanks!

Its been a while but I think I only used one location for the file path. You will need to edit the loops and stuff if you need to change the file paths.

1 Like

Thanks. I’m a dummy. I only need one path.

This works well (per your code above), but I need the sheets to be combined in the order which it is sent. Currently, it uses the ViewSet order from Revit (or it’s simply alphabetical), and ignores the order as sent. I assume this is due to the code lines below?

# create view set
viewSet = ViewSet()
#viewSet.Insert(sheet)
for i in viewSheets:
viewSet.Insert(i)

The order I want is that which you see in List.Flatten below. Is there a way to do this? Thanks for any input!

Try this:

for i in range(len(viewSheets)):
    viewSet.Insert(viewSheet[i])
1 Like

Thanks Sean,
I simply replaced the bottom two lines mentioned above with your code. I ran it, and it returns “null”.
The full script is below, if you wouldn’t mind looking at it. Thanks for your help!

#Copyright(c) 2015, Konrad K Sobon
# @arch_laboratory, http://archi-lab.net

import clr
import msvcrt

clr.AddReference("RevitAPIUI")
from  Autodesk.Revit.UI import *

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# Import Element wrapper extension methods
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)

# Import geometry conversion extension methods
clr.ImportExtensions(Revit.GeometryConversion)

# Import DocumentManager and TransactionManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application

# Import RevitAPI
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

import sys
pyt_path = r'C:\Program Files (x86)\IronPython 2.7\Lib'
sys.path.append(pyt_path)
import System

#The inputs to this node will be stored as a list in the IN variable.
dataEnteringNode = IN

sheets = IN[0]
pRange = System.Enum.Parse(Autodesk.Revit.DB.PrintRange, IN[1])
combined = IN[2]
printerName = IN[3]
printSetting = IN[4]
filePath = IN[5]
runIt = IN[6]

if isinstance(sheets, list):
	viewSheets = []
	for i in sheets:
		viewSheets.append(UnwrapElement(i))
else:
	viewSheets = UnwrapElement(sheets)

def PrintView(doc, sheet, pRange, printerName, combined, filePath, printSetting):
	# create view set 
	viewSet = ViewSet()
	#viewSet.Insert(sheet)
	#for i in viewSheets:
		#viewSet.Insert(i)
	for i in range(len(viewSheets)):
    viewSet.Insert(viewSheet[i])

	# determine print range
	printManager = doc.PrintManager
	printManager.PrintRange = pRange
	printManager.Apply()
	# make new view set current
	viewSheetSetting = printManager.ViewSheetSetting
	viewSheetSetting.CurrentViewSheetSet.Views = viewSet
	# set printer
	printManager.SelectNewPrintDriver(printerName)
	printManager.Apply()
	
	TransactionManager.Instance.EnsureInTransaction(doc)
	printManager.CombinedFile = True
	printManager.Apply()
	printManager.PrintToFile = True
	printManager.Apply()
	TransactionManager.Instance.TransactionTaskDone()
	
	# set combined and print to file
	#if printManager.IsVirtual:
	#	printManager.CombinedFile = combined
	#	printManager.Apply()
	#	printManager.PrintToFile = True
	#	printManager.Apply()
	#else:
	#	printManager.CombinedFile = combined
	#	printManager.Apply()
	#	printManager.PrintToFile = False
	#	printManager.Apply()
		
	# set file path
	printManager.PrintToFileName = filePath
	printManager.Apply()
	# apply print setting
	TransactionManager.Instance.EnsureInTransaction(doc)
	printSetup = printManager.PrintSetup
	printSetup.CurrentPrintSetting = UnwrapElement(printSetting)
	printManager.Apply()	
	TransactionManager.Instance.TransactionTaskDone()	
	# save settings and submit print
	TransactionManager.Instance.EnsureInTransaction(doc)
	viewSheetSetting.SaveAs("tempSetName")
	printManager.Apply()
	printManager.SubmitPrint()
	viewSheetSetting.Delete()
	TransactionManager.Instance.TransactionTaskDone()
	return True
try:
	viewSets = FilteredElementCollector(doc).OfClass(ViewSheetSet)
	for i in viewSets:
		if i.Name == "tempSetName":
			TransactionManager.Instance.EnsureInTransaction(doc)
			doc.Delete(i.Id)
			TransactionManager.Instance.ForceCloseTransaction()
		else:
			continue
	errorReport = None
	message = True
	if runIt:
		PrintView(doc, viewSheets, pRange, printerName, combined, filePath, printSetting)
	else:
		message = "Set RunIt to True"
except:
	# if error accurs anywhere in the process catch it
	import traceback
	errorReport = traceback.format_exc()
	
#Assign your output to the OUT variable
if errorReport == None:
	OUT = message
else:
	OUT = errorReport

In case you want to see the dyn graph:


Looks like there is a missing “s” here on viewSheets. Sorry about that.

viewSet.Insert(viewSheet[i])

Use this

viewSet.Insert(viewSheets[i])

1 Like

Thanks,
I tried it. Still “null”. (I did restart Dynamo to be sure.)

Perhaps we are trying to force the Revit View/Sheet Set to change order when it can’t? Thus it returns null? The View/Sheet Set is always alphanumeric order.

I did try the following:

for i, viewSet in enumerate(viewSheets):
viewSet.Insert(viewSheets[i])

I’m a complete novice. There was a suggestion online to use enumerate instead of range(len).

Can you show me how you can do that? I’m ok with dynamo but not with python

@jonathan.laurent Sorry for the late reply. If you’re asking how to print and combine PDFs with Dynamo, then I have made a DYN file here: Print Sheets from Drawing Schedule - Sharing DYN file