From 09d35fd2189002070be49c288cb4d602db4ffcde Mon Sep 17 00:00:00 2001 From: Georges Gabereau Date: Mon, 26 Aug 2019 21:01:24 -0400 Subject: [PATCH 1/3] Implemented PDFPage.drawWrappedText --- src/api/PDFPage.ts | 65 +++++++++++++++++++++++++++++++++++++++ src/api/PDFPageOptions.ts | 4 +++ 2 files changed, 69 insertions(+) diff --git a/src/api/PDFPage.ts b/src/api/PDFPage.ts index 94639f8d5..b89f634c4 100644 --- a/src/api/PDFPage.ts +++ b/src/api/PDFPage.ts @@ -20,6 +20,7 @@ import { PDFPageDrawRectangleOptions, PDFPageDrawSquareOptions, PDFPageDrawTextOptions, + PDFPageDrawWrappedTextOptions, } from 'src/api/PDFPageOptions'; import { degrees, Rotation, toDegrees } from 'src/api/rotations'; import { StandardFonts } from 'src/api/StandardFonts'; @@ -609,6 +610,70 @@ export default class PDFPage { if (options.font) this.setFont(originalFont); } + /** + * Draw a line of text on the page and wrap it at line length `maxWidth`. Default width is the page width. + * + * For example: + * ```js + * import { StandardFonts, rgb } from 'pdf-lib' + * + * const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica) + * const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman) + * + * const page = pdfDoc.addPage() + * + * page.setFont(helveticaFont) + * + * page.moveTo(5, 200) + * page.drawWrappedText( + * 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + * { + * x: 25, + * y: 100, + * font: timesRomanFont, + * size: 24, + * color: rgb(1, 0, 0), + * lineHeight: 24, + * maxWidth: 100, + * } + * ) + * ``` + * @param text The text to be drawn. + * @param options The options to be used when drawing the text. + */ + drawWrappedText( + text: string, + options: PDFPageDrawWrappedTextOptions = {}, + ): void { + assertIs(text, 'text', ['string']); + assertOrUndefined(options.maxWidth, 'options.maxWidth', ['number']); + + const fontSize = options.size || this.fontSize; + if (options.font) this.setFont(options.font); + const [font] = this.getFont(); + + const maxWidth = options.maxWidth || this.getWidth(); + + const words = text.split(' '); + + const wrappedLines = []; + let startIndex = 0; + for (let i = 0; i <= words.length; i++) { + const candidateString = words.slice(startIndex, i).join(' '); + const lengthReached = + font.widthOfTextAtSize(candidateString, fontSize) >= maxWidth; + + if (i < words.length && lengthReached) { + wrappedLines.push(words.slice(startIndex, i - 1).join(' ')); + startIndex = i; + } else if (i === words.length) { + wrappedLines.push(words.slice(startIndex, i - 1).join(' ')); + } + } + + this.drawText(wrappedLines.join('\n'), options); + } + /** * Draw an image on this page. For example: * ```js diff --git a/src/api/PDFPageOptions.ts b/src/api/PDFPageOptions.ts index f29a8066b..983f12bdc 100644 --- a/src/api/PDFPageOptions.ts +++ b/src/api/PDFPageOptions.ts @@ -14,6 +14,10 @@ export interface PDFPageDrawTextOptions { lineHeight?: number; } +export interface PDFPageDrawWrappedTextOptions extends PDFPageDrawTextOptions { + maxWidth?: number; +} + export interface PDFPageDrawImageOptions { x?: number; y?: number; From a663019d9b8aacb34e71d00eb6b8da0e75c0c1a7 Mon Sep 17 00:00:00 2001 From: Georges Gabereau Date: Mon, 26 Aug 2019 21:04:59 -0400 Subject: [PATCH 2/3] Improve the function documentation. --- src/api/PDFPage.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/api/PDFPage.ts b/src/api/PDFPage.ts index b89f634c4..6c925162e 100644 --- a/src/api/PDFPage.ts +++ b/src/api/PDFPage.ts @@ -611,19 +611,16 @@ export default class PDFPage { } /** - * Draw a line of text on the page and wrap it at line length `maxWidth`. Default width is the page width. + * Draw a line of text on the page and wrap it at a specified line length. + * This accepts all the options of `drawText` as well as an additional `maxWidth` option. * * For example: * ```js * import { StandardFonts, rgb } from 'pdf-lib' * - * const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica) * const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman) - * * const page = pdfDoc.addPage() * - * page.setFont(helveticaFont) - * * page.moveTo(5, 200) * page.drawWrappedText( * 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', From 3210810be3a8a0b6dd8ce1e65811041cbbb0a165 Mon Sep 17 00:00:00 2001 From: Georges Gabereau Date: Mon, 26 Aug 2019 21:27:51 -0400 Subject: [PATCH 3/3] Fix off-by-one error. --- src/api/PDFPage.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/PDFPage.ts b/src/api/PDFPage.ts index 6c925162e..9656a1cb1 100644 --- a/src/api/PDFPage.ts +++ b/src/api/PDFPage.ts @@ -661,10 +661,10 @@ export default class PDFPage { font.widthOfTextAtSize(candidateString, fontSize) >= maxWidth; if (i < words.length && lengthReached) { - wrappedLines.push(words.slice(startIndex, i - 1).join(' ')); + wrappedLines.push(words.slice(startIndex, i).join(' ')); startIndex = i; } else if (i === words.length) { - wrappedLines.push(words.slice(startIndex, i - 1).join(' ')); + wrappedLines.push(words.slice(startIndex, i).join(' ')); } }