ซ่อม text ไทย PDF (ActualText) + revalidatePath ทุก action + คีย์ลัด DEL + ตรายาง label บรรทัดเดียว
- โหลด PDF ผ่าน /api/pdf?fileId= ที่สร้าง ToUnicode CMap ใหม่บนสำเนาในหน่วยความจำ จาก ActualText ใน marked content (lib/pdf-actual-text.ts + unit tests) — แก้ ฟอนต์ไทยที่ cmap เพี้ยน (คำสั่งศาล) ให้ textLayer select/copy/ค้นหา/ชื่อ bookmark ถูกต้องตั้งแต่ต้น ไฟล์ใน public/ ไม่ถูกแตะ (invariant #1) — PDF ปกติได้ bytes เดิม ไม่มี cost และ fail แล้ว PDFViewer fallback fetch ไฟล์ดิบเอง - ข้อความจาก selection ห้าม selection.toString() ตรง ๆ: ใช้ selectionTextWithin เดินทีละอักษร เรียงตามตำแหน่งบนจอ (จัดการ Thai combining marks + ctrl ขยะ) ปิดท้ายด้วย sanitizePdfText ก่อนเก็บ DB/ชื่อ bookmark/คลิปบอร์ด (มี tests) - mergeRectsByLine ใช้ median ความสูง rect คำนวณเกณฑ์บรรทัดแทนค่าคงที่ - Server Actions ทุกตัวที่เขียน DB เรียก revalidateFilePages (revalidatePath หน้า viewer+summary) คู่กับ publish event — แก้กด back แล้วเข้าไฟล์ใหม่ได้ RSC payload เก่าจาก Router Cache ฝั่ง client จนต้อง hard refresh - คีย์ลัด DEL/Backspace ลบ annotation ที่เลือกอยู่ (ของตัวเองเท่านั้น ข้ามเมื่อ focus อยู่ใน input/textarea/select/contenteditable) - STAMP: ย่อฟอนต์ label ให้อยู่บรรทัดเดียวพอดีกรอบทั้งบนจอ (canvas measure) และ export PDF (stampFitFontSize แชร์กัน) + เพิ่ม handle ปรับขนาดตรายางในแผง selection (uniform scale + clamp รายแกน) - sync invariant/กติกา: CLAUDE.md #4, rules/*.md, PLAN-FEAT.md (F3) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
289d735bf3
commit
6fd3a1515f
19 changed files with 890 additions and 53 deletions
|
|
@ -244,6 +244,29 @@ describe("scaleAnnotationData", () => {
|
|||
expect(out).toEqual({ position: { x: 50, y: 10 }, message: "m" });
|
||||
});
|
||||
|
||||
it("STAMP anchor มุมตรงข้าม ×2: position ขยายจาก anchor และ scale ×2", () => {
|
||||
// bbox เดิม x 10 y 20 กว้าง 18 สูง 7.2 → anchor = มุมขวาล่าง (28, 27.2)
|
||||
const out = scaleAnnotationData(
|
||||
{ label: "สำคัญ", position: { x: 10, y: 20 }, scale: 18 },
|
||||
{ x: 28, y: 27.2 },
|
||||
2,
|
||||
2,
|
||||
);
|
||||
expect(out).toEqual({ label: "สำคัญ", position: { x: -8, y: 12.8 }, scale: 36 });
|
||||
});
|
||||
|
||||
it("STAMP หลังขยาย ×k รอบ anchor: bbox ใหม่ = ขอบเดิม ×k รอบ anchor (กว้าง-สูงผูกกัน)", () => {
|
||||
const data = { label: "สำคัญ", position: { x: 10, y: 20 }, scale: 18 };
|
||||
const anchor = { x: 28, y: 27.2 };
|
||||
const out = scaleAnnotationData(data, anchor, 1.5, 1.5);
|
||||
const before = annotationBBox({ type: "STAMP", data }, S);
|
||||
const after = annotationBBox({ type: "STAMP", data: out }, S);
|
||||
expect(after.width).toBeCloseTo(before.width * 1.5);
|
||||
expect(after.height).toBeCloseTo(before.height * 1.5); // สัดส่วน 0.4 คงเดิม
|
||||
expect(after.x + after.width).toBeCloseTo(anchor.x); // ขอบที่ anchor อยู่นิ่ง
|
||||
expect(after.y + after.height).toBeCloseTo(anchor.y);
|
||||
});
|
||||
|
||||
it("DRAW: strokeWidth คงเดิมตามสเปก F1", () => {
|
||||
const out = scaleAnnotationData(
|
||||
{ strokeColor: "#000", strokeWidth: 2, paths: [{ x: 0, y: 0 }] },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue