Nettoyer la table de montage [MÀJ]
March 14, 2017 | Snippets | fr | en
MISE À JOUR (14 mars 2017). — Ajout de l'option « Préserver les blocs chaînés », d'après une suggestion de Colin Flashman et Tim Gouder. Cochez cette case pour empêcher que CleanupPasteboard inclue les blocs chaînés dans l'opération de nettoyage.
Voici un petit script sans prétention suggéré par Rasmus Olsen il y a quelques jours au détour du Forum InDesign Scripting. L'idée de départ est de débarrasser votre document des éléments temporaires que vous avez disposés ça et là sur la table de montage (au-delà des limites imprimables de la page). L'interface dialoguée du script vous permet d'étendre ou de réduire la zone à nettoyer, en prenant par exemple en considération la marge de fond tournant (les fonds perdus) ou celle dite de ligne-bloc. (Voir l'animation en bas de page — désolé, j'ai laissé l'interface en anglais!)
La principale opération à exécuter étant d'une simplicité biblique, profitons-en pour examiner plus religieusement les objets impliqués dans la manœuvre, et leurs à-côtés.
Table de montage et planche
AVERTISSEMENT (15 mars 2017). — Cette section n'est pertinente que sous CS3/CS4, ce qui correspond à la date de publication de l'article original (2009). De profondes modifications du Scripting DOM ont été opérées depuis. En particulier, il n'est plus vrai que l'objet parent d'un PageItem de premier niveau soit, ou bien une page, ou bien une planche. Aujourd'hui, l'objet Spread représente toujours le parent ultime d'un élément paginé, peu importe qu'il se situe à l'intérieur ou à l'extérieur de l'aire de la page. Ainsi, les lignes qui suivent ne doivent être considérées que dans leur perspective historique.
Le point qu'il faut absolument saisir concernant la « table de montage » (pasteboard), c'est qu'un tel objet n'existe pas réellement aux yeux du DOM JavaScript d'InDesign. C'est une abstraction. Les objets Application
et Document
ont bien dans leurs bagages une propriété pasteboardPreferences
, mais elle ne conduit qu'à un objet PasteboardPreference
. Objet dans lequel on ne trouve, pour l'essentiel, qu'une propriété minimumSpaceAboveAndBelow
contrôlant la zone intercalaire au-dessus et au-dessous des pages du document affiché. Pour info, l'API du SDK d'InDesign expose une class IPasteboard
(« I » pour « Interface »), laquelle accède à la « géométrie de la table de montage ». Mais la table de montage n'est d'aucune façon un conteneur au sens naïf du terme, sa fonction essentielle étant plutôt de fixer les bases du système de coordonnées (Pasteboard coordinate space), comme l'illustre le guide du développeur:
Ainsi, quand nous parlons de « nettoyer la table de montage », la véritable zone à laquelle nous faisons référence est l'espace extérieur des pages — plus ou moins visible selon vos préférences d'affichage — et cet espace est en réalité contrôlé par l'objet spread (« étendue, déploiement, éventail ») qui correspond aux planches dans la version francisée d'InDesign. Un objet Spread
peut se concevoir comme un ensemble compact d'une ou plusieurs pages contiguës. Une double-page réside sur une planche de deux pages, mais les amateurs de dépliants en accordéon peuvent tout aussi bien créer des planches de 10 pages. Cela dit, une planche ne correspond pas seulement à la réunion géométrique de plusieurs pages, c'est aussi une sorte de méta-conteneur capable d'adresser tous les objets résidant à l'intérieur et à l'extérieur des pages. De ce fait, il peut régner une certaine confusion, lexicale ou conceptuelle, entre la planche (spread) et la table de montage (pasteboard).
« Une planche, explique-t-on dans la documentation d'InDesign, est une série de pages affichées ensemble, comme les deux pages visibles lorsque vous ouvrez un livre ou un magazine. La table de montage, zone extérieure à la page dans laquelle sont stockés les objets qui ne sont pas encore positionnés sur une page, est propre à une planche InDesign. Elle prévoit un espace réservé aux objets à fonds perdus, c’est-à-dire qui dépassent les limites d’une page. » Techniquement, il suffira de retenir qu'il n'y a pas d'objet Pasteboard et que l'objet Spread
supervise tout le monde : l'agrégat de pages, les composants graphiques mis en page et les composants graphiques mis hors page dans cette portée de la table de montage. Supposons que nous avons créé un bloc sur la page active. Dupliquons-le, déplaçons la copie hors de la page et relevons les compteurs : mySpread.pageItems.length
vaut 2, alors que myPage.pageItems.length
en reste à 1 (deux blocs au total vus de la planche, mais un seul sur la page).
À ce stade, la grande question est de savoir comment collecter uniquement les objets outsiders (ceux que l'utilisateur perçoit comme inscrits sur la table de montage). La réponse découle de la hiérarchie des objets. Considérons un composant myPageItem
situé hors de page. Il est alors caractérisé par le fait que son parent immédiat (myPageItem.parent
) n'est pas une Page
, mais un Spread
(ou un MasterSpread
, pour les gabarits). Par conséquent, lorsque vous souhaitez récupérer les objets hors-page du document actif, il suffit de filtrer les objets par la classe de leur parent (obj.parent.constructor
) :
// Identification des éléments d'une planche sous CS4 // (Ne fonctionne plus dans les versions ultérieures). var pasteboardItems = [], pItems = app.activeDocument.pageItems.everyItem().getElements(), i,p; while( i=pItems.pop() ) { p = i.parent.constructor; if ( p == Spread || p == MasterSpread ) { pasteboardItems.push(i); } } alert(pasteboardItems.length + " objects sur la table de montage");
Limites (“bounds”) et unités de mesure
Le script CleanupPasteboard a été étendu pour localiser sélectivement les objets situés au-delà du fond perdu, de la ligne-bloc, ou bien d'un périmètre quelconque défini par sa distance aux bords de page (« custom offset »). Ce dernier paramètre offre la possibilité de poser un périmètre de sécurité par rapport aux limites géométriques de la page. Il s'ensuit que nous ne pouvons pas réutiliser tel quel notre algorithme de détection des objets retranchés sur la table de montage. Il nous faut un calcul plus fin, basé sur la position des objets vis-à-vis du périmètre considéré et tenant compte des valeurs saisies par l'utilisateur dans l'interface dialoguée (famille measurementEditboxes
) ainsi que des unités de mesure courantes (measurement units).
Bien qu'un objet Spread
puisse se voir comme l'union géométrique d'une ou plusieurs page(s), le DOM n'offre pas de propriété bounds
à ce niveau. Si vous avez besoin de connaître le périmètre total d'une planche, il est commode de prototyper une fonction d'appoint s'appuyant sur les limites (Page.bounds
) des pages situées aux extrémités de la planche :
Spread.prototype.bounds = MasterSpread.prototype.bounds = function() { // renvoie les limites [top,left,bottom,right] de cette planche var bFirst = this.pages.item(0).bounds; // perimetre de la premiere page var bLast = this.pages.item(-1).bounds; // perimetre de la derniere page return [ bFirst[0], bFirst[1], bLast[2], bLast[3] ]; } // utilisation: alert( app.activeWindow.activeSpread.bounds() );
Notre script s'inspire de cette approche (cf. extraBounds
dans la méthode Document.prototype.cleanout
), à ceci près que le paramètre offset est injecté dans le calcul afin d'obtenir directement le périmètre de travail.
Signalons aux scripters une particularité importante de la propriété bounds
: les valeurs qu'elle retourne sont exprimées dans les unités de mesure en vigueur dans l'interface, soit verticalMeasurementUnits
pour top/bottom et horizontalMeasurementUnits
pour left/right. (Au niveau des composants de la famille PageItems
, il en va de même des propriétés geometricBounds
et visibleBounds
.) Cependant, les contrôles MeasurementEditbox
(ou MeasurementCombobox
) sollicités dans vos boîtes de dialogue suivent une logique particulière : ils affichent les données saisies (editContents
) dans l'unité spécifiée par leur propriété editUnits
, mais ils interprètent toujours en points la valeur résultante (editValue
). La question se pose souvent de savoir s'il vaut mieux travailler avec editContents
(chaîne de caractère) ou avec editValue
(nombre). Pour synchroniser les calculs impliquant des unités de mesure, on pourrait penser que editContents
est plus souple du fait qu'il permet de s'aligner sur les unités préférentielles de l'utilisateur. Cependant, s'il est en effet souhaitable d'afficher par défaut les informations dans l'unité attendue par l'utilisateur, le traitement des données via editContents
comporte certains risques, parce que cette chaîne est « localisée » (virgule décimale en français, point décimal en anglais) et peut introduire des difficultés de conversion. C'est pourquoi il me paraît préférable de travailler malgré tout avec editValue
, sous réserve de traduire cette mesure numérique (en points) vers l'unité désirée.
Pour ce faire, il vous suffit de mettre en place un mécanisme générique de conversion à l'aide de la classe UnitValue
fournie par le noyau JavaScript. Voici une approche possible :
var UNITS = (function() { var r={}, mu=MeasurementUnits; r[mu.AGATES]='agt'; r[mu.CENTIMETERS]='cm'; r[mu.CICEROS]='ci'; r[mu.INCHES]='in'; r[mu.INCHES_DECIMAL]='in'; r[mu.MILLIMETERS]='mm'; r[mu.PICAS]='pc'; r[mu.POINTS]='pt'; return(r); })(); // convertir myPointsValue (pts) vers myMeasurementUnits var uv = UnitValue(myPointsValue, 'pt'); var convertedValue = uv.as(UNITS[myMeasurementUnits]);
Le script CleanupPasteboard illustre cette logique dans la méthode ViewPreference.prototype.toOffsets()
.
CleanupPasteboard Demo
Comments
Bonjour et merci pour ce script.
Je suis toujours sous CS3, est-il possible d'adapter ce sript ?
Merci
Bonjour edfred,
Pour faire tourner le script sous CS3, je pense qu'il suffit de remplacer les deux dernières lignes:
app.doScript('app.main();', ScriptLanguage.javascript,
undefined, UndoModes.entireScript, app.activeScript.displayName);
par:
app.main();
Dites-moi si ça marche. (Avec cette modif, vous perdez seulement la faculté d'annuler globalement l'action effectuée par le script.)
Marc
Bonsoir Marc, merci pour la modification, ça fonctionne parfaitement.
Bonne fin de semaine et bon W-E.
[MàJ] La version 1.10 du script est désormais rétrocompatible avec ID CS3; et l'interface commute en langue française chez les utilisateurs francophones.
Que demander de plus, merci Marc. ;)
Bonjour Marc,
Je me joins à Edfred pour te remercier de cette MàJ, en particulier pour l'interface française.
Merci à tous deux. C'est en forgeant qu'on devient forgeron.
@+
Marc
Bonjour Marc,
Bath…
Salut Marc, il semblerait que le script ne fonctionne pas avec ma version de CS4!!? Seul les blocs à gauche des pages sont supprimés..??! Les valeurs négatives ne sont pas supportées non plus. J'ai essayé avec les pages en vis-à-vis (et sans vis-à-vis aussi). J'ai également essayé avec des blocs vides, des blocs couleurs... avec des photos dans les blocs(ça plante).
Je suis sous OS 10.4.11 et Indesign 6.04
Merci pour tout tes autres scripts plus utiles les uns que les autres ;
++
Steph
Merci, Steph, pour ton feedback. Je te contacte par email, on va essayer de voir d'où ça vient.
@+
Marc
[MàJ] La version 1.11 de CleanupPasteboard corrige le bug signalé par Steph (v. ci-dessus). Le script original ne prenait pas en considération les préférences d'origine (Origine par page vs Origine par planche). Et comme beaucoup d'utilisateurs optent pour l'origine par planche, ce bug était passé inaperçu jusqu'alors.
Au passage, petit correctif d'interface pour les utilisateurs Mac francophones qui obtenaient des caractères accentués erratiques.
Pensez à télécharger la version mise à jour!
Hi Marc,
Thank you for this script. Would it be difficult to batch a folder or all opened documents at once?
Thanks again
Hi eugen_v
> Would it be difficult to batch a folder
> or all opened documents at once?
No, it really wouldn't, especially with the “all opened documents” scope.
In the Application.prototype.main function, you mainly just need to transform:
var doc = this.activeDocument;
to a LOOP within the `this.documents` collection. Something like this:
var doc, offsets;
for( var i=this.documents.length-1 ; i>=0 ; i--)
{
doc = this.documents[i];
offsets = ( ui.choice > 1 ) ?
doc.viewPreferences.toOffsets(ui.customOffset) :
doc.documentPreferences.bsOffsets(ui.choice);
// cleanup
doc.cleanOut(offsets, ui.parseMaster);
}
Très bon!
Fantastic.
The in-depth explanation is illuminating!
Bonjour,
Est-il possible de changé la couleur du "fond perdu" avec avec javascript? et quelle est la commande? Merci.