Aller au contenu principal
Recette numéro 175

Recettes · Chapitre 5 · Structure du livre

Un guide de musée dont les liens s’impriment en codes QR

Une promenade de poche dans un musée dont les liens web s’impriment en notes numérotées en bas de page, avec adresse courte et code QR (links.print à notes).

  • Exemple en anglais : pas encore d’édition française
  • Format 160 × 240 mm
  • 1 colonne
  • Newsreader 10,2/14
  • Archivo
  • Instrument Serif
  • 7 pages
  • Niveau
  • Postext 1.65.0
  • Mis en page en 167 ms
  • 177 lignes de code

En bref

Un petit guide imprimé de cinq tableaux. Là où le texte cite une page web, un petit numéro renvoie au bas de la page, où un code carré ouvre cette page sur le téléphone.

Ce que vous allez composer

Un guide de poche des salles hollandaises du Metropolitan Museum of Art : cinq tableaux, une heure à pied, un tableau par page. La couverture est la jeune femme de Vermeer à la fenêtre, coupée par le bord supérieur. Chaque étape s’ouvre sur le numéro de salle, le titre et le peintre, puis le tableau avec son cartel à côté, puis trois courts paragraphes. Le texte renvoie au catalogue du musée comme le ferait n’importe quelle page web. Sur papier, chaque lien devient un petit numéro, et en bas de page la note donne l’adresse courte et un code QR que le visiteur vise avec son téléphone devant le tableau.

Cette recette répond à

  • Comment imprimer les adresses web des liens d’un livre, en notes numérotées ou en codes QR que le lecteur peut scanner ?

La réponse courte

script.js · lignes 39–50dans le code complet
const links = {
  print: 'notes', // a note marker after the link text, the address in a note at the foot
  show: 'both', // the short address for reading, the code for the phone
  urlDisplay: 'short', // metmuseum.org/art/collection/search/436616: no https://, no www.
  repeat: 'first', // an address noted once is cited again by its number, never noted twice
  qr: { size: mm(16), side: 'start', gap: em(1.2), color: col('ink') },
};
// Link notes are footnotes: they take the note style and the numbering below. 'document'
// numbers them through the walk, so the five stops print notes 3 to 7, not five notes 1.
const footnotes = { placement: 'column', numbering: 'document', fontSize: pt(8),
  lineHeight: pt(10.5), color: col('muted'), spaceAbove: pt(LEAD), spaceBetween: pt(5),
  separator: { enabled: true, width: 0.18, lineWidth: pt(0.5), color: col('rule') } };

Ingrédients

Typographie
Newsreader, Instrument Serif, Archivo (SIL OFL 1.1)
Ressources
  • hals-1200.jpg
  • rembrandt-1200.jpg
  • ruisdael-1400.jpg
  • steen-1200.jpg
  • vermeer-1600.jpg
  • vermeer-cover-1800.jpg
  • Johannes Vermeer, Young Woman with a Water Pitcher, about 1662 (the cover, cropped) (The Metropolitan Museum of Art, CC0 1.0)
  • Frans Hals, Young Man and Woman in an Inn, 1623 (stop 1) (The Metropolitan Museum of Art, CC0 1.0)
  • Jan Steen, Merry Company on a Terrace, about 1670 (stop 2) (The Metropolitan Museum of Art, CC0 1.0)
  • Rembrandt, Aristotle with a Bust of Homer, 1653 (stop 3) (The Metropolitan Museum of Art, CC0 1.0)
  • Johannes Vermeer, Young Woman with a Water Pitcher, about 1662 (stop 4) (The Metropolitan Museum of Art, CC0 1.0)
  • Jacob van Ruisdael, Wheat Fields, about 1670 (stop 5) (The Metropolitan Museum of Art, CC0 1.0)

Préparation

#1 · Écrire des liens, imprimer des notes

Le code est la réponse courte ci-dessus. Le Markdown garde des liens ordinaires, [La fiche du catalogue](https://www.metmuseum.org/…/436616), et links.print: 'notes' change chacun en note numérotée avec l’adresse et le code (liens sur papier). Ces notes sont des notes de bas de page : numbering: 'document' les compte sur toute la promenade, le lecteur rencontre donc les notes 1 à 7, et repeat: 'first' laisse la dernière étape citer le Hals par sa note 3 au lieu d’imprimer deux fois le même code. Dans le PDF, le code est dessiné en vectoriel et forme lui-même un lien.

Le bas de l’étape 1 : la note 3, la fiche du tableau en adresse courte à côté d’un code de 16 mm.

#2 · Une étape par page

script.js · lignes 74–82dans le code complet
const stop = { enabled: true, minHeight: pt(4 * LEAD), slot: { elements: [
    { kind: 'text', id: 'stop', content: '{attr.stop}', ...caps(7.5), color: col('delft'),
      align: 'left', placement: at('container', 'top-left', 0, 0) },
    { kind: 'text', id: 'title', content: '{titleText}', fontFamily: DISPLAY, fontSize: pt(22),
      lineHeight: 1.05, color: col('ink'), align: 'left', placement: at('#stop', 'below', 0, 1.6) },
    { kind: 'text', id: 'artist', content: '{attr.artist}', fontFamily: TEXT, italic: true,
      fontSize: pt(10.5), color: col('muted'), align: 'left',
      placement: at('#title', 'below', 0, 0.8) },
  ] } };

Chaque étape est un titre de second niveau dont le breakBefore ouvre une page, paire ou impaire : le visiteur tourne un feuillet par tableau. Le numéro de salle et le peintre sont des attributs du titre ; le dessin les place au-dessus et au-dessous du titre, et minHeight met le tableau à la même hauteur sur toutes les pages.

#3 · Le cartel à côté du tableau

script.js · lignes 219–259dans le code complet
// Paintings are not numbered: their own type, with no caption prefix and no number.
const paintingType = { id: 'painting', name: t({ en: 'Painting', es: 'Cuadro' }),
  shortLabel: t({ en: 'painting', es: 'cuadro' }), captionPrefix: '', numberingTemplate: '',
  resetOn: 'never', counterFormat: 'decimal' };
// Set where the ::resource line stands, under the stop's heading; caption and note beside it.
const HERE = { position: 'here', captionSide: 'inside' };
const cm = (n) => (LANG === 'es' ? String(n).replace('.', ',') : String(n)); // decimal comma
// The wall label: medium, size in cm (no-break spaces) and the museum's credit line.
const painting = (id, w, h, [cmH, cmW], credit, alt, width = 0.5) => ({
  id, typeId: 'painting', kind: 'bitmap', createdAt: 0, updatedAt: 0, placement: { ...HERE, width },
  bitmap: { fileId: `${id}-${Math.max(w, h)}.jpg`, format: 'jpeg', width: w, height: h },
  caption: `${OIL}, ${cm(cmH)}\u00a0×\u00a0${cm(cmW)}\u00a0cm. ${credit}`, altText: alt,
  note: 'The Metropolitan Museum of Art, Open Access (CC0)' });
const OIL = t({ en: 'Oil on canvas', es: 'Óleo sobre lienzo' });
const ALTMAN = t({ en: 'Bequest of Benjamin Altman, 1913', es: 'Legado de Benjamin Altman, 1913' });
const resources = [
  painting('hals', 908, 1200, [105.4, 79.4], `${ALTMAN} (14.40.602)`, t({
    en: 'A laughing young man raises a glass; a young woman leans on his shoulder.',
    es: 'Un joven ríe y alza una copa; una joven se apoya en su hombro.' }), 0.4), // portrait
  painting('steen', 1115, 1200, [141, 131.4], 'Fletcher Fund, 1958 (58.89)', t({
    en: 'A crowded party under a vine, with a lute player, a child and a dog.',
    es: 'Una fiesta concurrida bajo una parra, con un laudista, un niño y un perro.' })),
  painting('rembrandt', 1139, 1200, [143.5, 136.5], t({
    en: 'Purchase, special contributions and funds given or bequeathed by friends of the Museum',
    es: 'Compra con aportaciones y fondos donados o legados por amigos del Museo' })
    + ', 1961 (61.198)', t({ en: 'A bearded man in a black hat rests his hand on a marble bust.',
    es: 'Un hombre barbado con sombrero negro apoya la mano en un busto de mármol.' })),
  painting('vermeer', 1422, 1600, [45.7, 40.6], t({ en: 'Marquand Collection, gift of',
    es: 'Colección Marquand, donación de' }) + ' Henry G. Marquand, 1889 (89.15.21)', t({
    en: 'A young woman at an open window holds a gilt pitcher over a basin.',
    es: 'Una joven junto a una ventana abierta sujeta una jarra dorada sobre una jofaina.' })),
  painting('ruisdael', 1400, 1084, [100, 130.2], `${ALTMAN} (14.40.623)`, t({
    en: 'A sandy road between wheat fields under a tall bank of cloud.',
    es: 'Un camino de arena entre campos de trigo bajo un alto banco de nubes.' }), 0.6),
  // The cover: the Vermeer cut to the box's 4 : 3 (160 × 120 mm), since the opener fits a
  // picture inside its box. Drawn by the cover design, never cited.
  { ...painting('vermeer-cover', 1800, 1350, [], '', t({
    en: 'Detail of Vermeer’s young woman at the window, in blue and white.',
    es: 'Detalle de la joven de Vermeer junto a la ventana, en azul y blanco.' })),
  caption: '', note: '' },
];

captionSide: 'inside' place la légende et sa note de crédit à côté du tableau, comme un musée accroche son cartel, et width donne à chaque tableau sa part de la justification : moins au Hals, qui est haut, plus au Ruisdael, qui est en largeur, si bien que les cinq pages gardent une hauteur de texte voisine. Le cartel réunit la technique, les dimensions en centimètres avec des espaces insécables et la ligne de crédit du musée, avec une virgule décimale dans l’édition espagnole.

#4 · L’étape dans le titre courant

script.js · lignes 86–96dans le code complet
const head = (id, content, parity, edge, x, extra = {}) => ({
  kind: 'text', id, content, parity, pages: 'body', ...caps(7, 600), color: col('muted'),
  placement: at('page', edge, x, 13), ...extra,
});
const folio = { ...caps(8, 700), color: col('ink') };
const header = { elements: [
  head('verso-folio', '{pageNumber}', 'even', 'top-left', OUTER, folio),
  head('verso-title', '{title}', 'even', 'top-left', OUTER + 9),
  head('recto-stop', '{firstMark.h2}', 'odd', 'top-right', -(OUTER + 9)),
  head('recto-folio', '{pageNumber}', 'odd', 'top-right', -OUTER, folio),
] };

{firstMark.h2} imprime le titre de l’étape qui commence sur la page : la belle page nomme le tableau, la fausse page le guide. Aucun titre courant n’atteint la couverture, une page dont le rôle est celui d’ouverture.

La recette complète

Sandbox
// ═══ Postext Cookbook · Nº 175 · A museum walk whose links print as QR notes ═════
// https://postext.dev/en/cookbook/museum-guide-qr-link-notes
// Code: MIT · Text: original (CC BY 4.0) · Paintings: The Metropolitan Museum of Art (CC0)
// Fonts: Newsreader, Instrument Serif, Archivo (SIL OFL 1.1) · Needs postext ≥ 1.65.0
// A pocket gallery guide: five paintings, one to a page. The Markdown writes the museum's
// catalogue pages as ordinary links; the print edition turns each one into a numbered note at
// the foot of the page, with the short address and a code a phone can scan.
import {
  buildDocumentWithFonts, renderPageToCanvas, registerResourceImage,
} from 'https://esm.sh/postext';
import { renderToPdf, decompressWoff2 } from 'https://esm.sh/postext-pdf';

const LANG = 'en'; // @lang: the language of the sample document ('en' | 'es')
const RECIPE = 'museum-guide-qr-link-notes';

// ─── 1 · Design ─────────────────────────────────────────────────────────────
// #region palette: Delft blue on warm paper, every colour linked by id
const palette = {
  ink: '#1f1d1a', // text: a warm near-black
  delft: '#2b4a7a', // the one accent: kickers, stop numbers, rules (8.6:1 on paper)
  rule: '#c6c9cf', // hairlines
  muted: '#5f6168', // running heads, notes, credits (6.1:1 on paper)
  paper: '#ffffff',
};
const col = (id) => ({ hex: palette[id], model: 'hex', paletteId: id });
const colorPalette = [
  ...Object.entries(palette).map(([id, hex]) => ({ id, name: id, value: { hex, model: 'hex' } })),
  // The engine's defaults link to main-color: point it at the accent, so nothing prints blue.
  { id: 'main-color', name: 'delft (defaults)', value: { hex: palette.delft, model: 'hex' } },
];
// #endregion
const TRIM = { w: 160, h: 240 }; // a large pocket guide, in mm
const TOP = 22; // top margin in mm: the cover's container starts here
const OUTER = 22; // outer margin in mm: folios and running heads align to it
const LEAD = 14; // body leading in pt: the baseline grid
const [TEXT, DISPLAY, LABEL] = ['Newsreader', 'Instrument Serif', 'Archivo']; // three voices

// #region answer: every web link of the guide prints as a numbered note with a code to scan
const links = {
  print: 'notes', // a note marker after the link text, the address in a note at the foot
  show: 'both', // the short address for reading, the code for the phone
  urlDisplay: 'short', // metmuseum.org/art/collection/search/436616: no https://, no www.
  repeat: 'first', // an address noted once is cited again by its number, never noted twice
  qr: { size: mm(16), side: 'start', gap: em(1.2), color: col('ink') },
};
// Link notes are footnotes: they take the note style and the numbering below. 'document'
// numbers them through the walk, so the five stops print notes 3 to 7, not five notes 1.
const footnotes = { placement: 'column', numbering: 'document', fontSize: pt(8),

Le script.js composé s’exécute tel quel : collez-le dans le script de module de n’importe quelle page, ou ouvrez la recette sur CodePen. Dossier de la recette sur GitHub ↗ (s’ouvre dans un nouvel onglet)

Variantes

#Imprimer l’adresse dans la ligne

Pour un guide lu chez soi, 'inline' ajoute l’adresse entre parenthèses après le texte du lien, sans note ni code.

-  print: 'notes', // a note marker after the link text, the address in a note at the foot
-  show: 'both', // the short address for reading, the code for the phone
+  print: 'inline', // (metmuseum.org/…) after the link text

#Des codes sans adresse

show: 'qr' imprime le code seul à côté du numéro de note, pour une affiche ou un cartel où l’adresse ne ferait que prendre de la place.

-  show: 'both', // the short address for reading, the code for the phone
+  show: 'qr', // the code alone

Erreurs fréquentes

Une note avec code est au moins aussi haute que le code. Quand la ligne qui porte le lien n’a pas la place de sa note en dessous sur la page, la ligne passe à la suivante avec sa note : gardez les liens hors des dernières lignes d’une page qui doit finir là où elle finit, comme le premier paragraphe de la couverture de ce guide.

Crédits

Texte
Texte original, CC BY 4.0
Images
Polices
Newsreader (SIL OFL 1.1) · Instrument Serif (SIL OFL 1.1) · Archivo (SIL OFL 1.1)
SandboxPDF