react-native-text-reader 1.5.0 → 2.0.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-native-text-reader",
3
- "version": "1.5.0",
4
- "description": "A React Native library for OCR (Optical Character Recognition) using Vision Framework on iOS and Firebase ML Kit on Android. Optimized for Android 16KB page size compatibility.",
3
+ "version": "2.0.0",
4
+ "description": "A React Native library for OCR using Vision Framework on iOS and ML Kit on Android. Supports Expo development builds, detailed OCR metadata, and Android 16KB page size compatibility.",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/commonjs/index.js",
7
7
  "module": "./lib/module/index.js",
@@ -25,6 +25,7 @@
25
25
  "cpp",
26
26
  "*.podspec",
27
27
  "react-native.config.json",
28
+ "app.plugin.js",
28
29
  "!ios/build",
29
30
  "!android/build",
30
31
  "!android/gradle",
@@ -37,13 +38,17 @@
37
38
  "!**/.*"
38
39
  ],
39
40
  "scripts": {
40
- "example": "yarn workspace react-native-text-reader-example",
41
+ "example": "pnpm --filter react-native-text-reader-example",
42
+ "example:prebuild": "pnpm --filter react-native-text-reader-example prebuild",
43
+ "example:ios": "pnpm --filter react-native-text-reader-example ios",
44
+ "example:android": "pnpm --filter react-native-text-reader-example android",
41
45
  "test": "jest",
42
46
  "typecheck": "tsc",
43
47
  "lint": "eslint \"**/*.{js,ts,tsx}\"",
44
48
  "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
45
49
  "prepare": "bob build",
46
- "release": "release-it"
50
+ "release": "release-it",
51
+ "audit": "pnpm audit --audit-level high"
47
52
  },
48
53
  "keywords": [
49
54
  "react-native",
@@ -64,49 +69,59 @@
64
69
  "registry": "https://registry.npmjs.org/"
65
70
  },
66
71
  "devDependencies": {
67
- "@babel/plugin-proposal-class-properties": "^7.18.6",
68
72
  "@babel/plugin-transform-class-properties": "^7.27.1",
69
73
  "@babel/preset-env": "^7.28.3",
70
- "@commitlint/config-conventional": "^17.0.2",
71
- "@evilmartians/lefthook": "^1.5.0",
72
- "@react-native/eslint-config": "^0.73.1",
73
- "@release-it/conventional-changelog": "^5.0.0",
74
- "@types/jest": "^29.5.5",
75
- "@types/react": "^19.0.0",
76
- "commitlint": "^17.0.2",
77
- "del-cli": "^5.1.0",
78
- "eslint": "^8.51.0",
79
- "eslint-config-prettier": "^9.0.0",
80
- "eslint-plugin-prettier": "^5.0.1",
81
- "jest": "^29.7.0",
82
- "prettier": "^3.0.3",
83
- "react": "19.1.1",
84
- "react-native": "0.81.4",
85
- "react-native-builder-bob": "^0.30.2",
86
- "release-it": "^15.0.0",
87
- "turbo": "^1.10.7",
88
- "typescript": "^5.2.2"
89
- },
90
- "resolutions": {
91
- "@types/react": "^19.0.0"
74
+ "@commitlint/config-conventional": "^21.0.2",
75
+ "@evilmartians/lefthook": "^2.1.9",
76
+ "@react-native/eslint-config": "^0.86.0",
77
+ "@release-it/conventional-changelog": "^11.0.1",
78
+ "@types/jest": "^30.0.0",
79
+ "@types/react": "^19.2.17",
80
+ "commitlint": "^21.0.2",
81
+ "del-cli": "^7.0.0",
82
+ "eslint": "^8.57.1",
83
+ "eslint-config-prettier": "^10.1.8",
84
+ "eslint-plugin-prettier": "^5.5.6",
85
+ "jest": "^30.4.2",
86
+ "ts-jest": "^29.4.11",
87
+ "prettier": "^3.8.4",
88
+ "react": "19.2.7",
89
+ "react-native": "0.86.0",
90
+ "react-native-builder-bob": "^0.43.0",
91
+ "release-it": "^20.2.0",
92
+ "turbo": "^2.9.18",
93
+ "typescript": "^5.9.3"
92
94
  },
93
95
  "peerDependencies": {
94
96
  "react": "*",
95
97
  "react-native": "*"
96
98
  },
97
- "workspaces": [
98
- "example"
99
- ],
100
- "packageManager": "yarn@3.6.1",
99
+ "engines": {
100
+ "node": ">=22",
101
+ "pnpm": ">=11"
102
+ },
103
+ "packageManager": "pnpm@11.8.0",
101
104
  "jest": {
102
- "preset": "react-native",
105
+ "preset": "ts-jest",
106
+ "testEnvironment": "node",
103
107
  "modulePathIgnorePatterns": [
104
- "<rootDir>/example/node_modules",
105
- "<rootDir>/lib/"
108
+ "<rootDir>/lib/",
109
+ "<rootDir>/example/"
106
110
  ],
107
- "transformIgnorePatterns": [
108
- "node_modules/(?!(react-native|@react-native|react-native-.*)/)"
109
- ]
111
+ "setupFilesAfterEnv": [
112
+ "<rootDir>/jest.setup.js"
113
+ ],
114
+ "moduleNameMapper": {
115
+ "^react-native$": "<rootDir>/jest.react-native-mock.js"
116
+ },
117
+ "transform": {
118
+ "^.+\\.tsx?$": [
119
+ "ts-jest",
120
+ {
121
+ "tsconfig": "tsconfig.test.json"
122
+ }
123
+ ]
124
+ }
110
125
  },
111
126
  "commitlint": {
112
127
  "extends": [
@@ -126,7 +141,7 @@
126
141
  },
127
142
  "plugins": {
128
143
  "@release-it/conventional-changelog": {
129
- "preset": "angular"
144
+ "preset": "conventionalcommits"
130
145
  }
131
146
  }
132
147
  },
@@ -136,6 +151,9 @@
136
151
  "@react-native",
137
152
  "prettier"
138
153
  ],
154
+ "plugins": [
155
+ "prettier"
156
+ ],
139
157
  "rules": {
140
158
  "react/react-in-jsx-scope": "off",
141
159
  "prettier/prettier": [
@@ -152,7 +170,8 @@
152
170
  },
153
171
  "eslintIgnore": [
154
172
  "node_modules/",
155
- "lib/"
173
+ "lib/",
174
+ "example/"
156
175
  ],
157
176
  "prettier": {
158
177
  "quoteProps": "consistent",
@@ -180,8 +199,7 @@
180
199
  [
181
200
  "typescript",
182
201
  {
183
- "project": "tsconfig.build.json",
184
- "esm": true
202
+ "project": "tsconfig.build.json"
185
203
  }
186
204
  ]
187
205
  ]
@@ -190,5 +208,13 @@
190
208
  "type": "module-legacy",
191
209
  "languages": "kotlin-swift",
192
210
  "version": "0.42.0"
211
+ },
212
+ "codegenConfig": {
213
+ "name": "NativeTextReaderSpec",
214
+ "type": "modules",
215
+ "jsSrcsDir": "src",
216
+ "android": {
217
+ "javaPackageName": "com.textreader"
218
+ }
193
219
  }
194
- }
220
+ }
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,41 @@
1
+ import type { TurboModule } from 'react-native';
2
+ import { TurboModuleRegistry } from 'react-native';
3
+
4
+ export type NativeOptions = {
5
+ visionIgnoreThreshold?: number;
6
+ confidenceThreshold?: number;
7
+ script?: string;
8
+ recognitionLevel?: 'fast' | 'accurate';
9
+ recognitionLanguages?: string[];
10
+ customWords?: string[];
11
+ useLanguageCorrection?: boolean;
12
+ minimumTextHeight?: number;
13
+ };
14
+
15
+ export type NativeTextLine = {
16
+ text: string;
17
+ confidence?: number;
18
+ frame?: {
19
+ top: number;
20
+ left: number;
21
+ width: number;
22
+ height: number;
23
+ };
24
+ recognizedLanguages?: string[];
25
+ };
26
+
27
+ export type NativeDetailedResult = {
28
+ fullText: string;
29
+ lines: string[];
30
+ details: NativeTextLine[];
31
+ };
32
+
33
+ export interface Spec extends TurboModule {
34
+ read(imagePath: string, options?: NativeOptions): Promise<string[]>;
35
+ readDetailed(
36
+ imagePath: string,
37
+ options?: NativeOptions
38
+ ): Promise<NativeDetailedResult>;
39
+ }
40
+
41
+ export default TurboModuleRegistry.get<Spec>('TextReader');
package/src/index.tsx CHANGED
@@ -1,13 +1,16 @@
1
1
  import { NativeModules, Platform } from 'react-native';
2
+ import NativeTextReaderModule from './NativeTextReader';
2
3
 
3
4
  const LINKING_ERROR =
4
5
  `The package 'react-native-text-reader' doesn't seem to be linked. Make sure: \n\n` +
5
6
  Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
6
7
  '- You rebuilt the app after installing the package\n' +
7
- '- You are not using Expo Go\n';
8
+ '- You are not using Expo Go (use a development build instead)\n';
8
9
 
9
- const TextReader = NativeModules.TextReader
10
- ? NativeModules.TextReader
10
+ const TextReaderModule = NativeTextReaderModule ?? NativeModules.TextReader;
11
+
12
+ const TextReader = TextReaderModule
13
+ ? TextReaderModule
11
14
  : new Proxy(
12
15
  {},
13
16
  {
@@ -25,30 +28,81 @@ export enum ScriptOptions {
25
28
  KOREAN = 'Korean',
26
29
  }
27
30
 
28
- // Options
31
+ export type RecognitionLevel = 'fast' | 'accurate';
32
+
33
+ export type TextFrame = {
34
+ top: number;
35
+ left: number;
36
+ width: number;
37
+ height: number;
38
+ };
39
+
40
+ export type TextLine = {
41
+ text: string;
42
+ confidence?: number;
43
+ frame?: TextFrame;
44
+ recognizedLanguages?: string[];
45
+ };
46
+
47
+ export type DetailedResult = {
48
+ fullText: string;
49
+ lines: string[];
50
+ details: TextLine[];
51
+ };
52
+
29
53
  export type Options = {
30
- visionIgnoreThreshold?: number; // only iOS
31
- script?: ScriptOptions; // only Android
54
+ visionIgnoreThreshold?: number;
55
+ confidenceThreshold?: number;
56
+ script?: ScriptOptions;
57
+ recognitionLevel?: RecognitionLevel;
58
+ recognitionLanguages?: string[];
59
+ customWords?: string[];
60
+ useLanguageCorrection?: boolean;
61
+ minimumTextHeight?: number;
32
62
  };
33
63
 
34
- type TextReaderType = {
64
+ type TextReaderNative = {
35
65
  read(imagePath: string, options?: Options): Promise<string[]>;
66
+ readDetailed(imagePath: string, options?: Options): Promise<DetailedResult>;
36
67
  };
37
68
 
69
+ const DEFAULT_OPTIONS: Options = {
70
+ script: ScriptOptions.LATIN,
71
+ };
72
+
73
+ function normalizeDetailedResult(result: DetailedResult): DetailedResult {
74
+ return {
75
+ fullText: result.fullText ?? '',
76
+ lines: result.lines ?? [],
77
+ details: (result.details ?? []).map((detail) => ({
78
+ text: detail.text,
79
+ confidence: detail.confidence,
80
+ frame: detail.frame,
81
+ recognizedLanguages: detail.recognizedLanguages,
82
+ })),
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Extracts text lines from an image.
88
+ */
89
+ async function read(imagePath: string, options?: Options): Promise<string[]> {
90
+ const detailed = await readDetailed(imagePath, options);
91
+ return detailed.lines;
92
+ }
93
+
38
94
  /**
39
- * Extracts text from an image.
40
- * @param imagePath - Image path
41
- * @param options - Additional options
42
- * @param options.visionIgnoreThreshold - Vision ignore threshold(iOS)
43
- * @param options.script - Language script (Android)
95
+ * Extracts text with confidence, bounding boxes, and language metadata.
44
96
  */
45
- async function read(imagePath: string, options: Options): Promise<string[]> {
46
- return await TextReader.read(
97
+ async function readDetailed(
98
+ imagePath: string,
99
+ options?: Options
100
+ ): Promise<DetailedResult> {
101
+ const result = await TextReader.readDetailed(
47
102
  imagePath,
48
- options || {
49
- script: ScriptOptions.LATIN,
50
- }
103
+ options ?? DEFAULT_OPTIONS
51
104
  );
105
+ return normalizeDetailedResult(result);
52
106
  }
53
107
 
54
- export default { read } as TextReaderType;
108
+ export default { read, readDetailed } as TextReaderNative;