11 Mar 2009
Acrobat, JavaScript and VB walk into a bar…
Update:
Please visit the same post on my business site. The comments are closed here, so if you want to comment, you have to head over to http://khkonsulting.com/2009/03/acrobat-javascript-and-vb-walk-into-a-bar/
OK, let’s just forget about that old joke and concentrate on how to combine all three into something that is quite useful.
As I’ve described in one of my previous posting, it is quite easy to automate Acrobat from VB or VBA. So how does JavaScript fit into this picture? As you may know, Acrobat comes with a very powerful JavaScript engine that provides access to a lot of functionality – more functions actually than what you have access to from your VB program. So, if you want to access some of these features, but you are stuck with VB, how can you do that?
Adobe provides a VB/JavaScript bridge with Acrobat – the JSObject, and the Acrobat SDK describes how to use that feature.
There is quite a bit of good information in the documentation. When you access the online documentation, expand the tree to “Acrobat Interapplication Communication > Developing Applications Using Interapplication Communication > Using OLE > Using the JSObject interface”.
JavaScript
In this example, I want to illustrate how you can create a folder level JavaScript function, instantiate the JSObject, and then call the custom function and display the result in VB. My plan was to use the JavaScript code from my last posting, but I found one small problem in the way I wrote the code (it works fine as a standalone JavaScript program, but we cannot use it in the VB context), so here is it’s replacement:
function CountBookmarks(bkm, nLevel) { var count = 0; if (bkm.children != null) { count = bkm.children.length; for (var i = 0; i < bkm.children.length; i++) { count += CountBookmarks(bkm.children[i], nLevel + 1); } } return count; } function CountAllBookmarks() { console.clear(); console.show(); var n = CountBookmarks(this.bookmarkRoot, 0); console.println("Number of bookmarks found: " + n); return n; } // add the menu item app.addMenuItem({ cName: "countBookmarks", cUser: "Count Bookmarks", cParent: "Document", cExec: "CountAllBookmarks();", cEnable: "event.rc = (event.target != null);" });
Save this JavaScript program as a folder level JavaScript file and make sure that it works.
So, why can’t we just implement the whole algorithm with the JSObject? The problem is with how VB handles objects that are actually JavaScript objects – in this case the root bookmark object. I cannot figure out how to access it’s “children” property through the JSObject. That’s the reason why I’m “cheating” by calling our custom JavaScript function – being able to do that is pretty cool IMHO.
The VB Part
We start out just like with any other VB program, by declaring some objects, initializing them and then it gets interesting…
Here is some sample code that shows how to initialize the JSObject, and how to call our own JavaScript function.
Create a button on an Excel spreadsheet again, and put the following code into the button handler callback (just like before).
Dim gApp As Acrobat.CAcroApp Dim gPDDoc As Acrobat.CAcroPDDoc Dim jso As Object Sub Button1_Click() Set gApp = CreateObject("AcroExch.App") Set gPDDoc = CreateObject("AcroExch.PDDoc") If gPDDoc.Open("c:\temp\test.pdf") Then Set jso = gPDDoc.GetJSObject MsgBox (jso.CountAllBookmarks()) End If End Sub
Now just make sure that you have a file c:\temp\test.pdf that has some bookmarks in it.
khk, I have been looking for how to do this for aa numbe rof hours this last week or so. your posting was really helpful. I tried your code / example… on my windows XP machine its falls over when I step inot the open first pdf line: Part1Document.Open (“C:tempPart1.pdf”)..
excel closes and the system wants to send a message to microosft.
any ideas whats wrong?
the type library is acrobat 8 on my system.
I checked in the register and AcroExch.PDDoc was there.
Paul
pab
April 2nd, 2009 at 6:11 ampermalink
Thanks very much fot the info on Acrobat, JavaScript and VB. How would one go about to do the same with Photoshop, Javascript and VB?
I have created a VB6 app to copy photo files from mem cards and would like to extend it to include running Javascrips fot Photoshop.
Thanks.
Regards.
Ernst
June 4th, 2009 at 6:35 ampermalink
Ernst,
you can find information about Photoshop scripting here: http://www.adobe.com/devnet/photoshop/scripting/ and a tutorial for example here http://www.kirupa.com/motiongraphics/ps_scripting.htm
What exactly are you trying to accomplish with a Photoshop script?
khk
June 4th, 2009 at 6:59 ampermalink
Ah, now I’m getting it, you are asking if Photoshop also has a VB/JavaScript bridge… As far as I know, it does not support the same functionality. You can run JavaScripts via the DoJavaScript and DoJavaScriptFile functions, but it’s not bridged like in Acrobat. Does that help?
khk
June 4th, 2009 at 7:24 ampermalink
Kindly tell me where to store that given java script Please ..
shankyee
December 2nd, 2010 at 8:22 ampermalink
Take a look at a blog post I wrote yesterday: http://khkonsulting.com/2010/12/acrobat-javascripts-where-do-they-go/
It will give you a tool to find out where you should store the script.
khk
December 2nd, 2010 at 8:57 ampermalink
Dear friend actually I have a java script & I want to call it on various pdf files. Java script having some function with parameters. Please help me..
shankyee
December 3rd, 2010 at 1:17 ampermalink
Hi Karl,
I have two newbie questions for you. First of all, how do I test the js in Acrobat? I did save it in the right folder, but I can’t seem to view the script (let alone execute it) from within Acrobat. I have ver. 9 Pro Extended. “Edit All Javascripts” doesn’t bring it up.
Second, the VBA code chokes on the line
MsgBox (jso.CountAllBookmarks())
The javascript I copied from your site I pasted into a text editor and renamed CountAllBookmarks.js. It’s stored in the right folder, but maybe I didn’t name it correctly.
Thanks very much for any help. Also, thank you very much for your posting on combining PDF files from Excel. It was simple and quick. There is a lot of information out there on Javascript and Acrobat and bridges, but most of it starts with a lengthy history and overview, and it’s too time-consuming for amateurs to wade through. Yours was perfect.
Meg
June 24th, 2011 at 12:22 pmpermalink
CreateObject(“AcroExch.App”)
acr=CreateObject(“AFormAut.App”)
? acr.fields.count
what=acr.fields(“c.1”).value
what=acr.fields(“C.1”).value
this code works in Foxpro calling the api and I can use all the properties like textfont etc
But I cannot after hours figure out how to get the name of a field
like I would think the following should work but it doesn’t
what=acr.fields(1).name
anyway to get a field name with vba???
Craig Lytle
July 9th, 2011 at 9:57 ampermalink
here is working foxpro code to show all fields – you kind of have to use the loop
public what, whtn, formapp
cr=chr(13)+chr(10)
FormApp = CreateObject(“AFormAut.App”)
what=’ ‘
i=1
For Each Field In FormApp.Fields
? field.name + ‘ ‘+field.value
* you don’t need the rest of this except the endfor but it shows what you can do
whf=field.name
chrl= formapp.fields(“&whf”).charlimit
whtn=field.name
if !left(whtn,1)=’C’
*and len(alltrim(field.value))>1
i=val(substr(whtn,at(‘.’,whtn)+1,3))
*i=str(substr(whtn,at(‘.’,whtn)+1,3))
*sm(i)=field.value
*substr(whtn,at(‘.’,whtn)+1,3)
what=what+substr(whtn,at(‘.’,whtn)+1)+’ ‘+field.value+str(chrl,2)+cr
endif
if i=30 or i=60 or i=90 or i=120
wait
endif
i=i+1
endfor
return
Craig Lytle
August 29th, 2011 at 9:00 ampermalink
Meg this was for u and if ur using a field named C.1 ur probably using CEB Jud forms. If so you can easily do all of it with foxpro
like
public what, whtn
FormApp = CreateObject(“AFormAut.App”)
what=’ ‘
i=1
For Each Field In FormApp.Fields
? field.name + ‘ ‘+field.value
whtn=field.name
if substr(whtn,1,1)’C’
i=val(substr(whtn,at(‘.’,whtn)+1,3))
if !empty(sm(i))
field.value=sm(i)
field.textfont=”Times-Bold”
endif
if i=30 or i=60 or i=90 or i=120
wait
endif
endif
i=i+1
endfor
return
obvious sm is an array but you could use a dbf instead
these forms use C.? as the header with case info and then the form name like fl120.?? as the rest of the fields
Craig Lytle
August 29th, 2011 at 9:08 ampermalink
Hi,
I havé a question for you. Is it possible to include actions in a pdf, Such as file open … Without using a javasript? I nées to do That in a pdf files Without usiing javasripts functionality.
Tanks.
Christian
July 2nd, 2013 at 4:31 pmpermalink
Sorry, but for actions, you need JavaScript, there is no way around it.
khk
July 2nd, 2013 at 7:26 pmpermalink
Thanks for your blogs like: http://www.khk.net/wordpress/2009/03/11/acrobat-javascript-and-vb-walk-into-a-bar/
Have you tried JScript in VBA?
e.g.
‘http://www.mcpher.com/Home/excelquirks/snippets/scriptcontrol
‘ Note: you’ll need to add a reference to Microsoft Script Control v1.0 in Tools > References
Public Sub x()
Dim o As New ScriptControl
o.Language = “JScript”
With o
.AddCode “function x(a,b) {return ‘the answer is:’ +(a+b);}”
Debug.Print .Run(“x”, 1, 2)
End With
End Sub
Kenneth Hobson
July 25th, 2013 at 4:34 pmpermalink
Kenneth,
JScript in VBA does not help you with the Acrobat JavaScript implementation – you would be using a completely different interpreter, and would not have access to the Acrobat domain specific extensions to JavaScript that Adobe provides.
khk
July 27th, 2013 at 4:50 pmpermalink
I have used this code for merging and adding text to PDF files. I have upgraded to Adobe Acrobat XI Pro, the script no longer works. Do you know a fix for this.
Thanks
vickie
June 28th, 2014 at 12:40 pmpermalink
Do you have any examples of using .getlinks method in VBA to retrive the list of links for a page in a PDF? The follwoing code snipet is what I attempted to do, however I get a run time error (object required) at the Set arrynks = jos.getLinks(.. ) statement below. Any ideas?
Dim AcroApp As Acrobat.CAcroApp
Dim Part1Document As Acrobat.CAcroPDDoc
Dim jso As Object
Dim numPages, numLinks As Integer
Dim arraylnks() As Object
Dim rect(0 To 3) As Integer
Dim retval As Integer
Set AcroApp = CreateObject(“AcroExch.App”)
Set Part1Document = CreateObject(“AcroExch.PDDoc”)
retval = Part1Document.Open(NewName)
Set jso = Part1Document.GetJSObject
rect(0) = 0
rect(1) = 792
rect(2) = 614
rect(3) = 0
Set arraylnks = jso.getLinks(0, rect)
numLinks = arraylnks.Length
Larry
August 25th, 2015 at 6:55 ampermalink
Larry, unfortunately I don’t have any sample code, and I’ve never used the getLinks() method myself from VB/VBA, so I also don’t have any guidance in how to get around this error. Sorry.
khk
August 26th, 2015 at 12:48 pmpermalink