1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-22 16:18:08 +02:00

[Editor] Try to make the position of an edited FreeText the more accurated as possible

- Take into account the page translation,
- Take into account the correct translation for the editor border,
- Take into account the position of the first glyph in the annotation,
- Take into account the rotation of the editor.

Close #16633.
This commit is contained in:
Calixte Denizet 2023-07-05 19:46:21 +02:00
parent 35202ec0f3
commit 944c68ee85
11 changed files with 424 additions and 59 deletions

View file

@ -546,7 +546,7 @@ class Annotation {
const MK = dict.get("MK");
this.setBorderAndBackgroundColors(MK);
this.setRotation(MK);
this.setRotation(MK, dict);
this.ref = params.ref instanceof Ref ? params.ref : null;
this._streams = [];
@ -838,18 +838,21 @@ class Annotation {
}
}
setRotation(mk) {
setRotation(mk, dict) {
this.rotation = 0;
let angle;
if (mk instanceof Dict) {
let angle = mk.get("R") || 0;
if (Number.isInteger(angle) && angle !== 0) {
angle %= 360;
if (angle < 0) {
angle += 360;
}
if (angle % 90 === 0) {
this.rotation = angle;
}
angle = mk.get("R") || 0;
} else {
angle = dict.get("Rotate") || 0;
}
if (Number.isInteger(angle) && angle !== 0) {
angle %= 360;
if (angle < 0) {
angle += 360;
}
if (angle % 90 === 0) {
this.rotation = angle;
}
}
}
@ -1069,6 +1072,7 @@ class Annotation {
const text = [];
const buffer = [];
let firstPosition = null;
const sink = {
desiredSize: Math.Infinity,
ready: true,
@ -1078,6 +1082,7 @@ class Annotation {
if (item.str === undefined) {
continue;
}
firstPosition ||= item.transform.slice(-2);
buffer.push(item.str);
if (item.hasEOL) {
text.push(buffer.join(""));
@ -1102,6 +1107,17 @@ class Annotation {
}
if (text.length > 1 || text[0]) {
const appearanceDict = this.appearance.dict;
const bbox = appearanceDict.getArray("BBox") || [0, 0, 1, 1];
const matrix = appearanceDict.getArray("Matrix") || [1, 0, 0, 1, 0, 0];
const rect = this.data.rect;
const transform = getTransformMatrix(rect, bbox, matrix);
transform[4] -= rect[0];
transform[5] -= rect[1];
firstPosition = Util.applyTransform(firstPosition, transform);
firstPosition = Util.applyTransform(firstPosition, matrix);
this.data.textPosition = firstPosition;
this.data.textContent = text;
}
}

View file

@ -304,6 +304,9 @@ class AnnotationElement {
}
setRotation(angle, container = this.container) {
if (!this.data.rect) {
return;
}
const { pageWidth, pageHeight } = this.parent.viewport.rawDims;
const { width, height } = getRectDims(this.data.rect);
@ -2210,6 +2213,7 @@ class FreeTextAnnotationElement extends AnnotationElement {
);
super(parameters, { isRenderable, ignoreBorder: true });
this.textContent = parameters.data.textContent;
this.textPosition = parameters.data.textPosition;
this.annotationEditorType = AnnotationEditorType.FREETEXT;
}

View file

@ -296,6 +296,24 @@ class AnnotationEditor {
}
}
/**
* Convert a page translation into a screen one.
* @param {number} x
* @param {number} y
*/
pageTranslationToScreen(x, y) {
switch (this.parentRotation) {
case 90:
return [-y, x];
case 180:
return [-x, -y];
case 270:
return [y, -x];
default:
return [x, y];
}
}
get parentScale() {
return this._uiManager.viewParameters.realScale;
}
@ -398,6 +416,9 @@ class AnnotationEditor {
this.#hasBeenSelected = true;
}
/**
* Convert the current rect into a page one.
*/
getRect(tx, ty) {
const scale = this.parentScale;
const [pageWidth, pageHeight] = this.pageDimensions;

View file

@ -502,8 +502,47 @@ class FreeTextEditor extends AnnotationEditor {
// This editor was created in using copy (ctrl+c).
const [parentWidth, parentHeight] = this.parentDimensions;
if (this.annotationElementId) {
const [tx] = this.getInitialTranslation();
this.setAt(baseX * parentWidth, baseY * parentHeight, tx, tx);
// This stuff is hard to test: if something is changed here, please
// test with the following PDF file:
// - freetexts.pdf
// - rotated_freetexts.pdf
// Only small variations between the original annotation and its editor
// are allowed.
// position is the position of the first glyph in the annotation
// and it's relative to its container.
const { position } = this.#initialData;
let [tx, ty] = this.getInitialTranslation();
[tx, ty] = this.pageTranslationToScreen(tx, ty);
const [pageWidth, pageHeight] = this.pageDimensions;
const [pageX, pageY] = this.pageTranslation;
let posX, posY;
switch (this.rotation) {
case 0:
posX = baseX + (position[0] - pageX) / pageWidth;
posY = baseY + this.height - (position[1] - pageY) / pageHeight;
break;
case 90:
posX = baseX + (position[0] - pageX) / pageWidth;
posY = baseY - (position[1] - pageY) / pageHeight;
[tx, ty] = [ty, -tx];
break;
case 180:
posX = baseX - this.width + (position[0] - pageX) / pageWidth;
posY = baseY - (position[1] - pageY) / pageHeight;
[tx, ty] = [-tx, -ty];
break;
case 270:
posX =
baseX +
(position[0] - pageX - this.height * pageHeight) / pageWidth;
posY =
baseY +
(position[1] - pageY - this.width * pageWidth) / pageHeight;
[tx, ty] = [-ty, tx];
break;
}
this.setAt(posX * parentWidth, posY * parentHeight, tx, ty);
} else {
this.setAt(
baseX * parentWidth,
@ -521,6 +560,10 @@ class FreeTextEditor extends AnnotationEditor {
this.editorDiv.contentEditable = true;
}
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
this.div.setAttribute("annotation-id", this.annotationElementId);
}
return this.div;
}
@ -554,6 +597,7 @@ class FreeTextEditor extends AnnotationEditor {
id,
},
textContent,
textPosition,
parent: {
page: { pageNumber },
},
@ -569,6 +613,7 @@ class FreeTextEditor extends AnnotationEditor {
color: Array.from(fontColor),
fontSize,
value: textContent.join("\n"),
position: textPosition,
pageIndex: pageNumber - 1,
rect,
rotation,