@build-qube/papyra 0.0.4 → 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.
- package/README.md +102 -0
- package/dist/cache.d.ts +3 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js.map +1 -1
- package/dist/document.d.ts +135 -1
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +237 -10
- package/dist/document.js.map +1 -1
- package/dist/encode.d.ts +49 -0
- package/dist/encode.d.ts.map +1 -0
- package/dist/encode.js +71 -0
- package/dist/encode.js.map +1 -0
- package/dist/encoded.d.ts +62 -0
- package/dist/encoded.d.ts.map +1 -0
- package/dist/encoded.js +56 -0
- package/dist/encoded.js.map +1 -0
- package/dist/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/outline.d.ts +64 -0
- package/dist/outline.d.ts.map +1 -0
- package/dist/outline.js +67 -0
- package/dist/outline.js.map +1 -0
- package/dist/runtime.d.ts +8 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +2 -0
- package/dist/runtime.js.map +1 -1
- package/dist/scheduler.d.ts +20 -2
- package/dist/scheduler.d.ts.map +1 -1
- package/dist/scheduler.js +15 -0
- package/dist/scheduler.js.map +1 -1
- package/dist/search.d.ts +50 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +151 -0
- package/dist/search.js.map +1 -0
- package/dist/text.d.ts +111 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +75 -0
- package/dist/text.js.map +1 -0
- package/dist/types.d.ts +46 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -3
package/dist/search.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type PageText, type Quad, type Rect } from './text.js';
|
|
2
|
+
/** How loosely a query is allowed to match. Shared by {@link findRanges} and search. */
|
|
3
|
+
export interface MatchOptions {
|
|
4
|
+
/** Default `false`. */
|
|
5
|
+
caseSensitive?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Treat `e` and `é` as the same letter. Default `true`.
|
|
8
|
+
*
|
|
9
|
+
* Users type what is on their keyboard, and a document written in French or German
|
|
10
|
+
* is otherwise unsearchable to most of them.
|
|
11
|
+
*/
|
|
12
|
+
ignoreDiacritics?: boolean;
|
|
13
|
+
/** Require the match to start and end at a word boundary. Default `false`. */
|
|
14
|
+
wholeWords?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** One occurrence of the query on a page. */
|
|
17
|
+
export interface SearchMatch {
|
|
18
|
+
/** 0-based index of the page the hit is on. */
|
|
19
|
+
readonly page: number;
|
|
20
|
+
/** The matched text exactly as the document writes it. */
|
|
21
|
+
readonly text: string;
|
|
22
|
+
/** Surrounding text, for showing the hit in a results list. */
|
|
23
|
+
readonly context: string;
|
|
24
|
+
/** Where the match sits inside {@link context}. */
|
|
25
|
+
readonly contextStart: number;
|
|
26
|
+
/** End of the match inside {@link context}, exclusive. */
|
|
27
|
+
readonly contextEnd: number;
|
|
28
|
+
/**
|
|
29
|
+
* One quadrilateral per line the match covers — more than one when a phrase runs
|
|
30
|
+
* over a line break. Coordinates are 72-DPI page space; see {@link PageText}.
|
|
31
|
+
*/
|
|
32
|
+
readonly quads: readonly Quad[];
|
|
33
|
+
/** {@link quads}, as upright bounding boxes. */
|
|
34
|
+
readonly rects: readonly Rect[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Where the query occurs in a page's text, as `[start, end)` in the *source* string.
|
|
38
|
+
*
|
|
39
|
+
* Exported for testing and for callers that hold their own page text.
|
|
40
|
+
*/
|
|
41
|
+
export declare function findRanges(source: string, query: string, options?: MatchOptions): Array<[number, number]>;
|
|
42
|
+
/**
|
|
43
|
+
* Find `query` in one page's already-extracted text.
|
|
44
|
+
*
|
|
45
|
+
* Matching runs over the whole page rather than line by line, so a phrase broken
|
|
46
|
+
* across a line break still matches — and comes back with one quadrilateral per line
|
|
47
|
+
* it covers, which is what a highlight needs.
|
|
48
|
+
*/
|
|
49
|
+
export declare function searchPageText(text: PageText, query: string, options?: MatchOptions): SearchMatch[];
|
|
50
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,IAAI,EAET,KAAK,IAAI,EAEV,MAAM,WAAW,CAAC;AAEnB,wFAAwF;AACxF,MAAM,WAAW,YAAY;IAC3B,uBAAuB;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,6CAA6C;AAC7C,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mDAAmD;IACnD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;CACjC;AAyFD;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,YAAiB,GACzB,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CA6BzB;AAoBD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,YAAiB,GACzB,WAAW,EAAE,CAkCf"}
|
package/dist/search.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { lineQuad, quadBounds, } from './text.js';
|
|
2
|
+
/** How much of the surrounding line to keep either side of a hit. */
|
|
3
|
+
const CONTEXT_PADDING = 40;
|
|
4
|
+
/** Ligatures that carry no `ToUnicode` mapping arrive as a single character. */
|
|
5
|
+
const LIGATURES = {
|
|
6
|
+
ff: 'ff',
|
|
7
|
+
fi: 'fi',
|
|
8
|
+
fl: 'fl',
|
|
9
|
+
ffi: 'ffi',
|
|
10
|
+
ffl: 'ffl',
|
|
11
|
+
ſt: 'st',
|
|
12
|
+
st: 'st',
|
|
13
|
+
Æ: 'AE',
|
|
14
|
+
æ: 'ae',
|
|
15
|
+
Œ: 'OE',
|
|
16
|
+
œ: 'oe',
|
|
17
|
+
};
|
|
18
|
+
const COMBINING = /\p{M}/gu;
|
|
19
|
+
function fold(source, options) {
|
|
20
|
+
const { caseSensitive = false, ignoreDiacritics = true } = options;
|
|
21
|
+
let text = '';
|
|
22
|
+
const origin = [];
|
|
23
|
+
for (let i = 0; i < source.length; i++) {
|
|
24
|
+
let piece = source[i];
|
|
25
|
+
// A line break is a place where a phrase may continue, not a barrier. Searching
|
|
26
|
+
// for "dynamic languages" should find a title broken across two lines.
|
|
27
|
+
if (piece === '\n' || piece === '\t')
|
|
28
|
+
piece = ' ';
|
|
29
|
+
piece = LIGATURES[piece] ?? piece;
|
|
30
|
+
if (ignoreDiacritics) {
|
|
31
|
+
piece = piece.normalize('NFD').replace(COMBINING, '');
|
|
32
|
+
// A character that is *only* a combining mark folds away entirely.
|
|
33
|
+
if (piece === '')
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (!caseSensitive)
|
|
37
|
+
piece = piece.toLowerCase();
|
|
38
|
+
for (const c of piece) {
|
|
39
|
+
text += c;
|
|
40
|
+
origin.push(i);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return { text, origin };
|
|
44
|
+
}
|
|
45
|
+
/** Collapse runs of whitespace so "Hello World" matches "Hello World". */
|
|
46
|
+
function squash(folded) {
|
|
47
|
+
let text = '';
|
|
48
|
+
const origin = [];
|
|
49
|
+
let previousWasSpace = false;
|
|
50
|
+
for (let i = 0; i < folded.text.length; i++) {
|
|
51
|
+
const c = folded.text[i];
|
|
52
|
+
const isSpace = c === ' ';
|
|
53
|
+
if (isSpace && previousWasSpace)
|
|
54
|
+
continue;
|
|
55
|
+
text += isSpace ? ' ' : c;
|
|
56
|
+
origin.push(folded.origin[i]);
|
|
57
|
+
previousWasSpace = isSpace;
|
|
58
|
+
}
|
|
59
|
+
return { text, origin };
|
|
60
|
+
}
|
|
61
|
+
const WORD = /[\p{L}\p{N}_]/u;
|
|
62
|
+
function isBoundary(text, index) {
|
|
63
|
+
if (index < 0 || index >= text.length)
|
|
64
|
+
return true;
|
|
65
|
+
return !WORD.test(text[index]);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Where the query occurs in a page's text, as `[start, end)` in the *source* string.
|
|
69
|
+
*
|
|
70
|
+
* Exported for testing and for callers that hold their own page text.
|
|
71
|
+
*/
|
|
72
|
+
export function findRanges(source, query, options = {}) {
|
|
73
|
+
const needle = squash(fold(query, options)).text.trim();
|
|
74
|
+
if (needle === '')
|
|
75
|
+
return [];
|
|
76
|
+
const haystack = squash(fold(source, options));
|
|
77
|
+
const ranges = [];
|
|
78
|
+
let at = 0;
|
|
79
|
+
for (;;) {
|
|
80
|
+
const found = haystack.text.indexOf(needle, at);
|
|
81
|
+
if (found === -1)
|
|
82
|
+
break;
|
|
83
|
+
const end = found + needle.length;
|
|
84
|
+
if (!options.wholeWords ||
|
|
85
|
+
(isBoundary(haystack.text, found - 1) && isBoundary(haystack.text, end))) {
|
|
86
|
+
const start = haystack.origin[found];
|
|
87
|
+
// `end` is exclusive, so the last folded character's origin is the last source
|
|
88
|
+
// character the match covers — and a source character may fold to several.
|
|
89
|
+
const lastSource = haystack.origin[end - 1];
|
|
90
|
+
ranges.push([start, lastSource + 1]);
|
|
91
|
+
}
|
|
92
|
+
// Advance past the start, not past the end: overlapping occurrences of a
|
|
93
|
+
// repetitive query ("aa" in "aaa") are still two hits.
|
|
94
|
+
at = found + 1;
|
|
95
|
+
}
|
|
96
|
+
return ranges;
|
|
97
|
+
}
|
|
98
|
+
function locate(lines, index) {
|
|
99
|
+
let start = 0;
|
|
100
|
+
for (let i = 0; i < lines.length; i++) {
|
|
101
|
+
const line = lines[i];
|
|
102
|
+
const end = start + line.text.length;
|
|
103
|
+
if (index < end)
|
|
104
|
+
return { line: i, offset: index - start };
|
|
105
|
+
// +1 for the '\n' the page string joins lines with.
|
|
106
|
+
start = end + 1;
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Find `query` in one page's already-extracted text.
|
|
112
|
+
*
|
|
113
|
+
* Matching runs over the whole page rather than line by line, so a phrase broken
|
|
114
|
+
* across a line break still matches — and comes back with one quadrilateral per line
|
|
115
|
+
* it covers, which is what a highlight needs.
|
|
116
|
+
*/
|
|
117
|
+
export function searchPageText(text, query, options = {}) {
|
|
118
|
+
const source = text.lines.map((line) => line.text).join('\n');
|
|
119
|
+
const matches = [];
|
|
120
|
+
for (const [start, end] of findRanges(source, query, options)) {
|
|
121
|
+
const from = locate(text.lines, start);
|
|
122
|
+
// `end` is exclusive; step back to a character that is really inside the match.
|
|
123
|
+
const to = locate(text.lines, end - 1);
|
|
124
|
+
if (!from || !to)
|
|
125
|
+
continue;
|
|
126
|
+
const quads = [];
|
|
127
|
+
for (let i = from.line; i <= to.line; i++) {
|
|
128
|
+
const line = text.lines[i];
|
|
129
|
+
const first = i === from.line ? from.offset : 0;
|
|
130
|
+
const last = i === to.line ? to.offset + 1 : line.text.length;
|
|
131
|
+
if (last > first)
|
|
132
|
+
quads.push(lineQuad(line, first, last));
|
|
133
|
+
}
|
|
134
|
+
if (quads.length === 0)
|
|
135
|
+
continue;
|
|
136
|
+
const contextStart = Math.max(0, start - CONTEXT_PADDING);
|
|
137
|
+
matches.push({
|
|
138
|
+
page: text.page,
|
|
139
|
+
text: source.slice(start, end),
|
|
140
|
+
context: source
|
|
141
|
+
.slice(contextStart, end + CONTEXT_PADDING)
|
|
142
|
+
.replace(/\n/g, ' '),
|
|
143
|
+
contextStart: start - contextStart,
|
|
144
|
+
contextEnd: end - contextStart,
|
|
145
|
+
quads,
|
|
146
|
+
rects: quads.map(quadBounds),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return matches;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
|
package/dist/text.d.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { PageText as NativePageText } from '@build-qube/papyra-native';
|
|
2
|
+
/**
|
|
3
|
+
* A run of glyphs sharing one baseline.
|
|
4
|
+
*
|
|
5
|
+
* Geometry runs *along the baseline* rather than being a rectangle per character. A
|
|
6
|
+
* page is thousands of glyphs and four numbers each is far more than a search needs;
|
|
7
|
+
* an origin, a direction and a list of distances reconstruct any substring's
|
|
8
|
+
* quadrilateral exactly, and keep working when the text is rotated.
|
|
9
|
+
*/
|
|
10
|
+
export interface TextLine {
|
|
11
|
+
/** The line's characters, with spaces reinserted between glyph runs. */
|
|
12
|
+
readonly text: string;
|
|
13
|
+
/**
|
|
14
|
+
* Distance along the baseline to the start of each character, plus the end of the
|
|
15
|
+
* last — one entry more than `text.length`.
|
|
16
|
+
*/
|
|
17
|
+
readonly offsets: Float32Array;
|
|
18
|
+
/** Start of the baseline, x. */
|
|
19
|
+
readonly x: number;
|
|
20
|
+
/** Start of the baseline, y. */
|
|
21
|
+
readonly y: number;
|
|
22
|
+
/** Unit vector along the baseline, x. `(1, 0)` for ordinary horizontal text. */
|
|
23
|
+
readonly dx: number;
|
|
24
|
+
/** Unit vector along the baseline, y. */
|
|
25
|
+
readonly dy: number;
|
|
26
|
+
/** Extent above the baseline, perpendicular to it. */
|
|
27
|
+
readonly ascent: number;
|
|
28
|
+
/** Extent below the baseline. */
|
|
29
|
+
readonly descent: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The text of one page.
|
|
33
|
+
*
|
|
34
|
+
* Coordinates are **the page as rendered at 72 DPI**: pixels from the top-left corner
|
|
35
|
+
* with y increasing downwards, page rotation and crop box already applied. That makes
|
|
36
|
+
* them the same space as {@link PageSize}, so lining text up with a rendered bitmap is
|
|
37
|
+
* one multiply — `rendered.width / pageSize.width`, or equivalently `dpi / 72`.
|
|
38
|
+
*/
|
|
39
|
+
export interface PageText {
|
|
40
|
+
/** 0-based index of the page this text came from. */
|
|
41
|
+
readonly page: number;
|
|
42
|
+
/**
|
|
43
|
+
* The page's lines, in the order the content stream drew them — which is not
|
|
44
|
+
* necessarily reading order, because a PDF is under no obligation to draw text in
|
|
45
|
+
* the order a human reads it.
|
|
46
|
+
*/
|
|
47
|
+
readonly lines: readonly TextLine[];
|
|
48
|
+
/**
|
|
49
|
+
* Glyphs the page drew that no encoding could map back to Unicode.
|
|
50
|
+
*
|
|
51
|
+
* Non-zero **alongside lines** is the case worth warning about: a paper whose
|
|
52
|
+
* headings use a standard font and whose body uses an embedded subset with no
|
|
53
|
+
* `ToUnicode` cmap looks searchable and mostly is not. Non-zero with no lines is a
|
|
54
|
+
* page of text nothing can read; zero with no lines is a page with no text, which
|
|
55
|
+
* may be a scan. Telling a user which they are looking at is the difference between
|
|
56
|
+
* "no results" and "this cannot be searched".
|
|
57
|
+
*
|
|
58
|
+
* Weigh it against the characters actually extracted — a few undecodable ornaments
|
|
59
|
+
* are not a lost paragraph.
|
|
60
|
+
*/
|
|
61
|
+
readonly undecodedGlyphs: number;
|
|
62
|
+
}
|
|
63
|
+
/** Four corners, clockwise from the top-left of the text's own orientation. */
|
|
64
|
+
export interface Quad {
|
|
65
|
+
/** Top-left, x. */
|
|
66
|
+
readonly x0: number;
|
|
67
|
+
/** Top-left, y. */
|
|
68
|
+
readonly y0: number;
|
|
69
|
+
/** Top-right, x. */
|
|
70
|
+
readonly x1: number;
|
|
71
|
+
/** Top-right, y. */
|
|
72
|
+
readonly y1: number;
|
|
73
|
+
/** Bottom-right, x. */
|
|
74
|
+
readonly x2: number;
|
|
75
|
+
/** Bottom-right, y. */
|
|
76
|
+
readonly y2: number;
|
|
77
|
+
/** Bottom-left, x. */
|
|
78
|
+
readonly x3: number;
|
|
79
|
+
/** Bottom-left, y. */
|
|
80
|
+
readonly y3: number;
|
|
81
|
+
}
|
|
82
|
+
/** An axis-aligned rectangle. */
|
|
83
|
+
export interface Rect {
|
|
84
|
+
/** Left edge. */
|
|
85
|
+
readonly x: number;
|
|
86
|
+
/** Top edge — y increases downwards, so this is the smaller of the two. */
|
|
87
|
+
readonly y: number;
|
|
88
|
+
/** Width. */
|
|
89
|
+
readonly width: number;
|
|
90
|
+
/** Height. */
|
|
91
|
+
readonly height: number;
|
|
92
|
+
}
|
|
93
|
+
/** @internal */
|
|
94
|
+
export declare function toPageText(page: number, native: NativePageText): PageText;
|
|
95
|
+
/** Every character on the page a search can see. */
|
|
96
|
+
export declare function pageString(text: PageText): string;
|
|
97
|
+
/** Roughly how much memory a page's text holds, for cache accounting. */
|
|
98
|
+
export declare function pageTextBytes(text: PageText): number;
|
|
99
|
+
/**
|
|
100
|
+
* The quadrilateral covering `line`'s characters in `[start, end)`.
|
|
101
|
+
*
|
|
102
|
+
* Built from the baseline rather than from a stored rectangle, so rotated text — a
|
|
103
|
+
* drawing's vertical dimension labels, a sideways table header — gets a box at its own
|
|
104
|
+
* angle instead of an axis-aligned one that covers the wrong pixels.
|
|
105
|
+
*/
|
|
106
|
+
export declare function lineQuad(line: TextLine, start: number, end: number): Quad;
|
|
107
|
+
/** The smallest upright rectangle containing `quad`. */
|
|
108
|
+
export declare function quadBounds(quad: Quad): Rect;
|
|
109
|
+
/** Scale a quad from 72-DPI page space into a render's pixels. */
|
|
110
|
+
export declare function scaleQuad(quad: Quad, scale: number): Quad;
|
|
111
|
+
//# sourceMappingURL=text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,IAAI,cAAc,EAE3B,MAAM,2BAA2B,CAAC;AAEnC;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,gCAAgC;IAChC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IACpC;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,+EAA+E;AAC/E,MAAM,WAAW,IAAI;IACnB,mBAAmB;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,mBAAmB;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,uBAAuB;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,uBAAuB;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,iCAAiC;AACjC,MAAM,WAAW,IAAI;IACnB,iBAAiB;IACjB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa;IACb,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,cAAc;IACd,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,gBAAgB;AAChB,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,QAAQ,CAMzE;AAED,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAEjD;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAMpD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAyBzE;AAED,wDAAwD;AACxD,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAM3C;AAED,kEAAkE;AAClE,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAWzD"}
|
package/dist/text.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** @internal */
|
|
2
|
+
export function toPageText(page, native) {
|
|
3
|
+
return {
|
|
4
|
+
page,
|
|
5
|
+
lines: native.lines,
|
|
6
|
+
undecodedGlyphs: native.undecodedGlyphs,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/** Every character on the page a search can see. */
|
|
10
|
+
export function pageString(text) {
|
|
11
|
+
return text.lines.map((line) => line.text).join('\n');
|
|
12
|
+
}
|
|
13
|
+
/** Roughly how much memory a page's text holds, for cache accounting. */
|
|
14
|
+
export function pageTextBytes(text) {
|
|
15
|
+
let bytes = 64;
|
|
16
|
+
for (const line of text.lines) {
|
|
17
|
+
bytes += line.text.length * 2 + line.offsets.byteLength + 48;
|
|
18
|
+
}
|
|
19
|
+
return bytes;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The quadrilateral covering `line`'s characters in `[start, end)`.
|
|
23
|
+
*
|
|
24
|
+
* Built from the baseline rather than from a stored rectangle, so rotated text — a
|
|
25
|
+
* drawing's vertical dimension labels, a sideways table header — gets a box at its own
|
|
26
|
+
* angle instead of an axis-aligned one that covers the wrong pixels.
|
|
27
|
+
*/
|
|
28
|
+
export function lineQuad(line, start, end) {
|
|
29
|
+
const last = line.offsets.length - 1;
|
|
30
|
+
const from = line.offsets[clamp(start, 0, last)] ?? 0;
|
|
31
|
+
const to = line.offsets[clamp(end, 0, last)] ?? from;
|
|
32
|
+
// Rotating the baseline direction a quarter turn gives "up" — negative y, since the
|
|
33
|
+
// space has y increasing downwards.
|
|
34
|
+
const upX = line.dy;
|
|
35
|
+
const upY = -line.dx;
|
|
36
|
+
const ax = line.x + line.dx * from;
|
|
37
|
+
const ay = line.y + line.dy * from;
|
|
38
|
+
const bx = line.x + line.dx * to;
|
|
39
|
+
const by = line.y + line.dy * to;
|
|
40
|
+
return {
|
|
41
|
+
x0: ax + upX * line.ascent,
|
|
42
|
+
y0: ay + upY * line.ascent,
|
|
43
|
+
x1: bx + upX * line.ascent,
|
|
44
|
+
y1: by + upY * line.ascent,
|
|
45
|
+
x2: bx - upX * line.descent,
|
|
46
|
+
y2: by - upY * line.descent,
|
|
47
|
+
x3: ax - upX * line.descent,
|
|
48
|
+
y3: ay - upY * line.descent,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/** The smallest upright rectangle containing `quad`. */
|
|
52
|
+
export function quadBounds(quad) {
|
|
53
|
+
const xs = [quad.x0, quad.x1, quad.x2, quad.x3];
|
|
54
|
+
const ys = [quad.y0, quad.y1, quad.y2, quad.y3];
|
|
55
|
+
const x = Math.min(...xs);
|
|
56
|
+
const y = Math.min(...ys);
|
|
57
|
+
return { x, y, width: Math.max(...xs) - x, height: Math.max(...ys) - y };
|
|
58
|
+
}
|
|
59
|
+
/** Scale a quad from 72-DPI page space into a render's pixels. */
|
|
60
|
+
export function scaleQuad(quad, scale) {
|
|
61
|
+
return {
|
|
62
|
+
x0: quad.x0 * scale,
|
|
63
|
+
y0: quad.y0 * scale,
|
|
64
|
+
x1: quad.x1 * scale,
|
|
65
|
+
y1: quad.y1 * scale,
|
|
66
|
+
x2: quad.x2 * scale,
|
|
67
|
+
y2: quad.y2 * scale,
|
|
68
|
+
x3: quad.x3 * scale,
|
|
69
|
+
y3: quad.y3 * scale,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function clamp(value, low, high) {
|
|
73
|
+
return value < low ? low : value > high ? high : value;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=text.js.map
|
package/dist/text.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { MatchOptions } from './search.js';
|
|
1
2
|
/** Anything we can turn into PDF bytes. `File` is a `Blob`, so it is covered. */
|
|
2
3
|
export type PdfSource = Uint8Array | ArrayBuffer | ArrayBufferView | Blob;
|
|
4
|
+
/** How to size a render, and where it sits in the queue. */
|
|
3
5
|
export interface RenderOptions {
|
|
4
6
|
/**
|
|
5
7
|
* Scheduling order. **Lower runs first**; the default, 0, is the most urgent tier.
|
|
@@ -25,6 +27,7 @@ export interface RenderOptions {
|
|
|
25
27
|
*/
|
|
26
28
|
fitWidth?: number;
|
|
27
29
|
}
|
|
30
|
+
/** {@link RenderOptions}, plus the two dials that only apply to a stream. */
|
|
28
31
|
export interface StreamOptions extends RenderOptions {
|
|
29
32
|
/**
|
|
30
33
|
* How far ahead of consumption to queue. Defaults to the runtime's concurrency.
|
|
@@ -41,22 +44,41 @@ export interface StreamOptions extends RenderOptions {
|
|
|
41
44
|
}
|
|
42
45
|
/** A rendered page. `data` is tightly packed RGBA8, `height * stride` bytes. */
|
|
43
46
|
export interface RenderedPage {
|
|
47
|
+
/** Output width in pixels, after `dpi` or `fitWidth` was applied. */
|
|
44
48
|
readonly width: number;
|
|
49
|
+
/** Output height in pixels. */
|
|
45
50
|
readonly height: number;
|
|
51
|
+
/**
|
|
52
|
+
* Bytes per row. Always `width * 4` today, since the buffer is tightly packed —
|
|
53
|
+
* read it rather than recomputing it, so a future padded layout does not silently
|
|
54
|
+
* skew every row.
|
|
55
|
+
*/
|
|
46
56
|
readonly stride: number;
|
|
57
|
+
/** Always `'rgba8'`. Present so a second pixel layout could be added without a cast. */
|
|
47
58
|
readonly format: 'rgba8';
|
|
59
|
+
/**
|
|
60
|
+
* The pixels, non-premultiplied RGBA.
|
|
61
|
+
*
|
|
62
|
+
* On wasm this view is backed by the module's shared linear memory, which is why
|
|
63
|
+
* {@link toImageData} and `Blob` construction copy rather than borrow.
|
|
64
|
+
*/
|
|
48
65
|
readonly data: Uint8Array;
|
|
49
66
|
}
|
|
67
|
+
/** One result from {@link Document.stream}, tagged with the page it came from. */
|
|
50
68
|
export interface StreamedPage {
|
|
51
69
|
/** Index of the page in the document. */
|
|
52
70
|
readonly page: number;
|
|
71
|
+
/** The rendered pixels. */
|
|
53
72
|
readonly bitmap: RenderedPage;
|
|
54
73
|
}
|
|
55
74
|
/** Page dimensions in PDF points (1/72 inch). */
|
|
56
75
|
export interface PageSize {
|
|
76
|
+
/** Width in points, with rotation and the crop box already applied. */
|
|
57
77
|
readonly width: number;
|
|
78
|
+
/** Height in points, with rotation and the crop box already applied. */
|
|
58
79
|
readonly height: number;
|
|
59
80
|
}
|
|
81
|
+
/** Everything fixed for the lifetime of a {@link Document}: its queue and its caches. */
|
|
60
82
|
export interface OpenOptions {
|
|
61
83
|
/** Password for an encrypted document. */
|
|
62
84
|
password?: string;
|
|
@@ -87,5 +109,29 @@ export interface OpenOptions {
|
|
|
87
109
|
* `renderPages` is a throughput API and would evict everything useful in one call.
|
|
88
110
|
*/
|
|
89
111
|
cacheBytes?: number;
|
|
112
|
+
/**
|
|
113
|
+
* Bytes of extracted page text to keep. Defaults to 32 MB; `0` disables it.
|
|
114
|
+
*
|
|
115
|
+
* Text is three orders of magnitude smaller than the same page's pixels — a dense
|
|
116
|
+
* page of a paper is ~80 KB against ~11 MB — so the default holds hundreds of pages
|
|
117
|
+
* and a repeated search never re-extracts one.
|
|
118
|
+
*/
|
|
119
|
+
textCacheBytes?: number;
|
|
120
|
+
}
|
|
121
|
+
/** Options for {@link Document.search}. */
|
|
122
|
+
export interface SearchOptions extends MatchOptions {
|
|
123
|
+
/**
|
|
124
|
+
* Pages to search, in order. Defaults to every page from the first.
|
|
125
|
+
*
|
|
126
|
+
* A viewer wants to search outward from the page on screen: the nearest hit is
|
|
127
|
+
* almost never on page 1, and the first result is usually the one being looked for.
|
|
128
|
+
*/
|
|
129
|
+
order?: readonly number[];
|
|
130
|
+
/** Stop after this many matches. */
|
|
131
|
+
limit?: number;
|
|
132
|
+
/** Where text extraction sits in the render queue. Defaults to behind rendering. */
|
|
133
|
+
priority?: number;
|
|
134
|
+
/** Abort the search. Pages already being extracted are left to finish. */
|
|
135
|
+
signal?: AbortSignal;
|
|
90
136
|
}
|
|
91
137
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,eAAe,GAAG,IAAI,CAAC;AAE1E,MAAM,WAAW,aAAa;IAC5B;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED,gFAAgF;AAChF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;CAC/B;AAED,iDAAiD;AACjD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,iFAAiF;AACjF,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,eAAe,GAAG,IAAI,CAAC;AAE1E,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,6EAA6E;AAC7E,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED,gFAAgF;AAChF,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wFAAwF;IACxF,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B;AAED,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC3B,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2BAA2B;IAC3B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;CAC/B;AAED,iDAAiD;AACjD,MAAM,WAAW,QAAQ;IACvB,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,yFAAyF;AACzF,MAAM,WAAW,WAAW;IAC1B,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,2CAA2C;AAC3C,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@build-qube/papyra",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Fast PDF rendering for Node and the browser, powered by Rust",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -36,10 +36,11 @@
|
|
|
36
36
|
"build": "tsc -p tsconfig.json",
|
|
37
37
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
38
38
|
"clean": "rm -rf dist *.tsbuildinfo",
|
|
39
|
-
"test": "bun test"
|
|
39
|
+
"test": "bun test test/unit",
|
|
40
|
+
"test:integration": "bun test test/integration"
|
|
40
41
|
},
|
|
41
42
|
"dependencies": {
|
|
42
|
-
"@build-qube/papyra-native": "0.0
|
|
43
|
+
"@build-qube/papyra-native": "0.1.0"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"typescript": "^7.0.2"
|