diff --git a/plugins/plugin-print/src/__image_snapshots__/index-node-test-ts-src-index-node-test-ts-write-text-over-image-max-width-works-without-spaces-1-snap.png b/plugins/plugin-print/src/__image_snapshots__/index-node-test-ts-src-index-node-test-ts-write-text-over-image-max-width-works-without-spaces-1-snap.png new file mode 100644 index 00000000..f244013a Binary files /dev/null and b/plugins/plugin-print/src/__image_snapshots__/index-node-test-ts-src-index-node-test-ts-write-text-over-image-max-width-works-without-spaces-1-snap.png differ diff --git a/plugins/plugin-print/src/index.node.test.ts b/plugins/plugin-print/src/index.node.test.ts index 7cb55c72..bebf627c 100644 --- a/plugins/plugin-print/src/index.node.test.ts +++ b/plugins/plugin-print/src/index.node.test.ts @@ -109,6 +109,24 @@ describe("Write text over image", function () { expect(output).toMatchImageSnapshot(); }); + test("Max width works without spaces", async () => { + const font = await loadFont( + "https://raw.githubusercontent.com/jimp-dev/jimp/main/plugins/plugin-print/fonts/open-sans/open-sans-16-black/open-sans-16-black.fnt" + ); + const image = new Jimp({ width: 300, height: 100, color: 0xff8800ff }); + const output = await image + .print({ + font, + x: 150, + y: 50, + text: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + maxWidth: 100, + }) + .getBuffer("image/png"); + + expect(output).toMatchImageSnapshot(); + }); + test("Jimp renders ? for unknown characters", async () => { const font = await loadFont(fonts.SANS_16_BLACK); const image = new Jimp({ width: 300, height: 100, color: 0xff8800ff }); diff --git a/plugins/plugin-print/src/measure-text.ts b/plugins/plugin-print/src/measure-text.ts index 6bb5e894..0f6cf999 100644 --- a/plugins/plugin-print/src/measure-text.ts +++ b/plugins/plugin-print/src/measure-text.ts @@ -30,6 +30,34 @@ export function splitLines(font: BmFont, text: string, maxWidth: number) { let longestLine = 0; words.forEach((word) => { + const wordWidth = measureText(font, word + (words.length > 1 ? " " : "")); + + // If a word is longer than the allowable width we need to split it across lines. + if (wordWidth > maxWidth) { + const characterIterator = word[Symbol.iterator](); + + let current = ""; + + for (const char of characterIterator) { + const nextLine = [...currentLine, current + char].join(" "); + const length = measureText(font, nextLine); + + if (length < maxWidth) { + current += char; + } else if (length > maxWidth) { + lines.push([...currentLine, current]); + currentLine = []; + current = char; + } else { + lines.push([...currentLine, current + char]); + currentLine = []; + current = ""; + } + } + + return; + } + const line = [...currentLine, word].join(" "); const length = measureText(font, line);