yom-format 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +86 -0
  3. package/dist/cli.d.ts +30 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +344 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/index.d.ts +36 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +25 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/pipeline/avif.d.ts +3 -0
  12. package/dist/pipeline/avif.d.ts.map +1 -0
  13. package/dist/pipeline/avif.js +30 -0
  14. package/dist/pipeline/avif.js.map +1 -0
  15. package/dist/pipeline/convert.d.ts +28 -0
  16. package/dist/pipeline/convert.d.ts.map +1 -0
  17. package/dist/pipeline/convert.js +111 -0
  18. package/dist/pipeline/convert.js.map +1 -0
  19. package/dist/pipeline/index.d.ts +17 -0
  20. package/dist/pipeline/index.d.ts.map +1 -0
  21. package/dist/pipeline/index.js +17 -0
  22. package/dist/pipeline/index.js.map +1 -0
  23. package/dist/pipeline/ocrLayoutBuilder.d.ts +10 -0
  24. package/dist/pipeline/ocrLayoutBuilder.d.ts.map +1 -0
  25. package/dist/pipeline/ocrLayoutBuilder.js +62 -0
  26. package/dist/pipeline/ocrLayoutBuilder.js.map +1 -0
  27. package/dist/pipeline/pdfDocument.d.ts +12 -0
  28. package/dist/pipeline/pdfDocument.d.ts.map +1 -0
  29. package/dist/pipeline/pdfDocument.js +76 -0
  30. package/dist/pipeline/pdfDocument.js.map +1 -0
  31. package/dist/pipeline/renderPage.d.ts +10 -0
  32. package/dist/pipeline/renderPage.d.ts.map +1 -0
  33. package/dist/pipeline/renderPage.js +36 -0
  34. package/dist/pipeline/renderPage.js.map +1 -0
  35. package/dist/pipeline/textExtract.d.ts +29 -0
  36. package/dist/pipeline/textExtract.d.ts.map +1 -0
  37. package/dist/pipeline/textExtract.js +48 -0
  38. package/dist/pipeline/textExtract.js.map +1 -0
  39. package/dist/yom/blobLimits.d.ts +15 -0
  40. package/dist/yom/blobLimits.d.ts.map +1 -0
  41. package/dist/yom/blobLimits.js +25 -0
  42. package/dist/yom/blobLimits.js.map +1 -0
  43. package/dist/yom/byteSource.d.ts +56 -0
  44. package/dist/yom/byteSource.d.ts.map +1 -0
  45. package/dist/yom/byteSource.js +111 -0
  46. package/dist/yom/byteSource.js.map +1 -0
  47. package/dist/yom/bytes.d.ts +2 -0
  48. package/dist/yom/bytes.d.ts.map +1 -0
  49. package/dist/yom/bytes.js +13 -0
  50. package/dist/yom/bytes.js.map +1 -0
  51. package/dist/yom/constants.d.ts +34 -0
  52. package/dist/yom/constants.d.ts.map +1 -0
  53. package/dist/yom/constants.js +82 -0
  54. package/dist/yom/constants.js.map +1 -0
  55. package/dist/yom/errors.d.ts +44 -0
  56. package/dist/yom/errors.d.ts.map +1 -0
  57. package/dist/yom/errors.js +44 -0
  58. package/dist/yom/errors.js.map +1 -0
  59. package/dist/yom/flatbufferVerify.d.ts +21 -0
  60. package/dist/yom/flatbufferVerify.d.ts.map +1 -0
  61. package/dist/yom/flatbufferVerify.js +255 -0
  62. package/dist/yom/flatbufferVerify.js.map +1 -0
  63. package/dist/yom/generated/yomu/yom/blob-kind.d.ts +9 -0
  64. package/dist/yom/generated/yomu/yom/blob-kind.d.ts.map +1 -0
  65. package/dist/yom/generated/yomu/yom/blob-kind.js +12 -0
  66. package/dist/yom/generated/yomu/yom/blob-kind.js.map +1 -0
  67. package/dist/yom/generated/yomu/yom/blob-ref.d.ts +45 -0
  68. package/dist/yom/generated/yomu/yom/blob-ref.d.ts.map +1 -0
  69. package/dist/yom/generated/yomu/yom/blob-ref.js +141 -0
  70. package/dist/yom/generated/yomu/yom/blob-ref.js.map +1 -0
  71. package/dist/yom/generated/yomu/yom/book-metadata.d.ts +32 -0
  72. package/dist/yom/generated/yomu/yom/book-metadata.d.ts.map +1 -0
  73. package/dist/yom/generated/yomu/yom/book-metadata.js +89 -0
  74. package/dist/yom/generated/yomu/yom/book-metadata.js.map +1 -0
  75. package/dist/yom/generated/yomu/yom/compression.d.ts +5 -0
  76. package/dist/yom/generated/yomu/yom/compression.d.ts.map +1 -0
  77. package/dist/yom/generated/yomu/yom/compression.js +8 -0
  78. package/dist/yom/generated/yomu/yom/compression.js.map +1 -0
  79. package/dist/yom/generated/yomu/yom/main-index.d.ts +63 -0
  80. package/dist/yom/generated/yomu/yom/main-index.d.ts.map +1 -0
  81. package/dist/yom/generated/yomu/yom/main-index.js +208 -0
  82. package/dist/yom/generated/yomu/yom/main-index.js.map +1 -0
  83. package/dist/yom/generated/yomu/yom/ocrblock.d.ts +32 -0
  84. package/dist/yom/generated/yomu/yom/ocrblock.d.ts.map +1 -0
  85. package/dist/yom/generated/yomu/yom/ocrblock.js +84 -0
  86. package/dist/yom/generated/yomu/yom/ocrblock.js.map +1 -0
  87. package/dist/yom/generated/yomu/yom/ocrlayout.d.ts +27 -0
  88. package/dist/yom/generated/yomu/yom/ocrlayout.d.ts.map +1 -0
  89. package/dist/yom/generated/yomu/yom/ocrlayout.js +76 -0
  90. package/dist/yom/generated/yomu/yom/ocrlayout.js.map +1 -0
  91. package/dist/yom/generated/yomu/yom/ocrline.d.ts +35 -0
  92. package/dist/yom/generated/yomu/yom/ocrline.d.ts.map +1 -0
  93. package/dist/yom/generated/yomu/yom/ocrline.js +95 -0
  94. package/dist/yom/generated/yomu/yom/ocrline.js.map +1 -0
  95. package/dist/yom/generated/yomu/yom/ocrpage.d.ts +46 -0
  96. package/dist/yom/generated/yomu/yom/ocrpage.d.ts.map +1 -0
  97. package/dist/yom/generated/yomu/yom/ocrpage.js +147 -0
  98. package/dist/yom/generated/yomu/yom/ocrpage.js.map +1 -0
  99. package/dist/yom/generated/yomu/yom/ocrtoken.d.ts +44 -0
  100. package/dist/yom/generated/yomu/yom/ocrtoken.d.ts.map +1 -0
  101. package/dist/yom/generated/yomu/yom/ocrtoken.js +128 -0
  102. package/dist/yom/generated/yomu/yom/ocrtoken.js.map +1 -0
  103. package/dist/yom/generated/yomu/yom/outline-entry.d.ts +31 -0
  104. package/dist/yom/generated/yomu/yom/outline-entry.d.ts.map +1 -0
  105. package/dist/yom/generated/yomu/yom/outline-entry.js +92 -0
  106. package/dist/yom/generated/yomu/yom/outline-entry.js.map +1 -0
  107. package/dist/yom/generated/yomu/yom/page-entry.d.ts +95 -0
  108. package/dist/yom/generated/yomu/yom/page-entry.d.ts.map +1 -0
  109. package/dist/yom/generated/yomu/yom/page-entry.js +288 -0
  110. package/dist/yom/generated/yomu/yom/page-entry.js.map +1 -0
  111. package/dist/yom/generated/yomu/yom/pdfexport-metadata.d.ts +32 -0
  112. package/dist/yom/generated/yomu/yom/pdfexport-metadata.d.ts.map +1 -0
  113. package/dist/yom/generated/yomu/yom/pdfexport-metadata.js +96 -0
  114. package/dist/yom/generated/yomu/yom/pdfexport-metadata.js.map +1 -0
  115. package/dist/yom/generated/yomu/yom/reading-direction.d.ts +5 -0
  116. package/dist/yom/generated/yomu/yom/reading-direction.d.ts.map +1 -0
  117. package/dist/yom/generated/yomu/yom/reading-direction.js +8 -0
  118. package/dist/yom/generated/yomu/yom/reading-direction.js.map +1 -0
  119. package/dist/yom/generated/yomu/yom/search-term-ref.d.ts +34 -0
  120. package/dist/yom/generated/yomu/yom/search-term-ref.d.ts.map +1 -0
  121. package/dist/yom/generated/yomu/yom/search-term-ref.js +99 -0
  122. package/dist/yom/generated/yomu/yom/search-term-ref.js.map +1 -0
  123. package/dist/yom/generated/yomu/yom.d.ts +6 -0
  124. package/dist/yom/generated/yomu/yom.d.ts.map +1 -0
  125. package/dist/yom/generated/yomu/yom.js +8 -0
  126. package/dist/yom/generated/yomu/yom.js.map +1 -0
  127. package/dist/yom/hash.d.ts +4 -0
  128. package/dist/yom/hash.d.ts.map +1 -0
  129. package/dist/yom/hash.js +21 -0
  130. package/dist/yom/hash.js.map +1 -0
  131. package/dist/yom/header.d.ts +44 -0
  132. package/dist/yom/header.d.ts.map +1 -0
  133. package/dist/yom/header.js +115 -0
  134. package/dist/yom/header.js.map +1 -0
  135. package/dist/yom/reader.d.ts +57 -0
  136. package/dist/yom/reader.d.ts.map +1 -0
  137. package/dist/yom/reader.js +141 -0
  138. package/dist/yom/reader.js.map +1 -0
  139. package/dist/yom/searchIndex.d.ts +41 -0
  140. package/dist/yom/searchIndex.d.ts.map +1 -0
  141. package/dist/yom/searchIndex.js +133 -0
  142. package/dist/yom/searchIndex.js.map +1 -0
  143. package/dist/yom/textNormalizer.d.ts +19 -0
  144. package/dist/yom/textNormalizer.d.ts.map +1 -0
  145. package/dist/yom/textNormalizer.js +77 -0
  146. package/dist/yom/textNormalizer.js.map +1 -0
  147. package/dist/yom/validator.d.ts +14 -0
  148. package/dist/yom/validator.d.ts.map +1 -0
  149. package/dist/yom/validator.js +197 -0
  150. package/dist/yom/validator.js.map +1 -0
  151. package/dist/yom/writer.d.ts +76 -0
  152. package/dist/yom/writer.d.ts.map +1 -0
  153. package/dist/yom/writer.js +154 -0
  154. package/dist/yom/writer.js.map +1 -0
  155. package/dist/yom/zstd.d.ts +14 -0
  156. package/dist/yom/zstd.d.ts.map +1 -0
  157. package/dist/yom/zstd.js +43 -0
  158. package/dist/yom/zstd.js.map +1 -0
  159. package/package.json +65 -0
  160. package/src/cli.ts +372 -0
  161. package/src/index.ts +109 -0
  162. package/src/pipeline/avif.ts +33 -0
  163. package/src/pipeline/convert.ts +148 -0
  164. package/src/pipeline/index.ts +28 -0
  165. package/src/pipeline/ocrLayoutBuilder.ts +73 -0
  166. package/src/pipeline/pdfDocument.ts +86 -0
  167. package/src/pipeline/renderPage.ts +48 -0
  168. package/src/pipeline/textExtract.ts +64 -0
  169. package/src/worker/convert.worker.ts +54 -0
  170. package/src/yom/blobLimits.ts +30 -0
  171. package/src/yom/byteSource.ts +144 -0
  172. package/src/yom/bytes.ts +11 -0
  173. package/src/yom/constants.ts +89 -0
  174. package/src/yom/errors.ts +43 -0
  175. package/src/yom/flatbufferVerify.ts +298 -0
  176. package/src/yom/generated/yomu/yom/blob-kind.ts +12 -0
  177. package/src/yom/generated/yomu/yom/blob-ref.ts +184 -0
  178. package/src/yom/generated/yomu/yom/book-metadata.ts +121 -0
  179. package/src/yom/generated/yomu/yom/compression.ts +8 -0
  180. package/src/yom/generated/yomu/yom/main-index.ts +257 -0
  181. package/src/yom/generated/yomu/yom/ocrblock.ts +117 -0
  182. package/src/yom/generated/yomu/yom/ocrlayout.ts +102 -0
  183. package/src/yom/generated/yomu/yom/ocrline.ts +131 -0
  184. package/src/yom/generated/yomu/yom/ocrpage.ts +191 -0
  185. package/src/yom/generated/yomu/yom/ocrtoken.ts +173 -0
  186. package/src/yom/generated/yomu/yom/outline-entry.ts +124 -0
  187. package/src/yom/generated/yomu/yom/page-entry.ts +388 -0
  188. package/src/yom/generated/yomu/yom/pdfexport-metadata.ts +128 -0
  189. package/src/yom/generated/yomu/yom/reading-direction.ts +8 -0
  190. package/src/yom/generated/yomu/yom/search-term-ref.ts +134 -0
  191. package/src/yom/generated/yomu/yom.ts +9 -0
  192. package/src/yom/hash.ts +20 -0
  193. package/src/yom/header.ts +132 -0
  194. package/src/yom/reader.ts +163 -0
  195. package/src/yom/searchIndex.ts +178 -0
  196. package/src/yom/textNormalizer.ts +92 -0
  197. package/src/yom/validator.ts +245 -0
  198. package/src/yom/writer.ts +337 -0
  199. package/src/yom/zstd.ts +47 -0
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Mirrors the Swift implementation's `YOMConverter.Stage`
3
+ * (`swift/Sources/YOMConverter/YOMConverter.swift`) so Web and native
4
+ * progress reporting read the same way. `rendering`, `encoding`, and
5
+ * `extractingText` all advance together per-page here since this pipeline
6
+ * does all three in one pass per page (see `convertPdfToYom`).
7
+ */
8
+ export type ConversionStage = "rendering" | "encoding" | "extractingText" | "buildingSearchIndex" | "writingPackfile" | "validating";
9
+ export type ProgressCallback = (stage: ConversionStage, fraction: number) => void;
10
+ export declare class ConversionCancelledError extends Error {
11
+ constructor();
12
+ }
13
+ export interface ConvertOptions {
14
+ title: string;
15
+ onProgress?: ProgressCallback;
16
+ isCancelled?: () => boolean;
17
+ }
18
+ /**
19
+ * Converts a source PDF's bytes into a validated `.yom` package, entirely in
20
+ * the browser. Ports the shape of the Swift implementation's
21
+ * `YOMConverter.convert` + `YOMConversionPipeline.buildWriterInput`
22
+ * (`swift/Sources/YOMConverter/`), with two known scope differences:
23
+ * image-only pages get no OCR text yet (a vendored OCR engine for that is
24
+ * not yet implemented), and PDF export metadata is generated but not
25
+ * consumed by an export feature yet.
26
+ */
27
+ export declare function convertPdfToYom(pdfBytes: Uint8Array, options: ConvertOptions): Promise<Uint8Array>;
28
+ //# sourceMappingURL=convert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../src/pipeline/convert.ts"],"names":[],"mappings":"AAaA;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,UAAU,GACV,gBAAgB,GAChB,qBAAqB,GACrB,iBAAiB,GACjB,YAAY,CAAC;AAEjB,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;AAElF,qBAAa,wBAAyB,SAAQ,KAAK;;CAIlD;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAgGxG"}
@@ -0,0 +1,111 @@
1
+ import { BlobKind } from "../yom/generated/yomu/yom/blob-kind.js";
2
+ import { Compression } from "../yom/generated/yomu/yom/compression.js";
3
+ import { ReadingDirection } from "../yom/generated/yomu/yom/reading-direction.js";
4
+ import { writeYOM } from "../yom/writer.js";
5
+ import { validateYOM } from "../yom/validator.js";
6
+ import { buildNormalizedTextBlob } from "../yom/textNormalizer.js";
7
+ import { buildSearchIndex } from "../yom/searchIndex.js";
8
+ import { loadPdfDocument, extractOutline, extractPageLabels } from "./pdfDocument.js";
9
+ import { renderPage } from "./renderPage.js";
10
+ import { extractPageText } from "./textExtract.js";
11
+ import { encodePageAvif, encodeThumbnailAvif } from "./avif.js";
12
+ import { buildOcrLayoutBlob } from "./ocrLayoutBuilder.js";
13
+ export class ConversionCancelledError extends Error {
14
+ constructor() {
15
+ super("conversion cancelled");
16
+ }
17
+ }
18
+ /**
19
+ * Converts a source PDF's bytes into a validated `.yom` package, entirely in
20
+ * the browser. Ports the shape of the Swift implementation's
21
+ * `YOMConverter.convert` + `YOMConversionPipeline.buildWriterInput`
22
+ * (`swift/Sources/YOMConverter/`), with two known scope differences:
23
+ * image-only pages get no OCR text yet (a vendored OCR engine for that is
24
+ * not yet implemented), and PDF export metadata is generated but not
25
+ * consumed by an export feature yet.
26
+ */
27
+ export async function convertPdfToYom(pdfBytes, options) {
28
+ const { title, onProgress = () => { }, isCancelled = () => false } = options;
29
+ const doc = await loadPdfDocument(pdfBytes);
30
+ const pageCount = doc.numPages;
31
+ if (pageCount === 0)
32
+ throw new Error("PDF has no pages");
33
+ const [outline, pageLabels] = await Promise.all([extractOutline(doc), extractPageLabels(doc)]);
34
+ const pageTexts = [];
35
+ const pageInputs = [];
36
+ for (let i = 0; i < pageCount; i++) {
37
+ if (isCancelled())
38
+ throw new ConversionCancelledError();
39
+ const page = await doc.getPage(i + 1);
40
+ const rendered = await renderPage(page);
41
+ onProgress("rendering", (i + 1) / pageCount);
42
+ const [pageAvif, thumbAvif] = await Promise.all([
43
+ encodePageAvif(rendered.image),
44
+ encodeThumbnailAvif(rendered.thumbnail),
45
+ ]);
46
+ onProgress("encoding", (i + 1) / pageCount);
47
+ const pageText = await extractPageText(page, rendered.viewport);
48
+ pageTexts.push(pageText);
49
+ onProgress("extractingText", (i + 1) / pageCount);
50
+ // Geometry uses PDF-space `page.view` (pdf.js does not expose distinct
51
+ // mediaBox/cropBox), matching the native converter's own simplification
52
+ // of collapsing contentBox into cropBox (`YOMPDFExportMetadata.swift`).
53
+ const pdfBox = page.view.slice();
54
+ pageInputs.push({
55
+ pageLabel: pageLabels[i] ?? `${i + 1}`,
56
+ pixelWidth: rendered.image.width,
57
+ pixelHeight: rendered.image.height,
58
+ dpi: 150,
59
+ colorSpace: "sRGB",
60
+ colorProfileRef: "",
61
+ mediaBox: pdfBox,
62
+ cropBox: pdfBox,
63
+ contentBox: pdfBox,
64
+ rotation: page.rotate,
65
+ readingDirection: ReadingDirection.LeftToRight,
66
+ pageImage: { kind: BlobKind.PageImage, data: pageAvif, compression: Compression.None },
67
+ thumbnail: { kind: BlobKind.ThumbnailImage, data: thumbAvif, compression: Compression.None },
68
+ });
69
+ page.cleanup();
70
+ }
71
+ if (isCancelled())
72
+ throw new ConversionCancelledError();
73
+ onProgress("buildingSearchIndex", 0);
74
+ const ocrLayoutBytes = buildOcrLayoutBlob(pageTexts);
75
+ const normalized = buildNormalizedTextBlob(pageTexts.map((p) => p.text));
76
+ const searchIndex = buildSearchIndex(normalized.normalizedPageTexts);
77
+ const searchTerms = searchIndex.searchTerms.map((t) => ({
78
+ term: t.term,
79
+ dictionaryOffset: BigInt(t.dictionaryOffset),
80
+ dictionaryLength: BigInt(t.dictionaryLength),
81
+ postingsOffset: BigInt(t.postingsOffset),
82
+ postingsLength: BigInt(t.postingsLength),
83
+ }));
84
+ onProgress("buildingSearchIndex", 1);
85
+ const writerInput = {
86
+ book: {
87
+ title,
88
+ readingDirection: ReadingDirection.LeftToRight,
89
+ createdAtUnix: BigInt(Math.floor(Date.now() / 1000)),
90
+ },
91
+ pages: pageInputs,
92
+ ocrLayout: { kind: BlobKind.OCRLayout, data: ocrLayoutBytes, compression: Compression.Zstd },
93
+ normalizedText: { kind: BlobKind.NormalizedText, data: normalized.data, compression: Compression.Zstd },
94
+ searchDictionary: { kind: BlobKind.SearchDictionary, data: searchIndex.dictionaryBlob, compression: Compression.Zstd },
95
+ searchPostings: { kind: BlobKind.SearchPostings, data: searchIndex.postingsBlob, compression: Compression.None },
96
+ searchTerms,
97
+ pdfExport: { pageLabels, outline },
98
+ };
99
+ if (isCancelled())
100
+ throw new ConversionCancelledError();
101
+ onProgress("writingPackfile", 0);
102
+ const packfileBytes = await writeYOM(writerInput);
103
+ onProgress("writingPackfile", 1);
104
+ if (isCancelled())
105
+ throw new ConversionCancelledError();
106
+ onProgress("validating", 0);
107
+ await validateYOM(packfileBytes);
108
+ onProgress("validating", 1);
109
+ return packfileBytes;
110
+ }
111
+ //# sourceMappingURL=convert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert.js","sourceRoot":"","sources":["../../src/pipeline/convert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Browser-only PDF-to-YOM conversion pipeline: renders a PDF with pdf.js,
3
+ * encodes pages/thumbnails as AVIF, extracts embedded text and outline, and
4
+ * writes a validated `.yom` package. Requires a DOM (Canvas/OffscreenCanvas)
5
+ * environment; it will not run under plain Node.
6
+ *
7
+ * Kept as a separate subpath (`yom-format/pipeline`) so the core read/write
8
+ * API in `yom-format` stays free of the pdf.js and image-codec dependencies
9
+ * this pulls in.
10
+ */
11
+ export { convertPdfToYom, ConversionCancelledError, type ConversionStage, type ProgressCallback, type ConvertOptions, } from "./convert.js";
12
+ export { loadPdfDocument, extractOutline, extractPageLabels, type OutlineEntryData } from "./pdfDocument.js";
13
+ export { renderPage, THUMBNAIL_MAX_DIMENSION, type RenderedPage } from "./renderPage.js";
14
+ export { extractPageText, type PageText, type PageTextToken } from "./textExtract.js";
15
+ export { encodePageAvif, encodeThumbnailAvif } from "./avif.js";
16
+ export { buildOcrLayoutBlob } from "./ocrLayoutBuilder.js";
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pipeline/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAE7G,OAAO,EAAE,UAAU,EAAE,uBAAuB,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEzF,OAAO,EAAE,eAAe,EAAE,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtF,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Browser-only PDF-to-YOM conversion pipeline: renders a PDF with pdf.js,
3
+ * encodes pages/thumbnails as AVIF, extracts embedded text and outline, and
4
+ * writes a validated `.yom` package. Requires a DOM (Canvas/OffscreenCanvas)
5
+ * environment; it will not run under plain Node.
6
+ *
7
+ * Kept as a separate subpath (`yom-format/pipeline`) so the core read/write
8
+ * API in `yom-format` stays free of the pdf.js and image-codec dependencies
9
+ * this pulls in.
10
+ */
11
+ export { convertPdfToYom, ConversionCancelledError, } from "./convert.js";
12
+ export { loadPdfDocument, extractOutline, extractPageLabels } from "./pdfDocument.js";
13
+ export { renderPage, THUMBNAIL_MAX_DIMENSION } from "./renderPage.js";
14
+ export { extractPageText } from "./textExtract.js";
15
+ export { encodePageAvif, encodeThumbnailAvif } from "./avif.js";
16
+ export { buildOcrLayoutBlob } from "./ocrLayoutBuilder.js";
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pipeline/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,eAAe,EACf,wBAAwB,GAIzB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,iBAAiB,EAAyB,MAAM,kBAAkB,CAAC;AAE7G,OAAO,EAAE,UAAU,EAAE,uBAAuB,EAAqB,MAAM,iBAAiB,CAAC;AAEzF,OAAO,EAAE,eAAe,EAAqC,MAAM,kBAAkB,CAAC;AAEtF,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { PageText } from "./textExtract.js";
2
+ /**
3
+ * Builds the pre-compression OCR FlatBuffers blob (`writer.ts` zstd-
4
+ * compresses it per the fixed policy) from per-page token layout. Each
5
+ * page's `text` field is the concatenation of its own tokens' text, in
6
+ * order, with no separators -- `textStart`/`textLength` index directly into
7
+ * that buffer, not into the original PDF text run structure.
8
+ */
9
+ export declare function buildOcrLayoutBlob(pages: PageText[]): Uint8Array;
10
+ //# sourceMappingURL=ocrLayoutBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ocrLayoutBuilder.d.ts","sourceRoot":"","sources":["../../src/pipeline/ocrLayoutBuilder.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,kBAAkB,CAAC;AAIhE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,UAAU,CAsChE"}
@@ -0,0 +1,62 @@
1
+ import { Builder } from "flatbuffers";
2
+ import { OCRLayoutT } from "../yom/generated/yomu/yom/ocrlayout.js";
3
+ import { OCRPageT } from "../yom/generated/yomu/yom/ocrpage.js";
4
+ import { OCRBlockT } from "../yom/generated/yomu/yom/ocrblock.js";
5
+ import { OCRLineT } from "../yom/generated/yomu/yom/ocrline.js";
6
+ import { OCRTokenT } from "../yom/generated/yomu/yom/ocrtoken.js";
7
+ import { concatBytes } from "../yom/bytes.js";
8
+ /**
9
+ * Builds the pre-compression OCR FlatBuffers blob (`writer.ts` zstd-
10
+ * compresses it per the fixed policy) from per-page token layout. Each
11
+ * page's `text` field is the concatenation of its own tokens' text, in
12
+ * order, with no separators -- `textStart`/`textLength` index directly into
13
+ * that buffer, not into the original PDF text run structure.
14
+ */
15
+ export function buildOcrLayoutBlob(pages) {
16
+ const encoder = new TextEncoder();
17
+ const builder = new Builder(1024);
18
+ builder.forceDefaults(true);
19
+ const ocrPages = pages.map((page, pageIndex) => {
20
+ const tokenBytesList = page.tokens.map((t) => encoder.encode(t.text));
21
+ let cursor = 0;
22
+ const tokens = page.tokens.map((token, i) => {
23
+ const bytes = tokenBytesList[i];
24
+ const textStart = cursor;
25
+ cursor += bytes.length;
26
+ return new OCRTokenT(textStart, bytes.length, token.bbox, 1.0, token.lineId, token.blockId);
27
+ });
28
+ const pageText = new TextDecoder().decode(concatBytes(tokenBytesList));
29
+ const lineBboxes = new Map();
30
+ const blockBboxes = new Map();
31
+ for (const token of page.tokens) {
32
+ unionBbox(lineBboxes, token.lineId, token.bbox);
33
+ unionBbox(blockBboxes, token.blockId, token.bbox);
34
+ }
35
+ const lines = Array.from(lineBboxes.keys())
36
+ .sort((a, b) => a - b)
37
+ .map((id) => new OCRLineT(id, blockIdForLine(page.tokens, id), lineBboxes.get(id)));
38
+ const blocks = Array.from(blockBboxes.keys())
39
+ .sort((a, b) => a - b)
40
+ .map((id) => new OCRBlockT(id, blockBboxes.get(id)));
41
+ return new OCRPageT(pageIndex, pageText, blocks, lines, tokens);
42
+ });
43
+ const layout = new OCRLayoutT(ocrPages);
44
+ const offset = layout.pack(builder);
45
+ builder.finish(offset);
46
+ return builder.asUint8Array();
47
+ }
48
+ function blockIdForLine(tokens, lineId) {
49
+ return tokens.find((t) => t.lineId === lineId)?.blockId ?? 0;
50
+ }
51
+ function unionBbox(map, id, bbox) {
52
+ const existing = map.get(id);
53
+ if (!existing) {
54
+ map.set(id, [...bbox]);
55
+ return;
56
+ }
57
+ existing[0] = Math.min(existing[0], bbox[0]);
58
+ existing[1] = Math.min(existing[1], bbox[1]);
59
+ existing[2] = Math.max(existing[2], bbox[2]);
60
+ existing[3] = Math.max(existing[3], bbox[3]);
61
+ }
62
+ //# sourceMappingURL=ocrLayoutBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ocrLayoutBuilder.js","sourceRoot":"","sources":["../../src/pipeline/ocrLayoutBuilder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { PDFDocumentProxy } from "pdfjs-dist";
2
+ export declare function loadPdfDocument(data: Uint8Array): Promise<PDFDocumentProxy>;
3
+ export interface OutlineEntryData {
4
+ title: string;
5
+ pageId: number;
6
+ children: OutlineEntryData[];
7
+ }
8
+ /** Extracts the PDF outline/TOC, resolving each destination to a page index. */
9
+ export declare function extractOutline(doc: PDFDocumentProxy): Promise<OutlineEntryData[]>;
10
+ /** Page labels, falling back to 1-based numbering when the PDF has none. */
11
+ export declare function extractPageLabels(doc: PDFDocumentProxy): Promise<string[]>;
12
+ //# sourceMappingURL=pdfDocument.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdfDocument.d.ts","sourceRoot":"","sources":["../../src/pipeline/pdfDocument.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA4BnD,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAKjF;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAED,gFAAgF;AAChF,wBAAsB,cAAc,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAIvF;AAiCD,4EAA4E;AAC5E,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAIhF"}
@@ -0,0 +1,76 @@
1
+ import { GlobalWorkerOptions, getDocument } from "pdfjs-dist";
2
+ // Runs inside `convert.worker.ts`; pdf.js spawns (or fakes, if the browser
3
+ // disallows a nested worker) its own core worker from this URL.
4
+ GlobalWorkerOptions.workerSrc = new URL("pdfjs-dist/build/pdf.worker.mjs", import.meta.url).href;
5
+ /**
6
+ * Minimal `CanvasFactory` so pdf.js's *internal* auxiliary canvases (soft
7
+ * masks, tiling patterns) work in a Worker, where `document` does not exist.
8
+ * Our own top-level per-page render target is a separate `OffscreenCanvas`
9
+ * created directly in `renderPage.ts`.
10
+ */
11
+ class OffscreenCanvasFactory {
12
+ create(width, height) {
13
+ const canvas = new OffscreenCanvas(width, height);
14
+ const context = canvas.getContext("2d");
15
+ return { canvas, context };
16
+ }
17
+ reset(canvasAndContext, width, height) {
18
+ canvasAndContext.canvas.width = width;
19
+ canvasAndContext.canvas.height = height;
20
+ }
21
+ destroy(canvasAndContext) {
22
+ canvasAndContext.canvas = null;
23
+ canvasAndContext.context = null;
24
+ }
25
+ }
26
+ export async function loadPdfDocument(data) {
27
+ // pdf.js instantiates this itself (`new CanvasFactory(...)`), so the
28
+ // option must be the class, not an instance of it.
29
+ const task = getDocument({ data, CanvasFactory: OffscreenCanvasFactory });
30
+ return task.promise;
31
+ }
32
+ /** Extracts the PDF outline/TOC, resolving each destination to a page index. */
33
+ export async function extractOutline(doc) {
34
+ const raw = await doc.getOutline();
35
+ if (!raw)
36
+ return [];
37
+ return resolveOutlineNodes(doc, raw);
38
+ }
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ async function resolveOutlineNodes(doc, nodes) {
41
+ const result = [];
42
+ for (const node of nodes) {
43
+ const pageId = await resolvePageId(doc, node.dest);
44
+ const children = node.items?.length ? await resolveOutlineNodes(doc, node.items) : [];
45
+ result.push({ title: typeof node.title === "string" ? node.title : "", pageId, children });
46
+ }
47
+ return result;
48
+ }
49
+ async function resolvePageId(doc,
50
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
51
+ dest) {
52
+ try {
53
+ let resolved = dest;
54
+ if (typeof resolved === "string") {
55
+ resolved = await doc.getDestination(resolved);
56
+ }
57
+ if (!Array.isArray(resolved) || resolved.length === 0)
58
+ return 0;
59
+ const ref = resolved[0];
60
+ if (typeof ref === "number")
61
+ return ref;
62
+ const index = await doc.getPageIndex(ref);
63
+ return index >= 0 ? index : 0;
64
+ }
65
+ catch {
66
+ return 0;
67
+ }
68
+ }
69
+ /** Page labels, falling back to 1-based numbering when the PDF has none. */
70
+ export async function extractPageLabels(doc) {
71
+ const labels = await doc.getPageLabels();
72
+ if (labels)
73
+ return labels;
74
+ return Array.from({ length: doc.numPages }, (_, i) => `${i + 1}`);
75
+ }
76
+ //# sourceMappingURL=pdfDocument.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdfDocument.js","sourceRoot":"","sources":["../../src/pipeline/pdfDocument.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { PDFPageProxy } from "pdfjs-dist";
2
+ import type { PageViewport } from "pdfjs-dist";
3
+ export declare const THUMBNAIL_MAX_DIMENSION = 320;
4
+ export interface RenderedPage {
5
+ image: ImageData;
6
+ thumbnail: ImageData;
7
+ viewport: PageViewport;
8
+ }
9
+ export declare function renderPage(page: PDFPageProxy): Promise<RenderedPage>;
10
+ //# sourceMappingURL=renderPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderPage.d.ts","sourceRoot":"","sources":["../../src/pipeline/renderPage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAS/C,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,SAAS,CAAC;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CA6B1E"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Render resolution and thumbnail sizing. `RENDER_DPI` favors legibility for
3
+ * the primary reading surface (mirrors the intent behind
4
+ * `AVIFCodec.pageQuality` on the native side, expressed here as resolution
5
+ * rather than a platform-specific encoder quality knob).
6
+ */
7
+ const RENDER_DPI = 150;
8
+ export const THUMBNAIL_MAX_DIMENSION = 320;
9
+ export async function renderPage(page) {
10
+ const scale = RENDER_DPI / 72;
11
+ const viewport = page.getViewport({ scale });
12
+ const width = Math.max(1, Math.round(viewport.width));
13
+ const height = Math.max(1, Math.round(viewport.height));
14
+ const canvas = new OffscreenCanvas(width, height);
15
+ const ctx = canvas.getContext("2d");
16
+ if (!ctx)
17
+ throw new Error("failed to acquire 2D rendering context");
18
+ await page.render({
19
+ canvas: null,
20
+ canvasContext: ctx,
21
+ viewport,
22
+ }).promise;
23
+ const image = ctx.getImageData(0, 0, width, height);
24
+ const longestSide = Math.max(width, height);
25
+ const thumbScale = longestSide > THUMBNAIL_MAX_DIMENSION ? THUMBNAIL_MAX_DIMENSION / longestSide : 1;
26
+ const thumbWidth = Math.max(1, Math.round(width * thumbScale));
27
+ const thumbHeight = Math.max(1, Math.round(height * thumbScale));
28
+ const thumbCanvas = new OffscreenCanvas(thumbWidth, thumbHeight);
29
+ const thumbCtx = thumbCanvas.getContext("2d");
30
+ if (!thumbCtx)
31
+ throw new Error("failed to acquire 2D rendering context");
32
+ thumbCtx.drawImage(canvas, 0, 0, thumbWidth, thumbHeight);
33
+ const thumbnail = thumbCtx.getImageData(0, 0, thumbWidth, thumbHeight);
34
+ return { image, thumbnail, viewport };
35
+ }
36
+ //# sourceMappingURL=renderPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderPage.js","sourceRoot":"","sources":["../../src/pipeline/renderPage.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,UAAU,GAAG,GAAG,CAAC;AACvB,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAQ3C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAkB;IACjD,MAAM,KAAK,GAAG,UAAU,GAAG,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAExD,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAEpE,MAAM,IAAI,CAAC,MAAM,CAAC;QAChB,MAAM,EAAE,IAAI;QACZ,aAAa,EAAE,GAA0C;QACzD,QAAQ;KACT,CAAC,CAAC,OAAO,CAAC;IACX,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAEpD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,WAAW,GAAG,uBAAuB,CAAC,CAAC,CAAC,uBAAuB,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IACrG,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC;IAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC;IAEjE,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACzE,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAEvE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;AACxC,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { PDFPageProxy, PageViewport } from "pdfjs-dist";
2
+ export interface PageTextToken {
3
+ text: string;
4
+ /** Normalized `[x0, y0, x1, y1]`, 0..1 relative to the page. */
5
+ bbox: [number, number, number, number];
6
+ lineId: number;
7
+ blockId: number;
8
+ }
9
+ export interface PageText {
10
+ text: string;
11
+ tokens: PageTextToken[];
12
+ }
13
+ /**
14
+ * Extracts the PDF's embedded text layer as page text plus a token layout
15
+ * suitable for the OCR FlatBuffers schema. This is not OCR -- it reuses the
16
+ * PDF's own text layer positions, which is exactly the "prefer existing text
17
+ * layer" half of the format's OCR/text rule (see docs/format-spec.md §6,
18
+ * "Search/OCR quality variance"). Image-only pages (no embedded text) get an
19
+ * empty token list here; filling that gap with a vendored OCR engine is not
20
+ * yet implemented.
21
+ *
22
+ * Block/line/bbox derivation is intentionally simple (one block per page,
23
+ * lines split on pdf.js's `hasEOL`, an axis-aligned box approximated from
24
+ * each item's transform and width) since the schema only requires a valid
25
+ * byte range, not layout-analysis-grade precision -- true OCR is
26
+ * responsible for real layout quality.
27
+ */
28
+ export declare function extractPageText(page: PDFPageProxy, viewport: PageViewport): Promise<PageText>;
29
+ //# sourceMappingURL=textExtract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textExtract.d.ts","sourceRoot":"","sources":["../../src/pipeline/textExtract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiCnG"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Extracts the PDF's embedded text layer as page text plus a token layout
3
+ * suitable for the OCR FlatBuffers schema. This is not OCR -- it reuses the
4
+ * PDF's own text layer positions, which is exactly the "prefer existing text
5
+ * layer" half of the format's OCR/text rule (see docs/format-spec.md §6,
6
+ * "Search/OCR quality variance"). Image-only pages (no embedded text) get an
7
+ * empty token list here; filling that gap with a vendored OCR engine is not
8
+ * yet implemented.
9
+ *
10
+ * Block/line/bbox derivation is intentionally simple (one block per page,
11
+ * lines split on pdf.js's `hasEOL`, an axis-aligned box approximated from
12
+ * each item's transform and width) since the schema only requires a valid
13
+ * byte range, not layout-analysis-grade precision -- true OCR is
14
+ * responsible for real layout quality.
15
+ */
16
+ export async function extractPageText(page, viewport) {
17
+ const content = await page.getTextContent();
18
+ const tokens = [];
19
+ const textParts = [];
20
+ let lineId = 0;
21
+ const blockId = 0;
22
+ for (const item of content.items) {
23
+ if (!("str" in item))
24
+ continue; // skip TextMarkedContent entries
25
+ textParts.push(item.str);
26
+ if (item.str.length > 0) {
27
+ const [a, b, c, d, e, f] = item.transform;
28
+ const fontHeight = Math.hypot(c, d) || Math.hypot(a, b) || 1;
29
+ const x0 = e;
30
+ const y0 = f;
31
+ const x1 = e + a * item.width;
32
+ const y1 = f + fontHeight;
33
+ const [vx0, vy0] = viewport.convertToViewportPoint(x0, y0);
34
+ const [vx1, vy1] = viewport.convertToViewportPoint(x1, y1);
35
+ const bbox = [
36
+ Math.min(vx0, vx1) / viewport.width,
37
+ Math.min(vy0, vy1) / viewport.height,
38
+ Math.max(vx0, vx1) / viewport.width,
39
+ Math.max(vy0, vy1) / viewport.height,
40
+ ];
41
+ tokens.push({ text: item.str, bbox, lineId, blockId });
42
+ }
43
+ if (item.hasEOL)
44
+ lineId += 1;
45
+ }
46
+ return { text: textParts.join(""), tokens };
47
+ }
48
+ //# sourceMappingURL=textExtract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textExtract.js","sourceRoot":"","sources":["../../src/pipeline/textExtract.ts"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAkB,EAAE,QAAsB;IAC9E,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,OAAO,GAAG,CAAC,CAAC;IAElB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC;YAAE,SAAS,CAAC,iCAAiC;QACjE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEzB,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YAC7D,MAAM,EAAE,GAAG,CAAC,CAAC;YACb,MAAM,EAAE,GAAG,CAAC,CAAC;YACb,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;YAC9B,MAAM,EAAE,GAAG,CAAC,GAAG,UAAU,CAAC;YAC1B,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,sBAAsB,CAAC,EAAE,EAAE,EAAE,CAAqB,CAAC;YAC/E,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,sBAAsB,CAAC,EAAE,EAAE,EAAE,CAAqB,CAAC;YAC/E,MAAM,IAAI,GAAqC;gBAC7C,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,KAAK;gBACnC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM;gBACpC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,KAAK;gBACnC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM;aACrC,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACzD,CAAC;QAED,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { BlobKind } from "./generated/yomu/yom/blob-kind.js";
2
+ /**
3
+ * Gap 2 reader-side size caps. Enforces, from a blob's *declared* sizes
4
+ * (before any bytes are read or decompressed):
5
+ *
6
+ * - `uncompressed_length <= MAX_BLOB_UNCOMPRESSED[kind]`
7
+ * - inflation ratio `uncompressed / max(compressed, 1) <= MAX_INFLATION_RATIO`
8
+ *
9
+ * so a hostile file can't drive an unbounded allocation. Offset/length
10
+ * against-the-source bounds are checked by the caller (reader/validator),
11
+ * which know the exact source extent. These are reader limits, not format
12
+ * requirements -- see `constants.ts`.
13
+ */
14
+ export declare function enforceBlobSizePolicy(kind: BlobKind, compressedLength: number, uncompressedLength: number): void;
15
+ //# sourceMappingURL=blobLimits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blobLimits.d.ts","sourceRoot":"","sources":["../../src/yom/blobLimits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAIlE;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAahH"}
@@ -0,0 +1,25 @@
1
+ import { MAX_INFLATION_RATIO, maxBlobUncompressed } from "./constants.js";
2
+ import { BlobTooLargeError } from "./errors.js";
3
+ /**
4
+ * Gap 2 reader-side size caps. Enforces, from a blob's *declared* sizes
5
+ * (before any bytes are read or decompressed):
6
+ *
7
+ * - `uncompressed_length <= MAX_BLOB_UNCOMPRESSED[kind]`
8
+ * - inflation ratio `uncompressed / max(compressed, 1) <= MAX_INFLATION_RATIO`
9
+ *
10
+ * so a hostile file can't drive an unbounded allocation. Offset/length
11
+ * against-the-source bounds are checked by the caller (reader/validator),
12
+ * which know the exact source extent. These are reader limits, not format
13
+ * requirements -- see `constants.ts`.
14
+ */
15
+ export function enforceBlobSizePolicy(kind, compressedLength, uncompressedLength) {
16
+ const cap = maxBlobUncompressed(kind);
17
+ if (uncompressedLength > cap) {
18
+ throw new BlobTooLargeError(`blob kind ${kind} declares uncompressed length ${uncompressedLength} > cap ${cap}`);
19
+ }
20
+ const ratio = uncompressedLength / Math.max(compressedLength, 1);
21
+ if (ratio > MAX_INFLATION_RATIO) {
22
+ throw new BlobTooLargeError(`blob kind ${kind} inflation ratio ${ratio.toFixed(1)} > cap ${MAX_INFLATION_RATIO}`);
23
+ }
24
+ }
25
+ //# sourceMappingURL=blobLimits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blobLimits.js","sourceRoot":"","sources":["../../src/yom/blobLimits.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAc,EAAE,gBAAwB,EAAE,kBAA0B;IACxG,MAAM,GAAG,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,kBAAkB,GAAG,GAAG,EAAE,CAAC;QAC7B,MAAM,IAAI,iBAAiB,CACzB,aAAa,IAAI,iCAAiC,kBAAkB,UAAU,GAAG,EAAE,CACpF,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC;IACjE,IAAI,KAAK,GAAG,mBAAmB,EAAE,CAAC;QAChC,MAAM,IAAI,iBAAiB,CACzB,aAAa,IAAI,oBAAoB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,mBAAmB,EAAE,CACrF,CAAC;IACJ,CAAC;AACH,CAAC"}