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 000000000..ae496b092 Binary files /dev/null and b/test/reference/justify-custom-font.pdf differ 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 });