Phase 3 implementation. Coordinate system implemented. Initial text box tool implemented.
Some checks failed
Automated Container Build / build-and-push (push) Failing after 4s
CI / Backend (Python) (push) Failing after 17s
CI / Frontend (TypeScript) (push) Failing after 4m48s

This commit is contained in:
Elijah 2026-06-12 16:30:07 -07:00
parent c159ad4f37
commit 4cb038ec78
34 changed files with 6676 additions and 130 deletions

View file

@ -0,0 +1,74 @@
export interface PdfPoint { x: number; y: number }
export interface ScreenPoint { x: number; y: number }
export interface PdfRect { x: number; y: number; width: number; height: number }
export interface ScreenRect { x: number; y: number; width: number; height: number }
export interface ViewportParams {
scale: number; // CSS Zoom level (1.0 = 100%)
rotation: number; // 0, 90, 180, 270 (clockwise)
canonicalWidth: number; // Unrotated CropBox width in PDF points
canonicalHeight: number;// Unrotated CropBox height in PDF points
dpr?: number; // Device Pixel Ratio (defaults to 1)
}
function getEffectiveScale(vp: ViewportParams): number {
return vp.scale * (vp.dpr || 1);
}
export function pdfToScreen(p: PdfPoint, vp: ViewportParams): ScreenPoint {
const s = getEffectiveScale(vp);
const { rotation, canonicalWidth: W, canonicalHeight: H } = vp;
const { x, y } = p;
const rot = ((rotation % 360) + 360) % 360;
switch (rot) {
case 0: return { x: x * s, y: y * s };
case 90: return { x: (H - y) * s, y: x * s };
case 180: return { x: (W - x) * s, y: (H - y) * s };
case 270: return { x: y * s, y: (W - x) * s };
default: throw new Error(`Invalid rotation: ${rotation}`);
}
}
export function screenToPdf(p: ScreenPoint, vp: ViewportParams): PdfPoint {
const s = getEffectiveScale(vp);
const { rotation, canonicalWidth: W, canonicalHeight: H } = vp;
const sx = p.x / s;
const sy = p.y / s;
const rot = ((rotation % 360) + 360) % 360;
switch (rot) {
case 0: return { x: sx, y: sy };
case 90: return { x: sy, y: H - sx };
case 180: return { x: W - sx, y: H - sy };
case 270: return { x: W - sy, y: sx };
default: throw new Error(`Invalid rotation: ${rotation}`);
}
}
export function pdfRectToScreen(r: PdfRect, vp: ViewportParams): ScreenRect {
const p1 = pdfToScreen({ x: r.x, y: r.y }, vp);
const p2 = pdfToScreen({ x: r.x + r.width, y: r.y + r.height }, vp);
return {
x: Math.min(p1.x, p2.x),
y: Math.min(p1.y, p2.y),
width: Math.abs(p2.x - p1.x),
height: Math.abs(p2.y - p1.y)
};
}
export function screenRectToPdf(r: ScreenRect, vp: ViewportParams): PdfRect {
const p1 = screenToPdf({ x: r.x, y: r.y }, vp);
const p2 = screenToPdf({ x: r.x + r.width, y: r.y + r.height }, vp);
return {
x: Math.min(p1.x, p2.x),
y: Math.min(p1.y, p2.y),
width: Math.abs(p2.x - p1.x),
height: Math.abs(p2.y - p1.y)
};
}