Copy link to clipboard
Copied
I have 600+ fm files that I want to save as a pdf. They are all in the same directory. This is the script I started with (though I currently have Frankencode doing other stuff that was added between me and things suggested by Claudet/Gemini/etc).
#target framemaker
(function () {
// --- CONFIG ---
var PDF_SETTINGS_NAME = "";
// Leave empty "" to use the document's default PDF settings
// Or put the name of a PDF setup, e.g. "High Quality Print"
// ----------------
function log(msg) {
$.writeln(msg);
var oFile = new File ("C:/Catalog/output/run.log" );
oFile.open("a");
oFile.writeln(msg);
oFile.close();
}
function saveAsPdf(doc, savePath) {
// Get default save parameters
var params = GetSaveDefaultParams();
var i;
// Set the file type to PDF
i = GetPropIndex(params, Constants.FS_FileType);
params[i].propVal.ival = Constants.FV_SaveFmtPdf;
// Optional: Configure other PDF settings if needed
// Example: Set to not use Distiller (rely on modern internal PDF generation)
i = GetPropIndex(params, Constants.FS_PDFUseDistiller);
if (i > -1) {
params[i].propVal.ival = 0; // 0 for false, 1 for true
}
// Call the Save function
// FA_errno is a global variable that will contain the error code after the call
FA_errno = 0;
var returnParams = new PropVals();
// Check if the input is a book or a document to use the correct function
if (doc.Type === Constants.FA_Book) {
doc.Save(savePath, params, returnParams);
} else {
// For a single document, use F_ApiSave (often accessed via the document object in modern ExtendScript)
// Note: Direct doc.Save(path, params, returnParams) works for documents too in many cases.
// The Book object has a specific method signature in some versions.
doc.Save(savePath, params, returnParams);
}
if (FA_errno !== 0) {
log("Failed to save PDF. Error code: " + FA_errno);
} else {
log("PDF saved successfully to: " + savePath);
}
}
var runFile = new File("C:/Catalog/output/run.go");
if (!runFile.exists) {
$.writeln("run.go file does not exist. Exiting.");
return;
}
var folder = new Folder("C:/Catalog/output");
var files = folder.getFiles(function (f) {
return f instanceof File && /\.fm$/i.test(f.name);
});
if (files.length === 0) {
log("No .fm files found.");
app.Close(Constants.FF_CLOSE_MODIFIED);
}
log("Found " + files.length + " file(s).");
for (var i = 0; i < files.length; i++) {
var file = files[i];
log("Processing: " + file.name);
var doc = null;
try {
doc = SimpleOpen(file.fsName, false);
var pdfPath = file.fsName.replace(/\.fm$/i, ".pdf");
if (saveAsPdf(doc, pdfPath)) {
log(" PDF created: " + pdfPath);
}
} catch (e) {
log(" ERROR opening file: " + e);
} finally {
if (doc) {
try {
// Close without saving changes
doc.Close(Constants.FF_CLOSE_MODIFIED);
} catch (closeErr) {
log(" ERROR closing file: " + closeErr);
}
}
}
}
log("Batch PDF export complete.");
app.Close(Constants.FF_CLOSE_MODIFIED);
})();
I get timeout errors at random places. It will handle anywhere between 2-7 files, then give me a timeout error. I have the script in the startup folder so that I can place a file in the output folder, open FM, and then let it go to work. I'd also like to move the fm files to an archive folder once it's done.
Can someone give me a push in the right direction? I also don't really know if the SaveAsPdf function is what it should be, I'd be surprised if it was.
Copy link to clipboard
Copied
After looking at more posts on here, I was able to cobble something together that works.
Copy link to clipboard
Copied
Would you care to post your solution here to help other beginner scripters?
Copy link to clipboard
Copied
Here is a script that works on a book, but you could modify it to work on a folder. Or, you could put all of the folder's FM files into a temporary book. I originally wrote it for a client, and thus the AC_SCP namespace.
#target framemaker
var AC_SCP = AC_SCP || {}; // Save each component to PDF.
AC_SCP.version = "Version 0.1b January 11, 2022";
AC_SCP.file = $.fileName;
AC_SCP.main = function (book) {
var doc;
if ((book) && (book.ObjectValid () === 1)) {
AC_SCP.processBook (book);
}
else {
book = app.ActiveBook;
if (book.ObjectValid () === 1) {
AC_SCP.processBook (book);
}
}
};
AC_SCP.saveDocAsPdf = function (doc, name) {
var params, returnParams, i;
if (!name) {
name = doc.Name.replace (/[^\.]+$/, "pdf");
}
params = GetSaveDefaultParams();
returnParams = new PropVals();
i = GetPropIndex (params, Constants.FS_FileType);
params[i].propVal.ival = Constants.FV_SaveFmtPdf;
i = GetPropIndex (params, Constants.FS_PDFUseDistiller);
params[i].propVal.ival = 0;
FA_errno = 0;
doc.Save (name, params, returnParams);
if (FA_errno !== 0) {
PrintSaveStatus (returnParams);
}
return FA_errno;
};
AC_SCP.processBook = function (book) {
var bookComp, file;
// Loop through all of the components in the book.
bookComp = book.FirstComponentInBook;
while (bookComp.ObjectValid ()) {
if (bookComp.ComponentType === 512) {
file = new File (bookComp.Name);
// Get the document returned in a JavaScript object.
doc = CP.getDocument (bookComp.Name, undefined, true);
if ((doc) && (doc.ObjectValid () === 1)) {
book.StatusLine = "Processing " + file.name;
AC_SCP.saveDocAsPdf (doc);
// If the document was opened by the script, close it.
if (doc.openedByScript === true) {
doc.Close (true);
}
}
}
bookComp = bookComp.NextBookComponentInDFSOrder;
}
// Reset the book status line.
book.StatusLine = "";
};
Copy link to clipboard
Copied
I just realized that the script refers to a function in another script (CP.getDocument). You should be able to use the code from your original script to open each document.
Copy link to clipboard
Copied
Hi,
When you want to automate publishing, it could be that this is not allowed with a regular FrameMaker licence. You would need FrameMaker Publishing Server.
https://www.adobe.com/products/framemaker/publishing-server.html
Best regards, Winfried
Get ready! An upgraded Adobe Community experience is coming in January.
Learn more