Skip to content

Instantly share code, notes, and snippets.

@elmimmo
Last active September 30, 2025 11:45
Show Gist options
  • Save elmimmo/b0bf4be03df4527762ca405196f2c8a8 to your computer and use it in GitHub Desktop.
Save elmimmo/b0bf4be03df4527762ca405196f2c8a8 to your computer and use it in GitHub Desktop.
InCopy script to export blank PDF with annotations + Acrobat Quick Action JavaScript to import them into PDF exported from InDesign
//DESCRIPTION:Export blank PDF with annotations for later import into PDF exported with InDesign
(function () {
// ============================
// Export all open documents to PDF
// - Hides all layers before export (restores afterwards)
// - Enables "Include notes as annotations" (best-effort across versions)
// - Exports to the same folder as the document
// - Forces file names to end with "_annotations.pdf"
// - Shows a summary of failures at the end
// ============================
function getPDFExportFormat() {
// Be tolerant to naming differences across app versions
try { if (ExportFormat && ExportFormat.PDF_TYPE !== undefined) return ExportFormat.PDF_TYPE; } catch (e) { }
// try { if (ExportFormat && ExportFormat.pdfType !== undefined) return ExportFormat.pdfType; } catch (e) { }
// try { if (ExportFormat && ExportFormat.adobePDF !== undefined) return ExportFormat.adobePDF; } catch (e) { }
throw new Error("PDF export format is not available in this app/version.");
}
function setIncludeNotesAsAnnotations() {
// Some versions expose different property names; try both.
var ok = false;
try { app.layoutPDFExportPreferences.includeNotes = true; ok = true; } catch (e) { }
// try { app.layoutPDFExportPreferences.includeNotesAsAnnotations = true; ok = true; } catch (e) { }
return ok;
}
function hideAllLayers(doc) {
var states = [];
var hadLayers = false;
try {
if (doc.layers && doc.layers.length > 0) {
hadLayers = true;
for (var i = 0; i < doc.layers.length; i++) {
states[i] = doc.layers[i].visible;
try { doc.layers[i].visible = false; } catch (e) { }
}
}
} catch (e) { }
return { hadLayers: hadLayers, states: states };
}
function restoreLayerVisibility(doc, snapshot) {
if (!snapshot || !snapshot.hadLayers) return;
try {
for (var i = 0; i < doc.layers.length && i < snapshot.states.length; i++) {
try { doc.layers[i].visible = snapshot.states[i]; } catch (e) { }
}
} catch (e) { }
}
// Build "<base>_annotations.pdf" from the document name.
function annotationsPDFName(name) {
// Replace the last ".ext" (if any) with "_annotations.pdf"; if no extension, append it.
return name.replace(/(?:\.[^.]+)?$/, "_annotations.pdf");
}
function exportDocumentAsPDF(doc) {
// 1) Resolve the document's own folder
var folder = null;
try { folder = doc.filePath; } catch (e) { }
if (!folder) {
throw new Error("Document is not saved (no containing folder).");
}
// 2) Build the output name "<doc>_annotations.pdf"
var pdfFileName = annotationsPDFName(doc.name);
var pdfFilePath = folder.fsName + "/" + pdfFileName;
// 3) Hide all layers (restore afterwards)
var snapshot = hideAllLayers(doc);
// 4) Ensure "Include notes as annotations" is enabled (best-effort)
setIncludeNotesAsAnnotations();
// 5) Export to PDF without showing the dialog
var fmt = getPDFExportFormat();
try {
doc.exportFile(fmt, new File(pdfFilePath), false);
} finally {
// Always restore layer visibility even if export fails
restoreLayerVisibility(doc, snapshot);
}
}
// ============================
// Run
// ============================
if (app.documents.length === 0) {
alert("No documents are open.");
return;
}
var failures = [];
var successes = 0;
for (var i = 0; i < app.documents.length; i++) {
var doc = app.documents[i];
try {
exportDocumentAsPDF(doc);
successes++;
} catch (e) {
failures.push({ name: doc.name, reason: (e && e.message) ? e.message : String(e) });
}
}
// Final summary
var msg = "Export finished.\n\nSuccesses: " + successes + "\n";
if (failures.length > 0) {
msg += "Failures: " + failures.length + "\n\n";
for (var j = 0; j < failures.length; j++) {
msg += "• " + failures[j].name + " — " + failures[j].reason + "\n";
}
} else {
msg += "Failures: 0";
}
alert(msg);
})();
/*
* ================================================================================
* Annotation Importer for Adobe Acrobat Quick Action
* ================================================================================
*
* Description:
* This script is designed to be used as a step in an Adobe Acrobat Quick Action.
* For each document processed by the action, it automatically finds a corresponding
* "_annotations.pdf" file, copies all annotations from it, and adds them to the
* target document.
*
* Workflow:
* 1. For the current document (e.g., "MyFile.pdf"), it constructs the path for a
* source document (e.g., "MyFile_annotations.pdf") expected to be in the
* same directory.
* 2. It opens the source document in the background.
* 3. It copies all annotations from the source document.
* 4. It closes the source document.
* 5. It adds the copied annotations to the target document.
* 6. It saves the target document.
*
* Behavior:
* - On success, the script is completely silent.
* - If the target document already contains annotations, it is skipped and a
* message is logged to the console.
* - If a source PDF is not found, or if it contains no annotations, an alert
* will be displayed for that specific file, and a message is logged to the console.
*
* Usage:
* - Create a new Quick Action in Adobe Acrobat.
* - Add an "Execute JavaScript" step.
* - Paste this entire script into the step's options.
* - Run the action on one or more open files.
*
*/
var targetDoc = this;
// Check if the document is saved, as a path is required.
if (!targetDoc.path) {
console.println("\n--- Annotation Import Report ---\nFile: Unsaved Document\nStatus: SKIPPED\nReason: Document must be saved first.\n--------------------------------\n");
app.alert({
cMsg: "An unsaved document was skipped. Please save it and run the action again.",
cTitle: "Unsaved Document",
nIcon: 1 // Error Icon
});
} else {
// Safety Check: Skip if the document already has annotations.
var existingAnnots = targetDoc.getAnnots();
if (existingAnnots && existingAnnots.length > 0) {
console.println("\n--- Annotation Import Report ---\nFile: " + targetDoc.documentFileName + "\nStatus: SKIPPED\nReason: Document already contains " + existingAnnots.length + " annotation(s).\n--------------------------------\n");
} else {
var suffix = "_annotations";
var sourcePath = targetDoc.path.replace(/\.pdf$/i, suffix + ".pdf");
var sourceDoc = null; // Initialize as null
try {
sourceDoc = app.openDoc({ cPath: sourcePath });
// If the line above fails, it jumps to catch, and sourceDoc remains null.
// Force the script to wait for the document to be fully loaded.
sourceDoc.syncAnnotScan();
var annots = sourceDoc.getAnnots();
if (annots && annots.length > 0) {
// SUCCESS PATH: Silently process, save, and finish.
targetDoc.bringToFront();
for (var i = 0; i < annots.length; i++) {
targetDoc.addAnnot(annots[i].getProps());
}
targetDoc.saveAs(targetDoc.path);
} else {
// FAILURE PATH 1: No annotations found. Show an alert.
console.println("\n--- Annotation Import Report ---\nFile: " + targetDoc.documentFileName + "\nStatus: FAILED\nReason: Source file contains no annotations.\n--------------------------------\n");
app.alert({
cMsg: "Source file for '" + targetDoc.documentFileName + "' contains no annotations to import.",
cTitle: "No Annotations Found",
nIcon: 2 // Warning Icon
});
}
} catch (e) {
// CATCH-ALL ERROR HANDLER
if (sourceDoc == null) {
// If sourceDoc is still null, the error came from app.openDoc.
console.println("\n--- Annotation Import Report ---\nFile: " + targetDoc.documentFileName + "\nStatus: FAILED\nReason: Source file not found.\nPath Checked: " + sourcePath + "\n--------------------------------\n");
app.alert({
cMsg: "Source file not found for '" + targetDoc.documentFileName + "'.\n\nPath checked:\n" + sourcePath,
cTitle: "Source Not Found",
nIcon: 1 // Error Icon
});
} else {
// If sourceDoc exists, the error happened during processing.
console.println("\n--- Annotation Import Report ---\nFile: " + targetDoc.documentFileName + "\nStatus: FAILED\nReason: An unexpected error occurred.\nError Details: " + e.toString() + "\n--------------------------------\n");
app.alert({
cMsg: "An unexpected error occurred while processing '" + targetDoc.documentFileName + "'.\n\nError: " + e.toString(),
cTitle: "Unexpected Error",
nIcon: 1 // Error Icon
});
}
} finally {
// Final cleanup: ensure the source document is closed if it was opened.
if (sourceDoc) {
sourceDoc.closeDoc(true);
}
}
}
}

Comments are disabled for this gist.