本文へスキップ
レシピ番号175

レシピ集 · 第5章 · 本の構成

リンクを QR コードとして印刷する美術館ガイド

ウェブのリンクをページ下の番号付きの注にし、短いアドレスと QR コードを添えるポケット美術館ガイド。links.print を notes にして組む。

このページの内容
出力
Canvas · PDF
レベル
中級
Postext
Postext 1.65.0で検証済み
1.65.0以上が必要 · postext-pdf ≥ 1.65.0
ライセンス
2026年10月31日更新
コードMIT · 本文CC BY 4.0

1ページ(全7ページ)

  • 英語の見本:日本語版はまだありません
  • 仕上がり160 × 240 mm
  • 1段
  • Newsreader 10.2/14
  • Archivo
  • Instrument Serif
  • 7ページ
  • レベル
  • Postext 1.65.0
  • 組版時間167 ms
  • コード177行

かんたんな説明

5 点の絵を案内する小さな印刷ガイド。本文がウェブページに触れるところには小さな番号があり、ページの下の四角いコードをスマートフォンで読むとそのページが開く。

できあがり

メトロポリタン美術館のオランダ絵画の展示室をめぐるポケットガイド。5 点の絵を 1 時間で歩き、1 ページに 1 点を載せる。表紙はフェルメールの窓辺の若い女性で、絵は紙の上端で断ち切られている。各ストップは展示室番号、作品名、画家で始まり、その下に絵と横の作品ラベル、続いて短い 3 段落が来る。本文は美術館のカタログへ、ふつうのウェブページと同じようにリンクする。紙の上では各リンクが小さな番号になり、ページの下の注に短いアドレスと QR コードが入る。来館者は絵の前でスマートフォンをコードにかざす。

このレシピが答える質問

  • 本のリンクのウェブアドレスを、番号付きの注や読者が読み取れる QR コードとして印刷するには?

手短な答え

script.js · 39〜50行コード全体で見る
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') } };

材料

種類
Newsreader, Instrument Serif, Archivo (SIL OFL 1.1)
素材
  • 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)

作り方

#1 · リンクを書き、注を印刷する

コードは上の手短な答えにある。Markdown にはふつうのリンク [The catalogue entry](https://www.metmuseum.org/…/436616) を書き、links.print: 'notes' がそれぞれをアドレスとコード付きの番号注にする(印刷物でのリンク)。この注は脚注として扱われる。numbering: 'document' で散策全体に通し番号を振るので、読者が見るのは 1 から 7 まで。repeat: 'first' により、最後のストップはハルスの絵を注 3 の番号で引き、同じコードを 2 度印刷しない。PDF ではコードがベクターで描かれ、それ自体もリンクになる。

ストップ 1 のページ下。注 3 に、作品のカタログページの短いアドレスと 16 mm のコードが並ぶ。

#2 · 1 ストップを 1 ページに

script.js · 74〜82行コード全体で見る
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) },
  ] } };

各ストップは第 2 レベルの見出しで、breakBefore によって左右を問わず新しいページから始まる。来館者は絵ごとに 1 枚めくればよい。展示室番号と画家は見出しの属性で、デザインがそれを作品名の上と下に置く。minHeight によって、どのページでも絵が同じ高さから始まる。

#3 · 絵の横に作品ラベル

script.js · 219〜259行コード全体で見る
// 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' は、キャプションとクレジットの注を絵の横に置く。展示室の壁のラベルと同じ配置だ。width で絵ごとに版面の取り分を決める。縦長のハルスは少なめ、横長のロイスダールは多めにして、5 ページの本文の高さをそろえる。ラベルは技法、センチメートルの寸法(改行しないスペースでつなぐ)、美術館の収蔵の記載から組み立て、スペイン語版では小数点にコンマを使う。

#4 · 柱にストップ名を

script.js · 86〜96行コード全体で見る
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} は、そのページで始まるストップの作品名を印刷する。奇数ページには絵の名、偶数ページにはガイドの名が入る。表紙は扉の役割のページなので、柱は出ない。

レシピの全体

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),

組み立てたscript.jsはそのまま動きます。任意のページのモジュールスクリプトに貼り付けるか、レシピをCodePenで開いてください。 GitHub上のレシピのフォルダー ↗ (新しいタブで開きます)

アレンジ

#アドレスを行内に印刷する

家で読むガイドなら、'inline' でリンクの文字の後ろに丸括弧でアドレスを加え、注もコードも付けない。

-  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

#アドレスなしのコード

show: 'qr' は注の番号の横にコードだけを印刷する。アドレスが場所を取るだけのポスターや作品ラベルに向く。

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

よくあるつまずき

コード付きの注は、少なくともコードと同じ高さになる。リンクを含む行の下に、そのページで注を置く余地がないと、その行は注と一緒に次のページへ移る。決まった位置で終わらせたいページでは、最後の数行にリンクを置かないこと。このガイドの表紙の最初の段落もそうしている。

クレジット

レシピ
Ignacio Ferro
本文
書き下ろしの文章, CC BY 4.0
画像
フォント
Newsreader (SIL OFL 1.1) · Instrument Serif (SIL OFL 1.1) · Archivo (SIL OFL 1.1)
SandboxPDF