diff --git a/administration/src/cards/PdfFactory.ts b/administration/src/cards/PdfFactory.ts index 95b57e486..37b06f5b5 100644 --- a/administration/src/cards/PdfFactory.ts +++ b/administration/src/cards/PdfFactory.ts @@ -3,7 +3,9 @@ import { PDFDocument, PDFPage, StandardFonts } from 'pdf-lib' import { DynamicActivationCode, QrCode, StaticVerificationCode } from '../generated/card_pb' import { Region } from '../generated/graphql' import { PdfConfig } from '../project-configs/getProjectConfig' +import { uint8ArrayToBase64 } from '../util/base64' import CardBlueprint from './CardBlueprint' +import hashCardInfo from './hashCardInfo' import pdfFormElement from './pdf/PdfFormElement' import pdfQrCodeElement from './pdf/PdfQrCodeElement' import pdfTextElement from './pdf/PdfTextElement' @@ -36,6 +38,8 @@ async function fillContentAreas( ) } + const cardInfoHash = await hashCardInfo(dynamicCode.value.info!, dynamicCode.value.pepper!) + const form = doc.getForm() pdfConfig.elements?.form?.forEach(configOptions => pdfFormElement(configOptions, { @@ -45,6 +49,7 @@ async function fillContentAreas( info: dynamicCode.value.info!, region: region, cardBlueprint, + cardInfoHash: uint8ArrayToBase64(cardInfoHash), }) ) @@ -55,6 +60,7 @@ async function fillContentAreas( info: dynamicCode.value.info!, region: region, cardBlueprint, + cardInfoHash: uint8ArrayToBase64(cardInfoHash), }) ) } diff --git a/administration/src/cards/pdf/PdfFormElement.ts b/administration/src/cards/pdf/PdfFormElement.ts index 4fb051296..d90967c89 100644 --- a/administration/src/cards/pdf/PdfFormElement.ts +++ b/administration/src/cards/pdf/PdfFormElement.ts @@ -9,6 +9,7 @@ export type InfoParams = { info: CardInfo region: Region cardBlueprint: CardBlueprint + cardInfoHash: string } export type PdfFormElementProps = { @@ -24,14 +25,15 @@ type PdfFormElementRendererProps = { info: CardInfo region: Region cardBlueprint: CardBlueprint + cardInfoHash: string } const pdfFormElements: PdfElement = ( { infoToFormFields, fontSize, width, x, y }, - { page, form, font, info, region, cardBlueprint } + { page, form, font, info, region, cardBlueprint, cardInfoHash } ) => { const pageIdx = page.doc.getPageCount() - const formFields = infoToFormFields(form, pageIdx, { info, region, cardBlueprint }) + const formFields = infoToFormFields(form, pageIdx, { info, region, cardBlueprint, cardInfoHash }) const lineHeight = font.heightAtSize(fontSize) + 6 formFields.forEach((formField, index) => { diff --git a/administration/src/cards/pdf/PdfTextElement.ts b/administration/src/cards/pdf/PdfTextElement.ts index c326dfa40..863bc513f 100644 --- a/administration/src/cards/pdf/PdfTextElement.ts +++ b/administration/src/cards/pdf/PdfTextElement.ts @@ -9,13 +9,15 @@ export type InfoParams = { info: CardInfo region: Region cardBlueprint: CardBlueprint + cardInfoHash: string } export type PdfTextElementProps = { - width: number + maxWidth?: number | undefined fontSize: number + textAlign?: 'left' | 'right' | 'center' spacing?: number - angle?: number + angle?: number | undefined color?: Color infoToText: (info: InfoParams) => string } & Coordinates @@ -26,21 +28,35 @@ type PdfTextElementRendererProps = { info: CardInfo region: Region cardBlueprint: CardBlueprint + cardInfoHash: string } const pdfTextElement: PdfElement = ( - { width, x, y, fontSize, infoToText, spacing = 1, angle = 0, color = undefined }, - { page, font, info, region, cardBlueprint } + { maxWidth, x, y, fontSize, infoToText, spacing = 1, angle = 0, color = undefined, textAlign = 'left' }, + { page, font, info, region, cardBlueprint, cardInfoHash } ) => { - const text = infoToText({ info, region, cardBlueprint }) + const text = infoToText({ info, region, cardBlueprint, cardInfoHash }) + + let xPt: number + switch (textAlign) { + case 'left': + xPt = mmToPt(x) + break + case 'right': + xPt = mmToPt(x) - font.widthOfTextAtSize(text, fontSize) + break + case 'center': + xPt = mmToPt(x) - font.widthOfTextAtSize(text, fontSize) / 2 + break + } const lineHeight = font.heightAtSize(fontSize) + spacing page.drawText(text, { font, - x: mmToPt(x), + x: xPt, y: page.getSize().height - mmToPt(y) - lineHeight, - maxWidth: mmToPt(width), + maxWidth: maxWidth !== undefined ? mmToPt(maxWidth) : undefined, wordBreaks: text.split('').filter(c => !'\n\f\r\u000B'.includes(c)), // Split on every character lineHeight, color, diff --git a/administration/src/project-configs/bayern/pdf.ts b/administration/src/project-configs/bayern/pdf.ts index 63cc7760d..9cbdacb98 100644 --- a/administration/src/project-configs/bayern/pdf.ts +++ b/administration/src/project-configs/bayern/pdf.ts @@ -18,13 +18,20 @@ Ausgestellt am ${PlainDate.fromLocalDate(new Date()).format('dd.MM.yyyy')} von ${region.prefix} ${region.name}` } +const renderCardHash = ({ cardInfoHash }: InfoParams) => { + return cardInfoHash +} + const pdfConfiguration: PdfConfig = { title: 'Ehrenamtskarten', templatePath: pdfTemplate, issuer: 'Bayerische Staatsministerium für Arbeit und Soziales, Familie und Integration', elements: { dynamicActivationQrCodes: [{ x: 108, y: 73, size: 84 }], - text: [{ x: 108, y: 170, width: 84, fontSize: 10, spacing: 4, infoToText: renderPdfInfo }], + text: [ + { x: 108, y: 170, maxWidth: 84, fontSize: 10, spacing: 4, infoToText: renderPdfInfo }, + { x: 149.75, y: 162, fontSize: 6, textAlign: 'center', infoToText: renderCardHash }, + ], }, } diff --git a/administration/src/project-configs/nuernberg/pdf.ts b/administration/src/project-configs/nuernberg/pdf.ts index 0f792152e..ea453f234 100644 --- a/administration/src/project-configs/nuernberg/pdf.ts +++ b/administration/src/project-configs/nuernberg/pdf.ts @@ -58,6 +58,10 @@ const renderPassNumber = ({ info }: InfoParams) => { return passNumber ? `Nürnberg-Pass-Nr.: ${passNumber?.toString()}` : '' } +const renderCardHash = ({ cardInfoHash }: InfoParams) => { + return cardInfoHash +} + const pdfConfiguration: PdfConfig = { title: 'Nürnberg-Pässe', templatePath: pdfTemplate, @@ -69,9 +73,10 @@ const pdfConfiguration: PdfConfig = { ], dynamicActivationQrCodes: [{ x: 122, y: 110, size: 63 }], text: [ - { x: 108, y: 243, width: 52, fontSize: 9, spacing: 5, infoToText: renderPdfDetails }, - { x: 129.5, y: 79, width: 44, fontSize: 13, color: rgb(0.17, 0.17, 0.2), infoToText: renderPassId }, - { x: 27, y: 265, width: 46, fontSize: 8, angle: 90, infoToText: renderPassNumber }, + { x: 108, y: 243, maxWidth: 52, fontSize: 9, spacing: 5, infoToText: renderPdfDetails }, + { x: 129.5, y: 79, maxWidth: 44, fontSize: 13, color: rgb(0.17, 0.17, 0.2), infoToText: renderPassId }, + { x: 27, y: 265, maxWidth: 46, fontSize: 8, angle: 90, infoToText: renderPassNumber }, + { x: 153.892, y: 178, fontSize: 6, textAlign: 'center', infoToText: renderCardHash }, ], form: [{ infoToFormFields: createAddressFormFields, x: 25, y: 66, width: 65, fontSize: 10 }], },