Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix text height rendering for PDF generation #196

Merged
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/common/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const DEFAULT_CHARACTER_SPACING = 0;
export const DEFAULT_FONT_COLOR = '#000';
export const DEFAULT_TOLERANCE = 1;
export const DEFAULT_FONT_SIZE_ADJUSTMENT = 0.25;
export const DEFAULT_PT_TO_PX_RATIO = 1.333;
export const DEFAULT_PT_TO_MM_RATIO = 0.3528;

export const BLANK_PDF =
Expand Down
14 changes: 14 additions & 0 deletions packages/common/src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
GenerateProps as GeneratePropsSchema,
UIProps as UIPropsSchema,
} from './schema.js';
import type { Font as FontkitFont } from 'fontkit';

const blob2Base64Pdf = (blob: Blob) => {
return new Promise<string>((resolve, reject) => {
Expand Down Expand Up @@ -73,6 +74,19 @@ export const getDefaultFont = (): Font => ({
[DEFAULT_FONT_NAME]: { data: b64toUint8Array(DEFAULT_FONT_VALUE), fallback: true },
});

export const heightOfFontAtSize = (font: FontkitFont, size: number) => {
let { ascent, descent, bbox } = font;

const scale = 1000 / font.unitsPerEm;
const yTop = (ascent || bbox.maxY) * scale;
const yBottom = (descent || bbox.minY) * scale;

let height = yTop - yBottom;
height -= Math.abs(descent * scale) || 0;

return (height / 1000) * size;
};

const uniq = <T>(array: Array<T>) => Array.from(new Set(array));

const getFontNamesInSchemas = (schemas: { [key: string]: Schema }[]) =>
Expand Down
4 changes: 4 additions & 0 deletions packages/common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
DEFAULT_TOLERANCE,
DEFAULT_FONT_SIZE_ADJUSTMENT,
DEFAULT_PT_TO_MM_RATIO,
DEFAULT_PT_TO_PX_RATIO,
BLANK_PDF,
DEFAULT_FONT_VALUE,
} from './constants.js';
Expand Down Expand Up @@ -42,6 +43,7 @@ import {
b64toUint8Array,
getFallbackFontName,
getDefaultFont,
heightOfFontAtSize,
checkFont,
checkInputs,
checkUIOptions,
Expand All @@ -64,6 +66,7 @@ export {
DEFAULT_TOLERANCE,
DEFAULT_FONT_SIZE_ADJUSTMENT,
DEFAULT_PT_TO_MM_RATIO,
DEFAULT_PT_TO_PX_RATIO,
BLANK_PDF,
DEFAULT_FONT_VALUE,
schemaTypes,
Expand All @@ -74,6 +77,7 @@ export {
b64toUint8Array,
getFallbackFontName,
getDefaultFont,
heightOfFontAtSize,
checkFont,
checkInputs,
checkUIOptions,
Expand Down
steffancarrington marked this conversation as resolved.
Show resolved Hide resolved
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/Aone72312宛名.pdf
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/background.pdf
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/barcodes.pdf
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/canvasPdf.pdf
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/connpass名札.pdf
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/fontColor.pdf
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/fontSubset.pdf
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/test.pdf
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/z97mmx210mm.pdf
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/履歴書.pdf
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/書類送付状.pdf
Binary file not shown.
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/納品書.pdf
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/表彰状.pdf
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/見積書.pdf
Binary file not shown.
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/請求書.pdf
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/領収書.pdf
Binary file not shown.
Binary file modified packages/generator/__tests__/assets/pdfs/assert/領収書x4.pdf
Binary file not shown.
3 changes: 1 addition & 2 deletions packages/generator/src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const preprocessing = async (arg: { inputs: SchemaInputs[]; template: Template;
const fallbackFontName = getFallbackFontName(font);

const pdfDoc = await PDFDocument.create();
// @ts-ignore
pdfDoc.registerFontkit(fontkit);

const pdfFontObj = await embedAndGetFontObj({ pdfDoc, font });
Expand All @@ -47,8 +48,6 @@ const generate = async (props: GenerateProps) => {
const { font = getDefaultFont() } = options;
const { schemas } = template;



const preRes = await preprocessing({ inputs, template, font });
const { pdfDoc, pdfFontObj, fallbackFontName, embeddedPages, embedPdfBoxes } = preRes;

Expand Down
47 changes: 34 additions & 13 deletions packages/generator/src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,18 @@ import {
BasePdf,
BarCodeType,
Alignment,
DEFAULT_FONT_NAME,
DEFAULT_FONT_SIZE,
DEFAULT_ALIGNMENT,
DEFAULT_LINE_HEIGHT,
DEFAULT_CHARACTER_SPACING,
DEFAULT_FONT_COLOR,
calculateDynamicFontSize,
heightOfFontAtSize,
getDefaultFont
} from '@pdfme/common';
import { Buffer } from 'buffer';
import * as fontkit from 'fontkit';

export interface InputImageCache {
[key: string]: PDFImage | undefined;
Expand Down Expand Up @@ -251,7 +256,8 @@ const getSplittedLines = (inputLine: string, isOverEval: IsOverEval): string[] =
const splittedLine = inputLine.substring(0, splitPos);
const rest = inputLine.substring(splitPos).trimStart();

if (rest.length === 0) { // end recursion if there is no rest
if (rest.length === 0) {
// end recursion if there is no rest
return [splittedLine];
}

Expand All @@ -278,11 +284,23 @@ const drawInputByTextSchema = async (arg: {
const { font, pdfFontObj, fallbackFontName } = fontSetting;

const pdfFontValue = pdfFontObj[templateSchema.fontName ? templateSchema.fontName : fallbackFontName];
const fallbackFont = getDefaultFont();
let schemaFontData = fallbackFont[DEFAULT_FONT_NAME].data;

if (templateSchema.fontName) {
schemaFontData = font[templateSchema.fontName].data;
}

const fontkitFont = fontkit.create(Buffer.from(schemaFontData as ArrayBuffer));

drawBackgroundColor({ templateSchema, page, pageHeight });

const { width, rotate } = getSchemaSizeAndRotate(templateSchema);
const { size, color, alignment, lineHeight, characterSpacing } = await getFontProp({ input, font, schema: templateSchema });
const { width, height, rotate } = getSchemaSizeAndRotate(templateSchema);
const { size, color, alignment, lineHeight, characterSpacing } = await getFontProp({
input,
font,
schema: templateSchema,
});

page.pushOperators(setCharacterSpacing(characterSpacing));

Expand All @@ -294,16 +312,19 @@ const drawInputByTextSchema = async (arg: {
pdfFontValue.widthOfTextAtSize(testString, size) + (testString.length - 1) * characterSpacing;
return width <= testStringWidth;
};
const splitedLines = getSplittedLines(inputLine, isOverEval);
const drawLine = (splitedLine: string, splitedLineIndex: number) => {
const textWidth =
pdfFontValue.widthOfTextAtSize(splitedLine, size) +
(splitedLine.length - 1) * characterSpacing;
page.drawText(splitedLine, {
const splitLines = getSplittedLines(inputLine, isOverEval);

const drawLine = (line: string, lineIndex: number) => {
const textWidth = pdfFontValue.widthOfTextAtSize(line, size) + (line.length - 1) * characterSpacing;
const textHeight = heightOfFontAtSize(fontkitFont, size);

page.drawText(line, {
x: calcX(templateSchema.position.x, alignment, width, textWidth),
y:
calcY(templateSchema.position.y, pageHeight, size) -
lineHeight * size * (inputLineIndex + splitedLineIndex + beforeLineOver) -
calcY(templateSchema.position.y, pageHeight, height) +
height -
textHeight -
lineHeight * size * (inputLineIndex + lineIndex + beforeLineOver) -
(lineHeight === 0 ? 0 : ((lineHeight - 1) * size) / 2),
rotate,
size,
Expand All @@ -313,10 +334,10 @@ const drawInputByTextSchema = async (arg: {
font: pdfFontValue,
wordBreaks: [''],
});
if (splitedLines.length === splitedLineIndex + 1) beforeLineOver += splitedLineIndex;
if (splitLines.length === lineIndex + 1) beforeLineOver += lineIndex;
};

splitedLines.forEach(drawLine);
splitLines.forEach(drawLine);
});
};

Expand Down
1 change: 0 additions & 1 deletion packages/generator/type.d.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -370,18 +370,22 @@ exports[`Designer snapshot 1`] = `
title="field1"
>
<div
style="padding: 0px; resize: none; position: absolute; font-family: inherit; height: 56.692913386499995px; width: 377.95275591px; text-align: left; font-size: 30pt; letter-spacing: 0pt; line-height: 1em; white-space: pre-line; word-break: break-word; color: rgb(0, 0, 0);"
style="position: absolute; top: 0px; padding: 0px; height: 56.692913386499995px; width: 377.95275591px; resize: none; font-family: inherit; color: rgb(0, 0, 0); font-size: 30pt; letter-spacing: 0pt; line-height: 1em; text-align: left; white-space: pre-line; word-break: break-word;"
>
<span
style="letter-spacing: inherit;"
<div
style="margin-top: 0px; padding-top: 0px;"
>
b
</span>
<span
style="letter-spacing: 0;"
>
b
</span>
<span
style="letter-spacing: inherit;"
>
b
</span>
<span
style="letter-spacing: 0;"
>
b
</span>
</div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ exports[`Preview(as Form) snapshot 1`] = `
>
<textarea
placeholder="bb"
style="padding: 0px; resize: none; position: absolute; font-family: inherit; height: 56.692913386499995px; width: 377.95275591px; text-align: left; font-size: 30pt; letter-spacing: 0pt; line-height: 1em; white-space: pre-line; word-break: break-word; color: rgb(0, 0, 0);"
style="position: absolute; top: 0px; padding: 0px 0px 0px 0px; height: 56.692913386499995px; width: 377.95275591px; resize: none; font-family: inherit; color: rgb(0, 0, 0); font-size: 30pt; letter-spacing: 0pt; line-height: 1em; text-align: left; white-space: pre-line; word-break: break-word; margin-top: 0px;"
tabindex="100"
>
field1
Expand Down Expand Up @@ -227,38 +227,42 @@ exports[`Preview(as Viewer) snapshot 1`] = `
title="field1"
>
<div
style="padding: 0px; resize: none; position: absolute; font-family: inherit; height: 56.692913386499995px; width: 377.95275591px; text-align: left; font-size: 30pt; letter-spacing: 0pt; line-height: 1em; white-space: pre-line; word-break: break-word; color: rgb(0, 0, 0);"
style="position: absolute; top: 0px; padding: 0px; height: 56.692913386499995px; width: 377.95275591px; resize: none; font-family: inherit; color: rgb(0, 0, 0); font-size: 30pt; letter-spacing: 0pt; line-height: 1em; text-align: left; white-space: pre-line; word-break: break-word;"
>
<span
style="letter-spacing: inherit;"
<div
style="margin-top: 0px; padding-top: 0px;"
>
f
</span>
<span
style="letter-spacing: inherit;"
>
i
</span>
<span
style="letter-spacing: inherit;"
>
e
</span>
<span
style="letter-spacing: inherit;"
>
l
</span>
<span
style="letter-spacing: inherit;"
>
d
</span>
<span
style="letter-spacing: 0;"
>
1
</span>
<span
style="letter-spacing: inherit;"
>
f
</span>
<span
style="letter-spacing: inherit;"
>
i
</span>
<span
style="letter-spacing: inherit;"
>
e
</span>
<span
style="letter-spacing: inherit;"
>
l
</span>
<span
style="letter-spacing: inherit;"
>
d
</span>
<span
style="letter-spacing: 0;"
>
1
</span>
</div>
</div>
</div>
</div>
Expand Down