Skip to content

Commit

Permalink
Add full support for text annotations in rotated pages
Browse files Browse the repository at this point in the history
  • Loading branch information
mrtcode committed Dec 13, 2023
1 parent 62999fe commit e9cf1d3
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/pdf/lib/coordinates.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function p2v(position, viewport) {

// For text annotations
if (position.fontSize) {
position2.fontSize = viewport.convertToViewportPoint(position.fontSize, 0)[0];
position2.fontSize = position.fontSize * viewport.scale;
}
if (position.rotation) {
position2.rotation = position.rotation;
Expand Down
62 changes: 51 additions & 11 deletions src/pdf/lib/render.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { p2v } from './coordinates';
import { getRotationTransform } from './utilities';
import {
applyInverseTransform,
applyTransform,
transform
} from './utilities';

function calculateLines(context, text, maxWidth) {
let words = text.split(' ');
Expand Down Expand Up @@ -111,20 +115,56 @@ export function drawAnnotationsOnCanvas(canvas, viewport, annotations) {
ctx.stroke();
}
else if (annotation.type === 'text') {
let fontSize = position.fontSize;
let lineHeight = fontSize * 1.2; // 1.2 is a common line height for many fonts
let position = annotation.position;
let rect = position.rects[0];
let x = rect[0];
let y = rect[3] - lineHeight;
let width = rect[2] - rect[0] + 10;
let width = rect[2] - rect[0];
let lineHeight = position.fontSize * 1.2; // 1.2 is a common line height for many fonts
ctx.fillStyle = annotation.color;
ctx.font = fontSize + 'px ' + window.computedFontFamily;
ctx.font = position.fontSize + 'px ' + window.computedFontFamily;

// Translation matrix where the drawing starts
let x = rect[0];
let y = rect[1];
let translatedViewportMatrix = transform(viewport.transform, [1, 0, 0, 1, x, y]);

// Rotation matrix
let degrees = -position.rotation * Math.PI / 180;
let cosValue = Math.cos(degrees);
let sinValue = Math.sin(degrees);
let rotationMatrix = [cosValue, sinValue, -sinValue, cosValue, 0, 0];

// Flip matrix because text gets inverted otherwise
let flipMatrix = [1, 0, 0, -1, 0, 0];
// Combine flip and rotation matrices
let flipAndRotationMatrix = transform(flipMatrix, rotationMatrix);

// Annotation center without x and y coordinates because we translate the viewport
let centerX = (rect[2] - rect[0]) / 2;
let centerY = (rect[3] - rect[1]) / 2;

// Calculate center in the viewport matrix
let [x1, y1] = applyTransform([centerX, centerY], translatedViewportMatrix);
let [x2, y2] = applyTransform([centerX, centerY], transform(translatedViewportMatrix, flipAndRotationMatrix));

// Annotation center drift after applying flip and rotation matrix
let deltaX = x1 - x2;
let deltaY = y1 - y2;

// Adjust delta x and y scale and sign
let viewportWithoutTranslationMatrix = viewport.transform.slice();
viewportWithoutTranslationMatrix[4] = viewportWithoutTranslationMatrix[5] = 0;
[deltaX, deltaY] = applyInverseTransform([deltaX, deltaY], viewportWithoutTranslationMatrix);
// Correct flipAndRotationMatrix to have rotation and flip around the annotation center
flipAndRotationMatrix[4] = deltaX;
flipAndRotationMatrix[5] = deltaY;

let finalMatrix = transform(translatedViewportMatrix, flipAndRotationMatrix);
ctx.transform(...finalMatrix);
let lineIndex = 0;
let lines = calculateLines(ctx, annotation.comment, width);
let tm = getRotationTransform(rect, -position.rotation);
ctx.transform(...tm);
for (let line of lines) {
ctx.fillText(line, x, y);
y += lineHeight;
ctx.fillText(line, 0, lineIndex * lineHeight + lineHeight);
lineIndex++;
}
}
ctx.restore();
Expand Down
32 changes: 18 additions & 14 deletions src/pdf/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
transform,
scaleShape,
getRotationDegrees,
normalizeDegrees
normalizeDegrees,
inverseTransform
} from './lib/utilities';
import { DARKEN_INK_AND_TEXT_COLOR, MIN_IMAGE_ANNOTATION_SIZE, SELECTION_COLOR } from '../common/defines';
import { getRectRotationOnText } from './selection';
Expand Down Expand Up @@ -382,21 +383,26 @@ export default class Page {

for (let annotation of annotations) {
if (annotation.type === 'text' && annotation.position.pageIndex === this.pageIndex) {

let position = annotation.position;

if (action && ['resize', 'rotate'].includes(action.type) && action.annotation.id === annotation.id) {
let rect = position.rects[0];
if (action && action.position && ['resize', 'rotate'].includes(action.type) && action.annotation.id === annotation.id) {
position = action.position;
}

let node = customAnnotations.find(x => x.getAttribute('data-id') === annotation.id);

let disabled = this.layer._readOnly || annotation.readOnly;

let top = this.originalPage.viewport.viewBox[3] - position.rects[0][3];
let left = position.rects[0][0];
let width = position.rects[0][2] - position.rects[0][0];
let height = position.rects[0][3] - position.rects[0][1];
let viewport = this.originalPage.viewport;
let centerX = (rect[0] + rect[2]) / 2;
let centerY = (rect[1] + rect[3]) / 2;
// Exclude scale from viewport transform
let m = transform(inverseTransform([viewport.scale, 0, 0, viewport.scale, 0, 0]), viewport.transform);
let [x, y] = applyTransform([centerX, centerY], m);
let width = rect[2] - rect[0];
let height = rect[3] - rect[1];
let top = y - height / 2;
let left = x - width / 2;

let rotation = viewport.rotation - (position.rotation || 0);

let style = [
`left: calc(${left}px * var(--scale-factor))`,
Expand All @@ -407,11 +413,9 @@ export default class Page {
`height: calc(${height}px * var(--scale-factor))`,
`color: ${darkenHex(annotation.color, DARKEN_INK_AND_TEXT_COLOR)}`,
`font-size: calc(${position.fontSize}px * var(--scale-factor))`,
`font-family: ${window.computedFontFamily}`
`font-family: ${window.computedFontFamily}`,
`transform: rotate(${rotation}deg)`
];
if (position.rotation) {
style.push(`transform: rotate(${-position.rotation}deg)`);
}

style = style.join(';');

Expand Down

0 comments on commit e9cf1d3

Please sign in to comment.