Exporting Drawings to .pdf Files Using NX Journal

Sharing engineering drawings is important, using a format the recipient can open is vital. This program is designed to take a drawing and automate it into a .pdf file using NX Journal.

Journal Capabilities:

  • Journal automates the drawing to a .pdf file.
  • The journal will automatically iterate through all the sheets in a drawing and convert them into a multi-page single .pdf file.
  • The new file will be output as the form [partname].pdf.
  • The journal has the ability to browse for the output folder rather than exporting to same folder as original file.

Journal Requirements:

  • Assumes Journal is starting in the drafting application.

 

NX Journal: Converting a Drawing into a .pdf File

 

Option Strict Off
Imports System
Imports System.IO
Imports System.Collections
Imports System.Windows.Forms
Imports System.Windows.Forms.MessageBox
Imports NXOpen
Imports NXOpen.UF
 
Module NXJournal
 
Dim theSession As Session = Session.GetSession()
Dim workPart As Part = theSession.Parts.Work
Dim displayPart As Part = theSession.Parts.Display
 
'**********************************************************
 
Sub Main
 
Dim dwgs As Drawings.DrawingSheetCollection
dwgs = workPart.DrawingSheets
Dim sheet As Drawings.DrawingSheet
Dim i As Integer
Dim pdfFile As String
Dim currentPath As String
Dim currentFile As String
Dim exportFile As String
Dim partUnits As Integer
Dim strOutputFolder As String
Dim strRevision As String
Dim rspFileExists
Dim rspAdvancePrint
 
'determine if we are running under TC or native
Dim IsTcEng As Boolean = False
Dim UFSes As UFSession = UFSession.GetUFSession()
UFSes.UF.IsUgmanagerActive(IsTcEng)
 
partUnits = displayPart.PartUnits
'0 = inch
'1 = metric
 
If IsTcEng Then
   currentFile = workPart.GetStringAttribute("DB_PART_NO")
   strRevision = workPart.GetStringAttribute("DB_PART_REV")
 
Else 'running in native mode
   'currentFile = GetFilePath() & GetFileName() & ".prt"
   currentPath = GetFilePath()
   currentFile = GetFileName()
 
   Try
       strRevision = workPart.GetStringAttribute("REVISION")
       strRevision = Trim(strRevision)
   Catch ex As Exception
       strRevision = ""
   End Try
End If
exportFile = currentFile
 
strOutputFolder = OutputPath()
'if we don't have a valid directory (ie the user pressed 'cancel') exit the journal
If Not Directory.Exists(strOutputFolder) Then
   Exit Sub
End If
strOutputFolder = strOutputFolder & "\"
 
rspAdvancePrint = MessageBox.Show("Add advance print watermark?", "Add Watermark?", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
 
Dim shts As New ArrayList()
For Each sheet in dwgs
shts.Add(sheet.Name)
Next
shts.Sort()
 
i = 0
Dim sht As String
For Each sht in shts
 
   For Each sheet in dwgs
       If sheet.name = sht Then
           i = i + 1
 
           If rspAdvancePrint = vbyes Then
               pdfFile = strOutputFolder & exportFile & "_advance" & ".pdf"
           Else
               If strRevision <> "" Then
                   pdfFile = strOutputFolder & exportFile & "_" & strRevision & ".pdf"
               Else
                   pdfFile = strOutputFolder & exportFile & ".pdf"
               End If
           End If
 
           'the pdf export uses 'append file', if we are on sheet 1 make sure the user wants to overwrite
           'if the drawing is multisheet, don't ask on subsequent sheets
           If i = 1 Then
               If File.Exists(pdfFile) Then
                   rspFileExists = msgbox("The file: '" & pdfFile & "' already exists; overwrite?", vbyesno + vbquestion)
                   If rspFileExists = vbYes Then
                       Try
                           File.Delete(pdfFile)
                       Catch ex As Exception
                           msgbox(ex.message & vbcrlf & "Journal exiting", vbcritical + vbokonly, "Error")
                           Exit Sub
                       End Try
                   Else
                       'msgbox("journal exiting", vbokonly)
                       Exit Sub
                   End If
               End If
           End If
 
           'update any views that are out of date
           theSession.Parts.Work.DraftingViews.UpdateViews(Drawings.DraftingViewCollection.ViewUpdateOption.OutOfDate, sheet)
 
           Try
               ExportPDF(sheet, pdfFile, partUnits, rspAdvancePrint)
           Catch ex As exception
               msgbox("Error occurred in PDF export" & vbcrlf & ex.message & vbcrlf & "journal exiting", vbcritical + vbokonly, "Error")
               Exit Sub
           End Try
           Exit For
       End If
   Next
 
Next
 
   If i = 0 Then
       MessageBox.Show("This part has no drawing sheets to export", "PDF export failure", MessageBoxButtons.ok, MessageBoxIcon.Warning)
   Else
       MessageBox.Show("Exported: " & i & " sheet(s) to pdf file" & vbcrlf & pdfFile, "PDF export success", MessageBoxButtons.ok, MessageBoxIcon.Information)
   End If
 
End Sub
'**********************************************************
 
Function GetFileName()
   Dim strPath As String
   Dim strPart As String
   Dim pos As Integer
 
   'get the full file path
   strPath = displayPart.fullpath
   'get the part file name
   pos = InStrRev(strPath, "\")
   strPart = Mid(strPath, pos + 1)
 
   strPath = Left(strPath, pos)
   'strip off the ".prt" extension
   strPart = Left(strPart, Len(strPart) - 4)
 
   GetFileName = strPart
End Function
'**********************************************************
 
Function GetFilePath()
   Dim strPath As String
   Dim strPart As String
   Dim pos As Integer
 
   'get the full file path
   strPath = displayPart.fullpath
   'get the part file name
   pos = InStrRev(strPath, "\")
   strPart = Mid(strPath, pos + 1)
 
   strPath = Left(strPath, pos)
   'strip off the ".prt" extension
   strPart = Left(strPart, Len(strPart) - 4)
 
   GetFilePath = strPath
End Function
'**********************************************************
 
Function OutputPath()
'Requires:
'    Imports System.IO
'    Imports System.Windows.Forms
'if the user presses OK on the dialog box, the chosen path is returned
'if the user presses cancel on the dialog box, 0 is returned
 
Dim strLastPath As String
Dim strOutputPath As String
 
'Key will show up in HKEY_CURRENT_USER\Software\VB and VBA Program Settings
Try
  'Get the last path used from the registry
  strLastPath = GetSetting("NX journal", "Export pdf", "ExportPath")
  'msgbox("Last Path: " & strLastPath)
  Catch e As ArgumentException
  Catch e As Exception
  msgbox (e.GetType.ToString)
  Finally
End Try
 
Dim FolderBrowserDialog1 As New FolderBrowserDialog
 
' Then use the following code to create the Dialog window
' Change the .SelectedPath property to the default location
With FolderBrowserDialog1
    ' Desktop is the root folder in the dialog.
    .RootFolder = Environment.SpecialFolder.Desktop
    ' Select the D:\home directory on entry.
   If Directory.Exists(strLastPath) Then
       .SelectedPath = strLastPath
   Else
       .SelectedPath = "D:\home"
   End If
    ' Prompt the user with a custom message.
    .Description = "Select the directory to export .pdf file"
    If .ShowDialog = DialogResult.OK Then
       ' Display the selected folder if the user clicked on the OK button.
       OutputPath = .SelectedPath
       ' save the output folder path in the registry for use on next run
       SaveSetting("NX journal", "Export pdf", "ExportPath", .SelectedPath)
   Else
       'user pressed 'cancel', exit the subroutine
       OutputPath = 0
       'exit sub
    End If
End With
 
End Function
'**********************************************************
 
Sub ExportPDF(dwg As Drawings.DrawingSheet, outputFile As String, units As Integer, advancePrint As Integer)
 
   Dim printPDFBuilder1 As PrintPDFBuilder
 
   printPDFBuilder1 = workPart.PlotManager.CreatePrintPdfbuilder()
   printPDFBuilder1.Scale = 1.0
   printPDFBuilder1.Action = PrintPDFBuilder.ActionOption.Native
   printPDFBuilder1.Colors = PrintPDFBuilder.Color.BlackOnWhite
   printPDFBuilder1.Size = PrintPDFBuilder.SizeOption.ScaleFactor
   If units = 0 Then
       printPDFBuilder1.Units = PrintPDFBuilder.UnitsOption.English
   Else
       printPDFBuilder1.Units = PrintPDFBuilder.UnitsOption.Metric
   End If
   printPDFBuilder1.XDimension = dwg.height
   printPDFBuilder1.YDimension = dwg.length
   printPDFBuilder1.OutputText = PrintPDFBuilder.OutputTextOption.Polylines
   printPDFBuilder1.RasterImages = True
   printPDFBuilder1.ImageResolution = PrintPDFBuilder.ImageResolutionOption.Medium
   printPDFBuilder1.Append = True
   If advancePrint = vbyes Then
       printPDFBuilder1.AddWatermark = True
       printPDFBuilder1.Watermark = "ADVANCE PRINT NOT TO BE USED FOR PRODUCTION " & Today
   Else
       printPDFBuilder1.AddWatermark = False
       printPDFBuilder1.Watermark = ""
   End If
 
   Dim sheets1(0) As NXObject
   Dim drawingSheet1 As Drawings.DrawingSheet = CType(dwg, Drawings.DrawingSheet)
 
   sheets1(0) = drawingSheet1
   printPDFBuilder1.SourceBuilder.SetSheets(sheets1)
 
   printPDFBuilder1.Filename = outputFile
 
   Dim nXObject1 As NXObject
   nXObject1 = printPDFBuilder1.Commit()
 
   printPDFBuilder1.Destroy()
 
End Sub
'**********************************************************
 
End Module

Comments

I have modified your change attibute assembly journal with great success.  I now would like to use that again only this time instead of walking though and modifying an attribute, I would like it to create any drawings that exist.
The roadblock I'm at is as follows: I am struggling with how to make your recursion actually change the work AND displayed part to effectively access the drawings.
What would be the code to actually make a child component become the work part?
Using the journal recorder and modifying it has only helped me get so far.

nes386,
I sent an email to the address you supplied. It contains code to walk through an assembly and set each part as the display part in turn.
 
Let me know how it goes!

Hi,

can you please send the code for me also?

Stay Hungry
Stay Foolish

I'll take that code as well if it's available.

Thanks,

Singsonite

Hi!
It would be great to have this code :)
Would you please be so kind to send it to my email-address?
Thanks a lot!

Below is the code referenced in a previous post. I'd like to point out that it isn't necessary to change the display part to output the drawing sheets to a pdf file.

'Journal to recursively walk through the assembly structure
' will run on assemblies or piece parts
' will step through all components of the displayed part
'NX 7.5, native
'NXJournaling.com February 24, 2012
 
Option Strict Off
 
Imports System
Imports NXOpen
Imports NXOpen.UF
Imports NXOpen.Assemblies
 
Module NXJournal
 
    Public theSession As Session = Session.GetSession()
    Dim workPart As Part = theSession.Parts.Work
    Dim displayPart As Part = theSession.Parts.Display
    Dim startWorkPart As Part = theSession.Parts.Work
    Dim startDispPart As Part = theSession.Parts.Display
 
    Public ufs As UFSession = UFSession.GetUFSession()
    Public lw As ListingWindow = theSession.ListingWindow
 
    Sub Main()
        Dim startWorkPart As Part = theSession.Parts.Work
        Dim startDispPart As Part = theSession.Parts.Display
 
        lw.Open()
        Try
            Dim c As ComponentAssembly = displayPart.ComponentAssembly
            'to process the work part rather than the display part,
            '  comment the previous line and uncomment the following line
            'Dim c As ComponentAssembly = workPart.ComponentAssembly
            If Not IsNothing(c.RootComponent) Then
                '*** insert code to process 'root component' (assembly file)
                lw.WriteLine("Assembly: " & c.RootComponent.DisplayName)
                lw.WriteLine(" + Active Arrangement: " & c.ActiveArrangement.Name)
                '*** end of code to process root component
                ReportComponentChildren(c.RootComponent, 0)
            Else
                '*** insert code to process piece part
                lw.WriteLine("Part has no components")
            End If
        Catch e As Exception
            theSession.ListingWindow.WriteLine("Failed: " & e.ToString)
        End Try
        lw.Close()
 
    End Sub
 
    '**********************************************************
    Sub reportComponentChildren(ByVal comp As Component, _
        ByVal indent As Integer)
 
        'change displayed part to comp
        ChangeDisplayPart(comp)
        MsgBox("Displayed part is now: " & comp.Prototype.OwningPart.FullPath)
        'add code to process displayed part
        '
        '
        'change display part back to the display part when journal started
        ChangeDisplayPart(startDispPart)
 
 
        For Each child As Component In comp.GetChildren()
            '*** insert code to process component or subassembly
            lw.WriteLine(New String(" ", indent * 2) & child.DisplayName())
            '*** end of code to process component or subassembly
            If child.GetChildren.Length <> 0 Then
                '*** this is a subassembly, add code specific to subassemblies
                lw.WriteLine(New String(" ", indent * 2) & _
                    "* subassembly with " & _
                    child.GetChildren.Length & " components")
                lw.WriteLine(New String(" ", indent * 2) & _
                    " + Active Arrangement: " & _
                    child.OwningPart.ComponentAssembly.ActiveArrangement.Name)
                '*** end of code to process subassembly
            Else
                'this component has no children (it is a leaf node)
                'add any code specific to bottom level components
            End If
            reportComponentChildren(child, indent + 1)
        Next
    End Sub
 
    Public Sub ChangeDisplayPart(ByVal comp As Component)
 
        'make the given component the display part
        Dim markId1 As Session.UndoMarkId
        markId1 = theSession.SetUndoMark(Session.MarkVisibility.Invisible, "Display Part")
 
        Dim compPart As Part = comp.Prototype.OwningPart
        Try
            Dim partLoadStatus1 As PartLoadStatus
            Dim status1 As PartCollection.SdpsStatus
            status1 = theSession.Parts.SetDisplay(compPart, False, False, partLoadStatus1)
 
            workPart = theSession.Parts.Work
            displayPart = theSession.Parts.Display
            partLoadStatus1.Dispose()
        Catch ex As Exception
            lw.WriteLine("error opening part: " & compPart.FullPath)
            lw.WriteLine(ex.Message)
            theSession.UndoToMark(markId1, "Display Part")
        Finally
            theSession.DeleteUndoMark(markId1, "Display Part")
        End Try
 
    End Sub
 
    Public Sub ChangeDisplayPart(ByVal myPart As Part)
 
        'make the given component the display part
        Dim markId1 As Session.UndoMarkId
        markId1 = theSession.SetUndoMark(Session.MarkVisibility.Invisible, "Display Part")
 
        Try
            Dim partLoadStatus1 As PartLoadStatus
            Dim status1 As PartCollection.SdpsStatus
            status1 = theSession.Parts.SetDisplay(myPart, False, False, partLoadStatus1)
 
            workPart = theSession.Parts.Work
            displayPart = theSession.Parts.Display
            partLoadStatus1.Dispose()
        Catch ex As Exception
            lw.WriteLine("error opening part: " & myPart.FullPath)
            lw.WriteLine(ex.Message)
            theSession.UndoToMark(markId1, "Display Part")
        Finally
            theSession.DeleteUndoMark(markId1, "Display Part")
        End Try
 
    End Sub
    '**********************************************************
    Public Function GetUnloadOption(ByVal dummy As String) As Integer
        Return Session.LibraryUnloadOption.Immediately
    End Function
    '**********************************************************
 
End Module

We needed the really same program: to be able to to create a pdf walking through every sheets of a drawing.
That works great. Many thanks for your work !

Hello,
this Journal is working fine without any giving error in TC
in native it is create PDF excellent, but in TC it will not create PDF
just export file outside to giving path.
not create PDF it just a file without bytes, what its done only giving name of file
please solve this problem
I am using NX 8.5 with TC 10

Hi I tried to use export_pdf_from_folder.vb
but I get the error "Part Scan Error: File already exists"
Can you help me understand why I get the error. A fix would be even better.

If the journal finds an existing pdf in the output directory, it will attempt to delete it before exporting the current drawing to pdf. That error message is likely to occur if the attempt to delete the file is unsuccessful. A pdf file may not be able to be deleted if you do not have proper permissions on the file and/or folder that contains it. Also, if the file is currently being used by another process, the OS may not allow you to delete it. If the file is currently open, you may run into this situation. Bear in mind that if the files are saved on a network location, any user with the proper permissions may have the file open.

Thanks so much for the site and look at this.
I have full access to the folders. I tried add a counter and say counter01 = counter01 + 1
And then _outputPdfFile = _outputPdfFile & Count001 & ".pdf" so each pdf would have a unique name.
But I have trouble dim the counter01. I'm not very good with Public Property and Private funtions

Are we talking about the example code that comes in the pdf exporter zip file?

If not, please post the code that you are using or provide a link to it.

Hi

It's possible to have this Journal for NX9/NX10 & Tc10.1? Thanks in advanced.

The code referenced above has an option to export a PDF to TC, but it does not work as well as I would like. It will not update/overwrite an existing PDF in the dataset.

The code should work for NX 9 and 10. Did you encounter an error when running the code?

i created a new empty macro and copied the whole journal after the header into it. Nothing happend. Either in managed or nativ environment. I suppose my way doing is wrong?

ups, i'm sorry. Ill try to do an journal not an macro! Sorry for that mistake!

i tried it out. It works well in the native mode. It also overwrite an existing pdf. If i run the journal in a managed environment nx9 & tc10.1 it ask always for the save location.

Yes, I'm happy with how it works with native NX. My previous comments were about TC only. It prompts for a save location because the code you ran exports the PDF to the file system. The option for exporting to a dataset has been disabled until I can do further testing.

Any progress on getting this to export a PDF dataset to the item revision in Teamcenter? I'm trying to develop a one-click solution to export a PDF dataset of all drawing sheets and replacing any existing dataset. Right now I'm attempting to combine the sheet loop you used in this journal with the journal recorded when using the File, Export, PDF command in NX.

I now have access to TC, but I'm up to my eyeballs in data migration and trouble shooting. I don't know when/if I'll be able to get back to this journal code; please keep us updated on any progress that you make.

Instead of it finding each sheet contained in a file, how would I set it up to do just the active sheet?

The following line starts the loop to process all the sheets in the drawing:

For Each sheet in dwgs

You will need to remove the loop and instead only process the active sheet.

What's the syntax for calling the active sheet? Ctype is always what the journal creates and that's not going to work.

{part reference}.DrawingSheets.CurrentDrawingSheet

Hi,
Its working very well for individual drawings,
but how to make it to run through all open drawings. and export them to selected location.
??????

-[]-

http://nxjournaling.com/content/pdf-exporter-class

If you look at the "usage examples" section of the article, you will find a link to download the code. I'd suggest starting with the "export_pdf_test_min.vb" journal and looking to see how "Sub Main" exports a pdf based on the work part (it's only about 10 lines of code). Don't worry about the class code, you won't need to change it or even understand how it works; focus on Sub Main and study how it creates an "NXJ_PdfExporter" object and uses it to create the pdf.

Once you understand that, modify Sub Main to iterate through the open prt files in theSession.Parts, creating a pdf from each.

Hi,

Thanks for link.... Tried to edit but no luck.....:(

-[]-

Please post what you have tried and we'll go from there.

I'm Not getting how to add loaded parts to edit......so I have Zero to post

-[]-

Below is one way to do it.

Note: to run this as a journal, you will need to combine the code below with the class code from the PDF exporter article.

Option Strict Off
Imports System
Imports System.IO
Imports System.Collections.Generic
Imports System.Windows.Forms
Imports NXOpen
Imports NXOpen.UF
 
Module All_parts_in_session
 
    Sub Main()
 
        Dim theSession As Session = Session.GetSession
 
        If IsNothing(theSession.Parts.Display) Then
            MessageBox.Show("Active Part Required", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Return
        End If
 
        Dim workPart As Part = theSession.Parts.Work
        Dim displayPart As Part = theSession.Parts.Display
 
        For Each tempPart As Part In theSession.Parts
 
            Dim partLoadStatus1 As PartLoadStatus
            Dim status1 As PartCollection.SdpsStatus
            status1 = theSession.Parts.SetDisplay(tempPart, False, False, partLoadStatus1)
 
            workPart = theSession.Parts.Work
            displayPart = theSession.Parts.Display
            partLoadStatus1.Dispose()
 
            Dim myPdfExporter As New NXJ_PdfExporter
            myPdfExporter.Part = displayPart
 
            '$ show confirmation dialog box on completion
            myPdfExporter.ShowConfirmationDialog = True
 
            Try
                myPdfExporter.Commit()
            Catch ex As Exception
                MessageBox.Show("Error:" & ControlChars.CrLf & ex.GetType.ToString & " : " & ex.Message, "PDF export error", MessageBoxButtons.OK, MessageBoxIcon.Error)
 
            Finally
                myPdfExporter = Nothing
            End Try
 
        Next
 
    End Sub
 
End Module

ohhh......there is a small problem,
I had a weldment assembly consisting 46 parts,
and some other 6 parts loaded in session,
but only 7 (1 asm+6 parts) drawings open in window,
when tried to test given code.....its running through all the loaded parts,
I mean 46+6.....which took a long time to complete......is it possible to make it run only for open files instead of loaded files???

-[]-

An open file is a loaded file.

I guess there might be a difference.....
Let's take example of an assembly
If I opened an assembly consisting X number of Components
Assembly I'll be considered as opened part, and remaining all X number of components might be loaded. even window menu also shows only opened parts unless you go to more option....
If I'm wrong please suggest.....

-[]-

It appears that NX keeps track of "explicitly opened" vs. "implicitly opened" parts. However, either the function to differentiate between the two has not been made available in the API, or I simply overlooked it.

If you find it, please let us know.

It makes sense now......Thank you....
Sure I'll post as soon I get the solution....

-[]-

Hi
Can i have one code that runs through the complete assembly and export all the drawings available as pdf/tiff file.
Please mail me @ s.dinesh134@gmail.com

It ended up being a lot simpler than I thought. The key is to set the sheets to export as an array of all sheets using this line:
printPDFBuilder1.SourceBuilder.SetSheets(workpart.DrawingSheets.ToArray)

Imports System
Imports NXOpen
 
Module NXJournal
Sub Main (ByVal args() As String) 
 
Dim theSession As NXOpen.Session = NXOpen.Session.GetSession()
Dim workPart As NXOpen.Part = theSession.Parts.Work
 
Dim displayPart As NXOpen.Part = theSession.Parts.Display
 
Dim printPDFBuilder1 As NXOpen.PrintPDFBuilder = Nothing
printPDFBuilder1 = workPart.PlotManager.CreatePrintPdfbuilder()
 
'Get part number attribute (drawing must be work part)
Dim partnumber = workPart.GetUserAttribute("DB_PART_NO", NXObject.AttributeType.String, -1)
Dim partnumberstring = partnumber.StringValue
 
'Parameters
printPDFBuilder1.Relation = NXOpen.PrintPDFBuilder.RelationOption.Manifestation
 
printPDFBuilder1.DatasetType = "PDF"
 
printPDFBuilder1.NamedReferenceType = "PDF_Reference"
 
printPDFBuilder1.Scale = 1.0
 
printPDFBuilder1.Colors = NXOpen.PrintPDFBuilder.Color.BlackOnWhite
 
printPDFBuilder1.Size = NXOpen.PrintPDFBuilder.SizeOption.ScaleFactor
 
printPDFBuilder1.Units = NXOpen.PrintPDFBuilder.UnitsOption.English
 
printPDFBuilder1.RasterImages = True
 
printPDFBuilder1.ImageResolution = NXOpen.PrintPDFBuilder.ImageResolutionOption.Medium
 
printPDFBuilder1.Assign()
 
'Set sheets to an array of all drawing sheets
printPDFBuilder1.SourceBuilder.SetSheets(workpart.DrawingSheets.ToArray)
 
'Get part number attribute (drawing must be work part) and set as string
Dim partnumber = workPart.GetUserAttribute("DB_PART_NO", NXObject.AttributeType.String, -1)
Dim partnumberstring = partnumber.StringValue
 
'Assign Dataset name as part number
printPDFBuilder1.DatasetName = partnumberstring
 
Dim nXObject1 As NXOpen.NXObject = Nothing
nXObject1 = printPDFBuilder1.Commit()
 
printPDFBuilder1.Destroy()
 
End Sub
End Module

Sorry, meant to post this as a reply to the relevant comment above...