I want to convert a specified color page to gray programmatically using `PDDocColorConvertPage` with Dot Gain 15% as I would do it in Acrobat 9 Pro manually. In the API reference the syntax is explained but I don't understand it, especially `PDColorConvertParams`.
Is there anyone who can post a short example of code?
I'm trying to achieve this via COM-programming and Python. An example in VB, JavaScript or similar is also great.
Thanks in advance!
PDDocColorConvertPage and PDColorConvertParams are C/C++ methods and data structures – you can get to them from COM or Python.
In order to convert the page from COM/Python, you will need to use the JavaScript method for color conversion. Details in the docs.
FYI: Acrobat can't be used on a server….
I'm not the big C/C++ geek and always have difficulties finding the right parts in the docs. So can you post a link where exactly this is described?
Sorry, but I don't understand the mix between COM/Python and JavaScript... isn't it possible to use the `PDDocColorConvertPage` API call directly via COM? Also important for where to find this in the docs.
In the past I wrote some programs using COM to control Acrobat, e.g. to rotate, delete or insert pages. So I know all the basic stuff. I think I'm just looking for about 5-10 lines of code doing the right API call syntax. If somebody can help out with a short example this would really help me to go on. Thanks in advance.
The Acrobat SDK consists of different parts:
- plug-in and PDF library API - these are functions you can call from
C/C++, but only within a plug-in or an application that uses the PDFL. The
API function yo are trying to use is part of this interface and not
available via COM.
- Inter Application Commuication (IAC) interface - these are e.g. COM
methods that you can call from your Python program
- JavaScript - an API to automate Acrobat with JavaScript programs that are
either embedded in PDF files, or stored on your computer.
In general, you cannot cross API boundaries, but there is a way to execute
JavaScript in an application that uses the COM interface. Take a look at
the documentation that is part of the SDK, this is all documented, and
there are sample programs that come with the SDK. You will however not find
any Python programs in the SDK - you need to map the use of the COM
interface from VB to Python.
Here is a link to a blog post I wrote a few years ago about how to use
JavaScript from within a VB program:
http://www.khk.net/wordpress/2009/03/11/acrobat-javascript-and-vb-walk -into-a-bar/
Karl Heinz Kremer
PDF Acrobatics Without a Net
Hi Karl Heinz, I tried your scripts but didn't get them working... :-(
First, I wrote a simple JavaScript as you did and saved it to `C:\Program Files (x86)\Adobe\Acrobat 9.0\Acrobat\Javascripts\GrayConversion.js`:
function GrayConversion() {
var message = "The magic happens here...";
console.clear();
console.show();
console.println(message);
return message;
}
// add the menu item
app.addMenuItem({
cName: "grayConversion",
cUser: "Gray Conversion",
cParent: "Document",
cExec: "GrayConversion();",
cEnable: "event.rc = (event.target != null);"
});
When I restart Acrobat there's no new menu item. I also checked the tick box as you described here. As I'm using the German Acrobat, I also tried `cParent: "Dokument",`. Can you figure out what is wrong with it? Is there any name convention for the .js file? Does Acrobat automatically "scan" the Javascripts-folder and "includes" all of them?
Are you still sure that it's not possible to use the `PDDocColorConvertPage`via COM? I don't understand why some parts work and others won't. Is the API some kind of incomplete?
The other thing is also interesting that you said: do you think it's possible to call that API by an application using PDFL?
I did something similar to what you are describing with InDesign some years ago :-) So I appreciate for any tips and hints... I don't see the mistake.
I don't have a Windows version of Acrobat 9 handy, I was only able to test
with Acrobat X, and the menu item does show up (after changing "Document"
to "File" because AX does not have a Document menu anymore).
The "Document" name is a language independent name, so you have to use
that even with the German version of Acrobat. Are you sure that your path
is correct? You can easily test that by running a JavaScript command (take
a look at this blog post:
http://khkonsulting.com/2010/12/acrobat-javascripts-where-do-they-go/ )
Acrobat will automatically load anything that has a .js extension if it's
stored in either the user or the application level JavaScript directory.
The different APIs are not compatible with each other - you can only call
JavaScript methods from within JavaScript (with the exception of using the
JS bridge), you can call COM methods only when using COM, and you can call
the Acrobat/PDFL functions only when writing an Acrobat plug-in or a PDFL
based program. You could write your own COM server in form of a plug-in,
and make other functions available via a COM interface, but the standard
IAC API does not provide anything besides what is documented in the SDK IAC
documentation.
If you have a license for the PDFL, then you can certainly call this
function (and any of the other functions that are part of the Acrobat/PDFL
API) from your own application.
Karl Heinz Kremer
PDF Acrobatics Without a Net
Aaah, it was probably a permission problem because of Windows' UAC (user account control), so adding menu items via JavaScript was not allowed. I first tried to set this feature as a non-admin user using the `runas` command. But after logging on as the admin user showed that Adobe still did not allow JavaScript to add menu items...
Now, when using `Document` and after opening a PDF file in Acrobat (as admin user) the new command is visible as a menu item and it works.
First step done :-) Thanks! Also, app.getPath("app", "javascript"); shows that my JavaScript path is correct.
Now I have to find out how to convert a color page to gray using 15% dot gain. I found some code snippets doing color conversion with profiles... not the same but the right direction. I'll give it a try and still appreciate any useful ideas to achieve this :-)
This is really hard for me because I'm missing a full explanation/documentation of the `PDDocColorConvertPage` API, especially `PDColorConvertParams`.
[Edit:] Huh, my Python 2.6 script tells me this when calling `jso.GrayConversion()`:
com_error: (-2147467263, 'Nicht implementiert', None, None)
Meaning: "not implemented". Seems like it cannot find the JavaScript function `GrayConversion()`?
Everything seems to be fine until `GetJSObject()`. Here's my code:
import sys
import os
import win32com.client
def main():
App = win32com.client.Dispatch("AcroExch.App")PDDoc = win32com.client.Dispatch("AcroExch.PDDoc")
PDDoc.Open("file.pdf")
jso = PDDoc.GetJSObject()
print jso.GrayConversion()
if __name__ == "__main__":
main()
Sorry, Karl Heinz, but I don't get it... even after 6 days of searching and trying. It's a big strain ![]()
My status right now is that I'm using VB script because Python's COM binding do something strange... with VB script the COM-JS-connection works fine.
I found this link that seems to be very useful and very close to what I need
it's about the AcroColor extended API:
But I cannot "transform" it into JavaScript...
Pleeeeeeaaaaase, are you able to transform this into JavaScript code for me and post it here? I visited your homepage and it seems that you could do it because you have the experience and you understand what's going on in Acrobat. I'd really appreciate!
Also: is it possible just to replace `AC_Profile_AppleRGB` with `AC_Profile_DotGain15`? See the reference here.
You are, STILL, trying to use the C++ APIs from JavaScript.
You want the JavaScript API at http://livedocs.adobe.com/acrobat_sdk/9.1/Acrobat9_1_HTMLHelp/wwhelp/w whimpl/js/html/wwhelp.htm?href=JS_API_AcroJS.88.1.html#1515776&accessi ble=true
Look at the doc.colorConvertPage() API.
Just because you find a function somewhere in the Acrobat SDK documentation
does not mean you can use it in your program: As I said before, you cannot
cross API boundaries, if you have a function that is described in the
plug-in API, you can only use it in an Acrobat plug-in (or in most cased,
in an application that uses the PDFL). You need to stick to the API that
your application can use (e.g. as lrosenth pointed out, a function from the
JavaScript API when you try to either write a JavaScript program, or if you
want to use the JS bridge).
This is not a question of the level of experience somebody has, it's just
not possible to do that.
Karl Heinz Kremer
PDF Acrobatics Without a Net
I have a situation slightly different but similar enough in nature not to require a new thread. While I'm using Acrobat X on Win7, I think most everything I'm doing remains consistent in Acrobat 9, and it may help shed some common light.
In my case, I am trying to call "colorConvertPage" (the Javascript API version Iorsenth recommends, above, and not the "PDDocColorConvertPage" exposed by the C++ API) from a VBscript via the JSObject. My problem is that I cannot figure out how to correctly configure and pass the two arrays of "colorConvertAction" objects that the JavaScript method requires as its second and third parameters.
The purpose of the script is to merge large numbers of TIFFs into multiple PDFs, combining them based on a filename schema. After each document is created, I want the script to convert all of the page images to sRGB before saving.
I have been able to implement Mr. Kremer's method of creating a native Acrobat folder-level JavaScript to perform the color conversion and then calling that from the VBscript. The Javascript is taken almost verbatim from the example given under the "getColorConvertAction" method in the Acrobat X JavaScript API Reference, only changing the profile to sRGB and then adding the loop through all the pages and a slight modification of Karl's code to add the function as a menu item under Edit:
function ConvertAllTosRGB()
{
// Get a color convert action
var toRGB = this.getColorConvertAction();
// Set up the action for a conversion to RGB
toRGB.matchAttributesAny = -1;
toRGB.matchSpaceTypeAny = ~toRGB.constants.spaceFlags.AlternateSpace;
toRGB.matchIntent = toRGB.constants.renderingIntents.Any;
toRGB.convertProfile = "sRGB IEC61966-2.1";
toRGB.convertIntent = toRGB.constants.renderingIntents.Document;
toRGB.embed = true;
toRGB.preserveBlack = false;
toRGB.useBlackPointCompensation = true;
toRGB.action = toRGB.constants.actions.Convert;
// Convert the first each page of the document
for(var i = 0; i < this.numPages; i++) {
var result = this.colorConvertPage(i,[toRGB],[]);
}
}
// add the menu item
app.addMenuItem({
cName: "ConvertAllTosRGB",
cUser: "Convert Doc To sRGB",
cParent: "Edit",
cExec: "ConvertAllTosRGB();",
cEnable: "event.rc = (event.target != null);"
});
Once that .js is dropped into one of Acrobat's script folders, the function can be successfully called from vbs with "jso..ConvertAllTosRGB" (where "jso" is a JSObject successfully created by a call to a PDDoc's .GetJSObject method.)
Where I'm running into trouble is in trying to replicate that JavaScript function within the VBscript itself (which would be more convenient than having to distribute two separate scripts.) I can successfully create a colorConvertAction object, however I can't seem to successfully cast that object as one in an array to pass to colorConvertPage (nor create the empty array to pass as the third parameter.) The pertinent portions of the scipt are something like...
Dim AcroApp
Dim AVDoc
Dim PDDoc
Dim jso
Dim toRGB
Dim i
Dim result
Set AcroApp = CreateObject("AcroExch.App")
Set AVDoc = CreateObject("AcroExch.AVDoc")
If AVDoc.Open("c:\path\some.tif"), "") Then
Set PDDoc = AVDoc.GetPDDoc
Set jso = PDDoc.GetJSObject
Set toRGB = jso.getColorConvertAction
With toRGB
.matchAttributesAny = -1
.matchSpaceTypeAny = Not .constants.spaceFlags.AlternateSpace
.matchIntent = .constants.renderingIntents.Any
.convertProfile = "sRGB IEC61966-2.1"
.convertIntent = .constants.renderingIntents.Document
.embed = True
.preserveBlack = False
.useBlackPointCompensation = True
.action = .constants.actions.Convert
End With
For i = 0 to PDDoc.GetNumPages - 1
result = jso.colorConvertPage(i, ????, ????)
MsgBox(result)
Next
End If
Everything up to the call to jso.colorConvertPage works fine. However, as stated, no method that I've tried to pass the toRGB object as an array member (as called for by the second "actions" parameter) has worked. These include declaring the variable as an array and using the Array function. Nor have I been able to pass an empty array for the third "inkActions" parameter without throwing an error.
Interestingly, passing the toRGB object itself, directly, as both parameters does not raise any errors. However, the function then returns a null value and no conversion actually takes place.
I hope you were posting your answer a few days ago to avoid my headaches
because one day before you posted this I found the solutionn for my problem in the right docs.
^^ As I mentioned it's not hard to code this but to find the right place is much more difficult... but now I got it. Thanks to everybody here!
phibbus, I think your way is too complicated. Why don't you rename your JS function from `ConvertAllTosRGB()` to `ConvertAll(toProfile)` and submit an additional argument? `toProfile` then would be either "sRGB IEC61966-2.1" or "Apple RGB"... just an example. Of course you could submit any argument to your function. Like this:
function ConvertAll(toProfile)
{
// ...
toAny.convertProfile = toProfile;
// ...
}
What exactly are you trying to change in your VB script?
Hi Droptix,
I'm glad you got it working. What method did you wind up using?
Yes, the JavaScript function could certainly be made much more versatile by rewriting it to accept the conversion profile and other of the colorConvertAction's properties as arguments. I was mainly just doing a quick retool of the SDK documentation example by way of illustration.
The thing I'm trying to ascertain in the VBscript is whether or not it is possible to successfully call colorConvertPage from an external automation script using the JSObject bridge (i.e., accomplish the same thing that the JavaScript example does without having to first install the folder level script.)
No folder level script is a cool idea and this works for me. Pleast test it and give a short feedback:
Set argv = Wscript.Arguments
inFile = argv(0)
outFile = argv(1)
strPages = argv(2)Set App = CreateObject("AcroExch.App")
Set PDDoc = CreateObject("AcroExch.PDDoc")' open the PDF to get access to the JavaScript object
PDDoc.Open(inFile)Set jso = PDDoc.GetJSObject
' now open the file again, but using JSObject
Set doc = jso.app.openDoc(inFile)' do color conversion
Set target = doc.getColorConvertAction
target.matchAttributesAny = -1
target.matchSpaceTypeAny = Not target.constants.spaceFlags.AlternateSpace
target.matchIntent = target.constants.renderingIntents.Any
target.convertProfile = "Dot Gain 15%"
target.convertIntent = target.constants.renderingIntents.Document
target.embed = True
target.preserveBlack = False
target.useBlackPointCompensation = True
target.action = target.constants.actions.Convert' convert first page (0) to gray
doc.colorConvertPage 0, Array(target), Array()' save converted document to `outFile`
doc.saveAs(outFile)doc.closeDoc(True)
' close document
PDDoc.Close' exit and close Acrobat
App.Exit' clean up
Set PDDoc = Nothing
Set App = Nothing
Now here's the batch file I'm using for this one:
:go
cls
cscript.exe /nologo GrayConversion2.vbs "D:\folder\subfolder\in.pdf" "D:\folder\subfolder\out.pdf" 1,3,6,7,8
pause
goto go
What I need to do now is to go through the page numbers and auto-convert the ones specified by the script arguments (1,3,6,7,8). Maybe you got a good idea?
Hi Droptix,
I tested your code, and yes, it did work for me (with the exception noted below.) I see that my mistake was trying to call colorConvertPage as a method of the JSObject, itself, rather than as a method of a JavaScript Doc opened through the JSObject.
I'm not quite certain what you're trying to do with the goto loop in your batch file. Do you have multiple .pdf files that need converting, or is it just that single file with multiple pages?
In any event, given the single call to GrayConversion2.vbs in the .bat, the following simple modifications to your .vbs should work (but, again, see the exception, afterward.) Modifications are in red:
Set argv = Wscript.Arguments
inFile = argv(0)
outFile = argv(1)
arrPages = Split(argv(2), ",")Set App = CreateObject("AcroExch.App")
Set PDDoc = CreateObject("AcroExch.PDDoc")' open the PDF to get access to the JavaScript object
PDDoc.Open(inFile)Set jso = PDDoc.GetJSObject
' now open the file again, but using JSObject
Set doc = jso.app.openDoc(inFile)' do color conversion
Set target = doc.getColorConvertAction
target.matchAttributesAny = -1
target.matchSpaceTypeAny = Not target.constants.spaceFlags.AlternateSpace
target.matchIntent = target.constants.renderingIntents.Any
target.convertProfile = "Dot Gain 15%"
target.convertIntent = target.constants.renderingIntents.Document
target.embed = True
target.preserveBlack = False
target.useBlackPointCompensation = True
target.action = target.constants.actions.Convert' convert array of Pages (adjusting for 0 first page) to gray
For i = 0 to Ubound(arrPages)
doc.colorConvertPage arrPages(i)-1, Array(target), Array()
Next
' save converted document to `outFile`
doc.saveAs(outFile)doc.closeDoc(True)
' close document
PDDoc.Close' exit and close Acrobat
App.Exit' clean up
Set PDDoc = Nothing
Set App = Nothing
That works when run from the .bat as you have it, except: The call to colorConvertPage fails on the fifth call for me each time. I'm using a test .pdf that I created, and I've tried varying the order and number of the pages to be converted. It doesn't appear to be anything specific to the content of the .pdf. After four successful calls (with the conversion visiblly completed,) the method fails on the fifth call and gives a "Server threw an exception" error. I must then hard-quit Acrobat from the Task Manager to be able to test the script again.
Ah yes my batch file... it's just a loop to re-start the batch after I press Enter... makes testing easier for me :-) Just ignore it and just use the single line instead... but then the CLI window closes and I would have to double-click it again... annoying :-P Sorry, I'm lazy
cscript.exe /nologo GrayConversion2.vbs "D:\folder\subfolder\in.pdf" "D:\folder\subfolder\out.pdf" 1,3,6,7,8
P.S. I've not tested it but I think there's a typo in your script mod:
doc.colorConvertPage arrPages(i)-1, Array(target), Array()
I think `-1` is not needed in the counter and also would cause a runtime error because `colorConvertPage` expects a zero-index and in your case you would start with minus one instead of zero. Also, `arrPages(i)` is a page object and I think you cannot do a math operation like this...
To get this whole thing working I tested a lot how to get `this` or JSObject's `doc` object from my VB `PDDoc`... finally I found out that the easiest way seems to be opening the file again in JSObject. It took me some hours but at the end you can achieve color conversion without having a JavaScript what I find is really great!
North America
Europe, Middle East and Africa
Asia Pacific