Creating PDF files in Visual Basic

Level:
Level2

PDF stands for portable document format. It is a format that every operating system on virtually any computer can read. Its become the default standard for transferring and viewing files in an easy way. The problem is that Visual Basic has no built in VB6 PDF functions. Because of this it has been very hard in the past to create PDF files from VB. Hopefully by the end of this Visual Basic Tutorial, PDF creation will be an easy thing for you to understand and do first hand.

PDF is a pretty complex data format. Because, of this usually you have to buy a third party control from someone who's invested a large amount of time in navigating through the PDF format and written an easy way for you to access it. This tutorial explains how you can create a simple PDF file without a third party control. If you run into limitations down the road you might still end up having to purchase a control. However, you will then know exactly what to look for in the control and know how much you are willing to spend to get the functionality you need. Hopefully you won't even need to purchase one. If there is something you are trying to do, add a comment here or in the forum, and we will try to help you with it. Also there is a followup to this tutorial: Creating Advanced PDF files using Visual Basic. It goes a lot more in depth into things like adding pictures, headers, page numbers and bookmarks.

The first thing you will need to do to follow this tutorial is to download the mjwPDF class and the PDF fonts. This class allows you to easily create PDF files and is what we will be using in this Visual Basic Tutorial. PDF creation is a snap once you've downloaded the class. Now copy the class and the fonts folder to the area where you have your project saved.

If you created a default project (Project1.vbp) and didn't change the name of the form it creates (From1.frm) your project folder should look like this once you've copied the mjwPDF class and the Fonts folder.

If this seems confusing, just download this VB PDF tutorial source code. It has everything zipped into one location for you to see how to set it all up.

Now that the fonts folder and mjwPDF class are in the right spot we need to add the mjwPDF class to our project:

  1. Select Project -> Add File from the menu bar (or hit ctrl-D)
  2. Select the mjwPDF class and click Open

Great. Now add a button to your form. Double click on it and add the following code to it:

Private Sub Command1_Click()
    ' Create a simple PDF file using the mjwPDF class
    Dim objPDF As New mjwPDF
    
    ' Set the PDF title and filename
    objPDF.PDFTitle = "Test PDF Document"
    objPDF.PDFFileName = App.Path & "\test.pdf"
    
    ' We must tell the class where the PDF fonts are located
    objPDF.PDFLoadAfm = App.Path & "\Fonts"
    
    ' View the PDF file after we create it
    objPDF.PDFView = True
    
    ' Begin our PDF document
    objPDF.PDFBeginDoc
        ' Set the font name, size, and style
        objPDF.PDFSetFont FONT_ARIAL, 15, FONT_BOLD
        
        ' Set the text color
        objPDF.PDFSetTextColor = vbBlue
        
        ' Set the text we want to print
        objPDF.PDFTextOut _
            "Hello, World! From mjwPDF (www.vb6.us)"
    
    ' End our PDF document (this will save it to the filename)
    objPDF.PDFEndDoc
End Sub

Lets walk through this code so we know what it does. I've added comments to explain each section. First we create the mjwPDF class object. We set a title for the PDF file. This will show up if someone looks at the file properties for this PDF document. Next set where the document will be saved. We are just saving it as test.pdf in the same folder as our program is. Next we tell it where the fonts folder is located. This is why we had to copy that folder to our running directory. The class uses this information to add those fonts to the file when they are needed.

The next line (line 13) is completly optional. By specifying true, our PDF document will be opened once we finish writing to it. Obviously on many applications you simply want to save the document and not show it to the user. If this is the case set this property to false.

Starting at line 16 we get into the meat of this Visual Basic tutorial. PDF file creation is a simple step by step process. First we decide what font we want. What size it is and if we want any special characteristics (like bold or italic). Next we set the color we want our text to be. Lastly we call the PDFTextOut to actually write the text to the PDF file. NOTE: I am saying write the text to the PDF file, but really its simply stored in a buffer until we call PDFEndDoc. We do this next and that is when all of the buffer is actually saved to the filename you specified in line 7. Also, since we set the PDFView property to true the PDF file is then opened for us automatically and we can see a simple file with our text added to it.

Download the VB PDF tutorial source code and have fun! Please leave comments below as to how well this worked for you. Also, I have written another tutorial: Visual Basic and Advanced PDF Documents. It goes a lot more in depth into how to add pictures, shapes, headers, hyperlinks, multiple pages, and page numbers.

Note: The original source code for this class (before modifications) can be found here.

If you enjoyed this post, subscribe for updates (it's free)

PDF is empty

When I run the program the test_pdf seems te be empty. When I open it in professional it gives a pop-up that is gone so fast you can't read it. In the reader it says "there was an error reading document 14" ??

It opens the document anyway but it seems to be empty and very small. So small that the reader starts with zoom on 4228%. If you change it to 100% the document is 0,5 x 0,5 cm.

Any idea what might be the problem?

Jan Henk

Figured it out. Just

Figured it out. Just added
objPDF.PDFFormatPage = FORMAT_A4
objPDF.PDFOrientation = ORIENT_PAYSAGE

and now it works...

Hi, it happens on my pdf

Hi, it happens on my pdf too.
It is a bug, I think.
I have fixed it adding some code like the "Advance Pdf Example":

objPDF.PDFSetLayoutMode = LAYOUT_DEFAULT

objPDF.PDFFormatPage = FORMAT_A4

objPDF.PDFOrientation = ORIENT_PORTRAIT

objPDF.PDFSetUnit = UNIT_PT

Bye

Problem w/sample pdf when using a different computer

I downloaded and ran the pdf file generator via VB6 and it worked fine.

I downloaded the same exact files, set it up exactly as before, on a different computer and the pdf is generated. However, I also get an error message via Adobe Reader that locks up the reader. A message box is displayed that says, "There was an error opening this document. This file cannot be found."

I've checked the path generated by the program, and it is the path in which the file is located. Again, if I attempt to locate the file, it is generated and located where the program puts it.

The error generated in Adobe locks up, and clicking on the 'okay' button on the message box does not close the program.

Help!

Hi, It could be that the

Hi, It could be that the file path name is too long.
You have to use a function that convert into Format Dos name of the flle path.

Read some post below.

Bye

Excellent class

... but there is one thing more which will satisfy all my needs.
How to join, two pages in one pdf file, where the first page
is just created by the code and the next page is from existing
pdf file. This second, existing file, can be single or multipage
and should be added as a second and next pages, to that which
is just creating.

regards , Martin

Hi, I tried your code, the

Hi,
I tried your code, the PDF file was created but wasn't shown automatically at the end.
Can you help me?
Thank you.

Fix, automatically open file

Probably the directory path name where the file .pdf is stored is too long. You have to use the DOS format name for the directory path.

example: Windows Path --> C:\Programmi
DOS Format --> C:\PROGRA~1

I had your same problem. I have examined the code of the pdf class.
In the sub PdfEndDoc, in the last code rows there's the function Shell.
It opens the Adobe program e the file pdf created.
You have to modify this row.

I have found this function :
Private Declare Function GetShortPathName Lib "KERNEL32" Alias "GetShortPathNameA" (ByVal lpszLongPath As String, ByVal lpszShortPath As String, ByVal cchBuffer As Long) As Long

You use it to convert the .pdf file name

Bye

A better way to open the file

Thanks Luca, but it still wouldn't display for me. Stepping through the code, I noticed that it wasn't finding Adobe Acrobat (I'm running Vista and have Adobe Acrobat Standard 8.0 installed). So, I decided to modify things a bit.

I inserted this API declaration into the mjwPDF class:

Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

And then replaced this in the PDFEndDoc() subroutine:

    If boPDFView Then
        PDFScanRepAdobe "C:\Program Files\", 0
        If wsPathAdobe <> "" Then
            iRet = Shell(wsPathAdobe & " " & PDFGetFileName, vbMaximizedFocus)
        End If
    End If

With this:

    If boPDFView Then
        iRet = ShellExecute(0, "open", PDFGetFileName, vbNullString, vbNullString, 3)
    End If

This results in the PDF file opening in the default application set up to open PDF files. You'll also notice that there is no need to use the short path name.

Great class,

Todd

Thanks

Thanks a lot for your update..... it was great.....

Thank you so much!!!

Thank you so much!!!

That's good! It's a better

That's good!
It's a better solution.

Bye

HELP ME PLEASE!?!?!

Let me start off by saying THANK YOU SO MUCH FOR THIS!

However, I need some help.
Can you resize the pdf page to a custom width and height?
I have a vb6 form with two text boxes and a command button.
When you press the command button, I want a pdf file to be created with the width of text1.text and the height of text2.text.
If you could show me how to do this it would be wonderful!
Thanks in advance!
You can e-mail me at:
leptictidium109@yahoo.com

nevermind, i figured it out

nevermind, i figured it out

Creating a PDF file of an html table

I have a simple html table consisting of 2 lines:-

HelloWorld
GoodbyeWorld

Can you tell me how to write this to a PDF file including simple grid lines.

thanks

Charles W

Generating multiple PDF files

If you have to generate multiple PDF files at one time, remember to call objPDF.PDFInit AFTER calling objPDF.PDFEndDoc, THEN call objPDF.PDFBeginDoc as usual - if you don't call PDFInit you'll wind up with a jumbled mess and run-time errors after the first PDF file because things aren't set up properly.

text box

Hi is there a way to print a text box with more than 1 line of text in it so that each line is 1,2,3 and not in a row

Thanks Joe K

PDFfiles with multiple text lines

Like most things in life, this is pretty easy if you know how - and frustrating if you don't!

Here's how to do it from a text file - generating it from a list box or multiline text box would be similar:

LineYPos = 1
LineCtr = 1
Open InputFile For Input As #1
While Not EOF(1)
    Line Input #1, StrIn
    If LineCtr > 85 Then ' adjust for the number of lines to print per page
        objPDF.PDFEndPage
        objPDF.PDFNewPage
        LineYPos = 1
        LineCtr = 1
    End If
    ' here's the magic
    objPDF.PDFTextOut StrIn, 1, LineYPos
    LineYPos = LineYPos + 0.33
    LineCtr = LineCtr + 1
Wend
Close #1

list box on vb gui to convert to pdf

Hi, I have a few check boxes that have string part number text associated with one another. They are pointed to print on the list box on the gui. I set up the pdf module and works great however dont know how to get the data to convert from the list box to the pdf. What command do I want to use? thx

Anyone? Please give an

Anyone? Please give an example.

You need to read through

You need to read through each list item and then print it to your PDF doc.

Re: converting text to PDF

The idea behind this is that you have to think of a PDF file as sheets of paper, where you have to specify exactly where on the page you want to place text and images.

The above code sample works for 9 pt. Courier. I could've made it more generic by figuring out the line spacing based on the font size, and that's pretty easy code to add, but I was under a very tight time constraint to generate PDF files from straight text files, and there were no graphics or complicated text formatting to consider - just convert text to straight PDF, quick and dirty. Headers and footers would be easy to add, too.

Add an image then test from a textfile to PDF using VB6

hello...thks for ur code....I want to print a logo of my company and then copy the contents of a specific text file to the PDF file.....Is it possible to do so..if so please reply ur post here...

Yes see the Advanced VB PDF

Yes see the Advanced VB PDF Tutorial. It shows how to do both of those things!

I'm using your application

I'm using your application (without any modification) and I've an error in: Set oRep = Fso.GetFolder(sPathBegin). What can I do to change it?

What exactly is the error

What exactly is the error and what line does it occur on. I will try to help you once I know the details.

Protecting / Securing the PDF

I think this is the fine work done and published to save the time. Also it helps the emerging programmers to understand the complex programming in the simple manner. Further, I think the pdf file creation is completed but the secure creation of the PDF File is still pending. I would expect that the author would come and give some idea of protecting the pdf file in this module itself. Also anybody who is familiar with the PDF Structure could also provide solution to protecting the PDF file at the time of creation itself.

Anyway a great work.

Modifying old PDF's

I have had a brief look at your code and are quite impressed with it. I must say i thought the days of freely sharing knowledge was over. I am glad to see there is still people out there like you. My problem is that i need to be able to open an existing pdf file, add pages to it, and overlay page numbers across the entire document. This is not a one of task, so i am trying to make the process fully automated in VB6. Further compounding my problem is the fact i work on a high security network that makes the installation of third party controls, etc impossible. Is it possible, or can it be possible, to open existing PDF's (even if protected) and overlay text on them with your class?

Unicode enabled?

Hi,

Before I try your pdf class I whould like to ask if any one tried these to ceate pdf files for arabic language with unicode fonts?

Thanks
ag

arabic language

Hi,

ceate pdf files for arabic language ?

Thanks
hany
.

mjwPDF Class error message

Hello, First may I say thank you for producing this very useful class. It has enabled me to create a PDF index document with hyperlinks to other graphical PDF documents created using a PDF printer driver. I have been trying to do this for some time without success until now!.
I do have one observation, when the PDF document is opened using Acrobat reader it actually pops up a brief dialogue box saying that the file is damaged and is being repaired, it then displays correctly. This also happens with your example programs but it disappears so quickly that it is not easy to spot it. It is more obvious when the file is opened using the full acrobat program. Here it always asks if I want to save the modified file when I try to exit or select a hyperlink even if I havn't made any changes. I assume the 'modification' is refering to whatever repair has been done by acrobat when opening the file. I have tried reducing the document down to the simplest possible but it still does the same. It is not a major issue on systems with only acrobat reader installed but causes some problems if the full acrobat is installed. If I do elect to save the 'changes' then the resulting file works correctly on the next opening.

Once again many thanks for the useful class.

Colin D U.K.

Interesting

Hmm, Interesting. I wonder why that is. I wonder if a header isn't getting set up correctly or something. If anyone finds a solution to the problem post it here. Maybe if you get a chance you could save a file with the program and then repair it and save it as a different name. Then email them to me. I can do a diff on them and see if I can figure things out. Please make sure its a very simple file so it is easy to see the difference. You can email it to admin@vb6.us. Thanks a lot for finding this.

PDF Class (rebuild dialog box)

Hi. I think your class is great. Any luck with supressing thr "rebuild" dialog box that pops up?

Other than that, the class is terrific

Error message...

Hello, I have already tried to do as you suggest but unfortunately acrobat seems to save the repaired file in a compressed format which makes direct comparison difficult. I haven't been able to get it to save in uncompressed format yet but I will have another try.... If I am succesfull I will send you the files. ..... Colin

Final fix?

Further to my last post the final problem with the advanced page seems to be the %DEBUT and %FIN debugging lines were being inserted inside the stream/endstream pairs causing errors. I have commented out all of the %DEBUT.. and %FIN... lines and the file now reads OK with no errors..... Colin

Problem Fixed. (Partially!)

Hi again... After analysing the output from your example code I found the problem was due to the offsets in the xref table being incorrect. Acrobat was obviously ignoring the table and rebuilding it correctly. The problem is that the use of Strm.WriteLine to create the output file adds CR LF each time it is used. These two characters were not being included in the offset calculations. Therefore every object entry in the xref table was out by 2 bytes per object. In a 20 object table the last object reference was out by 40 bytes. The demo app. only worked because Acrobat reader was correcting the errors almost silently.

I fixed this by chaging the line in the PDFAddToOffset routine to read:-

ObjectOffset = ObjectOffset + offset + 2

This caused the xref table to be correct but then Acrobat reader refused to open the file at all!. Further investigation showed that the /Pages object was corrupted with left over data from the previous object.
This was found to be due to a commented out line in PDFSetPages. The line:

TempStream = ""

was commented out. Re-instating this line produced a document that was read happily by both Acrobat and acrobat reader.

The basic Page created by the demo app now works OK.
The Advanged page loads and displays OK but reader says "There is an error in the document" and acrobat 5.0 says that "An unrecognised token 'endstream' was found" and "There were several parsing errors on this page"

I will continue to try to remove these remaining two errors.

....Colin

Speed Tip

This, although very cool, was initially very slow to generate PDF's with multiple cells. For what I was using it for it would take up to a minute and a half to produce 1 pdf, around 5 minutes to produce the whole lot that I needed. I hax0red out the line in the mjwPDF class (PDFCell function) that checks the string width:

l = l + PDFGetStringWidth(sCar, PDFFontName, PDFFontSize)

With this commented out I was able to spit out all the PDF's I required in 30seconds.. around 10x faster. I think it controls line wrapping, etc so wasn't needed for my PDF's as they're more tabular so it did not effect the format and presentation of the PDFs. The wrapping was pretty average anyway, (ie didn't work at all), but if I need it in future I will try and tweak it for speed and function and post up results.

Size is another drawback to this PDF generator, but I've got around this by making a DDE connection to Acrobat and printing the larger files as smaller files with the smallest file size selected. Using this I have seen file size reductions by an order of magnitude (ie 600kb going to 54kb). Although this takes longer, the time I have saved from the above modification is more than enough to allow for this additional file generation.

End of the day though this class (with the tweaks) is brilliant and beats other commercial PDF generation software I've tried. Using the above methods it spits out my PDF's around 8x faster and half the size of most of the commercial applications. Many thanks!

Thank You

Thank you so much for contributing back to the vb6.us community please send me an email and let me know who you are. Again thank you for the speed improvement tips. Keep it up!

admin@vb6.us

I've always used this PDF

I've always used this PDF Creator

Keith
www.martin2k.co.uk/forums/

I've been programming with VB for 14 years. Started with VB4 16bit Pro, VB5 Pro, VB6 Pro/Enterprise and now VB3 Pro. But I'm no expert, I'm still learnin

Hard Coded Routine

Private Function PDFScanRepAdobe is hard coded to open the PDF File with Adobe Acrobat Reader. Any one using other reader will not be able to open file created automatically. I suggest to make following changes.

Add the following

Private Declare Function ShellExecute Lib "shell32.dll" Alias _
"ShellExecuteA" (ByVal hwnd As Long, ByVal lpszOp As _
String, ByVal lpszFile As String, ByVal lpszParams As String, _
ByVal lpszDir As String, ByVal FsShowCmd As Long) As Long

Const SW_SHOWNORMAL = 1
Const SE_ERR_FNF = 2&
Const SE_ERR_PNF = 3&
Const SE_ERR_ACCESSDENIED = 5&
Const SE_ERR_OOM = 8&
Const SE_ERR_DLLNOTFOUND = 32&
Const SE_ERR_SHARE = 26&
Const SE_ERR_ASSOCINCOMPLETE = 27&
Const SE_ERR_DDETIMEOUT = 28&
Const SE_ERR_DDEFAIL = 29&
Const SE_ERR_DDEBUSY = 30&
Const SE_ERR_NOASSOC = 31&
Const ERROR_BAD_FORMAT = 11&

Private Sub DisplayError(lngResult as Long)
Dim msg As String
If lngResult <= 32 Then
'There was an error
Select Case lngErrorNumber
Case SE_ERR_FNF
msg = "File not found"
Case SE_ERR_PNF
msg = "Path not found"
Case SE_ERR_ACCESSDENIED
msg = "Access denied"
Case SE_ERR_OOM
msg = "Out of memory"
Case SE_ERR_DLLNOTFOUND
msg = "DLL not found"
Case SE_ERR_SHARE
msg = "A sharing violation occurred"
Case SE_ERR_ASSOCINCOMPLETE
msg = "Incomplete or invalid file association"
Case SE_ERR_DDETIMEOUT
msg = "DDE Time out"
Case SE_ERR_DDEFAIL
msg = "DDE transaction failed"
Case SE_ERR_DDEBUSY
msg = "DDE busy"
Case SE_ERR_NOASSOC
msg = "No association for file extension"
Case ERROR_BAD_FORMAT
msg = "Invalid EXE file or error in EXE image"
Case Else
msg = "Unknown error"
End Select
MsgBox msg
End If
End Sub

Remove Following from General Declarations

Private wsPathAdobe As String
Private bScanAdobe As String

Remove Following Function as it is used to open PDF only through Adobe Acrobat Reader

PDFScanRepAdobe()

Remove following from Public Sub PDFInit()

bscanAdobe=False

Remove following Lines from Public Sub PDFEndDoc()

PDFScanRepAdobe “C:\Program Files\”,0
If wsPathAdobe <> “” Then
Endif

Replace iRet=Shell(wsPathAdobe & “ “ & PDFGetFileName, vbMaximizedFocus) with
iRet=ShellExecute(0,”open”,PDFGetFileName,””,0,SW_SHOWNORMAL) and add following line
Call DisplayError(iRet)

Its really very cool, but many correction and addition are still needed.

Hitesh Patel

multiple lines of text

Hi
your cls is cool..

I face problem when trying to modify the code by repeating the objPDF.PDFTextOut to pdf multiple lines of text
but the output pdf file only display 1 line..... is that the correct way to do it? pls help . thanks

objPDF.PDFTextOut " Line1 Hello, World! From mjwPDF (www.vb6.us)"
objPDF.PDFTextOut " Line2 Hello, World! From mjwPDF (www.vb6.us)"
objPDF.PDFTextOut " Line3 Hello, World! From mjwPDF (www.vb6.us)"

To get Coordinates of the text

hello,
I need one thing by this class......

i.e. I need to get Coordinates (x,y) where the last text was printed....or drawn...

Plz help me out....

PDF Class

Hi!
I have a question, seems to me that you can only choose a font and color for the entire document. I tried to change the font by doing:

        objPDF.PDFSetFont FONT_COURIER, 12, FONT_UNDERLINE
 
        objPDF.PDFSetTextColor = vbRed
 
        objPDF.PDFTextOut "this is a test."
 
        objPDF.PDFSetFont FONT_ARIAL, 15, FONT_BOLD
        objPDF.PDFSetTextColor = vbGreen
        objPDF.PDFTextOut vbCrLf & " And now I'm green!"

And instead of 2 lines, it only created the first one.
Also it seems to be kind of slow (about 40 seconds) to create a one-lined document.

Anyway, good job and thanks for this great site!

Another thing, I'm trying to access the second tutorial but it gives me Access Denied.

Cheers!
RB

Check it out!

Hi RB, Sorry about that, the second tutorial should help answer your question. It is now fully online so go check it out!

Will do!

Will do!
Thanks! :o)
RB

pdf class

are there any more instructions for using the more advanced features of this class
i picked up 2 errors in the class when running the sample project
thanks for the code

pete

Thanks

Thanks for the update on the errors - I got those fixed. I am also in the process of adding instructions for using the more advanced features of the class. I should have another tutorial up with in a day. Is there something in particular you are trying to do? I might be able to cater a tutorial towards it.

Its Done!

I've created a new tutorial that goes much more in depth on how to create more complex PDF documents. The tutorial explains how to add multiple pages with page numbers. How to add images, hyperlinks, headers, and shapes. Check it out: Advanced PDF creation using VB6.

Advanced PDF creation using VB6

Exellent Job.
Know how do I modify your code to convert a word document or plain text file to a PDF document file .

Thanks
BB