Add support for appendices: landscape diagrams, tables, and images; implement Kroki URL configurability; enhance directive parsing logic.
This commit is contained in:
+108
-4
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
|
||||
"github.com/go-pdf/fpdf"
|
||||
@@ -126,8 +127,8 @@ func (r *IHKRenderer) RenderBibliography() {
|
||||
}
|
||||
|
||||
// RenderAppendices renders the appendix section followed by individual annex
|
||||
// pages. The opening page contains the index of all annexes. Each annex image
|
||||
// is scaled to fill the available page area.
|
||||
// pages. The opening page contains the index of all annexes. Annexes marked
|
||||
// Landscape=true are placed on a landscape A4 page with 15 mm symmetric margins.
|
||||
func (r *IHKRenderer) RenderAppendices() {
|
||||
if len(r.appendices) == 0 {
|
||||
return
|
||||
@@ -144,14 +145,41 @@ func (r *IHKRenderer) RenderAppendices() {
|
||||
r.tr(fmt.Sprintf("Anlage %d: %s", i+1, app.Title)), "", 1, "L", false, 0, "")
|
||||
}
|
||||
|
||||
// Save portrait dimensions and standard margins for post-landscape restoration.
|
||||
portraitW, portraitH := r.pdf.GetPageSize()
|
||||
lm, tm, rm, _ := r.pdf.GetMargins()
|
||||
|
||||
const diagMargin = 15.0
|
||||
|
||||
// Individual annex pages
|
||||
for i, app := range r.appendices {
|
||||
r.pdf.AddPage()
|
||||
if app.Landscape {
|
||||
r.pdf.SetMargins(diagMargin, diagMargin, diagMargin)
|
||||
r.pdf.SetAutoPageBreak(true, diagMargin)
|
||||
// portraitH > portraitW → {Wd: portraitH, Ht: portraitW} = landscape 297×210.
|
||||
r.pdf.AddPageFormat("L", fpdf.SizeType{Wd: portraitH, Ht: portraitW})
|
||||
} else {
|
||||
r.pdf.AddPage()
|
||||
}
|
||||
|
||||
r.pdf.SetFont("Helvetica", "B", dinFontBody)
|
||||
r.pdf.CellFormat(0, dinLineHtBody,
|
||||
r.tr(fmt.Sprintf("Anlage %d: %s", i+1, app.Title)), "", 1, "L", false, 0, "")
|
||||
r.pdf.Ln(dinSpaceAfterHeading)
|
||||
r.renderAppendixImage(app.Path)
|
||||
|
||||
switch app.Kind {
|
||||
case AppendixKindImage:
|
||||
r.renderAppendixImage(app.Path)
|
||||
case AppendixKindTable:
|
||||
// Render without numbering/recording; the annex header already identifies the table.
|
||||
r.renderTableBody(app.TableData, "")
|
||||
}
|
||||
|
||||
if app.Landscape {
|
||||
// Restore standard margins so the next AddPage() returns to portrait.
|
||||
r.pdf.SetMargins(lm, tm, rm)
|
||||
r.pdf.SetAutoPageBreak(true, dinMarginBottom)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,6 +262,79 @@ func (r *IHKRenderer) RenderGlossary() {
|
||||
}
|
||||
}
|
||||
|
||||
// RenderLandscapeDiagram renders an image on a dedicated landscape A4 page,
|
||||
// scaled to fill the full printable area. A figure caption is added below the
|
||||
// image and recorded in the Abbildungsverzeichnis.
|
||||
//
|
||||
// The page uses symmetric 15 mm margins (no Korrekturrand — examiners do not
|
||||
// mark up diagram pages). After rendering, a fresh portrait page is opened so
|
||||
// subsequent content continues in the correct orientation.
|
||||
func (r *IHKRenderer) RenderLandscapeDiagram(path, caption string) {
|
||||
// Current dimensions before the landscape page (portrait A4: 210 × 297 mm).
|
||||
pw, ph := r.pdf.GetPageSize()
|
||||
lm, tm, rm, _ := r.pdf.GetMargins()
|
||||
|
||||
const diagMargin = 15.0
|
||||
|
||||
// Apply symmetric margins before adding the landscape page so the page
|
||||
// inherits them. The Korrekturrand (40 mm) is not needed on a diagram page.
|
||||
r.pdf.SetMargins(diagMargin, diagMargin, diagMargin)
|
||||
r.pdf.SetAutoPageBreak(true, diagMargin)
|
||||
// ph > pw for portrait A4 → {Wd: ph, Ht: pw} = landscape 297 × 210 mm.
|
||||
r.pdf.AddPageFormat("L", fpdf.SizeType{Wd: ph, Ht: pw})
|
||||
|
||||
captionH := dinLineHtCaption + 4
|
||||
availW := ph - 2*diagMargin // 297 − 30 = 267 mm
|
||||
availH := pw - 2*diagMargin - captionH - 2 // 210 − 30 − ~10 ≈ 170 mm
|
||||
|
||||
info := r.ensureImageRegistered(path)
|
||||
if info == nil {
|
||||
log.Printf("warning: landscape diagram image not found: %q", path)
|
||||
r.pdf.SetFont("Helvetica", "I", dinFontCaption)
|
||||
r.pdf.CellFormat(0, dinLineHtCaption,
|
||||
r.tr("[Bild nicht gefunden: "+path+"]"), "1", 1, "C", false, 0, "")
|
||||
} else {
|
||||
imgW := info.Width() * ptToMM
|
||||
imgH := info.Height() * ptToMM
|
||||
|
||||
// Scale to fill available width, clamp to available height.
|
||||
displayW := availW
|
||||
displayH := imgH * (displayW / imgW)
|
||||
if displayH > availH {
|
||||
displayH = availH
|
||||
displayW = imgW * (displayH / imgH)
|
||||
if displayW > availW {
|
||||
displayW = availW
|
||||
displayH = imgH * (displayW / imgW)
|
||||
}
|
||||
}
|
||||
|
||||
posX := diagMargin + (availW-displayW)/2
|
||||
posY := diagMargin
|
||||
|
||||
r.pdf.ImageOptions(path, posX, posY, displayW, displayH, false,
|
||||
fpdf.ImageOptions{ReadDpi: true}, 0, "")
|
||||
r.pdf.SetY(posY + displayH + 2)
|
||||
|
||||
r.figureCount++
|
||||
label := fmt.Sprintf("Abb. %d", r.figureCount)
|
||||
if caption != "" {
|
||||
label += ": " + caption
|
||||
}
|
||||
r.RecordFigure(label)
|
||||
|
||||
r.pdf.SetFont("Helvetica", "I", dinFontCaption)
|
||||
r.pdf.CellFormat(0, captionH, r.tr(label), "", 1, "C", false, 0, "")
|
||||
}
|
||||
|
||||
// Restore portrait margins and open a fresh portrait page.
|
||||
// AddPage() always uses the default orientation ("P") set at construction,
|
||||
// so subsequent content is guaranteed to be in portrait.
|
||||
r.pdf.SetMargins(lm, tm, rm)
|
||||
r.pdf.SetAutoPageBreak(true, dinMarginBottom)
|
||||
r.pdf.AddPage()
|
||||
}
|
||||
|
||||
// ensureImageRegistered registers an image with fpdf if not already known
|
||||
// and returns its metadata. Returns nil if the image cannot be loaded.
|
||||
func (r *IHKRenderer) ensureImageRegistered(path string) *fpdf.ImageInfoType {
|
||||
@@ -242,6 +343,9 @@ func (r *IHKRenderer) ensureImageRegistered(path string) *fpdf.ImageInfoType {
|
||||
r.pdf.RegisterImageOptions(path, fpdf.ImageOptions{ReadDpi: true})
|
||||
info = r.pdf.GetImageInfo(path)
|
||||
}
|
||||
if info == nil {
|
||||
log.Printf("warning: could not load image %q", path)
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user