Files
business-suite/bin/figures.lua
T
Marc WäckerlinandClaude Opus 5 adc58e19d7 One LaTeX design for a company, in three templates
A company that writes with LaTeX ends up with a document class, a letter class
and a presentation theme that share a design and not a line of code. Every fix
is then made three times, two of them late and the third never.

Here the page is written once. A company declares its colours, faces and logo in
one file, and the document template, the letter class and the presentation theme
read that one file. Nothing in the suite carries a colour value, a font name or
a file name of any company, which is what lets it be published while the
companies stay private.

Every measure of the page follows from a measurement or from a named definition:
the room the head and the foot need is taken from the boxes they really build,
one line of the body text stands between the head and the text and between the
text and the foot, a heading never stands alone at the foot of a page, a picture
takes the size of the family, and a Markdown file reaches the same page as the
same document written in LaTeX.

The suite ships with a company that does not exist, Nordwind AG, so that it
builds and is measured anywhere: three colours, the TeX Gyre families every
installation carries, and an icon drawn in TikZ.

574 checks over five measurements, all of them on the rendered page or on the
build log rather than on the source.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 15:06:07 +02:00

78 lines
3.1 KiB
Lua

-- Copyright (c) 2026 Marc Wäckerlin. SPDX-License-Identifier: MIT
-- A picture that stands alone in its paragraph gets its caption under it.
--
-- `![Das Logo als Bild](logo.png)` carries a text between the brackets, and
-- every reader who writes it means it as the caption. GFM has no such rule: the
-- text becomes the alternative text of the picture, which reaches a screen
-- reader and nobody else, and the PDF shows a picture with nothing under it.
--
-- pandoc has the rule under the name implicit_figures, and its GFM reader does
-- not carry it, so the paragraph is turned into a figure here. What the figure
-- then looks like — where it stands, how the caption is set — comes from the
-- package like everything else.
-- A picture that stands directly under a heading does not float away from it.
--
-- A floating picture leaves the page it was written on, and where the heading
-- announced nothing but that picture, the heading stays behind alone at the
-- foot of the page. Measured over one report: a page ended with its heading,
-- 430 points of it still empty, and its picture began on the next. The
-- reservation a heading takes cannot answer this — the room was there, and what
-- should have filled it had left the page.
--
-- So this one picture is placed where it stands. It then either fits under its
-- heading, or the page breaks BEFORE the heading and the two travel together,
-- which is what a reader expects of a heading.
local function nailed(figure)
return {
pandoc.RawBlock('latex', '\\begingroup\\floatplacement{figure}{H}'),
figure,
pandoc.RawBlock('latex', '\\endgroup'),
}
end
function Blocks(blocks)
if not FORMAT:match('latex') then return nil end
local kept, previous = pandoc.Blocks{}, nil
for _, block in ipairs(blocks) do
if block.t == 'Figure' and previous and previous.t == 'Header' then
for _, piece in ipairs(nailed(block)) do
kept:insert(piece)
end
else
kept:insert(block)
end
previous = block
end
return kept
end
-- A picture of pixels says so, because only this side knows the file name.
--
-- How large a picture may be drawn is the package's rule, and it is not the
-- same rule for a drawing and for a photograph: a drawing is drawn again at
-- every size, a raster of pixels gets coarse. What the package sees is the
-- finished box, which carries no file name any more, so the mark is set here
-- and read by the picture that follows it.
local RASTER = {
png = true, jpg = true, jpeg = true, bmp = true,
gif = true, tif = true, tiff = true,
}
function Image(image)
if not FORMAT:match('latex') then return nil end
local extension = image.src:match('%.([%a%d]+)$')
if extension and RASTER[extension:lower()] then
return { pandoc.RawInline('latex', '\\businessbitmap'), image }
end
end
function Para(para)
if #para.content ~= 1 then return nil end
local image = para.content[1]
if image.t ~= 'Image' or #image.caption == 0 then return nil end
return pandoc.Figure(
pandoc.Blocks{ pandoc.Plain{ image } },
{ long = pandoc.Blocks{ pandoc.Plain(image.caption) } })
end