[Editor] When saving/printing a FreeText, use the identity matrix for the AP and set the cm when rendering it

When there was a rotation, the generated bbox was wrong because of an inversion
between width and height.
This patch aims to fix this issue in re-writing the FreeText code generation
to have something similar to what Acrobat does.
And fix the name of the font which wasn't the correct one when calling the
evaluator.
This commit is contained in:
Calixte Denizet 2023-07-05 14:58:09 +02:00
parent 6d82f7f66f
commit 77656ce881
2 changed files with 47 additions and 23 deletions

View File

@ -3743,7 +3743,7 @@ class FreeTextAnnotation extends MarkupAnnotation {
evaluator,
task,
{
fontName: "Helvetica",
fontName: "Helv",
fontSize,
},
resources
@ -3783,26 +3783,52 @@ class FreeTextAnnotation extends MarkupAnnotation {
}
let vscale = 1;
const lineHeight = LINE_FACTOR * fontSize;
const lineDescent = LINE_DESCENT_FACTOR * fontSize;
const lineAscent = (LINE_FACTOR - LINE_DESCENT_FACTOR) * fontSize;
const totalHeight = lineHeight * lines.length;
if (totalHeight > h) {
vscale = h / totalHeight;
}
const fscale = Math.min(hscale, vscale);
const newFontSize = fontSize * fscale;
let firstPoint, clipBox, matrix;
switch (rotation) {
case 0:
matrix = [1, 0, 0, 1];
clipBox = [rect[0], rect[1], w, h];
firstPoint = [rect[0], rect[3] - lineAscent];
break;
case 90:
matrix = [0, 1, -1, 0];
clipBox = [rect[1], -rect[2], w, h];
firstPoint = [rect[1], -rect[0] - lineAscent];
break;
case 180:
matrix = [-1, 0, 0, -1];
clipBox = [-rect[2], -rect[3], w, h];
firstPoint = [-rect[2], -rect[1] - lineAscent];
break;
case 270:
matrix = [0, -1, 1, 0];
clipBox = [-rect[3], rect[0], w, h];
firstPoint = [-rect[3], rect[2] - lineAscent];
break;
}
const buffer = [
"q",
`0 0 ${numberToString(w)} ${numberToString(h)} re W n`,
`${matrix.join(" ")} 0 0 cm`,
`${clipBox.join(" ")} re W n`,
`BT`,
`1 0 0 1 0 ${numberToString(h + lineDescent)} Tm 0 Tc ${getPdfColor(
color,
/* isFill */ true
)}`,
`/Helv ${numberToString(newFontSize)} Tf`,
`${getPdfColor(color, /* isFill */ true)}`,
`0 Tc /Helv ${numberToString(newFontSize)} Tf`,
];
buffer.push(
`${firstPoint.join(" ")} Td (${escapeString(encodedLines[0])}) Tj`
);
const vShift = numberToString(lineHeight);
for (const line of encodedLines) {
for (let i = 1, ii = encodedLines.length; i < ii; i++) {
const line = encodedLines[i];
buffer.push(`0 -${vShift} Td (${escapeString(line)}) Tj`);
}
buffer.push("ET", "Q");
@ -3812,13 +3838,9 @@ class FreeTextAnnotation extends MarkupAnnotation {
appearanceStreamDict.set("FormType", 1);
appearanceStreamDict.set("Subtype", Name.get("Form"));
appearanceStreamDict.set("Type", Name.get("XObject"));
appearanceStreamDict.set("BBox", [0, 0, w, h]);
appearanceStreamDict.set("BBox", rect);
appearanceStreamDict.set("Resources", resources);
if (rotation) {
const matrix = getRotationMatrix(rotation, w, h);
appearanceStreamDict.set("Matrix", matrix);
}
appearanceStreamDict.set("Matrix", [1, 0, 0, 1, -rect[0], -rect[1]]);
const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;

View File

@ -4110,14 +4110,16 @@ describe("annotation", function () {
const appearance = data.dependencies[1].data;
expect(appearance).toEqual(
"3 0 obj\n" +
"<< /FormType 1 /Subtype /Form /Type /XObject /BBox [0 0 44 44] " +
"/Resources << /Font << /Helv 1 0 R>>>> /Length 101>> stream\n" +
"<< /FormType 1 /Subtype /Form /Type /XObject /BBox [12 34 56 78] " +
"/Resources << /Font << /Helv 1 0 R>>>> /Matrix [1 0 0 1 -12 -34] " +
"/Length 98>> stream\n" +
"q\n" +
"0 0 44 44 re W n\n" +
"1 0 0 1 0 0 cm\n" +
"12 34 44 44 re W n\n" +
"BT\n" +
"1 0 0 1 0 47.5 Tm 0 Tc 0 g\n" +
"/Helv 10 Tf\n" +
"0 -13.5 Td (Hello PDF.js World!) Tj\n" +
"0 g\n" +
"0 Tc /Helv 10 Tf\n" +
"12 68 Td (Hello PDF.js World!) Tj\n" +
"ET\n" +
"Q\n" +
"endstream\n" +
@ -4153,13 +4155,13 @@ describe("annotation", function () {
expect(opList.fnArray).toEqual([
OPS.beginAnnotation,
OPS.save,
OPS.transform,
OPS.constructPath,
OPS.clip,
OPS.endPath,
OPS.beginText,
OPS.setTextMatrix,
OPS.setCharSpacing,
OPS.setFillRGBColor,
OPS.setCharSpacing,
OPS.dependency,
OPS.setFont,
OPS.moveText,