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