mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-14 19:27:04 -04:00
780 lines
62 KiB
HTML
780 lines
62 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>PrintCraft Showcase</title>
|
||
<!--
|
||
PrintCraft Showcase: source for `cargo xtask demo-pdf`.
|
||
All prose in this file is original to the PrintCraft project.
|
||
Placeholders substituted by the xtask:
|
||
{{ASSETS}} file:// URL of the repository's assets/ directory
|
||
{{MANDELBROT_PNG}} data: URI of a procedurally generated PNG
|
||
Links to https://mark.printcraft.invalid/<kind>/<id> are *markers*: the xtask
|
||
converts the link rectangles Chrome emits for them into real PDF annotations
|
||
(highlight, sticky note, stamp, ...), so annotation geometry follows the layout.
|
||
-->
|
||
<style>
|
||
@font-face { font-family: "PC Inter"; src: url("{{ASSETS}}/fonts/Inter-Regular.ttf"); font-weight: 400; }
|
||
@font-face { font-family: "PC Inter"; src: url("{{ASSETS}}/fonts/Inter-Medium.ttf"); font-weight: 500; }
|
||
@font-face { font-family: "PC Inter"; src: url("{{ASSETS}}/fonts/Inter-SemiBold.ttf"); font-weight: 600 900; }
|
||
@font-face { font-family: "PC Mono"; src: url("{{ASSETS}}/fonts/JetBrainsMono-Regular.ttf"); }
|
||
|
||
@page { size: Letter; margin: 0; }
|
||
|
||
:root {
|
||
--ink: #16213b;
|
||
--ink-2: #4a5268;
|
||
--ink-3: #7b8196;
|
||
--paper: #fbf8f2;
|
||
--rule: #e2dccf;
|
||
--accent: #e4572e;
|
||
--blue: #2a6fdb;
|
||
--teal: #1a9e8f;
|
||
--gold: #e9a100;
|
||
--serif: "Hoefler Text", "Iowan Old Style", Baskerville, Georgia, serif;
|
||
--display: Didot, "Bodoni 72", "Hoefler Text", serif;
|
||
--sans: "Avenir Next", "PC Inter", system-ui, sans-serif;
|
||
--ui: system-ui, -apple-system, "PC Inter", sans-serif;
|
||
--mono: "PC Mono", Menlo, monospace;
|
||
}
|
||
|
||
* { box-sizing: border-box; }
|
||
html, body { margin: 0; padding: 0; }
|
||
body {
|
||
background: var(--paper);
|
||
color: var(--ink);
|
||
font-family: var(--serif);
|
||
font-size: 10.5pt;
|
||
line-height: 1.45;
|
||
-webkit-print-color-adjust: exact;
|
||
print-color-adjust: exact;
|
||
font-kerning: normal;
|
||
text-rendering: optimizeLegibility;
|
||
}
|
||
|
||
.page {
|
||
position: relative;
|
||
width: 8.5in;
|
||
height: 11in;
|
||
padding: 0.8in 0.85in 0.9in;
|
||
overflow: hidden;
|
||
break-after: page;
|
||
background: var(--paper);
|
||
}
|
||
.page:last-child { break-after: auto; }
|
||
|
||
a { color: var(--blue); text-decoration: none; }
|
||
a.mk { color: inherit; }
|
||
|
||
/* running header and folio */
|
||
.runhead {
|
||
position: absolute; top: 0.42in; left: 0.85in; right: 0.85in;
|
||
display: flex; justify-content: space-between;
|
||
font: 500 7pt var(--sans); letter-spacing: 0.18em; text-transform: uppercase;
|
||
color: var(--ink-3);
|
||
border-bottom: 0.5pt solid var(--rule); padding-bottom: 4pt;
|
||
}
|
||
.folio {
|
||
position: absolute; bottom: 0.45in; left: 0.85in; right: 0.85in;
|
||
display: flex; justify-content: space-between; align-items: baseline;
|
||
font: 400 8pt var(--sans); color: var(--ink-3);
|
||
}
|
||
.folio b { font: 600 9pt var(--sans); color: var(--ink); font-feature-settings: "lnum", "tnum"; }
|
||
|
||
/* section openers */
|
||
.kicker {
|
||
font: 600 7.5pt var(--sans); letter-spacing: 0.24em; text-transform: uppercase;
|
||
color: var(--accent); margin: 0 0 6pt;
|
||
}
|
||
h1, h2, h3 { font-weight: normal; margin: 0; }
|
||
h2.sec {
|
||
font-family: var(--display); font-size: 34pt; line-height: 1.02;
|
||
letter-spacing: -0.01em; margin: 0 0 10pt;
|
||
}
|
||
h2.sec em { font-style: italic; color: var(--accent); }
|
||
.dek {
|
||
font: italic 13pt/1.4 var(--serif); color: var(--ink-2);
|
||
max-width: 5.4in; margin: 0 0 18pt;
|
||
}
|
||
h3 {
|
||
font: 600 8pt var(--sans); letter-spacing: 0.16em; text-transform: uppercase;
|
||
color: var(--ink); margin: 16pt 0 6pt;
|
||
}
|
||
.rule { height: 0.5pt; background: var(--rule); margin: 14pt 0; }
|
||
.caption { font: 400 7.5pt/1.4 var(--sans); color: var(--ink-3); margin-top: 5pt; }
|
||
.caption b { color: var(--ink-2); font-weight: 600; }
|
||
small, .small { font-size: 8pt; }
|
||
|
||
/* ---------- cover ---------- */
|
||
.cover { background: #0f1830; color: #f6f1e7; padding: 0; }
|
||
.cover svg.bg { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||
.cover .inner { position: absolute; left: 0.9in; right: 0.9in; top: 1.05in; bottom: 0.9in; }
|
||
.cover .edition {
|
||
font: 600 8pt var(--sans); letter-spacing: 0.4em; text-transform: uppercase; color: #f2c14e;
|
||
}
|
||
.cover h1 {
|
||
margin-top: 2.2in;
|
||
font-family: var(--display); font-weight: normal;
|
||
font-size: 88pt; line-height: 0.9; letter-spacing: -0.02em;
|
||
}
|
||
.cover h1 .it { font-style: italic; }
|
||
.cover .grad {
|
||
display: inline-block;
|
||
font: 700 30pt/1.1 var(--ui); letter-spacing: -0.01em;
|
||
background: linear-gradient(90deg, #f2c14e 0%, #f08a5d 45%, #e4572e 70%, #b83b5e 100%);
|
||
-webkit-background-clip: text; background-clip: text; color: transparent;
|
||
margin-top: 14pt;
|
||
}
|
||
.cover .sub {
|
||
margin-top: 18pt; max-width: 4.6in;
|
||
font: italic 14pt/1.45 var(--serif); color: #d9d3c7;
|
||
}
|
||
.cover .meta {
|
||
position: absolute; bottom: 0; left: 0; right: 0;
|
||
display: flex; justify-content: space-between; align-items: flex-end;
|
||
font: 500 8pt/1.5 var(--sans); letter-spacing: 0.08em; color: #a9b0c4;
|
||
border-top: 0.5pt solid rgba(246,241,231,0.25); padding-top: 10pt;
|
||
}
|
||
.cover .meta strong { color: #f6f1e7; font-weight: 600; letter-spacing: 0.2em; text-transform: uppercase; }
|
||
|
||
/* ---------- contents ---------- */
|
||
.toc { list-style: none; padding: 0; margin: 24pt 0 0; counter-reset: toc; }
|
||
.toc li {
|
||
display: grid; grid-template-columns: 0.55in 1fr auto; align-items: baseline;
|
||
padding: 5.5pt 0; border-bottom: 0.5pt solid var(--rule);
|
||
}
|
||
.toc .n { font: 400 20pt var(--display); color: var(--accent); font-feature-settings: "lnum"; }
|
||
.toc a { color: var(--ink); }
|
||
.toc .t { font: 400 14pt var(--serif); }
|
||
.toc .d { display: block; font: italic 9.5pt var(--serif); color: var(--ink-3); margin-top: 1pt; }
|
||
.toc .p { font: 600 10pt var(--sans); color: var(--ink-2); font-feature-settings: "tnum"; }
|
||
.colophon {
|
||
position: absolute; left: 0.85in; right: 0.85in; bottom: 1.05in;
|
||
display: grid; grid-template-columns: 1fr 1fr; gap: 24pt;
|
||
font: 400 8pt/1.5 var(--sans); color: var(--ink-2);
|
||
}
|
||
.colophon h4 { font: 600 7pt var(--sans); letter-spacing: 0.2em; text-transform: uppercase; color: var(--ink); margin: 0 0 4pt; }
|
||
|
||
/* ---------- foreword ---------- */
|
||
.foreword p { font-size: 12pt; line-height: 1.55; text-align: justify; hyphens: auto; margin: 0 0 9pt; }
|
||
.foreword p.lead::first-line { font-variant-caps: small-caps; letter-spacing: 0.06em; font-feature-settings: "smcp"; }
|
||
.signoff { font: 26pt "Snell Roundhand", "Apple Chancery", cursive; color: var(--ink); margin-top: 8pt; }
|
||
.tracking { margin-top: 18pt; }
|
||
.tracking div { font: 500 11pt var(--sans); text-transform: uppercase; color: var(--ink-2); padding: 3pt 0; border-bottom: 0.5pt dotted var(--rule); display: flex; justify-content: space-between; }
|
||
.tracking span.v { font: 400 7pt var(--mono); color: var(--ink-3); letter-spacing: 0; text-transform: none; }
|
||
|
||
/* ---------- body text ---------- */
|
||
.cols {
|
||
column-count: 2; column-gap: 0.32in; column-rule: 0.5pt solid var(--rule);
|
||
text-align: justify; hyphens: auto; -webkit-hyphens: auto;
|
||
font-feature-settings: "kern", "liga", "onum";
|
||
}
|
||
.cols p { margin: 0; text-indent: 1.2em; }
|
||
.cols p.first { text-indent: 0; }
|
||
.cols p.first::first-letter {
|
||
float: left; font-family: var(--display); font-size: 52pt; line-height: 0.82;
|
||
padding: 3pt 5pt 0 0; color: var(--accent);
|
||
}
|
||
.cols p.first::first-line { font-variant: small-caps; letter-spacing: 0.04em; }
|
||
.pull {
|
||
column-span: all; margin: 12pt 0.4in; padding: 10pt 0;
|
||
border-top: 1.5pt solid var(--ink); border-bottom: 0.5pt solid var(--ink);
|
||
font: italic 18pt/1.3 var(--serif); text-align: center; color: var(--ink);
|
||
font-feature-settings: "dlig", "swsh";
|
||
text-indent: 0;
|
||
}
|
||
.pull cite { display: block; font: 600 7pt var(--sans); font-style: normal; letter-spacing: 0.2em; text-transform: uppercase; color: var(--accent); margin-top: 6pt; }
|
||
sup.fn { font: 600 6.5pt var(--sans); color: var(--accent); vertical-align: super; line-height: 0; }
|
||
.footnotes {
|
||
position: absolute; left: 0.85in; right: 0.85in; bottom: 0.85in;
|
||
border-top: 0.5pt solid var(--ink-3); padding-top: 6pt; width: 2.2in;
|
||
}
|
||
.footnotes-body { position: absolute; left: 0.85in; right: 0.85in; bottom: 0.82in; font: 7.5pt/1.45 var(--serif); color: var(--ink-2); columns: 2; column-gap: 0.32in; }
|
||
.footnotes-body p { margin: 0 0 3pt; }
|
||
.footnotes-body b { font: 600 6.5pt var(--sans); color: var(--accent); }
|
||
|
||
/* ---------- specimen tables (OpenType) ---------- */
|
||
.spec { width: 100%; border-collapse: collapse; }
|
||
.spec td { padding: 7pt 6pt; border-bottom: 0.5pt solid var(--rule); vertical-align: baseline; }
|
||
.spec td.tag { font: 500 8pt var(--mono); color: var(--accent); width: 0.55in; white-space: nowrap; }
|
||
.spec td.lbl { font: 400 7.5pt/1.3 var(--sans); color: var(--ink-3); width: 1.15in; }
|
||
.spec td.off, .spec td.on { font-family: "Hoefler Text", serif; font-size: 17pt; line-height: 1.15; }
|
||
.spec td.off { color: var(--ink-3); }
|
||
.spec th { font: 600 6.5pt var(--sans); letter-spacing: 0.2em; text-transform: uppercase; color: var(--ink-3); text-align: left; padding: 0 6pt 4pt; }
|
||
.weights { display: grid; grid-template-columns: repeat(9, 1fr); gap: 2pt; margin-top: 6pt; }
|
||
.weights div { text-align: center; font: 26pt var(--ui); line-height: 1.1; }
|
||
.weights span { display: block; font: 400 6.5pt var(--mono); color: var(--ink-3); }
|
||
.scriptline { font: 30pt/1.25 "Snell Roundhand", cursive; color: var(--ink); }
|
||
.scriptline2 { font: 22pt/1.3 "Apple Chancery", cursive; color: var(--accent); }
|
||
|
||
/* ---------- expressive ---------- */
|
||
.fx-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14pt 22pt; }
|
||
.fx { border: 0.5pt solid var(--rule); border-radius: 6pt; padding: 12pt 14pt 10pt; background: #fffdf8; position: relative; overflow: hidden; height: 1.35in; }
|
||
.fx .caption { position: absolute; bottom: 8pt; left: 14pt; right: 14pt; }
|
||
.shadow { font: 800 40pt var(--ui); color: #fffdf8; letter-spacing: -0.02em; text-shadow: 3pt 3pt 0 rgba(228,87,46,0.55), 6pt 6pt 0 rgba(42,111,219,0.35), 0 0 1pt rgba(22,33,59,0.9); }
|
||
.gradtext { display: inline-block; padding-right: 4pt; font: 800 42pt/1 var(--ui); letter-spacing: -0.03em; background: linear-gradient(120deg, #2a6fdb, #1a9e8f 40%, #e9a100 70%, #e4572e); -webkit-background-clip: text; background-clip: text; color: transparent; }
|
||
.rot { position: absolute; top: 18pt; right: 18pt; transform: rotate(-12deg); font: 700 13pt var(--sans); color: #fff; background: var(--accent); padding: 3pt 10pt; letter-spacing: 0.2em; }
|
||
.skew { display: inline-block; transform: skewX(-18deg); font: 700 28pt var(--sans); background: var(--ink); color: var(--paper); padding: 2pt 14pt; }
|
||
.vert-stack { font: 600 9pt var(--sans); letter-spacing: 0.3em; writing-mode: vertical-rl; transform: rotate(180deg); position: absolute; left: 12pt; top: 12pt; color: var(--teal); text-transform: uppercase; }
|
||
.outline-text { font: 800 38pt var(--ui); color: transparent; -webkit-text-stroke: 1pt var(--ink); letter-spacing: 0.02em; }
|
||
.tracked { font: 400 9pt var(--sans); letter-spacing: 0.6em; text-transform: uppercase; color: var(--ink-2); }
|
||
|
||
/* ---------- scripts ---------- */
|
||
.scripts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10pt; }
|
||
.sc { border-top: 1.5pt solid var(--ink); padding: 6pt 0 0; }
|
||
.sc .nm { font: 600 6.8pt var(--sans); letter-spacing: 0.2em; text-transform: uppercase; color: var(--ink-3); display: flex; justify-content: space-between; }
|
||
.sc .nm i { font-style: normal; color: var(--accent); letter-spacing: 0.05em; }
|
||
.sc .tx { font-size: 14pt; line-height: 1.35; margin-top: 3pt; }
|
||
.sc .en { font: italic 8pt var(--serif); color: var(--ink-3); margin-top: 2pt; }
|
||
.jp-block {
|
||
writing-mode: vertical-rl; font: 15pt/1.7 "Hiragino Mincho ProN", serif; height: 2.7in;
|
||
border-right: 3pt solid var(--accent); padding-right: 8pt; color: var(--ink);
|
||
}
|
||
.jp-wrap { display: flex; gap: 18pt; align-items: flex-start; }
|
||
.emoji { font: 24pt/1.2 "Apple Color Emoji", sans-serif; letter-spacing: 4pt; }
|
||
|
||
/* ---------- math ---------- */
|
||
math { font-family: "STIX Two Math", math; font-size: 15pt; }
|
||
.eqs { display: grid; grid-template-columns: 1fr 1fr; gap: 12pt 24pt; }
|
||
.eq { border-left: 2pt solid var(--teal); padding: 6pt 0 6pt 14pt; }
|
||
.eq .caption { margin-top: 6pt; }
|
||
.eq math[display="block"] { margin: 4pt 0; }
|
||
|
||
/* ---------- graphics ---------- */
|
||
.gfx { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16pt 14pt; }
|
||
.gfx figure { margin: 0; }
|
||
.gfx svg { width: 100%; height: auto; display: block; border-radius: 4pt; }
|
||
.blend { position: relative; height: 1.5in; background: #fffdf8; border-radius: 4pt; border: 0.5pt solid var(--rule); overflow: hidden; }
|
||
.blend div { position: absolute; width: 0.95in; height: 0.95in; border-radius: 50%; }
|
||
.blend .a { background: #e4572e; left: 0.35in; top: 0.12in; mix-blend-mode: multiply; }
|
||
.blend .b { background: #1a9e8f; left: 0.8in; top: 0.12in; mix-blend-mode: multiply; }
|
||
.blend .c { background: #e9a100; left: 0.575in; top: 0.5in; mix-blend-mode: multiply; }
|
||
.blend.dark { background: #16213b; }
|
||
.blend.dark div { mix-blend-mode: screen; }
|
||
.blend.dark .a { background: #d0352a; } .blend.dark .b { background: #2fae3f; } .blend.dark .c { background: #2a6fdb; }
|
||
|
||
/* ---------- data ---------- */
|
||
table.data { width: 100%; border-collapse: collapse; font: 400 8.5pt var(--sans); }
|
||
table.data thead th { text-align: left; font: 600 7pt var(--sans); letter-spacing: 0.14em; text-transform: uppercase; color: #fff; background: var(--ink); padding: 6pt 8pt; }
|
||
table.data td { padding: 5pt 8pt; border-bottom: 0.5pt solid var(--rule); }
|
||
table.data tbody tr:nth-child(even) td { background: #f1ece2; }
|
||
table.data td.num { text-align: right; font-feature-settings: "tnum", "lnum"; }
|
||
.pill { display: inline-block; font: 600 6.5pt var(--sans); letter-spacing: 0.1em; text-transform: uppercase; padding: 1.5pt 6pt; border-radius: 8pt; }
|
||
.pill.ok { background: #d8efe9; color: #0f6b5f; }
|
||
.pill.part { background: #fbeccc; color: #8a5a00; }
|
||
.pill.plan { background: #e3e8f5; color: #2b4a8f; }
|
||
.charts { display: grid; grid-template-columns: 1fr 1fr; gap: 20pt; }
|
||
.charts svg { width: 100%; height: auto; display: block; }
|
||
.chart-title { font: 600 9pt var(--sans); color: var(--ink); margin: 0 0 2pt; }
|
||
.chart-sub { font: 400 7.5pt var(--sans); color: var(--ink-3); margin: 0 0 6pt; }
|
||
|
||
/* ---------- code ---------- */
|
||
pre.code {
|
||
font: 8.2pt/1.55 var(--mono); background: #121a2e; color: #d7dcea; border-radius: 6pt;
|
||
padding: 12pt 14pt; margin: 0; white-space: pre; overflow: hidden;
|
||
font-variant-ligatures: none; counter-reset: ln;
|
||
}
|
||
pre.code .ln { color: #4d5877; display: inline-block; width: 1.6em; }
|
||
.k { color: #ff8f6b; } .ty { color: #6fd3c6; } .s { color: #f2c14e; } .c { color: #7c87a6; font-style: italic; } .f { color: #8fb4ff; } .n { color: #d6a6ff; } .m { color: #ffb86b; }
|
||
.imgrow { display: grid; grid-template-columns: 2.6in 1fr; gap: 18pt; align-items: start; margin-top: 16pt; }
|
||
.imgrow img { width: 2.6in; height: 2.6in; border-radius: 6pt; display: block; }
|
||
.links li { margin-bottom: 4pt; }
|
||
|
||
/* ---------- review ---------- */
|
||
.review { display: grid; grid-template-columns: 3.3in 1fr; gap: 26pt; }
|
||
.review p { font-size: 11pt; line-height: 1.7; margin: 0 0 10pt; text-align: left; }
|
||
.canvas { position: relative; height: 6.3in; border: 0.5pt dashed var(--ink-3); border-radius: 6pt; background:
|
||
radial-gradient(circle, #d9d2c3 0.6pt, transparent 0.7pt) 0 0 / 12pt 12pt; }
|
||
.canvas .lab { position: absolute; font: 600 6.5pt var(--sans); letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-3); }
|
||
a.box { position: absolute; display: block; color: transparent; font-size: 1pt; }
|
||
.legend-list { font: 400 8pt/1.6 var(--sans); color: var(--ink-2); columns: 2; padding-left: 12pt; margin: 8pt 0 0; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- ============================ 1. COVER ============================ -->
|
||
<section class="page cover" id="cover">
|
||
<svg class="bg" viewBox="0 0 612 792" preserveAspectRatio="none" aria-hidden="true">
|
||
<defs>
|
||
<radialGradient id="glowA" cx="0.78" cy="0.22" r="0.55">
|
||
<stop offset="0" stop-color="#e4572e" stop-opacity="0.85"/>
|
||
<stop offset="1" stop-color="#e4572e" stop-opacity="0"/>
|
||
</radialGradient>
|
||
<radialGradient id="glowB" cx="0.15" cy="0.95" r="0.6">
|
||
<stop offset="0" stop-color="#2a6fdb" stop-opacity="0.8"/>
|
||
<stop offset="1" stop-color="#2a6fdb" stop-opacity="0"/>
|
||
</radialGradient>
|
||
<linearGradient id="band" x1="0" y1="0" x2="1" y2="1">
|
||
<stop offset="0" stop-color="#f2c14e"/>
|
||
<stop offset="1" stop-color="#1a9e8f"/>
|
||
</linearGradient>
|
||
<pattern id="dots" width="14" height="14" patternUnits="userSpaceOnUse">
|
||
<circle cx="2" cy="2" r="0.9" fill="#f6f1e7" fill-opacity="0.18"/>
|
||
</pattern>
|
||
</defs>
|
||
<rect width="612" height="792" fill="#0f1830"/>
|
||
<rect width="612" height="792" fill="url(#glowA)"/>
|
||
<rect width="612" height="792" fill="url(#glowB)"/>
|
||
<rect x="330" y="0" width="282" height="330" fill="url(#dots)"/>
|
||
<g style="mix-blend-mode:screen" opacity="0.9">
|
||
<circle cx="470" cy="190" r="92" fill="none" stroke="url(#band)" stroke-width="1.2"/>
|
||
<circle cx="470" cy="190" r="70" fill="none" stroke="#f6f1e7" stroke-opacity="0.35" stroke-width="0.6" stroke-dasharray="2 5"/>
|
||
<circle cx="510" cy="230" r="46" fill="#e4572e" fill-opacity="0.55"/>
|
||
<circle cx="440" cy="240" r="34" fill="#2a6fdb" fill-opacity="0.6"/>
|
||
</g>
|
||
<path d="M0 640 C 160 590, 320 700, 612 610 L 612 792 L 0 792 Z" fill="#0b1226" fill-opacity="0.55"/>
|
||
</svg>
|
||
<div class="inner">
|
||
<div class="edition">Specimen · Volume One</div>
|
||
<h1>Print<span class="it">Craft</span><br>Showcase</h1>
|
||
<div class="grad">A tour of the page, glyph by glyph.</div>
|
||
<p class="sub">Typography, world scripts, vector graphics, mathematics, forms and annotations — gathered in one document to put a PDF engine through its paces.</p>
|
||
<div class="meta">
|
||
<div><strong>PrintCraft</strong><br>Open-source PDF toolkit in Rust</div>
|
||
<div style="text-align:right">Generated by <span style="font-family:var(--mono)">cargo xtask demo-pdf</span><br>US Letter · 8.5 × 11 in</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============================ 2. CONTENTS ============================ -->
|
||
<section class="page" id="contents">
|
||
<div class="runhead"><span>PrintCraft Showcase</span><span>Contents</span></div>
|
||
<div class="kicker">Inside this specimen</div>
|
||
<h2 class="sec">Contents</h2>
|
||
<ol class="toc">
|
||
<li><span class="n">1</span><a href="#setting"><span class="t">Setting Text</span><span class="d">Columns, justification, hyphenation, drop caps and notes</span></a><span class="p">1</span></li>
|
||
<li><span class="n">2</span><a href="#opentype"><span class="t">OpenType Features</span><span class="d">Ligatures, small capitals, figures, fractions, swashes, weights</span></a><span class="p">2</span></li>
|
||
<li><span class="n">3</span><a href="#expressive"><span class="t">Expressive Type</span><span class="d">Shadows, gradients, rotation, skew and text on a path</span></a><span class="p">3</span></li>
|
||
<li><span class="n">4</span><a href="#scripts"><span class="t">Scripts of the World</span><span class="d">Right-to-left, complex shaping, vertical CJK and emoji</span></a><span class="p">4</span></li>
|
||
<li><span class="n">5</span><a href="#math"><span class="t">Mathematics</span><span class="d">MathML Core set in STIX Two Math</span></a><span class="p">5</span></li>
|
||
<li><span class="n">6</span><a href="#vector"><span class="t">Vector Graphics</span><span class="d">Shadings, blend modes, clipping, masks and patterns</span></a><span class="p">6</span></li>
|
||
<li><span class="n">7</span><a href="#data"><span class="t">Data & Tables</span><span class="d">Charts and a striped feature matrix</span></a><span class="p">7</span></li>
|
||
<li><span class="n">8</span><a href="#code"><span class="t">Code & Images</span><span class="d">A syntax-coloured listing and a generated raster</span></a><span class="p">8</span></li>
|
||
<li><span class="n">9</span><a href="#review"><span class="t">Review & Markup</span><span class="d">Every common annotation type, with appearance streams</span></a><span class="p">9</span></li>
|
||
<li><span class="n">10</span><span><span class="t">Interactive Form</span><span class="d">AcroForm fields written directly by the xtask</span></span><span class="p">10</span></li>
|
||
</ol>
|
||
<div class="colophon">
|
||
<div><h4>Colophon</h4>Body text is set in Hoefler Text with Didot for display, Avenir Next and Inter for labels, and JetBrains Mono for code. Layout is authored in HTML and CSS, printed by headless Chrome, then post-processed with <span style="font-family:var(--mono)">lopdf</span>.</div>
|
||
<div><h4>What to look for</h4>Open the bookmarks, layers, attachments and comments panels. Page labels run Cover, i–ii, then 1–10. One layer adds a draft watermark; another holds print-only notes and starts hidden.</div>
|
||
</div>
|
||
<div class="folio"><span>PrintCraft Showcase</span><b>i</b></div>
|
||
</section>
|
||
|
||
<!-- ============================ 3. FOREWORD ============================ -->
|
||
<section class="page foreword" id="foreword">
|
||
<div class="runhead"><span>PrintCraft Showcase</span><span>Foreword</span></div>
|
||
<div class="kicker">Foreword</div>
|
||
<h2 class="sec">Why a <em>specimen?</em></h2>
|
||
<p class="lead">A PDF reader is judged in the first second. The page appears, and either the letters sit on it the way the author intended or they do not. Every kerning pair, every ligature and every soft gradient is a small promise the file makes and the renderer must keep.</p>
|
||
<p>This document collects those promises in one place. It was written for the people who build PrintCraft, as a single file to open after every change: if all of it still looks right, the change is probably safe. It is also, we hope, pleasant to read on its own.</p>
|
||
<p>Nothing here is exotic. Each feature is something ordinary documents use every day — an invoice with a form field, a thesis full of equations, a contract with comments in the margin, a brochure with a translucent photograph laid over a tinted panel. What is unusual is only that they are all together, and that each page says plainly what it is testing.</p>
|
||
<p>The layout is authored in HTML and printed by a browser; the interactive parts are then written into the file by hand, object by object. That split mirrors the real world, where most PDFs are produced by one program and amended by several others.</p>
|
||
<div class="signoff">The PrintCraft contributors</div>
|
||
|
||
<h3>Tracking, from tight to airy</h3>
|
||
<div class="tracking">
|
||
<div style="letter-spacing:-0.04em">Measure twice, set once <span class="v">−40</span></div>
|
||
<div style="letter-spacing:0">Measure twice, set once <span class="v">0</span></div>
|
||
<div style="letter-spacing:0.12em">Measure twice, set once <span class="v">+120</span></div>
|
||
<div style="letter-spacing:0.3em">Measure twice <span class="v">+300</span></div>
|
||
</div>
|
||
<div class="folio"><span>Foreword</span><b>ii</b></div>
|
||
</section>
|
||
|
||
<!-- ============================ 4. SETTING TEXT ============================ -->
|
||
<section class="page" id="setting">
|
||
<div class="runhead"><span>PrintCraft Showcase</span><span>1 · Setting Text</span></div>
|
||
<div class="kicker">Chapter one</div>
|
||
<h2 class="sec" id="h-setting">Setting <em>Text</em></h2>
|
||
<p class="dek">Two justified columns with automatic hyphenation, old-style figures, a drop cap and a pull quote — the everyday machinery of a well-made page.</p>
|
||
<div class="cols">
|
||
<p class="first">Long before there were screens, a page of type was a negotiation between the width of a column and the length of the words that had to fill it. The compositor adjusted spaces, divided a word at a sensible syllable, and occasionally rewrote a line so the paragraph would lie flat. Justified text asks for exactly that care, and <a class="mk" href="https://mark.printcraft.invalid/highlight/body">a renderer must honour the spacing it was given</a>.<sup class="fn">1</sup></p>
|
||
<p>A PDF does not reflow. Every glyph has already been placed by the program that wrote the file, and the reader’s job is to reproduce those positions faithfully at any zoom. That sounds simple until one remembers that a single line may mix three fonts, a ligature standing in for two letters, and a hyphen that exists only because the line happened to break there in 1994 or 2026.</p>
|
||
<p>Old-style figures, like the ones in this paragraph’s 1,280 characters and 36 lines, rise and fall with the lowercase so that numbers do not shout. Ligatures such as <i>fi</i>, <i>fl</i> and <i>ffi</i> in words like <i>officially</i>, <i>affluent</i> and <i>afflicted</i> join letters that would otherwise collide.<sup class="fn">2</sup></p>
|
||
<div class="pull">“The best typography is the kind you only notice when it is missing.”<cite>A working maxim of the trade</cite></div>
|
||
<p>Hyphenation is where browsers and word processors differ most. Chrome consults the system’s hyphenation dictionaries when a paragraph declares its language and asks for automatic hyphens, which is why the words in these columns occasionally divide across lines. The result is a more even texture, with fewer rivers of white running down the column.</p>
|
||
<p>Columns introduce their own questions: where to break, whether a heading may sit at the foot of one, and how a quotation spanning both should interrupt the flow. Here the pull quote spans the full measure and the text resumes beneath it, balanced between the two columns.</p>
|
||
<p>Small text matters too. Notes, captions and legal lines are often set at seven or eight points, where hinting, stem darkening and subpixel positioning decide whether a reader squints. The footnotes below are set at seven and a half points in the same face as the body.<sup class="fn">3</sup></p>
|
||
<p>Finally, notice the drop cap that opens this chapter. It is an ordinary letter, floated and enlarged, with the first line set in small capitals. A renderer need do nothing special for it, which is precisely the point: most typographic richness in a PDF is just careful placement of ordinary glyphs.</p>
|
||
</div>
|
||
<div class="footnotes"></div>
|
||
<div class="footnotes-body">
|
||
<p><b>1</b> Word spacing in PDF is usually baked into glyph positions rather than expressed with the word-spacing operator, so readers rarely need to stretch anything themselves.</p>
|
||
<p><b>2</b> In a PDF a ligature is a single glyph; text extraction relies on the font’s ToUnicode map to recover the letters it represents.</p>
|
||
<p><b>3</b> Try zooming to 400 percent here: well-rendered small text stays crisp and evenly weighted.</p>
|
||
</div>
|
||
<div class="folio"><span>Setting Text</span><b>1</b></div>
|
||
</section>
|
||
|
||
<!-- ============================ 5. OPENTYPE ============================ -->
|
||
<section class="page" id="opentype">
|
||
<div class="runhead"><span>PrintCraft Showcase</span><span>2 · OpenType Features</span></div>
|
||
<div class="kicker">Chapter two</div>
|
||
<h2 class="sec" id="h-opentype">OpenType <em>Features</em></h2>
|
||
<p class="dek">Each row shows the same text with a feature off, then on. The glyphs differ; the underlying characters do not.</p>
|
||
<table class="spec">
|
||
<tr><th>Tag</th><th>Feature</th><th>Off</th><th>On</th></tr>
|
||
<tr><td class="tag">liga</td><td class="lbl">Standard ligatures</td><td class="off" style="font-feature-settings:'liga' 0">office fluffy fjord</td><td class="on" style="font-feature-settings:'liga' 1">office fluffy fjord</td></tr>
|
||
<tr><td class="tag">dlig</td><td class="lbl">Discretionary ligatures</td><td class="off">Asterisk & strict</td><td class="on" style="font-feature-settings:'dlig' 1">Asterisk & strict</td></tr>
|
||
<tr><td class="tag">smcp</td><td class="lbl">Small capitals</td><td class="off">Printed in Boston</td><td class="on" style="font-feature-settings:'smcp' 1">Printed in Boston</td></tr>
|
||
<tr><td class="tag">onum</td><td class="lbl">Old-style figures</td><td class="off" style="font-feature-settings:'lnum' 1">Since 1885: 3,467,920</td><td class="on" style="font-feature-settings:'onum' 1">Since 1885: 3,467,920</td></tr>
|
||
<tr><td class="tag">frac</td><td class="lbl">Fractions</td><td class="off" style="font-family:var(--ui)">1/2 cup, 3/4 inch, 7/8</td><td class="on" style="font-family:var(--ui);font-feature-settings:'frac' 1">1/2 cup, 3/4 inch, 7/8</td></tr>
|
||
<tr><td class="tag">swsh</td><td class="lbl">Swash capitals</td><td class="off" style="font-style:italic">The Quiet River</td><td class="on" style="font-style:italic;font-feature-settings:'swsh' 1">The Quiet River</td></tr>
|
||
<tr><td class="tag">ss01</td><td class="lbl">Stylistic set 1</td><td class="off" style="font-family:'PC Inter'">a 1 4 6 9 G ?</td><td class="on" style="font-family:'PC Inter';font-feature-settings:'ss01' 1">a 1 4 6 9 G ?</td></tr>
|
||
<tr><td class="tag">kern</td><td class="lbl">Kerning</td><td class="off" style="font-kerning:none;font-family:var(--sans)">AVATAR Type Wave</td><td class="on" style="font-kerning:normal;font-family:var(--sans)">AVATAR Type Wave</td></tr>
|
||
<tr><td class="tag">tnum</td><td class="lbl">Tabular figures</td><td class="off" style="font-family:var(--ui);font-feature-settings:'pnum' 1">1111 / 8888</td><td class="on" style="font-family:var(--ui);font-feature-settings:'tnum' 1">1111 / 8888</td></tr>
|
||
</table>
|
||
|
||
<h3>One variable font, nine weights</h3>
|
||
<div class="weights">
|
||
<div style="font-weight:100">Ag<span>100</span></div>
|
||
<div style="font-weight:200">Ag<span>200</span></div>
|
||
<div style="font-weight:300">Ag<span>300</span></div>
|
||
<div style="font-weight:400">Ag<span>400</span></div>
|
||
<div style="font-weight:500">Ag<span>500</span></div>
|
||
<div style="font-weight:600">Ag<span>600</span></div>
|
||
<div style="font-weight:700">Ag<span>700</span></div>
|
||
<div style="font-weight:800">Ag<span>800</span></div>
|
||
<div style="font-weight:900">Ag<span>900</span></div>
|
||
</div>
|
||
<p class="caption"><b>System UI</b> · a single variable font file supplies every weight; the PDF embeds each instance as its own subset.</p>
|
||
|
||
<h3>Script faces</h3>
|
||
<div class="scriptline">Handsome letters, joined in flight</div>
|
||
<div class="scriptline2">Quietly Ornamental — 1234567890</div>
|
||
<div class="folio"><span>OpenType Features</span><b>2</b></div>
|
||
</section>
|
||
|
||
<!-- ============================ 6. EXPRESSIVE ============================ -->
|
||
<section class="page" id="expressive">
|
||
<div class="runhead"><span>PrintCraft Showcase</span><span>3 · Expressive Type</span></div>
|
||
<div class="kicker">Chapter three</div>
|
||
<h2 class="sec" id="h-expressive">Expressive <em>Type</em></h2>
|
||
<p class="dek">Effects that become transparency groups, soft masks, clipping paths and transformed text objects once they reach PDF.</p>
|
||
<div class="fx-grid">
|
||
<div class="fx"><div class="shadow">Layered</div><div class="caption"><b>text-shadow</b> · two translucent offset copies composited under the glyphs</div></div>
|
||
<div class="fx"><div class="gradtext">Spectrum</div><div class="caption"><b>background-clip: text</b> · a linear shading clipped to glyph outlines</div></div>
|
||
<div class="fx"><div style="margin-top:22pt"><span class="skew">Skewed</span></div><div class="rot">Rotated</div><div class="caption"><b>transform</b> · skewX(−18°) on a filled box and rotate(−12°) on a label</div></div>
|
||
<div class="fx"><div class="outline-text">Outline</div><div class="tracked" style="margin-top:4pt">Tracked to 600</div><div class="caption"><b>-webkit-text-stroke</b> · glyphs stroked, not filled (render mode 1)</div></div>
|
||
</div>
|
||
|
||
<h3>Text on a curve</h3>
|
||
<svg viewBox="0 0 520 170" style="width:100%;height:auto;display:block" aria-label="Text following a curved path">
|
||
<defs>
|
||
<path id="wave" d="M20 140 C 120 20, 220 20, 270 90 S 420 160, 500 40"/>
|
||
<linearGradient id="waveGrad" x1="0" x2="1">
|
||
<stop offset="0" stop-color="#2a6fdb"/><stop offset="0.5" stop-color="#1a9e8f"/><stop offset="1" stop-color="#e4572e"/>
|
||
</linearGradient>
|
||
</defs>
|
||
<use href="#wave" fill="none" stroke="#e2dccf" stroke-width="14" stroke-linecap="round"/>
|
||
<use href="#wave" fill="none" stroke="#16213b" stroke-width="0.6" stroke-dasharray="3 4"/>
|
||
<text font-family="Hoefler Text, serif" font-size="22" font-style="italic" fill="url(#waveGrad)" dy="-10">
|
||
<textPath href="#wave" startOffset="4%">Letters can follow any path the designer draws — up, over, and away</textPath>
|
||
</text>
|
||
</svg>
|
||
<p class="caption"><b>SVG textPath</b> · each glyph is positioned and rotated individually along a cubic Bézier, filled with a gradient.</p>
|
||
|
||
<h3>Hierarchy through contrast</h3>
|
||
<div style="display:grid;grid-template-columns:1.4fr 1fr;gap:20pt;align-items:end">
|
||
<div style="font:italic 400 32pt/1 var(--display);letter-spacing:-0.02em">Contrast is the<br><span style="font:800 32pt/1 var(--ui);font-style:normal;letter-spacing:-0.04em;color:var(--accent)">engine</span> of design.</div>
|
||
<div style="font:10pt/1.5 var(--serif);color:var(--ink-2)">Pair a hairline Didot italic with a heavy grotesque and the eye knows where to go. The PDF sees only two fonts and a handful of positioning operators; the hierarchy is entirely in the choices.</div>
|
||
</div>
|
||
<div class="folio"><span>Expressive Type</span><b>3</b></div>
|
||
</section>
|
||
|
||
<!-- ============================ 7. SCRIPTS ============================ -->
|
||
<section class="page" id="scripts">
|
||
<div class="runhead"><span>PrintCraft Showcase</span><span>4 · Scripts of the World</span></div>
|
||
<div class="kicker">Chapter four</div>
|
||
<h2 class="sec" id="h-scripts">Scripts of the <em>World</em></h2>
|
||
<p class="dek">A short greeting — roughly, “every letter deserves a good home” — in writing systems that need bidirectional layout, contextual shaping, reordering and vertical setting.</p>
|
||
<div style="display:grid;grid-template-columns:1fr 1.25in;gap:18pt">
|
||
<div class="scripts">
|
||
<div class="sc" lang="ar" dir="rtl"><div class="nm" dir="ltr">Arabic <i>RTL · joining</i></div><div class="tx" style="font-family:'Geeza Pro'">لكل حرف بيت جميل</div><div class="en" dir="ltr">Geeza Pro</div></div>
|
||
<div class="sc" lang="he" dir="rtl"><div class="nm" dir="ltr">Hebrew <i>RTL</i></div><div class="tx" style="font-family:'SF Hebrew','Arial Hebrew',sans-serif">לכל אות יש בית טוב</div><div class="en" dir="ltr">SF Hebrew</div></div>
|
||
<div class="sc" lang="hi"><div class="nm">Devanagari <i>conjuncts</i></div><div class="tx" style="font-family:'Kohinoor Devanagari'">हर अक्षर का सुंदर घर</div><div class="en">Kohinoor Devanagari</div></div>
|
||
<div class="sc" lang="th"><div class="nm">Thai <i>no spaces</i></div><div class="tx" style="font-family:Thonburi,sans-serif">ทุกตัวอักษรมีบ้านที่ดี</div><div class="en">Thonburi</div></div>
|
||
<div class="sc" lang="el"><div class="nm">Greek <i>polytonic</i></div><div class="tx" style="font-family:'Hoefler Text',serif">Κάθε γράμμα ἔχει σπίτι</div><div class="en">Hoefler Text</div></div>
|
||
<div class="sc" lang="ru"><div class="nm">Cyrillic</div><div class="tx" style="font-family:Baskerville,serif">У каждой буквы есть дом</div><div class="en">Baskerville</div></div>
|
||
<div class="sc" lang="zh-Hans"><div class="nm">Chinese <i>simplified</i></div><div class="tx" style="font-family:'PingFang SC','Hiragino Sans GB',sans-serif">每个字都有一个好家</div><div class="en">PingFang SC</div></div>
|
||
<div class="sc" lang="ko"><div class="nm">Korean <i>Hangul</i></div><div class="tx" style="font-family:'Apple SD Gothic Neo',sans-serif">모든 글자에게 좋은 집을</div><div class="en">Apple SD Gothic Neo</div></div>
|
||
<div class="sc"><div class="nm">IPA <i>phonetics</i></div><div class="tx" style="font-family:'Charis SIL','Hoefler Text','Times New Roman',serif">/ˈtaɪpˌsɛtɪŋ ɪz ˈkræft/</div><div class="en">International Phonetic Alphabet</div></div>
|
||
<div class="sc" lang="hy"><div class="nm">Armenian</div><div class="tx" style="font-family:'SF Armenian',sans-serif">Ամեն տառ ունի տուն</div><div class="en">SF Armenian</div></div>
|
||
<div class="sc" lang="ka"><div class="nm">Georgian</div><div class="tx" style="font-family:'SF Georgian',sans-serif">ყველა ასოს აქვს სახლი</div><div class="en">SF Georgian</div></div>
|
||
<div class="sc" lang="ta"><div class="nm">Tamil</div><div class="tx" style="font-family:'Tamil Sangam MN',sans-serif">ஒவ்வொரு எழுத்துக்கும் வீடு</div><div class="en">Tamil Sangam MN</div></div>
|
||
</div>
|
||
<div>
|
||
<div class="sc" lang="ja" style="border-top:none;padding:0"><div class="nm">Japanese <i>vertical</i></div>
|
||
<div class="jp-wrap" style="margin-top:6pt"><div class="jp-block">すべての文字に、<br>よい家を。<br>縦書きで読む。</div></div>
|
||
<div class="en" style="margin-top:6pt">Hiragino Mincho ProN, writing-mode: vertical-rl</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>Mixed direction in one line</h3>
|
||
<p style="font-size:12pt;margin:0">The word <span lang="ar" style="font-family:'Geeza Pro'">كتاب</span> means “book”, and <span lang="he" style="font-family:'SF Hebrew'">ספר</span> does too — the bidi algorithm keeps each run in its own direction while the sentence stays left-to-right, even across numbers like <span lang="ar" style="font-family:'Geeza Pro'">٣٤٥</span> and 345.</p>
|
||
|
||
<h3>Colour emoji</h3>
|
||
<div class="emoji">📄🖋️🎨📐🔍🌍🧮✅🦀📎</div>
|
||
<p class="caption"><b>Apple Color Emoji</b> · bitmap (sbix) glyphs that Chrome places into the PDF as images.</p>
|
||
<div class="folio"><span>Scripts of the World</span><b>4</b></div>
|
||
</section>
|
||
|
||
<!-- ============================ 8. MATH ============================ -->
|
||
<section class="page" id="math">
|
||
<div class="runhead"><span>PrintCraft Showcase</span><span>5 · Mathematics</span></div>
|
||
<div class="kicker">Chapter five</div>
|
||
<h2 class="sec" id="h-math"><em>Mathematics</em></h2>
|
||
<p class="dek">Equations written in MathML Core and laid out by the browser: stretchy delimiters, radicals, large operators, scripts and matrices.</p>
|
||
<div class="eqs">
|
||
<div class="eq">
|
||
<math display="block"><mi>x</mi><mo>=</mo><mfrac><mrow><mo>−</mo><mi>b</mi><mo>±</mo><msqrt><mrow><msup><mi>b</mi><mn>2</mn></msup><mo>−</mo><mn>4</mn><mi>a</mi><mi>c</mi></mrow></msqrt></mrow><mrow><mn>2</mn><mi>a</mi></mrow></mfrac></math>
|
||
<div class="caption"><b>Quadratic formula</b> · fraction, radical, superscript</div>
|
||
</div>
|
||
<div class="eq">
|
||
<math display="block"><msubsup><mo>∫</mo><mrow><mo>−</mo><mi>∞</mi></mrow><mi>∞</mi></msubsup><msup><mi>e</mi><mrow><mo>−</mo><msup><mi>x</mi><mn>2</mn></msup></mrow></msup><mspace width="0.17em"/><mi>d</mi><mi>x</mi><mo>=</mo><msqrt><mi>π</mi></msqrt></math>
|
||
<div class="caption"><b>Gaussian integral</b> · large operator with limits</div>
|
||
</div>
|
||
<div class="eq">
|
||
<math display="block"><msup><mi>e</mi><mrow><mi>i</mi><mi>π</mi></mrow></msup><mo>+</mo><mn>1</mn><mo>=</mo><mn>0</mn></math>
|
||
<div class="caption"><b>Euler’s identity</b> · five constants, one line</div>
|
||
</div>
|
||
<div class="eq">
|
||
<math display="block"><munderover><mo>∑</mo><mrow><mi>n</mi><mo>=</mo><mn>1</mn></mrow><mi>∞</mi></munderover><mfrac><mn>1</mn><msup><mi>n</mi><mn>2</mn></msup></mfrac><mo>=</mo><mfrac><msup><mi>π</mi><mn>2</mn></msup><mn>6</mn></mfrac></math>
|
||
<div class="caption"><b>Basel problem</b> · summation with under- and over-scripts</div>
|
||
</div>
|
||
<div class="eq">
|
||
<math display="block"><mi mathvariant="normal">R</mi><mo>(</mo><mi>θ</mi><mo>)</mo><mo>=</mo><mrow><mo>[</mo><mtable><mtr><mtd><mi>cos</mi><mi>θ</mi></mtd><mtd><mo>−</mo><mi>sin</mi><mi>θ</mi></mtd></mtr><mtr><mtd><mi>sin</mi><mi>θ</mi></mtd><mtd><mi>cos</mi><mi>θ</mi></mtd></mtr></mtable><mo>]</mo></mrow></math>
|
||
<div class="caption"><b>Rotation matrix</b> · the transform behind every rotated page</div>
|
||
</div>
|
||
<div class="eq">
|
||
<math display="block"><mi mathvariant="bold">B</mi><mo>(</mo><mi>t</mi><mo>)</mo><mo>=</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>0</mn></mrow><mn>3</mn></munderover><mrow><mo>(</mo><mfrac linethickness="0"><mn>3</mn><mi>i</mi></mfrac><mo>)</mo></mrow><msup><mrow><mo>(</mo><mn>1</mn><mo>−</mo><mi>t</mi><mo>)</mo></mrow><mrow><mn>3</mn><mo>−</mo><mi>i</mi></mrow></msup><msup><mi>t</mi><mi>i</mi></msup><msub><mi mathvariant="bold">P</mi><mi>i</mi></msub></math>
|
||
<div class="caption"><b>Cubic Bézier</b> · the curve PDF paths are made of</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>Inline mathematics</h3>
|
||
<p style="font-size:11.5pt;line-height:1.7;text-align:justify;hyphens:auto;margin:0">A PDF page maps user space to device space with a matrix <math><mrow><mo>[</mo><mi>a</mi><mspace width="0.2em"/><mi>b</mi><mspace width="0.2em"/><mi>c</mi><mspace width="0.2em"/><mi>d</mi><mspace width="0.2em"/><mi>e</mi><mspace width="0.2em"/><mi>f</mi><mo>]</mo></mrow></math>, so a point <math><mo>(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo>)</mo></math> lands at <math><mo>(</mo><mi>a</mi><mi>x</mi><mo>+</mo><mi>c</mi><mi>y</mi><mo>+</mo><mi>e</mi><mo>,</mo><mspace width="0.2em"/><mi>b</mi><mi>x</mi><mo>+</mo><mi>d</mi><mi>y</mi><mo>+</mo><mi>f</mi><mo>)</mo></math>. With one point equal to <math><mfrac><mn>1</mn><mn>72</mn></mfrac></math> inch, a Letter page measures <math><mn>612</mn><mo>×</mo><mn>792</mn></math> points, and a 300 dpi raster of it holds roughly <math><mn>8.4</mn><mo>×</mo><msup><mn>10</mn><mn>6</mn></msup></math> pixels.</p>
|
||
|
||
<h3>Symbols and arrows</h3>
|
||
<div style="font:17pt/1.5 'STIX Two Math',serif;letter-spacing:6pt;color:var(--ink-2)">∀ ∃ ∅ ∇ ∂ ∈ ∉ ⊂ ⊆ ∪ ∩ ≤ ≥ ≠ ≈ ≡ ∞ ℵ ℝ ℂ ℤ ℕ → ⇒ ⇔ ↦ ⟨ ⟩ ⌈ ⌉</div>
|
||
<div class="folio"><span>Mathematics</span><b>5</b></div>
|
||
</section>
|
||
|
||
<!-- ============================ 9. VECTOR ============================ -->
|
||
<section class="page" id="vector">
|
||
<div class="runhead"><span>PrintCraft Showcase</span><span>6 · Vector Graphics</span></div>
|
||
<div class="kicker">Chapter six</div>
|
||
<h2 class="sec" id="h-vector">Vector <em>Graphics</em></h2>
|
||
<p class="dek">Nine small plates, each exercising one piece of the PDF imaging model.</p>
|
||
<div class="gfx">
|
||
<figure>
|
||
<svg viewBox="0 0 160 120"><defs><linearGradient id="lg1" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#2a6fdb"/><stop offset="0.5" stop-color="#1a9e8f"/><stop offset="1" stop-color="#e9a100"/></linearGradient></defs><rect width="160" height="120" rx="6" fill="url(#lg1)"/></svg>
|
||
<figcaption class="caption"><b>Axial shading</b> · three-stop linear gradient</figcaption>
|
||
</figure>
|
||
<figure>
|
||
<svg viewBox="0 0 160 120"><defs><radialGradient id="rg1" cx="0.35" cy="0.35" r="0.75"><stop offset="0" stop-color="#fff5d6"/><stop offset="0.35" stop-color="#e9a100"/><stop offset="0.75" stop-color="#e4572e"/><stop offset="1" stop-color="#16213b"/></radialGradient></defs><rect width="160" height="120" rx="6" fill="#16213b"/><circle cx="80" cy="60" r="52" fill="url(#rg1)"/></svg>
|
||
<figcaption class="caption"><b>Radial shading</b> · off-centre focal point</figcaption>
|
||
</figure>
|
||
<figure>
|
||
<div class="blend"><div class="a"></div><div class="b"></div><div class="c"></div></div>
|
||
<figcaption class="caption"><b>Multiply</b> · subtractive overlaps, /BM /Multiply</figcaption>
|
||
</figure>
|
||
<figure>
|
||
<div class="blend dark"><div class="a"></div><div class="b"></div><div class="c"></div></div>
|
||
<figcaption class="caption"><b>Screen</b> · additive light, /BM /Screen</figcaption>
|
||
</figure>
|
||
<figure>
|
||
<svg viewBox="0 0 160 120"><defs><clipPath id="cp1"><text x="80" y="88" text-anchor="middle" font-family="Didot, serif" font-size="70" font-weight="bold">Clip</text></clipPath><linearGradient id="lg2" x1="0" x2="0" y1="0" y2="1"><stop offset="0" stop-color="#e4572e"/><stop offset="1" stop-color="#b83b5e"/></linearGradient></defs><rect width="160" height="120" rx="6" fill="#f1ece2"/><g clip-path="url(#cp1)"><rect width="160" height="120" fill="url(#lg2)"/><g stroke="#f2c14e" stroke-width="3">
|
||
<line x1="0" y1="10" x2="160" y2="130"/><line x1="0" y1="40" x2="160" y2="160"/><line x1="0" y1="-20" x2="160" y2="100"/><line x1="0" y1="-50" x2="160" y2="70"/></g></g></svg>
|
||
<figcaption class="caption"><b>Clipping path</b> · glyph outlines as a clip</figcaption>
|
||
</figure>
|
||
<figure>
|
||
<svg viewBox="0 0 160 120"><defs><linearGradient id="fade" x1="0" x2="1"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><mask id="m1"><rect width="160" height="120" fill="url(#fade)"/></mask></defs><rect width="160" height="120" rx="6" fill="#f1ece2"/><g mask="url(#m1)"><rect x="12" y="14" width="136" height="92" rx="8" fill="#2a6fdb"/><circle cx="60" cy="60" r="26" fill="#f2c14e"/><circle cx="104" cy="60" r="26" fill="#e4572e"/></g></svg>
|
||
<figcaption class="caption"><b>Soft mask</b> · luminosity gradient fades artwork</figcaption>
|
||
</figure>
|
||
<figure>
|
||
<svg viewBox="0 0 160 120"><rect width="160" height="120" rx="6" fill="#fffdf8" stroke="#e2dccf"/><g fill="none" stroke="#16213b" stroke-width="2.5"><path d="M16 26 H144" stroke-dasharray="12 6"/><path d="M16 46 H144" stroke-dasharray="2 6" stroke-linecap="round"/><path d="M16 66 H144" stroke-dasharray="18 5 3 5" stroke="#e4572e"/><path d="M16 96 Q 50 70 80 96 T 144 96" stroke="#1a9e8f" stroke-width="5" stroke-linejoin="round" stroke-dasharray="1 9" stroke-linecap="round"/></g></svg>
|
||
<figcaption class="caption"><b>Dash patterns</b> · caps, joins and phase</figcaption>
|
||
</figure>
|
||
<figure>
|
||
<svg viewBox="0 0 160 120"><defs><pattern id="checks" width="16" height="16" patternUnits="userSpaceOnUse"><rect width="16" height="16" fill="#f1ece2"/><rect width="8" height="8" fill="#16213b"/><rect x="8" y="8" width="8" height="8" fill="#16213b"/></pattern><pattern id="hatch" width="8" height="8" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"><rect width="8" height="8" fill="#fbeccc"/><line x1="0" y1="0" x2="0" y2="8" stroke="#e9a100" stroke-width="3"/></pattern></defs><rect width="160" height="120" rx="6" fill="url(#checks)"/><circle cx="80" cy="60" r="40" fill="url(#hatch)" stroke="#16213b" stroke-width="2"/></svg>
|
||
<figcaption class="caption"><b>Tiling patterns</b> · checks and rotated hatch</figcaption>
|
||
</figure>
|
||
<figure>
|
||
<svg viewBox="0 0 160 120"><rect width="160" height="120" rx="6" fill="#16213b"/><g transform="translate(80 60)"><g fill="none" stroke-width="1.2">
|
||
<path id="star" d="M0 -46 L13 -14 L46 -14 L19 6 L29 40 L0 20 L-29 40 L-19 6 L-46 -14 L-13 -14 Z" stroke="#f2c14e" fill="#f2c14e" fill-opacity="0.25" fill-rule="evenodd"/>
|
||
<path d="M0 -46 L27 37 L-44 -14 L44 -14 L-27 37 Z" stroke="#e4572e" fill="#e4572e" fill-opacity="0.45" fill-rule="evenodd"/></g></g></svg>
|
||
<figcaption class="caption"><b>Fill rules</b> · even-odd pentagram, 45% opacity</figcaption>
|
||
</figure>
|
||
</div>
|
||
<div class="rule"></div>
|
||
<svg viewBox="0 0 520 110" style="width:100%;height:auto;display:block">
|
||
<defs><linearGradient id="spec" x1="0" x2="1"><stop offset="0" stop-color="#16213b"/><stop offset="0.25" stop-color="#2a6fdb"/><stop offset="0.5" stop-color="#1a9e8f"/><stop offset="0.75" stop-color="#e9a100"/><stop offset="1" stop-color="#e4572e"/></linearGradient></defs>
|
||
<g style="mix-blend-mode:multiply">
|
||
<path d="M0 80 C 80 10, 160 110, 260 50 S 440 20, 520 70 L520 110 L0 110Z" fill="url(#spec)" opacity="0.85"/>
|
||
<path d="M0 95 C 100 40, 200 120, 300 70 S 460 60, 520 90 L520 110 L0 110Z" fill="#e4572e" opacity="0.5"/>
|
||
<path d="M0 60 C 120 100, 240 20, 360 80 S 480 40, 520 55" fill="none" stroke="#16213b" stroke-width="1.2" stroke-dasharray="4 3"/>
|
||
</g>
|
||
</svg>
|
||
<p class="caption"><b>Layered waves</b> · five-stop shading, 50% overlay in multiply mode, dashed stroke over the top.</p>
|
||
<div class="folio"><span>Vector Graphics</span><b>6</b></div>
|
||
</section>
|
||
|
||
<!-- ============================ 10. DATA ============================ -->
|
||
<section class="page" id="data">
|
||
<div class="runhead"><span>PrintCraft Showcase</span><span>7 · Data & Tables</span></div>
|
||
<div class="kicker">Chapter seven</div>
|
||
<h2 class="sec" id="h-data">Data & <em>Tables</em></h2>
|
||
<p class="dek">Charts drawn as SVG and a striped table. All figures are illustrative sample data, not measurements.</p>
|
||
<div class="charts">
|
||
<div>
|
||
<p class="chart-title">Pages per second, by document type</p>
|
||
<p class="chart-sub">Illustrative sample data · higher is better</p>
|
||
<svg viewBox="0 0 260 180" aria-label="Bar chart">
|
||
<g font-family="Avenir Next, sans-serif" font-size="7" fill="#7b8196">
|
||
<g stroke="#e2dccf" stroke-width="0.5"><line x1="30" x2="255" y1="150" y2="150" stroke="#7b8196"/><line x1="30" x2="255" y1="120" y2="120"/><line x1="30" x2="255" y1="90" y2="90"/><line x1="30" x2="255" y1="60" y2="60"/><line x1="30" x2="255" y1="30" y2="30"/></g>
|
||
<text x="24" y="152" text-anchor="end">0</text><text x="24" y="122" text-anchor="end">50</text><text x="24" y="92" text-anchor="end">100</text><text x="24" y="62" text-anchor="end">150</text><text x="24" y="32" text-anchor="end">200</text>
|
||
</g>
|
||
<g fill="#2a6fdb">
|
||
<path d="M40 150 V40.8 a4 4 0 0 1 4 -4 h22 a4 4 0 0 1 4 4 V150 Z"/>
|
||
<path d="M84 150 V70.8 a4 4 0 0 1 4 -4 h22 a4 4 0 0 1 4 4 V150 Z"/>
|
||
<path d="M128 150 V97.8 a4 4 0 0 1 4 -4 h22 a4 4 0 0 1 4 4 V150 Z"/>
|
||
<path d="M172 150 V112.2 a4 4 0 0 1 4 -4 h22 a4 4 0 0 1 4 4 V150 Z"/>
|
||
<path d="M216 150 V128.4 a4 4 0 0 1 4 -4 h22 a4 4 0 0 1 4 4 V150 Z"/>
|
||
</g>
|
||
<g font-family="Avenir Next, sans-serif" font-size="7.5" fill="#16213b" text-anchor="middle" font-weight="600">
|
||
<text x="55" y="32">189</text><text x="99" y="62">139</text><text x="143" y="89">94</text><text x="187" y="104">70</text><text x="231" y="120">43</text>
|
||
</g>
|
||
<g font-family="Avenir Next, sans-serif" font-size="7" fill="#4a5268" text-anchor="middle">
|
||
<text x="55" y="162">Text</text><text x="99" y="162">Forms</text><text x="143" y="162">Vector</text><text x="187" y="162">Scans</text><text x="231" y="162">Maps</text>
|
||
</g>
|
||
</svg>
|
||
</div>
|
||
<div>
|
||
<p class="chart-title">Renderer conformance over releases</p>
|
||
<p class="chart-sub">Illustrative sample data · % of test pages matching reference</p>
|
||
<svg viewBox="0 0 260 180" aria-label="Line chart">
|
||
<g font-family="Avenir Next, sans-serif" font-size="7" fill="#7b8196">
|
||
<g stroke="#e2dccf" stroke-width="0.5"><line x1="30" x2="220" y1="150" y2="150" stroke="#7b8196"/><line x1="30" x2="220" y1="120" y2="120"/><line x1="30" x2="220" y1="90" y2="90"/><line x1="30" x2="220" y1="60" y2="60"/><line x1="30" x2="220" y1="30" y2="30"/></g>
|
||
<text x="24" y="152" text-anchor="end">60</text><text x="24" y="122" text-anchor="end">70</text><text x="24" y="92" text-anchor="end">80</text><text x="24" y="62" text-anchor="end">90</text><text x="24" y="32" text-anchor="end">100</text>
|
||
<g text-anchor="middle" fill="#4a5268"><text x="36" y="162">0.1</text><text x="82" y="162">0.2</text><text x="128" y="162">0.3</text><text x="174" y="162">0.4</text><text x="214" y="162">0.5</text></g>
|
||
</g>
|
||
<g fill="none" stroke-width="2" stroke-linejoin="round" stroke-linecap="round">
|
||
<polyline stroke="#2a6fdb" points="36,108 82,84 128,63 174,48 214,39"/>
|
||
<polyline stroke="#1a9e8f" points="36,132 82,111 128,90 174,69 214,54"/>
|
||
<polyline stroke="#e4572e" points="36,144 82,135 128,117 174,93 214,75"/>
|
||
</g>
|
||
<g stroke="#fbf8f2" stroke-width="2">
|
||
<circle cx="214" cy="39" r="4" fill="#2a6fdb"/><circle cx="214" cy="54" r="4" fill="#1a9e8f"/><circle cx="214" cy="75" r="4" fill="#e4572e"/>
|
||
</g>
|
||
<g font-family="Avenir Next, sans-serif" font-size="7.5" fill="#16213b" font-weight="600">
|
||
<text x="222" y="41">Text 97</text><text x="222" y="56">Vector 92</text><text x="222" y="77">Forms 85</text>
|
||
</g>
|
||
</svg>
|
||
<div style="display:flex;gap:14pt;font:400 7.5pt var(--sans);color:var(--ink-2);margin:2pt 0 0 30pt">
|
||
<span><span style="display:inline-block;width:8pt;height:8pt;border-radius:2pt;background:#2a6fdb;vertical-align:-1pt"></span> Text</span>
|
||
<span><span style="display:inline-block;width:8pt;height:8pt;border-radius:2pt;background:#1a9e8f;vertical-align:-1pt"></span> Vector</span>
|
||
<span><span style="display:inline-block;width:8pt;height:8pt;border-radius:2pt;background:#e4572e;vertical-align:-1pt"></span> Forms</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style="margin-top:22pt">Where each PDF feature lives in this file</h3>
|
||
<table class="data">
|
||
<thead><tr><th>Feature</th><th>PDF object</th><th>Produced by</th><th>Page</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Embedded font subsets</td><td>/FontFile2, /FontFile3</td><td>Chrome</td><td class="num">all</td><td><span class="pill ok">Present</span></td></tr>
|
||
<tr><td>Tagged structure</td><td>/StructTreeRoot</td><td>Chrome</td><td class="num">all</td><td><span class="pill ok">Present</span></td></tr>
|
||
<tr><td>Axial & radial shadings</td><td>/ShadingType 2, 3</td><td>Chrome</td><td class="num">6</td><td><span class="pill ok">Present</span></td></tr>
|
||
<tr><td>Blend modes</td><td>/ExtGState /BM</td><td>Chrome</td><td class="num">6</td><td><span class="pill ok">Present</span></td></tr>
|
||
<tr><td>Bookmarks</td><td>/Outlines</td><td>Chrome, xtask</td><td class="num">—</td><td><span class="pill ok">Present</span></td></tr>
|
||
<tr><td>Page labels</td><td>/PageLabels</td><td>xtask</td><td class="num">—</td><td><span class="pill ok">Present</span></td></tr>
|
||
<tr><td>Optional content</td><td>/OCProperties</td><td>xtask</td><td class="num">9, 10</td><td><span class="pill part">Two layers</span></td></tr>
|
||
<tr><td>Annotations</td><td>/Annots with /AP</td><td>xtask</td><td class="num">1, 9, 10</td><td><span class="pill ok">Present</span></td></tr>
|
||
<tr><td>Form fields</td><td>/AcroForm</td><td>xtask</td><td class="num">10</td><td><span class="pill ok">Present</span></td></tr>
|
||
<tr><td>File attachments</td><td>/EmbeddedFiles</td><td>xtask</td><td class="num">—</td><td><span class="pill ok">Present</span></td></tr>
|
||
<tr><td>Digital signature</td><td>/FT /Sig</td><td>xtask</td><td class="num">10</td><td><span class="pill plan">Unsigned</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
<div class="folio"><span>Data & Tables</span><b>7</b></div>
|
||
</section>
|
||
|
||
<!-- ============================ 11. CODE ============================ -->
|
||
<section class="page" id="code">
|
||
<div class="runhead"><span>PrintCraft Showcase</span><span>8 · Code & Images</span></div>
|
||
<div class="kicker">Chapter eight</div>
|
||
<h2 class="sec" id="h-code">Code & <em>Images</em></h2>
|
||
<p class="dek">A monospaced listing with syntax colouring, and the raster that it describes.</p>
|
||
<pre class="code"><span class="ln">1</span><span class="c">// Escape-time rendering of the Mandelbrot set into an RGB buffer.</span>
|
||
<span class="ln">2</span><span class="k">fn</span> <span class="f">mandelbrot</span>(width: <span class="ty">u32</span>, height: <span class="ty">u32</span>) -> <span class="ty">Vec</span><<span class="ty">u8</span>> {
|
||
<span class="ln">3</span> <span class="k">let mut</span> rgb = <span class="ty">Vec</span>::<span class="f">with_capacity</span>((width * height * <span class="m">3</span>) <span class="k">as</span> <span class="ty">usize</span>);
|
||
<span class="ln">4</span> <span class="k">for</span> py <span class="k">in</span> <span class="m">0</span>..height {
|
||
<span class="ln">5</span> <span class="k">for</span> px <span class="k">in</span> <span class="m">0</span>..width {
|
||
<span class="ln">6</span> <span class="k">let</span> c = (<span class="m">-2.2</span> + <span class="m">3.0</span> * px <span class="k">as</span> <span class="ty">f64</span> / width <span class="k">as</span> <span class="ty">f64</span>,
|
||
<span class="ln">7</span> <span class="m">-1.5</span> + <span class="m">3.0</span> * py <span class="k">as</span> <span class="ty">f64</span> / height <span class="k">as</span> <span class="ty">f64</span>);
|
||
<span class="ln">8</span> <span class="k">let</span> (<span class="k">mut</span> z, <span class="k">mut</span> n) = ((<span class="m">0.0</span>, <span class="m">0.0</span>), <span class="m">0</span>);
|
||
<span class="ln">9</span> <span class="k">while</span> n < <span class="n">MAX_ITER</span> && z.<span class="m">0</span> * z.<span class="m">0</span> + z.<span class="m">1</span> * z.<span class="m">1</span> <= <span class="m">4.0</span> {
|
||
<span class="ln">10</span> z = (z.<span class="m">0</span> * z.<span class="m">0</span> - z.<span class="m">1</span> * z.<span class="m">1</span> + c.<span class="m">0</span>, <span class="m">2.0</span> * z.<span class="m">0</span> * z.<span class="m">1</span> + c.<span class="m">1</span>);
|
||
<span class="ln">11</span> n += <span class="m">1</span>;
|
||
<span class="ln">12</span> }
|
||
<span class="ln">13</span> rgb.<span class="f">extend_from_slice</span>(&<span class="f">palette</span>(n)); <span class="c">// smooth colour ramp</span>
|
||
<span class="ln">14</span> }
|
||
<span class="ln">15</span> }
|
||
<span class="ln">16</span> rgb
|
||
<span class="ln">17</span>}</pre>
|
||
<div class="imgrow">
|
||
<figure style="margin:0"><img src="{{MANDELBROT_PNG}}" alt="Procedurally generated Mandelbrot set"></figure>
|
||
<div>
|
||
<h3 style="margin-top:0">A generated raster</h3>
|
||
<p style="margin:0 0 8pt;font-size:10.5pt;text-align:justify;hyphens:auto">The image at left is computed by the xtask each time the showcase is built, encoded as PNG and handed to Chrome, which embeds it as an image XObject. Nothing is downloaded and no third-party artwork is involved, so the file stays reproducible and free to redistribute.</p>
|
||
<p style="margin:0 0 8pt;font-size:10.5pt;text-align:justify;hyphens:auto">At 60 dpi the fractal edge looks smooth; zoom in and the individual pixels appear, a useful check that the viewer switches from filtered to nearest-neighbour sampling at the right moment.</p>
|
||
<h3>Links</h3>
|
||
<ul class="links" style="padding-left:14pt;margin:0;font-size:10pt">
|
||
<li>External: <a href="https://example.com/">https://example.com/</a></li>
|
||
<li>External: <a href="https://example.org/printcraft">example.org/printcraft</a></li>
|
||
<li>Internal: back to <a href="#contents">the contents</a> or ahead to <a href="#review">review & markup</a></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="folio"><span>Code & Images</span><b>8</b></div>
|
||
</section>
|
||
|
||
<!-- ============================ 12. REVIEW ============================ -->
|
||
<section class="page" id="review">
|
||
<div class="runhead"><span>PrintCraft Showcase</span><span>9 · Review & Markup</span></div>
|
||
<div class="kicker">Chapter nine</div>
|
||
<h2 class="sec" id="h-review">Review & <em>Markup</em></h2>
|
||
<p class="dek">Every annotation on this page was added after printing, each with its own appearance stream, author, date and unique name.</p>
|
||
<div class="review">
|
||
<div>
|
||
<h3 style="margin-top:0">Text markup</h3>
|
||
<p>Reviewers rarely rewrite a document; they <a class="mk" href="https://mark.printcraft.invalid/highlight/review">highlight the phrase that matters</a>, <a class="mk" href="https://mark.printcraft.invalid/underline/review">underline a claim that needs a source</a>, and <a class="mk" href="https://mark.printcraft.invalid/strikeout/review">strike out a redundant word</a> before moving on.</p>
|
||
<p>A wavy line says <a class="mk" href="https://mark.printcraft.invalid/squiggly/review">check the spelling here</a>, while a caret marks where text should<a class="mk" href="https://mark.printcraft.invalid/caret/review"> </a>be inserted.</p>
|
||
<h3>Comments</h3>
|
||
<p>Sticky notes carry threaded replies, and a free-text box writes directly on the page. The paperclip holds an attached file that can be saved from the comment itself.</p>
|
||
<h3>Legend</h3>
|
||
<ol class="legend-list">
|
||
<li>Highlight</li><li>Underline</li><li>StrikeOut</li><li>Squiggly</li><li>Caret</li><li>Text + Popup</li><li>FreeText</li><li>Line (arrow)</li><li>Square</li><li>Circle</li><li>Polygon</li><li>PolyLine</li><li>Ink</li><li>Stamp</li><li>FileAttachment</li><li>Link</li>
|
||
</ol>
|
||
</div>
|
||
<div class="canvas">
|
||
<span class="lab" style="left:10pt;top:8pt">Review canvas</span>
|
||
<a class="box" style="left:12pt;top:26pt;width:152pt;height:40pt" href="https://mark.printcraft.invalid/freetext/1">.</a>
|
||
<a class="box" style="left:196pt;top:22pt;width:20pt;height:20pt" href="https://mark.printcraft.invalid/note/1">.</a>
|
||
<a class="box" style="left:196pt;top:60pt;width:18pt;height:22pt" href="https://mark.printcraft.invalid/attach/1">.</a>
|
||
<a class="box" style="left:16pt;top:88pt;width:90pt;height:60pt" href="https://mark.printcraft.invalid/square/1">.</a>
|
||
<a class="box" style="left:120pt;top:92pt;width:90pt;height:60pt" href="https://mark.printcraft.invalid/circle/1">.</a>
|
||
<a class="box" style="left:16pt;top:170pt;width:94pt;height:80pt" href="https://mark.printcraft.invalid/polygon/1">.</a>
|
||
<a class="box" style="left:120pt;top:170pt;width:96pt;height:80pt" href="https://mark.printcraft.invalid/polyline/1">.</a>
|
||
<a class="box" style="left:16pt;top:268pt;width:196pt;height:40pt" href="https://mark.printcraft.invalid/line/1">.</a>
|
||
<a class="box" style="left:16pt;top:322pt;width:196pt;height:50pt" href="https://mark.printcraft.invalid/ink/1">.</a>
|
||
<a class="box" style="left:30pt;top:388pt;width:170pt;height:56pt" href="https://mark.printcraft.invalid/stamp/1">.</a>
|
||
</div>
|
||
</div>
|
||
<div class="folio"><span>Review & Markup</span><b>9</b></div>
|
||
</section>
|
||
|
||
</body>
|
||
</html>
|