358 lines
20 KiB
JavaScript
358 lines
20 KiB
JavaScript
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib'
|
|
import fs from 'fs'
|
|
|
|
async function create() {
|
|
const pdfDoc = await PDFDocument.create()
|
|
const page = pdfDoc.addPage([595.28, 841.89]) // A4
|
|
const helv = await pdfDoc.embedFont(StandardFonts.Helvetica)
|
|
const helvBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold)
|
|
const { width, height } = page.getSize()
|
|
|
|
// left column moved further left to align with checkboxes
|
|
const leftX = 48
|
|
const rightX = 320
|
|
// baseY is the vertical anchor for page-1 content. Increase it by ~5.2mm (≈14.739pt)
|
|
const baseY = height - 160 + 14.739
|
|
// shift to apply only to labels and input fields (move those 1cm down)
|
|
const labelsShift = -28.35
|
|
const gap = 36
|
|
const labelWidth = 100
|
|
const fieldXOffset = 100
|
|
// Make fields 10% narrower
|
|
const fieldWidth = Math.round(180 * 0.9)
|
|
// shrink most fields by another 20% on request (applied selectively later)
|
|
const fieldShrinkFactor = 0.8
|
|
const fieldHeight = 14
|
|
// raise date fields by 0.4cm (≈11.34pt) when requested; add extra 1.2mm (≈3.4016pt) per user request
|
|
const dateRaise = 11.34 + 3.4016 // now ≈14.7416pt
|
|
// fixed checkbox positions (do not move with leftX)
|
|
const cbX = 48
|
|
const cbYOffset = 5
|
|
|
|
// Header: centered club name and a full-width horizontal bar underneath (~2mm high)
|
|
const headerText = 'Harheimer Tischtennis-Club 1954 e.V.'
|
|
const headerSize = 20
|
|
const textWidth = helv.widthOfTextAtSize(headerText, headerSize)
|
|
const headerX = (width - textWidth) / 2
|
|
const headerY = height - 72
|
|
page.drawText(headerText, { x: headerX, y: headerY, size: headerSize, font: helv })
|
|
// draw full-width bar directly under the header; 2mm ≈ 5.67 points
|
|
const barHeight = 5.67
|
|
const barY = headerY - 20
|
|
page.drawRectangle({ x: 0, y: barY, width: width, height: barHeight, color: rgb(0,0,0) })
|
|
|
|
// Labels and lines
|
|
// Labels left-aligned in their columns
|
|
// Add form title above the fields
|
|
const titleText = 'Beitrittserklärung'
|
|
const titleSize = 14
|
|
const titleWidth = helvBold.widthOfTextAtSize(titleText, titleSize)
|
|
// left-align title above the left labels and move up ~0.7cm (≈20pt)
|
|
const titleX = leftX
|
|
// move title down by 0.5cm (≈14.17pt)
|
|
const titleY = baseY + 24 + 20 - 14.17
|
|
page.drawText(titleText, { x: titleX, y: titleY, size: titleSize, font: helvBold })
|
|
|
|
const subtitle = 'Hiermit beantrage ich,'
|
|
const subtitleSize = 12
|
|
const subtitleX = leftX
|
|
const subtitleY = titleY - 18 - 14.17
|
|
page.drawText(subtitle, { x: subtitleX, y: subtitleY, size: subtitleSize, font: helv })
|
|
// apply same vertical shift as fields so labels align
|
|
const fieldsShift = -14.17
|
|
page.drawText('Name:', { x: leftX, y: baseY + fieldsShift + labelsShift, size: 12, font: helv })
|
|
page.drawText('Vorname:', { x: rightX, y: baseY + fieldsShift + labelsShift, size: 12, font: helv })
|
|
|
|
page.drawText('Straße:', { x: leftX, y: baseY - gap + fieldsShift + labelsShift, size: 12, font: helv })
|
|
page.drawText('PLZ/Wohnort:', { x: rightX, y: baseY - gap + fieldsShift + labelsShift, size: 12, font: helv })
|
|
|
|
page.drawText('Geburtsdatum:', { x: leftX, y: baseY - gap * 2 + fieldsShift + labelsShift, size: 12, font: helv })
|
|
page.drawText('Telefon(privat):', { x: rightX, y: baseY - gap * 2 + fieldsShift + labelsShift, size: 12, font: helv })
|
|
|
|
page.drawText('E-Mail:', { x: leftX, y: baseY - gap * 3 + fieldsShift + labelsShift, size: 12, font: helv })
|
|
page.drawText('Telefon(Mobil):', { x: rightX, y: baseY - gap * 3 + fieldsShift + labelsShift, size: 12, font: helv })
|
|
|
|
// Create form fields
|
|
const form = pdfDoc.getForm()
|
|
// Place fields on the same baseline as their labels
|
|
// We need to move only the input fields on page 1 up by 0.6cm (≈17.01pt) without moving labels.
|
|
const labelToFieldYDelta = 2 // small vertical offset so field baseline matches label visually
|
|
const lift = 0 // original lift value
|
|
// previously raised inputs by 17.01pt (0.6cm); move them down by 5.67pt (0.2cm)
|
|
const inputFieldRaise = 11.34 // net upward offset now ~11.34pt
|
|
form.createTextField('nachname').addToPage(page, { x: leftX + fieldXOffset, y: baseY - fieldHeight + labelToFieldYDelta + lift + fieldsShift + labelsShift + inputFieldRaise, width: Math.round(fieldWidth * fieldShrinkFactor), height: fieldHeight, font: helv })
|
|
form.createTextField('vorname').addToPage(page, { x: rightX + fieldXOffset, y: baseY - fieldHeight + labelToFieldYDelta + lift + fieldsShift + labelsShift + inputFieldRaise, width: Math.round(fieldWidth * fieldShrinkFactor), height: fieldHeight, font: helv })
|
|
form.createTextField('strasse').addToPage(page, { x: leftX + fieldXOffset, y: baseY - gap - fieldHeight + labelToFieldYDelta + lift + fieldsShift + labelsShift + inputFieldRaise, width: Math.round(fieldWidth * fieldShrinkFactor), height: fieldHeight, font: helv })
|
|
form.createTextField('plz_ort').addToPage(page, { x: rightX + fieldXOffset, y: baseY - gap - fieldHeight + labelToFieldYDelta + lift + fieldsShift + labelsShift + inputFieldRaise, width: Math.round(fieldWidth * fieldShrinkFactor), height: fieldHeight, font: helv })
|
|
form.createTextField('geburtsdatum').addToPage(page, { x: leftX + fieldXOffset, y: baseY - gap * 2 - fieldHeight + labelToFieldYDelta + lift + fieldsShift + labelsShift + inputFieldRaise, width: Math.round(fieldWidth * fieldShrinkFactor), height: fieldHeight, font: helv })
|
|
form.createTextField('telefon').addToPage(page, { x: rightX + fieldXOffset, y: baseY - gap * 2 - fieldHeight + labelToFieldYDelta + lift + fieldsShift + labelsShift + inputFieldRaise, width: Math.round(fieldWidth * fieldShrinkFactor), height: fieldHeight, font: helv })
|
|
form.createTextField('email').addToPage(page, { x: leftX + fieldXOffset, y: baseY - gap * 3 - fieldHeight + labelToFieldYDelta + lift + fieldsShift + labelsShift + inputFieldRaise, width: Math.round(fieldWidth * fieldShrinkFactor), height: fieldHeight, font: helv })
|
|
form.createTextField('telefon_mobil').addToPage(page, { x: rightX + fieldXOffset, y: baseY - gap * 3 - fieldHeight + labelToFieldYDelta + lift + fieldsShift + labelsShift + inputFieldRaise, width: Math.round(fieldWidth * fieldShrinkFactor), height: fieldHeight, font: helv })
|
|
|
|
// read membership amounts from config (fall back to defaults)
|
|
let erw = 120, jug = 72, passv = 30
|
|
try {
|
|
const cfg = JSON.parse(fs.readFileSync('server/data/config.json', 'utf8'))
|
|
const ms = cfg.mitgliedschaft || []
|
|
erw = (ms.find(m => /Erwachsene/i.test(m.typ)) || ms.find(m => m.typ === 'Erwachsene') || {}).preis || erw
|
|
jug = (ms.find(m => /Jugend|Kinder/i.test(m.typ)) || ms.find(m => m.typ === 'Kinder/Jugend') || {}).preis || jug
|
|
passv = (ms.find(m => /Passiv/i.test(m.typ)) || {}).preis || passv
|
|
} catch (e) {
|
|
console.error('Could not read config for membership amounts', e)
|
|
}
|
|
|
|
const paraLines = [
|
|
'Den derzeitigen jährlichen Mitgliedsbeitrag in Höhe von',
|
|
`€ ${erw},-- (Erwachsene)`,
|
|
`€ ${jug},-- (Jugendliche bis zum vollendeten 18. Lebensjahr)`,
|
|
`€ ${passv},-- (passive Mitglieder)`,
|
|
'bitte ich per Lastschrift jährlich von meinem Konto einzuziehen.',
|
|
'Hierzu erteile ich beigefügtes SEPA-Lastschriftmandat.',
|
|
'Mir ist bekannt, dass die Mitgliedschaft im Harheimer Tischtennis-Club erst nach Bestätigung durch den',
|
|
'Vorstand Wirksamkeit erlangt. Die Beitragspflicht beginnt mit dem darauf folgenden Monat.',
|
|
'Ich erkenne die Vereinssatzung (erhältlich beim Vorstand bzw. auf der Vereinshomepage) an.'
|
|
]
|
|
|
|
// compute intermediate line position and move it down by additional 0.3cm ≈ 8.5pt
|
|
const intermediateY = baseY - gap * 3 + fieldsShift - 6 - 14.17 - 8.5 - 8.5 + labelsShift
|
|
page.drawText('meine Aufnahme in den Harheimer Tischtennis-Club 1954 e.V. als', { x: leftX, y: intermediateY, size: 12, font: helv })
|
|
|
|
// membership checkboxes
|
|
// Keep checkbox labels and boxes at fixed left positions, but move them down by 0.8cm ≈ 22.68pt
|
|
const cbLift = -22.68
|
|
page.drawText('aktives Mitglied', { x: cbX + 16, y: baseY - gap * 5 + cbLift + labelsShift, size: 12, font: helv })
|
|
page.drawText('passives Mitglied', { x: cbX + 16, y: baseY - gap * 6 + cbLift + labelsShift, size: 12, font: helv })
|
|
form.createCheckBox('mitglied_aktiv').addToPage(page, { x: cbX, y: baseY - gap * 5 - cbYOffset + cbLift + labelsShift, width: 12, height: 12 })
|
|
form.createCheckBox('mitglied_passiv').addToPage(page, { x: cbX, y: baseY - gap * 6 - cbYOffset + cbLift + labelsShift, width: 12, height: 12 })
|
|
|
|
// place the paragraph below the checkboxes with extra spacing before and after the cost lines (~0.3cm)
|
|
try {
|
|
// increase gap around cost lines for better readability (~0.6cm)
|
|
const beforeCostGap = 17
|
|
const afterCostGap = 17
|
|
const paraStartY = baseY - gap * 6 + cbLift - 28 - beforeCostGap
|
|
const lineHeight = 14
|
|
// insert explicit gaps before and after the cost lines (lines 1-3)
|
|
let y = paraStartY
|
|
// first line
|
|
page.drawText(paraLines[0], { x: leftX, y: y, size: 11, font: helv })
|
|
y -= lineHeight
|
|
// gap before costs
|
|
y -= beforeCostGap
|
|
// cost lines (1..3)
|
|
for (let k = 1; k <= 3; k++) {
|
|
page.drawText(paraLines[k], { x: leftX + 6, y: y, size: 11, font: helv })
|
|
y -= lineHeight
|
|
}
|
|
// gap after costs
|
|
y -= afterCostGap
|
|
// remaining lines
|
|
for (let i = 4; i < paraLines.length; i++) {
|
|
page.drawText(paraLines[i], { x: leftX, y: y, size: 11, font: helv })
|
|
y -= lineHeight
|
|
}
|
|
// shift following content down by afterCostGap if needed (none after currently)
|
|
// now add signature/city line 2 cm below the current text
|
|
const twoCm = 56.7
|
|
const signY = y - twoCm
|
|
const sigText = 'Frankfurt/Main-Harheim, den'
|
|
const sigSize = 12
|
|
page.drawText(sigText + ' ', { x: leftX, y: signY, size: sigSize, font: helv })
|
|
const sigStartX = leftX + helv.widthOfTextAtSize(sigText + ' ', sigSize)
|
|
const sigWidth = 220
|
|
// draw thin line for signature
|
|
page.drawRectangle({ x: sigStartX, y: signY - 2, width: sigWidth, height: 1, color: rgb(0,0,0) })
|
|
// draw 'Datum' centered under the signature line
|
|
const datum = 'Datum'
|
|
const datumSize = 11
|
|
const datumX = sigStartX + sigWidth / 2 - helv.widthOfTextAtSize(datum, datumSize) / 2
|
|
page.drawText(datum, { x: datumX, y: signY - 18, size: datumSize, font: helv })
|
|
// create a date form field on page 1 centered under the date line
|
|
const dateFieldWidth = 120
|
|
const dateFieldX = sigStartX + sigWidth / 2 - dateFieldWidth / 2
|
|
// position date field so its bottom edge is exactly on the signature line
|
|
const signatureLineY = signY - 2 // the 1pt-high rectangle was drawn at signY-2
|
|
// raise date fields by 0.4cm (≈11.34pt) upward relative to the line
|
|
const dateRaise = 11.34
|
|
// For page 1 we need to move only the date input up by 5.2mm (≈14.739pt)
|
|
const signDatumExtraRaise = 14.739
|
|
form.createTextField('sign_datum').addToPage(page, { x: dateFieldX, y: signatureLineY - fieldHeight + signDatumExtraRaise, width: dateFieldWidth, height: fieldHeight, font: helv })
|
|
// second signature line 3cm below first
|
|
const threeCm = 85.04
|
|
const secondY = signY - threeCm
|
|
const line2Width = 300
|
|
page.drawRectangle({ x: leftX, y: secondY - 2, width: line2Width, height: 1, color: rgb(0,0,0) })
|
|
const label2 = 'Unterschrift (bei Jugendlichen gesetzlicher Vertreter)'
|
|
page.drawText(label2, { x: leftX, y: secondY - 18, size: 11, font: helv })
|
|
} catch (e) {
|
|
// ignore
|
|
}
|
|
|
|
// footer: right-aligned 'Seite 1 von 3' 2cm from bottom
|
|
const footerY = 56.7
|
|
const footerText = 'Seite 1 von 3'
|
|
const footerSize = 10
|
|
const footerWidth = helv.widthOfTextAtSize(footerText, footerSize)
|
|
page.drawText(footerText, { x: width - footerWidth - leftX, y: footerY, size: footerSize, font: helv })
|
|
|
|
// --- Add a second page with the same header and horizontal bar ---
|
|
const page2 = pdfDoc.addPage([595.28, 841.89])
|
|
const { width: width2, height: height2 } = page2.getSize()
|
|
const textWidth2 = helv.widthOfTextAtSize(headerText, headerSize)
|
|
const headerX2 = (width2 - textWidth2) / 2
|
|
const headerY2 = height2 - 72
|
|
page2.drawText(headerText, { x: headerX2, y: headerY2, size: headerSize, font: helv })
|
|
const barY2 = headerY2 - 20
|
|
page2.drawRectangle({ x: 0, y: barY2, width: width2, height: barHeight, color: rgb(0,0,0) })
|
|
|
|
// --- Page 2: SEPA-Lastschriftmandat text and fields ---
|
|
// move SEPA section slightly up so title sits closer to the header bar
|
|
const sepaYStart = headerY2 - 54
|
|
const sepaLeft = leftX
|
|
// increase line gap for SEPA section (~22pt)
|
|
const lineGap = 22
|
|
let sy = sepaYStart
|
|
const small = 11
|
|
page2.drawText('Erteilung eines SEPA-Lastschriftmandates', { x: sepaLeft, y: sy, size: 12, font: helvBold })
|
|
sy -= lineGap
|
|
// draw these two lines as a tight block (no extra gap)
|
|
page2.drawText('Harheimer Tischtennis-Club 1954 e.V.', { x: sepaLeft, y: sy, size: small, font: helv })
|
|
sy -= 12
|
|
page2.drawText('Unsere Gläubiger-Identifikationsnummer: DE46ZZZ00000745362', { x: sepaLeft, y: sy, size: small, font: helv })
|
|
// add 0.7cm vertical gap (≈19.8pt) before the authorization paragraph
|
|
sy -= 19.8
|
|
// draw the authorization text as wrapped lines within page margins
|
|
const wrapMaxWidth = width2 - sepaLeft - 48
|
|
function drawWrapped(text, x, y, size, font) {
|
|
const words = text.split(' ')
|
|
let line = ''
|
|
let curY = y
|
|
for (const w of words) {
|
|
const test = line ? line + ' ' + w : w
|
|
const testWidth = helv.widthOfTextAtSize(test, size)
|
|
if (testWidth > wrapMaxWidth) {
|
|
page2.drawText(line, { x, y: curY, size, font })
|
|
line = w
|
|
curY -= size + 4
|
|
} else {
|
|
line = test
|
|
}
|
|
}
|
|
if (line) {
|
|
page2.drawText(line, { x, y: curY, size, font })
|
|
curY -= size + 4
|
|
}
|
|
return curY
|
|
}
|
|
sy = drawWrapped('Hiermit ermächtige ich den Harheimer Tischtennis-Club 1954 e.V. die jährlichen Mitgliedsbeiträge von meinem untenstehenden Konto per Lastschrift einzuziehen. Zugleich weise ich mein Kreditinstitut an, die vom Harheimer Tischtennis-Club 1954 e.V. auf mein Konto gezogenen Lastschriften einzulösen.', sepaLeft, sy, small, helv)
|
|
sy -= lineGap * 0.2
|
|
// draw mandate reference and validity with a small gap
|
|
page2.drawText('Mandatsreferenz: HTC0000 _ _ _', { x: sepaLeft, y: sy, size: small, font: helv })
|
|
// add 0.7cm space after Mandatsreferenz as requested
|
|
sy -= 19.8
|
|
page2.drawText('Dieses Mandat gilt für die zugrundeliegende Beitrittserklärung ab sofort.', { x: sepaLeft, y: sy, size: small, font: helv })
|
|
sy -= lineGap * 0.6
|
|
|
|
// Draw labeled lines and create text fields for mandate details
|
|
const fieldHeight2 = 14
|
|
const fieldWidth2 = 380
|
|
const labelOffset = 0
|
|
// place SEPA inputs 1cm left (≈28.35pt) from previous and slightly up; adjust to align with labels
|
|
const inputX = sepaLeft + 220 - 28.35
|
|
// reduce vertical raise so inputs sit on same baseline as labels (previously too high)
|
|
const inputYAdjust = 6
|
|
|
|
// apply labelsShift only to the SEPA form labels/inputs so paragraphs remain unaffected
|
|
let syFields = sy + labelsShift
|
|
page2.drawText('Mitglied (Vorname und Name)', { x: sepaLeft + labelOffset, y: syFields, size: small, font: helv })
|
|
form.createTextField('sepa_mitglied').addToPage(page2, { x: inputX, y: syFields - fieldHeight2 + 2 + inputYAdjust, width: Math.round(fieldWidth2 * fieldShrinkFactor), height: fieldHeight2, font: helv })
|
|
syFields -= lineGap * 1.1
|
|
|
|
page2.drawText('Kontoinhaber (Vorname und Name):', { x: sepaLeft + labelOffset, y: syFields, size: small, font: helv })
|
|
form.createTextField('sepa_kontoinhaber').addToPage(page2, { x: inputX, y: syFields - fieldHeight2 + 2 + inputYAdjust, width: Math.round(fieldWidth2 * fieldShrinkFactor), height: fieldHeight2, font: helv })
|
|
syFields -= lineGap * 1.1
|
|
|
|
page2.drawText('Straße und Hausnummer:', { x: sepaLeft + labelOffset, y: syFields, size: small, font: helv })
|
|
form.createTextField('sepa_strasse').addToPage(page2, { x: inputX, y: syFields - fieldHeight2 + 2 + inputYAdjust, width: Math.round(fieldWidth2 * fieldShrinkFactor), height: fieldHeight2, font: helv })
|
|
syFields -= lineGap * 1.1
|
|
|
|
page2.drawText('PLZ und Ort:', { x: sepaLeft + labelOffset, y: syFields, size: small, font: helv })
|
|
form.createTextField('sepa_plz_ort').addToPage(page2, { x: inputX, y: syFields - fieldHeight2 + 2 + inputYAdjust, width: Math.round(fieldWidth2 * fieldShrinkFactor), height: fieldHeight2, font: helv })
|
|
syFields -= lineGap * 1.1
|
|
|
|
page2.drawText('Kreditinstitut:', { x: sepaLeft + labelOffset, y: syFields, size: small, font: helv })
|
|
form.createTextField('sepa_bank').addToPage(page2, { x: inputX, y: syFields - fieldHeight2 + 2 + inputYAdjust, width: Math.round(fieldWidth2 * fieldShrinkFactor), height: fieldHeight2, font: helv })
|
|
syFields -= lineGap * 1.1
|
|
|
|
page2.drawText('IBAN:', { x: sepaLeft + labelOffset, y: syFields, size: small, font: helv })
|
|
form.createTextField('sepa_iban').addToPage(page2, { x: inputX, y: syFields - fieldHeight2 + 2 + inputYAdjust, width: Math.round(fieldWidth2 * fieldShrinkFactor), height: fieldHeight2, font: helv })
|
|
syFields -= lineGap * 1.1
|
|
|
|
page2.drawText('BIC:', { x: sepaLeft + labelOffset, y: syFields, size: small, font: helv })
|
|
// BIC remains full width as requested
|
|
form.createTextField('sepa_bic').addToPage(page2, { x: inputX, y: syFields - fieldHeight2 + 2 + inputYAdjust, width: 220, height: fieldHeight2, font: helv })
|
|
syFields -= lineGap * 1.1
|
|
|
|
// add signature and date lines 2cm below last field
|
|
const twoCm = 56.7
|
|
const signY2 = syFields - twoCm
|
|
// date text and line
|
|
const sigDateText = 'Frankfurt/Main-Harheim, den'
|
|
page2.drawText(sigDateText + ' ', { x: sepaLeft, y: signY2, size: 12, font: helv })
|
|
const sigDateStartX = sepaLeft + helv.widthOfTextAtSize(sigDateText + ' ', 12)
|
|
const sigDateWidth = 160
|
|
page2.drawRectangle({ x: sigDateStartX, y: signY2 - 2, width: sigDateWidth, height: 1, color: rgb(0,0,0) })
|
|
page2.drawText('Datum', { x: sigDateStartX + sigDateWidth / 2 - helv.widthOfTextAtSize('Datum', 11) / 2, y: signY2 - 18, size: 11, font: helv })
|
|
// create a date form field on page 2 centered under the date line
|
|
const sepaDateFieldWidth = 120
|
|
const sepaDateFieldX = sigDateStartX + sigDateWidth / 2 - sepaDateFieldWidth / 2
|
|
// position sepa date field so its bottom edge is on the signature line
|
|
// raise SEPA date field by the same amount so its top/bottom alignment matches requested position
|
|
form.createTextField('sepa_datum').addToPage(page2, { x: sepaDateFieldX, y: signY2 - 2 - fieldHeight2 + dateRaise, width: sepaDateFieldWidth, height: fieldHeight2, font: helv })
|
|
|
|
// footer on page 2: right-aligned 'Seite 2 von 3' 2cm from bottom
|
|
const footerText2 = 'Seite 2 von 3'
|
|
const footerSize2 = 10
|
|
const footerWidth2 = helv.widthOfTextAtSize(footerText2, footerSize2)
|
|
page2.drawText(footerText2, { x: width2 - footerWidth2 - leftX, y: 56.7, size: footerSize2, font: helv })
|
|
|
|
// signature line
|
|
// move signature label/line 2cm (≈56.7pt) further down
|
|
const signLineY = signY2 - 36 - 56.7
|
|
const signLineWidth = 300
|
|
page2.drawRectangle({ x: sepaLeft, y: signLineY - 2, width: signLineWidth, height: 1, color: rgb(0,0,0) })
|
|
page2.drawText('Unterschrift des Kontoinhabers', { x: sepaLeft, y: signLineY - 18, size: 11, font: helv })
|
|
// no form field for signature on page 2 (physical signature)
|
|
|
|
const pdfBytes = await pdfDoc.save()
|
|
fs.writeFileSync('server/templates/mitgliedschaft-fillable.pdf', pdfBytes)
|
|
console.log('Wrote server/templates/mitgliedschaft-fillable.pdf')
|
|
|
|
// --- Add a third page with same header/bar/footer and title 'Einwilligungserklärung' ---
|
|
const page3 = pdfDoc.addPage([595.28, 841.89])
|
|
const { width: width3, height: height3 } = page3.getSize()
|
|
const headerX3 = (width3 - textWidth) / 2
|
|
const headerY3 = height3 - 72
|
|
page3.drawText(headerText, { x: headerX3, y: headerY3, size: headerSize, font: helv })
|
|
const barY3 = headerY3 - 20
|
|
page3.drawRectangle({ x: 0, y: barY3, width: width3, height: barHeight, color: rgb(0,0,0) })
|
|
|
|
// title for page 3
|
|
const page3Title = 'Einwilligungserklärung'
|
|
const page3TitleSize = 14
|
|
const page3TitleX = leftX
|
|
const page3TitleY = headerY3 - 48
|
|
page3.drawText(page3Title, { x: page3TitleX, y: page3TitleY, size: page3TitleSize, font: helvBold })
|
|
|
|
// footer on page 3
|
|
const footerText3 = 'Seite 3 von 3'
|
|
const footerSize3 = 10
|
|
const footerWidth3 = helv.widthOfTextAtSize(footerText3, footerSize3)
|
|
page3.drawText(footerText3, { x: width3 - footerWidth3 - leftX, y: 56.7, size: footerSize3, font: helv })
|
|
}
|
|
|
|
create().catch(e => {
|
|
console.error(e)
|
|
process.exit(1)
|
|
})
|