Start to abstract

This commit is contained in:
2026-04-28 12:20:14 +09:30
parent d23dcd7382
commit 3fbd1871b6

102
main.go
View File

@@ -2,35 +2,60 @@ package main
import ( import (
"fmt" "fmt"
"io"
"log/slog" "log/slog"
"os"
"codeberg.org/go-pdf/fpdf" "codeberg.org/go-pdf/fpdf"
"github.com/yeqown/go-qrcode/v2" "github.com/yeqown/go-qrcode/v2"
"github.com/yeqown/go-qrcode/writer/standard" "github.com/yeqown/go-qrcode/writer/standard"
) )
var cols = 4 var textTopPadding = 0.0 // typically none is required
var rows = 4 var qrTopPadding = 5.0 // below the baseline of the text, remember the descenders like 'y', 'q'
var qrSize = 48.0
var fontSize = 25.0 // pts
var fontSizeMM = fontSize / 72 * 25.4
var text = "Á[Hjqy]|"
var font = "Courier"
var textTopPadding = 0.0 // typically none is required
var qrTopPadding = 5.0 // below the baseline of the text, remember the descenders like 'y', 'q'
var requiredCellPadding = 3.0 // half on each side, effectively var requiredCellPadding = 3.0 // half on each side, effectively
// var probably some padding instead of offsets for qr/font placement
func main() { func main() {
f, _ := os.Create("hello.pdf")
err := generatePage(f, PageOptions{
qrURL: "https://nanocat.net/dom/sdfih/dsifj/sidhof/sdifho/sdfiuoh/safiuho",
qrLabel: "Á[Hjqy]|",
qrSize: 54,
qrc, err := qrcode.New("https://nanocat.net/dom/sdfih/dsifj/sidhof/sdifho/sdfiuoh/safiuho") font: "Helvetica",
fontStyle: "B",
fontSize: 34.0,
rows: 4,
cols: 3,
borders: true,
})
if err != nil {
slog.Error("could not generate pdf", "error", err)
os.Exit(1)
}
}
type PageOptions struct {
qrURL string
qrLabel string
qrSize float64
font string
fontStyle string
fontSize float64
rows int
cols int
borders bool
}
func generatePage(w io.Writer, po PageOptions) error {
fontSizeMM := po.fontSize / 72 * 25.4
qrc, err := qrcode.New(po.qrURL)
if err != nil { if err != nil {
fmt.Printf("could not generate QRCode: %v", err) return fmt.Errorf("could not generate QRCode: %v", err)
return
} }
b := newBWC() b := newBWC()
@@ -78,65 +103,66 @@ func main() {
AllowNegativePosition: false, AllowNegativePosition: false,
}, b) }, b)
// info := pdf.GetImageInfo("qr")
// panic(info.Height())
pdf.AddPage() pdf.AddPage()
pdf.SetFont(font, "B", float64(fontSize)) pdf.SetFont(po.font, po.fontStyle, float64(po.fontSize))
textWidth := pdf.GetStringWidth(text) textWidth := pdf.GetStringWidth(po.qrLabel)
colWidth := pageWidth / float64(cols) colWidth := pageWidth / float64(po.cols)
rowHeight := pageHeight / float64(rows) rowHeight := pageHeight / float64(po.rows)
cellHeight := textTopPadding + fontSizeMM + qrTopPadding + qrSize cellHeight := textTopPadding + fontSizeMM + qrTopPadding + po.qrSize
cellWidth := qrSize cellWidth := po.qrSize
if cellHeight > rowHeight-requiredCellPadding { if cellHeight > rowHeight-requiredCellPadding {
slog.Warn("qr is too big for row", "cell_height", cellHeight, "row_height", rowHeight) slog.Warn("qr is too big for row", "cell_height", cellHeight, "row_height", rowHeight)
return fmt.Errorf("qr is too big for row size")
} }
slog.Info("check width", "cell_width", cellWidth, "col_width", colWidth) // slog.Info("check width", "cell_width", cellWidth, "col_width", colWidth)
if cellWidth > colWidth-requiredCellPadding { if cellWidth > colWidth-requiredCellPadding {
slog.Warn("qr is too big for column", "cell_width", cellWidth, "col_width", colWidth) slog.Warn("qr is too big for column", "cell_width", cellWidth, "col_width", colWidth)
return fmt.Errorf("qr is too big for col size")
} }
if textWidth > colWidth { if textWidth > colWidth {
slog.Warn("text probably too wide") slog.Warn("text probably too wide")
return fmt.Errorf("text is too wide for col size")
} }
for rowIdx := range rows { for rowIdx := range po.rows {
for colIdx := range cols { for colIdx := range po.cols {
topLeftX := colWidth * float64(colIdx) topLeftX := colWidth * float64(colIdx)
topLeftY := rowHeight * float64(rowIdx) topLeftY := rowHeight * float64(rowIdx)
// draw box // draw box
pdf.SetDashPattern([]float64{1, 1}, 0) if po.borders {
pdf.Rect(topLeftX, topLeftY, colWidth, rowHeight, "D") pdf.SetDashPattern([]float64{1, 1}, 0)
pdf.SetDashPattern([]float64{}, 0) pdf.Rect(topLeftX, topLeftY, colWidth, rowHeight, "D")
pdf.SetDashPattern([]float64{}, 0)
}
// label at the top // label at the top
pdf.Text( pdf.Text(
topLeftX+colWidth/2-textWidth/2, topLeftX+colWidth/2-textWidth/2,
topLeftY+fontSizeMM+textTopPadding, topLeftY+fontSizeMM+textTopPadding,
text, // +fmt.Sprintf("%d/%d", rowIdx, colIdx) po.qrLabel, // +fmt.Sprintf("%d/%d", rowIdx, colIdx)
) )
// qr at the bottom // qr at the bottom
pdf.ImageOptions("qr", pdf.ImageOptions("qr",
topLeftX+colWidth/2-qrSize/2, topLeftX+colWidth/2-po.qrSize/2,
topLeftY+textTopPadding+fontSizeMM+qrTopPadding, topLeftY+textTopPadding+fontSizeMM+qrTopPadding,
qrSize, qrSize, po.qrSize, po.qrSize,
false, false,
fpdf.ImageOptions{AllowNegativePosition: true}, 0, "") fpdf.ImageOptions{AllowNegativePosition: true}, 0, "")
} }
} }
err = pdf.OutputFileAndClose("hello.pdf") err = pdf.Output(w)
if err != nil { if err != nil {
panic(err) return fmt.Errorf("could not output PDF: %w", err)
} }
fmt.Println(pageWidth, pageHeight) return nil
} }