meticulous-ui 3.12.0 → 3.12.1

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/index.d.ts CHANGED
@@ -1488,28 +1488,32 @@ export declare function getQrAsJsonContent(source: QrSource): Promise<QrJsonResu
1488
1488
 
1489
1489
  export interface RecognizeImageResult {
1490
1490
  success: boolean;
1491
- /** Whether the TextDetector API is available in this browser. */
1492
- supported?: boolean;
1493
1491
  /** BCP-47 code of the primary language used for recognition. */
1494
1492
  detectedLanguage?: string;
1495
- /** Full extracted text, newline-separated by detected region. */
1493
+ /** Full extracted text from OCR, newline-separated by detected region. */
1496
1494
  text?: string;
1497
- /** OCR confidence score 0–100, or null when not available. */
1495
+ /** OCR confidence score 0–100. */
1498
1496
  confidence?: number | null;
1499
- /** Raw per-region data including bounding boxes and corner points. */
1500
- rawJson?: Array<{
1501
- rawValue: string;
1502
- boundingBox: { x: number; y: number; width: number; height: number };
1503
- cornerPoints: Array<{ x: number; y: number }>;
1504
- }>;
1497
+ /**
1498
+ * All readable lines from the OCR output as a key-value object.
1499
+ * Lines matching `ALL-CAPS KEY : value` use the label as the key.
1500
+ * Lines without a recognisable label are assigned generic keys (`param_1`, `param_2`, …).
1501
+ * Continuation lines (e.g. a wrapped address) are appended to the previous key.
1502
+ */
1503
+ fields?: Record<string, string>;
1504
+ /** Raw Tesseract output including per-word bounding boxes and metadata. */
1505
+ rawJson?: object;
1505
1506
  /** Human-readable error when success is false. */
1506
1507
  error?: string;
1507
1508
  }
1508
1509
 
1509
1510
  /**
1510
- * Detect text in a base64 image using the browser-native TextDetector API.
1511
- * No external dependencies or network requests.
1512
- * Supported in Chrome 70+ and Edge 79+; returns supported:false on other browsers.
1511
+ * Runs OCR on a base64 image in all browsers with no npm dependency.
1512
+ * Powered by Tesseract.js loaded on demand from a CDN (fetched once, then
1513
+ * browser-cached). Preprocesses the image (grayscale + upscale + contrast
1514
+ * boost) before recognition for higher accuracy. Returns structured `fields`
1515
+ * with extracted key-value pairs alongside the raw `text`, `confidence` score,
1516
+ * and `rawJson` with full word-level bounding-box metadata.
1513
1517
  */
1514
1518
  export declare function recognizeImageContent(
1515
1519
  base64Image: string,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meticulous-ui",
3
- "version": "3.12.0",
3
+ "version": "3.12.1",
4
4
  "license": "ISC",
5
5
  "description": "A comprehensive React UI component library with a wide range of customizable components, icons, colors, and utilities for building modern web applications.",
6
6
  "types": "./index.d.ts",
@@ -1,4 +1,62 @@
1
- const l = {
1
+ const b = (l) => new Promise((n, s) => {
2
+ const o = new Image();
3
+ o.onload = () => {
4
+ const r = document.createElement("canvas");
5
+ r.width = o.width * 2, r.height = o.height * 2;
6
+ const e = r.getContext("2d");
7
+ e.filter = "grayscale(1) contrast(1.8)", e.drawImage(o, 0, 0, r.width, r.height), n(r.toDataURL("image/png"));
8
+ }, o.onerror = s, o.src = l;
9
+ }), u = (l) => {
10
+ var r;
11
+ const n = ((r = l.words) != null ? r : []).map((e) => {
12
+ var t;
13
+ return { text: (t = e.text) == null ? void 0 : t.trim(), bbox: e.bbox };
14
+ }).filter((e) => e.text && e.bbox);
15
+ if (!n.length) return [];
16
+ const s = [];
17
+ for (const e of n) {
18
+ const t = (e.bbox.y0 + e.bbox.y1) / 2, c = (e.bbox.y1 - e.bbox.y0) / 2;
19
+ let a = s.find((m) => Math.abs(m.cy - t) < c);
20
+ a || (a = { cy: t, words: [] }, s.push(a)), a.words.push(e);
21
+ }
22
+ const o = [];
23
+ for (const e of s) {
24
+ const t = e.words.slice().sort((i, x) => i.bbox.x0 - x.bbox.x0), c = t.slice(1).map((i, x) => i.bbox.x0 - t[x].bbox.x1), a = c.length ? c.reduce((i, x) => i + x, 0) / c.length : 0, m = Math.max(a * 3, (t[0].bbox.y1 - t[0].bbox.y0) * 1.5);
25
+ let d = [t[0]];
26
+ for (let i = 1; i < t.length; i++)
27
+ t[i].bbox.x0 - t[i - 1].bbox.x1 > m && (o.push({
28
+ text: d.map((x) => x.text).join(" "),
29
+ y: e.cy,
30
+ x: d[0].bbox.x0
31
+ }), d = []), d.push(t[i]);
32
+ o.push({
33
+ text: d.map((i) => i.text).join(" "),
34
+ y: e.cy,
35
+ x: d[0].bbox.x0
36
+ });
37
+ }
38
+ return o.sort((e, t) => e.y - t.y || e.x - t.x), o.map((e) => e.text);
39
+ }, h = (l) => {
40
+ const n = {};
41
+ let s = null, o = 0;
42
+ const r = (e) => {
43
+ let t = e.replace(/^[^A-Za-z0-9"'(]+/, "").trim();
44
+ return t = t.replace(/[^A-Za-z0-9"')]+$/, "").trim(), t = t.replace(/^[A-Za-z]{1,3}\s+(?=\d)/, ""), t;
45
+ };
46
+ for (const e of l) {
47
+ const t = r(e.trim());
48
+ if (!t) {
49
+ s = null;
50
+ continue;
51
+ }
52
+ const c = t.match(/\b([A-Z][A-Z.]{0,}(?:\s+[A-Z.]+){0,2})\s*[:©]\s*(.+)/);
53
+ if (c) {
54
+ const a = c[1].trim();
55
+ n[a] = c[2].trim(), s = a;
56
+ } else s && /^[A-Z0-9][A-Z0-9\s.,'\-]+$/.test(t) ? (n[s] += " " + t, s = null) : (/\w{3,}/.test(t) && (n[`param_${++o}`] = t), s = null);
57
+ }
58
+ return n;
59
+ }, g = {
2
60
  en: "eng",
3
61
  hi: "hin",
4
62
  fr: "fra",
@@ -17,37 +75,40 @@ const l = {
17
75
  vi: "vie",
18
76
  th: "tha",
19
77
  id: "ind"
20
- }, d = (t) => t.map((r) => {
21
- var e;
22
- return (e = l[r]) != null ? e : r;
78
+ }, f = (l) => l.map((n) => {
79
+ var s;
80
+ return (s = g[n]) != null ? s : n;
23
81
  }).join("+");
24
- let s = null;
25
- const u = () => (s || (s = import(
82
+ let p = null;
83
+ const y = () => (p || (p = import(
26
84
  /* webpackIgnore: true */
27
85
  /* @vite-ignore */
28
86
  "https://esm.sh/tesseract.js@5"
29
- )), s), p = async (t, r = "en") => {
30
- var e;
87
+ )), p), w = async (l, n = "en") => {
88
+ var s;
31
89
  try {
32
- const a = t.startsWith("data:") ? t : `data:image/png;base64,${t}`, o = r.split("+").filter(Boolean), { createWorker: i } = await u(), c = await i(d(o));
90
+ const o = l.startsWith("data:") ? l : `data:image/png;base64,${l}`, r = n.split("+").filter(Boolean), e = await b(o), { createWorker: t } = await y(), c = await t(f(r));
33
91
  try {
34
- const { data: n } = await c.recognize(a);
92
+ await c.setParameters({ tessedit_pageseg_mode: "3" });
93
+ const { data: a } = await c.recognize(e), m = a.text.trim();
35
94
  return {
36
95
  success: !0,
37
- detectedLanguage: (e = o[0]) != null ? e : "en",
38
- text: n.text.trim(),
39
- confidence: n.confidence,
96
+ detectedLanguage: (s = r[0]) != null ? s : "en",
97
+ text: m,
98
+ confidence: a.confidence,
40
99
  // 0–100
41
- rawJson: n
100
+ fields: h(u(a)),
101
+ // structured key-value extraction, split on bbox gaps
102
+ rawJson: a
42
103
  // full metadata: words, blocks, bounding boxes
43
104
  };
44
105
  } finally {
45
106
  await c.terminate();
46
107
  }
47
- } catch (a) {
48
- return { success: !1, error: a.message };
108
+ } catch (o) {
109
+ return { success: !1, error: o.message };
49
110
  }
50
111
  };
51
112
  export {
52
- p as default
113
+ w as default
53
114
  };