kordoc 4.15.6 → 4.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -9
- package/dist/{-F73GANY7.js → -VQNLLLPE.js} +11 -11
- package/dist/{chunk-UKD7C2WS.js → chunk-3JWMDL3S.js} +5 -4
- package/dist/chunk-3JWMDL3S.js.map +1 -0
- package/dist/{chunk-FWT24USP.js → chunk-43FKGDDO.js} +354 -135
- package/dist/chunk-43FKGDDO.js.map +1 -0
- package/dist/{chunk-KJKMBV5K.js → chunk-46DZF3RK.js} +5 -4
- package/dist/chunk-46DZF3RK.js.map +1 -0
- package/dist/{chunk-NK5XFKL4.js → chunk-476OYHGZ.js} +24 -7
- package/dist/chunk-476OYHGZ.js.map +1 -0
- package/dist/{chunk-QC736WXT.js → chunk-6LMKQM7I.js} +3 -3
- package/dist/{chunk-U7J7BFV3.js → chunk-A3QDRMVD.js} +2 -2
- package/dist/{chunk-SQJ7Q2Q5.cjs → chunk-B5NEGP65.cjs} +61 -76
- package/dist/chunk-B5NEGP65.cjs.map +1 -0
- package/dist/{chunk-OQ3DY7RF.js → chunk-C75WE52C.js} +2 -2
- package/dist/{chunk-FA5JIHUV.js → chunk-CB5XDCSL.js} +272 -74
- package/dist/chunk-CB5XDCSL.js.map +1 -0
- package/dist/{chunk-2DLW4CMC.cjs → chunk-DRY3L5KQ.cjs} +57 -61
- package/dist/chunk-DRY3L5KQ.cjs.map +1 -0
- package/dist/{chunk-2OKMF2KY.js → chunk-DYENR3PX.js} +2 -2
- package/dist/{chunk-UGIESTA6.js → chunk-GOQBON77.js} +10 -2
- package/dist/{chunk-UGIESTA6.js.map → chunk-GOQBON77.js.map} +1 -1
- package/dist/{chunk-QJX4IR77.cjs → chunk-H6KMTYYZ.cjs} +3 -3
- package/dist/{chunk-QJX4IR77.cjs.map → chunk-H6KMTYYZ.cjs.map} +1 -1
- package/dist/{chunk-RSKR6A6S.js → chunk-HIVK5V27.js} +428 -128
- package/dist/chunk-HIVK5V27.js.map +1 -0
- package/dist/{chunk-ISJRNC2G.js → chunk-JB5X5NNL.js} +50 -12
- package/dist/chunk-JB5X5NNL.js.map +1 -0
- package/dist/{chunk-SOM7JIKG.cjs → chunk-MH6MAL64.cjs} +468 -168
- package/dist/chunk-MH6MAL64.cjs.map +1 -0
- package/dist/{chunk-DRQW5SYI.js → chunk-N6TPODYL.js} +15 -2
- package/dist/chunk-N6TPODYL.js.map +1 -0
- package/dist/{chunk-A63JPQEE.js → chunk-NNYF2AGC.js} +45 -49
- package/dist/chunk-NNYF2AGC.js.map +1 -0
- package/dist/{chunk-FBZCWSPN.cjs → chunk-NWODPYBD.cjs} +11 -3
- package/dist/chunk-NWODPYBD.cjs.map +1 -0
- package/dist/{chunk-765SAMGS.js → chunk-PIMB2YNO.js} +2 -2
- package/dist/{chunk-HT2TGO46.js → chunk-PQRP4NSF.js} +2 -2
- package/dist/{chunk-U6SS43O6.js → chunk-QJERJZJ6.js} +1 -1
- package/dist/chunk-QJERJZJ6.js.map +1 -0
- package/dist/{chunk-JX7URXOL.js → chunk-RC4C7Q33.js} +10 -2
- package/dist/{chunk-JX7URXOL.js.map → chunk-RC4C7Q33.js.map} +1 -1
- package/dist/{chunk-O6A6SK55.js → chunk-TGD7UFHD.js} +45 -49
- package/dist/chunk-TGD7UFHD.js.map +1 -0
- package/dist/{chunk-6OQTREJ5.js → chunk-UDX7TSOC.js} +2 -2
- package/dist/{chunk-3PDCVDSO.js → chunk-UQ6TZDW6.js} +1 -1
- package/dist/chunk-UQ6TZDW6.js.map +1 -0
- package/dist/{chunk-WXEXWGPT.js → chunk-XHOZB2WP.js} +59 -71
- package/dist/chunk-XHOZB2WP.js.map +1 -0
- package/dist/{chunk-CND4NRNF.cjs → chunk-ZY5K3LPM.cjs} +1 -1
- package/dist/chunk-ZY5K3LPM.cjs.map +1 -0
- package/dist/chunks-JD25E5PM.js +10 -0
- package/dist/cli.js +62 -39
- package/dist/cli.js.map +1 -1
- package/dist/{formula-HU2APQRR.js → formula-5775PTP2.js} +4 -4
- package/dist/{formula-P54CLKTH.js → formula-FNQYHMIY.js} +3 -3
- package/dist/{formula-LWU5I4NX.cjs → formula-VEFKYXPB.cjs} +9 -9
- package/dist/{formula-LWU5I4NX.cjs.map → formula-VEFKYXPB.cjs.map} +1 -1
- package/dist/{image-ocr-RCM3KL27.cjs → image-ocr-6JZR734G.cjs} +17 -15
- package/dist/image-ocr-6JZR734G.cjs.map +1 -0
- package/dist/{image-ocr-2UCO6DQD.js → image-ocr-PYZU4TO7.js} +14 -9
- package/dist/image-ocr-PYZU4TO7.js.map +1 -0
- package/dist/{image-ocr-I62V7QB2.js → image-ocr-YA2MQBRP.js} +9 -11
- package/dist/image-ocr-YA2MQBRP.js.map +1 -0
- package/dist/index.cjs +967 -751
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +301 -85
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +67 -50
- package/dist/mcp.js.map +1 -1
- package/dist/{model-bundle-MSYSZSDJ.js → model-bundle-O6J7ORVC.js} +5 -5
- package/dist/{models-BCUGEIQX.js → models-YMOKZGCI.js} +7 -5
- package/dist/{parser-SI4DSZ6J.js → parser-3B6I2XL7.js} +854 -39
- package/dist/parser-3B6I2XL7.js.map +1 -0
- package/dist/{parser-KZDC4LLY.js → parser-PXATL5DM.js} +850 -38
- package/dist/parser-PXATL5DM.js.map +1 -0
- package/dist/{parser-M26S76U2.cjs → parser-YAQV7FBO.cjs} +962 -150
- package/dist/parser-YAQV7FBO.cjs.map +1 -0
- package/dist/pdf-ocr-2TTO5PX2.js +15 -0
- package/dist/pdf-ocr-T2JXQATA.cjs +16 -0
- package/dist/{pdf-ocr-IOQA7ZQM.cjs.map → pdf-ocr-T2JXQATA.cjs.map} +1 -1
- package/dist/pdf-ocr-WF2NQA6X.js +18 -0
- package/dist/{profile-io-QHKLJKAM.js → profile-io-ZTV2MKRT.js} +3 -3
- package/dist/{rasterize-JY72CIBX.js → rasterize-MMUZ537K.js} +3 -3
- package/dist/{redact-doc-BWS4KRNH.js → redact-doc-S42XGV5D.js} +11 -11
- package/dist/{render-53DA6GD5.js → render-WCWPZKJ7.js} +7 -7
- package/dist/seal-WHK4GOHR.js +10 -0
- package/dist/{setup-GHLZX5VK.js → setup-D35LKZCH.js} +3 -3
- package/dist/visual-WL4TDE5B.js +20 -0
- package/dist/{watch-SYDX4ZLX.js → watch-AX64CIMN.js} +41 -19
- package/dist/watch-AX64CIMN.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-2DLW4CMC.cjs.map +0 -1
- package/dist/chunk-3PDCVDSO.js.map +0 -1
- package/dist/chunk-A63JPQEE.js.map +0 -1
- package/dist/chunk-CND4NRNF.cjs.map +0 -1
- package/dist/chunk-DRQW5SYI.js.map +0 -1
- package/dist/chunk-FA5JIHUV.js.map +0 -1
- package/dist/chunk-FBZCWSPN.cjs.map +0 -1
- package/dist/chunk-FWT24USP.js.map +0 -1
- package/dist/chunk-ISJRNC2G.js.map +0 -1
- package/dist/chunk-KJKMBV5K.js.map +0 -1
- package/dist/chunk-NK5XFKL4.js.map +0 -1
- package/dist/chunk-O6A6SK55.js.map +0 -1
- package/dist/chunk-RSKR6A6S.js.map +0 -1
- package/dist/chunk-SOM7JIKG.cjs.map +0 -1
- package/dist/chunk-SQJ7Q2Q5.cjs.map +0 -1
- package/dist/chunk-U6SS43O6.js.map +0 -1
- package/dist/chunk-UKD7C2WS.js.map +0 -1
- package/dist/chunk-WXEXWGPT.js.map +0 -1
- package/dist/chunks-RJXLSR5O.js +0 -10
- package/dist/image-ocr-2UCO6DQD.js.map +0 -1
- package/dist/image-ocr-I62V7QB2.js.map +0 -1
- package/dist/image-ocr-RCM3KL27.cjs.map +0 -1
- package/dist/parser-KZDC4LLY.js.map +0 -1
- package/dist/parser-M26S76U2.cjs.map +0 -1
- package/dist/parser-SI4DSZ6J.js.map +0 -1
- package/dist/pdf-ocr-IOQA7ZQM.cjs +0 -16
- package/dist/pdf-ocr-KA6BQTAB.js +0 -18
- package/dist/pdf-ocr-TPTWVV57.js +0 -15
- package/dist/seal-TJX6N5EE.js +0 -10
- package/dist/visual-JSTROEWO.js +0 -20
- package/dist/watch-SYDX4ZLX.js.map +0 -1
- /package/dist/{-F73GANY7.js.map → -VQNLLLPE.js.map} +0 -0
- /package/dist/{chunk-QC736WXT.js.map → chunk-6LMKQM7I.js.map} +0 -0
- /package/dist/{chunk-U7J7BFV3.js.map → chunk-A3QDRMVD.js.map} +0 -0
- /package/dist/{chunk-OQ3DY7RF.js.map → chunk-C75WE52C.js.map} +0 -0
- /package/dist/{chunk-2OKMF2KY.js.map → chunk-DYENR3PX.js.map} +0 -0
- /package/dist/{chunk-765SAMGS.js.map → chunk-PIMB2YNO.js.map} +0 -0
- /package/dist/{chunk-HT2TGO46.js.map → chunk-PQRP4NSF.js.map} +0 -0
- /package/dist/{chunk-6OQTREJ5.js.map → chunk-UDX7TSOC.js.map} +0 -0
- /package/dist/{chunks-RJXLSR5O.js.map → chunks-JD25E5PM.js.map} +0 -0
- /package/dist/{formula-HU2APQRR.js.map → formula-5775PTP2.js.map} +0 -0
- /package/dist/{formula-P54CLKTH.js.map → formula-FNQYHMIY.js.map} +0 -0
- /package/dist/{model-bundle-MSYSZSDJ.js.map → model-bundle-O6J7ORVC.js.map} +0 -0
- /package/dist/{models-BCUGEIQX.js.map → models-YMOKZGCI.js.map} +0 -0
- /package/dist/{pdf-ocr-KA6BQTAB.js.map → pdf-ocr-2TTO5PX2.js.map} +0 -0
- /package/dist/{pdf-ocr-TPTWVV57.js.map → pdf-ocr-WF2NQA6X.js.map} +0 -0
- /package/dist/{profile-io-QHKLJKAM.js.map → profile-io-ZTV2MKRT.js.map} +0 -0
- /package/dist/{rasterize-JY72CIBX.js.map → rasterize-MMUZ537K.js.map} +0 -0
- /package/dist/{redact-doc-BWS4KRNH.js.map → redact-doc-S42XGV5D.js.map} +0 -0
- /package/dist/{render-53DA6GD5.js.map → render-WCWPZKJ7.js.map} +0 -0
- /package/dist/{seal-TJX6N5EE.js.map → seal-WHK4GOHR.js.map} +0 -0
- /package/dist/{setup-GHLZX5VK.js.map → setup-D35LKZCH.js.map} +0 -0
- /package/dist/{visual-JSTROEWO.js.map → visual-WL4TDE5B.js.map} +0 -0
|
@@ -3,76 +3,14 @@ import {
|
|
|
3
3
|
HEADING_RATIO_H1,
|
|
4
4
|
HEADING_RATIO_H2,
|
|
5
5
|
HEADING_RATIO_H3
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-UQ6TZDW6.js";
|
|
7
7
|
import {
|
|
8
8
|
safeMax,
|
|
9
9
|
safeMin
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
|
|
12
|
-
// src/pdf/image-regions.ts
|
|
13
|
-
import { OPS } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
14
|
-
function multiplyTransform(m, t) {
|
|
15
|
-
return [
|
|
16
|
-
m[0] * t[0] + m[2] * t[1],
|
|
17
|
-
m[1] * t[0] + m[3] * t[1],
|
|
18
|
-
m[0] * t[2] + m[2] * t[3],
|
|
19
|
-
m[1] * t[2] + m[3] * t[3],
|
|
20
|
-
m[0] * t[4] + m[2] * t[5] + m[4],
|
|
21
|
-
m[1] * t[4] + m[3] * t[5] + m[5]
|
|
22
|
-
];
|
|
23
|
-
}
|
|
24
|
-
function extractImageRegions(fnArray, argsArray) {
|
|
25
|
-
const regions = [];
|
|
26
|
-
let ctm = [1, 0, 0, 1, 0, 0];
|
|
27
|
-
const stack = [];
|
|
28
|
-
for (let i = 0; i < fnArray.length; i++) {
|
|
29
|
-
const op = fnArray[i];
|
|
30
|
-
switch (op) {
|
|
31
|
-
case OPS.save:
|
|
32
|
-
stack.push(ctm);
|
|
33
|
-
break;
|
|
34
|
-
case OPS.restore:
|
|
35
|
-
ctm = stack.pop() || [1, 0, 0, 1, 0, 0];
|
|
36
|
-
break;
|
|
37
|
-
case OPS.transform: {
|
|
38
|
-
const t = argsArray[i];
|
|
39
|
-
if (Array.isArray(t) && t.length >= 6) ctm = multiplyTransform(ctm, t);
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
// Form XObject 는 /Matrix 공간에서 그린다 — pdfjs 인자 [matrix, bbox], End 에서 복원 (line-extract.ts 와 같음)
|
|
43
|
-
case OPS.paintFormXObjectBegin: {
|
|
44
|
-
stack.push(ctm);
|
|
45
|
-
const m = argsArray[i]?.[0];
|
|
46
|
-
if (Array.isArray(m) && m.length >= 6) ctm = multiplyTransform(ctm, m);
|
|
47
|
-
break;
|
|
48
|
-
}
|
|
49
|
-
case OPS.paintFormXObjectEnd:
|
|
50
|
-
ctm = stack.pop() || [1, 0, 0, 1, 0, 0];
|
|
51
|
-
break;
|
|
52
|
-
case OPS.paintImageXObject:
|
|
53
|
-
case OPS.paintInlineImageXObject:
|
|
54
|
-
case OPS.paintImageMaskXObject:
|
|
55
|
-
case OPS.paintImageXObjectRepeat: {
|
|
56
|
-
const corners = [[0, 0], [1, 0], [0, 1], [1, 1]];
|
|
57
|
-
let x1 = Infinity, y1 = Infinity, x2 = -Infinity, y2 = -Infinity;
|
|
58
|
-
for (const [u, v] of corners) {
|
|
59
|
-
const x = ctm[0] * u + ctm[2] * v + ctm[4];
|
|
60
|
-
const y = ctm[1] * u + ctm[3] * v + ctm[5];
|
|
61
|
-
if (x < x1) x1 = x;
|
|
62
|
-
if (x > x2) x2 = x;
|
|
63
|
-
if (y < y1) y1 = y;
|
|
64
|
-
if (y > y2) y2 = y;
|
|
65
|
-
}
|
|
66
|
-
if (x2 - x1 > 0 && y2 - y1 > 0) regions.push({ x1, y1, x2, y2 });
|
|
67
|
-
break;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return regions;
|
|
72
|
-
}
|
|
10
|
+
} from "./chunk-RC4C7Q33.js";
|
|
73
11
|
|
|
74
12
|
// src/pdf/line-extract.ts
|
|
75
|
-
import { OPS
|
|
13
|
+
import { OPS } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
76
14
|
var ORIENTATION_TOL = 2;
|
|
77
15
|
var MIN_LINE_LENGTH = 15;
|
|
78
16
|
var MAX_LINE_WIDTH = 5;
|
|
@@ -185,20 +123,20 @@ function extractLines(fnArray, argsArray) {
|
|
|
185
123
|
const op = fnArray[i];
|
|
186
124
|
const args = argsArray[i];
|
|
187
125
|
switch (op) {
|
|
188
|
-
case
|
|
126
|
+
case OPS.setLineWidth:
|
|
189
127
|
lineWidth = args[0] || 1;
|
|
190
128
|
break;
|
|
191
|
-
case
|
|
129
|
+
case OPS.save:
|
|
192
130
|
ctmStack.push(ctm.slice());
|
|
193
131
|
colorStack.push(fillColor);
|
|
194
132
|
alphaStack.push([fillAlpha, strokeAlpha]);
|
|
195
133
|
break;
|
|
196
|
-
case
|
|
134
|
+
case OPS.restore:
|
|
197
135
|
ctm = ctmStack.pop() ?? [1, 0, 0, 1, 0, 0];
|
|
198
136
|
fillColor = colorStack.pop() ?? 0;
|
|
199
137
|
[fillAlpha, strokeAlpha] = alphaStack.pop() ?? [1, 1];
|
|
200
138
|
break;
|
|
201
|
-
case
|
|
139
|
+
case OPS.setGState: {
|
|
202
140
|
const entries = args[0];
|
|
203
141
|
if (!Array.isArray(entries)) break;
|
|
204
142
|
for (const e of entries) {
|
|
@@ -208,15 +146,15 @@ function extractLines(fnArray, argsArray) {
|
|
|
208
146
|
}
|
|
209
147
|
break;
|
|
210
148
|
}
|
|
211
|
-
case
|
|
149
|
+
case OPS.setFillRGBColor: {
|
|
212
150
|
const c = args;
|
|
213
151
|
fillColor = c[0] << 16 | c[1] << 8 | c[2];
|
|
214
152
|
break;
|
|
215
153
|
}
|
|
216
|
-
case
|
|
217
|
-
case
|
|
154
|
+
case OPS.transform:
|
|
155
|
+
case OPS.paintFormXObjectBegin: {
|
|
218
156
|
let t = args;
|
|
219
|
-
if (op ===
|
|
157
|
+
if (op === OPS.paintFormXObjectBegin) {
|
|
220
158
|
ctmStack.push(ctm.slice());
|
|
221
159
|
colorStack.push(fillColor);
|
|
222
160
|
alphaStack.push([fillAlpha, strokeAlpha]);
|
|
@@ -234,41 +172,41 @@ function extractLines(fnArray, argsArray) {
|
|
|
234
172
|
];
|
|
235
173
|
break;
|
|
236
174
|
}
|
|
237
|
-
case
|
|
175
|
+
case OPS.paintFormXObjectEnd:
|
|
238
176
|
ctm = ctmStack.pop() ?? [1, 0, 0, 1, 0, 0];
|
|
239
177
|
fillColor = colorStack.pop() ?? 0;
|
|
240
178
|
[fillAlpha, strokeAlpha] = alphaStack.pop() ?? [1, 1];
|
|
241
179
|
break;
|
|
242
|
-
case
|
|
180
|
+
case OPS.constructPath: {
|
|
243
181
|
const arg0 = args[0];
|
|
244
182
|
if (Array.isArray(arg0)) {
|
|
245
183
|
const subOps = arg0;
|
|
246
184
|
const coords = args[1];
|
|
247
185
|
let ci = 0;
|
|
248
186
|
for (const subOp of subOps) {
|
|
249
|
-
if (subOp ===
|
|
187
|
+
if (subOp === OPS.moveTo) {
|
|
250
188
|
curX = coords[ci++];
|
|
251
189
|
curY = coords[ci++];
|
|
252
190
|
pathStartX = curX;
|
|
253
191
|
pathStartY = curY;
|
|
254
|
-
} else if (subOp ===
|
|
192
|
+
} else if (subOp === OPS.lineTo) {
|
|
255
193
|
const x2 = coords[ci++], y2 = coords[ci++];
|
|
256
194
|
pushSeg(curX, curY, x2, y2);
|
|
257
195
|
curX = x2;
|
|
258
196
|
curY = y2;
|
|
259
|
-
} else if (subOp ===
|
|
197
|
+
} else if (subOp === OPS.rectangle) {
|
|
260
198
|
const rx = coords[ci++], ry = coords[ci++];
|
|
261
199
|
const rw = coords[ci++], rh = coords[ci++];
|
|
262
200
|
pushRectangle(rx, ry, rw, rh);
|
|
263
|
-
} else if (subOp ===
|
|
201
|
+
} else if (subOp === OPS.closePath) {
|
|
264
202
|
if (curX !== pathStartX || curY !== pathStartY) {
|
|
265
203
|
pushSeg(curX, curY, pathStartX, pathStartY);
|
|
266
204
|
}
|
|
267
205
|
curX = pathStartX;
|
|
268
206
|
curY = pathStartY;
|
|
269
|
-
} else if (subOp ===
|
|
207
|
+
} else if (subOp === OPS.curveTo) {
|
|
270
208
|
ci += 6;
|
|
271
|
-
} else if (subOp ===
|
|
209
|
+
} else if (subOp === OPS.curveTo2 || subOp === OPS.curveTo3) {
|
|
272
210
|
ci += 4;
|
|
273
211
|
}
|
|
274
212
|
}
|
|
@@ -306,37 +244,37 @@ function extractLines(fnArray, argsArray) {
|
|
|
306
244
|
}
|
|
307
245
|
}
|
|
308
246
|
}
|
|
309
|
-
if (afterOp ===
|
|
247
|
+
if (afterOp === OPS.stroke || afterOp === OPS.closeStroke) {
|
|
310
248
|
flushPath(true);
|
|
311
|
-
} else if (afterOp ===
|
|
249
|
+
} else if (afterOp === OPS.fill || afterOp === OPS.eoFill) {
|
|
312
250
|
flushPath(true, true);
|
|
313
|
-
} else if (afterOp ===
|
|
251
|
+
} else if (afterOp === OPS.fillStroke || afterOp === OPS.eoFillStroke || afterOp === OPS.closeFillStroke || afterOp === OPS.closeEOFillStroke) {
|
|
314
252
|
flushPath(true, false, true);
|
|
315
|
-
} else if (afterOp ===
|
|
253
|
+
} else if (afterOp === OPS.endPath) {
|
|
316
254
|
flushPath(false);
|
|
317
255
|
}
|
|
318
256
|
}
|
|
319
257
|
break;
|
|
320
258
|
}
|
|
321
|
-
case
|
|
322
|
-
case
|
|
259
|
+
case OPS.stroke:
|
|
260
|
+
case OPS.closeStroke:
|
|
323
261
|
flushPath(true);
|
|
324
262
|
break;
|
|
325
|
-
case
|
|
326
|
-
case
|
|
263
|
+
case OPS.fill:
|
|
264
|
+
case OPS.eoFill:
|
|
327
265
|
flushPath(true, true);
|
|
328
266
|
break;
|
|
329
|
-
case
|
|
330
|
-
case
|
|
331
|
-
case
|
|
332
|
-
case
|
|
267
|
+
case OPS.fillStroke:
|
|
268
|
+
case OPS.eoFillStroke:
|
|
269
|
+
case OPS.closeFillStroke:
|
|
270
|
+
case OPS.closeEOFillStroke:
|
|
333
271
|
flushPath(true, false, true);
|
|
334
272
|
break;
|
|
335
|
-
case
|
|
273
|
+
case OPS.endPath:
|
|
336
274
|
flushPath(false);
|
|
337
275
|
break;
|
|
338
|
-
case
|
|
339
|
-
case
|
|
276
|
+
case OPS.clip:
|
|
277
|
+
case OPS.eoClip:
|
|
340
278
|
pendingClip = true;
|
|
341
279
|
break;
|
|
342
280
|
}
|
|
@@ -672,6 +610,68 @@ function filterPageBorderLines(horizontals, verticals, pageWidth, pageHeight) {
|
|
|
672
610
|
};
|
|
673
611
|
}
|
|
674
612
|
|
|
613
|
+
// src/pdf/image-regions.ts
|
|
614
|
+
import { OPS as OPS2 } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
615
|
+
function multiplyTransform(m, t) {
|
|
616
|
+
return [
|
|
617
|
+
m[0] * t[0] + m[2] * t[1],
|
|
618
|
+
m[1] * t[0] + m[3] * t[1],
|
|
619
|
+
m[0] * t[2] + m[2] * t[3],
|
|
620
|
+
m[1] * t[2] + m[3] * t[3],
|
|
621
|
+
m[0] * t[4] + m[2] * t[5] + m[4],
|
|
622
|
+
m[1] * t[4] + m[3] * t[5] + m[5]
|
|
623
|
+
];
|
|
624
|
+
}
|
|
625
|
+
function extractImageRegions(fnArray, argsArray) {
|
|
626
|
+
const regions = [];
|
|
627
|
+
let ctm = [1, 0, 0, 1, 0, 0];
|
|
628
|
+
const stack = [];
|
|
629
|
+
for (let i = 0; i < fnArray.length; i++) {
|
|
630
|
+
const op = fnArray[i];
|
|
631
|
+
switch (op) {
|
|
632
|
+
case OPS2.save:
|
|
633
|
+
stack.push(ctm);
|
|
634
|
+
break;
|
|
635
|
+
case OPS2.restore:
|
|
636
|
+
ctm = stack.pop() || [1, 0, 0, 1, 0, 0];
|
|
637
|
+
break;
|
|
638
|
+
case OPS2.transform: {
|
|
639
|
+
const t = argsArray[i];
|
|
640
|
+
if (Array.isArray(t) && t.length >= 6) ctm = multiplyTransform(ctm, t);
|
|
641
|
+
break;
|
|
642
|
+
}
|
|
643
|
+
// Form XObject 는 /Matrix 공간에서 그린다 — pdfjs 인자 [matrix, bbox], End 에서 복원 (line-extract.ts 와 같음)
|
|
644
|
+
case OPS2.paintFormXObjectBegin: {
|
|
645
|
+
stack.push(ctm);
|
|
646
|
+
const m = argsArray[i]?.[0];
|
|
647
|
+
if (Array.isArray(m) && m.length >= 6) ctm = multiplyTransform(ctm, m);
|
|
648
|
+
break;
|
|
649
|
+
}
|
|
650
|
+
case OPS2.paintFormXObjectEnd:
|
|
651
|
+
ctm = stack.pop() || [1, 0, 0, 1, 0, 0];
|
|
652
|
+
break;
|
|
653
|
+
case OPS2.paintImageXObject:
|
|
654
|
+
case OPS2.paintInlineImageXObject:
|
|
655
|
+
case OPS2.paintImageMaskXObject:
|
|
656
|
+
case OPS2.paintImageXObjectRepeat: {
|
|
657
|
+
const corners = [[0, 0], [1, 0], [0, 1], [1, 1]];
|
|
658
|
+
let x1 = Infinity, y1 = Infinity, x2 = -Infinity, y2 = -Infinity;
|
|
659
|
+
for (const [u, v] of corners) {
|
|
660
|
+
const x = ctm[0] * u + ctm[2] * v + ctm[4];
|
|
661
|
+
const y = ctm[1] * u + ctm[3] * v + ctm[5];
|
|
662
|
+
if (x < x1) x1 = x;
|
|
663
|
+
if (x > x2) x2 = x;
|
|
664
|
+
if (y < y1) y1 = y;
|
|
665
|
+
if (y > y2) y2 = y;
|
|
666
|
+
}
|
|
667
|
+
if (x2 - x1 > 0 && y2 - y1 > 0) regions.push({ x1, y1, x2, y2 });
|
|
668
|
+
break;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
return regions;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
675
|
// src/pdf/vertical-bridge.ts
|
|
676
676
|
var BRIDGE_X_TOL = 1.5;
|
|
677
677
|
var BRIDGE_MIN_GAP = 5;
|
|
@@ -791,6 +791,10 @@ var CUT_INTERIOR_MATCH_TOL = 8;
|
|
|
791
791
|
var CUT_MAX_INTERIOR_OVERLAP = 0.5;
|
|
792
792
|
var CUT_VCHAIN_X_TOL = 1.5;
|
|
793
793
|
var CUT_VCHAIN_GAP = 1;
|
|
794
|
+
var NEST_STRICT_TOL = 0.5;
|
|
795
|
+
var NEST_MIN_GAP = 0.8;
|
|
796
|
+
var NEST_EDGE_COVER = 0.95;
|
|
797
|
+
var NEST_DOUBLE_RULE_GAP = 6;
|
|
794
798
|
var VERTEX_BUCKET_CELL = 100;
|
|
795
799
|
function lowerBound(sorted, key) {
|
|
796
800
|
let lo = 0, hi = sorted.length;
|
|
@@ -894,9 +898,12 @@ function buildTableGrids(horizontals, verticals) {
|
|
|
894
898
|
...verticals.map((l, i) => ({ ...l, type: "v", id: i + horizontals.length }))
|
|
895
899
|
];
|
|
896
900
|
const groups = [];
|
|
897
|
-
for (const
|
|
901
|
+
for (const g0 of groupConnectedLines(allLines)) {
|
|
902
|
+
const { outer: g, nested } = splitNestedBoxes(g0);
|
|
903
|
+
for (const n of nested) groups.push({ lines: n, fromSplit: true, nested: true });
|
|
904
|
+
if (g.length === 0) continue;
|
|
898
905
|
const bands = splitStackedGroup(g);
|
|
899
|
-
for (const b of bands) groups.push({ lines: b, fromSplit: bands.length > 1 });
|
|
906
|
+
for (const b of bands) groups.push({ lines: b, fromSplit: bands.length > 1 || nested.length > 0 });
|
|
900
907
|
}
|
|
901
908
|
const grids = [];
|
|
902
909
|
const byY = [...vertices].sort((a, b) => a.y - b.y);
|
|
@@ -910,7 +917,7 @@ function buildTableGrids(horizontals, verticals) {
|
|
|
910
917
|
}
|
|
911
918
|
return lo;
|
|
912
919
|
};
|
|
913
|
-
for (const { lines: group, fromSplit } of groups) {
|
|
920
|
+
for (const { lines: group, fromSplit, nested } of groups) {
|
|
914
921
|
const hLines = group.filter((l) => l.type === "h");
|
|
915
922
|
const vLines = group.filter((l) => l.type === "v");
|
|
916
923
|
if (hLines.length < 2 || vLines.length < 2) continue;
|
|
@@ -972,9 +979,9 @@ function buildTableGrids(horizontals, verticals) {
|
|
|
972
979
|
x2: validColXs[validColXs.length - 1],
|
|
973
980
|
y2: validRowYs[0]
|
|
974
981
|
};
|
|
975
|
-
grids.push({ rowYs: validRowYs, colXs: validColXs, bbox, vertexRadius: groupRadius });
|
|
982
|
+
grids.push({ rowYs: validRowYs, colXs: validColXs, bbox, vertexRadius: groupRadius, ...nested ? { lineNested: true } : {} });
|
|
976
983
|
}
|
|
977
|
-
return mergeAdjacentGrids(grids);
|
|
984
|
+
return [...mergeAdjacentGrids(grids.filter((g) => !g.lineNested)), ...grids.filter((g) => g.lineNested)];
|
|
978
985
|
}
|
|
979
986
|
var SHADE_CLIP_TOL = 1.5;
|
|
980
987
|
var SHADE_CLIP_MAX_AREA = 0.5;
|
|
@@ -1153,8 +1160,52 @@ function splitStackedGroup(group) {
|
|
|
1153
1160
|
}
|
|
1154
1161
|
return bands.filter((b) => b.length > 0);
|
|
1155
1162
|
}
|
|
1163
|
+
function splitNestedBoxes(group) {
|
|
1164
|
+
const comps = groupConnectedLines(group, NEST_STRICT_TOL);
|
|
1165
|
+
if (comps.length < 2) return { outer: group, nested: [] };
|
|
1166
|
+
const boxes = comps.map((c) => {
|
|
1167
|
+
const hs = c.filter((l) => l.type === "h"), vs = c.filter((l) => l.type === "v");
|
|
1168
|
+
if (hs.length < 2 || vs.length < 2) return null;
|
|
1169
|
+
const x1 = Math.min(...vs.map((v) => v.x1)), x2 = Math.max(...vs.map((v) => v.x1));
|
|
1170
|
+
const y1 = Math.min(...hs.map((h) => h.y1)), y2 = Math.max(...hs.map((h) => h.y1));
|
|
1171
|
+
if (x2 - x1 < 1 || y2 - y1 < 1) return null;
|
|
1172
|
+
const cover = (segs, a, b) => segs.reduce((s, [p, q]) => s + Math.max(0, Math.min(q, b) - Math.max(p, a)), 0) >= (b - a) * NEST_EDGE_COVER;
|
|
1173
|
+
const edgeH = (y) => cover(hs.filter((h) => Math.abs(h.y1 - y) <= NEST_STRICT_TOL).map((h) => [h.x1, h.x2]), x1, x2);
|
|
1174
|
+
const edgeV = (x) => cover(vs.filter((v) => Math.abs(v.x1 - x) <= NEST_STRICT_TOL).map((v) => [v.y1, v.y2]), y1, y2);
|
|
1175
|
+
return edgeH(y1) && edgeH(y2) && edgeV(x1) && edgeV(x2) ? { x1, y1, x2, y2 } : null;
|
|
1176
|
+
});
|
|
1177
|
+
const bboxOf = (c) => ({
|
|
1178
|
+
x1: Math.min(...c.map((l) => Math.min(l.x1, l.x2))),
|
|
1179
|
+
x2: Math.max(...c.map((l) => Math.max(l.x1, l.x2))),
|
|
1180
|
+
y1: Math.min(...c.map((l) => Math.min(l.y1, l.y2))),
|
|
1181
|
+
y2: Math.max(...c.map((l) => Math.max(l.y1, l.y2)))
|
|
1182
|
+
});
|
|
1183
|
+
const extents = comps.map(bboxOf);
|
|
1184
|
+
const nestedIdx = /* @__PURE__ */ new Set();
|
|
1185
|
+
comps.forEach((_, i) => {
|
|
1186
|
+
const b = boxes[i];
|
|
1187
|
+
if (!b) return;
|
|
1188
|
+
const e = extents[i];
|
|
1189
|
+
const uniq = (xs) => xs.filter((x, k) => xs.findIndex((y) => Math.abs(y - x) <= NEST_STRICT_TOL) === k).length;
|
|
1190
|
+
const bare = uniq(comps[i].filter((l) => l.type === "h").map((l) => l.y1)) === 2 && uniq(comps[i].filter((l) => l.type === "v").map((l) => l.x1)) === 2;
|
|
1191
|
+
const inside = comps.some((c, j) => {
|
|
1192
|
+
if (j === i || c.filter((l) => l.type === "v").length < 2 || !c.some((l) => l.type === "h")) return false;
|
|
1193
|
+
const p = extents[j];
|
|
1194
|
+
const gaps = [e.x1 - p.x1, p.x2 - e.x2, e.y1 - p.y1, p.y2 - e.y2];
|
|
1195
|
+
return gaps.every((g) => g >= NEST_MIN_GAP) && !(bare && gaps.every((g) => g <= NEST_DOUBLE_RULE_GAP));
|
|
1196
|
+
});
|
|
1197
|
+
if (!inside) return;
|
|
1198
|
+
const crossed = comps.some((c, j) => j !== i && c.some((l) => l.type === "h" ? l.y1 > e.y1 + NEST_MIN_GAP && l.y1 < e.y2 - NEST_MIN_GAP && Math.min(l.x2, e.x2) - Math.max(l.x1, e.x1) > NEST_MIN_GAP : l.x1 > e.x1 + NEST_MIN_GAP && l.x1 < e.x2 - NEST_MIN_GAP && Math.min(l.y2, e.y2) - Math.max(l.y1, e.y1) > NEST_MIN_GAP) && !(extents[j].x1 >= e.x1 && extents[j].x2 <= e.x2 && extents[j].y1 >= e.y1 && extents[j].y2 <= e.y2));
|
|
1199
|
+
if (!crossed) nestedIdx.add(i);
|
|
1200
|
+
});
|
|
1201
|
+
if (nestedIdx.size === 0) return { outer: group, nested: [] };
|
|
1202
|
+
return {
|
|
1203
|
+
outer: comps.filter((_, i) => !nestedIdx.has(i)).flat(),
|
|
1204
|
+
nested: comps.filter((_, i) => nestedIdx.has(i))
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1156
1207
|
var GROUP_BUCKET_CELL = 100;
|
|
1157
|
-
function groupConnectedLines(lines) {
|
|
1208
|
+
function groupConnectedLines(lines, tol = CONNECT_TOL) {
|
|
1158
1209
|
const parent = lines.map((_, i) => i);
|
|
1159
1210
|
function find(x) {
|
|
1160
1211
|
while (parent[x] !== x) {
|
|
@@ -1196,7 +1247,7 @@ function groupConnectedLines(lines) {
|
|
|
1196
1247
|
const key = i * lines.length + j;
|
|
1197
1248
|
if (tested.has(key)) continue;
|
|
1198
1249
|
tested.add(key);
|
|
1199
|
-
if (linesIntersect(lines[i], lines[j])) {
|
|
1250
|
+
if (linesIntersect(lines[i], lines[j], tol)) {
|
|
1200
1251
|
union(i, j);
|
|
1201
1252
|
}
|
|
1202
1253
|
}
|
|
@@ -1210,19 +1261,18 @@ function groupConnectedLines(lines) {
|
|
|
1210
1261
|
}
|
|
1211
1262
|
return [...groups.values()];
|
|
1212
1263
|
}
|
|
1213
|
-
function linesIntersect(a, b) {
|
|
1264
|
+
function linesIntersect(a, b, tol = CONNECT_TOL) {
|
|
1214
1265
|
if (a.type === b.type) {
|
|
1215
1266
|
if (a.type === "h") {
|
|
1216
|
-
if (Math.abs(a.y1 - b.y1) >
|
|
1217
|
-
return Math.min(a.x2, b.x2) >= Math.max(a.x1, b.x1) -
|
|
1267
|
+
if (Math.abs(a.y1 - b.y1) > tol) return false;
|
|
1268
|
+
return Math.min(a.x2, b.x2) >= Math.max(a.x1, b.x1) - tol;
|
|
1218
1269
|
} else {
|
|
1219
|
-
if (Math.abs(a.x1 - b.x1) >
|
|
1220
|
-
return Math.min(a.y2, b.y2) >= Math.max(a.y1, b.y1) -
|
|
1270
|
+
if (Math.abs(a.x1 - b.x1) > tol) return false;
|
|
1271
|
+
return Math.min(a.y2, b.y2) >= Math.max(a.y1, b.y1) - tol;
|
|
1221
1272
|
}
|
|
1222
1273
|
}
|
|
1223
1274
|
const h = a.type === "h" ? a : b;
|
|
1224
1275
|
const v = a.type === "h" ? b : a;
|
|
1225
|
-
const tol = CONNECT_TOL;
|
|
1226
1276
|
return v.x1 >= h.x1 - tol && v.x1 <= h.x2 + tol && h.y1 >= v.y1 - tol && h.y1 <= v.y2 + tol;
|
|
1227
1277
|
}
|
|
1228
1278
|
|
|
@@ -1266,6 +1316,13 @@ function clusterCoords(values) {
|
|
|
1266
1316
|
if (run.length > 0) out.push(run.reduce((s, x) => s + x, 0) / run.length);
|
|
1267
1317
|
return out;
|
|
1268
1318
|
}
|
|
1319
|
+
function dropSliverGaps(coords) {
|
|
1320
|
+
const out = [...coords];
|
|
1321
|
+
if (out.length > 2 && out[1] - out[0] < 1) out.splice(0, 2, (out[0] + out[1]) / 2);
|
|
1322
|
+
const n = out.length;
|
|
1323
|
+
if (n > 2 && out[n - 1] - out[n - 2] < 1) out.splice(n - 2, 2, (out[n - 2] + out[n - 1]) / 2);
|
|
1324
|
+
return out;
|
|
1325
|
+
}
|
|
1269
1326
|
var nearestIndex = (coords, v) => {
|
|
1270
1327
|
let best = 0;
|
|
1271
1328
|
for (let i = 1; i < coords.length; i++) if (Math.abs(coords[i] - v) < Math.abs(coords[best] - v)) best = i;
|
|
@@ -1463,7 +1520,7 @@ function buildClipCellGrids(rects, strokedH, strokedV, pageWidth, pageHeight, te
|
|
|
1463
1520
|
if (!edgeStroked(strokedV, "v", r.x2, r.y1, r.y2)) invisible++;
|
|
1464
1521
|
}
|
|
1465
1522
|
if (invisible / edges < CLIP_MIN_INVISIBLE) continue;
|
|
1466
|
-
const colXs = clusterCoords(members.flatMap((r) => [r.x1, r.x2]));
|
|
1523
|
+
const colXs = dropSliverGaps(clusterCoords(members.flatMap((r) => [r.x1, r.x2])));
|
|
1467
1524
|
const rowYs = clusterCoords(members.flatMap((r) => [r.y1, r.y2])).reverse();
|
|
1468
1525
|
const numRows = rowYs.length - 1, numCols = colXs.length - 1;
|
|
1469
1526
|
if (numRows < 1 || numCols < 1) continue;
|
|
@@ -1860,6 +1917,7 @@ var hasBatchim = (c) => {
|
|
|
1860
1917
|
const k = c.charCodeAt(0) - 44032;
|
|
1861
1918
|
return k >= 0 && k < 11172 && k % 28 !== 0;
|
|
1862
1919
|
};
|
|
1920
|
+
var CJK = /[\u3000-\u303F\u3040-\u30FF\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF\uFF00-\uFFEF]/;
|
|
1863
1921
|
var CLOSE_TAIL = /[’”」』)\]〉》>]+$/;
|
|
1864
1922
|
var TAIL = "[.,)\u300D\u300F\u2019\u201D]*";
|
|
1865
1923
|
var PARTICLE = new RegExp(`^(?:\uB2E4\\.|\uC758|\uC5D0|\uC5D0\uC11C|\uC5D0\uB294|\uC5D0\uAC8C|\uC5D0\uB3C4|\uC5D0\uC11C\uB294|\uAE4C\uC9C0|\uBD80\uD130|\uCC98\uB7FC|\uB9C8\uB2E4|\uB9CC|\uB3C4|\uB4E4|\uB4E4\uC774|\uB4E4\uC758|\uB4E4\uC740|\uB4E4\uC744|\uB4E4\uC5D0\uAC8C|\uC11C\uB294|\uC11C\uB3C4|\uB77C\uACE0|\uB77C\uBA70|\uC740|\uB294|\uC744|\uB97C|\uC73C\uB85C|\uB85C|\uC73C\uB85C\uC11C|\uB85C\uC11C|\uC73C\uB85C\uC368|\uB85C\uC368)${TAIL}$`);
|
|
@@ -1909,6 +1967,7 @@ function wrapJoiner(prevText, nextText, lex) {
|
|
|
1909
1967
|
const prev = prevText.replace(MARKUP, "").trimEnd(), next = nextText.replace(MARKUP, "").trimStart();
|
|
1910
1968
|
const a = prev[prev.length - 1], b = next[0];
|
|
1911
1969
|
if (!a || !b || /[,;:!?]/.test(a) || DATE_DAY_END.test(prev) && b !== "(") return " ";
|
|
1970
|
+
if (CJK.test(a) && CJK.test(b) && !/[가-힣ㄱ-ㅎㅏ-ㅣ]/.test(prev + next)) return "";
|
|
1912
1971
|
let s = prev.length;
|
|
1913
1972
|
while (s > 0 && !/\s/.test(prev[s - 1])) s--;
|
|
1914
1973
|
const left = prev.slice(s), right = next.match(/^\S+/)[0];
|
|
@@ -1950,6 +2009,7 @@ function joinPageBreakWraps(blocks, lex) {
|
|
|
1950
2009
|
blocks.splice(i, 1);
|
|
1951
2010
|
}
|
|
1952
2011
|
}
|
|
2012
|
+
var HANGING = /[,。、:;!?)」』】〕》〉.]\s*$/;
|
|
1953
2013
|
var BODY_FULL_TOL = 0.25;
|
|
1954
2014
|
var BODY_MIN_WIDTH_EM = 12;
|
|
1955
2015
|
var BODY_MAX_PITCH_EM = 2;
|
|
@@ -1958,12 +2018,15 @@ var BODY_MAX_PITCH_ABS_EM = 3.5;
|
|
|
1958
2018
|
function bodyLineJoins(lines, lex) {
|
|
1959
2019
|
let right = -Infinity;
|
|
1960
2020
|
for (const l of lines) if (l.right > right) right = l.right;
|
|
2021
|
+
let inner = -Infinity;
|
|
2022
|
+
for (const l of lines) if (!HANGING.test(l.text) && l.right > inner) inner = l.right;
|
|
2023
|
+
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;
|
|
1961
2024
|
const pitch = (k) => lines[k].y - lines[k + 1].y;
|
|
1962
2025
|
const sameSize = (k) => Math.abs(lines[k + 1].fontSize - lines[k].fontSize) <= 0.15 * lines[k].fontSize;
|
|
1963
2026
|
let p1 = Infinity, p2 = Infinity, i1 = -1;
|
|
1964
2027
|
for (let k = 0; k + 1 < lines.length; k++) {
|
|
1965
2028
|
const p = pitch(k);
|
|
1966
|
-
if (p <= 0 || !sameSize(k)) continue;
|
|
2029
|
+
if (p <= 0 || !sameSize(k) || Math.min(lines[k].right - lines[k].left, lines[k + 1].right - lines[k + 1].left) < 3 * lines[k].fontSize) continue;
|
|
1967
2030
|
if (p < p1) {
|
|
1968
2031
|
p2 = p1;
|
|
1969
2032
|
p1 = p;
|
|
@@ -1976,7 +2039,7 @@ function bodyLineJoins(lines, lex) {
|
|
|
1976
2039
|
const fs = a.fontSize;
|
|
1977
2040
|
const others = i === i1 ? p2 : p1;
|
|
1978
2041
|
const maxPitch = Number.isFinite(others) ? Math.min(BODY_MAX_PITCH_ABS_EM * fs, Math.max(BODY_MAX_PITCH_EM * fs, others * BODY_PITCH_REL)) : BODY_MAX_PITCH_EM * fs;
|
|
1979
|
-
const wraps = fs > 0 &&
|
|
2042
|
+
const wraps = fs > 0 && full(a) && a.right - a.left >= BODY_MIN_WIDTH_EM * fs && a.y - b.y > 0 && a.y - b.y < maxPitch && Math.abs(b.fontSize - fs) <= 0.15 * fs && !startsNewItem(a.text, b.text);
|
|
1980
2043
|
out.push(wraps ? wrapJoiner(a.text, b.text, lex) : "\n");
|
|
1981
2044
|
}
|
|
1982
2045
|
return out;
|
|
@@ -2086,6 +2149,7 @@ function cellTextToString(items, wrap) {
|
|
|
2086
2149
|
const textLines = merged.map((line) => {
|
|
2087
2150
|
const s = sortLineByX(line);
|
|
2088
2151
|
if (s.length === 1) return s[0].text;
|
|
2152
|
+
if (s.length === 2 && /^[가-힣]$/.test(s[0].text) && /^[가-힣]$/.test(s[1].text) && !!wrap?.lex && (wrap.lex.isWord(s[0].text + s[1].text) || wrap.lex.evidence(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;
|
|
2089
2153
|
const evenSpaced = detectEvenSpacedItems(s);
|
|
2090
2154
|
let result = s[0].text;
|
|
2091
2155
|
for (let j = 1; j < s.length; j++) {
|
|
@@ -2095,7 +2159,9 @@ function cellTextToString(items, wrap) {
|
|
|
2095
2159
|
}
|
|
2096
2160
|
const gap = s[j].x - (s[j - 1].x + s[j - 1].w);
|
|
2097
2161
|
const avgFs = (s[j].fontSize + s[j - 1].fontSize) / 2;
|
|
2098
|
-
if (s[j].
|
|
2162
|
+
if (isCjkLatinAutospace(s[j - 1].text, s[j].text, gap, avgFs)) {
|
|
2163
|
+
result += s[j].text;
|
|
2164
|
+
} else if (s[j].hasSpaceBefore && gap >= avgFs * 0.05) {
|
|
2099
2165
|
result += " " + s[j].text;
|
|
2100
2166
|
} else if (gap > spaceGapThreshold(avgFs)) {
|
|
2101
2167
|
result += " " + s[j].text;
|
|
@@ -2225,7 +2291,7 @@ function mergeCellTextLines(textLines, wrap) {
|
|
|
2225
2291
|
merged[merged.length - 1] = prev + curr.trim();
|
|
2226
2292
|
} else if (!wrap && /[,(]$/.test(prev.trim()) && curr.trim().length <= 15) {
|
|
2227
2293
|
merged[merged.length - 1] = prev + curr.trim();
|
|
2228
|
-
} else if (/[\d,]$/.test(prev) && /^[\d,]+[)\]]?$/.test(curr.trim()) && curr.trim().length <= 10 && !(/\d,\d{3}$/.test(prev) && /^\d/.test(curr.trim())) && !(/(?:^|[^\d,])\d{1,3}$/.test(prev) && /^(\d{1,3}(,\d{3})+|\d{1,3})$/.test(curr.trim()))) {
|
|
2294
|
+
} else if (/[\d,]$/.test(prev) && /^[\d,]+[)\]]?$/.test(curr.trim()) && curr.trim().length <= 10 && !(/\d,\d{3}$/.test(prev) && /^\d/.test(curr.trim())) && !(/(?:^|[^\d,])\d{1,3}$/.test(prev) && /^(\d{1,3}(,\d{3})+|\d{1,3})$/.test(curr.trim()) && !wrap?.wraps[i - 1]) && !(/(?:^|\s)\d{1,7}$/.test(prev) && /^\d{1,7}$/.test(curr.trim()) && !wrap?.wraps[i - 1])) {
|
|
2229
2295
|
merged[merged.length - 1] = prev + curr.trim();
|
|
2230
2296
|
} else {
|
|
2231
2297
|
merged.push(curr);
|
|
@@ -2388,6 +2454,12 @@ function sortLineByX(items) {
|
|
|
2388
2454
|
}
|
|
2389
2455
|
return items;
|
|
2390
2456
|
}
|
|
2457
|
+
function isCjkLatinAutospace(prevText, nextText, gap, fontSize) {
|
|
2458
|
+
if (!(gap < fontSize * 0.3)) return false;
|
|
2459
|
+
const a = prevText.slice(-1), b = nextText[0] ?? "";
|
|
2460
|
+
const cjk = /[\u3040-\u30ff\u3400-\u9fff\uf900-\ufaff]/, latin = /[A-Za-z0-9]/;
|
|
2461
|
+
return cjk.test(a) && latin.test(b) || latin.test(a) && cjk.test(b);
|
|
2462
|
+
}
|
|
2391
2463
|
function filterHiddenText(items, pageWidth, pageHeight, originX = 0, originY = 0) {
|
|
2392
2464
|
let hiddenCount = 0;
|
|
2393
2465
|
const visible = [];
|
|
@@ -2463,10 +2535,14 @@ function normalizeItems(rawItems) {
|
|
|
2463
2535
|
const scaleX = Math.hypot(i.transform[0], i.transform[1]);
|
|
2464
2536
|
const scaleY = Math.hypot(i.transform[2], i.transform[3]);
|
|
2465
2537
|
const fontSize = Math.round(Math.max(scaleY, scaleX));
|
|
2466
|
-
|
|
2538
|
+
let w = Math.round(i.width);
|
|
2467
2539
|
const h = Math.round(i.height);
|
|
2540
|
+
if (/[^\u0000]\u0000+$/.test(i.str)) {
|
|
2541
|
+
w = Math.max(1, Math.round(i.width - Math.round(Math.max(Math.hypot(i.transform[2], i.transform[3]), Math.hypot(i.transform[0], i.transform[1]))) * 0.3));
|
|
2542
|
+
spacePositions.push({ x: x + w, y });
|
|
2543
|
+
}
|
|
2468
2544
|
const isHidden = fontSize === 0 || i.width === 0 && i.str.trim().length > 0;
|
|
2469
|
-
let text = i.str.trim();
|
|
2545
|
+
let text = i.str.trim().replace(/[\u2F00-\u2FD5]/g, (c) => c.normalize("NFKC"));
|
|
2470
2546
|
if (/^[\d\s\-().·,☎]+$/.test(text) && /\d/.test(text) && / /.test(text)) {
|
|
2471
2547
|
text = text.replace(/ /g, "");
|
|
2472
2548
|
}
|
|
@@ -2687,6 +2763,10 @@ function mergeLineSimple(items) {
|
|
|
2687
2763
|
result += sorted[i].text;
|
|
2688
2764
|
continue;
|
|
2689
2765
|
}
|
|
2766
|
+
if (isCjkLatinAutospace(sorted[i - 1].text, sorted[i].text, gap, avgFs)) {
|
|
2767
|
+
result += sorted[i].text;
|
|
2768
|
+
continue;
|
|
2769
|
+
}
|
|
2690
2770
|
if (sorted[i].hasSpaceBefore && gap >= avgFs * 0.05) {
|
|
2691
2771
|
result += " ";
|
|
2692
2772
|
result += sorted[i].text;
|
|
@@ -2844,6 +2924,9 @@ function pushLineParagraphs(out, yLines, pageNum, lex) {
|
|
|
2844
2924
|
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: dominantStyle(l.items)?.fontSize ?? 0 };
|
|
2845
2925
|
});
|
|
2846
2926
|
const joins = bodyLineJoins(geo, lex);
|
|
2927
|
+
for (let i = 0; i + 1 < geo.length; i++) {
|
|
2928
|
+
if (/^\d{1,2}$/.test(geo[i].text.trim()) && geo[i].fontSize >= geo[i + 1].fontSize * 1.2) joins[i] = "\n";
|
|
2929
|
+
}
|
|
2847
2930
|
if (hasNumberedStyledTitle(lines.map((line) => line.items))) {
|
|
2848
2931
|
joins[0] = "\n";
|
|
2849
2932
|
joins[1] = "\n";
|
|
@@ -2880,11 +2963,12 @@ function computeMedianFontSizeFromFreq(freq) {
|
|
|
2880
2963
|
return sorted[sorted.length - 1][0];
|
|
2881
2964
|
}
|
|
2882
2965
|
function detectHeadings(blocks, medianFontSize) {
|
|
2883
|
-
for (
|
|
2966
|
+
for (let bi = 0; bi < blocks.length; bi++) {
|
|
2967
|
+
const block = blocks[bi];
|
|
2884
2968
|
if (block.type !== "paragraph" || !block.text || !block.style?.fontSize) continue;
|
|
2885
2969
|
const text = block.text.trim();
|
|
2886
2970
|
if (text.length === 0 || text.length > 200) continue;
|
|
2887
|
-
if (/^\d+$/.test(text)) continue;
|
|
2971
|
+
if (/^\d+$/.test(text) && !isChapterNumber(block, blocks[bi + 1], medianFontSize)) continue;
|
|
2888
2972
|
const ratio = block.style.fontSize / medianFontSize;
|
|
2889
2973
|
let level = 0;
|
|
2890
2974
|
if (ratio >= HEADING_RATIO_H1) level = 1;
|
|
@@ -2897,6 +2981,13 @@ function detectHeadings(blocks, medianFontSize) {
|
|
|
2897
2981
|
}
|
|
2898
2982
|
}
|
|
2899
2983
|
}
|
|
2984
|
+
function isChapterNumber(block, next, medianFontSize) {
|
|
2985
|
+
const size = block.style?.fontSize ?? 0;
|
|
2986
|
+
const nextSize = next?.style?.fontSize ?? 0;
|
|
2987
|
+
const text = next?.text?.trim() ?? "";
|
|
2988
|
+
const a = block.bbox, b = next?.bbox;
|
|
2989
|
+
return /^\d{1,2}$/.test(block.text?.trim() ?? "") && size >= medianFontSize * 2.5 && !!next && (next.type === "paragraph" || next.type === "heading") && next.pageNumber === block.pageNumber && nextSize >= medianFontSize * 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;
|
|
2990
|
+
}
|
|
2900
2991
|
function mergeStackedHeadingLines(blocks, medianFontSize) {
|
|
2901
2992
|
for (let i = 0; i < blocks.length - 1; ) {
|
|
2902
2993
|
const a = blocks[i], b = blocks[i + 1];
|
|
@@ -2907,7 +2998,7 @@ function mergeStackedHeadingLines(blocks, medianFontSize) {
|
|
|
2907
2998
|
const sameAnchor = ab && bb && Math.abs(ab.x - bb.x) <= 5;
|
|
2908
2999
|
const wrapped = sameAnchor && a.style?.fontName === b.style?.fontName && af === bf && ab.width >= bb.width * 0.95 && (a.text?.trim().split(/\s+/).length ?? 0) >= 3;
|
|
2909
3000
|
const displayStack = centered && gap <= Math.min(af, bf) * 0.3 && Math.max(af, bf) <= Math.min(af, bf) * 1.45;
|
|
2910
|
-
if (a.type !== "heading" || b.type !== "heading" || !a.text || !b.text || !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)) {
|
|
3001
|
+
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)) {
|
|
2911
3002
|
i++;
|
|
2912
3003
|
continue;
|
|
2913
3004
|
}
|
|
@@ -3089,7 +3180,7 @@ function detectPageLeadHeadings(blocks) {
|
|
|
3089
3180
|
byPage.set(b.pageNumber ?? 0, page);
|
|
3090
3181
|
}
|
|
3091
3182
|
for (const page of byPage.values()) {
|
|
3092
|
-
const content = page.filter((b) => b.type !== "image" && b.type !== "separator");
|
|
3183
|
+
const content = page.filter((b) => b.type !== "image" && b.type !== "separator" && !(b.type === "paragraph" && !b.style));
|
|
3093
3184
|
const [first, second, third] = content;
|
|
3094
3185
|
if (!first?.bbox || !first.text || !first.style?.fontSize || !second) continue;
|
|
3095
3186
|
const firstText = first.text.trim();
|
|
@@ -3450,16 +3541,23 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings) {
|
|
|
3450
3541
|
if (entries.length === 0) continue;
|
|
3451
3542
|
const patternCount = /* @__PURE__ */ new Map();
|
|
3452
3543
|
const patternPages = /* @__PURE__ */ new Map();
|
|
3544
|
+
const patternNumbers = /* @__PURE__ */ new Map();
|
|
3453
3545
|
for (const e of entries) {
|
|
3454
3546
|
const norm = e.text.replace(/\d+/g, "#");
|
|
3455
3547
|
patternCount.set(norm, (patternCount.get(norm) || 0) + 1);
|
|
3548
|
+
const nums = patternNumbers.get(norm) || /* @__PURE__ */ new Set();
|
|
3549
|
+
nums.add((e.text.match(/\d+/g) ?? []).join(","));
|
|
3550
|
+
patternNumbers.set(norm, nums);
|
|
3456
3551
|
const pages = patternPages.get(norm) || /* @__PURE__ */ new Set();
|
|
3457
3552
|
pages.add(e.page);
|
|
3458
3553
|
patternPages.set(norm, pages);
|
|
3459
3554
|
}
|
|
3460
3555
|
const repeatedPatterns = /* @__PURE__ */ new Set();
|
|
3461
3556
|
for (const [p, count] of patternCount) {
|
|
3462
|
-
|
|
3557
|
+
const pages = [...patternPages.get(p) ?? []];
|
|
3558
|
+
const span = pages.length ? Math.max(...pages) - Math.min(...pages) + 1 : 0;
|
|
3559
|
+
const pageNumbered = (patternNumbers.get(p)?.size ?? 0) > 1;
|
|
3560
|
+
if (count >= MIN_REPEAT && pages.length >= MIN_REPEAT && (pages.length >= span * 0.4 || pageNumbered)) {
|
|
3463
3561
|
repeatedPatterns.add(p);
|
|
3464
3562
|
}
|
|
3465
3563
|
}
|
|
@@ -3664,6 +3762,12 @@ function isFormulaTable(table) {
|
|
|
3664
3762
|
const math = texts.filter((text) => /^[a-z]{1,2}$/.test(text) || /[=∂∑∫∣Γ∇√∞]/.test(text)).length;
|
|
3665
3763
|
return math >= texts.length * 0.6;
|
|
3666
3764
|
}
|
|
3765
|
+
function isExamLayoutTable(table) {
|
|
3766
|
+
const texts = table.cells.flat().map((cell) => cell.text.trim()).filter(Boolean);
|
|
3767
|
+
if (texts.length < 3 || !texts.some((text) => /[①-⑤]|문\d+)/.test(text))) return false;
|
|
3768
|
+
const layout = texts.filter((text) => /\$|[①-⑤]|문\d+)/.test(text) || !/[\p{L}\p{N}]/u.test(text)).length;
|
|
3769
|
+
return layout >= texts.length * 0.6;
|
|
3770
|
+
}
|
|
3667
3771
|
|
|
3668
3772
|
// src/pdf/cluster-detector.ts
|
|
3669
3773
|
var Y_TOL = 3;
|
|
@@ -4433,7 +4537,7 @@ function joinCellItems(items) {
|
|
|
4433
4537
|
for (let i = 1; i < line.length; i++) {
|
|
4434
4538
|
const gap = line[i].x - (line[i - 1].x + line[i - 1].w);
|
|
4435
4539
|
const fs = (line[i].fontSize + line[i - 1].fontSize) / 2;
|
|
4436
|
-
s += (line[i].hasSpaceBefore && gap >= fs * 0.05 || gap > spaceGapThreshold(fs) ? " " : "") + line[i].text;
|
|
4540
|
+
s += (!isCjkLatinAutospace(line[i - 1].text, line[i].text, gap, fs) && (line[i].hasSpaceBefore && gap >= fs * 0.05 || gap > spaceGapThreshold(fs)) ? " " : "") + line[i].text;
|
|
4437
4541
|
}
|
|
4438
4542
|
return s;
|
|
4439
4543
|
}).join(" ");
|
|
@@ -4486,9 +4590,9 @@ function xyCutOrder(items, gapThreshold, depth = 0) {
|
|
|
4486
4590
|
const hCut = findHorizontalCut(items);
|
|
4487
4591
|
const vCut = findVerticalCutWithOutlierFilter(items, minGap);
|
|
4488
4592
|
const hValid = hCut.gap >= minGap;
|
|
4489
|
-
const vValid = vCut.gap >= minGap || vCut.gap >= PROSE_GUTTER_MIN_GAP && isProseGutter(items, vCut.position);
|
|
4593
|
+
const vValid = (vCut.gap >= minGap || vCut.gap >= PROSE_GUTTER_MIN_GAP && isProseGutter(items, vCut.position)) && !splitsSpacedLabel(items, vCut.position);
|
|
4490
4594
|
let useHorizontal;
|
|
4491
|
-
if (hValid && vValid) useHorizontal = vCut.gap <= hCut.gap * 1.5;
|
|
4595
|
+
if (hValid && vValid) useHorizontal = vCut.gap <= hCut.gap * 1.5 || staggeredSides(items, vCut.position);
|
|
4492
4596
|
else if (hValid) useHorizontal = true;
|
|
4493
4597
|
else if (vValid) useHorizontal = false;
|
|
4494
4598
|
else return splitEdgeSpannedColumns(items, gapThreshold, depth) ?? [items];
|
|
@@ -4507,6 +4611,33 @@ function xyCutOrder(items, gapThreshold, depth = 0) {
|
|
|
4507
4611
|
}
|
|
4508
4612
|
return [items];
|
|
4509
4613
|
}
|
|
4614
|
+
function splitsSpacedLabel(items, cutX) {
|
|
4615
|
+
const lone = (i) => /^[가-힣]$/.test(i.text.trim());
|
|
4616
|
+
const sameRow = (a, b) => Math.min(a.y, b.y) > Math.max(a.y - a.h, b.y - b.h);
|
|
4617
|
+
const left = items.filter((i) => i.x + i.w / 2 < cutX);
|
|
4618
|
+
const right = items.filter((i) => i.x + i.w / 2 >= cutX);
|
|
4619
|
+
let spaced = 0;
|
|
4620
|
+
for (const r of right) {
|
|
4621
|
+
if (right.some((o) => o !== r && o.x < r.x && sameRow(o, r))) continue;
|
|
4622
|
+
const row = left.filter((l2) => sameRow(l2, r));
|
|
4623
|
+
if (row.length === 0) continue;
|
|
4624
|
+
const l = row.reduce((a, b) => b.x + b.w > a.x + a.w ? b : a);
|
|
4625
|
+
if (!lone(l) || !lone(r)) return false;
|
|
4626
|
+
spaced++;
|
|
4627
|
+
}
|
|
4628
|
+
return spaced > 0;
|
|
4629
|
+
}
|
|
4630
|
+
function staggeredSides(items, cutX) {
|
|
4631
|
+
const left = items.filter((i) => i.x + i.w / 2 < cutX);
|
|
4632
|
+
const right = items.filter((i) => i.x + i.w / 2 >= cutX);
|
|
4633
|
+
if (left.length * right.length > 2e5) return false;
|
|
4634
|
+
const shareRow = (a, b) => Math.min(a.y, b.y) > Math.max(a.y - a.h, b.y - b.h);
|
|
4635
|
+
if (left.some((a) => right.some((b) => shareRow(a, b)))) return false;
|
|
4636
|
+
const sides = [...items].sort((a, b) => b.y - a.y).map((i) => i.x + i.w / 2 < cutX);
|
|
4637
|
+
let switches = 0;
|
|
4638
|
+
for (let k = 1; k < sides.length; k++) if (sides[k] !== sides[k - 1]) switches++;
|
|
4639
|
+
return switches >= 3;
|
|
4640
|
+
}
|
|
4510
4641
|
function identifyCrossLayoutItems(items) {
|
|
4511
4642
|
const cross = /* @__PURE__ */ new Set();
|
|
4512
4643
|
if (items.length < 3) return cross;
|
|
@@ -4669,6 +4800,27 @@ function splitEdgeSpannedColumns(items, gapThreshold, depth) {
|
|
|
4669
4800
|
];
|
|
4670
4801
|
}
|
|
4671
4802
|
|
|
4803
|
+
// src/pdf/blank-fills.ts
|
|
4804
|
+
var FILL_EDGE_GAP = 6;
|
|
4805
|
+
var FILL_MAX_THICKNESS = 2;
|
|
4806
|
+
function fillBlanks(items, horizontals, verticals = []) {
|
|
4807
|
+
const widened = /* @__PURE__ */ new Map();
|
|
4808
|
+
const used = /* @__PURE__ */ new Set();
|
|
4809
|
+
for (const h of horizontals) {
|
|
4810
|
+
if (h.lineWidth > FILL_MAX_THICKNESS || Math.abs(h.y1 - h.y2) > 1) continue;
|
|
4811
|
+
const x1 = Math.min(h.x1, h.x2), x2 = Math.max(h.x1, h.x2);
|
|
4812
|
+
const row = items.filter((i) => i.y >= h.y1 && i.y - h.y1 <= Math.max(3, i.fontSize * 0.5));
|
|
4813
|
+
const left = row.find((i) => i.x + i.w <= x1 + 1 && x1 - (i.x + i.w) <= FILL_EDGE_GAP);
|
|
4814
|
+
const right = row.find((i) => i.x >= x2 - 1 && i.x - x2 <= FILL_EDGE_GAP);
|
|
4815
|
+
if (!left || !right || widened.has(left) || row.some((i) => i.x < x2 && i.x + i.w > x1) || x2 - x1 < 2 * left.fontSize) continue;
|
|
4816
|
+
if (verticals.some((v) => (Math.abs(v.x1 - x1) <= 3 || Math.abs(v.x1 - x2) <= 3) && Math.min(v.y1, v.y2) - 3 <= h.y1 && Math.max(v.y1, v.y2) + 3 >= h.y1)) continue;
|
|
4817
|
+
widened.set(left, { ...left, text: left.text.trimEnd() + " ", w: x2 - left.x });
|
|
4818
|
+
used.add(h);
|
|
4819
|
+
}
|
|
4820
|
+
if (!used.size) return { items, horizontals };
|
|
4821
|
+
return { items: items.map((i) => widened.get(i) ?? i), horizontals: horizontals.filter((h) => !used.has(h)) };
|
|
4822
|
+
}
|
|
4823
|
+
|
|
4672
4824
|
// src/pdf/two-column.ts
|
|
4673
4825
|
var GUTTER_SCAN_LO = 0.3;
|
|
4674
4826
|
var GUTTER_SCAN_HI = 0.7;
|
|
@@ -5273,6 +5425,23 @@ function headerLineAbove(free, colXs, top) {
|
|
|
5273
5425
|
return cols;
|
|
5274
5426
|
}
|
|
5275
5427
|
|
|
5428
|
+
// src/pdf/page-frame.ts
|
|
5429
|
+
function isPageFrameGrid(grid, cells, pageWidth, pageHeight, items = []) {
|
|
5430
|
+
const b = grid.bbox;
|
|
5431
|
+
if (grid.cells || b.x2 - b.x1 < pageWidth * 0.85 || b.y2 - b.y1 < pageHeight * 0.75) return false;
|
|
5432
|
+
const pageArea = pageWidth * pageHeight;
|
|
5433
|
+
const area = (c) => (c.bbox.x2 - c.bbox.x1) * (c.bbox.y2 - c.bbox.y1);
|
|
5434
|
+
const big = cells.filter((c) => area(c) >= pageArea * 0.15);
|
|
5435
|
+
if (big.reduce((s, c) => s + area(c), 0) < pageArea * 0.5) return false;
|
|
5436
|
+
const inner = grid.colXs.slice(1, -1);
|
|
5437
|
+
const inBig = items.filter((it) => big.some((c) => {
|
|
5438
|
+
const cx = it.x + it.w / 2, cy = it.y + it.h / 2;
|
|
5439
|
+
return cx > c.bbox.x1 && cx < c.bbox.x2 && cy > c.bbox.y1 && cy < c.bbox.y2;
|
|
5440
|
+
}));
|
|
5441
|
+
const crossing = inBig.filter((it) => inner.some((x) => x > it.x + 1 && x < it.x + it.w - 1)).length;
|
|
5442
|
+
return inner.length === 0 || crossing >= 1 && crossing >= inBig.length * 0.01;
|
|
5443
|
+
}
|
|
5444
|
+
|
|
5276
5445
|
// src/pdf/open-table-ends.ts
|
|
5277
5446
|
var ALIGN_TOL = 3;
|
|
5278
5447
|
var MIN_RULES = 3;
|
|
@@ -5306,6 +5475,19 @@ function commonEnd(ends) {
|
|
|
5306
5475
|
}
|
|
5307
5476
|
return bestN >= MIN_REACHING ? best : null;
|
|
5308
5477
|
}
|
|
5478
|
+
function splitBodies(g, chained) {
|
|
5479
|
+
if (g.length < MIN_RULES * 2) return [g];
|
|
5480
|
+
const x1 = Math.min(...g.map((r) => r.x1)), x2 = Math.max(...g.map((r) => r.x2));
|
|
5481
|
+
const sorted = [...g].sort((a, b) => b.y1 - a.y1);
|
|
5482
|
+
const parts = [[sorted[0]]];
|
|
5483
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
5484
|
+
const upper = sorted[i - 1].y1, lower = sorted[i].y1;
|
|
5485
|
+
const joined = chained.some((v) => v.x1 >= x1 - ALIGN_TOL && v.x1 <= x2 + ALIGN_TOL && v.y2 >= upper - TOUCH_TOL && v.y1 <= lower + TOUCH_TOL);
|
|
5486
|
+
if (joined) parts[parts.length - 1].push(sorted[i]);
|
|
5487
|
+
else parts.push([sorted[i]]);
|
|
5488
|
+
}
|
|
5489
|
+
return parts.filter((p) => p.length >= MIN_RULES).length >= 2 ? parts : [g];
|
|
5490
|
+
}
|
|
5309
5491
|
function closeOpenTableEnds(horizontals, verticals, textLayer = false) {
|
|
5310
5492
|
if (horizontals.length < MIN_RULES || verticals.length < MIN_REACHING) return horizontals;
|
|
5311
5493
|
const groups = [];
|
|
@@ -5316,7 +5498,7 @@ function closeOpenTableEnds(horizontals, verticals, textLayer = false) {
|
|
|
5316
5498
|
}
|
|
5317
5499
|
const chained = chainVerticals2(verticals);
|
|
5318
5500
|
const added = [];
|
|
5319
|
-
for (const g of groups) {
|
|
5501
|
+
for (const g of groups.flatMap((gr) => splitBodies(gr, chained))) {
|
|
5320
5502
|
if (g.length < MIN_RULES) continue;
|
|
5321
5503
|
const x1 = Math.min(...g.map((r) => r.x1)), x2 = Math.max(...g.map((r) => r.x2));
|
|
5322
5504
|
const yLo = Math.min(...g.map((r) => r.y1)), yHi = Math.max(...g.map((r) => r.y1));
|
|
@@ -5924,6 +6106,9 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
|
|
|
5924
6106
|
for (const line of streamLines(items)) lex.addLine(mergeLineSimple(line));
|
|
5925
6107
|
const extracted = extractLines(opList.fnArray, opList.argsArray);
|
|
5926
6108
|
let { horizontals, verticals } = extracted;
|
|
6109
|
+
const filled = fillBlanks(items, horizontals, verticals);
|
|
6110
|
+
items = filled.items;
|
|
6111
|
+
horizontals = filled.horizontals;
|
|
5927
6112
|
const prevPage = carry?.page === pageNum - 1 ? carry.clip : void 0;
|
|
5928
6113
|
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 };
|
|
5929
6114
|
if (carry) {
|
|
@@ -5989,6 +6174,7 @@ function markStrikethroughItems(items, horizontals) {
|
|
|
5989
6174
|
if (line.lineWidth > STRIKE_MAX_THICKNESS) continue;
|
|
5990
6175
|
const matches = [];
|
|
5991
6176
|
for (const item of items) {
|
|
6177
|
+
if (item.fontName === "ocr") continue;
|
|
5992
6178
|
const h = item.h > 0 ? item.h : item.fontSize;
|
|
5993
6179
|
if (h <= 0 || item.w <= 0) continue;
|
|
5994
6180
|
if (line.lineWidth > h * STRIKE_MAX_THICKNESS_RATIO) continue;
|
|
@@ -6069,16 +6255,25 @@ function isProseBoxGrid(grid, verticals, table) {
|
|
|
6069
6255
|
if (longCells < PROSEBOX_LONG_CELL_MIN || longCells < texts.length * PROSEBOX_LONG_CELL_RATIO) return false;
|
|
6070
6256
|
return true;
|
|
6071
6257
|
}
|
|
6258
|
+
function isSparseProseGrid(table) {
|
|
6259
|
+
if (table.rows < 4) return false;
|
|
6260
|
+
const texts = table.cells.flat().map((c) => c.text.trim());
|
|
6261
|
+
const filled = texts.filter(Boolean);
|
|
6262
|
+
if (filled.length === 0 || filled.length > texts.length * 0.25) return false;
|
|
6263
|
+
const chars = filled.reduce((n, t) => n + t.length, 0);
|
|
6264
|
+
const prose = filled.filter((t) => t.length >= 60 && /[.!?。]/.test(t)).reduce((n, t) => n + t.length, 0);
|
|
6265
|
+
return prose >= chars * 0.6;
|
|
6266
|
+
}
|
|
6072
6267
|
function cleanCellText(text) {
|
|
6073
6268
|
const stripped = text.replace(/^[\s]*[-–—]\s*\d+\s*[-–—][\s]*$/gm, "").trim();
|
|
6074
6269
|
return stripped.split("\n").map((line) => collapseEvenSpacing(line)).join("\n");
|
|
6075
6270
|
}
|
|
6076
6271
|
var FRAME_RECT_TOL = 1.5;
|
|
6077
|
-
function takePendingNested(pending, cellBox) {
|
|
6272
|
+
function takePendingNested(pending, cellBox, clipCell) {
|
|
6078
6273
|
const out = [];
|
|
6079
6274
|
for (let i = pending.length - 1; i >= 0; i--) {
|
|
6080
6275
|
const p = pending[i].parent;
|
|
6081
|
-
if (Math.abs(p.x1 - cellBox.x1) <= FRAME_RECT_TOL && Math.abs(p.x2 - cellBox.x2) <= FRAME_RECT_TOL && Math.abs(p.y1 - cellBox.y1) <= FRAME_RECT_TOL && Math.abs(p.y2 - cellBox.y2) <= FRAME_RECT_TOL) {
|
|
6276
|
+
if (pending[i].contained ? p.x1 >= cellBox.x1 - FRAME_RECT_TOL && p.x2 <= cellBox.x2 + FRAME_RECT_TOL && p.y1 >= cellBox.y1 - FRAME_RECT_TOL && p.y2 <= cellBox.y2 + FRAME_RECT_TOL : clipCell && Math.abs(p.x1 - cellBox.x1) <= FRAME_RECT_TOL && Math.abs(p.x2 - cellBox.x2) <= FRAME_RECT_TOL && Math.abs(p.y1 - cellBox.y1) <= FRAME_RECT_TOL && Math.abs(p.y2 - cellBox.y2) <= FRAME_RECT_TOL) {
|
|
6082
6277
|
out.push(pending[i].block);
|
|
6083
6278
|
pending.splice(i, 1);
|
|
6084
6279
|
}
|
|
@@ -6107,6 +6302,7 @@ function buildFrameCellBlocks(cellItems, nested, pageNum, wrap) {
|
|
|
6107
6302
|
return { blocks, text };
|
|
6108
6303
|
}
|
|
6109
6304
|
function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, horizontals, verticals, imageRegions = [], lex, ruled = []) {
|
|
6305
|
+
const ocrPage = items.length > 0 && items.every((i) => i.fontName === "ocr");
|
|
6110
6306
|
const blocks = [];
|
|
6111
6307
|
const usedItems = /* @__PURE__ */ new Set();
|
|
6112
6308
|
for (const r of ruled) {
|
|
@@ -6116,13 +6312,15 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
6116
6312
|
const proseSidebars = /* @__PURE__ */ new Set();
|
|
6117
6313
|
const pendingNested = [];
|
|
6118
6314
|
const gridArea = (g) => (g.bbox.x2 - g.bbox.x1) * (g.bbox.y2 - g.bbox.y1);
|
|
6119
|
-
const sortedGrids = [...grids].sort((a, b) => (b.cells ? 1 : 0) - (a.cells ? 1 : 0) || (a.cells && b.cells ? gridArea(a) - gridArea(b) : 0) || b.bbox.y2 - a.bbox.y2);
|
|
6315
|
+
const sortedGrids = [...grids].sort((a, b) => (b.cells ? 1 : 0) - (a.cells ? 1 : 0) || (a.cells && b.cells ? gridArea(a) - gridArea(b) : 0) || (b.lineNested ? 1 : 0) - (a.lineNested ? 1 : 0) || (a.lineNested && b.lineNested ? gridArea(a) - gridArea(b) : 0) || b.bbox.y2 - a.bbox.y2);
|
|
6120
6316
|
for (const grid of sortedGrids) {
|
|
6121
6317
|
const numGridRows = grid.rowYs.length - 1;
|
|
6122
6318
|
const numGridCols = grid.colXs.length - 1;
|
|
6123
6319
|
const gridW = grid.bbox.x2 - grid.bbox.x1;
|
|
6124
|
-
|
|
6125
|
-
if (!grid.cells &&
|
|
6320
|
+
const holdsNested = !grid.cells && pendingNested.some((p) => p.contained && p.parent.x1 >= grid.bbox.x1 - FRAME_RECT_TOL && p.parent.x2 <= grid.bbox.x2 + FRAME_RECT_TOL && p.parent.y1 >= grid.bbox.y1 - FRAME_RECT_TOL && p.parent.y2 <= grid.bbox.y2 + FRAME_RECT_TOL);
|
|
6321
|
+
if (!grid.cells && !holdsNested && numGridRows === 1 && numGridCols >= 2) continue;
|
|
6322
|
+
if (!grid.cells && !holdsNested && numGridCols === 1 && numGridRows >= 2 && (numGridRows < 5 || gridW > pageWidth * 0.7)) continue;
|
|
6323
|
+
if (!holdsNested && isPageFrameGrid(grid, extractCells(grid, horizontals, verticals), pageWidth, pageHeight, items)) continue;
|
|
6126
6324
|
const tableItems = [];
|
|
6127
6325
|
const pad = 3;
|
|
6128
6326
|
for (const item of items) {
|
|
@@ -6158,7 +6356,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
6158
6356
|
let nestedAttached = false;
|
|
6159
6357
|
for (const cell of cells) {
|
|
6160
6358
|
const cellItems = cellTextMap.get(cell) || [];
|
|
6161
|
-
const nested =
|
|
6359
|
+
const nested = pendingNested.length ? takePendingNested(pendingNested, cell.bbox, !!grid.cells) : [];
|
|
6162
6360
|
if (nested.length > 0) {
|
|
6163
6361
|
nestedAttached = true;
|
|
6164
6362
|
const built = buildFrameCellBlocks(cellItems, nested, pageNum, { box: cell.bbox, lex });
|
|
@@ -6216,6 +6414,18 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
6216
6414
|
finalRows++;
|
|
6217
6415
|
for (const item of unitLine) usedItems.add(item);
|
|
6218
6416
|
}
|
|
6417
|
+
const filledCells = finalGrid.flat().filter((c) => c.text.trim()).length;
|
|
6418
|
+
if (!rebuiltUsed && filledCells * 2 >= finalGrid.flat().length && !/^\s*\(\s*단위\s*[::]/.test(finalGrid[0]?.[0]?.text ?? "")) {
|
|
6419
|
+
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);
|
|
6420
|
+
const line = above.filter((it) => Math.abs(it.y - Math.min(...above.map((a) => a.y))) <= 1).sort((a, b) => a.x - b.x);
|
|
6421
|
+
const text = line.map((it) => it.text).join("");
|
|
6422
|
+
const inset = line.length ? grid.bbox.x2 - (line[line.length - 1].x + line[line.length - 1].w) : 0;
|
|
6423
|
+
if (line.length && /^\s*\(\s*단위\s*[::]/.test(text) && inset >= 4.6 && inset <= 5.6) {
|
|
6424
|
+
finalGrid.unshift(Array.from({ length: numCols }, (_, c) => ({ text: c === 0 ? cleanCellText(text) : "", colSpan: c === 0 ? numCols : 1, rowSpan: 1 })));
|
|
6425
|
+
finalRows++;
|
|
6426
|
+
for (const item of line) usedItems.add(item);
|
|
6427
|
+
}
|
|
6428
|
+
}
|
|
6219
6429
|
let semanticOneColumn = false;
|
|
6220
6430
|
if (!grid.cells && numCols === 1 && numGridRows >= 2) {
|
|
6221
6431
|
const populatedRows = finalGrid.filter((row) => row[0]?.text.trim());
|
|
@@ -6276,11 +6486,11 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
6276
6486
|
pendingNested.push({ parent: grid.clipParent, block: { type: "table", table: irTable, pageNumber: pageNum, bbox: nb } });
|
|
6277
6487
|
continue;
|
|
6278
6488
|
}
|
|
6279
|
-
if (!grid.cells && isProseBoxGrid(grid, verticals, irTable)) {
|
|
6489
|
+
if (!grid.cells && !nestedAttached && (isProseBoxGrid(grid, verticals, irTable) || ocrPage && isSparseProseGrid(irTable))) {
|
|
6280
6490
|
for (const it of tableItems) usedItems.delete(it);
|
|
6281
6491
|
continue;
|
|
6282
6492
|
}
|
|
6283
|
-
if (!grid.cells && isChartTable(irTable)) {
|
|
6493
|
+
if (!grid.cells && !nestedAttached && isChartTable(irTable)) {
|
|
6284
6494
|
blocks.push(chartBlock(tableItems, pageNum, { page: pageNum, x: grid.bbox.x1, y: grid.bbox.y1, width: gridW, height: grid.bbox.y2 - grid.bbox.y1 }));
|
|
6285
6495
|
continue;
|
|
6286
6496
|
}
|
|
@@ -6318,6 +6528,10 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
6318
6528
|
}
|
|
6319
6529
|
continue;
|
|
6320
6530
|
}
|
|
6531
|
+
if (grid.lineNested) {
|
|
6532
|
+
pendingNested.push({ parent: grid.bbox, block: { type: "table", table: irTable, pageNumber: pageNum, bbox: tableBbox }, contained: true });
|
|
6533
|
+
continue;
|
|
6534
|
+
}
|
|
6321
6535
|
blocks.push({ type: "table", table: irTable, pageNumber: pageNum, bbox: tableBbox });
|
|
6322
6536
|
}
|
|
6323
6537
|
for (const p of pendingNested) blocks.push(p.block);
|
|
@@ -6339,7 +6553,10 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
|
|
|
6339
6553
|
hasSpaceBefore: i.hasSpaceBefore
|
|
6340
6554
|
}));
|
|
6341
6555
|
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;
|
|
6342
|
-
const clusterResults = proseColumns ? [] : detectClusterTables(clusterItems, pageNum)
|
|
6556
|
+
const clusterResults = (proseColumns ? [] : detectClusterTables(clusterItems, pageNum)).filter((cr) => {
|
|
6557
|
+
const b = cr.bbox;
|
|
6558
|
+
return !blocks.some((x) => x.type === "paragraph" && x.bbox && (x.text?.match(/\p{L}/gu)?.length ?? 0) >= 10 && Math.min(x.bbox.x + x.bbox.width, b.x + b.width) - Math.max(x.bbox.x, b.x) >= 0.8 * b.width && x.bbox.y >= b.y - 2 && x.bbox.y + x.bbox.height <= b.y + b.height + 2);
|
|
6559
|
+
});
|
|
6343
6560
|
if (clusterResults.length > 0) {
|
|
6344
6561
|
const ciToIdx = /* @__PURE__ */ new Map();
|
|
6345
6562
|
for (let ci = 0; ci < clusterItems.length; ci++) ciToIdx.set(clusterItems[ci], ci);
|
|
@@ -6503,6 +6720,7 @@ function clusterTableBlock(cr, source, pageNum, horizontals = []) {
|
|
|
6503
6720
|
if (!ruled && isTableOfContents(cr.table)) return tocBlock(cr.table, pageNum, cr.bbox, dominantStyle(source));
|
|
6504
6721
|
if (isChartTable(cr.table)) return chartBlock(source, pageNum, cr.bbox);
|
|
6505
6722
|
if (isFormulaTable(cr.table)) return chartBlock(source, pageNum, cr.bbox);
|
|
6723
|
+
if (isExamLayoutTable(cr.table)) return { ...chartBlock(source, pageNum, cr.bbox), text: groupByY(source).map((line) => mergeLineSimple(line).trim()).filter(Boolean).join("\n") };
|
|
6506
6724
|
return { type: "table", table: cr.table, pageNumber: pageNum, bbox: cr.bbox };
|
|
6507
6725
|
}
|
|
6508
6726
|
function chartBlock(source, pageNum, bbox) {
|
|
@@ -6725,6 +6943,7 @@ function extractPageBlocksFallback(items, pageNum, fullPage = false, detectTable
|
|
|
6725
6943
|
}
|
|
6726
6944
|
|
|
6727
6945
|
export {
|
|
6946
|
+
extractLines,
|
|
6728
6947
|
extractImageRegions,
|
|
6729
6948
|
filterHiddenText,
|
|
6730
6949
|
collapseEvenSpacing,
|
|
@@ -6757,4 +6976,4 @@ export {
|
|
|
6757
6976
|
trimTrailingEmptyTableCols,
|
|
6758
6977
|
extractPageBlocksWithLines
|
|
6759
6978
|
};
|
|
6760
|
-
//# sourceMappingURL=chunk-
|
|
6979
|
+
//# sourceMappingURL=chunk-43FKGDDO.js.map
|