kordoc 4.24.6 → 4.24.8
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 +7 -7
- package/dist/{-7J7Y3XPH.js → -TLCDUU22.js} +11 -11
- package/dist/{chunk-TZVVK5MI.js → chunk-5MQG3GJI.js} +2 -2
- package/dist/{chunk-JIU7E7Z6.cjs → chunk-73MRAQXA.cjs} +1098 -209
- package/dist/chunk-73MRAQXA.cjs.map +1 -0
- package/dist/{chunk-ISTIOEIL.cjs → chunk-7F35EPMM.cjs} +3 -3
- package/dist/{chunk-ISTIOEIL.cjs.map → chunk-7F35EPMM.cjs.map} +1 -1
- package/dist/{chunk-GI5LWQ3S.js → chunk-7JUF6G6Z.js} +2 -2
- package/dist/{chunk-BBKRJE57.js → chunk-7XPTKW76.js} +2 -2
- package/dist/{chunk-XM2Y4DB5.js → chunk-BJABLQMB.js} +2 -2
- package/dist/{chunk-2JDVPQ33.cjs → chunk-C3BOYTY5.cjs} +2 -2
- package/dist/{chunk-2JDVPQ33.cjs.map → chunk-C3BOYTY5.cjs.map} +1 -1
- package/dist/{chunk-EVBSSU3N.js → chunk-CB57N2MG.js} +2 -2
- package/dist/{chunk-WNOWRBM4.js → chunk-D3EHIHYN.js} +2 -2
- package/dist/{chunk-GYX26HZR.js → chunk-DPB6ZVQ5.js} +927 -38
- package/dist/chunk-DPB6ZVQ5.js.map +1 -0
- package/dist/{chunk-DFRQD254.js → chunk-F7UWIMUA.js} +2 -2
- package/dist/{chunk-BKTEGPEO.js → chunk-FSWJC5RR.js} +3 -3
- package/dist/{chunk-W75FRCAP.js → chunk-IT5XO3UG.js} +926 -37
- package/dist/chunk-IT5XO3UG.js.map +1 -0
- package/dist/{chunk-HAMIOQYO.js → chunk-J7MFKS73.js} +2 -2
- package/dist/{chunk-435ECXNG.cjs → chunk-JM7PZM6E.cjs} +3 -3
- package/dist/{chunk-435ECXNG.cjs.map → chunk-JM7PZM6E.cjs.map} +1 -1
- package/dist/{chunk-G343MTBX.js → chunk-K2FGQ5D5.js} +43 -15
- package/dist/chunk-K2FGQ5D5.js.map +1 -0
- package/dist/{chunk-BZW2WS44.js → chunk-KA6JZZIW.js} +83 -716
- package/dist/chunk-KA6JZZIW.js.map +1 -0
- package/dist/{chunk-RMUDX5Q2.js → chunk-N2XN6GAQ.js} +2 -2
- package/dist/{chunk-XVTGFK2F.js → chunk-NE6G6LCP.js} +2 -2
- package/dist/{chunk-AM5ALISV.cjs → chunk-NW2CKOFL.cjs} +6 -6
- package/dist/{chunk-AM5ALISV.cjs.map → chunk-NW2CKOFL.cjs.map} +1 -1
- package/dist/{chunk-5RZBLPVP.js → chunk-OUJIV2AM.js} +4 -4
- package/dist/chunk-OUJIV2AM.js.map +1 -0
- package/dist/{chunk-VMRH6UVA.js → chunk-RCDRTQ37.js} +2 -2
- package/dist/{chunk-KR4UKOX2.js → chunk-RCT5MO53.js} +6 -6
- package/dist/{chunk-3ZLS54V4.js → chunk-TDB27K2Z.js} +2 -2
- package/dist/{chunk-EBJWBGWF.js → chunk-TTUAJYTC.js} +83 -716
- package/dist/chunk-TTUAJYTC.js.map +1 -0
- package/dist/{chunk-5XBZJ3O4.js → chunk-WTSID6AI.js} +2 -2
- package/dist/{chunk-PKCOOSDT.js → chunk-XOUZC7MX.js} +2 -2
- package/dist/{chunk-TLJJF3J6.js → chunk-Z5DT55TW.js} +3 -3
- package/dist/{chunk-J4XCQNVH.cjs → chunk-ZJYNTA5R.cjs} +141 -774
- package/dist/chunk-ZJYNTA5R.cjs.map +1 -0
- package/dist/chunks-S2GGFN6W.js +10 -0
- package/dist/cli.js +30 -30
- package/dist/{formula-DKNZKJ5Z.js → formula-DZMBNPWT.js} +4 -4
- package/dist/{formula-T7D5JIZR.js → formula-PNMQ5JFJ.js} +3 -3
- package/dist/{formula-D7LBREWP.cjs → formula-ZLNSVWS6.cjs} +9 -9
- package/dist/{formula-D7LBREWP.cjs.map → formula-ZLNSVWS6.cjs.map} +1 -1
- package/dist/{image-ocr-5POXVGN2.js → image-ocr-BPH25SFW.js} +9 -9
- package/dist/{image-ocr-7NCSIZGA.js → image-ocr-P5Q6YXTO.js} +6 -6
- package/dist/{image-ocr-N3I3MUKF.cjs → image-ocr-YUXCVOOP.cjs} +17 -17
- package/dist/{image-ocr-N3I3MUKF.cjs.map → image-ocr-YUXCVOOP.cjs.map} +1 -1
- package/dist/index.cjs +729 -701
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +38 -10
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +23 -23
- package/dist/{model-bundle-XT7G2IJU.js → model-bundle-XAM6JFZV.js} +5 -5
- package/dist/{models-AB2VO45L.js → models-6Q5ULSTP.js} +5 -5
- package/dist/{parse-worker-v2-YSSAUPWU.js → parse-worker-v2-ONX5QLJZ.js} +12 -12
- package/dist/{parser-KGDUPSA7.js → parser-54R7ENH6.js} +9 -9
- package/dist/{parser-ES3I54QL.js → parser-JHXN4S6L.js} +12 -12
- package/dist/{parser-AGDY3ZOA.cjs → parser-Z352BN56.cjs} +159 -159
- package/dist/{parser-AGDY3ZOA.cjs.map → parser-Z352BN56.cjs.map} +1 -1
- package/dist/{pdf-ocr-53WUTX6H.js → pdf-ocr-FQ4LAXM6.js} +9 -9
- package/dist/{pdf-ocr-7QSP7JLG.js → pdf-ocr-LFVER7IE.js} +6 -6
- package/dist/pdf-ocr-SMFFJYTD.cjs +31 -0
- package/dist/{pdf-ocr-X6OAHK46.cjs.map → pdf-ocr-SMFFJYTD.cjs.map} +1 -1
- package/dist/{profile-io-GGEJ3MZW.js → profile-io-YW5QWKBB.js} +3 -3
- package/dist/{rasterize-YXICEI5S.js → rasterize-T4S3NMQ7.js} +3 -3
- package/dist/{redact-doc-OYXBNTWI.js → redact-doc-CAVBR5XO.js} +11 -11
- package/dist/{render-4PBNDLK2.js → render-ZW52ZX6R.js} +7 -7
- package/dist/seal-TQ3RLVVT.js +10 -0
- package/dist/{setup-WHTMPK74.js → setup-7UGSJPJP.js} +3 -3
- package/dist/visual-6GXHKPCJ.js +21 -0
- package/dist/{watch-P6UWW52D.js → watch-M4A7B5WS.js} +12 -12
- package/package.json +4 -4
- package/dist/chunk-5RZBLPVP.js.map +0 -1
- package/dist/chunk-BZW2WS44.js.map +0 -1
- package/dist/chunk-EBJWBGWF.js.map +0 -1
- package/dist/chunk-G343MTBX.js.map +0 -1
- package/dist/chunk-GYX26HZR.js.map +0 -1
- package/dist/chunk-J4XCQNVH.cjs.map +0 -1
- package/dist/chunk-JIU7E7Z6.cjs.map +0 -1
- package/dist/chunk-W75FRCAP.js.map +0 -1
- package/dist/chunks-3MWJ7HOZ.js +0 -10
- package/dist/pdf-ocr-X6OAHK46.cjs +0 -31
- package/dist/seal-KJYAU23C.js +0 -10
- package/dist/visual-PHKJTSFR.js +0 -21
- /package/dist/{-7J7Y3XPH.js.map → -TLCDUU22.js.map} +0 -0
- /package/dist/{chunk-TZVVK5MI.js.map → chunk-5MQG3GJI.js.map} +0 -0
- /package/dist/{chunk-GI5LWQ3S.js.map → chunk-7JUF6G6Z.js.map} +0 -0
- /package/dist/{chunk-BBKRJE57.js.map → chunk-7XPTKW76.js.map} +0 -0
- /package/dist/{chunk-XM2Y4DB5.js.map → chunk-BJABLQMB.js.map} +0 -0
- /package/dist/{chunk-EVBSSU3N.js.map → chunk-CB57N2MG.js.map} +0 -0
- /package/dist/{chunk-WNOWRBM4.js.map → chunk-D3EHIHYN.js.map} +0 -0
- /package/dist/{chunk-DFRQD254.js.map → chunk-F7UWIMUA.js.map} +0 -0
- /package/dist/{chunk-BKTEGPEO.js.map → chunk-FSWJC5RR.js.map} +0 -0
- /package/dist/{chunk-HAMIOQYO.js.map → chunk-J7MFKS73.js.map} +0 -0
- /package/dist/{chunk-RMUDX5Q2.js.map → chunk-N2XN6GAQ.js.map} +0 -0
- /package/dist/{chunk-XVTGFK2F.js.map → chunk-NE6G6LCP.js.map} +0 -0
- /package/dist/{chunk-VMRH6UVA.js.map → chunk-RCDRTQ37.js.map} +0 -0
- /package/dist/{chunk-KR4UKOX2.js.map → chunk-RCT5MO53.js.map} +0 -0
- /package/dist/{chunk-3ZLS54V4.js.map → chunk-TDB27K2Z.js.map} +0 -0
- /package/dist/{chunk-5XBZJ3O4.js.map → chunk-WTSID6AI.js.map} +0 -0
- /package/dist/{chunk-PKCOOSDT.js.map → chunk-XOUZC7MX.js.map} +0 -0
- /package/dist/{chunk-TLJJF3J6.js.map → chunk-Z5DT55TW.js.map} +0 -0
- /package/dist/{chunks-3MWJ7HOZ.js.map → chunks-S2GGFN6W.js.map} +0 -0
- /package/dist/{formula-DKNZKJ5Z.js.map → formula-DZMBNPWT.js.map} +0 -0
- /package/dist/{formula-T7D5JIZR.js.map → formula-PNMQ5JFJ.js.map} +0 -0
- /package/dist/{image-ocr-5POXVGN2.js.map → image-ocr-BPH25SFW.js.map} +0 -0
- /package/dist/{image-ocr-7NCSIZGA.js.map → image-ocr-P5Q6YXTO.js.map} +0 -0
- /package/dist/{model-bundle-XT7G2IJU.js.map → model-bundle-XAM6JFZV.js.map} +0 -0
- /package/dist/{models-AB2VO45L.js.map → models-6Q5ULSTP.js.map} +0 -0
- /package/dist/{parse-worker-v2-YSSAUPWU.js.map → parse-worker-v2-ONX5QLJZ.js.map} +0 -0
- /package/dist/{parser-KGDUPSA7.js.map → parser-54R7ENH6.js.map} +0 -0
- /package/dist/{parser-ES3I54QL.js.map → parser-JHXN4S6L.js.map} +0 -0
- /package/dist/{pdf-ocr-53WUTX6H.js.map → pdf-ocr-FQ4LAXM6.js.map} +0 -0
- /package/dist/{pdf-ocr-7QSP7JLG.js.map → pdf-ocr-LFVER7IE.js.map} +0 -0
- /package/dist/{profile-io-GGEJ3MZW.js.map → profile-io-YW5QWKBB.js.map} +0 -0
- /package/dist/{rasterize-YXICEI5S.js.map → rasterize-T4S3NMQ7.js.map} +0 -0
- /package/dist/{redact-doc-OYXBNTWI.js.map → redact-doc-CAVBR5XO.js.map} +0 -0
- /package/dist/{render-4PBNDLK2.js.map → render-ZW52ZX6R.js.map} +0 -0
- /package/dist/{seal-KJYAU23C.js.map → seal-TQ3RLVVT.js.map} +0 -0
- /package/dist/{setup-WHTMPK74.js.map → setup-7UGSJPJP.js.map} +0 -0
- /package/dist/{visual-PHKJTSFR.js.map → visual-6GXHKPCJ.js.map} +0 -0
- /package/dist/{watch-P6UWW52D.js.map → watch-M4A7B5WS.js.map} +0 -0
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
var
|
|
8
|
+
var _chunkNW2CKOFLcjs = require('./chunk-NW2CKOFL.cjs');
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
var
|
|
12
|
+
var _chunkJM7PZM6Ecjs = require('./chunk-JM7PZM6E.cjs');
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
var
|
|
16
|
+
var _chunkC3BOYTY5cjs = require('./chunk-C3BOYTY5.cjs');
|
|
17
17
|
|
|
18
18
|
// src/ocr/models.ts
|
|
19
19
|
var _path = require('path');
|
|
@@ -57,7 +57,7 @@ var OCR_REC_DICT = {
|
|
|
57
57
|
sizeMb: 1
|
|
58
58
|
};
|
|
59
59
|
function getOcrModelsDir() {
|
|
60
|
-
return
|
|
60
|
+
return _chunkJM7PZM6Ecjs.getModelsDir.call(void 0, "ppocr");
|
|
61
61
|
}
|
|
62
62
|
var DEFAULT_OCR_MODELS = Object.freeze({
|
|
63
63
|
det: { spec: OCR_DET_MODEL },
|
|
@@ -99,7 +99,7 @@ async function ensureOcrModelsFor(sel, onProgress) {
|
|
|
99
99
|
if (!stamp || verifiedInProcess.get(path) !== stamp) todo.push(s.spec);
|
|
100
100
|
}
|
|
101
101
|
if (!todo.length) return;
|
|
102
|
-
await
|
|
102
|
+
await _chunkJM7PZM6Ecjs.ensureModelsIn.call(void 0, dir, todo, onProgress);
|
|
103
103
|
for (const spec of todo) {
|
|
104
104
|
const path = _path.join.call(void 0, dir, spec.filename), stamp = await fileStamp(path);
|
|
105
105
|
if (stamp) verifiedInProcess.set(path, stamp);
|
|
@@ -146,6 +146,773 @@ function ocrModelPath(spec) {
|
|
|
146
146
|
return _path.join.call(void 0, getOcrModelsDir(), spec.filename);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
// src/ocr/line-split.ts
|
|
150
|
+
function grayCrop(rgba, pageW, box) {
|
|
151
|
+
const out = new Uint8Array(box.w * box.h);
|
|
152
|
+
for (let y = 0; y < box.h; y++) {
|
|
153
|
+
let si = ((box.y + y) * pageW + box.x) * 4;
|
|
154
|
+
let di = y * box.w;
|
|
155
|
+
for (let x = 0; x < box.w; x++, si += 4, di++) {
|
|
156
|
+
out[di] = rgba[si] * 77 + rgba[si + 1] * 150 + rgba[si + 2] * 29 >> 8;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return out;
|
|
160
|
+
}
|
|
161
|
+
function inkStats(gray) {
|
|
162
|
+
const hist = new Uint32Array(256);
|
|
163
|
+
for (let i = 0; i < gray.length; i++) hist[gray[i]]++;
|
|
164
|
+
const total = gray.length;
|
|
165
|
+
let sumAll = 0;
|
|
166
|
+
for (let v = 0; v < 256; v++) sumAll += v * hist[v];
|
|
167
|
+
let wB = 0, sumB = 0, best = -1, thr = 127;
|
|
168
|
+
for (let t = 0; t < 256; t++) {
|
|
169
|
+
wB += hist[t];
|
|
170
|
+
if (wB === 0) continue;
|
|
171
|
+
const wF = total - wB;
|
|
172
|
+
if (wF === 0) break;
|
|
173
|
+
sumB += t * hist[t];
|
|
174
|
+
const mB = sumB / wB;
|
|
175
|
+
const mF = (sumAll - sumB) / wF;
|
|
176
|
+
const between = wB * wF * (mB - mF) * (mB - mF);
|
|
177
|
+
if (between > best) {
|
|
178
|
+
best = between;
|
|
179
|
+
thr = t;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
let nDark = 0, sDark = 0;
|
|
183
|
+
for (let v = 0; v <= thr; v++) {
|
|
184
|
+
nDark += hist[v];
|
|
185
|
+
sDark += v * hist[v];
|
|
186
|
+
}
|
|
187
|
+
const nLight = total - nDark;
|
|
188
|
+
const sLight = sumAll - sDark;
|
|
189
|
+
if (nDark === 0 || nLight === 0) return { threshold: thr, darkInk: true, contrast: 0, inkRatio: 0 };
|
|
190
|
+
const darkInk = nDark <= nLight;
|
|
191
|
+
return {
|
|
192
|
+
threshold: thr,
|
|
193
|
+
darkInk,
|
|
194
|
+
contrast: sLight / nLight - sDark / nDark,
|
|
195
|
+
inkRatio: (darkInk ? nDark : nLight) / total
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function splitRowBands(gray, w, h, ink, minBandRatio) {
|
|
199
|
+
const isInk = (v) => ink.darkInk ? v <= ink.threshold : v > ink.threshold;
|
|
200
|
+
const colInk = new Uint32Array(w);
|
|
201
|
+
for (let y = 0; y < h; y++) {
|
|
202
|
+
const off = y * w;
|
|
203
|
+
for (let x = 0; x < w; x++) if (isInk(gray[off + x])) colInk[x]++;
|
|
204
|
+
}
|
|
205
|
+
const ruleCol = new Uint8Array(w);
|
|
206
|
+
let liveW = 0;
|
|
207
|
+
for (let x = 0; x < w; x++) {
|
|
208
|
+
if (colInk[x] >= h * 0.85) ruleCol[x] = 1;
|
|
209
|
+
else liveW++;
|
|
210
|
+
}
|
|
211
|
+
const rowInk = new Uint32Array(h);
|
|
212
|
+
for (let y = 0; y < h; y++) {
|
|
213
|
+
let n = 0;
|
|
214
|
+
const off = y * w;
|
|
215
|
+
for (let x = 0; x < w; x++) if (!ruleCol[x] && isInk(gray[off + x])) n++;
|
|
216
|
+
rowInk[y] = n >= liveW * 0.85 ? 0 : n;
|
|
217
|
+
}
|
|
218
|
+
const blank = Math.max(1, Math.floor(w * 0.02));
|
|
219
|
+
let bands = [];
|
|
220
|
+
let start = -1;
|
|
221
|
+
for (let y = 0; y <= h; y++) {
|
|
222
|
+
const on = y < h && rowInk[y] > blank;
|
|
223
|
+
if (on && start < 0) start = y;
|
|
224
|
+
else if (!on && start >= 0) {
|
|
225
|
+
bands.push([start, y]);
|
|
226
|
+
start = -1;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const inkCols = (y0, y1) => {
|
|
230
|
+
let x0 = w, x1 = -1;
|
|
231
|
+
for (let y = y0; y < y1; y++) {
|
|
232
|
+
const off = y * w;
|
|
233
|
+
for (let x = 0; x < w; x++) if (!ruleCol[x] && isInk(gray[off + x])) {
|
|
234
|
+
if (x < x0) x0 = x;
|
|
235
|
+
if (x > x1) x1 = x;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return x1 >= x0 ? [x0, x1 + 1] : [0, w];
|
|
239
|
+
};
|
|
240
|
+
if (bands.length <= 1) return [{ y0: _nullishCoalesce(_optionalChain([bands, 'access', _7 => _7[0], 'optionalAccess', _8 => _8[0]]), () => ( 0)), y1: _nullishCoalesce(_optionalChain([bands, 'access', _9 => _9[0], 'optionalAccess', _10 => _10[1]]), () => ( h)), x0: 0, x1: w }];
|
|
241
|
+
const widths = bands.map(([y0, y1]) => {
|
|
242
|
+
const [a, b] = inkCols(y0, y1);
|
|
243
|
+
return b - a;
|
|
244
|
+
}).sort((a, b) => a - b);
|
|
245
|
+
const charSize = widths[widths.length >> 1];
|
|
246
|
+
const minBand = Math.max(3, minBandRatio * charSize);
|
|
247
|
+
for (let i = 0; i + 1 < bands.length; ) {
|
|
248
|
+
const gap = bands[i + 1][0] - bands[i][1];
|
|
249
|
+
if (gap <= Math.max(2, charSize * 0.15) && bands[i + 1][1] - bands[i][0] <= charSize * 1.3) {
|
|
250
|
+
bands.splice(i, 2, [bands[i][0], bands[i + 1][1]]);
|
|
251
|
+
} else i++;
|
|
252
|
+
}
|
|
253
|
+
while (bands.length > 1 && bands[0][0] <= 1 && bands[0][1] - bands[0][0] < minBand) bands.shift();
|
|
254
|
+
while (bands.length > 1 && bands[bands.length - 1][1] >= h - 1 && bands[bands.length - 1][1] - bands[bands.length - 1][0] < minBand) bands.pop();
|
|
255
|
+
for (; ; ) {
|
|
256
|
+
let idx = -1, minH = Infinity;
|
|
257
|
+
for (let i = 0; i < bands.length; i++) {
|
|
258
|
+
const bh = bands[i][1] - bands[i][0];
|
|
259
|
+
if (bh < minBand && bh < minH) {
|
|
260
|
+
minH = bh;
|
|
261
|
+
idx = i;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (idx < 0 || bands.length === 1) break;
|
|
265
|
+
const gapPrev = idx > 0 ? bands[idx][0] - bands[idx - 1][1] : Infinity;
|
|
266
|
+
const gapNext = idx < bands.length - 1 ? bands[idx + 1][0] - bands[idx][1] : Infinity;
|
|
267
|
+
const j = gapPrev <= gapNext ? idx - 1 : idx + 1;
|
|
268
|
+
const a = Math.min(idx, j), b = Math.max(idx, j);
|
|
269
|
+
bands = [...bands.slice(0, a), [bands[a][0], bands[b][1]], ...bands.slice(b + 1)];
|
|
270
|
+
}
|
|
271
|
+
if (bands.length === 1) return [{ y0: bands[0][0], y1: bands[0][1], x0: 0, x1: w }];
|
|
272
|
+
return bands.map(([y0, y1]) => {
|
|
273
|
+
const [x0, x1] = inkCols(y0, y1);
|
|
274
|
+
return { y0, y1, x0, x1 };
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function components(gray, w, h, ink) {
|
|
278
|
+
const isInk = (v) => ink.darkInk ? v <= ink.threshold : v > ink.threshold;
|
|
279
|
+
const comps = [];
|
|
280
|
+
const label = new Int32Array(w * h);
|
|
281
|
+
const stack = [];
|
|
282
|
+
for (let p0 = 0; p0 < w * h; p0++) {
|
|
283
|
+
if (label[p0] || !isInk(gray[p0])) continue;
|
|
284
|
+
const c = { x0: w, x1: 0, y0: h, y1: 0, id: comps.length + 1 };
|
|
285
|
+
label[p0] = c.id;
|
|
286
|
+
stack.push(p0);
|
|
287
|
+
while (stack.length) {
|
|
288
|
+
const p = stack.pop();
|
|
289
|
+
const x = p % w, y = p / w | 0;
|
|
290
|
+
if (x < c.x0) c.x0 = x;
|
|
291
|
+
if (x + 1 > c.x1) c.x1 = x + 1;
|
|
292
|
+
if (y < c.y0) c.y0 = y;
|
|
293
|
+
if (y + 1 > c.y1) c.y1 = y + 1;
|
|
294
|
+
for (let dy = -1; dy <= 1; dy++) for (let dx = -1; dx <= 1; dx++) {
|
|
295
|
+
const nx = x + dx, ny = y + dy;
|
|
296
|
+
if (nx < 0 || ny < 0 || nx >= w || ny >= h) continue;
|
|
297
|
+
const q = ny * w + nx;
|
|
298
|
+
if (!label[q] && isInk(gray[q])) {
|
|
299
|
+
label[q] = c.id;
|
|
300
|
+
stack.push(q);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (c.y1 - c.y0 < h * 0.85 && c.x1 - c.x0 < w * 0.85) comps.push(c);
|
|
305
|
+
}
|
|
306
|
+
return { comps, label };
|
|
307
|
+
}
|
|
308
|
+
function leadingTriangle(gray, w, h, ink) {
|
|
309
|
+
const { comps, label } = components(gray, w, h, ink);
|
|
310
|
+
let charH = 0;
|
|
311
|
+
for (const c of comps) charH = Math.max(charH, c.y1 - c.y0);
|
|
312
|
+
const first = comps.filter((c) => c.y1 - c.y0 >= charH * 0.4).sort((a, b) => a.x0 - b.x0)[0];
|
|
313
|
+
if (!first || charH < 8) return null;
|
|
314
|
+
const cw = first.x1 - first.x0, ch = first.y1 - first.y0;
|
|
315
|
+
if (cw < ch * 0.8 || cw > ch * 1.8) return null;
|
|
316
|
+
const rowSpan = (y) => {
|
|
317
|
+
let n = 0, lo = -1, hi = -1, runs = 0, prev = false;
|
|
318
|
+
for (let x = first.x0; x < first.x1; x++) {
|
|
319
|
+
const on = label[y * w + x] === first.id;
|
|
320
|
+
if (on) {
|
|
321
|
+
n++;
|
|
322
|
+
if (lo < 0) lo = x - first.x0;
|
|
323
|
+
hi = x - first.x0;
|
|
324
|
+
if (!prev) runs++;
|
|
325
|
+
}
|
|
326
|
+
prev = on;
|
|
327
|
+
}
|
|
328
|
+
return { n, lo, hi, runs };
|
|
329
|
+
};
|
|
330
|
+
const base = Math.max(rowSpan(first.y1 - 1).n, rowSpan(first.y1 - 2).n);
|
|
331
|
+
if (base < cw * 0.7) return null;
|
|
332
|
+
for (let y = first.y0; y < first.y0 + Math.max(1, Math.round(ch * 0.2)); y++) {
|
|
333
|
+
const r = rowSpan(y);
|
|
334
|
+
if (r.n === 0) continue;
|
|
335
|
+
if (r.hi - r.lo + 1 > cw * 0.4 || (r.lo + r.hi) / 2 < cw * 0.25 || (r.lo + r.hi) / 2 > cw * 0.75) return null;
|
|
336
|
+
}
|
|
337
|
+
const mid = rowSpan(first.y0 + Math.round(ch * 0.6));
|
|
338
|
+
if (mid.lo < 0 || mid.lo > cw * 0.3 || mid.hi < cw * 0.7) return null;
|
|
339
|
+
return mid.runs >= 2 ? "\u25B3" : "\u25B2";
|
|
340
|
+
}
|
|
341
|
+
function leaderRuns(gray, w, h, ink, minDots) {
|
|
342
|
+
const comps = components(gray, w, h, ink).comps.sort((a, b) => a.x0 - b.x0);
|
|
343
|
+
const blobs = [];
|
|
344
|
+
for (const c of comps) {
|
|
345
|
+
const last = blobs[blobs.length - 1];
|
|
346
|
+
if (last && c.x0 < last.x1) {
|
|
347
|
+
last.x1 = Math.max(last.x1, c.x1);
|
|
348
|
+
last.y0 = Math.min(last.y0, c.y0);
|
|
349
|
+
last.y1 = Math.max(last.y1, c.y1);
|
|
350
|
+
} else blobs.push({ x0: c.x0, x1: c.x1, y0: c.y0, y1: c.y1 });
|
|
351
|
+
}
|
|
352
|
+
let charH = 0;
|
|
353
|
+
for (const b of blobs) charH = Math.max(charH, b.y1 - b.y0);
|
|
354
|
+
if (charH < 8) return [];
|
|
355
|
+
const small = (c) => c.x1 - c.x0 <= charH * 0.3 && c.y1 - c.y0 <= charH * 0.3;
|
|
356
|
+
let bandTop = h, bandBot = 0;
|
|
357
|
+
for (const c of comps) if (!small(c)) {
|
|
358
|
+
bandTop = Math.min(bandTop, c.y0);
|
|
359
|
+
bandBot = Math.max(bandBot, c.y1);
|
|
360
|
+
}
|
|
361
|
+
const cy = (c) => (c.y0 + c.y1) / 2;
|
|
362
|
+
const isDot = (b) => small(b) && cy(b) >= bandTop && cy(b) <= bandBot;
|
|
363
|
+
const runs = [];
|
|
364
|
+
for (let i = 0; i < blobs.length; ) {
|
|
365
|
+
if (!isDot(blobs[i])) {
|
|
366
|
+
i++;
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
let j = i;
|
|
370
|
+
while (j + 1 < blobs.length && isDot(blobs[j + 1]) && blobs[j + 1].x0 - blobs[j].x1 <= charH && Math.abs(cy(blobs[j + 1]) - cy(blobs[i])) <= charH * 0.2) j++;
|
|
371
|
+
const x0 = blobs[i].x0, x1 = blobs[j].x1, y = cy(blobs[i]);
|
|
372
|
+
const onLine = comps.some((c) => !small(c) && c.y0 <= y && c.y1 >= y && (c.x1 <= x0 + 2 && c.x1 >= x0 - 2 * charH || c.x0 >= x1 - 2 && c.x0 <= x1 + 2 * charH));
|
|
373
|
+
const run = blobs.slice(i, j + 1).filter((b) => b.x0 > 0 && b.x1 < w);
|
|
374
|
+
const spread = (xs) => {
|
|
375
|
+
const v = [...xs].sort((a, b) => a - b).slice(xs.length >= 5 ? 1 : 0, xs.length >= 5 ? -1 : void 0);
|
|
376
|
+
return v[v.length - 1] / Math.max(1, v[0]);
|
|
377
|
+
};
|
|
378
|
+
const even = run.length >= 2 && spread(run.map((b) => b.x1 - b.x0)) <= 2.5 && spread(run.map((b) => b.y1 - b.y0)) <= 2.5 && spread(run.slice(1).map((b, k) => b.x0 - run[k].x0)) <= 1.8;
|
|
379
|
+
if (j - i + 1 >= minDots && onLine && even) runs.push([x0, x1]);
|
|
380
|
+
i = j + 1;
|
|
381
|
+
}
|
|
382
|
+
return runs;
|
|
383
|
+
}
|
|
384
|
+
function inkBounds(gray, w, h, ink) {
|
|
385
|
+
const isInk = (v) => ink.darkInk ? v <= ink.threshold : v > ink.threshold;
|
|
386
|
+
const colInk = new Uint32Array(w);
|
|
387
|
+
const rowInk = new Uint32Array(h);
|
|
388
|
+
for (let y = 0; y < h; y++) {
|
|
389
|
+
const off = y * w;
|
|
390
|
+
for (let x = 0; x < w; x++) if (isInk(gray[off + x])) {
|
|
391
|
+
colInk[x]++;
|
|
392
|
+
rowInk[y]++;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
const ruleCol = new Uint8Array(w), ruleRow = new Uint8Array(h);
|
|
396
|
+
for (let x = 0; x < w; x++) if (colInk[x] >= h * 0.85) ruleCol[x] = 1;
|
|
397
|
+
for (let y = 0; y < h; y++) if (rowInk[y] >= w * 0.85) ruleRow[y] = 1;
|
|
398
|
+
let x0 = w, x1 = -1, y0 = h, y1 = -1;
|
|
399
|
+
for (let y = 0; y < h; y++) {
|
|
400
|
+
if (ruleRow[y]) continue;
|
|
401
|
+
const off = y * w;
|
|
402
|
+
for (let x = 0; x < w; x++) {
|
|
403
|
+
if (ruleCol[x] || !isInk(gray[off + x])) continue;
|
|
404
|
+
if (x < x0) x0 = x;
|
|
405
|
+
if (x > x1) x1 = x;
|
|
406
|
+
if (y < y0) y0 = y;
|
|
407
|
+
if (y > y1) y1 = y;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (x1 < x0 || y1 < y0) return { x0: 0, y0: 0, x1: w, y1: h };
|
|
411
|
+
return { x0, y0, x1: x1 + 1, y1: y1 + 1 };
|
|
412
|
+
}
|
|
413
|
+
function bracketFeatures(gray, w, h, ink, cx) {
|
|
414
|
+
const { comps, label } = components(gray, w, h, ink);
|
|
415
|
+
let charH = 0;
|
|
416
|
+
for (const c of comps) charH = Math.max(charH, c.y1 - c.y0);
|
|
417
|
+
if (charH < 8) return null;
|
|
418
|
+
const tol = Math.max(2, charH * 0.3);
|
|
419
|
+
let best = null, bestD = Infinity;
|
|
420
|
+
for (const c of comps) {
|
|
421
|
+
if (c.y1 - c.y0 < charH * 0.3 || c.x1 < cx - tol || c.x0 > cx + tol) continue;
|
|
422
|
+
const d = Math.abs((c.x0 + c.x1) / 2 - cx);
|
|
423
|
+
if (d < bestD) {
|
|
424
|
+
bestD = d;
|
|
425
|
+
best = c;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (!best) return null;
|
|
429
|
+
const b = best;
|
|
430
|
+
const cw = b.x1 - b.x0, ch = b.y1 - b.y0;
|
|
431
|
+
if (cw < 3 || ch < 8) return null;
|
|
432
|
+
const spans = [];
|
|
433
|
+
for (let y = b.y0; y < b.y1; y++) {
|
|
434
|
+
let n = 0;
|
|
435
|
+
for (let x = b.x0; x < b.x1; x++) if (label[y * w + x] === b.id) n++;
|
|
436
|
+
spans.push(n);
|
|
437
|
+
}
|
|
438
|
+
const band = Math.max(1, Math.round(ch * 0.15));
|
|
439
|
+
const top = Math.max(...spans.slice(0, band)) / cw, bottom = Math.max(...spans.slice(ch - band)) / cw;
|
|
440
|
+
const midRows = spans.slice(Math.floor(ch * 0.3), Math.ceil(ch * 0.7)).sort((p, q) => p - q);
|
|
441
|
+
const stroke = _nullishCoalesce(midRows[midRows.length >> 1], () => ( 0));
|
|
442
|
+
const taper = spans.filter((n) => n > stroke && n < cw).length / ch;
|
|
443
|
+
const fill = spans.reduce((a, n) => a + n, 0) / (cw * ch);
|
|
444
|
+
return { top, bottom, taper, fill, cw, ch, charH };
|
|
445
|
+
}
|
|
446
|
+
function romanStems(gray, w, h, ink, prevX, nextX) {
|
|
447
|
+
const { comps, label } = components(gray, w, h, ink);
|
|
448
|
+
let charH = 0;
|
|
449
|
+
for (const c of comps) charH = Math.max(charH, c.y1 - c.y0);
|
|
450
|
+
if (charH < 10) return null;
|
|
451
|
+
const x0 = prevX + charH * 0.35, x1 = nextX - charH * 0.35;
|
|
452
|
+
const sel = comps.filter((c) => c.y1 - c.y0 >= charH * 0.6 && (c.x0 + c.x1) / 2 >= x0 && (c.x0 + c.x1) / 2 < x1);
|
|
453
|
+
if (!sel.length) return null;
|
|
454
|
+
const ids = new Set(sel.map((c) => c.id));
|
|
455
|
+
const ux0 = Math.min(...sel.map((c) => c.x0)), ux1 = Math.max(...sel.map((c) => c.x1));
|
|
456
|
+
const uy0 = Math.min(...sel.map((c) => c.y0)), uy1 = Math.max(...sel.map((c) => c.y1));
|
|
457
|
+
const uh = uy1 - uy0;
|
|
458
|
+
const counts = /* @__PURE__ */ new Map();
|
|
459
|
+
let rows = 0;
|
|
460
|
+
for (let y = uy0 + Math.floor(uh * 0.25); y < uy1 - Math.floor(uh * 0.25); y++) {
|
|
461
|
+
let runs = 0, len = 0, thick = false;
|
|
462
|
+
for (let x = ux0; x <= ux1; x++) {
|
|
463
|
+
const on = x < ux1 && ids.has(label[y * w + x]);
|
|
464
|
+
if (on) len++;
|
|
465
|
+
else if (len) {
|
|
466
|
+
runs++;
|
|
467
|
+
if (len > uh * 0.35) thick = true;
|
|
468
|
+
len = 0;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
rows++;
|
|
472
|
+
if (!thick) counts.set(runs, (_nullishCoalesce(counts.get(runs), () => ( 0))) + 1);
|
|
473
|
+
}
|
|
474
|
+
const [n, k] = _nullishCoalesce([...counts].sort((a, b) => b[1] - a[1])[0], () => ( [0, 0]));
|
|
475
|
+
return n >= 1 && n <= 3 && k >= rows * 0.7 ? n : null;
|
|
476
|
+
}
|
|
477
|
+
function circledAt(gray, w, h, ink, xs) {
|
|
478
|
+
const { comps } = components(gray, w, h, ink);
|
|
479
|
+
let charH = 0;
|
|
480
|
+
for (const c of comps) charH = Math.max(charH, c.y1 - c.y0);
|
|
481
|
+
const rings = charH < 10 ? [] : comps.filter((r) => {
|
|
482
|
+
const rw = r.x1 - r.x0, rh = r.y1 - r.y0;
|
|
483
|
+
return rh >= charH * 0.55 && rw >= rh * 0.8 && rw <= rh * 1.25 && comps.some((d) => d !== r && d.x0 > r.x0 && d.x1 < r.x1 && d.y0 > r.y0 && d.y1 < r.y1 && d.y1 - d.y0 >= rh * 0.35);
|
|
484
|
+
});
|
|
485
|
+
return xs.map((x) => rings.some((r) => x >= r.x0 && x <= r.x1));
|
|
486
|
+
}
|
|
487
|
+
function quoteHead(gray, w, h, ink, cx) {
|
|
488
|
+
const { comps, label } = components(gray, w, h, ink);
|
|
489
|
+
let charH = 0;
|
|
490
|
+
for (const c of comps) charH = Math.max(charH, c.y1 - c.y0);
|
|
491
|
+
if (charH < 10) return null;
|
|
492
|
+
const tall = comps.filter((c) => c.y1 - c.y0 >= charH * 0.6);
|
|
493
|
+
if (!tall.length) return null;
|
|
494
|
+
const mid = (Math.min(...tall.map((c) => c.y0)) + Math.max(...tall.map((c) => c.y1))) / 2;
|
|
495
|
+
let best = null, bestD = charH * 0.4;
|
|
496
|
+
for (const c of comps) {
|
|
497
|
+
const ch = c.y1 - c.y0, d = Math.abs((c.x0 + c.x1) / 2 - cx);
|
|
498
|
+
if (ch < charH * 0.12 || ch > charH * 0.5 || (c.y0 + c.y1) / 2 > mid || d > bestD) continue;
|
|
499
|
+
bestD = d;
|
|
500
|
+
best = c;
|
|
501
|
+
}
|
|
502
|
+
if (!best) return null;
|
|
503
|
+
let n = 0, sy = 0;
|
|
504
|
+
for (let y = best.y0; y < best.y1; y++) for (let x = best.x0; x < best.x1; x++) if (label[y * w + x] === best.id) {
|
|
505
|
+
n++;
|
|
506
|
+
sy += y;
|
|
507
|
+
}
|
|
508
|
+
return n ? (sy / n - best.y0) / (best.y1 - best.y0) : null;
|
|
509
|
+
}
|
|
510
|
+
function edgeTrim(gray, w, h, ink) {
|
|
511
|
+
const isInk = (v) => ink.darkInk ? v <= ink.threshold : v > ink.threshold;
|
|
512
|
+
const colInk = new Uint32Array(w);
|
|
513
|
+
for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) if (isInk(gray[y * w + x])) colInk[x]++;
|
|
514
|
+
const ruleCol = new Uint8Array(w);
|
|
515
|
+
let liveW = 0;
|
|
516
|
+
for (let x = 0; x < w; x++) {
|
|
517
|
+
if (colInk[x] >= h * 0.85) ruleCol[x] = 1;
|
|
518
|
+
else liveW++;
|
|
519
|
+
}
|
|
520
|
+
const blank = Math.max(1, Math.floor(w * 0.02));
|
|
521
|
+
const bands = [];
|
|
522
|
+
let start = -1;
|
|
523
|
+
for (let y = 0; y <= h; y++) {
|
|
524
|
+
let n = 0;
|
|
525
|
+
if (y < h) {
|
|
526
|
+
for (let x = 0; x < w; x++) if (!ruleCol[x] && isInk(gray[y * w + x])) n++;
|
|
527
|
+
}
|
|
528
|
+
const on = y < h && n > blank && n < liveW * 0.85;
|
|
529
|
+
if (on && start < 0) start = y;
|
|
530
|
+
else if (!on && start >= 0) {
|
|
531
|
+
bands.push([start, y]);
|
|
532
|
+
start = -1;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
let y0 = 0, y1 = h;
|
|
536
|
+
if (bands.length >= 2 && h >= 24) {
|
|
537
|
+
const mh = Math.max(...bands.map(([a, b]) => b - a));
|
|
538
|
+
const [top, next] = [bands[0], bands[1]], [bot, prev] = [bands[bands.length - 1], bands[bands.length - 2]];
|
|
539
|
+
if (top[0] <= 1 && top[1] - top[0] < mh * 0.45) y0 = top[1] + next[0] >> 1;
|
|
540
|
+
if (bot[1] >= h - 1 && bot[1] - bot[0] < mh * 0.45) y1 = bot[0] + prev[1] + 1 >> 1;
|
|
541
|
+
if (y0 > 0 || y1 < h) {
|
|
542
|
+
let runs = 0, len = 0;
|
|
543
|
+
for (let x = 0; x <= w; x++) {
|
|
544
|
+
let on = false;
|
|
545
|
+
if (x < w && !ruleCol[x]) for (let y = y0; y < y1 && !on; y++) on = isInk(gray[y * w + x]);
|
|
546
|
+
if (on) len++;
|
|
547
|
+
else {
|
|
548
|
+
if (len >= (y1 - y0) * 0.3) runs++;
|
|
549
|
+
len = 0;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
if (runs < 2) {
|
|
553
|
+
y0 = 0;
|
|
554
|
+
y1 = h;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
const textCol = (x) => {
|
|
559
|
+
for (let y = y0; y < y1; y++) if (isInk(gray[y * w + x])) return true;
|
|
560
|
+
return false;
|
|
561
|
+
};
|
|
562
|
+
const border = (x) => colInk[x] >= h * 0.95;
|
|
563
|
+
const gap = Math.max(2, Math.round(h * 0.1));
|
|
564
|
+
const clearFrom = (x, dir) => {
|
|
565
|
+
for (let k = 0; k < gap; k++) {
|
|
566
|
+
const c = x + dir * k;
|
|
567
|
+
if (c < 0 || c >= w || textCol(c)) return false;
|
|
568
|
+
}
|
|
569
|
+
return true;
|
|
570
|
+
};
|
|
571
|
+
let x0 = 0, x1 = w;
|
|
572
|
+
for (let x = 0; x < w * 0.2; x++) {
|
|
573
|
+
if (border(x)) {
|
|
574
|
+
let e = x;
|
|
575
|
+
while (e + 1 < w && border(e + 1)) e++;
|
|
576
|
+
if (clearFrom(e + 1, 1)) x0 = e + 1;
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
if (textCol(x)) break;
|
|
580
|
+
}
|
|
581
|
+
for (let x = w - 1; x >= w * 0.8; x--) {
|
|
582
|
+
if (border(x)) {
|
|
583
|
+
let e = x;
|
|
584
|
+
while (e - 1 >= 0 && border(e - 1)) e--;
|
|
585
|
+
if (clearFrom(e - 1, -1)) x1 = e;
|
|
586
|
+
break;
|
|
587
|
+
}
|
|
588
|
+
if (textCol(x)) break;
|
|
589
|
+
}
|
|
590
|
+
return y0 > 0 || y1 < h || x0 > 0 || x1 < w ? { x0, x1, y0, y1 } : null;
|
|
591
|
+
}
|
|
592
|
+
function tallInkCount(gray, w, h, ink) {
|
|
593
|
+
const { comps } = components(gray, w, h, ink);
|
|
594
|
+
let charH = 0;
|
|
595
|
+
for (const c of comps) charH = Math.max(charH, c.y1 - c.y0);
|
|
596
|
+
const tall = comps.filter((c) => c.y1 - c.y0 >= charH * 0.5).sort((a, b) => a.x0 - b.x0);
|
|
597
|
+
let n = 0, end = -1;
|
|
598
|
+
for (const c of tall) {
|
|
599
|
+
if (c.x0 >= end) n++;
|
|
600
|
+
end = Math.max(end, c.x1);
|
|
601
|
+
}
|
|
602
|
+
return n;
|
|
603
|
+
}
|
|
604
|
+
function gapGlyphs(gray, w, h, ink) {
|
|
605
|
+
const { comps, label } = components(gray, w, h, ink);
|
|
606
|
+
let charH = 0;
|
|
607
|
+
for (const c of comps) charH = Math.max(charH, c.y1 - c.y0);
|
|
608
|
+
if (charH < 10) return { glyphs: [], bandH: 0 };
|
|
609
|
+
const tall = comps.filter((c) => c.y1 - c.y0 >= charH * 0.6);
|
|
610
|
+
const bandT = Math.min(...tall.map((c) => c.y0)), bandB = Math.max(...tall.map((c) => c.y1)), bh = bandB - bandT;
|
|
611
|
+
const inBand = (c) => c.y1 > bandT && c.y0 < bandB;
|
|
612
|
+
const out = [];
|
|
613
|
+
for (const c of comps) {
|
|
614
|
+
if (!inBand(c)) continue;
|
|
615
|
+
const cw = c.x1 - c.x0, ch = c.y1 - c.y0;
|
|
616
|
+
if (ch >= bh * 0.9 && cw <= bh * 0.15) continue;
|
|
617
|
+
const others = comps.filter((o) => o !== c && inBand(o) && !(o.x0 >= c.x0 && o.x1 <= c.x1 && o.y0 >= c.y0 && o.y1 <= c.y1));
|
|
618
|
+
const apart = !others.some((o) => o.x0 < c.x1 + 1 && o.x1 > c.x0 - 1);
|
|
619
|
+
const abut = !apart && ch >= bh * 0.3 && ch <= bh * 0.65 && !others.some((o) => o.x0 < c.x1 && o.x1 > c.x0);
|
|
620
|
+
const nearlyApart = !others.some((o) => Math.min(o.x1, c.x1) - Math.max(o.x0, c.x0) > 2);
|
|
621
|
+
const spans = [], runs = [];
|
|
622
|
+
let n = 0;
|
|
623
|
+
for (let y = c.y0; y < c.y1; y++) {
|
|
624
|
+
let s = 0, r = 0, prev = false;
|
|
625
|
+
for (let x = c.x0; x < c.x1; x++) {
|
|
626
|
+
const on = label[y * w + x] === c.id;
|
|
627
|
+
if (on) {
|
|
628
|
+
s++;
|
|
629
|
+
if (!prev) r++;
|
|
630
|
+
}
|
|
631
|
+
prev = on;
|
|
632
|
+
}
|
|
633
|
+
spans.push(s);
|
|
634
|
+
runs.push(r);
|
|
635
|
+
n += s;
|
|
636
|
+
}
|
|
637
|
+
const fill = n / (cw * ch), cy = ((c.y0 + c.y1) / 2 - bandT) / bh;
|
|
638
|
+
const band = Math.max(1, Math.round(ch * 0.15));
|
|
639
|
+
const top = Math.max(...spans.slice(0, band)) / cw, bottom = Math.max(...spans.slice(ch - band)) / cw;
|
|
640
|
+
let mark = null;
|
|
641
|
+
const speck = Math.max(3, bh * 0.08);
|
|
642
|
+
const dot = ch <= bh * 0.25 && cw <= bh * 0.25 && ch >= speck && cw >= speck && cw >= ch * 0.6 && cw <= ch * 1.6;
|
|
643
|
+
const small = ch <= bh * 0.25 && cw <= bh * 0.25 && ch >= 2 && cw >= 2 && cw >= ch * 0.6 && cw <= ch * 1.6 && fill >= 0.6 && cy >= 0.3 && cy <= 0.7;
|
|
644
|
+
if (!apart && !abut && !(nearlyApart && ch >= bh * 0.6)) {
|
|
645
|
+
if (small) out.push({ x0: c.x0, x1: c.x1, mark: "\xB7" });
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
648
|
+
const bracket = () => {
|
|
649
|
+
const stem = (from, to) => {
|
|
650
|
+
let sx = 0, k = 0;
|
|
651
|
+
for (let y = from; y < to; y++) for (let x = c.x0; x < c.x1; x++) if (label[y * w + x] === c.id) {
|
|
652
|
+
sx += x - c.x0;
|
|
653
|
+
k++;
|
|
654
|
+
}
|
|
655
|
+
return k ? sx / k / cw : 0.5;
|
|
656
|
+
};
|
|
657
|
+
if (c.y0 <= bandT + bh * 0.15 && top >= 0.7 && bottom <= 0.5 && stem(c.y0 + band, c.y1) <= 0.35) return "\u300C";
|
|
658
|
+
if (c.y1 >= bandB - bh * 0.15 && bottom >= 0.7 && top <= 0.5 && stem(c.y0, c.y1 - band) >= 0.65) return "\u300D";
|
|
659
|
+
return null;
|
|
660
|
+
};
|
|
661
|
+
if (!apart && !abut) {
|
|
662
|
+
} else if (abut) {
|
|
663
|
+
if (fill < 0.5) mark = bracket();
|
|
664
|
+
} else if (dot && fill >= 0.6 && cy >= 0.3 && cy <= 0.7) mark = "\xB7";
|
|
665
|
+
else if (small) mark = "\xB7";
|
|
666
|
+
else if (dot && fill >= 0.6 && cy >= 0.75 && cw >= ch * 0.8) mark = ".";
|
|
667
|
+
else if (ch <= bh * 0.4 && ch >= speck && cw >= ch * 0.75 && cw <= ch * 1.3 && fill < 0.6 && runs[ch >> 1] === 2 && cy >= 0.6) mark = "\u3002";
|
|
668
|
+
else if (ch <= bh * 0.15 && cw >= ch * 2 && cw <= bh * 0.8 && fill >= 0.7 && cy >= 0.35 && cy <= 0.75) mark = "-";
|
|
669
|
+
else if (ch >= bh * 0.5 && cw >= ch * 0.9 && cw <= ch * 1.4 && fill >= 0.4 && runs.every((r) => r <= 1) && top <= 0.4 && bottom >= 0.8) mark = "\u25B2";
|
|
670
|
+
else if (ch >= bh * 0.3 && ch <= bh * 0.65 && fill < 0.5) mark = bracket();
|
|
671
|
+
else if (ch >= charH * 0.6 && cw >= ch * 0.8 && cw <= ch * 1.25 && fill < 0.5 && top >= 0.8 && bottom >= 0.8 && runs[ch >> 1] === 2) mark = ch <= charH * 0.92 ? "\u25A1" : "\u25A1\0";
|
|
672
|
+
if (!mark && ch >= bh * 0.6 && cw >= ch * 0.25 && cw <= ch * 0.7 && fill <= 0.4 && runs.every((r) => r <= 1)) {
|
|
673
|
+
const mx = (y) => {
|
|
674
|
+
let sx = 0, k = 0;
|
|
675
|
+
for (let x = c.x0; x < c.x1; x++) if (label[y * w + x] === c.id) {
|
|
676
|
+
sx += x;
|
|
677
|
+
k++;
|
|
678
|
+
}
|
|
679
|
+
return k ? sx / k : NaN;
|
|
680
|
+
};
|
|
681
|
+
if (mx(c.y0 + band) - mx(c.y1 - 1 - band) >= cw * 0.5) mark = "/";
|
|
682
|
+
}
|
|
683
|
+
if (mark) out.push({ x0: c.x0, x1: c.x1, mark });
|
|
684
|
+
}
|
|
685
|
+
return { glyphs: out, bandH: bh };
|
|
686
|
+
}
|
|
687
|
+
function ringBullet(gray, w, h, ink, cx) {
|
|
688
|
+
const { comps, label } = components(gray, w, h, ink);
|
|
689
|
+
let charH = 0;
|
|
690
|
+
for (const c2 of comps) charH = Math.max(charH, c2.y1 - c2.y0);
|
|
691
|
+
if (charH < 10) return null;
|
|
692
|
+
const tall = comps.filter((c2) => c2.y1 - c2.y0 >= charH * 0.6);
|
|
693
|
+
const bandT = Math.min(...tall.map((c2) => c2.y0)), bh = Math.max(...tall.map((c2) => c2.y1)) - bandT;
|
|
694
|
+
let best = null, bestD = bh * 0.6;
|
|
695
|
+
for (const c2 of comps) {
|
|
696
|
+
const d = Math.abs((c2.x0 + c2.x1) / 2 - cx);
|
|
697
|
+
if (c2.y1 - c2.y0 >= bh * 0.3 && d < bestD) {
|
|
698
|
+
bestD = d;
|
|
699
|
+
best = c2;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
if (!best) return null;
|
|
703
|
+
const c = best, cw = c.x1 - c.x0, ch = c.y1 - c.y0;
|
|
704
|
+
if (cw < ch * 0.85 || cw > ch * 1.2) return null;
|
|
705
|
+
const runs = (xs, at) => {
|
|
706
|
+
let n2 = 0, len = 0, mx2 = 0, mn = Infinity;
|
|
707
|
+
for (const k of [...xs, -1]) {
|
|
708
|
+
if (k >= 0 && at(k)) {
|
|
709
|
+
if (!len) n2++;
|
|
710
|
+
len++;
|
|
711
|
+
mx2 = Math.max(mx2, len);
|
|
712
|
+
} else {
|
|
713
|
+
if (len) mn = Math.min(mn, len);
|
|
714
|
+
len = 0;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
return { n: n2, mx: mx2, mn };
|
|
718
|
+
};
|
|
719
|
+
const my = c.y0 + c.y1 >> 1, mx = c.x0 + c.x1 >> 1;
|
|
720
|
+
const row = runs(Array.from({ length: cw }, (_, k) => c.x0 + k), (x) => label[my * w + x] === c.id);
|
|
721
|
+
const col = runs(Array.from({ length: ch }, (_, k) => c.y0 + k), (y) => label[y * w + mx] === c.id);
|
|
722
|
+
if (row.n !== 2 || col.n !== 2) return null;
|
|
723
|
+
let n = 0;
|
|
724
|
+
for (let y = c.y0; y < c.y1; y++) for (let x = c.x0; x < c.x1; x++) if (label[y * w + x] === c.id) n++;
|
|
725
|
+
const fill = n / (cw * ch), rel = ch / bh;
|
|
726
|
+
if (rel >= 0.62 && (fill <= 0.23 ? row.mx <= cw * 0.1 : fill <= 0.33 && row.mn <= cw * 0.08)) return "\u25CB";
|
|
727
|
+
if (rel <= 0.58 && fill >= 0.24) return "\u3147";
|
|
728
|
+
if (rel >= 0.6 && rel <= 0.8 && fill >= 0.3 && ((c.y0 + c.y1) / 2 - bandT) / bh >= 0.55) return "o";
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
function dashRatio(gray, w, h, ink, cx) {
|
|
732
|
+
const { comps } = components(gray, w, h, ink);
|
|
733
|
+
let charH = 0;
|
|
734
|
+
for (const c of comps) charH = Math.max(charH, c.y1 - c.y0);
|
|
735
|
+
if (charH < 10) return null;
|
|
736
|
+
const tall = comps.filter((c) => c.y1 - c.y0 >= charH * 0.6);
|
|
737
|
+
const bh = Math.max(...tall.map((c) => c.y1)) - Math.min(...tall.map((c) => c.y0));
|
|
738
|
+
const dash = comps.filter((c) => c.y1 - c.y0 <= bh * 0.25 && c.x1 - c.x0 >= (c.y1 - c.y0) * 2 && Math.abs((c.x0 + c.x1) / 2 - cx) <= bh * 0.6).sort((a, b) => Math.abs((a.x0 + a.x1) / 2 - cx) - Math.abs((b.x0 + b.x1) / 2 - cx))[0];
|
|
739
|
+
return dash ? (dash.x1 - dash.x0) / bh : null;
|
|
740
|
+
}
|
|
741
|
+
function discAt(gray, w, h, ink, cx) {
|
|
742
|
+
const { comps, label } = components(gray, w, h, ink);
|
|
743
|
+
let charH = 0;
|
|
744
|
+
for (const c2 of comps) charH = Math.max(charH, c2.y1 - c2.y0);
|
|
745
|
+
if (charH < 10) return false;
|
|
746
|
+
const tall = comps.filter((c2) => c2.y1 - c2.y0 >= charH * 0.6);
|
|
747
|
+
const bh = Math.max(...tall.map((c2) => c2.y1)) - Math.min(...tall.map((c2) => c2.y0));
|
|
748
|
+
const c = comps.filter((o) => Math.abs((o.x0 + o.x1) / 2 - cx) <= bh * 0.4).sort((a, b) => Math.abs((a.x0 + a.x1) / 2 - cx) - Math.abs((b.x0 + b.x1) / 2 - cx))[0];
|
|
749
|
+
if (!c) return false;
|
|
750
|
+
const cw = c.x1 - c.x0, ch = c.y1 - c.y0;
|
|
751
|
+
if (ch < bh * 0.45 || ch > bh * 1.05 || cw < ch * 0.8 || cw > ch * 1.25) return false;
|
|
752
|
+
let n = 0;
|
|
753
|
+
for (let y = c.y0; y < c.y1; y++) for (let x = c.x0; x < c.x1; x++) if (label[y * w + x] === c.id) n++;
|
|
754
|
+
const fill = n / (cw * ch);
|
|
755
|
+
return fill >= 0.65 && fill <= 0.9;
|
|
756
|
+
}
|
|
757
|
+
function serifOne(gray, w, h, ink, cx) {
|
|
758
|
+
const { comps, label } = components(gray, w, h, ink);
|
|
759
|
+
let charH = 0;
|
|
760
|
+
for (const c2 of comps) charH = Math.max(charH, c2.y1 - c2.y0);
|
|
761
|
+
if (charH < 10) return false;
|
|
762
|
+
const c = comps.filter((o) => o.x0 - 3 <= cx && o.x1 + 3 >= cx && o.y1 - o.y0 >= charH * 0.6).sort((a, b) => b.y1 - b.y0 - (a.y1 - a.y0))[0];
|
|
763
|
+
if (!c) return false;
|
|
764
|
+
const ch = c.y1 - c.y0;
|
|
765
|
+
const span2 = (a, b) => {
|
|
766
|
+
let mn = Infinity, mx = -1;
|
|
767
|
+
for (let y = c.y0 + Math.floor(ch * a); y < c.y0 + Math.ceil(ch * b); y++) for (let x = c.x0; x < c.x1; x++) if (label[y * w + x] === c.id) {
|
|
768
|
+
mn = Math.min(mn, x);
|
|
769
|
+
mx = Math.max(mx, x);
|
|
770
|
+
}
|
|
771
|
+
return [mn, mx];
|
|
772
|
+
};
|
|
773
|
+
const [m0, m1] = span2(0.4, 0.6), [t0, t1] = span2(0, 0.2), [b0, b1] = span2(0.8, 1);
|
|
774
|
+
const sw = m1 - m0 + 1;
|
|
775
|
+
const even = (l, r) => l >= sw * 0.4 && r >= sw * 0.4 && Math.abs(l - r) <= Math.max(l, r) * 0.35;
|
|
776
|
+
return sw >= 2 && sw <= ch * 0.3 && even(m0 - t0, t1 - m1) && even(m0 - b0, b1 - m1);
|
|
777
|
+
}
|
|
778
|
+
function starRun(gray, w, h, ink, cx) {
|
|
779
|
+
const { comps, label } = components(gray, w, h, ink);
|
|
780
|
+
let charH = 0;
|
|
781
|
+
for (const c of comps) charH = Math.max(charH, c.y1 - c.y0);
|
|
782
|
+
if (charH < 10) return 0;
|
|
783
|
+
const tall = comps.filter((c) => c.y1 - c.y0 >= charH * 0.6);
|
|
784
|
+
const bandT = Math.min(...tall.map((c) => c.y0)), bh = Math.max(...tall.map((c) => c.y1)) - bandT;
|
|
785
|
+
const star = (c) => {
|
|
786
|
+
const cw = c.x1 - c.x0, ch = c.y1 - c.y0;
|
|
787
|
+
if (ch < bh * 0.2 || ch > bh * 0.5 || cw < ch * 0.7 || cw > ch * 1.4 || ((c.y0 + c.y1) / 2 - bandT) / bh > 0.55) return false;
|
|
788
|
+
let n = 0;
|
|
789
|
+
for (let y = c.y0; y < c.y1; y++) for (let x = c.x0; x < c.x1; x++) if (label[y * w + x] === c.id) n++;
|
|
790
|
+
const fill = n / (cw * ch);
|
|
791
|
+
return fill >= 0.25 && fill <= 0.65;
|
|
792
|
+
};
|
|
793
|
+
const stars = comps.filter(star).sort((a, b) => a.x0 - b.x0);
|
|
794
|
+
const k = stars.findIndex((c) => cx >= c.x0 - (c.x1 - c.x0) && cx <= c.x1 + (c.x1 - c.x0));
|
|
795
|
+
if (k < 0) return 0;
|
|
796
|
+
let lo = k, hi = k;
|
|
797
|
+
while (lo > 0 && stars[lo].x0 - stars[lo - 1].x1 <= stars[lo].x1 - stars[lo].x0) lo--;
|
|
798
|
+
while (hi + 1 < stars.length && stars[hi + 1].x0 - stars[hi].x1 <= stars[hi].x1 - stars[hi].x0) hi++;
|
|
799
|
+
return hi - lo + 1;
|
|
800
|
+
}
|
|
801
|
+
var BRACKET_TAPER = 0.16;
|
|
802
|
+
var BRACKET_SOLID = 0.4;
|
|
803
|
+
var BRACKET_WIDE = 0.265;
|
|
804
|
+
var BRACKET_LENS = 0.35;
|
|
805
|
+
function bracketShape(f, close) {
|
|
806
|
+
const [near2, far] = close ? [f.bottom, f.top] : [f.top, f.bottom];
|
|
807
|
+
const paren = close ? ")" : "(";
|
|
808
|
+
if (near2 >= 0.7 && far <= 0.5) return f.taper < BRACKET_TAPER ? close ? "\u300D" : "\u300C" : paren;
|
|
809
|
+
if (near2 >= 0.7 && far >= 0.7 && f.taper >= BRACKET_TAPER) {
|
|
810
|
+
return f.fill >= BRACKET_SOLID && (f.cw >= f.ch * BRACKET_WIDE || f.taper >= BRACKET_LENS) ? close ? "\u3011" : "\u3010" : paren;
|
|
811
|
+
}
|
|
812
|
+
return null;
|
|
813
|
+
}
|
|
814
|
+
function leadingBullet(gray, w, h, ink, firstX) {
|
|
815
|
+
const { comps, label } = components(gray, w, h, ink);
|
|
816
|
+
let charH = 0;
|
|
817
|
+
for (const c of comps) charH = Math.max(charH, c.y1 - c.y0);
|
|
818
|
+
if (charH < 10) return null;
|
|
819
|
+
const cand = comps.filter((c) => c.y1 - c.y0 >= charH * 0.15).sort((a, b) => a.x0 - b.x0);
|
|
820
|
+
const first = cand[0];
|
|
821
|
+
if (!first) return null;
|
|
822
|
+
const cl = cand.filter((c) => c.x0 < first.x1 && c.x1 > first.x0);
|
|
823
|
+
const x0 = Math.min(...cl.map((c) => c.x0)), x1 = Math.max(...cl.map((c) => c.x1)), y0 = Math.min(...cl.map((c) => c.y0)), y1 = Math.max(...cl.map((c) => c.y1));
|
|
824
|
+
const cw = x1 - x0, ch = y1 - y0;
|
|
825
|
+
if (cw < ch * 0.8 || cw > ch * 1.25) return null;
|
|
826
|
+
const next = cand.find((c) => c.x0 >= x1);
|
|
827
|
+
if (next && next.x0 - x1 < ch * 0.3) return null;
|
|
828
|
+
let inkN = 0;
|
|
829
|
+
for (let y = y0; y < y1; y++) for (let x = x0; x < x1; x++) if (cl.some((c) => label[y * w + x] === c.id)) inkN++;
|
|
830
|
+
const fill = inkN / (cw * ch);
|
|
831
|
+
const rel = ch / charH;
|
|
832
|
+
const ring = (c) => {
|
|
833
|
+
const a = c.x1 - c.x0, b = c.y1 - c.y0;
|
|
834
|
+
return a >= b * 0.75 && a <= b * 1.33;
|
|
835
|
+
};
|
|
836
|
+
const nested = cl.length >= 2 && cl.some((a) => cl.some((b) => a !== b && b.x0 > a.x0 && b.x1 < a.x1 && b.y0 > a.y0 && b.y1 < a.y1 && ring(b) && Math.abs(b.x0 + b.x1 - (a.x0 + a.x1)) <= (a.x1 - a.x0) * 0.2 && Math.abs(b.y0 + b.y1 - (a.y0 + a.y1)) <= (a.y1 - a.y0) * 0.2));
|
|
837
|
+
const span2 = (y) => {
|
|
838
|
+
let n = 0;
|
|
839
|
+
for (let x = x0; x < x1; x++) if (cl.some((c) => label[y * w + x] === c.id)) n++;
|
|
840
|
+
return n;
|
|
841
|
+
};
|
|
842
|
+
const band = Math.max(1, Math.round(ch * 0.15));
|
|
843
|
+
const edgeFull = (from, dir) => {
|
|
844
|
+
let m = 0;
|
|
845
|
+
for (let k = 0; k < band; k++) m = Math.max(m, span2(from + dir * k));
|
|
846
|
+
return m >= cw * 0.8;
|
|
847
|
+
};
|
|
848
|
+
let midRuns = 0;
|
|
849
|
+
{
|
|
850
|
+
let prev = false;
|
|
851
|
+
const my = y0 + (ch >> 1);
|
|
852
|
+
for (let x = x0; x < x1; x++) {
|
|
853
|
+
const on = cl.some((c) => label[my * w + x] === c.id);
|
|
854
|
+
if (on && !prev) midRuns++;
|
|
855
|
+
prev = on;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
const hollowSquare = cl.length === 1 && fill < 0.5 && midRuns === 2 && edgeFull(y0, 1) && edgeFull(y1 - 1, -1);
|
|
859
|
+
let mark = null;
|
|
860
|
+
if (hollowSquare && rel >= 0.6 && rel <= 0.92) mark = "\u25A1";
|
|
861
|
+
else if (nested && fill < 0.45 && rel >= 0.6) mark = "\u25CE";
|
|
862
|
+
else if (cl.length === 1 && fill >= 0.9 && rel >= 0.28 && rel <= 0.6) mark = "\u25AA";
|
|
863
|
+
else if (cl.length === 1 && fill >= 0.65 && fill <= 0.88 && rel >= 0.5 && rel <= 0.8) mark = "\u25CF";
|
|
864
|
+
if (!mark) return null;
|
|
865
|
+
return { mark, covers: firstX <= x1 + ch * 0.3 };
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// src/ocr/text-gaps.ts
|
|
869
|
+
var evidence = /* @__PURE__ */ new WeakMap();
|
|
870
|
+
var NO_GAPS = [];
|
|
871
|
+
function rememberOcrTextGaps(item, gaps) {
|
|
872
|
+
if (gaps.length) evidence.set(item, { text: item.text, gaps });
|
|
873
|
+
}
|
|
874
|
+
function ocrTextGaps(item) {
|
|
875
|
+
const saved = evidence.get(item);
|
|
876
|
+
return _optionalChain([saved, 'optionalAccess', _11 => _11.text]) === item.text ? saved.gaps : NO_GAPS;
|
|
877
|
+
}
|
|
878
|
+
function copyOcrTextGaps(source, target, scale = 1, offsetX = 0) {
|
|
879
|
+
const gaps = ocrTextGaps(source);
|
|
880
|
+
if (!gaps.length || source.text !== target.text) return;
|
|
881
|
+
rememberOcrTextGaps(target, scale === 1 && offsetX === 0 ? gaps : gaps.map((g) => ({ ...g, left: g.left * scale + offsetX, right: g.right * scale + offsetX })));
|
|
882
|
+
}
|
|
883
|
+
function findOcrTextGaps(rgba, pageW, box, read, text, steps, stepPx) {
|
|
884
|
+
if (read.replace(/\s/g, "") !== text.replace(/\s/g, "") || [...read].length !== steps.length) return [];
|
|
885
|
+
const visible = [...read].flatMap((c, i) => /\s/.test(c) ? [] : [(steps[i] + 0.5) * stepPx]);
|
|
886
|
+
if (visible.length < 2) return [];
|
|
887
|
+
const gray = grayCrop(rgba, pageW, box), ink = inkStats(gray);
|
|
888
|
+
if (!ink.darkInk || ink.contrast < 35) return [];
|
|
889
|
+
const counts = new Uint32Array(box.w);
|
|
890
|
+
for (let y = 0; y < box.h; y++) for (let x = 0; x < box.w; x++) if (gray[y * box.w + x] <= ink.threshold) counts[x]++;
|
|
891
|
+
const out = [];
|
|
892
|
+
let offset = 0, index = 0;
|
|
893
|
+
for (const c of text) {
|
|
894
|
+
if (!/\s/.test(c)) {
|
|
895
|
+
if (index > 0) {
|
|
896
|
+
const from = Math.max(0, Math.floor(visible[index - 1]) + 1), end = Math.min(box.w, Math.ceil(visible[index]));
|
|
897
|
+
let start = from, left = from, right = from;
|
|
898
|
+
for (let x = from; x <= end; x++) {
|
|
899
|
+
if (x === end || counts[x] > Math.max(1, Math.floor(box.h * 0.03))) {
|
|
900
|
+
if (x - start > right - left) {
|
|
901
|
+
left = start;
|
|
902
|
+
right = x;
|
|
903
|
+
}
|
|
904
|
+
start = x + 1;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
if (right - left >= Math.max(3, box.h * 0.25)) out.push({ at: offset, left: box.x + left, right: box.x + right });
|
|
908
|
+
}
|
|
909
|
+
index++;
|
|
910
|
+
}
|
|
911
|
+
offset += c.length;
|
|
912
|
+
}
|
|
913
|
+
return out;
|
|
914
|
+
}
|
|
915
|
+
|
|
149
916
|
// src/pdf/line-extract.ts
|
|
150
917
|
var _pdfmjs = require('pdfjs-dist/legacy/build/pdf.mjs');
|
|
151
918
|
var ORIENTATION_TOL = 2;
|
|
@@ -369,7 +1136,7 @@ function extractLines(fnArray, argsArray) {
|
|
|
369
1136
|
} else {
|
|
370
1137
|
const afterOp = arg0;
|
|
371
1138
|
const dataArr = args[1];
|
|
372
|
-
const pathData = _optionalChain([dataArr, 'optionalAccess',
|
|
1139
|
+
const pathData = _optionalChain([dataArr, 'optionalAccess', _12 => _12[0]]);
|
|
373
1140
|
if (pathData && typeof pathData === "object") {
|
|
374
1141
|
const len = Object.keys(pathData).length;
|
|
375
1142
|
let di = 0;
|
|
@@ -747,7 +1514,7 @@ function mergeParallelLines(lines, dir, nonRules) {
|
|
|
747
1514
|
const overlap2 = Math.min(prevEnd, currEnd) - Math.max(prevStart, currStart);
|
|
748
1515
|
const minLen = Math.min(prevEnd - prevStart, currEnd - currStart);
|
|
749
1516
|
if (overlap2 > minLen * 0.3) {
|
|
750
|
-
if (_optionalChain([nonRules, 'optionalAccess',
|
|
1517
|
+
if (_optionalChain([nonRules, 'optionalAccess', _13 => _13.has, 'call', _14 => _14(prev)]) && !nonRules.has(curr)) nonRules.delete(prev);
|
|
751
1518
|
if (dir === "h") {
|
|
752
1519
|
prev.x1 = Math.min(prev.x1, curr.x1);
|
|
753
1520
|
prev.x2 = Math.max(prev.x2, curr.x2);
|
|
@@ -815,8 +1582,8 @@ function extractImageRegions(fnArray, argsArray, respectClip = false) {
|
|
|
815
1582
|
break;
|
|
816
1583
|
case _pdfmjs.OPS.restore: {
|
|
817
1584
|
const state = stack.pop();
|
|
818
|
-
ctm = _nullishCoalesce(_optionalChain([state, 'optionalAccess',
|
|
819
|
-
clip = _nullishCoalesce(_optionalChain([state, 'optionalAccess',
|
|
1585
|
+
ctm = _nullishCoalesce(_optionalChain([state, 'optionalAccess', _15 => _15.ctm]), () => ( [1, 0, 0, 1, 0, 0]));
|
|
1586
|
+
clip = _nullishCoalesce(_optionalChain([state, 'optionalAccess', _16 => _16.clip]), () => ( null));
|
|
820
1587
|
break;
|
|
821
1588
|
}
|
|
822
1589
|
case _pdfmjs.OPS.transform: {
|
|
@@ -827,19 +1594,19 @@ function extractImageRegions(fnArray, argsArray, respectClip = false) {
|
|
|
827
1594
|
// Form XObject 는 /Matrix 공간에서 그린다 — pdfjs 인자 [matrix, bbox], End 에서 복원 (line-extract.ts 와 같음)
|
|
828
1595
|
case _pdfmjs.OPS.paintFormXObjectBegin: {
|
|
829
1596
|
stack.push({ ctm, clip });
|
|
830
|
-
const m = _optionalChain([argsArray, 'access',
|
|
1597
|
+
const m = _optionalChain([argsArray, 'access', _17 => _17[i], 'optionalAccess', _18 => _18[0]]);
|
|
831
1598
|
if (Array.isArray(m) && m.length >= 6) ctm = multiplyTransform(ctm, m);
|
|
832
1599
|
break;
|
|
833
1600
|
}
|
|
834
1601
|
case _pdfmjs.OPS.paintFormXObjectEnd: {
|
|
835
1602
|
const state = stack.pop();
|
|
836
|
-
ctm = _nullishCoalesce(_optionalChain([state, 'optionalAccess',
|
|
837
|
-
clip = _nullishCoalesce(_optionalChain([state, 'optionalAccess',
|
|
1603
|
+
ctm = _nullishCoalesce(_optionalChain([state, 'optionalAccess', _19 => _19.ctm]), () => ( [1, 0, 0, 1, 0, 0]));
|
|
1604
|
+
clip = _nullishCoalesce(_optionalChain([state, 'optionalAccess', _20 => _20.clip]), () => ( null));
|
|
838
1605
|
break;
|
|
839
1606
|
}
|
|
840
1607
|
case _pdfmjs.OPS.constructPath: {
|
|
841
1608
|
const [ops, coords] = argsArray[i];
|
|
842
|
-
pathRect = pathRect === void 0 && _optionalChain([ops, 'optionalAccess',
|
|
1609
|
+
pathRect = pathRect === void 0 && _optionalChain([ops, 'optionalAccess', _21 => _21.length]) === 1 && ops[0] === _pdfmjs.OPS.rectangle && _optionalChain([coords, 'optionalAccess', _22 => _22.length]) >= 4 ? transformedRect(ctm, coords[0], coords[1], coords[2], coords[3]) : null;
|
|
843
1610
|
break;
|
|
844
1611
|
}
|
|
845
1612
|
case _pdfmjs.OPS.clip:
|
|
@@ -992,7 +1759,7 @@ function hasShadedRowBands(host, clips, fills, verticals, horizontals) {
|
|
|
992
1759
|
if (!host.colXs.slice(1, -1).every((x) => verticals.some((v) => !v.fromFill && near2(v.x1, x) && v.y1 <= host.bbox.y1 + tol && v.y2 >= host.bbox.y2 - tol))) return false;
|
|
993
1760
|
const covered = /* @__PURE__ */ new Set();
|
|
994
1761
|
for (const band of bands) {
|
|
995
|
-
if (band.clipParent || !_optionalChain([band, 'access',
|
|
1762
|
+
if (band.clipParent || !_optionalChain([band, 'access', _23 => _23.cells, 'optionalAccess', _24 => _24.length]) || band.colXs.length !== host.colXs.length || !band.colXs.every((x, i) => near2(x, host.colXs[i]))) return false;
|
|
996
1763
|
const start = host.rowYs.findIndex((y) => near2(y, band.rowYs[0]));
|
|
997
1764
|
if (start < 0 || !band.rowYs.every((y, i) => near2(y, host.rowYs[start + i]))) return false;
|
|
998
1765
|
if (!band.rowYs.every((y) => horizontals.some((h) => !h.fromFill && near2(h.y1, y) && h.x1 <= host.bbox.x1 + tol && h.x2 >= host.bbox.x2 - tol))) return false;
|
|
@@ -1094,7 +1861,7 @@ function mergeVertices(vertices) {
|
|
|
1094
1861
|
const candidates = [];
|
|
1095
1862
|
for (let dx = -1; dx <= 1; dx++) {
|
|
1096
1863
|
for (let dy = -1; dy <= 1; dy++) {
|
|
1097
|
-
const arr = _optionalChain([buckets, 'access',
|
|
1864
|
+
const arr = _optionalChain([buckets, 'access', _25 => _25.get, 'call', _26 => _26(cx + dx), 'optionalAccess', _27 => _27.get, 'call', _28 => _28(cy + dy)]);
|
|
1098
1865
|
if (!arr) continue;
|
|
1099
1866
|
for (const j of arr) {
|
|
1100
1867
|
if (j > i && !used[j]) candidates.push(j);
|
|
@@ -1221,7 +1988,7 @@ function dropShadingClipGrids(clipGrids, lineGrids, fillRects, verticals = [], h
|
|
|
1221
1988
|
const area = (b) => Math.max(0, b.x2 - b.x1) * Math.max(0, b.y2 - b.y1);
|
|
1222
1989
|
const inter = (a, b) => area({ x1: Math.max(a.x1, b.x1), y1: Math.max(a.y1, b.y1), x2: Math.min(a.x2, b.x2), y2: Math.min(a.y2, b.y2) });
|
|
1223
1990
|
return clipGrids.filter((c) => {
|
|
1224
|
-
if (!_optionalChain([c, 'access',
|
|
1991
|
+
if (!_optionalChain([c, 'access', _29 => _29.cells, 'optionalAccess', _30 => _30.length]) || c.clipParent) return true;
|
|
1225
1992
|
const sourceCells = c.cells.filter((cell) => !cell.filler);
|
|
1226
1993
|
if (sourceCells.length === 0) return true;
|
|
1227
1994
|
const shaded = sourceCells.every((cell) => fillRects.some((f) => near2(f.x1, cell.bbox.x1) && near2(f.x2, cell.bbox.x2) && near2(f.y1, cell.bbox.y1) && near2(f.y2, cell.bbox.y2)));
|
|
@@ -1231,7 +1998,7 @@ function dropShadingClipGrids(clipGrids, lineGrids, fillRects, verticals = [], h
|
|
|
1231
1998
|
const host = lineGrids.find((l) => (
|
|
1232
1999
|
// Inferred filler cells carry no boundary evidence. Replace their frame only
|
|
1233
2000
|
// with a finer ruled grid of the same extent, never a larger surrounding form.
|
|
1234
|
-
(!c.cells.some((cell) => cell.filler) || near2(c.bbox.x1, l.bbox.x1) && near2(c.bbox.x2, l.bbox.x2) && near2(c.bbox.y1, l.bbox.y1) && near2(c.bbox.y2, l.bbox.y2) && l.rowYs.length > c.rowYs.length && sourceCells.every((cell) => [cell.bbox.y1, cell.bbox.y2].every((y) => l.rowYs.some((ly) => near2(y, ly))))) && c.bbox.x1 >= l.bbox.x1 - SHADE_CLIP_TOL && c.bbox.x2 <= l.bbox.x2 + SHADE_CLIP_TOL && c.bbox.y1 >= l.bbox.y1 - SHADE_CLIP_TOL && c.bbox.y2 <= l.bbox.y2 + SHADE_CLIP_TOL && c.colXs.every((x) => l.colXs.some((lx) => near2(lx, x))) && (clipGrids.reduce((s, o) => s + (_optionalChain([o, 'access',
|
|
2001
|
+
(!c.cells.some((cell) => cell.filler) || near2(c.bbox.x1, l.bbox.x1) && near2(c.bbox.x2, l.bbox.x2) && near2(c.bbox.y1, l.bbox.y1) && near2(c.bbox.y2, l.bbox.y2) && l.rowYs.length > c.rowYs.length && sourceCells.every((cell) => [cell.bbox.y1, cell.bbox.y2].every((y) => l.rowYs.some((ly) => near2(y, ly))))) && c.bbox.x1 >= l.bbox.x1 - SHADE_CLIP_TOL && c.bbox.x2 <= l.bbox.x2 + SHADE_CLIP_TOL && c.bbox.y1 >= l.bbox.y1 - SHADE_CLIP_TOL && c.bbox.y2 <= l.bbox.y2 + SHADE_CLIP_TOL && c.colXs.every((x) => l.colXs.some((lx) => near2(lx, x))) && (clipGrids.reduce((s, o) => s + (_optionalChain([o, 'access', _31 => _31.cells, 'optionalAccess', _32 => _32.some, 'call', _33 => _33((cell) => cell.filler)]) ? o.cells.filter((cell) => !cell.filler).reduce((a, cell) => a + inter(cell.bbox, l.bbox), 0) : inter(o.bbox, l.bbox)), 0) <= area(l.bbox) * SHADE_CLIP_MAX_AREA || l.rowYs.length === c.rowYs.length + 1 && c.rowYs.every((y, i) => near2(y, l.rowYs[i])) && l.colXs.length === c.colXs.length && c.colXs.every((x, i) => near2(x, l.colXs[i])) && !clipGrids.some((o) => o !== c && inter(o.bbox, l.bbox) > 0) || hasShadedRowBands(l, clipGrids, fillRects, verticals, horizontals))
|
|
1235
2002
|
));
|
|
1236
2003
|
return !host;
|
|
1237
2004
|
});
|
|
@@ -1246,7 +2013,17 @@ function dropHeadBandClipGrids(clipGrids, lineGrids) {
|
|
|
1246
2013
|
if (clipGrids.length === 0 || lineGrids.length === 0) return clipGrids;
|
|
1247
2014
|
const near2 = (a, b) => Math.abs(a - b) <= SHADE_CLIP_TOL;
|
|
1248
2015
|
const overlaps = (a, b) => Math.min(a.x2, b.x2) > Math.max(a.x1, b.x1) && Math.min(a.y2, b.y2) > Math.max(a.y1, b.y1);
|
|
1249
|
-
|
|
2016
|
+
const kept = clipGrids.filter((c) => c.clipParent || !_optionalChain([c, 'access', _34 => _34.cells, 'optionalAccess', _35 => _35.length]) || !lineGrids.some((l) => l.rowYs.length > c.rowYs.length && l.colXs.length === c.colXs.length && c.colXs.every((x, k) => near2(x, l.colXs[k])) && c.rowYs.every((y, k) => near2(y, l.rowYs[k])) && !clipGrids.some((o) => o !== c && overlaps(o.bbox, l.bbox))));
|
|
2017
|
+
return kept.filter((c) => !lineGrids.some((l) => headBandTiles(kept, l, near2, overlaps).includes(c)));
|
|
2018
|
+
}
|
|
2019
|
+
function headBandTiles(clips, l, near2, overlaps) {
|
|
2020
|
+
const onRow = (y) => l.rowYs.some((r) => near2(r, y));
|
|
2021
|
+
const band = clips.filter((c) => !c.clipParent && _optionalChain([c, 'access', _36 => _36.cells, 'optionalAccess', _37 => _37.length]) && near2(c.bbox.y2, l.bbox.y2) && c.bbox.y1 > l.bbox.y1 + SHADE_CLIP_TOL && c.bbox.x1 >= l.bbox.x1 - SHADE_CLIP_TOL && c.bbox.x2 <= l.bbox.x2 + SHADE_CLIP_TOL && c.rowYs.every(onRow)).sort((a, b) => a.bbox.x1 - b.bbox.x1);
|
|
2022
|
+
if (band.length < 2 || !near2(band[0].bbox.x1, l.bbox.x1) || !near2(band[band.length - 1].bbox.x2, l.bbox.x2)) return [];
|
|
2023
|
+
if (band.some((c, k) => k > 0 && c.bbox.x1 > band[k - 1].bbox.x2 + SHADE_CLIP_TOL)) return [];
|
|
2024
|
+
const bottom = Math.min(...band.map((c) => c.bbox.y1));
|
|
2025
|
+
const body = { ...l.bbox, y2: bottom };
|
|
2026
|
+
return clips.some((o) => !band.includes(o) && overlaps(o.bbox, body)) ? [] : band;
|
|
1250
2027
|
}
|
|
1251
2028
|
function enforceMinWidth(colXs, minWidth, narrowRuns = true) {
|
|
1252
2029
|
if (colXs.length <= 2) return colXs;
|
|
@@ -1597,7 +2374,7 @@ function buildClipCellGrids(rects, strokedH, strokedV, pageWidth, pageHeight, te
|
|
|
1597
2374
|
for (let dx = -1; dx <= 1 && !duplicate; dx++) {
|
|
1598
2375
|
const ys2 = buckets.get(bx + dx);
|
|
1599
2376
|
for (let dy = -1; dy <= 1 && !duplicate; dy++) {
|
|
1600
|
-
duplicate = _nullishCoalesce(_optionalChain([ys2, 'optionalAccess',
|
|
2377
|
+
duplicate = _nullishCoalesce(_optionalChain([ys2, 'optionalAccess', _38 => _38.get, 'call', _39 => _39(by + dy), 'optionalAccess', _40 => _40.some, 'call', _41 => _41((c) => sameRect(c, r))]), () => ( false));
|
|
1601
2378
|
}
|
|
1602
2379
|
}
|
|
1603
2380
|
if (duplicate) continue;
|
|
@@ -1745,7 +2522,7 @@ function buildClipCellGrids(rects, strokedH, strokedV, pageWidth, pageHeight, te
|
|
|
1745
2522
|
else groups.set(r, [i]);
|
|
1746
2523
|
}
|
|
1747
2524
|
const containers = cells.filter((_, i) => isContainer[i]);
|
|
1748
|
-
const groupSize = (i) => _nullishCoalesce(_optionalChain([groups, 'access',
|
|
2525
|
+
const groupSize = (i) => _nullishCoalesce(_optionalChain([groups, 'access', _42 => _42.get, 'call', _43 => _43(find(i)), 'optionalAccess', _44 => _44.length]), () => ( 0));
|
|
1749
2526
|
const isGridMember = (i) => groupSize(i) >= CLIP_MIN_GROUP;
|
|
1750
2527
|
const framed = (r) => edgeStroked(strokedH, "h", r.y1, r.x1, r.x2) && edgeStroked(strokedH, "h", r.y2, r.x1, r.x2) && edgeStroked(strokedV, "v", r.x1, r.y1, r.y2) && edgeStroked(strokedV, "v", r.x2, r.y1, r.y2);
|
|
1751
2528
|
const titledFrame = (r) => r.y1 >= pageHeight * TITLED_FRAME_MIN_TOP && r.x2 - r.x1 >= pageWidth * TITLED_FRAME_MIN_WIDTH && textPoints.some((p) => p.y < r.y1 && p.y > pageHeight * HEADER_BAND && p.x >= r.x1 - CLIP_EDGE_TOL && p.x <= r.x2 + CLIP_EDGE_TOL) && textPoints.some((p) => p.x > r.x1 && p.x < r.x2 && p.y > r.y1 && p.y < r.y2);
|
|
@@ -2126,8 +2903,8 @@ function childRules(r, grid) {
|
|
|
2126
2903
|
}
|
|
2127
2904
|
function recordClipCellEdges(grids, horizontals, verticals, nonRules) {
|
|
2128
2905
|
if (!grids.some((g) => g.cells)) return;
|
|
2129
|
-
const h = rules(_optionalChain([nonRules, 'optionalAccess',
|
|
2130
|
-
const v = rules(_optionalChain([nonRules, 'optionalAccess',
|
|
2906
|
+
const h = rules(_optionalChain([nonRules, 'optionalAccess', _45 => _45.size]) ? horizontals.filter((l) => !nonRules.has(l)) : horizontals, "h");
|
|
2907
|
+
const v = rules(_optionalChain([nonRules, 'optionalAccess', _46 => _46.size]) ? verticals.filter((l) => !nonRules.has(l)) : verticals, "v");
|
|
2131
2908
|
for (const g of grids) {
|
|
2132
2909
|
if (!g.cells) continue;
|
|
2133
2910
|
const ownH = childRules(h, g), ownV = childRules(v, g);
|
|
@@ -2143,9 +2920,9 @@ function recordOpenEndCellEdges(grid, cells, horizontals) {
|
|
|
2143
2920
|
const end = horizontals.find((l) => OPEN_END_RULES.has(l) && Math.abs(l.y1 - b.y1) <= EDGE_NEAR2 && Math.abs(l.x1 - b.x1) <= EDGE_NEAR2 && Math.abs(l.x2 - b.x2) <= EDGE_NEAR2);
|
|
2144
2921
|
const raw = end && OPEN_END_RULES.get(end);
|
|
2145
2922
|
if (!raw) return;
|
|
2146
|
-
const hs = raw.horizontals.filter((l) => !_optionalChain([raw, 'access',
|
|
2923
|
+
const hs = raw.horizontals.filter((l) => !_optionalChain([raw, 'access', _47 => _47.nonRules, 'optionalAccess', _48 => _48.has, 'call', _49 => _49(l)]));
|
|
2147
2924
|
if (hs.some((l) => Math.abs(l.y1 - b.y1) <= EDGE_NEAR2 && Math.min(l.x2, b.x2) - Math.max(l.x1, b.x1) > TIP_MAX)) return;
|
|
2148
|
-
const h = rules(hs, "h"), v = rules(raw.verticals.filter((l) => !_optionalChain([raw, 'access',
|
|
2925
|
+
const h = rules(hs, "h"), v = rules(raw.verticals.filter((l) => !_optionalChain([raw, 'access', _50 => _50.nonRules, 'optionalAccess', _51 => _51.has, 'call', _52 => _52(l)])), "v");
|
|
2149
2926
|
const edges = cells.map((c) => edgesOf(c.bbox, h, v));
|
|
2150
2927
|
const last = grid.rowYs.length - 2;
|
|
2151
2928
|
if (!cells.every((c, i) => {
|
|
@@ -2156,16 +2933,16 @@ function recordOpenEndCellEdges(grid, cells, horizontals) {
|
|
|
2156
2933
|
}
|
|
2157
2934
|
function takeClipCellEdges(from, to) {
|
|
2158
2935
|
const e = CLIP_CELL_EDGES.get(from);
|
|
2159
|
-
if (e)
|
|
2936
|
+
if (e) _chunkNW2CKOFLcjs.CELL_EDGES.set(to, e);
|
|
2160
2937
|
}
|
|
2161
2938
|
function hasOpenCellSeam(a, b) {
|
|
2162
|
-
const u =
|
|
2939
|
+
const u = _chunkNW2CKOFLcjs.CELL_EDGES.get(a), d = _chunkNW2CKOFLcjs.CELL_EDGES.get(b);
|
|
2163
2940
|
return !!u && !!d && u.t && !u.b && !d.t && d.b && u.l && u.r && d.l && d.r;
|
|
2164
2941
|
}
|
|
2165
2942
|
function joinCellEdges(a, b) {
|
|
2166
|
-
const u =
|
|
2943
|
+
const u = _chunkNW2CKOFLcjs.CELL_EDGES.get(a), d = _chunkNW2CKOFLcjs.CELL_EDGES.get(b);
|
|
2167
2944
|
if (!u || !d) return;
|
|
2168
|
-
|
|
2945
|
+
_chunkNW2CKOFLcjs.CELL_EDGES.set(a, { t: u.t, b: d.b, l: u.l || d.l, r: u.r || d.r });
|
|
2169
2946
|
}
|
|
2170
2947
|
|
|
2171
2948
|
// src/pdf/cell-extract.ts
|
|
@@ -2341,7 +3118,7 @@ function tagScripts(text, lines) {
|
|
|
2341
3118
|
const [s, e, kind] = marks[m];
|
|
2342
3119
|
out = out.slice(0, s) + `<${kind}>` + out.slice(s, e) + `</${kind}>` + out.slice(e);
|
|
2343
3120
|
}
|
|
2344
|
-
return
|
|
3121
|
+
return _chunkNW2CKOFLcjs.tidyScriptTags.call(void 0, out);
|
|
2345
3122
|
}
|
|
2346
3123
|
|
|
2347
3124
|
// src/pdf/line-wrap.ts
|
|
@@ -2377,12 +3154,12 @@ var WrapLexicon = (_class = class {constructor() { _class.prototype.__init.call(
|
|
|
2377
3154
|
const t = toks[i], n = t.length;
|
|
2378
3155
|
if (i > 0 && i < toks.length - 1) {
|
|
2379
3156
|
bump(this.words, t);
|
|
2380
|
-
const run = _nullishCoalesce(_optionalChain([t, 'access',
|
|
3157
|
+
const run = _nullishCoalesce(_optionalChain([t, 'access', _53 => _53.match, 'call', _54 => _54(/^[가-힣]+/), 'optionalAccess', _55 => _55[0]]), () => ( ""));
|
|
2381
3158
|
for (let j = 2; j <= Math.min(run.length, 6); j++) this.heads.add(run.slice(0, j));
|
|
2382
3159
|
}
|
|
2383
3160
|
if (i + 1 < toks.length) {
|
|
2384
3161
|
this.pairs.add(t + " " + toks[i + 1]);
|
|
2385
|
-
const tail = _optionalChain([t, 'access',
|
|
3162
|
+
const tail = _optionalChain([t, 'access', _56 => _56.match, 'call', _57 => _57(/[가-힣]+$/), 'optionalAccess', _58 => _58[0]]);
|
|
2386
3163
|
if (tail) this.spacedHeads.add(tail + " " + toks[i + 1].charAt(0));
|
|
2387
3164
|
}
|
|
2388
3165
|
for (let a = 0; a + 1 < n; a++) {
|
|
@@ -2419,14 +3196,14 @@ var WrapLexicon = (_class = class {constructor() { _class.prototype.__init.call(
|
|
|
2419
3196
|
const n = left.length;
|
|
2420
3197
|
if (n < 2 || right.length < 2) return null;
|
|
2421
3198
|
const k1 = pairKey(left.charCodeAt(n - 2), left.charCodeAt(n - 1)), k2 = pairKey(right.charCodeAt(0), right.charCodeAt(1));
|
|
2422
|
-
return decideCounts(_nullishCoalesce(_optionalChain([this, 'access',
|
|
3199
|
+
return decideCounts(_nullishCoalesce(_optionalChain([this, 'access', _59 => _59.joined2, 'access', _60 => _60.get, 'call', _61 => _61(k1), 'optionalAccess', _62 => _62.get, 'call', _63 => _63(k2)]), () => ( 0)), _nullishCoalesce(_optionalChain([this, 'access', _64 => _64.spaced2, 'access', _65 => _65.get, 'call', _66 => _66(k1), 'optionalAccess', _67 => _67.get, 'call', _68 => _68(k2)]), () => ( 0)));
|
|
2423
3200
|
}
|
|
2424
3201
|
/** 꺾인 자리 증거: "" 붙음 · " " 띄움 · null 모름 (두 글자 증거가 갈리거나 없으면 한 글자) */
|
|
2425
3202
|
evidence(left, right) {
|
|
2426
3203
|
const n = left.length;
|
|
2427
3204
|
if (n >= 2 && right.length >= 2) {
|
|
2428
3205
|
const k1 = pairKey(left.charCodeAt(n - 2), left.charCodeAt(n - 1)), k2 = pairKey(right.charCodeAt(0), right.charCodeAt(1));
|
|
2429
|
-
const v = decideCounts(_nullishCoalesce(_optionalChain([this, 'access',
|
|
3206
|
+
const v = decideCounts(_nullishCoalesce(_optionalChain([this, 'access', _69 => _69.joined2, 'access', _70 => _70.get, 'call', _71 => _71(k1), 'optionalAccess', _72 => _72.get, 'call', _73 => _73(k2)]), () => ( 0)), _nullishCoalesce(_optionalChain([this, 'access', _74 => _74.spaced2, 'access', _75 => _75.get, 'call', _76 => _76(k1), 'optionalAccess', _77 => _77.get, 'call', _78 => _78(k2)]), () => ( 0)));
|
|
2430
3207
|
if (v !== null) return v;
|
|
2431
3208
|
}
|
|
2432
3209
|
if (n && right.length) {
|
|
@@ -2501,11 +3278,11 @@ function wrapJoiner(prevText, nextText, lex, heads = true) {
|
|
|
2501
3278
|
if (particleContinues(left, right)) return "";
|
|
2502
3279
|
if (endsAsWord(left)) return " ";
|
|
2503
3280
|
if (/[A-Za-z]-$/.test(left) && /^[A-Za-z]/.test(right) && !/[가-힣]/.test(prev + next)) {
|
|
2504
|
-
return _optionalChain([lex, 'optionalAccess',
|
|
3281
|
+
return _optionalChain([lex, 'optionalAccess', _79 => _79.joinedWord, 'call', _80 => _80(left, right.replace(/[.,;:!?)]*$/, ""))]) ? "" : " ";
|
|
2505
3282
|
}
|
|
2506
3283
|
if (/[·ㆍ‧-]/.test(a) && !/[·ㆍ‧…]{2}$/.test(prev) && /[가-힣A-Za-z0-9]/.test(b)) return "";
|
|
2507
3284
|
if (/[A-Za-z]/.test(a) && /[A-Za-z]/.test(b) || /\d/.test(a) && /\d/.test(b)) return " ";
|
|
2508
|
-
const ev = _optionalChain([lex, 'optionalAccess',
|
|
3285
|
+
const ev = _optionalChain([lex, 'optionalAccess', _81 => _81.evidence, 'call', _82 => _82(left, right)]);
|
|
2509
3286
|
if (ev != null) return ev;
|
|
2510
3287
|
if (lex && /[가-힣A-Za-z0-9]$/.test(left) && /^[가-힣A-Za-z0-9]/.test(right) && lex.joinedWord(left, right.replace(/[.,)」』’”;:]+$/, ""))) return "";
|
|
2511
3288
|
if (/\d$/.test(left) && COUNTER.test(right)) return "";
|
|
@@ -2513,7 +3290,7 @@ function wrapJoiner(prevText, nextText, lex, heads = true) {
|
|
|
2513
3290
|
const r1 = right.replace(/[.,)」』’”]+$/, "");
|
|
2514
3291
|
if (lex && /[가-힣]$/.test(left) && /^[가-힣]$/.test(r1) && !STANDALONE_SYLLABLE.test(r1) && !lex.isWord(r1) && !lex.isWord(right)) return "";
|
|
2515
3292
|
if (lex && heads) {
|
|
2516
|
-
const tail = _optionalChain([left, 'access',
|
|
3293
|
+
const tail = _optionalChain([left, 'access', _83 => _83.match, 'call', _84 => _84(/[가-힣]+$/), 'optionalAccess', _85 => _85[0]]), run = _optionalChain([right, 'access', _86 => _86.match, 'call', _87 => _87(/^[가-힣]+/), 'optionalAccess', _88 => _88[0]]);
|
|
2517
3294
|
if (tail && run && !STANDALONE_SYLLABLE.test(tail) && lex.startsWord(tail + run.slice(0, 2)) && !lex.spacedHead(tail, run[0])) return "";
|
|
2518
3295
|
if (/[가-힣]{2}$/.test(left) && /^\([^()\s]*\)/.test(right) && !endsAsWord(left) && !/(?:함|음|됨|임|다)$/.test(left) && !BARE_UNIT_PAREN.test(right) && !/^\(\d/.test(right)) return "";
|
|
2519
3296
|
}
|
|
@@ -2548,14 +3325,14 @@ function joinPageBreakWraps(blocks, lex) {
|
|
|
2548
3325
|
if (a.type !== "paragraph" && a.type !== "list" || b.type !== "paragraph") continue;
|
|
2549
3326
|
const last = a.bbox && PARA_LAST_LINE.get(a.bbox), fs = last ? last.fontSize : 0;
|
|
2550
3327
|
if (!last || fs <= 0 || (_nullishCoalesce(pageRight.get(a.pageNumber), () => ( Infinity))) - last.right >= BODY_FULL_TOL * fs) continue;
|
|
2551
|
-
if (last.width < BODY_MIN_WIDTH_EM * fs || Math.abs((_nullishCoalesce(_optionalChain([b, 'access',
|
|
3328
|
+
if (last.width < BODY_MIN_WIDTH_EM * fs || Math.abs((_nullishCoalesce(_optionalChain([b, 'access', _89 => _89.style, 'optionalAccess', _90 => _90.fontSize]), () => ( 0))) - fs) > 0.15 * fs) continue;
|
|
2552
3329
|
const bt = b.text.replace(MARKUP, "");
|
|
2553
3330
|
if (startsNewItem(a.text, b.text) || PAGE_REF_TAIL.test(a.text) || PAGE_ITEM_HEAD.test(bt)) continue;
|
|
2554
3331
|
if (PAGE_HEAD_MARK.test(bt) && !(/^[\u25a0-\u25ff]/.test(bt) && a.text.includes(bt[0]))) continue;
|
|
2555
3332
|
const firstLeft = b.bbox && PARA_FIRST_LEFT.get(b.bbox);
|
|
2556
3333
|
const indented = firstLeft === void 0 || firstLeft - (_nullishCoalesce(pageLeft.get(b.pageNumber), () => ( firstLeft))) >= 0.3 * fs;
|
|
2557
3334
|
if (indented && SENTENCE_END.test(a.text.replace(MARKUP, "").trimEnd())) continue;
|
|
2558
|
-
if (Math.round(_nullishCoalesce(_optionalChain([b, 'access',
|
|
3335
|
+
if (Math.round(_nullishCoalesce(_optionalChain([b, 'access', _91 => _91.style, 'optionalAccess', _92 => _92.fontSize]), () => ( 0))) !== Math.round(fs) && titleLike(b.text)) continue;
|
|
2559
3336
|
if (/\t/.test(a.text.slice(a.text.lastIndexOf("\n") + 1).replace(/^\S{1,8}\t/, "")) && titleLike(bt.trim().split("\n")[0])) continue;
|
|
2560
3337
|
const joined = wrapJoiner(a.text, b.text, lex);
|
|
2561
3338
|
const head = a.text, joiner = joined === "" && last.spaceAfter ? " " : joined;
|
|
@@ -2604,7 +3381,7 @@ function bodyLineJoins(lines, lex) {
|
|
|
2604
3381
|
for (const l of lines) if (!HANGING.test(l.text) && l.right > inner) inner = l.right;
|
|
2605
3382
|
const full = (l) => right - l.right < BODY_FULL_TOL * l.fontSize || right - inner <= 1.2 * l.fontSize && inner - l.right < BODY_FULL_TOL * l.fontSize;
|
|
2606
3383
|
const nextWordNoRoom = (a, b) => {
|
|
2607
|
-
const w = _optionalChain([b, 'access',
|
|
3384
|
+
const w = _optionalChain([b, 'access', _93 => _93.text, 'access', _94 => _94.trim, 'call', _95 => _95(), 'access', _96 => _96.match, 'call', _97 => _97(/^\S+/), 'optionalAccess', _98 => _98[0]]);
|
|
2608
3385
|
const n = [...b.text.trim()].length;
|
|
2609
3386
|
if (!w || n === 0) return false;
|
|
2610
3387
|
const em = (b.right - b.left) / n;
|
|
@@ -2800,7 +3577,7 @@ function cellTextToString(items, wrap) {
|
|
|
2800
3577
|
const merged = mergeSuperscriptRows(lines).map((line) => sortLineByX(line));
|
|
2801
3578
|
const textLines = merged.map((s) => {
|
|
2802
3579
|
if (s.length === 1) return s[0].text;
|
|
2803
|
-
if (s.length === 2 && /^[가-힣]$/.test(s[0].text) && /^[가-힣]$/.test(s[1].text) && !!_optionalChain([wrap, 'optionalAccess',
|
|
3580
|
+
if (s.length === 2 && /^[가-힣]$/.test(s[0].text) && /^[가-힣]$/.test(s[1].text) && !!_optionalChain([wrap, 'optionalAccess', _99 => _99.lex]) && (wrap.lex.isWord(s[0].text + s[1].text) || wrap.lex.evidence(s[0].text, s[1].text) === "" || REGION_LABELS.has(s[0].text + s[1].text)) && s[1].x - (s[0].x + s[0].w) >= Math.max(s[0].fontSize, s[1].fontSize) * 1.5 && s[1].x + s[1].w - s[0].x >= wrap.box.x2 - wrap.box.x1 - Math.max(s[0].fontSize, s[1].fontSize) * 2) return s[0].text + s[1].text;
|
|
2804
3581
|
const evenSpaced = detectEvenSpacedItems(s, true);
|
|
2805
3582
|
let result = s[0].text;
|
|
2806
3583
|
for (let j = 1; j < s.length; j++) {
|
|
@@ -2946,12 +3723,12 @@ function markEvenRun(items, visible, result, start, end) {
|
|
|
2946
3723
|
}
|
|
2947
3724
|
function mergeCellTextLines(textLines, wrap) {
|
|
2948
3725
|
if (textLines.length <= 1) return textLines[0] || "";
|
|
2949
|
-
const numberWrapped = (k) => !!_optionalChain([wrap, 'optionalAccess',
|
|
3726
|
+
const numberWrapped = (k) => !!_optionalChain([wrap, 'optionalAccess', _100 => _100.wraps, 'access', _101 => _101[k]]) && (_nullishCoalesce(_optionalChain([wrap, 'access', _102 => _102.wide, 'optionalAccess', _103 => _103[k]]), () => ( true)));
|
|
2950
3727
|
const merged = [textLines[0]];
|
|
2951
3728
|
for (let i = 1; i < textLines.length; i++) {
|
|
2952
3729
|
const prev = merged[merged.length - 1];
|
|
2953
3730
|
const curr = textLines[i];
|
|
2954
|
-
if (wrap ? wrap.wraps[i - 1] && !_optionalChain([wrap, 'access',
|
|
3731
|
+
if (wrap ? wrap.wraps[i - 1] && !_optionalChain([wrap, 'access', _104 => _104.spaced, 'optionalAccess', _105 => _105[i - 1]]) && !startsNewItem(prev, curr) && wrapJoiner(prev, curr, wrap.lex, false) === "" : /[가-힣]$/.test(prev) && /^[가-힣]+$/.test(curr) && curr.length <= 8 && !curr.includes(" ")) {
|
|
2955
3732
|
merged[merged.length - 1] = prev + curr;
|
|
2956
3733
|
} else if (curr.trim().length <= 3 && /^[)\]%}]/.test(curr.trim())) {
|
|
2957
3734
|
merged[merged.length - 1] = prev + curr.trim();
|
|
@@ -3046,7 +3823,7 @@ function normalizeUndersegmentedTable(originalCells, colXs, items, rowYs) {
|
|
|
3046
3823
|
if (numRows > MAX_UNDERSEGMENTED_ROWS || numCols < MIN_UNDERSEGMENTED_COLUMNS) return null;
|
|
3047
3824
|
if (items.length === 0) return null;
|
|
3048
3825
|
if (numRows >= 3) {
|
|
3049
|
-
if (_optionalChain([rowYs, 'optionalAccess',
|
|
3826
|
+
if (_optionalChain([rowYs, 'optionalAccess', _106 => _106.length]) !== numRows + 1) return null;
|
|
3050
3827
|
const rebuilt2 = [];
|
|
3051
3828
|
let expanded = 0;
|
|
3052
3829
|
for (let r = 0; r < numRows; r++) {
|
|
@@ -3140,7 +3917,7 @@ function sortLineByX(items) {
|
|
|
3140
3917
|
e++;
|
|
3141
3918
|
}
|
|
3142
3919
|
const run = items.slice(s, e), seqs = run.map((i) => i.seq);
|
|
3143
|
-
const ok = !wide ? !run.some((i) => _optionalChain([i, 'access',
|
|
3920
|
+
const ok = !wide ? !run.some((i) => _optionalChain([i, 'access', _107 => _107.text, 'optionalAccess', _108 => _108.startsWith, 'call', _109 => _109("$")])) : Math.max(...seqs) - Math.min(...seqs) <= 2 * (e - s - 1) && run.every((i) => Math.abs((_nullishCoalesce(i.fontSize, () => ( 0))) - (_nullishCoalesce(run[0].fontSize, () => ( 0)))) <= 0.5);
|
|
3144
3921
|
if (e - s > 1 && seqs.every((q) => q !== void 0) && ok) {
|
|
3145
3922
|
run.sort((a, b) => a.seq - b.seq);
|
|
3146
3923
|
for (let k = 0; k < run.length; k++) items[s + k] = run[k];
|
|
@@ -3209,7 +3986,7 @@ function dominantStyle(items) {
|
|
|
3209
3986
|
let maxCount = 0, dominantSize = 0;
|
|
3210
3987
|
for (const i of items) {
|
|
3211
3988
|
if (i.fontSize <= 0) continue;
|
|
3212
|
-
const count = (freq.get(i.fontSize) || 0) + Math.max(1, _nullishCoalesce(_optionalChain([i, 'access',
|
|
3989
|
+
const count = (freq.get(i.fontSize) || 0) + Math.max(1, _nullishCoalesce(_optionalChain([i, 'access', _110 => _110.text, 'access', _111 => _111.match, 'call', _112 => _112(/[\p{L}\p{N}]/gu), 'optionalAccess', _113 => _113.length]), () => ( 0)));
|
|
3213
3990
|
freq.set(i.fontSize, count);
|
|
3214
3991
|
if (count > maxCount) {
|
|
3215
3992
|
maxCount = count;
|
|
@@ -3217,7 +3994,7 @@ function dominantStyle(items) {
|
|
|
3217
3994
|
}
|
|
3218
3995
|
}
|
|
3219
3996
|
if (dominantSize === 0) return void 0;
|
|
3220
|
-
const fontName = _optionalChain([items, 'access',
|
|
3997
|
+
const fontName = _optionalChain([items, 'access', _114 => _114.find, 'call', _115 => _115((i) => i.fontSize === dominantSize), 'optionalAccess', _116 => _116.fontName]) || void 0;
|
|
3221
3998
|
return fontName ? { fontSize: dominantSize, fontName } : { fontSize: dominantSize };
|
|
3222
3999
|
}
|
|
3223
4000
|
function normalizeItems(rawItems) {
|
|
@@ -3362,7 +4139,7 @@ function splitAroundOverlays(c, overlays) {
|
|
|
3362
4139
|
const ov = overlays.filter((o) => {
|
|
3363
4140
|
for (let at = c.text.indexOf(o.text); at >= 0; at = c.text.indexOf(o.text, at + 1)) {
|
|
3364
4141
|
const prefix = c.text.slice(0, at);
|
|
3365
|
-
const est = c.x + glyphUnits(prefix.replace(/\s+/g, "")) * a0 + (_nullishCoalesce(_optionalChain([prefix, 'access',
|
|
4142
|
+
const est = c.x + glyphUnits(prefix.replace(/\s+/g, "")) * a0 + (_nullishCoalesce(_optionalChain([prefix, 'access', _117 => _117.match, 'call', _118 => _118(/\s+/g), 'optionalAccess', _119 => _119.length]), () => ( 0))) * ws;
|
|
3366
4143
|
if (Math.abs(est - o.x) <= OVERLAY_DUP_EM * fs) return false;
|
|
3367
4144
|
}
|
|
3368
4145
|
return true;
|
|
@@ -3487,7 +4264,7 @@ function mergeSuperscriptLines(lines) {
|
|
|
3487
4264
|
return result;
|
|
3488
4265
|
}
|
|
3489
4266
|
function mergeLineSimple(items) {
|
|
3490
|
-
if (items.length <= 1) return _optionalChain([items, 'access',
|
|
4267
|
+
if (items.length <= 1) return _optionalChain([items, 'access', _120 => _120[0], 'optionalAccess', _121 => _121.text]) || "";
|
|
3491
4268
|
const sorted = sortLineByX([...items]);
|
|
3492
4269
|
const isEvenSpaced = detectEvenSpacedItems(sorted);
|
|
3493
4270
|
let result = sorted[0].text;
|
|
@@ -3575,7 +4352,7 @@ function isProseTable(table) {
|
|
|
3575
4352
|
if (!(long > 0 && long >= total * 0.5 && longRows >= rows * 0.4)) return false;
|
|
3576
4353
|
for (let c = 0; c < table.cols; c++) {
|
|
3577
4354
|
const filled = table.cells.map((row) => row[c]).filter((cell) => cell && cell.colSpan < table.cols && cell.text.trim()).map((cell) => cell.text.trim());
|
|
3578
|
-
if (filled.length >= 3 && filled.length >= rows * 0.6 && filled.every((text) => text.length <= 30 && (_nullishCoalesce(_optionalChain([text, 'access',
|
|
4355
|
+
if (filled.length >= 3 && filled.length >= rows * 0.6 && filled.every((text) => text.length <= 30 && (_nullishCoalesce(_optionalChain([text, 'access', _122 => _122.match, 'call', _123 => _123(/\p{L}/gu), 'optionalAccess', _124 => _124.length]), () => ( 0))) >= 2)) return false;
|
|
3579
4356
|
}
|
|
3580
4357
|
return true;
|
|
3581
4358
|
}
|
|
@@ -3604,7 +4381,7 @@ var TICK = /^-?[\d,]+(?:\.\d+)?%?$/;
|
|
|
3604
4381
|
var QUANTITY = /^[-−–]?[\d,]*\.?\d+%?$/;
|
|
3605
4382
|
var quantity = (token) => Number(token.replace(/^[−–]/, "-").replace(/[,%]/g, ""));
|
|
3606
4383
|
function isValueAxisColumn(table, c) {
|
|
3607
|
-
const lines = table.cells.flatMap((row) => (_nullishCoalesce(_optionalChain([row, 'access',
|
|
4384
|
+
const lines = table.cells.flatMap((row) => (_nullishCoalesce(_optionalChain([row, 'access', _125 => _125[c], 'optionalAccess', _126 => _126.text]), () => ( ""))).split("\n").map((line) => line.trim().split(/\s+/)));
|
|
3608
4385
|
const others = table.cells.flatMap((row) => row.filter((_, k) => k !== c).map((cell) => cell.text.trim().split(/\s+/))).filter((tokens) => tokens.every((token) => QUANTITY.test(token))).flat().map(quantity).filter((v) => !(Number.isInteger(v) && v >= 1900 && v <= 2100));
|
|
3609
4386
|
for (const ticks of [lines.flat().filter((t) => TICK.test(t)).map(quantity), lines.map((tokens) => tokens[0]).filter((t) => TICK.test(t)).map(quantity)]) {
|
|
3610
4387
|
const run = fallingRun(ticks);
|
|
@@ -3636,7 +4413,7 @@ function isChartTable(table, ocr = false) {
|
|
|
3636
4413
|
const numeric = texts.filter((text) => NUMERIC_CELL.test(text)).length;
|
|
3637
4414
|
if (numeric < texts.length * 0.5) return false;
|
|
3638
4415
|
for (let c = 0; c < table.cols; c++) {
|
|
3639
|
-
if (!ocr ? isValueAxisColumn(table, c) : hasValueAxis(table.cells.flatMap((row) => (_nullishCoalesce(_optionalChain([row, 'access',
|
|
4416
|
+
if (!ocr ? isValueAxisColumn(table, c) : hasValueAxis(table.cells.flatMap((row) => (_nullishCoalesce(_optionalChain([row, 'access', _127 => _127[c], 'optionalAccess', _128 => _128.text]), () => ( ""))).split(/\s+/)).filter((t) => TICK.test(t)).map((t) => Number(t.replace(/[,%]/g, ""))))) return true;
|
|
3640
4417
|
}
|
|
3641
4418
|
const values = texts.filter((text) => text.split(/\s+/).every((token) => QUANTITY.test(token))).length;
|
|
3642
4419
|
const cells = table.rows * table.cols;
|
|
@@ -3689,7 +4466,7 @@ function clusterCellLines(items) {
|
|
|
3689
4466
|
}
|
|
3690
4467
|
var WRAP_INDENT_MAX = 3;
|
|
3691
4468
|
function joinClusterCellLines(lines, box, lex) {
|
|
3692
|
-
let out = _nullishCoalesce(_optionalChain([lines, 'access',
|
|
4469
|
+
let out = _nullishCoalesce(_optionalChain([lines, 'access', _129 => _129[0], 'optionalAccess', _130 => _130.text]), () => ( ""));
|
|
3693
4470
|
for (let i = 1; i < lines.length; i++) {
|
|
3694
4471
|
const a = lines[i - 1], b = lines[i];
|
|
3695
4472
|
const join2 = !a.spaceAfter && cellLineWraps(box, box.x1, a.right, a.fontSize, b.firstCharW) && a.left - box.x1 <= WRAP_INDENT_MAX * a.fontSize && b.left - box.x1 <= WRAP_INDENT_MAX * b.fontSize && /<\/u>$/.test(a.text) === /^<u>/.test(b.text) && !startsNewItem(out, b.text) && wrapJoiner(out, b.text, lex, false) === "";
|
|
@@ -3698,6 +4475,59 @@ function joinClusterCellLines(lines, box, lex) {
|
|
|
3698
4475
|
return out;
|
|
3699
4476
|
}
|
|
3700
4477
|
|
|
4478
|
+
// src/pdf/ocr-column-cuts.ts
|
|
4479
|
+
var OCR_NUMERIC_CELL = /^[+-]?\d+(?:[,.]\d+)*%?$/;
|
|
4480
|
+
var OCR_GROUPED_NUMBER = /^[+-]?\d{1,3}(?:\s+\d{3})+(?:[.,]\d+)?%?$/;
|
|
4481
|
+
function supportedOcrColumnCuts(rows) {
|
|
4482
|
+
const cuts = /* @__PURE__ */ new Map();
|
|
4483
|
+
for (const head of _nullishCoalesce(rows[0], () => ( []))) {
|
|
4484
|
+
if (head.items.length !== 1 || head.items[0].fontName !== "ocr") continue;
|
|
4485
|
+
const candidates = [];
|
|
4486
|
+
for (const gap of ocrTextGaps(head.items[0])) {
|
|
4487
|
+
const text = head.items[0].text;
|
|
4488
|
+
if (!/\p{L}/u.test(text.slice(0, gap.at)) || !/\p{L}/u.test(text.slice(gap.at))) continue;
|
|
4489
|
+
const intervals = [];
|
|
4490
|
+
for (const row of rows.slice(1)) {
|
|
4491
|
+
const cell = row.find((c) => c.col === head.col);
|
|
4492
|
+
if (!cell || cell.items.some((it) => it.fontName !== "ocr")) continue;
|
|
4493
|
+
let interval;
|
|
4494
|
+
if (cell.items.length === 1) {
|
|
4495
|
+
const it = cell.items[0];
|
|
4496
|
+
interval = ocrTextGaps(it).find((g) => isOcrNumericSplit(it.text, g.at));
|
|
4497
|
+
} else if (isOcrNumericPair(cell.items)) {
|
|
4498
|
+
const [a, b] = [...cell.items].sort((a2, b2) => a2.x - b2.x);
|
|
4499
|
+
interval = { left: a.x + a.w / 2, right: b.x + b.w / 2 };
|
|
4500
|
+
}
|
|
4501
|
+
if (interval) {
|
|
4502
|
+
const left = Math.max(gap.left, interval.left), right = Math.min(gap.right, interval.right);
|
|
4503
|
+
if (right > left) intervals.push({ left, right });
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4506
|
+
const events = intervals.flatMap((i) => [{ x: i.left, delta: 1 }, { x: i.right, delta: -1 }]).sort((a, b) => a.x - b.x);
|
|
4507
|
+
let active = 0, bestCount = 1, bestWidth = 0, cut;
|
|
4508
|
+
for (let i = 0; i < events.length; ) {
|
|
4509
|
+
const x = events[i].x;
|
|
4510
|
+
while (i < events.length && events[i].x === x) active += events[i++].delta;
|
|
4511
|
+
const width = i < events.length ? events[i].x - x : 0;
|
|
4512
|
+
if (active >= 2 && width > 0 && (active > bestCount || active === bestCount && width > bestWidth)) {
|
|
4513
|
+
bestCount = active;
|
|
4514
|
+
bestWidth = width;
|
|
4515
|
+
cut = x + width / 2;
|
|
4516
|
+
}
|
|
4517
|
+
}
|
|
4518
|
+
if (cut !== void 0) candidates.push(cut);
|
|
4519
|
+
}
|
|
4520
|
+
if (candidates.length === 1) cuts.set(head.col, candidates[0]);
|
|
4521
|
+
}
|
|
4522
|
+
return cuts;
|
|
4523
|
+
}
|
|
4524
|
+
function isOcrNumericPair(items) {
|
|
4525
|
+
return items.length === 2 && items.every((it) => it.fontName === "ocr" && OCR_NUMERIC_CELL.test(it.text.trim())) && !OCR_GROUPED_NUMBER.test([...items].sort((a, b) => a.x - b.x).map((it) => it.text.trim()).join(" "));
|
|
4526
|
+
}
|
|
4527
|
+
function isOcrNumericSplit(text, at) {
|
|
4528
|
+
return !OCR_GROUPED_NUMBER.test(text.trim()) && /\s/.test((_nullishCoalesce(text[at - 1], () => ( ""))) + (_nullishCoalesce(text[at], () => ( "")))) && OCR_NUMERIC_CELL.test(text.slice(0, at).trim()) && OCR_NUMERIC_CELL.test(text.slice(at).trim());
|
|
4529
|
+
}
|
|
4530
|
+
|
|
3701
4531
|
// src/pdf/cluster-detector.ts
|
|
3702
4532
|
var Y_TOL = 3;
|
|
3703
4533
|
var COL_CLUSTER_TOL = 15;
|
|
@@ -3908,7 +4738,7 @@ function detectAlignedTwoColumnTables(rows, pageNum) {
|
|
|
3908
4738
|
continue;
|
|
3909
4739
|
}
|
|
3910
4740
|
const top = rows[i - 1];
|
|
3911
|
-
const title = _optionalChain([top, 'optionalAccess',
|
|
4741
|
+
const title = _optionalChain([top, 'optionalAccess', _131 => _131.items, 'access', _132 => _132.length]) === 1 && Math.abs(top.items[0].x - first[0].x) <= 5 && top.items[0].text.length <= 65 && top.y - first[0].y <= Math.max(24, first[0].fontSize * 2.8) ? top : void 0;
|
|
3912
4742
|
const tableRows = title ? [title, ...body] : body;
|
|
3913
4743
|
const cells = tableRows.map((row, idx) => {
|
|
3914
4744
|
if (title && idx === 0) return [{ text: row.items[0].text, colSpan: 2, rowSpan: 1 }, { text: "", colSpan: 1, rowSpan: 1 }];
|
|
@@ -3964,12 +4794,12 @@ function isTwoColumnProse(r) {
|
|
|
3964
4794
|
if (t.rows < 8) return false;
|
|
3965
4795
|
const dense = [];
|
|
3966
4796
|
for (let c = 0; c < t.cols; c++) {
|
|
3967
|
-
const filled = t.cells.filter((row) => _optionalChain([row, 'access',
|
|
4797
|
+
const filled = t.cells.filter((row) => _optionalChain([row, 'access', _133 => _133[c], 'optionalAccess', _134 => _134.text, 'access', _135 => _135.trim, 'call', _136 => _136()])).length;
|
|
3968
4798
|
if (filled / t.rows >= 0.3) dense.push(c);
|
|
3969
4799
|
}
|
|
3970
4800
|
if (dense.length !== 2) return false;
|
|
3971
4801
|
for (const c of dense) {
|
|
3972
|
-
const lens = t.cells.map((row) => _nullishCoalesce(_optionalChain([row, 'access',
|
|
4802
|
+
const lens = t.cells.map((row) => _nullishCoalesce(_optionalChain([row, 'access', _137 => _137[c], 'optionalAccess', _138 => _138.text, 'access', _139 => _139.replace, 'call', _140 => _140(/\s+/g, ""), 'access', _141 => _141.length]), () => ( 0))).filter((n) => n > 0);
|
|
3973
4803
|
const avg = lens.reduce((s, v) => s + v, 0) / (lens.length || 1);
|
|
3974
4804
|
if (avg < 12) return false;
|
|
3975
4805
|
}
|
|
@@ -4396,7 +5226,7 @@ function assignRowItems(items, columns, numCols, headerFace) {
|
|
|
4396
5226
|
const runs = [];
|
|
4397
5227
|
for (const it of sorted) {
|
|
4398
5228
|
const last = runs[runs.length - 1];
|
|
4399
|
-
const prev = _optionalChain([last, 'optionalAccess',
|
|
5229
|
+
const prev = _optionalChain([last, 'optionalAccess', _142 => _142[last.length - 1]]);
|
|
4400
5230
|
if (prev && it.x - (prev.x + prev.w) <= Math.max(0.5, it.fontSize * 0.05) && !it.hasSpaceBefore) last.push(it);
|
|
4401
5231
|
else runs.push([it]);
|
|
4402
5232
|
}
|
|
@@ -4462,17 +5292,21 @@ function assignRowItems(items, columns, numCols, headerFace) {
|
|
|
4462
5292
|
return result;
|
|
4463
5293
|
}
|
|
4464
5294
|
function buildClusterTable(rows, columns, pageNum, lex) {
|
|
4465
|
-
const numCols = columns.length;
|
|
4466
5295
|
const numRows = rows.length;
|
|
4467
|
-
if (numRows < MIN_ROWS ||
|
|
5296
|
+
if (numRows < MIN_ROWS || columns.length < MIN_COLS) return null;
|
|
5297
|
+
const headFaces = new Set(_optionalChain([rows, 'access', _143 => _143[0], 'optionalAccess', _144 => _144.items, 'access', _145 => _145.map, 'call', _146 => _146((i) => i.fontName)]));
|
|
5298
|
+
const headerFace = headFaces.size === 1 && rows.slice(1).every((row) => row.items.every((i) => !headFaces.has(i.fontName))) ? [...headFaces][0] : void 0;
|
|
5299
|
+
const assigned = rows.map((row, r) => assignRowItems(row.items, columns, columns.length, r === 0 ? headerFace : void 0));
|
|
5300
|
+
const cuts = supportedOcrColumnCuts(assigned);
|
|
5301
|
+
const starts = columns.map((_, c) => c + [...cuts.keys()].filter((k) => k < c).length);
|
|
5302
|
+
const numCols = columns.length + cuts.size;
|
|
4468
5303
|
const cells = Array.from(
|
|
4469
5304
|
{ length: numRows },
|
|
4470
5305
|
() => Array.from({ length: numCols }, () => ({ text: "", colSpan: 1, rowSpan: 1 }))
|
|
4471
5306
|
);
|
|
4472
5307
|
const usedItems = /* @__PURE__ */ new Set();
|
|
4473
5308
|
const lines = cells.map((row) => row.map(() => []));
|
|
4474
|
-
const
|
|
4475
|
-
const headerFace = headFaces.size === 1 && rows.slice(1).every((row) => row.items.every((i) => !headFaces.has(i.fontName))) ? [...headFaces][0] : void 0;
|
|
5309
|
+
const origins = /* @__PURE__ */ new Map();
|
|
4476
5310
|
for (let r = 0; r < numRows; r++) {
|
|
4477
5311
|
const row = rows[r];
|
|
4478
5312
|
if (row.items.length === 1 && numCols > 1) {
|
|
@@ -4480,15 +5314,39 @@ function buildClusterTable(rows, columns, pageNum, lex) {
|
|
|
4480
5314
|
usedItems.add(row.items[0]);
|
|
4481
5315
|
continue;
|
|
4482
5316
|
}
|
|
4483
|
-
const assignments =
|
|
4484
|
-
|
|
5317
|
+
const assignments = assigned[r].flatMap(({ col, items }) => {
|
|
5318
|
+
const target = starts[col], cut = cuts.get(col);
|
|
5319
|
+
if (cut === void 0) return [{ col: target, items, span: 1 }];
|
|
5320
|
+
const gapAt = (it) => ocrTextGaps(it).find((g) => g.left < cut && g.right > cut && (r === 0 || isOcrNumericSplit(it.text, g.at)));
|
|
5321
|
+
const groupedNumber = OCR_GROUPED_NUMBER.test([...items].sort((a, b) => a.x - b.x).map((it) => it.text.trim()).join(" "));
|
|
5322
|
+
if (groupedNumber || !isOcrNumericPair(items) && items.some((it) => it.x < cut && it.x + it.w > cut && !gapAt(it))) return [{ col: target, items, span: 2 }];
|
|
5323
|
+
const parts = [[], []];
|
|
5324
|
+
for (const it of items) {
|
|
5325
|
+
const g = gapAt(it);
|
|
5326
|
+
if (!g) {
|
|
5327
|
+
parts[it.x + it.w / 2 < cut ? 0 : 1].push(it);
|
|
5328
|
+
continue;
|
|
5329
|
+
}
|
|
5330
|
+
const fragments = [
|
|
5331
|
+
{ ...it, text: it.text.slice(0, g.at).trimEnd(), w: g.left - it.x },
|
|
5332
|
+
{ ...it, text: it.text.slice(g.at).trimStart(), x: g.right, w: it.x + it.w - g.right }
|
|
5333
|
+
];
|
|
5334
|
+
fragments.forEach((fragment, side) => {
|
|
5335
|
+
origins.set(fragment, it);
|
|
5336
|
+
parts[side].push(fragment);
|
|
5337
|
+
});
|
|
5338
|
+
}
|
|
5339
|
+
return parts.flatMap((part, side) => part.length ? [{ col: target + side, items: part, span: 1 }] : []);
|
|
5340
|
+
});
|
|
5341
|
+
for (const { col, items, span: span2 } of assignments) {
|
|
5342
|
+
cells[r][col].colSpan = span2;
|
|
4485
5343
|
const cell = lines[r][col];
|
|
4486
5344
|
if (cell.length) cell[cell.length - 1].spaceAfter = true;
|
|
4487
5345
|
cell.push(...clusterCellLines(items));
|
|
4488
|
-
for (const item of items) usedItems.add(item);
|
|
5346
|
+
for (const item of items) usedItems.add(_nullishCoalesce(origins.get(item), () => ( item)));
|
|
4489
5347
|
}
|
|
4490
5348
|
}
|
|
4491
|
-
const boxes =
|
|
5349
|
+
const boxes = Array.from({ length: numCols }, (_, c) => {
|
|
4492
5350
|
const col = lines.flatMap((row) => row[c]);
|
|
4493
5351
|
return { x1: Math.min(...col.map((l) => l.left)), x2: Math.max(...col.map((l) => l.right)) };
|
|
4494
5352
|
});
|
|
@@ -4507,11 +5365,11 @@ function buildClusterTable(rows, columns, pageNum, lex) {
|
|
|
4507
5365
|
const nonEmptyCols = cells[r].filter((c) => c.text.trim()).length;
|
|
4508
5366
|
if (nonEmptyCols !== 1) continue;
|
|
4509
5367
|
if (cells[r][0].text.trim() !== "") continue;
|
|
4510
|
-
const contentText = _optionalChain([cells, 'access',
|
|
5368
|
+
const contentText = _optionalChain([cells, 'access', _147 => _147[r], 'access', _148 => _148.find, 'call', _149 => _149((c) => c.text.trim()), 'optionalAccess', _150 => _150.text, 'access', _151 => _151.trim, 'call', _152 => _152()]) || "";
|
|
4511
5369
|
if (/^[○●▶\-·]/.test(contentText)) continue;
|
|
4512
5370
|
for (let pr = r - 1; pr >= 0; pr--) {
|
|
4513
5371
|
if (cells[pr].some((c) => c.text.trim())) {
|
|
4514
|
-
if (cells[pr]
|
|
5372
|
+
if (cells[pr].some((c) => c.colSpan > 1)) break;
|
|
4515
5373
|
for (let c = 0; c < numCols; c++) {
|
|
4516
5374
|
if (!cells[r][c].text.trim()) continue;
|
|
4517
5375
|
lines[pr][c].push(...lines[r][c]);
|
|
@@ -4740,7 +5598,7 @@ function stackedTableBands(items) {
|
|
|
4740
5598
|
const caption = (start, end) => lines.slice(start, end).some((line) => /^Table\s+\d+\s*[:.]/i.test(mergeLineSimple(line).trim()));
|
|
4741
5599
|
while (runs.length > 0 && !caption(runs[runs.length - 1].end, lines.length)) runs.pop();
|
|
4742
5600
|
if (runs.length < 2) return null;
|
|
4743
|
-
if (runs.some((run, i) => !caption(run.end, _nullishCoalesce(_optionalChain([runs, 'access',
|
|
5601
|
+
if (runs.some((run, i) => !caption(run.end, _nullishCoalesce(_optionalChain([runs, 'access', _153 => _153[i + 1], 'optionalAccess', _154 => _154.start]), () => ( lines.length))))) return null;
|
|
4744
5602
|
const tables = runs.map((run) => lines.slice(run.start, run.end).flat());
|
|
4745
5603
|
const between = runs.slice(0, -1).map((run, i) => lines.slice(run.end, runs[i + 1].start).flat());
|
|
4746
5604
|
const tail = lines.slice(runs[runs.length - 1].end);
|
|
@@ -5008,7 +5866,7 @@ function splitTrailingColumnRegion(items) {
|
|
|
5008
5866
|
}
|
|
5009
5867
|
function panelBlocks(items, panel, pageNum) {
|
|
5010
5868
|
const lines = groupByY([...items].sort((a, b) => b.y - a.y || a.x - b.x));
|
|
5011
|
-
const faceOf = (line) => _nullishCoalesce(_optionalChain([dominantStyle, 'call',
|
|
5869
|
+
const faceOf = (line) => _nullishCoalesce(_optionalChain([dominantStyle, 'call', _155 => _155(line), 'optionalAccess', _156 => _156.fontName]), () => ( ""));
|
|
5012
5870
|
const runs = [];
|
|
5013
5871
|
for (const line of lines) {
|
|
5014
5872
|
const last = runs[runs.length - 1];
|
|
@@ -5190,7 +6048,7 @@ function validWrapBands(items, bands) {
|
|
|
5190
6048
|
}
|
|
5191
6049
|
function inheritedWrapBands(items) {
|
|
5192
6050
|
const source = XY_WRAP_ITEMS.get(items[0]);
|
|
5193
|
-
const present = _optionalChain([source, 'optionalAccess',
|
|
6051
|
+
const present = _optionalChain([source, 'optionalAccess', _157 => _157.length]) === items.length ? new Set(items) : null;
|
|
5194
6052
|
const sameLeaf = present && source.every((item) => present.has(item));
|
|
5195
6053
|
return sameLeaf ? validWrapBands(items, _nullishCoalesce(XY_WRAP_BANDS.get(items[0]), () => ( []))) : [];
|
|
5196
6054
|
}
|
|
@@ -5229,7 +6087,7 @@ function wrappedLineBands(items, inherited) {
|
|
|
5229
6087
|
left: box.x,
|
|
5230
6088
|
right: box.x + box.width,
|
|
5231
6089
|
y: row.reduce((n, i) => n + i.y, 0) / row.length,
|
|
5232
|
-
fontSize: _nullishCoalesce(_optionalChain([dominantStyle, 'call',
|
|
6090
|
+
fontSize: _nullishCoalesce(_optionalChain([dominantStyle, 'call', _158 => _158(row), 'optionalAccess', _159 => _159.fontSize]), () => ( 0)),
|
|
5233
6091
|
sources: row.map((item) => ({ item, state: { ...item } }))
|
|
5234
6092
|
};
|
|
5235
6093
|
});
|
|
@@ -5365,10 +6223,10 @@ function pushLineParagraphs(out, yLines, pageNum, lex) {
|
|
|
5365
6223
|
const lines = attachDropCaps(yLines).map((items) => ({ items, text: mergeLineSimple(items) })).filter((l) => l.text.trim());
|
|
5366
6224
|
const geo = lines.map((l) => {
|
|
5367
6225
|
const b = computeBBox(l.items, pageNum);
|
|
5368
|
-
return { text: l.text, left: b.x, right: b.x + b.width, y: l.items.reduce((s, i) => s + i.y, 0) / l.items.length, fontSize: _nullishCoalesce(_optionalChain([dominantStyle, 'call',
|
|
6226
|
+
return { text: l.text, left: b.x, right: b.x + b.width, y: l.items.reduce((s, i) => s + i.y, 0) / l.items.length, fontSize: _nullishCoalesce(_optionalChain([dominantStyle, 'call', _160 => _160(l.items), 'optionalAccess', _161 => _161.fontSize]), () => ( 0)) };
|
|
5369
6227
|
});
|
|
5370
6228
|
const joins = bodyLineJoins(geo, lex);
|
|
5371
|
-
const first = _optionalChain([lines, 'access',
|
|
6229
|
+
const first = _optionalChain([lines, 'access', _162 => _162[0], 'optionalAccess', _163 => _163.items, 'access', _164 => _164[0]]);
|
|
5372
6230
|
const bands = first ? _nullishCoalesce(XY_WRAP_BANDS.get(first), () => ( [])) : [];
|
|
5373
6231
|
const hasBand = (top, bottom) => {
|
|
5374
6232
|
let lo = 0, hi = bands.length;
|
|
@@ -5445,15 +6303,15 @@ function computeMedianFontSizeFromFreq(freq) {
|
|
|
5445
6303
|
function detectHeadings(blocks, medianFontSize) {
|
|
5446
6304
|
for (let bi = 0; bi < blocks.length; bi++) {
|
|
5447
6305
|
const block = blocks[bi];
|
|
5448
|
-
if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access',
|
|
6306
|
+
if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access', _165 => _165.style, 'optionalAccess', _166 => _166.fontSize])) continue;
|
|
5449
6307
|
const text = block.text.trim();
|
|
5450
6308
|
if (text.length === 0 || text.length > 200) continue;
|
|
5451
6309
|
if (/^\d+$/.test(text) && !isChapterNumber(block, blocks[bi + 1], medianFontSize)) continue;
|
|
5452
6310
|
const ratio = block.style.fontSize / medianFontSize;
|
|
5453
6311
|
let level = 0;
|
|
5454
|
-
if (ratio >=
|
|
5455
|
-
else if (ratio >=
|
|
5456
|
-
else if (ratio >=
|
|
6312
|
+
if (ratio >= _chunkNW2CKOFLcjs.HEADING_RATIO_H1) level = 1;
|
|
6313
|
+
else if (ratio >= _chunkNW2CKOFLcjs.HEADING_RATIO_H2) level = 2;
|
|
6314
|
+
else if (ratio >= _chunkNW2CKOFLcjs.HEADING_RATIO_H3) level = 3;
|
|
5457
6315
|
if (level > 0) {
|
|
5458
6316
|
block.type = "heading";
|
|
5459
6317
|
block.level = level;
|
|
@@ -5462,21 +6320,21 @@ function detectHeadings(blocks, medianFontSize) {
|
|
|
5462
6320
|
}
|
|
5463
6321
|
}
|
|
5464
6322
|
function isChapterNumber(block, next, medianFontSize) {
|
|
5465
|
-
const size = _nullishCoalesce(_optionalChain([block, 'access',
|
|
5466
|
-
const nextSize = _nullishCoalesce(_optionalChain([next, 'optionalAccess',
|
|
5467
|
-
const text = _nullishCoalesce(_optionalChain([next, 'optionalAccess',
|
|
5468
|
-
const a = block.bbox, b = _optionalChain([next, 'optionalAccess',
|
|
5469
|
-
return /^\d{1,2}$/.test(_nullishCoalesce(_optionalChain([block, 'access',
|
|
6323
|
+
const size = _nullishCoalesce(_optionalChain([block, 'access', _167 => _167.style, 'optionalAccess', _168 => _168.fontSize]), () => ( 0));
|
|
6324
|
+
const nextSize = _nullishCoalesce(_optionalChain([next, 'optionalAccess', _169 => _169.style, 'optionalAccess', _170 => _170.fontSize]), () => ( 0));
|
|
6325
|
+
const text = _nullishCoalesce(_optionalChain([next, 'optionalAccess', _171 => _171.text, 'optionalAccess', _172 => _172.trim, 'call', _173 => _173()]), () => ( ""));
|
|
6326
|
+
const a = block.bbox, b = _optionalChain([next, 'optionalAccess', _174 => _174.bbox]);
|
|
6327
|
+
return /^\d{1,2}$/.test(_nullishCoalesce(_optionalChain([block, 'access', _175 => _175.text, 'optionalAccess', _176 => _176.trim, 'call', _177 => _177()]), () => ( ""))) && size >= medianFontSize * 2.5 && !!next && (next.type === "paragraph" || next.type === "heading") && next.pageNumber === block.pageNumber && nextSize >= medianFontSize * _chunkNW2CKOFLcjs.HEADING_RATIO_H1 && text.length > 0 && text.length <= 80 && !/^[\d\s.]+$/.test(text) && !!a && !!b && a.y > b.y && a.y - (b.y + b.height) <= size * 2;
|
|
5470
6328
|
}
|
|
5471
6329
|
function mergeStackedHeadingLines(blocks, medianFontSize) {
|
|
5472
6330
|
for (let i = 0; i < blocks.length - 1; ) {
|
|
5473
6331
|
const a = blocks[i], b = blocks[i + 1];
|
|
5474
6332
|
const ab = a.bbox, bb = b.bbox;
|
|
5475
|
-
const af = _nullishCoalesce(_optionalChain([a, 'access',
|
|
6333
|
+
const af = _nullishCoalesce(_optionalChain([a, 'access', _178 => _178.style, 'optionalAccess', _179 => _179.fontSize]), () => ( 0)), bf = _nullishCoalesce(_optionalChain([b, 'access', _180 => _180.style, 'optionalAccess', _181 => _181.fontSize]), () => ( 0));
|
|
5476
6334
|
const gap = ab && bb ? ab.y - (bb.y + bb.height) : Infinity;
|
|
5477
|
-
const centered = ab && bb && _optionalChain([a, 'access',
|
|
6335
|
+
const centered = ab && bb && _optionalChain([a, 'access', _182 => _182.style, 'optionalAccess', _183 => _183.fontName]) === _optionalChain([b, 'access', _184 => _184.style, 'optionalAccess', _185 => _185.fontName]) && Math.abs(ab.x + ab.width / 2 - (bb.x + bb.width / 2)) <= Math.max(5, af * 0.5);
|
|
5478
6336
|
const sameAnchor = ab && bb && Math.abs(ab.x - bb.x) <= 5;
|
|
5479
|
-
const wrapped = sameAnchor && _optionalChain([a, 'access',
|
|
6337
|
+
const wrapped = sameAnchor && _optionalChain([a, 'access', _186 => _186.style, 'optionalAccess', _187 => _187.fontName]) === _optionalChain([b, 'access', _188 => _188.style, 'optionalAccess', _189 => _189.fontName]) && af === bf && ab.width >= bb.width * 0.95 && (_nullishCoalesce(_optionalChain([a, 'access', _190 => _190.text, 'optionalAccess', _191 => _191.trim, 'call', _192 => _192(), 'access', _193 => _193.split, 'call', _194 => _194(/\s+/), 'access', _195 => _195.length]), () => ( 0))) >= 3;
|
|
5480
6338
|
const displayStack = centered && gap <= Math.min(af, bf) * 0.3 && Math.max(af, bf) <= Math.min(af, bf) * 1.45;
|
|
5481
6339
|
if (a.type !== "heading" || b.type !== "heading" || !a.text || !b.text || /^\d+$/.test(a.text.trim()) || !ab || !bb || ab.page !== bb.page || !(sameAnchor && af >= medianFontSize * 2 && bf >= medianFontSize * 2) && !wrapped && !(centered && af >= medianFontSize * 1.25 && bf >= medianFontSize * 1.25) || Math.abs(af - bf) > Math.max(af, bf) * 0.15 && !displayStack || gap < -2 || gap > Math.max(af, bf) * 0.45 || a.text.length > (centered ? 120 : 50) || b.text.length > (centered ? 120 : 50)) {
|
|
5482
6340
|
i++;
|
|
@@ -5505,25 +6363,25 @@ function detectTypographyHeadings(blocks) {
|
|
|
5505
6363
|
if (page.some((block) => block.type === "heading")) continue;
|
|
5506
6364
|
const faceWeight = /* @__PURE__ */ new Map();
|
|
5507
6365
|
for (const block of page) {
|
|
5508
|
-
if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access',
|
|
6366
|
+
if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access', _196 => _196.style, 'optionalAccess', _197 => _197.fontName])) continue;
|
|
5509
6367
|
const faces = FACE_CHARS.get(block);
|
|
5510
6368
|
if (faces) for (const [face, n] of faces) faceWeight.set(face, (_nullishCoalesce(faceWeight.get(face), () => ( 0))) + n);
|
|
5511
6369
|
else faceWeight.set(block.style.fontName, (_nullishCoalesce(faceWeight.get(block.style.fontName), () => ( 0))) + block.text.length);
|
|
5512
6370
|
}
|
|
5513
|
-
const bodyFace = _optionalChain([[...faceWeight], 'access',
|
|
6371
|
+
const bodyFace = _optionalChain([[...faceWeight], 'access', _198 => _198.sort, 'call', _199 => _199((a, b) => b[1] - a[1]), 'access', _200 => _200[0], 'optionalAccess', _201 => _201[0]]);
|
|
5514
6372
|
if (!bodyFace || (_nullishCoalesce(faceWeight.get(bodyFace), () => ( 0))) < 250) continue;
|
|
5515
6373
|
const sizeWeight = /* @__PURE__ */ new Map();
|
|
5516
6374
|
for (const block of page) {
|
|
5517
|
-
if (block.type !== "paragraph" || !_optionalChain([block, 'access',
|
|
6375
|
+
if (block.type !== "paragraph" || !_optionalChain([block, 'access', _202 => _202.style, 'optionalAccess', _203 => _203.fontSize])) continue;
|
|
5518
6376
|
const faces = FACE_CHARS.get(block);
|
|
5519
|
-
const chars = faces ? _nullishCoalesce(faces.get(bodyFace), () => ( 0)) : block.style.fontName === bodyFace ? _nullishCoalesce(_optionalChain([block, 'access',
|
|
6377
|
+
const chars = faces ? _nullishCoalesce(faces.get(bodyFace), () => ( 0)) : block.style.fontName === bodyFace ? _nullishCoalesce(_optionalChain([block, 'access', _204 => _204.text, 'optionalAccess', _205 => _205.length]), () => ( 0)) : 0;
|
|
5520
6378
|
if (chars) sizeWeight.set(block.style.fontSize, (_nullishCoalesce(sizeWeight.get(block.style.fontSize), () => ( 0))) + chars);
|
|
5521
6379
|
}
|
|
5522
|
-
const bodySize = _nullishCoalesce(_optionalChain([[...sizeWeight], 'access',
|
|
6380
|
+
const bodySize = _nullishCoalesce(_optionalChain([[...sizeWeight], 'access', _206 => _206.sort, 'call', _207 => _207((a, b) => b[1] - a[1]), 'access', _208 => _208[0], 'optionalAccess', _209 => _209[0]]), () => ( 0));
|
|
5523
6381
|
for (let i = 0; i < page.length; i++) {
|
|
5524
6382
|
const block = page[i];
|
|
5525
6383
|
const { text, bbox, style } = block;
|
|
5526
|
-
if (block.type !== "paragraph" || !text || !bbox || !_optionalChain([style, 'optionalAccess',
|
|
6384
|
+
if (block.type !== "paragraph" || !text || !bbox || !_optionalChain([style, 'optionalAccess', _210 => _210.fontName]) || !style.fontSize) continue;
|
|
5527
6385
|
const title = text.trim();
|
|
5528
6386
|
const numbered = /^\d+(?:\.\d+)*\.?\s+[A-Z가-힣]/.test(title);
|
|
5529
6387
|
const faces = FACE_CHARS.get(block);
|
|
@@ -5553,16 +6411,16 @@ function detectDocumentStyleHeadings(blocks) {
|
|
|
5553
6411
|
for (const page of byPage.values()) {
|
|
5554
6412
|
const faceChars = /* @__PURE__ */ new Map();
|
|
5555
6413
|
for (const block of page) {
|
|
5556
|
-
if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access',
|
|
6414
|
+
if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access', _211 => _211.style, 'optionalAccess', _212 => _212.fontName])) continue;
|
|
5557
6415
|
faceChars.set(block.style.fontName, (_nullishCoalesce(faceChars.get(block.style.fontName), () => ( 0))) + block.text.length);
|
|
5558
6416
|
}
|
|
5559
|
-
const bodyFace = _optionalChain([[...faceChars], 'access',
|
|
6417
|
+
const bodyFace = _optionalChain([[...faceChars], 'access', _213 => _213.sort, 'call', _214 => _214((a, b) => b[1] - a[1]), 'access', _215 => _215[0], 'optionalAccess', _216 => _216[0]]);
|
|
5560
6418
|
if (!bodyFace || (_nullishCoalesce(faceChars.get(bodyFace), () => ( 0))) < 100) continue;
|
|
5561
|
-
const labels = page.filter((b) => b.type === "paragraph" && b.text && b.bbox && _optionalChain([b, 'access',
|
|
6419
|
+
const labels = page.filter((b) => b.type === "paragraph" && b.text && b.bbox && _optionalChain([b, 'access', _217 => _217.style, 'optionalAccess', _218 => _218.fontName]) && b.style.fontName !== bodyFace && b.text.trim().length >= 3 && b.text.trim().length <= 40);
|
|
5562
6420
|
for (const label of labels) {
|
|
5563
|
-
const peers = labels.filter((b) => _optionalChain([b, 'access',
|
|
6421
|
+
const peers = labels.filter((b) => _optionalChain([b, 'access', _219 => _219.style, 'optionalAccess', _220 => _220.fontName]) === _optionalChain([label, 'access', _221 => _221.style, 'optionalAccess', _222 => _222.fontName]) && Math.abs(b.bbox.y - label.bbox.y) <= 3 && Math.abs(b.bbox.x - label.bbox.x) >= 60);
|
|
5564
6422
|
if (peers.length < 2) continue;
|
|
5565
|
-
const value = page.find((b) => b.type === "paragraph" && b.bbox && _optionalChain([b, 'access',
|
|
6423
|
+
const value = page.find((b) => b.type === "paragraph" && b.bbox && _optionalChain([b, 'access', _223 => _223.style, 'optionalAccess', _224 => _224.fontName]) !== _optionalChain([label, 'access', _225 => _225.style, 'optionalAccess', _226 => _226.fontName]) && b.bbox.x >= label.bbox.x - 5 && b.bbox.x <= label.bbox.x + 20 && b.bbox.y < label.bbox.y && label.bbox.y - (b.bbox.y + b.bbox.height) <= 60);
|
|
5566
6424
|
if (value) {
|
|
5567
6425
|
label.type = "heading";
|
|
5568
6426
|
label.level = 2;
|
|
@@ -5571,7 +6429,7 @@ function detectDocumentStyleHeadings(blocks) {
|
|
|
5571
6429
|
const first = page.find((b) => b.type !== "image" && b.type !== "separator");
|
|
5572
6430
|
const second = page[page.indexOf(first) + 1];
|
|
5573
6431
|
const third = page[page.indexOf(first) + 2];
|
|
5574
|
-
if (!first || !second || !third || first.type !== "list" && first.type !== "paragraph" || second.type !== "paragraph" || !first.text || !second.text || !first.bbox || !second.bbox || !_optionalChain([first, 'access',
|
|
6432
|
+
if (!first || !second || !third || first.type !== "list" && first.type !== "paragraph" || second.type !== "paragraph" || !first.text || !second.text || !first.bbox || !second.bbox || !_optionalChain([first, 'access', _227 => _227.style, 'optionalAccess', _228 => _228.fontName]) || !_optionalChain([second, 'access', _229 => _229.style, 'optionalAccess', _230 => _230.fontName]) || !/^\d+(?:\.\d+)*\.\s+/.test(first.text.trim()) || first.style.fontName === bodyFace || second.style.fontName === bodyFace || first.text.length + second.text.length > 140 || Math.abs(first.bbox.x - second.bbox.x) > 30 || first.bbox.y - (second.bbox.y + second.bbox.height) > (_nullishCoalesce(first.style.fontSize, () => ( 0))) * 1.5 || _optionalChain([third, 'access', _231 => _231.style, 'optionalAccess', _232 => _232.fontName]) !== bodyFace) continue;
|
|
5575
6433
|
first.type = "heading";
|
|
5576
6434
|
first.level = 1;
|
|
5577
6435
|
first.text = `${first.text.trim()} ${second.text.trim()}`;
|
|
@@ -5595,18 +6453,18 @@ function detectSiblingStyleHeadings(blocks) {
|
|
|
5595
6453
|
for (const page of byPage.values()) {
|
|
5596
6454
|
const bodyChars = /* @__PURE__ */ new Map();
|
|
5597
6455
|
for (const block of page) {
|
|
5598
|
-
if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access',
|
|
6456
|
+
if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access', _233 => _233.style, 'optionalAccess', _234 => _234.fontName])) continue;
|
|
5599
6457
|
const face = block.style.fontName;
|
|
5600
6458
|
bodyChars.set(face, (_nullishCoalesce(bodyChars.get(face), () => ( 0))) + block.text.length);
|
|
5601
6459
|
}
|
|
5602
|
-
const bodyFace = _optionalChain([[...bodyChars], 'access',
|
|
5603
|
-
const anchors = page.filter((b) => b.type === "heading" && b.text && _optionalChain([b, 'access',
|
|
6460
|
+
const bodyFace = _optionalChain([[...bodyChars], 'access', _235 => _235.sort, 'call', _236 => _236((a, b) => b[1] - a[1]), 'access', _237 => _237[0], 'optionalAccess', _238 => _238[0]]);
|
|
6461
|
+
const anchors = page.filter((b) => b.type === "heading" && b.text && _optionalChain([b, 'access', _239 => _239.style, 'optionalAccess', _240 => _240.fontName]) && b.style.fontName !== bodyFace);
|
|
5604
6462
|
for (const anchor of anchors) {
|
|
5605
6463
|
const numbered = /^([A-Z])\.\d+\s+/.exec(anchor.text.trim());
|
|
5606
6464
|
const lettered = /^([A-Z])\s+/.exec(anchor.text.trim());
|
|
5607
|
-
const peers = anchors.filter((b) => _optionalChain([b, 'access',
|
|
6465
|
+
const peers = anchors.filter((b) => _optionalChain([b, 'access', _241 => _241.style, 'optionalAccess', _242 => _242.fontName]) === _optionalChain([anchor, 'access', _243 => _243.style, 'optionalAccess', _244 => _244.fontName]) && Math.abs((_nullishCoalesce(_optionalChain([b, 'access', _245 => _245.style, 'optionalAccess', _246 => _246.fontSize]), () => ( 0))) - (_nullishCoalesce(_optionalChain([anchor, 'access', _247 => _247.style, 'optionalAccess', _248 => _248.fontSize]), () => ( 0)))) < 0.5);
|
|
5608
6466
|
if (peers.length < 2 && !numbered && !lettered) continue;
|
|
5609
|
-
const candidates = page.filter((b) => b.type === "paragraph" && b.text && b.bbox && _optionalChain([b, 'access',
|
|
6467
|
+
const candidates = page.filter((b) => b.type === "paragraph" && b.text && b.bbox && _optionalChain([b, 'access', _249 => _249.style, 'optionalAccess', _250 => _250.fontName]) === _optionalChain([anchor, 'access', _251 => _251.style, 'optionalAccess', _252 => _252.fontName]) && Math.abs((_nullishCoalesce(_optionalChain([b, 'access', _253 => _253.style, 'optionalAccess', _254 => _254.fontSize]), () => ( 0))) - (_nullishCoalesce(_optionalChain([anchor, 'access', _255 => _255.style, 'optionalAccess', _256 => _256.fontSize]), () => ( 0)))) < 0.5 && b.text.trim().length >= 3 && b.text.trim().length <= 80 && b.bbox.height <= (_nullishCoalesce(_optionalChain([b, 'access', _257 => _257.style, 'optionalAccess', _258 => _258.fontSize]), () => ( 0))) * 1.6 && /^[A-Z]/.test(b.text.trim()) && !/[.!?:;,]$/.test(b.text.trim()) && !/^(?:Table|Figure|Fig\.?|Appendix)\s+\d/i.test(b.text.trim()));
|
|
5610
6468
|
const siblings = candidates.filter((b) => numbered ? new RegExp(`^${numbered[1]}\\.\\d+\\s+`).test(b.text.trim()) : lettered ? /^[A-Z]\s+/.test(b.text.trim()) && Math.abs(anchor.bbox.x - b.bbox.x) < 8 : peers.some((h) => h.bbox && Math.abs(h.bbox.x - b.bbox.x) < 8));
|
|
5611
6469
|
if (siblings.length < (numbered || lettered ? 1 : 2)) continue;
|
|
5612
6470
|
for (const sibling of siblings) {
|
|
@@ -5625,13 +6483,13 @@ function detectRepeatedPageLabels(blocks) {
|
|
|
5625
6483
|
}
|
|
5626
6484
|
for (const page of byPage.values()) {
|
|
5627
6485
|
const bodyChars = /* @__PURE__ */ new Map();
|
|
5628
|
-
for (const b of page) if (b.type === "paragraph" && b.text && _optionalChain([b, 'access',
|
|
6486
|
+
for (const b of page) if (b.type === "paragraph" && b.text && _optionalChain([b, 'access', _259 => _259.style, 'optionalAccess', _260 => _260.fontName])) {
|
|
5629
6487
|
const faces = FACE_CHARS.get(b);
|
|
5630
6488
|
if (faces) for (const [face, n] of faces) bodyChars.set(face, (_nullishCoalesce(bodyChars.get(face), () => ( 0))) + n);
|
|
5631
6489
|
else bodyChars.set(b.style.fontName, (_nullishCoalesce(bodyChars.get(b.style.fontName), () => ( 0))) + b.text.length);
|
|
5632
6490
|
}
|
|
5633
|
-
const bodyFace = _optionalChain([[...bodyChars], 'access',
|
|
5634
|
-
const candidates = page.filter((b) => b.type === "paragraph" && b.text && b.bbox && _optionalChain([b, 'access',
|
|
6491
|
+
const bodyFace = _optionalChain([[...bodyChars], 'access', _261 => _261.sort, 'call', _262 => _262((a, b) => b[1] - a[1]), 'access', _263 => _263[0], 'optionalAccess', _264 => _264[0]]);
|
|
6492
|
+
const candidates = page.filter((b) => b.type === "paragraph" && b.text && b.bbox && _optionalChain([b, 'access', _265 => _265.style, 'optionalAccess', _266 => _266.fontName]) && b.style.fontName !== bodyFace && b.bbox.height <= (_nullishCoalesce(b.style.fontSize, () => ( 0))) * 1.6 && b.text.trim().length >= 5 && b.text.trim().length <= 80);
|
|
5635
6493
|
const groups = /* @__PURE__ */ new Map();
|
|
5636
6494
|
for (const b of candidates) {
|
|
5637
6495
|
const key = `${b.style.fontName}:${b.style.fontSize}`;
|
|
@@ -5667,19 +6525,19 @@ function detectPageLeadHeadings(blocks) {
|
|
|
5667
6525
|
for (const page of byPage.values()) {
|
|
5668
6526
|
const content = page.filter((b) => b.type !== "image" && b.type !== "separator" && !(b.type === "paragraph" && !b.style));
|
|
5669
6527
|
const [first, second, third] = content;
|
|
5670
|
-
if (!_optionalChain([first, 'optionalAccess',
|
|
6528
|
+
if (!_optionalChain([first, 'optionalAccess', _267 => _267.bbox]) || !first.text || !_optionalChain([first, 'access', _268 => _268.style, 'optionalAccess', _269 => _269.fontSize]) || !second) continue;
|
|
5671
6529
|
const firstText = first.text.trim();
|
|
5672
6530
|
const captionLike = /^(?:Figure|Fig\.?|Table|표|그림)\s*\d/i;
|
|
5673
6531
|
const hasImage = page.some((b) => b.type === "image");
|
|
5674
|
-
const firstIsTitle = first.type === "paragraph" && firstText.length >= 5 && firstText.length <= 80 && first.bbox.height <= first.style.fontSize * 1.6 && (/^(?:CONTENTS|Table of Contents)$/i.test(firstText) || hasImage && /^[A-Z]/.test(firstText) && !captionLike.test(firstText) && second.type === "paragraph" && /^[A-Z]/.test(_nullishCoalesce(_optionalChain([second, 'access',
|
|
6532
|
+
const firstIsTitle = first.type === "paragraph" && firstText.length >= 5 && firstText.length <= 80 && first.bbox.height <= first.style.fontSize * 1.6 && (/^(?:CONTENTS|Table of Contents)$/i.test(firstText) || hasImage && /^[A-Z]/.test(firstText) && !captionLike.test(firstText) && second.type === "paragraph" && /^[A-Z]/.test(_nullishCoalesce(_optionalChain([second, 'access', _270 => _270.text, 'optionalAccess', _271 => _271.trim, 'call', _272 => _272()]), () => ( ""))) && (_nullishCoalesce(_optionalChain([second, 'access', _273 => _273.text, 'optionalAccess', _274 => _274.length]), () => ( 0))) >= 100 && second.bbox && first.bbox.y - (second.bbox.y + second.bbox.height) >= first.style.fontSize);
|
|
5675
6533
|
const firstAboveProse = first.type === "paragraph" && firstText.length >= 5 && firstText.length <= 80 && first.bbox.height <= first.style.fontSize * 2 && second.type === "paragraph" && second.bbox && second.bbox.height >= first.style.fontSize * 4 && Math.abs(first.bbox.x - second.bbox.x) <= first.style.fontSize * 2 && first.bbox.y - (second.bbox.y + second.bbox.height) >= first.style.fontSize * 2 && !captionLike.test(firstText) && !/^(?:doi:|https?:|www\.)/i.test(firstText);
|
|
5676
|
-
const firstIsSection = first.type === "list" && /^\d+\.\s+[A-Z][A-Z\s]{12,}$/.test(firstText) && second.type === "paragraph" && (_nullishCoalesce(_optionalChain([second, 'access',
|
|
6534
|
+
const firstIsSection = first.type === "list" && /^\d+\.\s+[A-Z][A-Z\s]{12,}$/.test(firstText) && second.type === "paragraph" && (_nullishCoalesce(_optionalChain([second, 'access', _275 => _275.text, 'optionalAccess', _276 => _276.length]), () => ( 0))) >= 100;
|
|
5677
6535
|
if (firstIsTitle || firstAboveProse || firstIsSection) {
|
|
5678
6536
|
first.type = "heading";
|
|
5679
6537
|
first.level = 1;
|
|
5680
6538
|
}
|
|
5681
|
-
if (first.type !== "heading" || captionLike.test(firstText) || second.type !== "paragraph" || !second.text || !second.bbox || !_optionalChain([second, 'access',
|
|
5682
|
-
const distinctFace = _optionalChain([third, 'access',
|
|
6539
|
+
if (first.type !== "heading" || captionLike.test(firstText) || second.type !== "paragraph" || !second.text || !second.bbox || !_optionalChain([second, 'access', _277 => _277.style, 'optionalAccess', _278 => _278.fontName]) || !second.style.fontSize || !_optionalChain([third, 'optionalAccess', _279 => _279.text]) || !third.bbox || second.text.trim().length < 5 || second.text.trim().length > 80 || captionLike.test(second.text.trim()) || /^(?:doi:|https?:)/i.test(second.text.trim()) || second.bbox.height > second.style.fontSize * 1.6 || Math.abs(second.bbox.x - third.bbox.x) > 30) continue;
|
|
6540
|
+
const distinctFace = _optionalChain([third, 'access', _280 => _280.style, 'optionalAccess', _281 => _281.fontName]) !== second.style.fontName;
|
|
5683
6541
|
const namedContents = /^Table of Contents$/i.test(second.text.trim());
|
|
5684
6542
|
if (distinctFace && third.text.length >= 60 || namedContents) {
|
|
5685
6543
|
second.type = "heading";
|
|
@@ -5690,24 +6548,24 @@ function detectPageLeadHeadings(blocks) {
|
|
|
5690
6548
|
function refineDocumentStyleHeadings(blocks) {
|
|
5691
6549
|
const faceChars = /* @__PURE__ */ new Map();
|
|
5692
6550
|
for (const block of blocks) {
|
|
5693
|
-
if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access',
|
|
6551
|
+
if (block.type !== "paragraph" || !block.text || !_optionalChain([block, 'access', _282 => _282.style, 'optionalAccess', _283 => _283.fontName])) continue;
|
|
5694
6552
|
faceChars.set(block.style.fontName, (_nullishCoalesce(faceChars.get(block.style.fontName), () => ( 0))) + block.text.length);
|
|
5695
6553
|
}
|
|
5696
6554
|
const [bodyFace, bodyChars] = _nullishCoalesce([...faceChars].sort((a, b) => b[1] - a[1])[0], () => ( []));
|
|
5697
6555
|
if (!bodyFace || !bodyChars || bodyChars < 300) return;
|
|
5698
6556
|
for (let i = 0; i < blocks.length; i++) {
|
|
5699
6557
|
const block = blocks[i];
|
|
5700
|
-
const text = _nullishCoalesce(_optionalChain([block, 'access',
|
|
6558
|
+
const text = _nullishCoalesce(_optionalChain([block, 'access', _284 => _284.text, 'optionalAccess', _285 => _285.trim, 'call', _286 => _286()]), () => ( ""));
|
|
5701
6559
|
if (block.type === "heading" && /(?:https?:\/\/|www\.|^arxiv:|^doi:)/i.test(text)) {
|
|
5702
6560
|
block.type = "paragraph";
|
|
5703
6561
|
block.level = void 0;
|
|
5704
6562
|
continue;
|
|
5705
6563
|
}
|
|
5706
6564
|
const box = block.bbox, style = block.style;
|
|
5707
|
-
if (block.type !== "paragraph" || !box || !_optionalChain([style, 'optionalAccess',
|
|
6565
|
+
if (block.type !== "paragraph" || !box || !_optionalChain([style, 'optionalAccess', _287 => _287.fontName]) || !style.fontSize || style.fontName === bodyFace || (_nullishCoalesce(faceChars.get(style.fontName), () => ( 0))) > bodyChars * 0.25 || text.length < 3 || text.length > 70 || text.includes("\n") || box.height > style.fontSize * 1.6 || /^(?:table|figure|fig\.?|source|doi:|arxiv:|https?:|www\.|[•●○▪▫⮚*∗†])/i.test(text) || /(?:https?:\/\/|www\.|@|[=¼≪þ])/i.test(text) || /^definition\s+\d+[.:]?\s+.*\b(?:is|are|means)\b/i.test(text) || /^[\d\s.,:%+\-–]+$/.test(text)) continue;
|
|
5708
6566
|
const previous = blocks[i - 1], next = blocks[i + 1];
|
|
5709
|
-
const pb = _optionalChain([previous, 'optionalAccess',
|
|
5710
|
-
if (!pb || !nb || previous.pageNumber !== block.pageNumber || next.pageNumber !== block.pageNumber || previous.type !== "paragraph" && previous.type !== "heading" || next.type !== "paragraph" || _optionalChain([next, 'access',
|
|
6567
|
+
const pb = _optionalChain([previous, 'optionalAccess', _288 => _288.bbox]), nb = _optionalChain([next, 'optionalAccess', _289 => _289.bbox]);
|
|
6568
|
+
if (!pb || !nb || previous.pageNumber !== block.pageNumber || next.pageNumber !== block.pageNumber || previous.type !== "paragraph" && previous.type !== "heading" || next.type !== "paragraph" || _optionalChain([next, 'access', _290 => _290.style, 'optionalAccess', _291 => _291.fontName]) !== bodyFace || !next.text || next.text.length < 40 || style.fontSize < (_nullishCoalesce(next.style.fontSize, () => ( 0))) * 0.95 || pb.y - (box.y + box.height) < style.fontSize * 0.5 || box.y - (nb.y + nb.height) < 0 || box.y - (nb.y + nb.height) > style.fontSize * 2 || box.x + box.width / 2 < nb.x - 10 || box.x + box.width / 2 > nb.x + nb.width + 10) continue;
|
|
5711
6569
|
block.type = "heading";
|
|
5712
6570
|
block.level = 2;
|
|
5713
6571
|
}
|
|
@@ -5757,7 +6615,7 @@ function detectMarkerHeadings(blocks) {
|
|
|
5757
6615
|
block.level = 4;
|
|
5758
6616
|
continue;
|
|
5759
6617
|
}
|
|
5760
|
-
if (/^[가-힣]{2,6}$/.test(text) && _optionalChain([block, 'access',
|
|
6618
|
+
if (/^[가-힣]{2,6}$/.test(text) && _optionalChain([block, 'access', _292 => _292.style, 'optionalAccess', _293 => _293.fontSize])) {
|
|
5761
6619
|
const prev = blocks[i - 1];
|
|
5762
6620
|
const next = blocks[i + 1];
|
|
5763
6621
|
const prevIsStructural = !prev || prev.type === "table" || prev.type === "heading" || prev.type === "separator";
|
|
@@ -5798,7 +6656,7 @@ function detectTableCaptions(blocks) {
|
|
|
5798
6656
|
block.table.caption = blocks[i - 1].text.trim();
|
|
5799
6657
|
blocks.splice(i - 1, 1);
|
|
5800
6658
|
i--;
|
|
5801
|
-
} else if (isCaptionCandidate(blocks[i + 1], block) && _optionalChain([blocks, 'access',
|
|
6659
|
+
} else if (isCaptionCandidate(blocks[i + 1], block) && _optionalChain([blocks, 'access', _294 => _294[i + 2], 'optionalAccess', _295 => _295.type]) !== "table") {
|
|
5802
6660
|
const cap = blocks[i + 1].bbox, tbl = block.bbox;
|
|
5803
6661
|
block.table.caption = blocks[i + 1].text.trim();
|
|
5804
6662
|
if (cap && tbl && cap.y + cap.height <= tbl.y + 1) block.table.captionBelow = true;
|
|
@@ -6036,7 +6894,7 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables =
|
|
|
6036
6894
|
const bottomEntries = [];
|
|
6037
6895
|
for (let bi = 0; bi < blocks.length; bi++) {
|
|
6038
6896
|
const b = blocks[bi];
|
|
6039
|
-
const text = !tables ? _optionalChain([b, 'access',
|
|
6897
|
+
const text = !tables ? _optionalChain([b, 'access', _296 => _296.text, 'optionalAccess', _297 => _297.trim, 'call', _298 => _298()]) : b.type === "table" && b.table ? b.table.cells.flat().map((c) => c.text.trim()).filter(Boolean).join(" | ") : void 0;
|
|
6040
6898
|
if (!b.bbox || !b.pageNumber || !text) continue;
|
|
6041
6899
|
const ph = pageHeights.get(b.bbox.page) || pageHeights.get(b.pageNumber);
|
|
6042
6900
|
if (!ph) continue;
|
|
@@ -6069,7 +6927,7 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables =
|
|
|
6069
6927
|
for (const [p, count] of patternCount) {
|
|
6070
6928
|
const pages = [..._nullishCoalesce(patternPages.get(p), () => ( []))];
|
|
6071
6929
|
const span2 = pages.length ? Math.max(...pages) - Math.min(...pages) + 1 : 0;
|
|
6072
|
-
const varying = !tables && (_nullishCoalesce(_optionalChain([patternNumbers, 'access',
|
|
6930
|
+
const varying = !tables && (_nullishCoalesce(_optionalChain([patternNumbers, 'access', _299 => _299.get, 'call', _300 => _300(p), 'optionalAccess', _301 => _301.size]), () => ( 0))) > 1;
|
|
6073
6931
|
const occ = _nullishCoalesce(patternOcc.get(p), () => ( []));
|
|
6074
6932
|
const dense = pages.length >= span2 * 0.4;
|
|
6075
6933
|
const loose = looseVaryingNumber(occ, entries === topEntries) && (entries === bottomEntries || dense || tracksPages(occ));
|
|
@@ -6081,8 +6939,8 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables =
|
|
|
6081
6939
|
for (const e of entries) {
|
|
6082
6940
|
const norm = e.text.replace(/\d+/g, "#");
|
|
6083
6941
|
if (!repeatedPatterns.has(norm)) continue;
|
|
6084
|
-
const noteMark = _optionalChain([e, 'access',
|
|
6085
|
-
if (noteMark && _optionalChain([notes, 'optionalAccess',
|
|
6942
|
+
const noteMark = _optionalChain([e, 'access', _302 => _302.text, 'access', _303 => _303.match, 'call', _304 => _304(/^\d{1,3}\)/), 'optionalAccess', _305 => _305[0]]);
|
|
6943
|
+
if (noteMark && _optionalChain([notes, 'optionalAccess', _306 => _306.get, 'call', _307 => _307(e.page), 'optionalAccess', _308 => _308.marks, 'access', _309 => _309.some, 'call', _310 => _310((m) => m.mark === noteMark)])) continue;
|
|
6086
6944
|
const cand = blocks[e.blockIdx];
|
|
6087
6945
|
const cb = cand.bbox;
|
|
6088
6946
|
const tableNote = /^(?:주\s*(?:\d+\s*[).:]|[::])|(?:자료|출처)\s*[::]|\*\s+\S)/.test(e.text.replace(/ \| /g, " ")) && blocks.some((o) => {
|
|
@@ -6096,7 +6954,7 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables =
|
|
|
6096
6954
|
if (bi === e.blockIdx) continue;
|
|
6097
6955
|
const o = blocks[bi];
|
|
6098
6956
|
if (!o.bbox || o.bbox.page !== cb.page) continue;
|
|
6099
|
-
const oNorm = _optionalChain([o, 'access',
|
|
6957
|
+
const oNorm = _optionalChain([o, 'access', _311 => _311.text, 'optionalAccess', _312 => _312.trim, 'call', _313 => _313(), 'access', _314 => _314.replace, 'call', _315 => _315(/\d+/g, "#")]);
|
|
6100
6958
|
if (oNorm && repeatedPatterns.has(oNorm)) continue;
|
|
6101
6959
|
const overlap2 = Math.min(cb.y + cb.height, o.bbox.y + o.bbox.height) - Math.max(cb.y, o.bbox.y);
|
|
6102
6960
|
if (overlap2 >= cb.height * 0.5) {
|
|
@@ -6224,7 +7082,7 @@ function recordRowRules(table, cells, bbox, hs) {
|
|
|
6224
7082
|
function markImageCell(cell) {
|
|
6225
7083
|
IMAGE_CELLS.add(cell);
|
|
6226
7084
|
}
|
|
6227
|
-
var emptyCell = (cell) => !cell || !_optionalChain([cell, 'access',
|
|
7085
|
+
var emptyCell = (cell) => !cell || !_optionalChain([cell, 'access', _316 => _316.text, 'optionalAccess', _317 => _317.trim, 'call', _318 => _318()]) && !_optionalChain([cell, 'access', _319 => _319.blocks, 'optionalAccess', _320 => _320.length]) && !IMAGE_CELLS.has(cell);
|
|
6228
7086
|
function trimTable(table) {
|
|
6229
7087
|
let cols = table.cols;
|
|
6230
7088
|
while (cols > 0 && table.cells.every((row) => emptyCell(row[cols - 1]))) cols--;
|
|
@@ -6240,7 +7098,7 @@ function trimTable(table) {
|
|
|
6240
7098
|
function trimTrailingEmptyTableCols(blocks) {
|
|
6241
7099
|
for (const b of blocks) {
|
|
6242
7100
|
if (b.type !== "table" || !b.table) continue;
|
|
6243
|
-
for (const row of b.table.cells) for (const cell of row) if (_optionalChain([cell, 'access',
|
|
7101
|
+
for (const row of b.table.cells) for (const cell of row) if (_optionalChain([cell, 'access', _321 => _321.blocks, 'optionalAccess', _322 => _322.length])) trimTrailingEmptyTableCols(cell.blocks);
|
|
6244
7102
|
trimTable(b.table);
|
|
6245
7103
|
}
|
|
6246
7104
|
}
|
|
@@ -6260,7 +7118,7 @@ function mergeSliverColumns(grid, colXs, maxWidth) {
|
|
|
6260
7118
|
}
|
|
6261
7119
|
const ok = owner.every((row) => {
|
|
6262
7120
|
const o = row[c];
|
|
6263
|
-
return !!o && (o.colSpan > 1 || !o.text.trim() && !_optionalChain([o, 'access',
|
|
7121
|
+
return !!o && (o.colSpan > 1 || !o.text.trim() && !_optionalChain([o, 'access', _323 => _323.blocks, 'optionalAccess', _324 => _324.length]));
|
|
6264
7122
|
});
|
|
6265
7123
|
if (!ok) continue;
|
|
6266
7124
|
const spanning = /* @__PURE__ */ new Set();
|
|
@@ -6287,7 +7145,7 @@ var multiply = (m, t) => [
|
|
|
6287
7145
|
m[1] * t[4] + m[3] * t[5] + m[5]
|
|
6288
7146
|
];
|
|
6289
7147
|
function hollowCircle(image) {
|
|
6290
|
-
if (!_optionalChain([image, 'optionalAccess',
|
|
7148
|
+
if (!_optionalChain([image, 'optionalAccess', _325 => _325.data]) || image.width < 16 || image.width > 128 || image.height < 16 || image.height > 128 || Math.abs(image.width - image.height) > Math.min(image.width, image.height) * 0.1) return false;
|
|
6291
7149
|
const stride = image.kind === _pdfmjs.ImageKind.RGB_24BPP ? 3 : image.kind === _pdfmjs.ImageKind.RGBA_32BPP ? 4 : 0;
|
|
6292
7150
|
const { width, height, data } = image;
|
|
6293
7151
|
if (!stride || data.length < width * height * stride) return false;
|
|
@@ -6352,9 +7210,9 @@ function smallVisibleImagePaints(fnArray, argsArray) {
|
|
|
6352
7210
|
const op = fnArray[i], args = argsArray[i];
|
|
6353
7211
|
if (op === _pdfmjs.OPS.save || op === _pdfmjs.OPS.paintFormXObjectBegin) {
|
|
6354
7212
|
stack.push({ ctm, alpha, clip, unknownClip });
|
|
6355
|
-
const matrix = op === _pdfmjs.OPS.paintFormXObjectBegin ? _optionalChain([args, 'optionalAccess',
|
|
7213
|
+
const matrix = op === _pdfmjs.OPS.paintFormXObjectBegin ? _optionalChain([args, 'optionalAccess', _326 => _326[0]]) : void 0;
|
|
6356
7214
|
if (Array.isArray(matrix) && matrix.length >= 6) ctm = multiply(ctm, matrix);
|
|
6357
|
-
const bounds = op === _pdfmjs.OPS.paintFormXObjectBegin ? _optionalChain([args, 'optionalAccess',
|
|
7215
|
+
const bounds = op === _pdfmjs.OPS.paintFormXObjectBegin ? _optionalChain([args, 'optionalAccess', _327 => _327[1]]) : void 0;
|
|
6358
7216
|
if (Array.isArray(bounds) && bounds.length === 4) {
|
|
6359
7217
|
const box = rectangle(bounds[0], bounds[1], bounds[2] - bounds[0], bounds[3] - bounds[1]);
|
|
6360
7218
|
if (box && ctm[1] === 0 && ctm[2] === 0) intersectClip(box);
|
|
@@ -6362,17 +7220,17 @@ function smallVisibleImagePaints(fnArray, argsArray) {
|
|
|
6362
7220
|
}
|
|
6363
7221
|
} else if (op === _pdfmjs.OPS.restore || op === _pdfmjs.OPS.paintFormXObjectEnd) {
|
|
6364
7222
|
const state = stack.pop();
|
|
6365
|
-
ctm = _nullishCoalesce(_optionalChain([state, 'optionalAccess',
|
|
6366
|
-
alpha = _nullishCoalesce(_optionalChain([state, 'optionalAccess',
|
|
6367
|
-
clip = _nullishCoalesce(_optionalChain([state, 'optionalAccess',
|
|
6368
|
-
unknownClip = _nullishCoalesce(_optionalChain([state, 'optionalAccess',
|
|
7223
|
+
ctm = _nullishCoalesce(_optionalChain([state, 'optionalAccess', _328 => _328.ctm]), () => ( [1, 0, 0, 1, 0, 0]));
|
|
7224
|
+
alpha = _nullishCoalesce(_optionalChain([state, 'optionalAccess', _329 => _329.alpha]), () => ( 1));
|
|
7225
|
+
clip = _nullishCoalesce(_optionalChain([state, 'optionalAccess', _330 => _330.clip]), () => ( null));
|
|
7226
|
+
unknownClip = _nullishCoalesce(_optionalChain([state, 'optionalAccess', _331 => _331.unknownClip]), () => ( false));
|
|
6369
7227
|
} else if (op === _pdfmjs.OPS.setGState) {
|
|
6370
|
-
for (const [key, value] of _nullishCoalesce(_optionalChain([args, 'optionalAccess',
|
|
7228
|
+
for (const [key, value] of _nullishCoalesce(_optionalChain([args, 'optionalAccess', _332 => _332[0]]), () => ( []))) {
|
|
6371
7229
|
if (key === "ca") alpha = typeof value === "number" ? value : 0;
|
|
6372
7230
|
}
|
|
6373
7231
|
} else if (op === _pdfmjs.OPS.constructPath) {
|
|
6374
7232
|
const [operations, coordinates] = args;
|
|
6375
|
-
pathRect = pathRect === void 0 && _optionalChain([operations, 'optionalAccess',
|
|
7233
|
+
pathRect = pathRect === void 0 && _optionalChain([operations, 'optionalAccess', _333 => _333.length]) === 1 && operations[0] === _pdfmjs.OPS.rectangle && _optionalChain([coordinates, 'optionalAccess', _334 => _334.length]) >= 4 && ctm[1] === 0 && ctm[2] === 0 ? rectangle(coordinates[0], coordinates[1], coordinates[2], coordinates[3]) : null;
|
|
6376
7234
|
} else if (op === _pdfmjs.OPS.clip || op === _pdfmjs.OPS.eoClip) pendingClip = true;
|
|
6377
7235
|
else if ([
|
|
6378
7236
|
_pdfmjs.OPS.endPath,
|
|
@@ -6392,7 +7250,7 @@ function smallVisibleImagePaints(fnArray, argsArray) {
|
|
|
6392
7250
|
pendingClip = false;
|
|
6393
7251
|
pathRect = void 0;
|
|
6394
7252
|
} else if (op === _pdfmjs.OPS.transform && Array.isArray(args) && args.length >= 6) ctm = multiply(ctm, args);
|
|
6395
|
-
else if (op === _pdfmjs.OPS.paintImageXObject && typeof _optionalChain([args, 'optionalAccess',
|
|
7253
|
+
else if (op === _pdfmjs.OPS.paintImageXObject && typeof _optionalChain([args, 'optionalAccess', _335 => _335[0]]) === "string") {
|
|
6396
7254
|
if (typeof args[1] !== "number" || typeof args[2] !== "number" || args[1] < 16 || args[1] > 128 || args[2] < 16 || args[2] > 128) continue;
|
|
6397
7255
|
const box = extractImageRegions([_pdfmjs.OPS.transform, _pdfmjs.OPS.paintImageXObject], [ctm, args])[0];
|
|
6398
7256
|
if (!box || ctm[1] !== 0 || ctm[2] !== 0 || alpha < 0.99 || unknownClip || clip && (box.x1 + (box.x2 - box.x1) * 0.03 < clip.x1 || box.y1 + (box.y2 - box.y1) * 0.03 < clip.y1 || box.x2 - (box.x2 - box.x1) * 0.03 > clip.x2 || box.y2 - (box.y2 - box.y1) * 0.03 > clip.y2)) continue;
|
|
@@ -6411,14 +7269,14 @@ async function restoreImageBullets(items, page, fnArray, argsArray, shapes = /*
|
|
|
6411
7269
|
const line = items.filter((item) => !item.isHidden && item.fontSize > 0 && item.x >= box.x2 && item.x - box.x2 <= item.fontSize * 0.7 && Math.abs(item.y + item.h / 2 - (box.y1 + box.y2) / 2) <= item.fontSize * 0.4 && height >= item.fontSize * 0.5 && height <= item.fontSize * 1.2).sort((a, b) => a.x - b.x)[0];
|
|
6412
7270
|
if (!line || /^[○●•◦□■∙]/.test(line.text.trim()) || !/\p{L}/u.test(line.text)) continue;
|
|
6413
7271
|
const row = items.filter((item) => Math.abs(item.y - line.y) <= 2 && item.x >= line.x);
|
|
6414
|
-
if (row.reduce((n, item) => n + (_nullishCoalesce(_optionalChain([item, 'access',
|
|
7272
|
+
if (row.reduce((n, item) => n + (_nullishCoalesce(_optionalChain([item, 'access', _336 => _336.text, 'access', _337 => _337.match, 'call', _338 => _338(/\p{L}/gu), 'optionalAccess', _339 => _339.length]), () => ( 0))), 0) < 12 || items.some((item) => item !== line && Math.abs(item.y - line.y) <= 2 && item.x < line.x)) continue;
|
|
6415
7273
|
candidates.push({ id, x: box.x1, width, line });
|
|
6416
7274
|
}
|
|
6417
7275
|
let restored = 0;
|
|
6418
7276
|
const used = /* @__PURE__ */ new Set();
|
|
6419
7277
|
for (const candidate of candidates) {
|
|
6420
7278
|
const same = candidates.filter((other) => other.id === candidate.id && other.line !== candidate.line && Math.abs(other.line.x - candidate.line.x) <= 1 && Math.abs(other.x - candidate.x) <= 1 && Math.abs(other.width - candidate.width) <= 1 && other.line.fontSize === candidate.line.fontSize && Math.abs(other.line.y - candidate.line.y) >= candidate.line.fontSize * 2);
|
|
6421
|
-
const numbered = items.filter((item) => !item.isHidden && /^[①-⑮]\s*/.test(item.text.trim()) && item.fontName === candidate.line.fontName && item.fontSize === candidate.line.fontSize && Math.abs(item.x - candidate.x) <= 1 && (_nullishCoalesce(_optionalChain([item, 'access',
|
|
7279
|
+
const numbered = items.filter((item) => !item.isHidden && /^[①-⑮]\s*/.test(item.text.trim()) && item.fontName === candidate.line.fontName && item.fontSize === candidate.line.fontSize && Math.abs(item.x - candidate.x) <= 1 && (_nullishCoalesce(_optionalChain([item, 'access', _340 => _340.text, 'access', _341 => _341.match, 'call', _342 => _342(/\p{L}/gu), 'optionalAccess', _343 => _343.length]), () => ( 0))) >= 12).sort((a, b) => b.y - a.y);
|
|
6422
7280
|
const numberedList = numbered.some((item, index) => index > 0 && item.text.trim().charCodeAt(0) === numbered[index - 1].text.trim().charCodeAt(0) + 1);
|
|
6423
7281
|
if (!same.length && !numberedList || used.has(candidate.line)) continue;
|
|
6424
7282
|
if (!shapes.has(candidate.id)) shapes.set(candidate.id, hollowCircle(await resolveImagePixels(page, candidate.id)));
|
|
@@ -6484,7 +7342,7 @@ function groupFlowBoxUnits(blocks, grids, hs, vs, images) {
|
|
|
6484
7342
|
return units;
|
|
6485
7343
|
}
|
|
6486
7344
|
function arrowDirection(image) {
|
|
6487
|
-
if (!_optionalChain([image, 'optionalAccess',
|
|
7345
|
+
if (!_optionalChain([image, 'optionalAccess', _344 => _344.data]) || image.width < 16 || image.width > 128 || image.height < 16 || image.height > 128) return 0;
|
|
6488
7346
|
const { width, height, data } = image;
|
|
6489
7347
|
const stride = image.kind === _pdfmjs.ImageKind.RGB_24BPP ? 3 : image.kind === _pdfmjs.ImageKind.RGBA_32BPP ? 4 : 0;
|
|
6490
7348
|
if (!stride || data.length < width * height * stride) return 0;
|
|
@@ -6552,7 +7410,7 @@ function isSideTabTable(box, table, others, pageWidth, pageHeight) {
|
|
|
6552
7410
|
function removeSideTabs(blocks, pageWidths) {
|
|
6553
7411
|
const edges = /* @__PURE__ */ new Map();
|
|
6554
7412
|
for (const b of blocks) {
|
|
6555
|
-
if (!b.bbox || b.pageNumber === void 0 || [..._nullishCoalesce(_optionalChain([b, 'access',
|
|
7413
|
+
if (!b.bbox || b.pageNumber === void 0 || [..._nullishCoalesce(_optionalChain([b, 'access', _345 => _345.text, 'optionalAccess', _346 => _346.trim, 'call', _347 => _347()]), () => ( ""))].length <= MAX_CHARS) continue;
|
|
6556
7414
|
const e = _nullishCoalesce(edges.get(b.pageNumber), () => ( { lefts: [], rights: [] }));
|
|
6557
7415
|
e.lefts.push(b.bbox.x);
|
|
6558
7416
|
e.rights.push(b.bbox.x + b.bbox.width);
|
|
@@ -6568,7 +7426,7 @@ function removeSideTabs(blocks, pageWidths) {
|
|
|
6568
7426
|
const fallback = all.length ? { left: q(all.map((e) => e.left), 0.5), right: q(all.map((e) => e.right), 0.5) } : void 0;
|
|
6569
7427
|
const key = (b) => {
|
|
6570
7428
|
const w = b.pageNumber !== void 0 ? pageWidths.get(b.pageNumber) : void 0;
|
|
6571
|
-
const text = _optionalChain([b, 'access',
|
|
7429
|
+
const text = _optionalChain([b, 'access', _348 => _348.text, 'optionalAccess', _349 => _349.trim, 'call', _350 => _350()]);
|
|
6572
7430
|
const area = _nullishCoalesce((b.pageNumber !== void 0 ? body.get(b.pageNumber) : void 0), () => ( fallback));
|
|
6573
7431
|
if (b.type === "table") {
|
|
6574
7432
|
if (!w || !b.bbox || !b.table || !SIDE_TAB_TABLES.has(b.table)) return null;
|
|
@@ -7004,16 +7862,16 @@ function isProseSpread(items) {
|
|
|
7004
7862
|
for (let i = 1; i < sorted.length; i++) {
|
|
7005
7863
|
gaps.push(sorted[i].x - (sorted[i - 1].x + sorted[i - 1].w));
|
|
7006
7864
|
}
|
|
7007
|
-
const maxGap =
|
|
7865
|
+
const maxGap = _chunkC3BOYTY5cjs.safeMax.call(void 0, gaps);
|
|
7008
7866
|
const avgLen = items.reduce((s, i) => s + i.text.length, 0) / items.length;
|
|
7009
7867
|
if (items.length >= 4 && maxGap < 40 && avgLen < 5) return true;
|
|
7010
|
-
const minGap =
|
|
7868
|
+
const minGap = _chunkC3BOYTY5cjs.safeMin.call(void 0, gaps);
|
|
7011
7869
|
return minGap > 0 && maxGap - minGap <= Math.max(2, maxGap * 0.15) && (items.filter((i) => /^\P{L}*\p{Ll}/u.test(i.text)).length * 2 >= items.length || items.some((i) => /\p{L}[,.;:]["”’)]?$/u.test(i.text)));
|
|
7012
7870
|
}
|
|
7013
7871
|
function detectColumns(yLines) {
|
|
7014
7872
|
const allItems = yLines.flat();
|
|
7015
7873
|
if (allItems.length === 0) return null;
|
|
7016
|
-
const pageWidth =
|
|
7874
|
+
const pageWidth = _chunkC3BOYTY5cjs.safeMax.call(void 0, allItems.map((i) => i.x + i.w)) - _chunkC3BOYTY5cjs.safeMin.call(void 0, allItems.map((i) => i.x));
|
|
7017
7875
|
if (pageWidth < 100) return null;
|
|
7018
7876
|
let bigoLineIdx = -1;
|
|
7019
7877
|
for (let i = 0; i < yLines.length; i++) {
|
|
@@ -7238,7 +8096,7 @@ var UNDER_BOX_PAIR_MAX_EM = 2.2;
|
|
|
7238
8096
|
var UNDER_BOX_PAIR_OVERLAP = 0.8;
|
|
7239
8097
|
function markUnderlineItems(items, horizontals, verticals, nonRules) {
|
|
7240
8098
|
const underlines = [];
|
|
7241
|
-
if (_optionalChain([nonRules, 'optionalAccess',
|
|
8099
|
+
if (_optionalChain([nonRules, 'optionalAccess', _351 => _351.size])) horizontals = horizontals.filter((line) => !nonRules.has(line));
|
|
7242
8100
|
if (items.length === 0 || horizontals.length === 0) return underlines;
|
|
7243
8101
|
const tightOwners = /* @__PURE__ */ new Map();
|
|
7244
8102
|
const tightlyOwned = (line) => {
|
|
@@ -7344,7 +8202,7 @@ function hasBoxTopPair(line, maxH, horizontals, cellItems) {
|
|
|
7344
8202
|
if (ow <= 0) continue;
|
|
7345
8203
|
const overlap2 = Math.min(line.x2, o.x2) - Math.max(line.x1, o.x1);
|
|
7346
8204
|
if (overlap2 / Math.max(w, ow) < UNDER_BOX_PAIR_OVERLAP) continue;
|
|
7347
|
-
const covered = _nullishCoalesce(_optionalChain([cellItems, 'optionalAccess',
|
|
8205
|
+
const covered = _nullishCoalesce(_optionalChain([cellItems, 'optionalAccess', _352 => _352.reduce, 'call', _353 => _353((sum, item) => {
|
|
7348
8206
|
const below = item.y - o.y1;
|
|
7349
8207
|
if (below < 0.5 || below > 3 || !item.text.trim()) return sum;
|
|
7350
8208
|
return sum + Math.max(0, Math.min(o.x2, item.x + item.w) - Math.max(o.x1, item.x));
|
|
@@ -7411,13 +8269,13 @@ function partTex(group) {
|
|
|
7411
8269
|
const base = Math.min(...g.filter((i) => i.fontSize >= size * SCRIPT_SIZE_RATIO).map((i) => i.y));
|
|
7412
8270
|
let s = "", run = "";
|
|
7413
8271
|
const flush = () => {
|
|
7414
|
-
if (run) s +=
|
|
8272
|
+
if (run) s += _chunkNW2CKOFLcjs.toTex.call(void 0, run);
|
|
7415
8273
|
run = "";
|
|
7416
8274
|
};
|
|
7417
8275
|
g.forEach((it, k) => {
|
|
7418
8276
|
if (it.fontSize < size * SCRIPT_SIZE_RATIO && it.y - base >= size * SCRIPT_RISE_EM) {
|
|
7419
8277
|
flush();
|
|
7420
|
-
s += `^{${
|
|
8278
|
+
s += `^{${_chunkNW2CKOFLcjs.toTex.call(void 0, it.text)}}`;
|
|
7421
8279
|
return;
|
|
7422
8280
|
}
|
|
7423
8281
|
if (k && it.x - (g[k - 1].x + g[k - 1].w) > spaceGapThreshold(it.fontSize)) run += " ";
|
|
@@ -7589,12 +8447,12 @@ function rebuildUnitLine(items, grid) {
|
|
|
7589
8447
|
function prependUnitRow(cells, cols, line, usedItems) {
|
|
7590
8448
|
const text = cleanCellText(line.map((item) => item.text).join(""));
|
|
7591
8449
|
cells.unshift(Array.from({ length: cols }, (_, c) => ({ text: c === 0 ? text : "", colSpan: c === 0 ? cols : 1, rowSpan: 1 })));
|
|
7592
|
-
for (const cell of cells[0])
|
|
8450
|
+
for (const cell of cells[0]) _chunkNW2CKOFLcjs.CELL_EDGES.set(cell, NO_EDGES);
|
|
7593
8451
|
for (const item of line) usedItems.add(item);
|
|
7594
8452
|
}
|
|
7595
8453
|
function attachUnitRow(items, grid, cells, cols, usedItems) {
|
|
7596
8454
|
const all = cells.flat();
|
|
7597
|
-
if (all.filter((c) => c.text.trim()).length * 2 < all.length || UNIT.test(_nullishCoalesce(_optionalChain([cells, 'access',
|
|
8455
|
+
if (all.filter((c) => c.text.trim()).length * 2 < all.length || UNIT.test(_nullishCoalesce(_optionalChain([cells, 'access', _354 => _354[0], 'optionalAccess', _355 => _355[0], 'optionalAccess', _356 => _356.text]), () => ( "")))) return false;
|
|
7598
8456
|
const above = items.filter((it) => !usedItems.has(it) && it.y >= grid.bbox.y2 && it.y - grid.bbox.y2 <= 8 && it.x >= grid.bbox.x1 - 3 && it.x + it.w <= grid.bbox.x2 + 3);
|
|
7599
8457
|
let nearest = Infinity;
|
|
7600
8458
|
for (const it of above) nearest = Math.min(nearest, it.y);
|
|
@@ -7629,7 +8487,7 @@ function closeShadedTableEdges(clipGrids, horizontals, verticals, fillRects) {
|
|
|
7629
8487
|
let hs = horizontals, vs = verticals;
|
|
7630
8488
|
const restored = [];
|
|
7631
8489
|
for (const grid of clipGrids) {
|
|
7632
|
-
if (grid.clipParent || grid.rowYs.length !== 2 || grid.colXs.length < 3 || !_optionalChain([grid, 'access',
|
|
8490
|
+
if (grid.clipParent || grid.rowYs.length !== 2 || grid.colXs.length < 3 || !_optionalChain([grid, 'access', _357 => _357.cells, 'optionalAccess', _358 => _358.length]) || grid.cells.some((c) => c.filler || c.rowSpan !== 1 || c.colSpan !== 1)) continue;
|
|
7633
8491
|
const { x1, x2, y1: mid, y2: top } = grid.bbox;
|
|
7634
8492
|
if (!grid.cells.every((c) => fillRects.some((f) => near2(f.x1, c.bbox.x1) && near2(f.x2, c.bbox.x2) && near2(f.y1, c.bbox.y1) && near2(f.y2, c.bbox.y2)))) continue;
|
|
7635
8493
|
const topRule = hs.find((h) => near2(h.y1, top) && near2(h.x1, x1) && near2(h.x2, x2));
|
|
@@ -8093,7 +8951,7 @@ function takeFrameSpanningText(items, cutX, pageNum, lex) {
|
|
|
8093
8951
|
const rows = groupByY([...items].sort((a, b) => b.y - a.y || a.x - b.x)).map((line) => {
|
|
8094
8952
|
const runs = [];
|
|
8095
8953
|
for (const item of [...line].sort((a, b) => a.x - b.x)) {
|
|
8096
|
-
const run = runs[runs.length - 1], prev = _optionalChain([run, 'optionalAccess',
|
|
8954
|
+
const run = runs[runs.length - 1], prev = _optionalChain([run, 'optionalAccess', _359 => _359[run.length - 1]]);
|
|
8097
8955
|
if (prev && item.x - (prev.x + prev.w) <= Math.max(prev.fontSize, item.fontSize) * 0.6) run.push(item);
|
|
8098
8956
|
else runs.push([item]);
|
|
8099
8957
|
}
|
|
@@ -8137,7 +8995,7 @@ function groupFrameParagraphUnits(units, frames) {
|
|
|
8137
8995
|
for (const unit of units) for (const block of unit) source.set(block, unit);
|
|
8138
8996
|
const members = /* @__PURE__ */ new Map(), emitted = /* @__PURE__ */ new Set();
|
|
8139
8997
|
for (const frame of frames) {
|
|
8140
|
-
if (frame.length < 2 || frame.some((block) => block.type !== "paragraph" || _optionalChain([source, 'access',
|
|
8998
|
+
if (frame.length < 2 || frame.some((block) => block.type !== "paragraph" || _optionalChain([source, 'access', _360 => _360.get, 'call', _361 => _361(block), 'optionalAccess', _362 => _362.length]) !== 1)) continue;
|
|
8141
8999
|
for (const block of frame) members.set(block, frame);
|
|
8142
9000
|
}
|
|
8143
9001
|
const out = [];
|
|
@@ -8150,7 +9008,7 @@ function groupFrameParagraphUnits(units, frames) {
|
|
|
8150
9008
|
}
|
|
8151
9009
|
}
|
|
8152
9010
|
for (const unit of out) {
|
|
8153
|
-
if (unit.length < 2 || _optionalChain([FRAME_READING_UNITS, 'access',
|
|
9011
|
+
if (unit.length < 2 || _optionalChain([FRAME_READING_UNITS, 'access', _363 => _363.get, 'call', _364 => _364(unit[0]), 'optionalAccess', _365 => _365.blocks]) === unit) continue;
|
|
8154
9012
|
const bs = unit.map((b) => b.bbox).filter((b) => !!b);
|
|
8155
9013
|
if (bs.length !== unit.length) continue;
|
|
8156
9014
|
const x = Math.min(...bs.map((b) => b.x)), y = Math.min(...bs.map((b) => b.y));
|
|
@@ -8167,14 +9025,14 @@ function groupFrameParagraphUnits(units, frames) {
|
|
|
8167
9025
|
function recordFrameTitle(table, source, pageNum) {
|
|
8168
9026
|
if (!CLIP_TABLES.has(table) || table.rows !== 1 || table.cols !== 3 || source.length < 2) return;
|
|
8169
9027
|
const cells = table.cells[0];
|
|
8170
|
-
if (cells.length !== 3 || cells.some((c) => c.colSpan !== 1 || c.rowSpan !== 1 || _optionalChain([c, 'access',
|
|
9028
|
+
if (cells.length !== 3 || cells.some((c) => c.colSpan !== 1 || c.rowSpan !== 1 || _optionalChain([c, 'access', _366 => _366.blocks, 'optionalAccess', _367 => _367.length]) || c.text.includes("\n"))) return;
|
|
8171
9029
|
const [label, spacer, title] = cells;
|
|
8172
9030
|
if (!/^(?:붙임|별첨|첨부|부록)\s*\d{1,3}$/.test(label.text.trim()) || spacer.text.trim() || !title.text.trim()) return;
|
|
8173
9031
|
if (cells.some((c) => {
|
|
8174
|
-
const e =
|
|
9032
|
+
const e = _chunkNW2CKOFLcjs.CELL_EDGES.get(c);
|
|
8175
9033
|
return !e || e.t || e.b || e.l || e.r;
|
|
8176
9034
|
})) return;
|
|
8177
|
-
const xs = TABLE_COLXS.get(table), style = dominantStyle(source), fs = _nullishCoalesce(_optionalChain([style, 'optionalAccess',
|
|
9035
|
+
const xs = TABLE_COLXS.get(table), style = dominantStyle(source), fs = _nullishCoalesce(_optionalChain([style, 'optionalAccess', _368 => _368.fontSize]), () => ( 0));
|
|
8178
9036
|
if (!xs || xs.length !== 4 || fs <= 0) return;
|
|
8179
9037
|
const width = xs[3] - xs[0], gap = xs[2] - xs[1];
|
|
8180
9038
|
if (width < fs * 12 || gap <= 0 || gap > fs * 1.5 || xs[1] - xs[0] > width * 0.25 || xs[3] - xs[2] < width * 0.6) return;
|
|
@@ -8232,7 +9090,7 @@ function extendNestedShadedHeaders(clipGrids, lineGrids, horizontals, verticals,
|
|
|
8232
9090
|
const extended = [];
|
|
8233
9091
|
for (let i = 0; i < clipGrids.length; i++) {
|
|
8234
9092
|
const c = clipGrids[i], parent = c.clipParent;
|
|
8235
|
-
if (!parent || c.rowYs.length !== 2 || c.colXs.length < 3 || !_optionalChain([c, 'access',
|
|
9093
|
+
if (!parent || c.rowYs.length !== 2 || c.colXs.length < 3 || !_optionalChain([c, 'access', _369 => _369.cells, 'optionalAccess', _370 => _370.length]) || c.cells.some((cell) => cell.filler || cell.rowSpan !== 1 || cell.colSpan !== 1)) continue;
|
|
8236
9094
|
if (!clipGrids.some((g) => g.rowYs.length === 2 && g.colXs.length === 2 && near2(g.bbox.x1, parent.x1) && near2(g.bbox.x2, parent.x2) && near2(g.bbox.y1, parent.y1) && near2(g.bbox.y2, parent.y2))) continue;
|
|
8237
9095
|
if (!c.cells.every((cell) => fills.some((f) => near2(f.x1, cell.bbox.x1) && near2(f.x2, cell.bbox.x2) && near2(f.y1, cell.bbox.y1) && near2(f.y2, cell.bbox.y2)))) continue;
|
|
8238
9096
|
const host = lineGrids.find((l) => l.rowYs.length > 2 && l.colXs.length === c.colXs.length && c.colXs.every((x, k) => near2(x, l.colXs[k])) && c.rowYs.every((y, k) => near2(y, l.rowYs[k])) && contains4(parent, l.bbox) && l.rowYs.every((y) => horizontals.some((h) => near2(h.y1, y) && near2(h.x1, l.bbox.x1) && near2(h.x2, l.bbox.x2))) && l.colXs.every((x) => verticals.some((v) => near2(v.x1, x) && v.y1 <= l.bbox.y1 + 1.5 && v.y2 >= l.bbox.y2 - 1.5)) && !clipGrids.some((o) => o !== c && !contains4(o.bbox, l.bbox) && Math.min(o.bbox.x2, l.bbox.x2) > Math.max(o.bbox.x1, l.bbox.x1) && Math.min(o.bbox.y2, l.bbox.y2) > Math.max(o.bbox.y1, l.bbox.y1)));
|
|
@@ -8255,7 +9113,7 @@ function attachSideTabBlocks(tab, body, pageNum) {
|
|
|
8255
9113
|
bbox: computeBBox(items, pageNum),
|
|
8256
9114
|
style: dominantStyle(items)
|
|
8257
9115
|
});
|
|
8258
|
-
const prefix = ordered.filter((g) => !_optionalChain([caps, 'optionalAccess',
|
|
9116
|
+
const prefix = ordered.filter((g) => !_optionalChain([caps, 'optionalAccess', _371 => _371.has, 'call', _372 => _372(g)])).map((g) => ({
|
|
8259
9117
|
type: "paragraph",
|
|
8260
9118
|
text: g.text.trim(),
|
|
8261
9119
|
pageNumber: pageNum,
|
|
@@ -8264,7 +9122,7 @@ function attachSideTabBlocks(tab, body, pageNum) {
|
|
|
8264
9122
|
}));
|
|
8265
9123
|
const groups = /* @__PURE__ */ new Map();
|
|
8266
9124
|
for (const g of ordered) {
|
|
8267
|
-
const cap = _optionalChain([caps, 'optionalAccess',
|
|
9125
|
+
const cap = _optionalChain([caps, 'optionalAccess', _373 => _373.get, 'call', _374 => _374(g)]);
|
|
8268
9126
|
if (cap) groups.set(cap, [..._nullishCoalesce(groups.get(cap), () => ( [])), g]);
|
|
8269
9127
|
}
|
|
8270
9128
|
for (const [cap, glyphs] of groups) {
|
|
@@ -8298,7 +9156,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
8298
9156
|
const filled = fillBlanks(items, horizontals, verticals);
|
|
8299
9157
|
items = filled.items;
|
|
8300
9158
|
horizontals = filled.horizontals;
|
|
8301
|
-
const prevPage = _optionalChain([carry, 'optionalAccess',
|
|
9159
|
+
const prevPage = _optionalChain([carry, 'optionalAccess', _375 => _375.page]) === pageNum - 1 ? carry.clip : void 0;
|
|
8302
9160
|
const clipResult = detectTables ? buildClipCellGrids(extracted.clipRects, horizontals, verticals, pageWidth, pageHeight, items.map((it) => ({ x: it.x + it.w / 2, y: it.y + it.h / 2 })), extracted.fillRects, prevPage) : { grids: [], containers: [], page: void 0 };
|
|
8303
9161
|
if (carry) {
|
|
8304
9162
|
carry.page = pageNum;
|
|
@@ -8555,14 +9413,14 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
8555
9413
|
if (!assignedItems.has(textItems[ti])) usedItems.delete(owners[ti]);
|
|
8556
9414
|
}
|
|
8557
9415
|
}
|
|
8558
|
-
if (unitLine.length > 0 && rebuiltUsed && !/^\s*\(\s*단위\s*[::]/.test(_nullishCoalesce(_optionalChain([finalGrid, 'access',
|
|
9416
|
+
if (unitLine.length > 0 && rebuiltUsed && !/^\s*\(\s*단위\s*[::]/.test(_nullishCoalesce(_optionalChain([finalGrid, 'access', _376 => _376[0], 'optionalAccess', _377 => _377[0], 'optionalAccess', _378 => _378.text]), () => ( "")))) {
|
|
8559
9417
|
prependUnitRow(finalGrid, numCols, unitLine, usedItems);
|
|
8560
9418
|
finalRows++;
|
|
8561
9419
|
}
|
|
8562
9420
|
if (!rebuiltUsed && attachUnitRow(items, grid, finalGrid, numCols, usedItems)) finalRows++;
|
|
8563
9421
|
let semanticOneColumn = false;
|
|
8564
9422
|
if (!grid.cells && !nestedAttached && numCols === 1 && numGridRows >= 2) {
|
|
8565
|
-
const populatedRows = finalGrid.filter((row) => _optionalChain([row, 'access',
|
|
9423
|
+
const populatedRows = finalGrid.filter((row) => _optionalChain([row, 'access', _379 => _379[0], 'optionalAccess', _380 => _380.text, 'access', _381 => _381.trim, 'call', _382 => _382()]));
|
|
8566
9424
|
if (populatedRows.length >= 4) {
|
|
8567
9425
|
const fontSizes = tableItems.map((item) => item.fontSize).filter((size) => size > 0).sort((a, b) => a - b);
|
|
8568
9426
|
const medianFont = _nullishCoalesce(fontSizes[Math.floor(fontSizes.length / 2)], () => ( 0));
|
|
@@ -8658,7 +9516,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
8658
9516
|
height: grid.bbox.y2 - grid.bbox.y1
|
|
8659
9517
|
};
|
|
8660
9518
|
if (numRows === 1 && numCols === 1 && gridW < pageWidth * 0.35) {
|
|
8661
|
-
const prose = _nullishCoalesce(_optionalChain([finalGrid, 'access',
|
|
9519
|
+
const prose = _nullishCoalesce(_optionalChain([finalGrid, 'access', _383 => _383[0], 'optionalAccess', _384 => _384[0], 'optionalAccess', _385 => _385.text]), () => ( ""));
|
|
8662
9520
|
const besideLines = (side) => new Set(side.map((it) => Math.round(it.y / 3))).size;
|
|
8663
9521
|
const rightLines = items.filter((it) => it.x >= grid.bbox.x2 + 3 && it.y >= grid.bbox.y1 && it.y <= grid.bbox.y2);
|
|
8664
9522
|
const leftLines = items.filter((it) => it.x + it.w <= grid.bbox.x1 - 3 && it.y >= grid.bbox.y1 && it.y <= grid.bbox.y2);
|
|
@@ -8677,8 +9535,8 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
8677
9535
|
}
|
|
8678
9536
|
}
|
|
8679
9537
|
if (!grid.cells && !nestedAttached && shouldDemoteTable(irTable)) {
|
|
8680
|
-
const paragraphs = numRows === 1 && numCols === 1 ? _optionalChain([irTable, 'access',
|
|
8681
|
-
if (_optionalChain([paragraphs, 'optionalAccess',
|
|
9538
|
+
const paragraphs = numRows === 1 && numCols === 1 ? _optionalChain([irTable, 'access', _386 => _386.cells, 'access', _387 => _387[0], 'optionalAccess', _388 => _388[0], 'optionalAccess', _389 => _389.blocks]) : void 0;
|
|
9539
|
+
if (_optionalChain([paragraphs, 'optionalAccess', _390 => _390.length])) {
|
|
8682
9540
|
blocks.push(...paragraphs);
|
|
8683
9541
|
frameParagraphUnits.push(paragraphs);
|
|
8684
9542
|
recordFrameReadingUnit(paragraphs, tableBbox);
|
|
@@ -8705,23 +9563,27 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
8705
9563
|
let panels = null;
|
|
8706
9564
|
if (remaining.length > 0) {
|
|
8707
9565
|
remaining.sort((a, b) => b.y - a.y || a.x - b.x);
|
|
8708
|
-
const clusterItems = remaining.map((i) =>
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
9566
|
+
const clusterItems = remaining.map((i) => {
|
|
9567
|
+
const item = {
|
|
9568
|
+
text: i.text,
|
|
9569
|
+
x: i.x,
|
|
9570
|
+
y: i.y,
|
|
9571
|
+
w: i.w,
|
|
9572
|
+
h: i.h,
|
|
9573
|
+
fontSize: i.fontSize,
|
|
9574
|
+
fontName: i.fontName,
|
|
9575
|
+
hasSpaceBefore: i.hasSpaceBefore,
|
|
9576
|
+
syntheticSpace: i.syntheticSpace,
|
|
9577
|
+
spaceAfter: i.spaceAfter
|
|
9578
|
+
};
|
|
9579
|
+
copyOcrTextGaps(i, item);
|
|
9580
|
+
return item;
|
|
9581
|
+
});
|
|
8720
9582
|
const proseColumns = findTwoColumnProseCutX(clusterItems) !== null || detectPersistentColumnGutter(remaining.map((i) => ({ x: i.x, y: i.y, w: i.w, h: i.h > 0 ? i.h : i.fontSize }))) !== null;
|
|
8721
9583
|
const clusterResults = (proseColumns ? [] : detectClusterTables(clusterItems, pageNum, void 0, lex)).filter((cr) => {
|
|
8722
9584
|
const b = cr.bbox;
|
|
8723
9585
|
const overlapX = (x) => Math.min(x.x + x.width, b.x + b.width) - Math.max(x.x, b.x);
|
|
8724
|
-
return !blocks.some((x) => x.bbox && x.bbox.y >= b.y - 2 && x.bbox.y + x.bbox.height <= b.y + b.height + 2 && (x.type === "paragraph" ? (_nullishCoalesce(_optionalChain([x, 'access',
|
|
9586
|
+
return !blocks.some((x) => x.bbox && x.bbox.y >= b.y - 2 && x.bbox.y + x.bbox.height <= b.y + b.height + 2 && (x.type === "paragraph" ? (_nullishCoalesce(_optionalChain([x, 'access', _391 => _391.text, 'optionalAccess', _392 => _392.match, 'call', _393 => _393(/\p{L}/gu), 'optionalAccess', _394 => _394.length]), () => ( 0))) >= 10 && overlapX(x.bbox) >= 0.8 * b.width : x.type === "table" && !ocrPage && _optionalChain([x, 'access', _395 => _395.table, 'optionalAccess', _396 => _396.cols]) === cr.table.cols && overlapX(x.bbox) >= 0.5 * Math.min(x.bbox.width, b.width)));
|
|
8725
9587
|
});
|
|
8726
9588
|
if (clusterResults.length > 0) {
|
|
8727
9589
|
const ciToIdx = /* @__PURE__ */ new Map();
|
|
@@ -8758,7 +9620,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
8758
9620
|
groupSizes.push(1);
|
|
8759
9621
|
}
|
|
8760
9622
|
const allY = remaining.map((i) => i.y);
|
|
8761
|
-
const pageH =
|
|
9623
|
+
const pageH = _chunkC3BOYTY5cjs.safeMax.call(void 0, allY) - _chunkC3BOYTY5cjs.safeMin.call(void 0, allY);
|
|
8762
9624
|
const gapThreshold = Math.max(15, pageH * 0.03);
|
|
8763
9625
|
const sides = frameColumnTextBands(remaining, spanning, gx);
|
|
8764
9626
|
const textBlocks = [];
|
|
@@ -8774,7 +9636,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
8774
9636
|
finalTextBlocks.push(...detectListBlocks(textBlocks));
|
|
8775
9637
|
} else {
|
|
8776
9638
|
const allY = remaining.map((i) => i.y);
|
|
8777
|
-
const pageH =
|
|
9639
|
+
const pageH = _chunkC3BOYTY5cjs.safeMax.call(void 0, allY) - _chunkC3BOYTY5cjs.safeMin.call(void 0, allY);
|
|
8778
9640
|
const gapThreshold = Math.max(15, pageH * 0.03);
|
|
8779
9641
|
const groups = xyCutOrder(remaining, gapThreshold);
|
|
8780
9642
|
const textBlocks = [];
|
|
@@ -9032,18 +9894,22 @@ function extractPageBlocksFallback(items, pageNum, fullPage = false, detectTable
|
|
|
9032
9894
|
if (cards) return cards.flatMap((group) => extractPageBlocksFallback(group, pageNum, false, detectTables, lex));
|
|
9033
9895
|
}
|
|
9034
9896
|
const blocks = [];
|
|
9035
|
-
const clusterItems = items.map((i) =>
|
|
9036
|
-
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
|
|
9043
|
-
|
|
9044
|
-
|
|
9045
|
-
|
|
9046
|
-
|
|
9897
|
+
const clusterItems = items.map((i) => {
|
|
9898
|
+
const item = {
|
|
9899
|
+
text: i.text,
|
|
9900
|
+
x: i.x,
|
|
9901
|
+
y: i.y,
|
|
9902
|
+
w: i.w,
|
|
9903
|
+
h: i.h,
|
|
9904
|
+
fontSize: i.fontSize,
|
|
9905
|
+
fontName: i.fontName,
|
|
9906
|
+
hasSpaceBefore: i.hasSpaceBefore,
|
|
9907
|
+
syntheticSpace: i.syntheticSpace,
|
|
9908
|
+
spaceAfter: i.spaceAfter
|
|
9909
|
+
};
|
|
9910
|
+
copyOcrTextGaps(i, item);
|
|
9911
|
+
return item;
|
|
9912
|
+
});
|
|
9047
9913
|
const textRects = items.map((i) => ({ x: i.x, y: i.y, w: i.w, h: i.h > 0 ? i.h : i.fontSize }));
|
|
9048
9914
|
const imagePanels = fullPage ? splitImagePanels(items, figures) : null;
|
|
9049
9915
|
if (imagePanels) return imagePanels.flatMap((group) => extractPageBlocksFallback(group, pageNum, false, detectTables, lex));
|
|
@@ -9102,7 +9968,7 @@ function extractPageBlocksFallback(items, pageNum, fullPage = false, detectTable
|
|
|
9102
9968
|
blocks.push(...columnTextToBlocks(tableText, pageNum, bbox, dominantStyle(items)));
|
|
9103
9969
|
} else {
|
|
9104
9970
|
const allY = items.map((i) => i.y);
|
|
9105
|
-
const pageHeight =
|
|
9971
|
+
const pageHeight = _chunkC3BOYTY5cjs.safeMax.call(void 0, allY) - _chunkC3BOYTY5cjs.safeMin.call(void 0, allY);
|
|
9106
9972
|
const gapThreshold = Math.max(15, pageHeight * 0.03);
|
|
9107
9973
|
const orderedGroups = proseCutX !== null ? splitTwoColumnProse(items, proseCutX) : xyCutOrder(items, gapThreshold, 0, void 0, minGap);
|
|
9108
9974
|
for (const group of orderedGroups) {
|
|
@@ -9134,19 +10000,19 @@ function mergeOcrImageRegions(blocks, page, regions, ocrBlocks) {
|
|
|
9134
10000
|
const overlapH = Math.max(0, Math.min(b.y + b.height, region.y2) - Math.max(b.y, region.y1));
|
|
9135
10001
|
return overlapW * overlapH >= b.width * b.height * 0.8;
|
|
9136
10002
|
});
|
|
9137
|
-
const labels = candidates.filter((b) => b.type === "paragraph" && b.bbox.height <= 24 && (_nullishCoalesce(_optionalChain([b, 'access',
|
|
10003
|
+
const labels = candidates.filter((b) => b.type === "paragraph" && b.bbox.height <= 24 && (_nullishCoalesce(_optionalChain([b, 'access', _397 => _397.text, 'optionalAccess', _398 => _398.match, 'call', _399 => _399(/[\p{L}\p{N}]/gu), 'optionalAccess', _400 => _400.length]), () => ( 0))) >= 2);
|
|
9138
10004
|
const axisFragments = rotatedAxisFragments(candidates);
|
|
9139
10005
|
const accepted = candidates.filter((b) => {
|
|
9140
|
-
if (b.type === "paragraph") return (_nullishCoalesce(_optionalChain([b, 'access',
|
|
10006
|
+
if (b.type === "paragraph") return (_nullishCoalesce(_optionalChain([b, 'access', _401 => _401.text, 'optionalAccess', _402 => _402.match, 'call', _403 => _403(/[\p{L}\p{N}]/gu), 'optionalAccess', _404 => _404.length]), () => ( 0))) >= 2 || !axisFragments.has(b) && (supportedDiagramLabel(b, labels, region) || axisTick(b, candidates));
|
|
9141
10007
|
const t = b.table;
|
|
9142
10008
|
if (b.type !== "table" || !t || UNRULED_REGION_TABLES.has(b)) return false;
|
|
9143
10009
|
const lone = t.cells.filter((row) => row.filter((c) => c.text.trim()).length === 1 && row.some((c) => c.colSpan === t.cols)).length;
|
|
9144
10010
|
if (t.rows >= 2 && lone * 2 >= t.rows) return false;
|
|
9145
10011
|
if (t.rows === 1 && t.cols === 1) {
|
|
9146
|
-
const text = _nullishCoalesce(_optionalChain([t, 'access',
|
|
9147
|
-
return (_nullishCoalesce(_optionalChain([text, 'access',
|
|
10012
|
+
const text = _nullishCoalesce(_optionalChain([t, 'access', _405 => _405.cells, 'access', _406 => _406[0], 'optionalAccess', _407 => _407[0], 'optionalAccess', _408 => _408.text]), () => ( ""));
|
|
10013
|
+
return (_nullishCoalesce(_optionalChain([text, 'access', _409 => _409.match, 'call', _410 => _410(/\n/g), 'optionalAccess', _411 => _411.length]), () => ( 0))) >= 5 && (_nullishCoalesce(_optionalChain([text, 'access', _412 => _412.match, 'call', _413 => _413(/\d/g), 'optionalAccess', _414 => _414.length]), () => ( 0))) >= text.length * 0.25;
|
|
9148
10014
|
}
|
|
9149
|
-
const headerLabels = _nullishCoalesce(_optionalChain([t, 'access',
|
|
10015
|
+
const headerLabels = _nullishCoalesce(_optionalChain([t, 'access', _415 => _415.cells, 'access', _416 => _416[0], 'optionalAccess', _417 => _417.filter, 'call', _418 => _418((c) => c.text.replace(/[^A-Za-z가-힣]/g, "").length >= 2), 'access', _419 => _419.length]), () => ( 0));
|
|
9150
10016
|
return t.rows >= 2 && t.cols >= 2 && headerLabels >= t.cols * 0.75 && t.cells.slice(1).some((row) => row.filter((c) => c.text.trim()).length >= 2);
|
|
9151
10017
|
});
|
|
9152
10018
|
const selected = candidates.flatMap((b) => accepted.includes(b) ? [b] : b.type === "table" && b.table ? rowParagraphs(b).filter((p) => /[\p{L}\p{N}]{2}/u.test(_nullishCoalesce(p.text, () => ( "")))) : []);
|
|
@@ -9163,14 +10029,14 @@ function mergeOcrImageRegions(blocks, page, regions, ocrBlocks) {
|
|
|
9163
10029
|
for (const block of selected) {
|
|
9164
10030
|
if (seen2.has(block)) continue;
|
|
9165
10031
|
const frame = FRAME_READING_UNITS.get(block);
|
|
9166
|
-
const source = _optionalChain([frame, 'optionalAccess',
|
|
10032
|
+
const source = _optionalChain([frame, 'optionalAccess', _420 => _420.blocks, 'access', _421 => _421.every, 'call', _422 => _422((member) => selectedSet.has(member))]) ? frame.blocks : [block];
|
|
9167
10033
|
source.forEach((member) => seen2.add(member));
|
|
9168
10034
|
const available = source.filter((member) => !hasOriginal(member));
|
|
9169
10035
|
const units = frame && available.length === source.length && source === frame.blocks ? [{ blocks: available, bbox: frame.bbox, atomic: true }] : available.map((member) => ({ blocks: [member], bbox: member.bbox, atomic: false }));
|
|
9170
10036
|
for (const unit of units) {
|
|
9171
10037
|
const b = unit.bbox;
|
|
9172
10038
|
const index = blocks.findIndex((existing) => {
|
|
9173
|
-
const e = _nullishCoalesce(_optionalChain([FRAME_READING_UNITS, 'access',
|
|
10039
|
+
const e = _nullishCoalesce(_optionalChain([FRAME_READING_UNITS, 'access', _423 => _423.get, 'call', _424 => _424(existing), 'optionalAccess', _425 => _425.bbox]), () => ( existing.bbox));
|
|
9174
10040
|
if (existing.pageNumber !== page || !e) return false;
|
|
9175
10041
|
const beside = e.y < region.y2 && e.y + e.height > region.y1 && e.x >= region.x2 - 1;
|
|
9176
10042
|
if (placedHere.has(existing) && Math.abs(e.y + e.height / 2 - b.y - b.height / 2) <= Math.min(e.height, b.height) * 0.25) return e.x > b.x;
|
|
@@ -9188,16 +10054,16 @@ function mergeOcrImageRegions(blocks, page, regions, ocrBlocks) {
|
|
|
9188
10054
|
}
|
|
9189
10055
|
function axisTick(block, candidates) {
|
|
9190
10056
|
const b = block.bbox;
|
|
9191
|
-
if (!/^\d$/u.test(_nullishCoalesce(_optionalChain([block, 'access',
|
|
9192
|
-
const numeric = candidates.filter((o) => o !== block && o.type === "paragraph" && o.bbox && /^[\d\s.,%+−-]+$/u.test(_nullishCoalesce(_optionalChain([o, 'access',
|
|
10057
|
+
if (!/^\d$/u.test(_nullishCoalesce(_optionalChain([block, 'access', _426 => _426.text, 'optionalAccess', _427 => _427.trim, 'call', _428 => _428()]), () => ( "")))) return false;
|
|
10058
|
+
const numeric = candidates.filter((o) => o !== block && o.type === "paragraph" && o.bbox && /^[\d\s.,%+−-]+$/u.test(_nullishCoalesce(_optionalChain([o, 'access', _429 => _429.text, 'optionalAccess', _430 => _430.trim, 'call', _431 => _431()]), () => ( ""))) && /\d/u.test(_nullishCoalesce(o.text, () => ( ""))) && Math.max(o.bbox.height, b.height) <= Math.min(o.bbox.height, b.height) * 2);
|
|
9193
10059
|
const cy = b.y + b.height / 2, right = b.x + b.width;
|
|
9194
10060
|
const row = numeric.filter((o) => Math.abs(o.bbox.y + o.bbox.height / 2 - cy) <= Math.min(o.bbox.height, b.height) * 0.35);
|
|
9195
10061
|
const column = numeric.filter((o) => Math.abs(o.bbox.x + o.bbox.width - right) <= Math.max(o.bbox.height, b.height) * 0.5);
|
|
9196
10062
|
return row.length >= 2 || column.length >= 2;
|
|
9197
10063
|
}
|
|
9198
10064
|
function supportedDiagramLabel(block, labels, region) {
|
|
9199
|
-
const b = block.bbox, text = _nullishCoalesce(_optionalChain([block, 'access',
|
|
9200
|
-
if (!b || !/^[\p{L}\p{N}]$/u.test(text) || b.height < 4 || b.width < 1 || b.width > b.height * 2 || b.x < region.x1 || b.y < region.y1 || b.x + b.width > region.x2 || b.y + b.height > region.y2 || b.width * b.height > (region.x2 - region.x1) * (region.y2 - region.y1) * 5e-3 || labels.length < 3 || !labels.some((l) => /\p{L}{3}/u.test(_nullishCoalesce(l.text, () => ( "")))) || labels.filter((l) => !/\p{L}/u.test(_nullishCoalesce(l.text, () => ( ""))) && (_nullishCoalesce(_optionalChain([l, 'access',
|
|
10065
|
+
const b = block.bbox, text = _nullishCoalesce(_optionalChain([block, 'access', _432 => _432.text, 'optionalAccess', _433 => _433.trim, 'call', _434 => _434()]), () => ( ""));
|
|
10066
|
+
if (!b || !/^[\p{L}\p{N}]$/u.test(text) || b.height < 4 || b.width < 1 || b.width > b.height * 2 || b.x < region.x1 || b.y < region.y1 || b.x + b.width > region.x2 || b.y + b.height > region.y2 || b.width * b.height > (region.x2 - region.x1) * (region.y2 - region.y1) * 5e-3 || labels.length < 3 || !labels.some((l) => /\p{L}{3}/u.test(_nullishCoalesce(l.text, () => ( "")))) || labels.filter((l) => !/\p{L}/u.test(_nullishCoalesce(l.text, () => ( ""))) && (_nullishCoalesce(_optionalChain([l, 'access', _435 => _435.text, 'optionalAccess', _436 => _436.match, 'call', _437 => _437(/\p{N}/gu), 'optionalAccess', _438 => _438.length]), () => ( 0))) >= 2).length < 2) return false;
|
|
9201
10067
|
let above = false, below = false;
|
|
9202
10068
|
for (const label of labels) {
|
|
9203
10069
|
const a = label.bbox, em = Math.max(b.height, a.height);
|
|
@@ -9212,7 +10078,7 @@ function rotatedAxisFragments(candidates) {
|
|
|
9212
10078
|
const paragraphs = candidates.filter((b) => b.type === "paragraph" && b.bbox.height <= 24);
|
|
9213
10079
|
const axes = [];
|
|
9214
10080
|
for (const block of paragraphs) {
|
|
9215
|
-
const b = block.bbox, text = _nullishCoalesce(_optionalChain([block, 'access',
|
|
10081
|
+
const b = block.bbox, text = _nullishCoalesce(_optionalChain([block, 'access', _439 => _439.text, 'optionalAccess', _440 => _440.trim, 'call', _441 => _441()]), () => ( ""));
|
|
9216
10082
|
if (!/^[\d\s.,%+−-]+$/u.test(text) || !/\d/u.test(text) || b.width > b.height * 6) continue;
|
|
9217
10083
|
const axis = axes.find((a) => Math.abs(a[0].bbox.x + a[0].bbox.width - b.x - b.width) <= Math.max(a[0].bbox.height, b.height) * 0.5);
|
|
9218
10084
|
if (axis) axis.push(block);
|
|
@@ -9229,8 +10095,8 @@ function rotatedAxisFragments(candidates) {
|
|
|
9229
10095
|
const em = Math.max(...axis.map((a) => a.bbox.height)), right = axis[0].bbox.x + axis[0].bbox.width;
|
|
9230
10096
|
if (top - bottom < em * 6) continue;
|
|
9231
10097
|
const left = paragraphs.filter((block) => {
|
|
9232
|
-
const b = block.bbox, text = _nullishCoalesce(_optionalChain([block, 'access',
|
|
9233
|
-
return /\p{Script=Latin}/u.test(text) && (_nullishCoalesce(_optionalChain([text, 'access',
|
|
10098
|
+
const b = block.bbox, text = _nullishCoalesce(_optionalChain([block, 'access', _442 => _442.text, 'optionalAccess', _443 => _443.trim, 'call', _444 => _444()]), () => ( ""));
|
|
10099
|
+
return /\p{Script=Latin}/u.test(text) && (_nullishCoalesce(_optionalChain([text, 'access', _445 => _445.match, 'call', _446 => _446(/[\p{L}\p{N}]/gu), 'optionalAccess', _447 => _447.length]), () => ( 0))) <= 3 && b.width <= b.height * 3 && b.x + b.width >= right - em * 6 && b.x + b.width <= right - Math.max(em, b.height) && b.y >= bottom && b.y + b.height <= top;
|
|
9234
10100
|
});
|
|
9235
10101
|
const stack = left.filter((a) => left.some((b) => {
|
|
9236
10102
|
if (a === b || !aligned(a, b)) return false;
|
|
@@ -9240,7 +10106,7 @@ function rotatedAxisFragments(candidates) {
|
|
|
9240
10106
|
if (stack.length < 2) continue;
|
|
9241
10107
|
for (const block of paragraphs) {
|
|
9242
10108
|
const b = block.bbox;
|
|
9243
|
-
if (b.y >= bottom && b.y + b.height <= top && b.x + b.width >= right - em * 6 && b.x + b.width <= right - Math.max(em, b.height) && /^[\p{L}\p{N}]$/u.test(_nullishCoalesce(_optionalChain([block, 'access',
|
|
10109
|
+
if (b.y >= bottom && b.y + b.height <= top && b.x + b.width >= right - em * 6 && b.x + b.width <= right - Math.max(em, b.height) && /^[\p{L}\p{N}]$/u.test(_nullishCoalesce(_optionalChain([block, 'access', _448 => _448.text, 'optionalAccess', _449 => _449.trim, 'call', _450 => _450()]), () => ( ""))) && stack.some((s) => aligned(s, block))) fragments.add(block);
|
|
9244
10110
|
}
|
|
9245
10111
|
}
|
|
9246
10112
|
return fragments;
|
|
@@ -9317,5 +10183,28 @@ function rowParagraphs(block) {
|
|
|
9317
10183
|
|
|
9318
10184
|
|
|
9319
10185
|
|
|
9320
|
-
|
|
9321
|
-
|
|
10186
|
+
|
|
10187
|
+
|
|
10188
|
+
|
|
10189
|
+
|
|
10190
|
+
|
|
10191
|
+
|
|
10192
|
+
|
|
10193
|
+
|
|
10194
|
+
|
|
10195
|
+
|
|
10196
|
+
|
|
10197
|
+
|
|
10198
|
+
|
|
10199
|
+
|
|
10200
|
+
|
|
10201
|
+
|
|
10202
|
+
|
|
10203
|
+
|
|
10204
|
+
|
|
10205
|
+
|
|
10206
|
+
|
|
10207
|
+
|
|
10208
|
+
|
|
10209
|
+
exports.DEFAULT_OCR_MODELS = DEFAULT_OCR_MODELS; exports.resolveOcrModels = resolveOcrModels; exports.ocrSelectionKey = ocrSelectionKey; exports.ocrSourcePath = ocrSourcePath; exports.ensureOcrModelsFor = ensureOcrModelsFor; exports.ocrModelsCached = ocrModelsCached; exports.parseCharacterDict = parseCharacterDict; exports.grayCrop = grayCrop; exports.inkStats = inkStats; exports.splitRowBands = splitRowBands; exports.leadingTriangle = leadingTriangle; exports.leaderRuns = leaderRuns; exports.inkBounds = inkBounds; exports.bracketFeatures = bracketFeatures; exports.romanStems = romanStems; exports.circledAt = circledAt; exports.quoteHead = quoteHead; exports.edgeTrim = edgeTrim; exports.tallInkCount = tallInkCount; exports.gapGlyphs = gapGlyphs; exports.ringBullet = ringBullet; exports.dashRatio = dashRatio; exports.discAt = discAt; exports.serifOne = serifOne; exports.starRun = starRun; exports.bracketShape = bracketShape; exports.leadingBullet = leadingBullet; exports.rememberOcrTextGaps = rememberOcrTextGaps; exports.copyOcrTextGaps = copyOcrTextGaps; exports.findOcrTextGaps = findOcrTextGaps; exports.extractLines = extractLines; exports.extractImageRegions = extractImageRegions; exports.NO_EDGES = NO_EDGES; exports.hasOpenCellSeam = hasOpenCellSeam; exports.joinCellEdges = joinCellEdges; exports.filterHiddenText = filterHiddenText; exports.collapseEvenSpacing = collapseEvenSpacing; exports.computeBBox = computeBBox; exports.dominantStyle = dominantStyle; exports.normalizeItems = normalizeItems; exports.groupByY = groupByY; exports.mergeLineSimple = mergeLineSimple; exports.WrapLexicon = WrapLexicon; exports.startsNewItem = startsNewItem; exports.wrapJoiner = wrapJoiner; exports.joinPageBreakWraps = joinPageBreakWraps; exports.splitPageBreakWraps = splitPageBreakWraps; exports.latinSoftWrap = latinSoftWrap; exports.TOC_BLOCKS = TOC_BLOCKS; exports.computeMedianFontSizeFromFreq = computeMedianFontSizeFromFreq; exports.detectHeadings = detectHeadings; exports.mergeStackedHeadingLines = mergeStackedHeadingLines; exports.detectTypographyHeadings = detectTypographyHeadings; exports.detectDocumentStyleHeadings = detectDocumentStyleHeadings; exports.detectSiblingStyleHeadings = detectSiblingStyleHeadings; exports.detectRepeatedPageLabels = detectRepeatedPageLabels; exports.detectPageLeadHeadings = detectPageLeadHeadings; exports.refineDocumentStyleHeadings = refineDocumentStyleHeadings; exports.detectMarkerHeadings = detectMarkerHeadings; exports.detectTableCaptions = detectTableCaptions; exports.detectKoreanListBlocks = detectKoreanListBlocks; exports.removeHeaderFooterBlocks = removeHeaderFooterBlocks; exports.runningLinePatterns = runningLinePatterns; exports.stripAbsorbedRunningLines = stripAbsorbedRunningLines; exports.CLIP_TABLES = CLIP_TABLES; exports.FRAME_TITLE_BLOCKS = FRAME_TITLE_BLOCKS; exports.TABLE_COLXS = TABLE_COLXS; exports.TABLE_ROWYS = TABLE_ROWYS; exports.TABLE_TAIL = TABLE_TAIL; exports.PART_COLXS = PART_COLXS; exports.EMPTY_PARTS = EMPTY_PARTS; exports.IMAGE_CELLS = IMAGE_CELLS; exports.FILLER_CELLS = FILLER_CELLS; exports.CONT_PARTS = CONT_PARTS; exports.CELL_LINES = CELL_LINES; exports.ROW_RULES = ROW_RULES; exports.trimTrailingEmptyTableCols = trimTrailingEmptyTableCols; exports.restoreImageBullets = restoreImageBullets; exports.detectRightArrowRegions = detectRightArrowRegions; exports.removeSideTabs = removeSideTabs; exports.extractPageBlocksWithLines = extractPageBlocksWithLines; exports.UNRULED_REGION_TABLES = UNRULED_REGION_TABLES; exports.mergeOcrImageRegions = mergeOcrImageRegions;
|
|
10210
|
+
//# sourceMappingURL=chunk-73MRAQXA.cjs.map
|