Files
copydev-imposing-tool/acrobat-plugin/src/Imposition-02-Livret.js
Jules Dubois fd92b80350 fix: menu direct par action, plus de choix intermediaire
Chaque action est un item de menu separe : "Imposer un livret",
"Delivretiser", etc. Un clic = une action. Seul le creep est
demande via app.response. Corrige aussi "doc is not defined".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-25 19:09:38 +02:00

289 lines
12 KiB
JavaScript
Executable File

// Imposition-02-Livret.js
// ---------------------------------------------------------------------------
// Suite d'imposition professionnelle - Folder-Level Script pour Adobe Acrobat Pro
// Module 2 : Creer un livret / Delivretiser (signature de cahier, piqure a cheval)
//
// Depend de Imposition-00-Core.js (doit etre charge avant).
//
// ATTENTION TECHNIQUE - a lire avant utilisation en production :
// Le placement des pages source sur les planches composites repose sur
// CDImp.Util.placerPageDansRect()/extraireRegionPage() (voir Core.js), qui
// utilisent la technique "template + recadrage de CropBox" standard en
// JavaScript pur pour Acrobat (sans plugin natif). Cette technique n'a pas
// pu etre executee/verifiee dans une vraie session Acrobat depuis cet
// environnement de developpement (Acrobat n'y est pas installe) : a tester
// sur un PDF reel avant tout usage en production.
// ---------------------------------------------------------------------------
if (typeof CDImp === "undefined") {
throw new Error("Imposition-02-Livret.js : CDImp.Core doit etre charge avant ce fichier.");
}
CDImp.Livret = CDImp.Livret || {};
// -----------------------------------------------------------------------
// Calcul de l'ordre des pages (imposition en cahier unique, piqure a cheval)
// -----------------------------------------------------------------------
/**
* Calcule l'imbrication des pages pour un cahier unique (selle/pliage central).
* Fonction symetrique : utilisee aussi bien pour imposer (Page logique ->
* position sur planche) que pour delivretiser (position sur planche -> page
* logique), puisque l'imposition en cahier simple est sa propre inverse au
* niveau de la formule (seul le sens d'utilisation change).
*
* Pour N pages (multiple de 4), chaque feuille porte 4 pages : 2 au recto,
* 2 au verso. Exemple pour N=8 :
* Feuille 1 - recto : (8 | 1) verso : (2 | 7)
* Feuille 2 - recto : (6 | 3) verso : (4 | 5)
*
* @param {Number} nPages nombre total de pages (doit etre un multiple de 4)
* @returns {Array} liste de planches, dans l'ordre d'impression :
* [{ feuille: 1, face: "recto", gauche: 8, droite: 1 }, ...]
* "gauche"/"droite" sont des numeros de page 1-based du document source.
*/
CDImp.Livret.calculerOrdre = function (nPages) {
if (nPages % 4 !== 0) {
throw new Error("calculerOrdre : le nombre de pages (" + nPages + ") doit etre un multiple de 4.");
}
var nFeuilles = nPages / 4;
var planches = [];
for (var s = 0; s < nFeuilles; s++) {
planches.push({ feuille: s + 1, face: "recto", gauche: nPages - 2 * s, droite: 2 * s + 1 });
planches.push({ feuille: s + 1, face: "verso", gauche: 2 * s + 2, droite: nPages - 2 * s - 1 });
}
return planches;
};
// -----------------------------------------------------------------------
// Ajout de pages blanches pour atteindre un multiple de 4
// -----------------------------------------------------------------------
/**
* Insere nManque pages blanches dans doc, a la position demandee.
* Les pages blanches reprennent le format (largeur/hauteur) de la premiere
* page du document.
*
* @param {Doc} doc document a modifier (modification en place)
* @param {Number} nManque nombre de pages blanches a ajouter
* @param {String} position "debut" | "fin" | "apres_couverture"
*/
CDImp.Livret.ajouterPagesBlanches = function (doc, nManque, position) {
if (nManque <= 0) {
return;
}
var boxRef = doc.getPageBox({ nPage: 0, cBox: "Crop" });
var largeur = Math.abs(boxRef[2] - boxRef[0]);
var hauteur = Math.abs(boxRef[3] - boxRef[1]);
CDImp.Util.avecPrivileges(function () {
for (var k = 0; k < nManque; k++) {
var idxInsertion;
switch (position) {
case "debut":
idxInsertion = 0;
break;
case "apres_couverture":
idxInsertion = 1;
break;
case "fin":
default:
idxInsertion = doc.numPages; // toujours recalcule : ajoute en fin
break;
}
doc.newPage({ nPage: idxInsertion, width: largeur, height: hauteur });
}
});
};
/**
* Demande a l'utilisateur ou inserer les pages blanches manquantes, via un
* menu contextuel simple (app.popUpMenu, API stable et bien documentee,
* preferee ici a un second execDialog pour limiter les risques sur un choix
* aussi simple).
*
* @returns {String|null} "debut" | "fin" | "apres_couverture", ou null si
* l'utilisateur annule.
*/
CDImp.Livret._demanderPositionPagesBlanches = function (nManque) {
var choix = app.popUpMenu(
{ cName: "A la fin du document (" + nManque + " page(s))", cReturn: "fin" },
{ cName: "Au debut du document (" + nManque + " page(s))", cReturn: "debut" },
{ cName: "Juste apres la couverture (page 1)", cReturn: "apres_couverture" }
);
return choix || null;
};
// -----------------------------------------------------------------------
// Construction du document imposes (sens direct : pages -> livret)
// -----------------------------------------------------------------------
/**
* Construit le document de sortie : une page composite (format double, en
* paysage) par planche recto/verso, avec les deux pages source positionnees
* cote a cote.
*
* @param {Doc} srcDoc document source (deja complete a un multiple de 4 pages)
* @param {Array} planches resultat de CDImp.Livret.calculerOrdre()
* @param {Number} creepMm compensation de chasse en mm, appliquee
* progressivement vers l'interieur du cahier (0 = desactive)
* @returns {Doc} le nouveau document compose
*/
CDImp.Livret.construireDocument = function (srcDoc, planches, creepMm) {
var boxSrc = srcDoc.getPageBox({ nPage: 0, cBox: "Crop" });
var largeurSrc = Math.abs(boxSrc[2] - boxSrc[0]);
var hauteurSrc = Math.abs(boxSrc[3] - boxSrc[1]);
var largeurDest = largeurSrc * 2;
var hauteurDest = hauteurSrc;
var nFeuilles = planches.length / 2;
var destDoc;
CDImp.Util.avecPrivileges(function () {
destDoc = new Doc();
destDoc.newPage({ nPage: 0, width: largeurDest, height: hauteurDest });
for (var k = 1; k < planches.length; k++) {
destDoc.newPage({ nPage: k, width: largeurDest, height: hauteurDest });
}
});
for (var i = 0; i < planches.length; i++) {
var planche = planches[i];
// Decalage de chasse (creep) : croissant en s'eloignant du centre du
// cahier vers l'exterieur, applique symetriquement gauche/droite.
var decalageCreepPt = creepMm
? CDImp.Util.mmToPt(creepMm) * (nFeuilles - planche.feuille)
: 0;
CDImp.Util.placerPageDansRect(srcDoc, planche.gauche, destDoc, i,
[decalageCreepPt, 0, decalageCreepPt + largeurSrc, hauteurSrc]);
CDImp.Util.placerPageDansRect(srcDoc, planche.droite, destDoc, i,
[largeurSrc - decalageCreepPt, 0, largeurDest - decalageCreepPt, hauteurSrc]);
}
return destDoc;
};
// -----------------------------------------------------------------------
// Delivretisation (sens inverse : livret imposes -> ordre de lecture normal)
// -----------------------------------------------------------------------
/**
* Reconstitue l'ordre de lecture normal d'un PDF imposé en cahier piqûre a
* cheval : chaque page du document source est une planche double (recto ou
* verso) contenant deux pages logiques cote a cote, dans l'ordre produit par
* CDImp.Livret.construireDocument(). On reutilise calculerOrdre() pour
* retrouver, pour chaque planche, les numeros de page logique a replacer a
* gauche et a droite, puis on extrait chaque moitie vers sa position finale.
*
* Limite connue : ne compense pas une eventuelle chasse (creep) appliquee
* lors de l'imposition d'origine (les pages reconstituees seront legerement
* decalees si un creep non nul avait ete utilise).
*
* @param {Doc} doc document imposes (planches doubles), document actif si omis
*/
CDImp.Livret.delivretiser = function (doc) {
doc = CDImp.Util.getDocActif(doc);
var nPlanches = doc.numPages;
if (nPlanches % 2 !== 0) {
CDImp.Util.erreur("Delivretiser : le document doit contenir un nombre pair de planches\n(une planche recto + une planche verso par feuille).");
return;
}
var nPagesLogiques = nPlanches * 2;
var planches;
try {
planches = CDImp.Livret.calculerOrdre(nPagesLogiques);
} catch (e) {
CDImp.Util.erreur(e.toString());
return;
}
var boxRef = doc.getPageBox({ nPage: 0, cBox: "Crop" });
var largeurPlanche = Math.abs(boxRef[2] - boxRef[0]);
var hauteur = Math.abs(boxRef[3] - boxRef[1]);
var largeurDemiPage = largeurPlanche / 2;
var destDoc;
try {
CDImp.Util.avecPrivileges(function () {
destDoc = new Doc();
destDoc.newPage({ nPage: 0, width: largeurDemiPage, height: hauteur });
for (var k = 1; k < nPagesLogiques; k++) {
destDoc.newPage({ nPage: k, width: largeurDemiPage, height: hauteur });
}
});
for (var i = 0; i < planches.length; i++) {
var planche = planches[i];
var rectGauche = [0, 0, largeurDemiPage, hauteur];
var rectDroite = [largeurDemiPage, 0, largeurPlanche, hauteur];
CDImp.Util.extraireRegionPage(doc, i + 1, rectGauche, destDoc, planche.gauche - 1);
CDImp.Util.extraireRegionPage(doc, i + 1, rectDroite, destDoc, planche.droite - 1);
}
} catch (e) {
CDImp.Util.erreur("Erreur lors de la delivretisation : " + e.toString());
return;
}
if (CDImp.Auto && CDImp.Auto.enregistrerDerniereAction) {
CDImp.Auto.enregistrerDerniereAction("Livret.delivretiser", {});
}
CDImp.Util.info("Delivretisation terminee (" + nPagesLogiques + " pages reconstituees).\nPensez a l'enregistrer (Ctrl+S) sous un nouveau nom.");
};
// -----------------------------------------------------------------------
// Point d'entree du module (appele depuis le panneau principal, Module 1)
// -----------------------------------------------------------------------
CDImp.Livret.imposer = function () {
var doc = CDImp.Util.getDocActif();
var nPages = doc.numPages;
var reste = nPages % 4;
var info = "Document : " + nPages + " pages.";
if (reste !== 0) {
info += "\n" + (4 - reste) + " page(s) blanche(s) seront ajoutees a la fin.";
}
var saisie = app.response({
cQuestion: info + "\n\nCompensation de chasse (creep) en mm par feuille :\n(0 = aucune)",
cTitle: "Imposer un livret",
cDefault: "0"
});
if (saisie === null) return;
var creepMm = parseFloat(saisie) || 0;
if (reste !== 0) {
CDImp.Livret.ajouterPagesBlanches(doc, 4 - reste, "fin");
nPages = doc.numPages;
}
var planches = CDImp.Livret.calculerOrdre(nPages);
var destDoc = CDImp.Livret.construireDocument(doc, planches, creepMm);
if (CDImp.Auto && CDImp.Auto.enregistrerDerniereAction) {
CDImp.Auto.enregistrerDerniereAction("Livret.imposer", { creepMm: creepMm });
}
app.alert("Livret cree avec succes (" + planches.length + " planches).\nPensez a l'enregistrer sous un nouveau nom.");
CDImp.Util.info("Livret cree avec succes (" + planches.length + " planches).\nPensez a l'enregistrer (Ctrl+S) sous un nouveau nom.");
};
/**
* Variante directe sans dialogues, utilisee par le Module 7 (Automatisation)
* pour rejouer une action enregistree sur un nouveau document. Ne gere pas
* l'ajout de pages blanches (le document doit deja etre un multiple de 4).
*/
CDImp.Livret.executerAvecParams = function (doc, params) {
doc = CDImp.Util.getDocActif(doc);
var nPages = doc.numPages;
if (nPages % 4 !== 0) {
CDImp.Util.erreur("Repeter l'action : le document (" + nPages + " pages) n'est pas un multiple de 4.\nUtilisez le module Livret manuellement pour ajouter les pages blanches.");
return;
}
var planches = CDImp.Livret.calculerOrdre(nPages);
var destDoc = CDImp.Livret.construireDocument(doc, planches, params.creepMm || 0);
CDImp.Util.info("Livret recree avec succes (" + planches.length + " planches).");
return destDoc;
};