PDFAddin slows with number of drawing sheets?

PDFAddin slows with number of drawing sheets?

mslosar
Advisor Advisor
1,417 Views
20 Replies
Message 1 of 21

PDFAddin slows with number of drawing sheets?

mslosar
Advisor
Advisor

So, we've run into an odd issue.  We have had an addin here for a long time that kicks out pdfs. No one has had an issue with it before. We recently brought in another branch of the company into our system. For us, a large IDW file might have had 5 sheets in it. For them, it is not uncommon to cross 100 sheets.

 

All that said, when they run the command to send all sheets to individual pdf's on 124 sheets, it takes close to 3 HOURS to complete - which is just not right at all.

 

If I use the file raw and disable Vault and ilogic, i still get over 1 minute per file. However, if it remove some sheets i get MUCH different results:

 

5 sheets: 1 second per sheet (if that)

25 sheets: 3 seconds per sheet

50 sheets: 6ish seconds a sheet

124 sheets: jumps to 1 minute per sheet.

 

To make matters worse, they have an ilogic routine that can kick out all 124 sheets in 5 minutes.  The PDF portion of the code looks to be exactly the same settings we use, so i'm at a loss as to why the ilogic version zips through and the full blown addin drags so bad with large files.

 

I've not run across anything like this and I was wondering if anyone had seen or had any ideas.

 

Debugging it, it gets directly to the PDFAddin.SaveCopyAs line immediately with no delay. It's executing that line that has the problem. I just cannot think of anything that would delay things so badly on an addin because of the number of sheets.

 

Below is the relevant part of the code:

Inventor.TranslatorAddIn PDFAddin = (TranslatorAddIn)Globals._InvApp.
                                        ApplicationAddIns.ItemById["{0AC6FD96-2F4D-42CE-8BE0-8AEA580399E4}"];

//set ref to the document
DrawingDocument oDoc = (DrawingDocument)Globals._InvApp.ActiveDocument;

//set translation context
TranslationContext oContext = Globals._InvApp.TransientObjects.CreateTranslationContext();
oContext.Type = Inventor.IOMechanismEnum.kFileBrowseIOMechanism;

//create name value map
NameValueMap oOptions = (NameValueMap)Globals._InvApp.TransientObjects.CreateNameValueMap();

//create a data medium object
DataMedium oDataMedium = (DataMedium)Globals._InvApp.TransientObjects.CreateDataMedium();

if(PDFAddin.HasSaveCopyAsOptions[oDoc, oContext, oOptions])
{
    //listing all options for reference
    oOptions.Value["All_Color_AS_Black"] = true;
    //oOptions.Value["Remove_Line_Weights"] = 0;
    oOptions.Value["Vector_Resolution"] = 600;
    //if (showPDF) 
    //{ 
    //    oOptions.Value["Launch_Viewer"] = 1; 
    //}
    //else
    //{
    //    oOptions.Value["Launch_Viewer"] = 0;
    //}
    oOptions.Value["Launch_Viewer"] = 0;
    if (allSheets == false)
    {
        oOptions.Value["Sheet_Range"] = PrintRangeEnum.kPrintCurrentSheet;
    }
    else
    {
        oOptions.Value["Sheet_Range"] = PrintRangeEnum.kPrintSheetRange;
        oOptions.Value["Custom_Begin_Sheet"] = customSheet;
        oOptions.Value["Custom_End_Sheet"] = customSheet;
    }
}
oDataMedium.FileName = pdfPath + @"\" + myPDF;
PDFAddin.SaveCopyAs(oDoc, oContext, oOptions, oDataMedium);

 

 

0 Likes
Accepted solutions (1)
1,418 Views
20 Replies
Replies (20)
Message 2 of 21

g.georgiades
Advocate
Advocate

Hi @mslosar 

 

Without seeing the iLogic and more of the addin code - I can only take a few stabs in the dark.

 

For the addin - you have the Globals._InvApp Lines - Can ensure those are not late bound calls? The way you would check is to look at how Globals._InvApp is defined in the Addin. It should be somewhat similar to this

Public g_inventorApplication As Inventor.Application
Public Class StandardAddInServer
	Implements Inventor.ApplicationAddInServer

	Public Sub Activate(ByVal addInSiteObject As Inventor.ApplicationAddInSite, ByVal firstTime As Boolean) Implements Inventor.ApplicationAddInServer.Activate
		g_inventorApplication = addInSiteObject.Application
       End Sub

...more code

 

If you see the code "GetObject" or "Marshal.GetActiveObject" anywhere in the addin code - then that may cause the function calls to be running late bound. Late bound access can be extremely slow.

 

The next thing I would look at is - is the ilogic code setting the drawing views to raster before exporting. That could affect the PDF render time.

 

The next thing is the colored view rendering options - those can take a long time to render - it is possible to change these during the export, and change them back. Please check if the iLogic is changing anything here. These settings are not the same as the PDF resolution option.

 

ggeorgiades_0-1723060738842.png

 

Although unlikely, "ThisApplication.ScreenUpdating=false" could affect the save time.

(Always wrap code in a try/finally to set this back to true!)

 

Please ensure the document is not programmatically being saved before the pdf is generated? That could be triggering view recalculation which the PDF addin could be competing with.

Actually - for your tests before - please determine if the views are calculating or not (green corners on the views). This could be hard to see in the drawing - but it spawns sub processes in task manager called "Inventor View Compute"

 

 

Another outlandish idea to test is if it is faster to export one sheet at a time and combine them afterwards.

You could also try print to pdf instead of the PDF addin.

 

 

0 Likes
Message 3 of 21

JelteDeJong
Mentor
Mentor

We used to have a similar problem with the dwg export. The problem was that we used to have lots of "Sketched symbols" in our drawing resources (not in a library.) For us, the solution was to delete all unused symbols from the drawing recources.

JelteDeJong_0-1723061710861.png

 

Jelte de Jong
Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.

EESignature


Blog: hjalte.nl - github.com

0 Likes
Message 4 of 21

mslosarKES
Observer
Observer

The globals call does have the March in there

 

public static Inventor.Application _InvApp = (Inventor.Application)Marshal.GetActiveObject("Inventor.Application");

 

So, i can try the other and see if it makes a difference.

 

The ilogic code is pretty basic as well and it isn't setting it to raster.

This is all the ilogic code does in relation to pdfs:

 

For i=1 To ThisDrawing.Document.sheets.count
			ActiveSheet = ThisDrawing.Sheet(ThisDrawing.Document.Sheets(i).Name)
			'iLogicVb.RunRule("SHEET REVISION CUSTOMER")
			'oRevNum = Parameter("SHEET_REV_CUST")
			SheetName = ActiveSheet.Name
			ColonIndex = SheetName.LastIndexOf(":")
			SheetNameOnly = SheetName.Substring(0,ColonIndex)
			fname = SheetNameOnly & ".pdf"  
			printedSheets = fname & vbCrLf & printedSheets
			printsheet (oFolder,fname)
		Next i

Function PrintSheet(sheetPath As String, sheetName As String  )
    
    ' Get the PDF translator Add-In.
    Dim PDFAddIn As TranslatorAddIn
    PDFAddIn = ThisApplication.ApplicationAddIns.ItemById _
                            ("{0AC6FD96-2F4D-42CE-8BE0-8AEA580399E4}")

    'Set a reference to the active document (the document to be published).
    Dim oDocument As Document
    oDocument = ThisApplication.ActiveDocument
     Dim oContext As TranslationContext
    oContext =  ThisApplication.TransientObjects.CreateTranslationContext
    oContext.Type = kFileBrowseIOMechanism
    'Create a NameValueMap object
    Dim oOptions As NameValueMap 
     oOptions = ThisApplication.TransientObjects.CreateNameValueMap
    ' Create a DataMedium object
    Dim oDataMedium As DataMedium
    oDataMedium = ThisApplication.TransientObjects.CreateDataMedium
    ' Check whether the translator has 'SaveCopyAs' options
    If PDFAddIn.HasSaveCopyAsOptions(oDocument, oContext, oOptions) Then
        
        ' Options for drawings...
        'oOptions.Value("Launch_Viewer") = launchviewer
        oOptions.Value("All_Color_AS_Black") = 1
        'oOptions.Value("Sheet_Range") = ThisApplication.PrintRangeEnum.kPrintAllSheets
        oOptions.Value("Sheet_Range") = Inventor.PrintRangeEnum.kPrintCurrentSheet
        
        'oOptions.Value("Remove_Line_Weights") = 0
        'oOptions.Value("Vector_Resolution") = 400
        
        'oOptions.Value("Custom_Begin_Sheet") = 2
        'oOptions.Value("Custom_End_Sheet") = 4
    End If
    'get PDF target folder path
    
     'Set the PDF target file name
    
    oDataMedium.FileName = sheetPath & "\" & sheetName 
    'Publish document.
    If  System.IO.File.Exists( sheetPath & "\" & sheetName ) Then
        resp = MsgBox("Overwrite?" & vbLf & "Yes = Overwrite old file" & vbLf & "No = Create New Appended File", vbYesNo, "PDF Rule")
        If resp = vbYes
            System.IO.File.Delete( sheetPath & "\" & sheetName )
            MessageBox.Show("Earlier PDF deleted! ", "Inventor")
        Else 
'            sheetName = sheetName + "0"
'            PrintSheet(sheetPath As String, sheetName As String) 
            'Exit here to prevent it from being saved again
            Exit Function
        End If
 End If 
 PDFAddIn.SaveCopyAs(oDocument, oContext, oOptions, oDataMedium)
End Function

 

 

0 Likes
Message 5 of 21

mslosarKES
Observer
Observer

Also, the globals file isn't 'the' addin, it's one of many files in there. I have one cs file per command.  The StandardAddinServer.cs is it's own file and never had a Inventor.Application in it. It is setting up the commands and UI structure only.

0 Likes
Message 6 of 21

g.georgiades
Advocate
Advocate

@mslosarKESIt looks like the ilogic you posted is printing the sheets one at a time. Is the output of that script a large batch of individual PDFs? Do the users then manually combine them afterwards? I don't see a programmatic method for it.

 

Even if the Late binding is not causing an issue, I strongly recommend changing the addin to use the "Activate" method to get the application object. Late bound calls are essentially all reflection and treated as out of process calls so any access to the inventor application can be significantly slower - even though the code is "inside" the application.

 

Windows seems to like to re-render PDFs a lot... and consume a huge amount of system resources while it does (just try scrolling quickly though a big PDF with lots of raster images). I am not sure what back-end Inventor uses to generate the PDFs, but it is possible when adding a new sheet to the PDF it is generating, it has to re-render the prior sheets. For a lot of PDF pages - that can add a lot of time. Printing separately then combining using non-graphical means seems to be significantly faster from what I have experienced using PDFSam or iText Libraries.

0 Likes
Message 7 of 21

mslosar
Advisor
Advisor

The way we're required to do things by our customers is each sheet is its own PDF in the end. If we have a 100 sheet drawing and make a change to one sheet, customers want that one sheet submitted, not a full book of 100 sheets where they need to figure out what sheet has a change on it.  This group has a similar mandate from their shop - each part must have it's own PDF.

 

As for the processes, i think exactly the same thing, I'm just at a loss to explain why two things using the same pdfaddin with the same settings have very different results. I got your response on the globals method as I was leaving last night and I just got back in, so i'll be seeing if that makes a difference later this morning. Fingers crossed!

0 Likes
Message 8 of 21

g.georgiades
Advocate
Advocate

In the ilogic code it uses

 

 

 

oOptions.Value("Sheet_Range") = Inventor.PrintRangeEnum.kPrintCurrentSheet

 

 

 

This means it has to activate the sheet before exporting it (somewhere - the code is not shown) - the addin code does it differently by using the sheet indices but it does not explicitly activate the sheet beforehand (unless elsewhere in the code not shown?). Is there a chance this is affecting it?

 

There is also the possibility of Garbage collection slowing it down - since you printing each sheet separately, you are calling the print function many times which ends up creating the same context and re-getting the pdf addin, document, etc only to end up with the same values - there is a possibility those are not getting cleaned up over the course of many calls. Especially since each of those calls is late bound in the addin currently. You could try making those global or restructuring your functions so the same variables get re-used for every sheet export. I am not sure if new context and data medium need to be recreated for every export

 

Here is a dirty example in ilogic - but it is similar for C# addin.

 

 

Sub exportAllSheetsExample(sheetPath As String)
		Dim PDFAddIn As TranslatorAddIn = ThisApplication.ApplicationAddIns.ItemById _
							("{0AC6FD96-2F4D-42CE-8BE0-8AEA580399E4}")

		Dim oDocument As DrawingDocument = ThisApplication.ActiveDocument
		Dim oContext As TranslationContext = ThisApplication.TransientObjects.CreateTranslationContext
		oContext.Type = kFileBrowseIOMechanism
		Dim oOptions As NameValueMap = ThisApplication.TransientObjects.CreateNameValueMap
		Dim oDataMedium As DataMedium = ThisApplication.TransientObjects.CreateDataMedium
		If PDFAddIn.HasSaveCopyAsOptions(oDocument, oContext, oOptions) Then
			oOptions.Value("All_Color_AS_Black") = 1
			oOptions.Value("Sheet_Range") = Inventor.PrintRangeEnum.kPrintCurrentSheet
		End If

		For Each sheet As Sheet In oDocument.Sheets
			sheet.Activate()
			'ThisApplication.UserInterfaceManager.DoEvents() 'may be necessary to let the UI update?

            SheetName = sheet.Name
			ColonIndex = SheetName.LastIndexOf(":")
			SheetNameOnly = SheetName.Substring(0,ColonIndex)
			fname = SheetNameOnly & ".pdf"  
			oDataMedium.FileName = sheetPath & "\" & fname
			If System.IO.File.Exists(sheetPath & "\" & fname) Then
				Dim resp As MsgBoxResult = MsgBox("Overwrite?" & vbLf & "Yes = Overwrite old file" & vbLf & "No = Create New Appended File", vbYesNo, "PDF Rule")
				If resp = vbYes Then
					System.IO.File.Delete(sheetPath & "\" & fname)
					MessageBox.Show("Earlier PDF deleted! ", "Inventor")
				Else
					Continue For
					'fname= fname+ "0"
					'oDataMedium.FileName = sheetPath & "\" & fname
				End If
			End If
			PDFAddIn.SaveCopyAs(oDocument, oContext, oOptions, oDataMedium)
		Next
	End Sub

 

 

 

0 Likes
Message 9 of 21

mslosar
Advisor
Advisor

I just tried changing the late access per what's shown above and it failed to pick up the instance (instance not found)

class Globals
{
    //public static Inventor.Application _InvApp = (Inventor.Application)Marshal.GetActiveObject("Inventor.Application");
    public static Inventor.Application _InvApp;

    public void Activate(Inventor.ApplicationAddInSite addInSiteObject, bool firstTime)
    {
        _InvApp = addInSiteObject.Application;
    }
0 Likes
Message 10 of 21

g.georgiades
Advocate
Advocate

GLobals is not the main addin load class. It is usually called standardaddinserver server or something - in order for the addin to be loaded - that function should already exist in the addin code - you just need to find it.

 

you need to find this in your addin code - then you can set the global value to this.

public class AddInServer : Inventor.ApplicationAddInServer
	{
		public void Activate(Inventor.ApplicationAddInSite addInSiteObject, bool firstTime)
		{
                        Globals._InvApp = addInSiteObject.Application;
		}
...

 

Here is an introductory bit - it is in vb.net, but it is similar to C#. There are also a few samples in the inventor dev tools.

https://help.autodesk.com/view/INVNTOR/2024/ENU/?guid=GUID-52422162-1784-4E8F-B495-CDB7BE9987AB

https://help.autodesk.com/view/INVNTOR/2022/ENU/?guid=GUID-6FD7AA08-1E43-43FC-971B-5F20E56C8846

0 Likes
Message 11 of 21

mslosar
Advisor
Advisor

OK, i have found it and made the changes there and am setting _InvApp with that. I had trouble finding it. This addin was last rewritten 4ish years ago and that function was well down the page.

 

I've also turned off activate as well.

 

No change in speed sadly. I can still get the SaveCopyAs line right off the bat, but executing that line is where the delay is. If the same problem occurred via ilogic, it'd make sense, but it only occurs on the API side for some reason. I've moved this to a test function and am trying to weed out everything possible, but it seems linked to number of sheets though i have no idea why it only affects the API side.

 

0 Likes
Message 12 of 21

g.georgiades
Advocate
Advocate
Accepted solution

Let me know how your test goes. At this point without seeing the full code of both the addin/iLogic, I cannot think of any other causes.

 

Did you try switching the addin to use

oOptions.Value("Sheet_Range") = Inventor.PrintRangeEnum.kPrintCurrentSheet

 and activate each sheet before exporting?

0 Likes
Message 13 of 21

g.georgiades
Advocate
Advocate

If iLogic is faster, you could also try rewriting the addin to run the ilogic rule instead of running itself?

It might behave the same since it is called from the addin initially, but would be worth a shot.

 

Is there a reason to use the addin over the ilogic? Is the addin adding a context menu entry somewhere? Otherwise, if it is making a ribbon button - you can do that with autodesk 2023+

0 Likes
Message 14 of 21

mslosar
Advisor
Advisor

So, this is the entire process with the complete Test function:

 

The calling function:

for (int i = 0; i < oDoc.Sheets.Count; i++)
{
    int customSheetNumber = i + 1;

    if (!string.IsNullOrEmpty(kgDwgType))
    {
        if (!oDoc.Sheets[i+1].ExcludeFromPrinting)
        {   
            PrintToPDF.TestPDF(true, customSheetNumber, false, false, kgDwgType, sendToVault, kgUnitType);
        }
    }
    else
    {
        PrintToPDF.TestPDF(true, customSheetNumber, false, false, "", sendToVault);        
    }  

}

 

There is a separate button to call a single sheet print (the active sheet) and it is simply this and runs the pdf in about a second.

if (!string.IsNullOrEmpty(kgDwgType))
{    
    TestPDF(false, 1, false, false, kgDwgType, sendToVault, kgUnitType);
    MessageBox.Show("Drawing printed successfully.");
   
}
else
{
    TestPDF(false, 1, false, false, "", sendToVault);
    MessageBox.Show("Drawing printed successfully.");
}

 

PrintAllSheets function:

public static void TestPDF(bool allSheets = false, int customSheet = 1, bool showPDF = false, bool CalledFromIlogic = false, string dwgtype = "", DialogResult vAnswer = DialogResult.Yes, string kgUnits = "none")
{
    
    Inventor.TranslatorAddIn PDFAddin = (TranslatorAddIn)Globals._InvApp.
                                            ApplicationAddIns.ItemById["{0AC6FD96-2F4D-42CE-8BE0-8AEA580399E4}"];

    //set ref to the document
    DrawingDocument oDoc = (DrawingDocument)Globals._InvApp.ActiveDocument;

    //set translation context
    TranslationContext oContext = Globals._InvApp.TransientObjects.CreateTranslationContext();
    oContext.Type = Inventor.IOMechanismEnum.kFileBrowseIOMechanism;

    //create name value map
    NameValueMap oOptions = (NameValueMap)Globals._InvApp.TransientObjects.CreateNameValueMap();

    //create a data medium object
    DataMedium oDataMedium = (DataMedium)Globals._InvApp.TransientObjects.CreateDataMedium();

    if (PDFAddin.HasSaveCopyAsOptions[oDoc, oContext, oOptions])
    {
        //listing all options for reference
        oOptions.Value["All_Color_AS_Black"] = true;        
        oOptions.Value["Vector_Resolution"] = 600; 
        oOptions.Value["Launch_Viewer"] = 0;             
        oOptions.Value["Sheet_Range"] = PrintRangeEnum.kPrintSheetRange;
        oOptions.Value["Custom_Begin_Sheet"] = customSheet;
        oOptions.Value["Custom_End_Sheet"] = customSheet;        
       }

    oDataMedium.FileName = "C:\\Projects\\PDFs\\STDM-002" + customSheet + ".pdf";
    
    //local pdfs will not be controlled files, so before we write, we have to remove read only.
    FileInfo fileInfo = new FileInfo(oDataMedium.FileName);
    if (File.Exists(oDataMedium.FileName) && fileInfo.IsReadOnly)
    {
        fileInfo.IsReadOnly = false;
    }

    //write the pdf file
    PDFAddin.SaveCopyAs(oDoc, oContext, oOptions, oDataMedium);
}

 

 

0 Likes
Message 15 of 21

mslosar
Advisor
Advisor

So, I need to do a good deal more testing, but that looks to be it.  Using a slightly modified test function (i had to turn sheet activation back on), it ran all 124 sheets in about 3 minutes.

 

I need to integrate that change to the original function and see if the time still holds (i don't see why not), but never assume anything will just work 🙂

0 Likes
Message 16 of 21

g.georgiades
Advocate
Advocate

What is the exact solution? It is not clear in your message 😂

 

I do hope it was not a fluke!

0 Likes
Message 17 of 21

mslosar
Advisor
Advisor

This board needs a quote feature....i clicked reply, it showed me the message i was replyng to, but it didn't show any reference to it in the post. So, it was this:

 

oOptions.Value("Sheet_Range") = Inventor.PrintRangeEnum.kPrintCurrentSheet

So, even though i had the range set to the equivalent of sheet 3 to sheet 3 (i.e., just one sheet), it would seem when using kPrintSheetRange it preps all 120 sheets in this case and then just makes a pdf file for 1 of the sheets. It wasn't limiting its work to the sheets in the range. I would think the PDFAddin would work that way, but, clearly not. On top of that, i had to turn on the oSheet.Activate() line again to make it the current sheet. Doing both of those has it running pretty quickly.

 

In fact, i set off a print run of all 124 sheets using the original function making the changes listed in the post and it is already complete in 3ish minutes which bests the 5 minutes from the ilogic routine 🙂

Message 18 of 21

g.georgiades
Advocate
Advocate

👍

 

@MjDeckCan you weigh in on why the PDF export functionality functions the way @mslosar describes?

0 Likes
Message 19 of 21

mslosar
Advisor
Advisor

FWIW, i tried looking up the different options in help (KPrintCurrentSheet, KPrintSheetRange) and there's nothing there about what actually occurs, it just says 'prints the current sheet' and 'prints a range of sheets' type of things, i sent a comment in on that asking for explanation and explaining what I ran into with this.

0 Likes
Message 20 of 21

MjDeck
Autodesk
Autodesk

@g.georgiades , I'm not very familiar with the details of PDF export from a drawing. @mslosar says he has asked a question (somewhere) about performance of the current sheet versus a sheet range. Maybe we can improve the performance for sheet range. Let me know if you want me to follow up on anything.


Mike Deck
Software Developer
Autodesk, Inc.

0 Likes