Merge (Combine) PDFs

Merge (Combine) PDFs

emanuel.c
Collaborator Collaborator
5,691 Views
24 Replies
Message 1 of 25

Merge (Combine) PDFs

emanuel.c
Collaborator
Collaborator

Hi! I would like to Merge PDFs (drawings) with Inventor. I would have, for example, an Assembly which contains parts and / or Sub-Assemblies. I would open the Drawing file of this Assembly and would read each line of the Parts List (probably the largest parts list on the drawing, if there are more Parts Lists) and confirm the existence of a PDF drawing of each part. Next would be to attach to the PDF of this original drawing all the PDFs of Sub-Assemblies and Parts and save it with an additional "Compiled" name or something, in a Compiled folder etc.

 

It seems difficult to use some kind of PDF compiler with ilogic, though I see it done with VB in Excel, Adobe Acrobat plugins etc.. I think I would prefer doing it from within Inventor, but I may have to jump to VB in Excel if I must.

 

I started with code from this post here, using the itextsharp.dll. It works well, it compiles a PDF of all PDFs it finds it the given folder and does this for its subfolders also. This it does well, but I have a hard time editing this piece of code to suit what I need, for example even changing not to read from subfolders, to compile only certain files. But I  might have to dig in a bit deeper here.

 

I can read the Parts List, see if each part has PDFs etc. but the compiling I'm struggling with a bit. I'll begin working on it, but wanted to ask in case someone more knowledgeable can give some input.

 

There are many ways to batch print PDF drawings including this little app drawing porter but for us, we would like to keep PDFs as manufacturing history etc.

 

Thank you!

0 Likes
5,692 Views
24 Replies
Replies (24)
Message 2 of 25

emanuel.c
Collaborator
Collaborator

This is what I'm working on. I still need to get referenced document type and open next level drawings if it's an Assembly or Weldment and see if those have PDF drawings.

 

My main issue is how to get these PDFs combined...

 

Public Class Variables
	Dim oDrawDoc As DrawingDocument
	Dim oPL As PartsList
	Dim oSheet As Sheet	

Sub Main()
	If Not ThisApplication.ActiveDocument.DocumentType = kDrawingDocumentObject Then
		MessageBox.Show("This rule only runs in drawing documents! Exiting...")
		Exit Sub
	End If

	CompileDrawings

End Sub

Sub CompileDrawings

	Dim oDrawingView As DrawingView	
	Dim i As Long = FirstPL
	oPL = oDrawDoc.Sheets.Item(i).PartsLists.Item(1)	
	Dim drawBomRow As DrawingBOMRow
	
	Dim partfiles() As String = System.IO.Directory.GetFiles(PartsFolder, "*.pdf")', IO.SearchOption.AllDirectories) 'AllDirectiories = Subfolders too
	If Not System.IO.Directory.Exists(PartsFolder) Or partfiles.Count = 0 Then
		MessageBox.Show("Either individual parts folder doesn't exist or it's empty", "Error")
	Exit Sub
	End If
	
	Dim weldmentfiles() As String = System.IO.Directory.GetFiles(WeldmentsFolder, "*.pdf")', IO.SearchOption.AllDirectories) 'AllDirectiories = Subfolders too
	If Not System.IO.Directory.Exists(PartsFolder) Or partfiles.Count = 0 Then
		MessageBox.Show("Either weldments folder doesn't exist or it's empty", "Error")
	Exit Sub
	End If	
	
	Dim iRowCount As Integer = 0
	For i = 1 To oPL.PartsListRows.Count	
		iRowCount = iRowCount + 1
		'Get Column "Part Number"
		oCell = oPL.PartsListRows.Item(i).Item("PART NUMBER")			
		Dim oPartNum As String = oCell.Value				
		MessageBox.Show("Line " & "(" & iRowCount & ")" & " PART NUMBER: " & oPartNum)
		'odrawBomRow = oPartListRow.ReferencedRows.Item(1)
		Dim ofound As Boolean = False
		For Each oFile In partfiles
			Dim oFileName As String = oFile
			If oFileName.Contains(oPartNum) Then
				ofound = True				
				Exit For			
			End If
		Next
		If ofound = True Then
			MessageBox.Show("Found PDF Drawing for Part: " & oPartNum)
		Else
			MessageBox.Show("No PDF Drawing for Part: " & oPartNum)
		End If
	Next
	
End Sub

Public Function FirstPL
	oDrawDoc = ThisApplication.ActiveDocument
	Dim oSheets As Inventor.Sheets = oDrawDoc.Sheets
	Dim iSheetNumber As Integer = 0
	oPL = Nothing
	
	For Each oSheet As Inventor.Sheet In oSheets
		Dim oPLs As PartsLists = oSheet.PartsLists
		If oPLs.Count = 0 Then
			Continue For
		Else
			iSheetNumber = CInt(oSheet.Name.Split(":").Last)
			'MsgBox(iSheetNumber)
			Exit For
		End If
	Next
	
	Return iSheetNumber
End Function

Public Function PartsFolder As String
	Dim pFolder As String = "C:\Inventor\Compile Testing\PDF Drawings - Individual Parts"
	Return pFolder
End Function

Public Function WeldmentsFolder As String
	Dim wFolder As String = "C:\Inventor\Compile Testing\PDF Drawings - Weldments"
	Return wFolder
End Function

End Class


 

 

0 Likes
Message 3 of 25

GosponZ
Collaborator
Collaborator

with 2 or more pdfs in folder run this rule. Change path C:\Workspace\PDF COLLECTION for your need. Rule is working perfect each time. It will end up in folder as .pdf and you rename for your spec.

 

0 Likes
Message 4 of 25

WCrihfield
Mentor
Mentor

Hi @emanuel.c.  I may be throwing a monkey wrench into your gears, but what about the idea of creating a new DrawingDocument, assigned to a high level variable, so that other routines can access it, then using a loop to open the other drawings, loop through their sheets and use Sheet.CopyTo(oCombinedDrawDoc) method to combine all sheets from all drawings into one huge drawing, then publish that drawing to a single, multi-page PDF?

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 5 of 25

emanuel.c
Collaborator
Collaborator

Hi @WCrihfield  Appreciate the input! Yes I thought about that, and actually began working that route. I just thought PDFs are so much easier and time saving to combine - I can literally combine hundreds of pages in seconds. Moreover I may have style clashes, which has happened before - copying sheets from drawings with different styles than the new drawing. Would you still think it's OK?

 

That itextsharp.dll works well in what it does but I wasn't able to edit it. Tried a few routes and maybe it's not open source and not meant to be edited. I wasn't sure if someone else had experience with it.

 

If I can't use it, I may have to export BOM to Excel and try using VB and some Acrobat plugins - which I don't have the Adobe Acrobat Pro at this point.

 

For reference, this particular assembly I'm working on has about 500 loose components and more than 100 weldments / sub assemblies. It the past we had all main subassemblies and their components under one DWG. As the project got larger, more and more subassemblies contain components of other subassemblies so we had to split drawings in assemblies and loose components. Now I need to compile them...

 

Thank you!

0 Likes
Message 6 of 25

emanuel.c
Collaborator
Collaborator

@WCrihfield   I would say most of the process is easy: opening drawings (or getting the info straight from the top level assembly), traversing parts list, making sure PDFs exits etc.

 

This itextsharp.dll takes all the PDF in a folder and combines them. But how could I tell it (I presume, in a For loop catching the PDF name) to combine only certain PDFs in a PDF and move on to the next? It would also be nice to be able to sort the sheets...

0 Likes
Message 7 of 25

emanuel.c
Collaborator
Collaborator

@GosponZ  Yes but I have this already. I would like to combine only certain PDFs in a folder.

0 Likes
Message 8 of 25

WCrihfield
Mentor
Mentor

If you can find a good code based process for combining the PDF files the way you want to, then that is definitely the way to go.  I was just throwing ideas out there.  I do not use either method myself.  We have always created separate drawing files for every part file, and separate drawing file just for the assembly, which only documents the assembly, with PartsList(s), but does not detail out all its components.  Then when we need to share drawings, we bundle the individual PDF files, and sometimes the individual STEP files into emails.  If there are a lot, we ZIP or compress them, then email (or otherwise 'share') the compressed files.  We have no need to actually combine a bunch of PDF's into one PDF.  Good luck with that.  I hope you get it figured out.  It seems like I have seen/used other small applications that had the ability to combine multiple PDF's into one, but I have not tried controlling any of them by code before.  I did attempt to dig into some of the API stuff for major PDF apps before, but it got more complicated than I wanted to get into at the time.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 9 of 25

WCrihfield
Mentor
Mentor

One rule I created a button for in my ribbon, within the Assembly environment for, is a rule that with one click will do the following:

Inspects the main assembly, and all referenced documents, checks if there is a drawing for them, if there is one, check for and get the PDF for the drawing.  If the drawing exists, but the PDF does not, create the PDF.  Put the PDF in a collection for later.  Make sure there is a STEP file for the model, and put the STEP file into a collection too, for later, then ask the user if they want to put attached all those files into a new email.  If yes, it creates a new email, and attaches all of them to it.  The email remains active when done, so you we can fill in the rest of the email, then send it.

Got to go for the day though.  Have a good weekend.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 10 of 25

emanuel.c
Collaborator
Collaborator

@WCrihfield  Thanks again for the input. It's very interesting to see how other companies do it. We don't share files via email, but rather through a server shared folder and send emails with links to the folders if necessary. There are smaller and larger projects that we work on.

 

For the smaller projects we usually have on one DWG (and then PDF and Excel BOM - for this I use some iLogic to automate, which I'm sure you had something to do with at some point or another 😊) the Assembly and all it's parts together. I usually draw them on my local computer and then back up the files to the server. From there, others in the process move them around from Pre-Production to Complete (can be fun for Inventor workflow...)

 

For the larger projects, the Assemblies and Weldments have their separate drawings and the loose parts all have their own drawings. The files remain in a shared folder on the server but the PDFs travel around...

 

It's very useful to combine drawings: Combining same thickness of material for the brake press, machining components for the machinist and assembly / weldments and their components for welders etc.

 

Thank you for looking into it. Have a nice weekend!

0 Likes
Message 11 of 25

yuzeaa
Advocate
Advocate

I'm trying to simplify the code for merging PDFs, so you can focus on getting the filelist of PDFs to be merged. I believe it would be better to add a bookmark to the PDF files based on the BOM level and I plan to work on adding this feature.

AddReference "iTextSharp.dll"
Sub Main()
'	doc = ThisDoc.Document
'	If Not TypeOf doc Is AssemblyDocument Then Return
		
'	Dim pdfFolders As New List(Of String) From _
'	{"C:\Inventor\Compile Testing\PDF Drawings - Individual Parts",
'	 "C:\Inventor\Compile Testing\PDF Drawings - Weldments"}
'	Dim filelist As New List(Of String)
	
'	For Each folder In pdfFolders
'		filelist.AddRange(System.IO.Directory.GetFiles(folder, "*.pdf"))
'	Next
	
'	Dim idwdocs As New List(Of Document)
	
'	For Each refdoc In doc.AllReferencedDocuments
'		idwname = Left(refdoc.FullDocumentName, Len(refdoc.FullDocumentName) -4) & ".idw"
'		If IO.File.Exists(idwname) Then
'            idwdocs.Add(refdoc)
'		End If 
'	Next
	
'    Dim MergePdfs = From item1 In filelist
'                    Where idwdocs.Any(Function(item2) item1.Contains(item2.PropertySets("Design Tracking Properties")("Part Number").Value))
'                    Select item1
'    outputPdfPath = "C:\temp\merged.pdf"
'	MergePDF(outputPdfPath,MergePdfs.ToList())
End Sub

Sub MergePDF(outputPdfPath As String,Filelist As List(Of String))
    doc = New iTextSharp.text.Document()
    stream = New System.IO.FileStream(outputPdfPath, System.IO.FileMode.Create)
    pdf = New iTextSharp.text.pdf.PdfCopy(doc, stream)
    doc.Open()
    For Each pdfFile In Filelist
		reader = New iTextSharp.text.pdf.PdfReader(pdfFile)
        For i = 0 To reader.NumberOfPages - 1
            page = pdf.GetImportedPage(reader, i + 1)
            pdf.AddPage(page)
        Next
        reader.Close()
    Next
    doc.Close()
End Sub

 

0 Likes
Message 12 of 25

A.Acheson
Mentor
Mentor

Hi @emanuel.c 

 

Here is the pdf file loop for the pdf merge code from that forum post.

    Private Function CreatePDF(ByVal sFolderPath) As String

        Dim bOutputfileAlreadyExists As Boolean = False
        Dim sOutFilePath As String = IO.Path.Combine(sFolderPath, _PDFName & ".pdf")

        'sdet up return for a successful pdf. ret changes to FALSE if any errors occur for qualifying purposes
        Dim ret As String = sOutFilePath

        If IO.File.Exists(sOutFilePath) Then
            Try
                IO.File.Delete(sOutFilePath)
            Catch ex As Exception
                bOutputfileAlreadyExists = True
            End Try
        End If

        Dim iPageCount As Integer = GetPageCount(sFolderPath)
        If iPageCount > 0 And bOutputfileAlreadyExists = False Then

            Dim oFiles As String() = IO.Directory.GetFiles(sFolderPath)
            Dim oPdfDoc As New iTextSharp.text.Document()
            Dim oPdfWriter As iTextSharp.text.pdf.PdfWriter = iTextSharp.text.pdf.PdfWriter.GetInstance(oPdfDoc, New IO.FileStream(sOutFilePath, IO.FileMode.Create))

            oPdfDoc.Open()

            System.Array.Sort(Of String)(oFiles)

            For i As Integer = 0 To oFiles.Length - 1
                Dim sFromFilePath As String = oFiles(i)
                Dim oFileInfo As New IO.FileInfo(sFromFilePath)
                Dim sFileType As String = "PDF"
                Dim sExt As String = PadExt(oFileInfo.Extension)

                Try
                    AddPdf(sFromFilePath, oPdfDoc, oPdfWriter)
                Catch ex As Exception
                    ret = "FALSE"
                End Try
            Next

            Try
                oPdfDoc.Close()
                oPdfWriter.Close()
            Catch ex As Exception

                Try
                    IO.File.Delete(sOutFilePath)
                Catch ex2 As Exception
                End Try
            End Try
        End If

        Dim oFolders As String() = IO.Directory.GetDirectories(sFolderPath)
        For i As Integer = 0 To oFolders.Length - 1
            Dim sChildFolder As String = oFolders(i)
            Dim iPos As Integer = sChildFolder.LastIndexOf("\")
            Dim sFolderName As String = sChildFolder.Substring(iPos + 1)
            CreatePDF(sChildFolder)
        Next

        Return ret

    End Function

For filtering the pdf by name this line here is your filepath reference so you will need some logic to filter the String. 

 Dim sFromFilePath As String = oFiles(i)
          

 

 

 

Here is the sub folder recursion loop, if you don't want that then remove from the code.

        Dim oFolders As String() = IO.Directory.GetDirectories(sFolderPath)
        For i As Integer = 0 To oFolders.Length - 1
            Dim sChildFolder As String = oFolders(i)
            Dim iPos As Integer = sChildFolder.LastIndexOf("\")
            Dim sFolderName As String = sChildFolder.Substring(iPos + 1)
            CreatePDF(sChildFolder)
        Next

 

If this solved a problem, please click (accept) as solution.‌‌‌‌
Or if this helped you, please, click (like)‌‌
Regards
Alan
0 Likes
Message 13 of 25

emanuel.c
Collaborator
Collaborator

Thank you @A.Acheson  and @yuzeaa   for the input!

My code is still in the making and I got to this point, though my coding knowledge is rather limited and sweating is rather significant 😊 As a note, I'm not reading parts list on a Drawing anymore but going straight from an Assembly model. I got down to where I have an array list of PDF document paths to be compiled (in the CompileWeldments Sub). I still need to sort the array and finish processing the Main Assembly, Sub Assemblies etc. But my main issue is compiling this list of PDFs for now. If you have time and desire and wish to help out I'm very grateful for the help.

 

 

'https://forums.autodesk.com/t5/inventor-programming-ilogic/merging-pdfs-using-ilogic/m-p/10645561#M129328
AddReference "C:\itextsharp.dll"
addreference "System.IO"
Sub Main()
	If ThisApplication.ActiveDocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then
		MessageBox.Show("Run this rule from an Assembly document!", "Error!")
		Exit Sub
	End If
	
	Dim oAsmCompDef As AssemblyComponentDefinition
	oAsmCompDef = ThisApplication.ActiveDocument.ComponentDefinition
	Dim oOccurrence As ComponentOccurrence
	
	For Each oOccurrence In oAsmCompDef.Occurrences
		If oOccurrence.Suppressed Then Continue For
		If TypeOf oOccurrence.Definition Is VirtualComponentDefinition Then Continue For
		If oOccurrence.Definition.Document.IsModifiable = False Then Continue For
		If oOccurrence.BOMStructure <> BOMStructureEnum.kNormalBOMStructure Then Continue For
		If oOccurrence.Definition.Type = ObjectTypeEnum.kWeldmentComponentDefinitionObject Or _
		oOccurrence.Definition.Type = ObjectTypeEnum.kAssemblyComponentDefinitionObject Then
			Dim oAsmPN As String = iProperties.Value(oOccurrence.Name, "Project", "Part Number")
			'MessageBox.Show(oAsmPN, "Assembly Part Number:")
			If Left(oAsmPN, 1) = "5" Then '5000s part numbers define a Weldment. SubType could be both Assm or Weldment
				'MessageBox.Show(oAsmPN, "Assembly Part Number:")
				CompileWeldments(oOccurrence, oAsmPN)				
			ElseIf Left(oAsmPN, 1) = "2" Then	 '2000s part number define an Assembly			
				'CompileAssemblies
			End If		
		End If
	Next

End Sub

Private Sub CompileWeldments(ByVal oOccurrence As ComponentOccurrence, oAsmPN As String)

	Dim oPDFlist As New ArrayList
	
	Dim oFiles() As String = System.IO.Directory.GetFiles(MainFolder, "*.pdf", System.IO.SearchOption.AllDirectories)
		For Each oFile In oFiles
			Dim oAsmPDF As String = oFile
			If oAsmPDF.Contains(oAsmPN) Then
				'Messagebox.show(oAsmPDF, "Assembly Path:")
				oPDFlist.Add(oAsmPDF)
				Exit For					
			End If
		Next
	
	'iterate through Assembly / Weldment components
	Dim oSubCompOcc As ComponentOccurrence		
	For Each oSubCompOcc In oOccurrence.SubOccurrences
		If (oSubCompOcc.ReferencedDocumentDescriptor Is Nothing) Then
			'avoid weld beads in Weldments
            'MessageBox.Show(oSubCompOcc.Name & " has no reference document")
            Continue For
        End If		
		
		If oSubCompOcc.Suppressed Then Continue For
		If TypeOf oSubCompOcc.Definition Is VirtualComponentDefinition Then Continue For
		If oSubCompOcc.Definition.Document.IsModifiable = False Then Continue For
		If oSubCompOcc.BOMStructure <> BOMStructureEnum.kNormalBOMStructure Then Continue For
			oPN = iProperties.Value(oSubCompOcc.Name, "Project", "Part Number")
			If Left(oPN, 1) = "7" Or Left (oPN, 1) = "8" Then 'get only part numbers 7000 and 8000
				'MessageBox.Show("Assembly: " & oAsmPN & vbCrLf & "Part: " & oPN, "Weldment and SubPart:")				
				For Each oFile In oFiles
					Dim oPartPDF As String = oFile
					If oPartPDF.Contains(oPN) Then
						'MessageBox.Show(oPartPDF, "Component Path:")
						oPDFlist.Add(oPartPDF)
						Exit For					
					End If
				Next
		End If
	Next
	
	For i As Integer = 0 To oPDFlist.Count - 1
	If i = 0 Then 
		oText = oPDFlist(i)
	Else
		oText = oText & vbLf & vbLf & oPDFlist(i)
	End If
	Next
	
	MessageBox.Show(oText)
	
	MergePDF(oPDFlist())
	
End Sub

Public Sub MergePDF(outputPdfPath As String, Filelist As List(Of String))
    
	doc = New iTextSharp.text.Document()
    stream = New System.IO.FileStream(outputPdfPath, System.IO.FileMode.Create)
    pdf = New iTextSharp.text.pdf.PdfCopy(doc, stream)
    doc.Open()
    For Each pdfFile In Filelist
		reader = New iTextSharp.text.pdf.PdfReader(pdfFile)
        For i = 0 To reader.NumberOfPages - 1
            page = pdf.GetImportedPage(reader, i + 1)
            pdf.AddPage(page)
        Next
        reader.Close()
    Next
    doc.Close()
End Sub

Public Function MainFolder As String
	Dim oFolder As String = "C:\Test"
	Return oFolder
End Function

Public Function CompiledFolder As String
	Dim oFolder As String = MainFolder & "\PDF Drawings - Compiled Drawings\"
	If Not System.IO.Directory.Exists(oFolder) Then
		MessageBox.Show("Target folder for compiled drawings doesn't exist yet", "Error")
		Dim oModelPane As BrowserPane = Nothing
		System.IO.Directory.CreateDirectory(oFolder)
	End If
	Return oFolder
End Function

 

 

0 Likes
Message 14 of 25

NachoShaw
Advisor
Advisor

Hey

 

the post you referred to was mine.

 

@emanuel.c wrote:

I started with code from this post here, using the itextsharp.dll. It works well, it compiles a PDF of all PDFs it finds it the given folder and does this for its subfolders also. This it does well, but I have a hard time editing this piece of code to suit what I need, for example even changing not to read from subfolders, to compile only certain files. But I  might have to dig in a bit deeper here.

 

This Piece of code is getting the sub folders.


 

Dim oFolders As String() = IO.Directory.GetDirectories(sFolderPath)
        For i As Integer = 0 To oFolders.Length - 1
            Dim sChildFolder As String = oFolders(i)
            Dim iPos As Integer = sChildFolder.LastIndexOf("\")
            Dim sFolderName As String = sChildFolder.Substring(iPos + 1)
            CreatePDF(sChildFolder)
        Next

 

to omit the sub folders, just use

CreatePDF(oFolderPath)

 

If you're looping through the partlist to check if theres a PDF, just move / copy the pdf found in the loop to a temp folder which will contain only PDFs matching your partlist then merge those PDFs into the single file. Once complete, delete the temp folder.

 

iTextSharp works on folder contents

 

let me know if you need some code help, this should work ok in iLogic as long as you have the reference

AddReference "C:\Users\Public\global references\itextsharp.dll"
AddReference "System.IO"

 

 

Thanks

Nacho
Automation & Design Engineer

Inventor automation Programmer (C#, VB.Net / iLogic)
Furniture, Sheet Metal, Structural, Metal fab, Tradeshow, Fabrication, CNC

EESignature


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.


Message 15 of 25

emanuel.c
Collaborator
Collaborator

Hi @NachoShaw  thanks for poppin in, I probably should have just tagged you 😉 Your code there works really well and hopefully I'll get it adapted to what I need here.

 

Thanks for answering my question! I was wondering if I could build the PDF from and array of files (file paths) or does itextsharp.dll  only take folders.  The Temp folder idea is wonderful! I can populate it, compile PDF, move it and empty it.

 

Thanks for your help so far!

0 Likes
Message 16 of 25

yuzeaa
Advocate
Advocate

If you want someone to help you write complete code, you must describe your requirements in great detail. Also, I found two errors.

20240123232912.png20240123232921.png

Message 17 of 25

emanuel.c
Collaborator
Collaborator

Yes, that for sure... But I apologize, my plans changed a bit as the project developed (don't know why I initially thought it was easier to go with reading Parts List from a Drawing...) though the scope is still the same: compile the PDFs. It didn't cross my mind to use a Temp folder  for compiling which Thank you @NachoShaw for the idea! I was stuck on not knowing how the isharptext was compiling. But since it does its thing (compile PDFs in a certain folder) very well, the Temp idea was amazing.

 

But indeed, my main question - compiling PDFs of Assemblies - has been answered.

Thank you all and the amazing forum for your help!!

 

Here is what I have if anyone else can use any of it.

If you wish to search for drawings first, you can use the attached rule - might have to adjust it here or there.

 

 

AddReference "M:\Autodesk Inventor\Ilogic\itextsharp\itextsharp.dll"
AddReference "System.IO"
Sub Main()
	
	If ThisApplication.ActiveDocumentType <> DocumentTypeEnum.kAssemblyDocumentObject Then
		MessageBox.Show("Run this rule from an Assembly document!", "Error!")
		Exit Sub
	End If
	
	Call CompiledFolder
	
	' Set reference to active document.
	Dim oDoc As Inventor.AssemblyDocument = ThisApplication.ActiveDocument
	
	Dim oSearchDrawings = MessageBox.Show("FIRST," & vbLf & vbLf _
		& "Do you need to verify all drawings exist?", "", MessageBoxButtons.YesNoCancel,
		MessageBoxIcon.Stop, MessageBoxDefaultButton.Button2)
	If oSearchDrawings = vbYes Then
		auto = iLogicVb.Automation			
		auto.RunExternalRule(oDoc, "C:\Find Missing Drawings")
	End If
	
	Dim question = MessageBox.Show("DRAWINGS folder:" & vbLf & DrawingsFolder _
		& vbLf & vbLf & "COMPILED folder:" & vbLf & CompiledFolder _
		& vbLf & vbLf & "Continue?", "Here are your folders:",
		MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
		
	If question = vbNo Then Exit Sub
	
	Dim oDocName As String = iProperties.Value(oDoc, "Project", "Part Number")
	
	' Get assembly component definition
	Dim oCompDef As Inventor.ComponentDefinition = oDoc.ComponentDefinition
	
	' Delete Temp folder to clear it
	If System.IO.Directory.Exists(TempFolder) Then
		IO.Directory.Delete(TempFolder, True)
	End If
	
	' Get all occurrences from component definition for Assembly document
	Dim oCompOcc As ComponentOccurrence
	Dim oSubAsmName As String
	For Each oCompOcc In oCompDef.Occurrences
		If oCompOcc.SubOccurrences.Count = 0 Then 'Skip Parts
		Else 'for subassemblies
			If oCompOcc.BOMStructure = BOMStructureEnum.kNormalBOMStructure Then
				oSubAsmName = iProperties.Value(oCompOcc.Name, "Project", "Part Number")
				'MessageBox.Show(oSubAsmName, "Sub-Assembly:")
				Call ProcessAllSubOcc(oCompOcc, oSubAsmName)
				Call PrepareDrawings(oCompOcc, oSubAsmName)
			Else
				Call ProcessAllSubOcc(oCompOcc, oSubAsmName)
			End If
		End If
	Next

	If oDoc.ComponentDefinition.BOMStructure = BOMStructureEnum.kNormalBOMStructure Then
		PrepareDrawings(oCompOcc, oDocName)
	End If
	
	MessageBox.Show("Completed Successfully", "", MessageBoxButtons.OK, MessageBoxIcon.Information)
		
End Sub

' Call Sub recursively to iterate through the entire assembly tree.
Private Sub ProcessAllSubOcc(ByVal oCompOcc As ComponentOccurrence, ByVal oSubAsmName As String)
    	
	Dim oSubName As String
	Dim oSubCompOcc As ComponentOccurrence
	For Each oSubCompOcc In oCompOcc.SubOccurrences
		If (oSubCompOcc.ReferencedDocumentDescriptor Is Nothing) Then
		'avoid weld beads in Weldments, for example
        'MessageBox.Show(oSubCompOcc.Name & " has no reference document")
        Continue For
        End If
		If oSubCompOcc.DefinitionDocumentType = kAssemblyDocumentObject Or _
			oSubCompOcc.DefinitionDocumentType = kWeldmentDocumentObject Then			
			oSubName = iProperties.Value(oSubCompOcc.Name, "Project", "Part Number")
			'MessageBox.Show(oSubName, "Sub-Assembly:")
			Call ProcessAllSubOcc(oSubCompOcc, oSubName)
			If oSubCompOcc.BOMStructure = BOMStructureEnum.kNormalBOMStructure Then		
				Call PrepareDrawings(oSubCompOcc, oSubName)
			End If
		End If
	Next

End Sub

Private Sub PrepareDrawings(ByVal oOccurrence As ComponentOccurrence, ByVal oAsmPN As String)
	
	'MessageBox.Show(oAsmPN, "Processing Drawings for Assembly:")	
	
	Dim oCFiles() As String = System.IO.Directory.GetFiles(CompiledFolder, "*.pdf", System.IO.SearchOption.AllDirectories)
	Dim oDFiles() As String = System.IO.Directory.GetFiles(DrawingsFolder, "*.pdf", System.IO.SearchOption.AllDirectories)
	
	Dim oFound As Boolean = False
	For Each oFile In oDFiles			
		If oFile.Contains(oAsmPN) Then
			oFound = True
			Exit For
		End If
	Next
		
	If oFound = False Then		
		'MessageBox.Show("Part Number:  " & oAsmPN & vbLf & vbLf & "Continuing", "Assembly Missing Drawings", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)			
		Exit Sub
	End If
	
	For Each oFile In oCFiles			
		If oFile.Contains(oAsmPN) Then Exit Sub
	Next	
	
	Dim oCompiledSubAsm As String	
	'iterate through Assembly / Weldment components
	Dim oSubCompOcc As ComponentOccurrence
	
	For Each oSubCompOcc In oOccurrence.SubOccurrences		
		'Avoid parts with following properties
		If oSubCompOcc.Suppressed Then Continue For
		If oSubCompOcc.Definition.Document.IsModifiable = False Then Continue For
		If TypeOf oSubCompOcc.Definition Is VirtualComponentDefinition Then Continue For
		If oSubCompOcc.BOMStructure <> BOMStructureEnum.kNormalBOMStructure Then Continue For
		If (oSubCompOcc.ReferencedDocumentDescriptor Is Nothing) Then
			'avoid weld beads in Weldments
            'MessageBox.Show(oSubCompOcc.Name & " has no reference document")
            Continue For
        End If
		
		'Get subcomponent Part Number
		oPN = iProperties.Value(oSubCompOcc.Name, "Project", "Part Number")				
		
		If oSubCompOcc.Definition.Type = ObjectTypeEnum.kPartComponentDefinitionObject Or _
			oSubCompOcc.Definition.Type = ObjectTypeEnum.kSheetMetalComponentDefinitionObject Then
			'for parts
			If Left(oPN, 1) = "7" Or Left(oPN, 1) = "8" Then 'get only part numbers 7000 and 8000		
				For Each pFile In oDFiles
					If pFile.Contains(oPN) Then
						'MessageBox.Show(pFile, "Component Path:")						
						oPartPDFname = Right(pFile, Len(pFile) - InStrRev(pFile, "\"))
						Dim oTempLocation As String = TempFolder & "\" & oPartPDFname
						'MessageBox.Show(oTempLocation, "Temp File Path: ")
						If Not IO.File.Exists(oTempLocation) Then
							FileCopy(pFile, oTempLocation)
						End If
						Exit For
					End If
				Next
			Else
			End If
		Else
			'for assemblies / weldments
			For Each pFile In oDFiles
				If pFile.Contains(oPN) Then
					'MessageBox.Show(pFile, "Component Path:")						
					oPartPDFname = Right(pFile, Len(pFile) - InStrRev(pFile, "\"))
					Dim oTempLocation As String = TempFolder & "\" & oPartPDFname
					'MessageBox.Show(oTempLocation, "Temp File Path: ")
					If Not IO.File.Exists(oTempLocation) Then
						FileCopy(pFile, oTempLocation)
					End If
					Exit For
				End If
			Next
		End If
	Next
	
	'Copy This Assembly's PDF to Temp Folder to be compiled
	Dim oAsmPDFname As String
	For Each oFile In oDFiles
		If oFile.Contains(oAsmPN) Then 'If any PDF file in folder contains Part Name of Assembly
			'MessageBox.Show(oFile, "Assembly Path:")
			oAsmPDFname = Right(oFile, Len(oFile) -InStrRev(oFile, "\"))
			'Define PDF Path for Temp Location
			Dim oTempLocation As String = TempFolder & "\" & oAsmPDFname
			'MessageBox.Show(oTempLocation, "Temp File Path: ")
			Dim oCompiledPdfName As String = CompiledFolder & "\Compiled - " & oAsmPDFname 
			'MessageBox.Show(oCompiledPdfName)
			If IO.File.Exists(oCompiledPdfName) Then Exit Sub 'Exit if already compiled
			If Not IO.File.Exists(oTempLocation) Then FileCopy(oFile, oTempLocation)
			Exit For					
		End If
	Next
	
	CreatePDF(oAsmPDFname)	
	
End Sub

Public Function DrawingsFolder As String
	Dim oFolder As String = "C:\Inventor\1 Bottle Washer\1 Drawings"
	Return oFolder
End Function

Public Function CompiledFolder As String
	'Define Location of Compiled folder
	'Must NOT be a subfolder of DrawingsFolder since code reads DrawingsFolder's subfolders too
	Dim oFolder As String = "C:\Inventor\1 Bottle Washer\2 Compiled Drawings"
	If Not System.IO.Directory.Exists(oFolder) Then
		Dim oModelPane As BrowserPane = Nothing
		System.IO.Directory.CreateDirectory(oFolder)
	End If
	Return oFolder
End Function

Public Function TempFolder
	Dim oTempfolder As String = DrawingsFolder & "\Temp"
	If Not System.IO.Directory.Exists(oTempfolder) Then
		Dim oModelPane As BrowserPane = Nothing
		System.IO.Directory.CreateDirectory(oTempfolder)
	End If
	Return oTempfolder	
End Function	

Private Function CreatePDF(oAsmPDFname As String) As String
	
	'Define Compiled PDF name
	Dim oCompiledPdfName As String = "Compiled - " & oAsmPDFname
	Dim bOutputfileAlreadyExists As Boolean = False
	Dim sTempFilePath As String = IO.Path.Combine(TempFolder, oCompiledPdfName)
	
	'Set up return for a successful pdf. ret changes to FALSE if any errors occur for qualifying purposes
	Dim ret As String = sTempFilePath
	
	If IO.File.Exists(sTempFilePath) Then
		Try
			IO.File.Delete(sTempFilePath)
		Catch ex As Exception
			bOutputfileAlreadyExists = True
		End Try
	End If
	
	If bOutputfileAlreadyExists = False Then
	
		Dim oFiles As String() = IO.Directory.GetFiles(TempFolder)
		Dim oPdfDoc As New iTextSharp.text.Document()
		Dim oPdfWriter As iTextSharp.text.pdf.PdfWriter = _
		iTextSharp.text.pdf.PdfWriter.GetInstance(oPdfDoc, New IO.FileStream(sTempFilePath, IO.FileMode.Create))
		
		oPdfDoc.Open()		
		System.Array.Sort(Of String)(oFiles)
		
		For i As Integer = 0 To oFiles.Length - 1
			Dim sFromFilePath As String = oFiles(i)
			Dim oFileInfo As New IO.FileInfo(sFromFilePath)
			Dim sFileType As String = "PDF"
			Dim sExt As String = PadExt(oFileInfo.Extension)
			
			Try
				AddPdf(sFromFilePath, oPdfDoc, oPdfWriter)
			Catch ex As Exception
				ret = "FALSE"
			End Try
		Next
		
		Try
			oPdfDoc.Close()
			oPdfWriter.Close()
		Catch ex As Exception		
			Try
				IO.File.Delete(sTempFilePath)
			Catch ex2 As Exception
			End Try
		End Try
	End If
	Dim oFolders As String() = IO.Directory.GetDirectories(TempFolder)
	For i As Integer = 0 To oFolders.Length - 1
		Dim sChildFolder As String = oFolders(i)
		Dim iPos As Integer = sChildFolder.LastIndexOf("\")
		Dim sFolderName As String = sChildFolder.Substring(iPos + 1)
		CreatePDF(oAsmPN)
	Next
	
	'move file to compiled folder
	Dim sCompiledFile As String = IO.Path.Combine(CompiledFolder, oCompiledPdfName)
	If Not IO.File.Exists(sCompiledFile) Then FileCopy(sTempFilePath, sCompiledFile)
	
	'Messagebox.Show(sCompiledFile, "Finished Compiling:")
	'delete Temp folder
	IO.Directory.Delete(TempFolder, True)
	
	Return ret	
End Function	
	
Private Sub AddPdf(ByVal sInFilePath As String, ByRef oPdfDoc As iTextSharp.text.Document, _
		ByRef oPdfWriter As iTextSharp.text.pdf.PdfWriter)
	
	Dim oDirectContent As iTextSharp.text.pdf.PdfContentByte = oPdfWriter.DirectContent
	Dim oPdfReader As iTextSharp.text.pdf.PdfReader = New iTextSharp.text.pdf.PdfReader(sInFilePath)
	Dim iNumberOfPages As Integer = oPdfReader.NumberOfPages
	Dim iPage As Integer = 0
	
	Do While (iPage < iNumberOfPages)
		iPage += 1
		oPdfDoc.SetPageSize(oPdfReader.GetPageSizeWithRotation(iPage))
		oPdfDoc.NewPage()
		
		Dim oPdfImportedPage As iTextSharp.text.pdf.PdfImportedPage = oPdfWriter.GetImportedPage(oPdfReader, iPage)
		Dim iRotation As Integer = oPdfReader.GetPageRotation(iPage)
		If (iRotation = 90) Or (iRotation = 270) Then
			oDirectContent.AddTemplate(oPdfImportedPage, 0, -1.0F, 1.0F, 0, 0, oPdfReader.GetPageSizeWithRotation(iPage).Height)
		Else
			oDirectContent.AddTemplate(oPdfImportedPage, 1.0F, 0, 0, 1.0F, 0, 0)
		End If
	Loop
	
End Sub
	
Private Function PadExt(ByVal s As String) As String
	s = UCase(s)
	If s.Length > 3 Then s = s.Substring(1, 3)
	Return s
End Function

 

 

 

 

 

0 Likes
Message 18 of 25

emanuel.c
Collaborator
Collaborator

What do these lines do? I thought I could get rid of that and just use CreatePDF(oAsmPN)

But it throws Inventor for a loop and eventually crashes...  

 

Dim oFolders As String() = IO.Directory.GetDirectories(TempFolder)
	For i As Integer = 0 To oFolders.Length - 1
		Dim sChildFolder As String = oFolders(i)
		Dim iPos As Integer = sChildFolder.LastIndexOf("\")
		Dim sFolderName As String = sChildFolder.Substring(iPos + 1)
		CreatePDF(oAsmPN)
	Next

 

0 Likes
Message 19 of 25

NachoShaw
Advisor
Advisor

Hey

 

Looks to me like you are assigning the part number of the occurrence

oSubName = iProperties.Value(oSubCompOcc.Name, "Project", "Part Number")

 Then passing that as the arg oAsmPN but what you actually need is a fully qualified path for the folder

CreatePDF(C:\SomePath\SomeFolder\)

 

 

 

Nacho
Automation & Design Engineer

Inventor automation Programmer (C#, VB.Net / iLogic)
Furniture, Sheet Metal, Structural, Metal fab, Tradeshow, Fabrication, CNC

EESignature


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.


Message 20 of 25

emanuel.c
Collaborator
Collaborator

Hi @NachoShaw or @A.Acheson or someone... I have a question if you would be able to help.

 

I have the code set to compile various PDF drawings as seen here: https://forums.autodesk.com/t5/inventor-programming-ilogic/compile-assembly-drawings/m-p/12807805 

 

I'm basically:

  • creating a bunch of folders named for subassemblies or manufacturing processes
  • dumping the required PDF drawings in respective folders
  • compiling all thoses folders into one PDF
  • copying that compiled PDF to a different folder (parent folder)
  • deleting the folder into which all them PDFs were originally dumped and ending up with a bunch of compiled PDFs

One of the options is to compile a PDF drawing of ALL the loose components of that project. There are no issues for 'smaller' assemblies (about 400 parts). But on an assembly with almost 500 parts it often crashes. If I restart Inventor and run it again it may or it may not compile. It gets to this folder with 500ish drawings and simply crashes. It tries to compile a PDF. There is a PDF with a correct name given and has a largish size but it is corrupt, I can't open it.

 

Is there 'something' in the itextsharp.dll that limits the size or I don't know, crashes because all the RAM is asked for. I have a feeling a lot of RAM is required (I have 64GB) and can see it in Task Manager but can't figure out why it crashes on the larger files. Doesn't crash on smaller assemblies.

 

Thanks a lot!

0 Likes