From 2d9a91916471f1fbe465dbcdc05db0cf22d720ec Mon Sep 17 00:00:00 2001 From: Owen Leong Date: Fri, 11 Feb 2022 23:34:56 +0800 Subject: [PATCH] Implement justifying for unicode fonts (#3285) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lukas Holländer --- src/jspdf.js | 58 +++++++++++++++++++------ test/reference/justify-custom-font.pdf | Bin 0 -> 47504 bytes test/specs/text.spec.js | 19 ++++++++ 3 files changed, 63 insertions(+), 14 deletions(-) create mode 100644 test/reference/justify-custom-font.pdf diff --git a/src/jspdf.js b/src/jspdf.js index fa3dd923d..dc009f313 100644 --- a/src/jspdf.js +++ b/src/jspdf.js @@ -3806,23 +3806,23 @@ function jsPDF(options) { flags = Object.assign({ autoencode: true, noBOM: true }, options.flags); var wordSpacingPerLine = []; - + var findWidth = function(v) { + return ( + (scope.getStringUnitWidth(v, { + font: activeFont, + charSpace: charSpace, + fontSize: activeFontSize, + doKerning: false + }) * + activeFontSize) / + scaleFactor + ); + }; if (Object.prototype.toString.call(text) === "[object Array]") { da = transformTextToSpecialArray(text); var newY; if (align !== "left") { - lineWidths = da.map(function(v) { - return ( - (scope.getStringUnitWidth(v, { - font: activeFont, - charSpace: charSpace, - fontSize: activeFontSize, - doKerning: false - }) * - activeFontSize) / - scaleFactor - ); - }); + lineWidths = da.map(findWidth); } //The first line uses the "main" Td setting, //and the subsequent lines are offset by the @@ -3869,11 +3869,41 @@ function jsPDF(options) { for (var h = 0; h < len; h++) { text.push(da[h]); } + } else if (align === "justify" && activeFont.encoding === "Identity-H") { + // when using unicode fonts, wordSpacePerLine does not apply + text = []; + len = da.length; + maxWidth = maxWidth !== 0 ? maxWidth : pageWidth; + let backToStartX = 0; + for (var l = 0; l < len; l++) { + newY = l === 0 ? getVerticalCoordinate(y) : -leading; + newX = l === 0 ? getHorizontalCoordinate(x) : backToStartX; + if (l < len - 1) { + let spacing = scale( + (maxWidth - lineWidths[l]) / (da[l].split(" ").length - 1) + ); + let words = da[l].split(" "); + text.push([words[0] + " ", newX, newY]); + backToStartX = 0; // distance to reset back to the left + for (let i = 1; i < words.length; i++) { + let shiftAmount = + (findWidth(words[i - 1] + " " + words[i]) - + findWidth(words[i])) * + scaleFactor + + spacing; + if (i == words.length - 1) text.push([words[i], shiftAmount, 0]); + else text.push([words[i] + " ", shiftAmount, 0]); + backToStartX -= shiftAmount; + } + } else { + text.push([da[l], newX, newY]); + } + } + text.push(["", backToStartX, 0]); } else if (align === "justify") { text = []; len = da.length; maxWidth = maxWidth !== 0 ? maxWidth : pageWidth; - for (var l = 0; l < len; l++) { newY = l === 0 ? getVerticalCoordinate(y) : -leading; newX = l === 0 ? getHorizontalCoordinate(x) : 0; diff --git a/test/reference/justify-custom-font.pdf b/test/reference/justify-custom-font.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ae496b092432bef923856816aa78b708ece93343 GIT binary patch literal 47504 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%0A5@KreNMx9b;Yk0|4yE*-=b6`mK(P zd+@twPG$tmr#Rd9WK)qvgyXI*t!is*wyHY$v(qYk*}E^c#V#A{vW5Bvkn~Sg&2WH* zuI8XsZC{0~8v81Y&rTWrjaZH*SA*YnV~rKCHKn=Mf>$(M>#P9TL#;x2&ht2^9BRU5S9PqvB;#TwHX%IbK5(Mw~cQB!63~tX_eZ>gb;IG8LHP8Y3 z8zPPTQD{XH?0j7vUf&XAUJa@KEquH;-~iu;wy_MwN-~tZmX$* z8q645ckFNLg literal 0 HcmV?d00001 diff --git a/test/specs/text.spec.js b/test/specs/text.spec.js index 168eb31ff..0a48280dc 100644 --- a/test/specs/text.spec.js +++ b/test/specs/text.spec.js @@ -175,6 +175,25 @@ break` comparePdf(doc.output(), "alignment.pdf", "text"); }); + it("should justify custom font", () => { + const doc = jsPDF({ floatPrecision: 2 }); + var PTSans; + if (typeof global === "object" && global.isNode === true) { + PTSans = doc.loadFile("./test/reference/PTSans.ttf"); + } else { + PTSans = doc.loadFile("base/test/reference/PTSans.ttf"); + } + doc.addFileToVFS("PTSans.ttf", PTSans); + doc.addFont("PTSans.ttf", "PTSans", "normal"); + doc.setFont("PTSans"); + doc.setFontSize(10); + doc.text("А ну чики брики и в дамки! А ну чики брики и в дамки! А ну чики брики и в дамки! А ну чики брики и в дамки! А ну чики брики и в дамки! А ну чики брики и в дамки! А ну чики брики и в дамки! А ну чики брики и в дамки! А ну чики брики и в дамки! ", 10, 10, { + align: "justify", + maxWidth: 100, + }); + comparePdf(doc.output(), "justify-custom-font.pdf", "text"); + }); + it("should throw an error if not a string", () => { expect(() => { const doc = jsPDF({ floatPrecision: 2 });