picturereader 1.0.2 → 1.0.3
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/package.json +2 -1
- package/scripts/preview.mjs +40 -0
- package/scripts/setup-ocr.mjs +96 -0
- package/src/core.js +1434 -1427
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "picturereader",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "DSH plugin: pixel-to-text image reading for text-only models. Downscales and color-quantizes PNG/JPEG/GIF/BMP and feeds the coarse pixel grid to the model so DeepSeek can \u0027see\u0027 layout, colors and rough shapes without a vision model.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
13
|
"src",
|
|
14
|
+
"scripts",
|
|
14
15
|
"cordis.patch.yml",
|
|
15
16
|
"skills",
|
|
16
17
|
"README.md",
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate fixture images on disk and print the image_scan render for a
|
|
3
|
+
* quick visual sanity check without booting a harness.
|
|
4
|
+
* Usage: node scripts/preview.mjs
|
|
5
|
+
* @module picturereader/scripts/preview
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { join, dirname } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
import { analyzeImage, renderImageScan } from '../src/core.js';
|
|
12
|
+
import { makeChartRgba, makeQuadrantRgba, pngFromRgba, jpegFromRgba, gifFromRgba, bmpFromRgba } from '../tests/fixtures.mjs';
|
|
13
|
+
|
|
14
|
+
const outDir = join(dirname(fileURLToPath(import.meta.url)), '..', 'tests', 'fixtures-out');
|
|
15
|
+
mkdirSync(outDir, { recursive: true });
|
|
16
|
+
|
|
17
|
+
const images = [
|
|
18
|
+
{ name: 'chart', width: 600, height: 400, rgba: makeChartRgba(), formats: ['png', 'jpeg', 'gif', 'bmp'] },
|
|
19
|
+
{ name: 'quadrant', width: 100, height: 100, rgba: makeQuadrantRgba(), formats: ['png'] }
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
for (const image of images) {
|
|
23
|
+
for (const format of image.formats) {
|
|
24
|
+
const buffer =
|
|
25
|
+
format === 'png' ? pngFromRgba(image.width, image.height, image.rgba)
|
|
26
|
+
: format === 'jpeg' ? jpegFromRgba(image.width, image.height, image.rgba)
|
|
27
|
+
: format === 'gif' ? gifFromRgba(image.width, image.height, image.rgba)
|
|
28
|
+
: bmpFromRgba(image.width, image.height, image.rgba, 24);
|
|
29
|
+
writeFileSync(join(outDir, `${image.name}.${format}`), buffer);
|
|
30
|
+
}
|
|
31
|
+
const analysis = analyzeImage(image.rgba, image.width, image.height, { size: 32, mode: 'auto', region: undefined });
|
|
32
|
+
console.log(renderImageScan({
|
|
33
|
+
path: join(outDir, `${image.name}.png`),
|
|
34
|
+
width: image.width,
|
|
35
|
+
height: image.height,
|
|
36
|
+
region: 'full',
|
|
37
|
+
...analysis
|
|
38
|
+
}));
|
|
39
|
+
console.log();
|
|
40
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional install helper for the PaddleOCR engine (image_ocr engine="paddle").
|
|
3
|
+
* PaddleOCR is RECOMMENDED (far better at glowing/curved/game text) but
|
|
4
|
+
* OPTIONAL — image_ocr degrades to the Windows engine when it is missing.
|
|
5
|
+
*
|
|
6
|
+
* What this does:
|
|
7
|
+
* 1. Ensures a Python 3.12+ interpreter exists (downloads the official
|
|
8
|
+
* 3.12.10 installer from the npmmirror mirror if missing).
|
|
9
|
+
* 2. Creates/repairs the paddle_venv.
|
|
10
|
+
* 3. Installs paddlepaddle + paddleocr from the Tsinghua PyPI mirror.
|
|
11
|
+
* 4. Warms the model cache by running one recognition on a test image.
|
|
12
|
+
*
|
|
13
|
+
* Usage: node scripts/setup-ocr.mjs
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
16
|
+
import { spawnSync } from 'node:child_process';
|
|
17
|
+
import { join, dirname } from 'node:path';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
19
|
+
|
|
20
|
+
const PY312 = 'C:\\Users\\Administrator\\Python312\\python.exe';
|
|
21
|
+
const VENV = 'C:\\Users\\Administrator\\paddle_venv\\Scripts\\python.exe';
|
|
22
|
+
const INSTALLER = 'C:\\Users\\Administrator\\Downloads\\python-3.12.10-amd64.exe';
|
|
23
|
+
const INSTALLER_URL = 'https://registry.npmmirror.com/-/binary/python/3.12.10/python-3.12.10-amd64.exe';
|
|
24
|
+
const PYPI = 'https://pypi.tuna.tsinghua.edu.cn/simple';
|
|
25
|
+
const CACHE = join(dirname(fileURLToPath(import.meta.url)), '..', '.paddlex-cache');
|
|
26
|
+
|
|
27
|
+
function run(cmd, args, opts = {}) {
|
|
28
|
+
console.log(`> ${cmd} ${args.join(' ')}`);
|
|
29
|
+
const result = spawnSync(cmd, args, { stdio: 'inherit', ...opts });
|
|
30
|
+
if (result.status !== 0) {
|
|
31
|
+
console.error(`!! command failed (exit ${result.status})`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 1. base Python 3.12
|
|
37
|
+
if (!existsSync(PY312)) {
|
|
38
|
+
console.log('[1/4] Python 3.12 missing — downloading installer (npmmirror mirror)...');
|
|
39
|
+
run('curl.exe', ['-L', '-o', INSTALLER, INSTALLER_URL]);
|
|
40
|
+
console.log('[1/4] Installing Python 3.12 to C:\\Users\\Administrator\\Python312 (user-level, silent)...');
|
|
41
|
+
spawnSync(INSTALLER, [
|
|
42
|
+
'/quiet', 'InstallAllUsers=0', 'TargetDir=C:\\Users\\Administrator\\Python312',
|
|
43
|
+
'Include_pip=1', 'PrependPath=0', 'Include_test=0', 'Include_launcher=0'
|
|
44
|
+
], { stdio: 'inherit' });
|
|
45
|
+
if (!existsSync(PY312)) {
|
|
46
|
+
console.error('!! Python install did not produce ' + PY312);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
console.log('[1/4] Python 3.12 found at ' + PY312);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 2. venv
|
|
54
|
+
if (!existsSync(VENV)) {
|
|
55
|
+
console.log('[2/4] Creating paddle_venv...');
|
|
56
|
+
mkdirSync(dirname(VENV), { recursive: true });
|
|
57
|
+
run(PY312, ['-m', 'venv', 'C:\\Users\\Administrator\\paddle_venv']);
|
|
58
|
+
} else {
|
|
59
|
+
console.log('[2/4] paddle_venv found');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 3. paddlepaddle + paddleocr
|
|
63
|
+
const probe = spawnSync(VENV, ['-c', 'import paddleocr; print(paddleocr.__version__)'], { encoding: 'utf8' });
|
|
64
|
+
if (probe.status !== 0) {
|
|
65
|
+
console.log('[3/4] Installing paddlepaddle + paddleocr (Tsinghua mirror, ~1-3 min)...');
|
|
66
|
+
run(VENV, ['-m', 'pip', 'install', '-i', PYPI, '--upgrade', 'pip']);
|
|
67
|
+
run(VENV, ['-m', 'pip', 'install', '-i', PYPI, 'paddlepaddle==3.3.1', 'paddleocr']);
|
|
68
|
+
} else {
|
|
69
|
+
console.log(`[3/4] paddleocr already installed (${probe.stdout.trim()})`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 4. warm the model cache with one recognition
|
|
73
|
+
console.log('[4/4] Warming the model cache (first run downloads detection/recognition models)...');
|
|
74
|
+
const testImage = join(dirname(fileURLToPath(import.meta.url)), '..', 'tests', 'fixtures-out', 'ocr-test.png');
|
|
75
|
+
mkdirSync(join(CACHE), { recursive: true });
|
|
76
|
+
if (existsSync(testImage)) {
|
|
77
|
+
const warm = spawnSync(VENV, ['-c', [
|
|
78
|
+
'from paddleocr import PaddleOCR',
|
|
79
|
+
"ocr = PaddleOCR(lang='ch', use_doc_orientation_classify=False, use_doc_unwarping=False, use_textline_orientation=False, enable_mkldnn=False)",
|
|
80
|
+
`result = ocr.predict(r'${testImage.replaceAll("'", "''")}')`,
|
|
81
|
+
'print("warm-up OCR ok, lines:", sum(len(r.get("rec_texts") or []) for r in result))'
|
|
82
|
+
].join('; ')], {
|
|
83
|
+
env: { ...process.env, PADDLE_PDX_CACHE_HOME: CACHE, PYTHONIOENCODING: 'utf-8' },
|
|
84
|
+
encoding: 'utf8'
|
|
85
|
+
});
|
|
86
|
+
if (warm.status !== 0) {
|
|
87
|
+
console.error('!! warm-up failed — see output above; the engine may still work once models download');
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
console.log(warm.stdout.trim());
|
|
91
|
+
} else {
|
|
92
|
+
console.log('[4/4] test image missing — skip warm-up (first image_ocr paddle call will download models)');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log('\nDone. image_ocr engine="paddle" is now available.');
|
|
96
|
+
console.log('Verify: ask the model to read an image with image_ocr(engine="paddle").');
|