Copy link to clipboard
Copied
How to save a book as PDF with bookmarks?
I am exporting an open book as PDF using the following script:
var params = GetSaveDefaultParams()
var returnParamsp =new PropVals()
var i = GetPropIndex(params, Constants.FS_FileType)
params.propVal.ival =Constants.FV_SaveFmtPdf
file.Save(pdfName, params, returnParamsp)
This works fine but the pdf document does not have bookmarks. I would like to get the same
result as if a selected "Generate PDF bookmarks" (translated from German) on the Bookmars
page of the PDF Settings dialog.
I guess I will have to set some property value, but which one? Is there a place where I can
look it up?
Thanks
Copy link to clipboard
Copied
Im surprised no one else has contributed to this question. If anyone has been able to get this to work consistently through extendscript then I would certainly be interested!
I have done this through code many times using Elmsoft Framescript, but simply cant get the process fully automated trough extendscript.
You do need more code in addition to your extract. You need to iterate through each component in the book and make sure that you set "Doc.PDFBookmark = true;" saving each component as you loop through.
In theory when you update the book it will use the PDFBookmark setting in the first component in the book to decide whether to generate the bookmarks or not. This is how it has worked in the past.
Unfortunately there seems to be a bug in the update book function in FM10 and the only way to reliably get it to set is to manually highlight the book and select "Format>Document>PDF Setup" and check the box "Generate PDF Bookmarks". Indeed if you open a component in the book and toggle the "Doc.PDFBookmark = true;" value you will see the "Generate PDF Bookmarks" checkbox toggle on and off. But unfortunately the value on the book itself seems to be read only (which was the case in the past but it would dynamically change once the book was updated after having changed the value on the document components).
An option here you might think would be to use fcodes to control the PDF Setup dialog to set the property, but alas there is an existing bug in FM10 which stops fcodes from working properly with a book (you can get the popup open but cant cant control it)! I think in all likelyhood the bug that stops fcodes from working properly is the same bug stopping the PDFBookmark functionality.
So it looks like we are stuck until Adobe issue a patch. Maybe someone out there has got this to work, if so please let us both know!
Copy link to clipboard
Copied
I have had to deal with this issue several times over the years. If you save a book file as MIF and look at it with a text editor, you will see that bookmark information is stored in the book. However, there is no way (that I know of) to programmatically reach this information with FrameScript, ExtendScript, or the FDK. The only reliable solution is to programmatically save the book as a MIF file, then parse through it and change the bookmark levels as appropriate, then open the MIF with FrameMaker and save it back to a .book file. This could all be done with ExtendScript or FrameScript, etc.
Rick Quatro
Copy link to clipboard
Copied
The only values that change in my MIF files are as follows:
[Old text]: "20202020203C786D703A437265617465446174653E303131322D30332D31305431343A33373A3134"
[New text]: "20202020203C786D703A437265617465446174653E303131322D30332D31305431343A33383A3533"
[Old text]: "64696679446174653E303131322D30332D31305431343A33373A31342B30313A30303C2F786D703A"
[New text]: "64696679446174653E303131322D30332D31305431343A33383A35332B30313A30303C2F786D703A"
[Old text]: "3131322D30332D31305431343A33373A31342B30313A30303C2F786D703A4D657461646174614461"
[New text]: "3131322D30332D31305431343A33383A35332B30313A30303C2F786D703A4D657461646174614461"
Im not sure this is what you expected.
Generating PDF files with bookmarks programmatically shouldnt be a problem at all, and i have done this without problem in FM7 & 8 using Framescript, I have the source code still on my old PC running FM7 and this is what im using to port my code to extend script.
My current extend script will open a book and loop through each component. The script will clear all headings and then set specific AcrobatLevel for page formats. Here is a code extract from my current routine:
// Clear all formats first
var count = 0;
var pgfFmt = doc.FirstPgfFmtInDoc;
while (pgfFmt.ObjectValid()) {
count++;
pgfFmt.AcrobatLevel = 0
pgfFmt = pgfFmt.NextPgfFmtInDoc;
}
// Now set specific headings
var pgfFmt = doc.GetNamedPgfFmt("Numbered Head");
pgfFmt.AcrobatLevel = 1
var pgfFmt = doc.GetNamedPgfFmt("Heading 1");
pgfFmt.AcrobatLevel = 2
I set other values such as PDFBookmark and
doc.GenerateAcrobatInfo = true;
The script will save each component after the change and then update the book.
After updating the book I save as PDF.
The script will generate a PDF wihtout bookmarks (but would work in Framescript).
Here is the rub:
Before running the function to save the book as a PDF i run the following sub routine to debug (after having made the book the focused item):
function pop(){
FcodeList = new Array(FCodes.KBD_ACROBAT_SETUP,FCodes.START_DIALOG,FCodes.KBD_RETURN,FCodes.END_DIALOG); //Fcodes
Fcodes(FcodeList); // Fcode Execution
}
This pops up the "PDF Setup" dialog.
I close the PDF Setup dialog without making any change to the values (by clicking cancel) and the PDF generates with the bookmarks correctly in tact at the right levels.
So it would appear that there is something that takes place when the PDF Setup dialog opens that updates the book correctly. However this is not accessable from the APIs currently in FM10. A basic update book call in Framescript was sufficient in my FM7 source code.
Any other opinions out there?
Copy link to clipboard
Copied
You have to edit the <PgfCatalog> entries for all of the paragraph formats represented in the MIF file. This is the entry that you have to look for for each paragraph format:
<PgfAcrobatLevel 3>
If you don't want the particular format to appear, you set the value to 0; or you set it to the level that you want it to appear.
Also, for the modified book, make sure you set this:
Set oBook.PDFBookmark = True;
Here is an overview of the entire process:
1) Save the book as MIF.
2) Make a temporary text file to write the edited MIF code to.
3) Loop through the MIF file line-by-line, reading from the original MIF file that you saved is step 1 and writing to the MIF file you created in step 2. As you encounter each <PgfTag PgfName>, determine which level PgfName should be. When you hit the corresponding <PgfAcrobatLevel #>, set the appropriate numeric value.
4) After the temporary MIF file has been completed, open it and save it over the original .book file. Now your bookmarks should be correctly set at the book level.
Rick
Copy link to clipboard
Copied
If you check my extendscript code extracts you will find this exactly what the code does to the books:
var pgfFmt = doc.GetNamedPgfFmt("Heading 1");
pgfFmt.AcrobatLevel = 2
Doc.PDFBookmark = true
And when viewing the MIF output from this all the AcrobatLevel's are correctly placed. However there is some hex information in the header that changes depending on whether the "PDF Setup" dialog has been previously opened manually.
Also your example "Set oBook.PDFBookmark = True;" is Framescript syntax, not Extendscript so im not sure your even experiencing the same issue thats being discussed here because we have already established that Framescript works correctly and not Extendscript!
The "framemaker_10_scripting" guide explains that this should work, but does not at present.
There should be no need at all to attempt to edit MIF files directly. Thats the point of the FDK and ESTK.
Your advice didnt help me in my case because the only difference in the MIF file i generate is the hex values in the header which is completely ditached from the heading level information in the body of the MIF file.
Copy link to clipboard
Copied
Because you are simply manipulating a MIF file, it doesn't matter what language you use, the results should be the same. And, I understand that there should be no need to edit MIF files; however, the bookmark information for the book is not directly exposed to the FDK, FrameScript or ExtendScript. The only way I got it to work was to edit the book's MIF. I used the method I outlined for my customer, it worked, and he is happy with the results.
Rick
Copy link to clipboard
Copied
So returning to one of my previous responses; I save out two versions of the same book to a MIF. The book has the PgfAcrobatLevel's all set through a script. The first time i save the book I avoid opening the "PDF Setup" window and save directly to PDF. The second MIF file is saved after having opened the "PDF Setup" window and imediately closing it again without making a change.
The MIF files have the following differences:
[Old text]: "20202020203C786D703A437265617465446174653E303131322D30332D3130543134 3A33373A3134"
[New text]: "20202020203C786D703A437265617465446174653E303131322D30332D3130543134 3A33383A3533"
[Old text]: "64696679446174653E303131322D30332D31305431343A33373A31342B30313A3030 3C2F786D703A"
[New text]: "64696679446174653E303131322D30332D31305431343A33383A35332B30313A3030 3C2F786D703A"
[Old text]: "3131322D30332D31305431343A33373A31342B30313A30303C2F786D703A4D657461 646174614461"
[New text]: "3131322D30332D31305431343A33383A35332B30313A30303C2F786D703A4D657461 646174614461"
The [Old text] version of the MIF does not show my bookmarks, the [New text] version does. Both MIF files have exactly the same entries for the PgfAcrobatLevels.
So what exactly would you be changing here? Because I have no idea what these strings control?
What you are proposing is changing the PgfAcrobatLevel but they are both exactly the same in both MIF files already!
Copy link to clipboard
Copied
I am not editing any of the content of the text in that section of the MIF file. My guess is that the problem is this:
Doc.PDFBookmark = true;
The equivalent code works with FrameScript and the FDK, but apparently not with ExtendScript. I am sorry I couldn't be more helpful in finding a solution.
Rick
Copy link to clipboard
Copied
Hi Rick
I tried to code your solution. I’m not sure if I got this right, because I’m very new to FrameScript (it’s my first script).
Anyway. The Code did not work. It produces a PDF, but there are still no Bookmarks in the PDF. If I save the book from FrameMaker with File/Save As PDF… it works perfectly
Is there any (or several) bugs in my code?
Set sOrigBookFile = 'C:\tmp\Bookmark-Test.book';
Set sTmpMifFile = 'C:\tmp\tempMif.mif';
Set sPdfFileName = 'C:\tmp\BookmarkedPDF.pdf'
//----------------------------------------------------
// 1) Save the book as MIF.
//----------------------------------------------------
Open Book File(sOrigBookFile) NewVar(Result) MakeVisible(False)
AlertUserAboutFailure(False) ReturnStatus(sErrors);
Run eSys.RemoveFileExtension FullPath(Result.Name) NewExt('mif') NewVar(vMifFileName);
Save Book BookObject(Result) File(vMifFileName)
AlertUserAboutFailure(false) FileType(SaveFmtInterchange100);
Close Book BookObject(Result) IgnoreMods;
//----------------------------------------------------
// 2) Make a temporary text file to write the edited MIF code to.
//----------------------------------------------------
New TextFile File(sTmpMifFile) NewVar(vTmpMifFile);
//----------------------------------------------------
//3) Loop through the MIF file line-by-line, reading from the original MIF file that you saved is
// step 1 and writing to the MIF file you created in step 2. As you encounter each <PgfTag PgfName>,
// determine which level PgfName should be. When you hit the corresponding <PgfAcrobatLevel #>, set
// the appropriate numeric value.
//----------------------------------------------------
Open Textfile File(vMifFileName) NewVar(vMifBook) IOType(ReadOnly);
New StringList NewVar(lvPgfFmtLevelLst)
' <PgfTag `Heading1' + QUOTE +'>' '3'
' <PgfTag `Heading2' + QUOTE +'>' '4';
Read File(vMifBook) NewVar(gvTextBuffer);
Loop While (ErrorCode = 0)
Set gvCharPos = eStr.FindString{gvTextBuffer,'<PgfTag', 'NoCase'};
If gvCharPos > 0
Find Member(gvTextBuffer) InList(lvPgfFmtLevelLst)
ReturnStatus(lvFound) ReturnPos(lvPos);
If (lvFound)
New Integer NewVar(lvLevel) Value(lvPgfFmtLevelLst[lvPos+1]);
EndIf
EndIf
// set the new level
If lvLevel > 0
Set gvCPos = eStr.FindString{gvTextBuffer,'<PgfAcrobatLevel', 'NoCase'};
If gvCPos > 0
Set sPgfAcrobatLevelElement = ' <PgfAcrobatLevel '+lvLevel+'>';
Set gvTextBuffer = sPgfAcrobatLevelElement;
//reset level
Set lvLevel = 0;
EndIf
EndIf
Write Object(vTmpMifFile) gvTextBuffer;
Read File(vMifBook) NewVar(gvTextBuffer);
EndLoop
Close Textfile Object(vTmpMifFile);
Close Textfile Object(vMifBook);
//----------------------------------------------------
// 4) After the temporary MIF file has been completed, open it and save it over the original .book file.
// Now your bookmarks should be correctly set at the book level.
//----------------------------------------------------
Open Book File(sTmpMifFile) NewVar(oBook) MakeVisible(False)
AlertUserAboutFailure(False) ReturnStatus(sErrors);
Set oBook.PDFBookmark = True;
Save Book BookObject(oBook) File(sFile)
AlertUserAboutFailure(false) FileType(SaveFmtBinary);
Close Book BookObject(oBook) IgnoreMods;
Open Book File(sFile) NewVar(ooBook) MakeVisible(False)
AlertUserAboutFailure(False) ReturnStatus(sErrors);
Save Book BookObject(ooBook) File(sPdfFileName) FileType(SaveFmtPdf);
Close Book BookObject(ooBook) IgnoreMods;
Thanks much for any help!!
Copy link to clipboard
Copied
Rick,
I'm trying to compare the bookmark levels of one document against the bookmark levels of a book file. I am writing a simple script to check the settings. We assume the document settings are the correct settings, and then we want to alert the user to any mismatches found at the book level.
So I understand what you mean about needing to save the book file in MIF format first before you can even see the book-level settings. You wrote, "3) Loop through the MIF file line-by-line. . ."
How do you do that? I see that Constants.FS_ForceOpenAsText can be used to make ExtendScript open the MIF file as a text file instead. Is this a valid approach?
Thanks,
Jason