Skip to content

Commit af1e3ed

Browse files
feat: add rn-mlkit-ocr
1 parent 157d61f commit af1e3ed

27 files changed

Lines changed: 16390 additions & 105 deletions

README.md

Lines changed: 203 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,225 @@
22

33
A powerful React Native OCR (Optical Character Recognition) module powered by Google ML Kit. Supports multiple languages and scripts with selective model loading for optimized app size.
44

5-
## Installation
5+
## Features
6+
7+
- 🌍 **Multi-language support**: Latin, Chinese, Devanagari, Japanese, and Korean scripts
8+
- 📦 **Selective model loading**: Include only the languages you need to minimize app size
9+
-**High performance**: Powered by Google ML Kit's on-device text recognition
10+
- 🔄 **Flexible deployment**: Choose between bundled models (offline) or unbundled models (download on demand)
11+
- 📱 **Cross-platform**: Works on both iOS and Android
612

13+
## Requirements
714

8-
```sh
15+
- iOS 15.5+
16+
- Android API 21+
17+
18+
## Installation
19+
20+
```bash
921
npm install rn-mlkit-ocr
22+
# or
23+
yarn add rn-mlkit-ocr
24+
```
25+
26+
### iOS Setup
27+
28+
Run pod install:
29+
30+
```bash
31+
cd ios && pod install
32+
```
33+
34+
### Android Setup
35+
36+
No additional setup required for Android.
37+
38+
## Configuration
39+
40+
### Selecting OCR Models
41+
42+
By default, all language models are included. To optimize your app size, you can specify which models to include.
43+
44+
#### For Expo Projects
45+
46+
Add the plugin to your `app.json` or `app.config.js`:
47+
48+
```json
49+
{
50+
"expo": {
51+
"plugins": [
52+
[
53+
"rn-mlkit-ocr",
54+
{
55+
"ocrModels": ["latin", "chinese"],
56+
"ocrUseBundled": true
57+
}
58+
]
59+
]
60+
}
61+
}
62+
```
63+
64+
#### For React Native CLI Projects
65+
66+
##### Android
67+
68+
Add the following to your `android/build.gradle` file inside the `buildscript { ext { ... } }` block:
69+
70+
```gradle
71+
buildscript {
72+
ext {
73+
// ... other configurations
74+
ocrModels = ["latin", "chinese"]
75+
ocrUseBundled = true
76+
}
77+
}
1078
```
1179

80+
##### iOS
81+
82+
Add the following to your `ios/Podfile` before the `use_react_native!` call:
83+
84+
```ruby
85+
# --- RN-MLKIT-OCR CONFIG ---
86+
$ReactNativeOcrSubspecs = ['Latin', 'Chinese']
87+
# --- END RN-MLKIT-OCR CONFIG ---
88+
```
89+
90+
### Configuration Options
91+
92+
- **`ocrModels`**: Array of language models to include
93+
- Available options: `'latin'`, `'chinese'`, `'devanagari'`, `'japanese'`, `'korean'`, or `'all'`
94+
- Default: `['all']`
95+
- **`ocrUseBundled`** (Android only): Whether to use bundled models
96+
- `true`: Models are bundled with the app (larger app size, works offline immediately)
97+
- `false`: Models are downloaded on first use (smaller app size, requires internet on first use)
98+
- Default: `false`
1299

13100
## Usage
14101

102+
### Basic Text Recognition
103+
104+
```typescript
105+
import { recognizeText } from 'rn-mlkit-ocr';
106+
107+
const imageUri = 'file:///path/to/image.jpg'; // or 'https://...'
108+
109+
try {
110+
const result = await recognizeText(imageUri);
111+
console.log('Recognized text:', result.text);
112+
113+
// Access detailed information
114+
result.blocks.forEach((block) => {
115+
console.log('Block:', block.text);
116+
block.lines.forEach((line) => {
117+
console.log(' Line:', line.text);
118+
line.elements.forEach((element) => {
119+
console.log(' Element:', element.text);
120+
});
121+
});
122+
});
123+
} catch (error) {
124+
console.error('OCR Error:', error);
125+
}
126+
```
127+
128+
### Using Specific Language Models
15129

16-
```js
17-
import { multiply } from 'rn-mlkit-ocr';
130+
```typescript
131+
import { recognizeText } from 'rn-mlkit-ocr';
18132

19-
// ...
133+
// Recognize Chinese text
134+
const result = await recognizeText(imageUri, 'chinese');
20135

21-
const result = multiply(3, 7);
136+
// Recognize Japanese text
137+
const result = await recognizeText(imageUri, 'japanese');
22138
```
23139

140+
### Getting Available Languages
24141

25-
## Contributing
142+
```typescript
143+
import { getAvailableLanguages } from 'rn-mlkit-ocr';
144+
145+
const languages = await getAvailableLanguages();
146+
console.log('Available languages:', languages);
147+
// Output: ['latin', 'chinese']
148+
```
149+
150+
## API Reference
151+
152+
### `recognizeText(imageUri: string, detectorType?: DetectorType): Promise<OcrResult>`
153+
154+
Performs OCR on the specified image.
155+
156+
**Parameters:**
157+
158+
- `imageUri`: Path to the image (file path, content URI, or HTTP/HTTPS URL)
159+
- `detectorType`: Optional language detector type (`'latin'`, `'chinese'`, `'devanagari'`, `'japanese'`, `'korean'`). Defaults to `'latin'`
160+
161+
**Returns:** Promise resolving to `OcrResult`
162+
163+
### `getAvailableLanguages(): Promise<DetectorType[]>`
164+
165+
Returns the list of language models available in the app based on your configuration.
166+
167+
**Returns:** Promise resolving to array of detector types
26168

27-
- [Development workflow](CONTRIBUTING.md#development-workflow)
28-
- [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request)
29-
- [Code of conduct](CODE_OF_CONDUCT.md)
169+
### Types
30170

31-
## License
171+
```typescript
172+
interface OcrResult {
173+
text: string; // Full recognized text
174+
blocks: OcrBlock[]; // Text blocks
175+
}
32176

33-
MIT
177+
interface OcrBlock {
178+
text: string;
179+
frame: OcrFrame;
180+
lines: OcrLine[];
181+
}
34182

35-
---
183+
interface OcrLine {
184+
text: string;
185+
frame: OcrFrame;
186+
elements: OcrElement[];
187+
}
188+
189+
interface OcrElement {
190+
text: string;
191+
frame: OcrFrame;
192+
}
193+
194+
interface OcrFrame {
195+
x: number;
196+
y: number;
197+
width: number;
198+
height: number;
199+
}
200+
201+
type DetectorType = 'latin' | 'chinese' | 'devanagari' | 'japanese' | 'korean';
202+
```
203+
204+
## Supported Languages & Scripts
205+
206+
For a complete list of supported languages, see [Google ML Kit Text Recognition Languages](https://developers.google.com/ml-kit/vision/text-recognition/v2/languages).
207+
208+
## Example App
209+
210+
Check out the example app in the `example/` directory for a complete working implementation.
211+
212+
```bash
213+
cd example
214+
yarn install
215+
216+
# For iOS
217+
cd ios && pod install && cd ..
218+
yarn ios
219+
220+
# For Android
221+
yarn android
222+
```
223+
224+
## Contributing
36225

37-
Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
226+
Contributions are welcome! Please feel free to submit a Pull Request.

RnMlkitOcr.podspec

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ require "json"
22

33
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
44

5+
selected_subspecs = defined?($ReactNativeOcrSubspecs) ? $ReactNativeOcrSubspecs : ['Latin', 'Chinese', 'Devanagari', 'Japanese', 'Korean']
6+
7+
58
Pod::Spec.new do |s|
69
s.name = "RnMlkitOcr"
710
s.version = package["version"]
@@ -10,11 +13,26 @@ Pod::Spec.new do |s|
1013
s.license = package["license"]
1114
s.authors = package["author"]
1215

13-
s.platforms = { :ios => min_ios_version_supported }
16+
s.platforms = { :ios => "15.5" }
1417
s.source = { :git => "https://github.com/ahmeterenodaci/rn-mlkit-ocr.git", :tag => "#{s.version}" }
1518

1619
s.source_files = "ios/**/*.{h,m,mm,swift,cpp}"
17-
s.private_header_files = "ios/**/*.h"
1820

19-
install_modules_dependencies(s)
21+
s.dependency "React-Core"
22+
23+
if selected_subspecs.include?('Latin')
24+
s.dependency 'GoogleMLKit/TextRecognition', '3.2.0'
25+
end
26+
if selected_subspecs.include?('Chinese')
27+
s.dependency 'GoogleMLKit/TextRecognitionChinese', '3.2.0'
28+
end
29+
if selected_subspecs.include?('Devanagari')
30+
s.dependency 'GoogleMLKit/TextRecognitionDevanagari', '3.2.0'
31+
end
32+
if selected_subspecs.include?('Japanese')
33+
s.dependency 'GoogleMLKit/TextRecognitionJapanese', '3.2.0'
34+
end
35+
if selected_subspecs.include?('Korean')
36+
s.dependency 'GoogleMLKit/TextRecognitionKorean', '3.2.0'
37+
end
2038
end

android/build.gradle

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ apply plugin: "com.facebook.react"
2424
def getExtOrIntegerDefault(name) {
2525
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["RnMlkitOcr_" + name]).toInteger()
2626
}
27+
def safeGetExt(name, fallback) {
28+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : fallback
29+
}
2730

2831
android {
2932
namespace "com.rnmlkitocr"
@@ -33,6 +36,14 @@ android {
3336
defaultConfig {
3437
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
3538
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
39+
40+
def ocrModels = safeGetExt('ocrModels', ['all'])
41+
def hasAllModels = ocrModels.contains('all')
42+
buildConfigField "boolean", "HAS_LATIN", "${hasAllModels || ocrModels.contains('latin')}"
43+
buildConfigField "boolean", "HAS_CHINESE", "${hasAllModels || ocrModels.contains('chinese')}"
44+
buildConfigField "boolean", "HAS_DEVANAGARI", "${hasAllModels || ocrModels.contains('devanagari')}"
45+
buildConfigField "boolean", "HAS_JAPANESE", "${hasAllModels || ocrModels.contains('japanese')}"
46+
buildConfigField "boolean", "HAS_KOREAN", "${hasAllModels || ocrModels.contains('korean')}"
3647
}
3748

3849
buildFeatures {
@@ -74,4 +85,53 @@ def kotlin_version = getExtOrDefault("kotlinVersion")
7485
dependencies {
7586
implementation "com.facebook.react:react-android"
7687
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
88+
89+
def ocrModels = safeGetExt('ocrModels', ['all'])
90+
def hasAllModels = ocrModels.contains('all')
91+
def isBundled = safeGetExt('ocrUseBundled', false)
92+
93+
// Latin
94+
if (hasAllModels || ocrModels.contains('latin')) {
95+
if (isBundled) {
96+
implementation 'com.google.mlkit:text-recognition:16.0.1'
97+
} else {
98+
implementation 'com.google.android.gms:play-services-mlkit-text-recognition:19.0.1'
99+
}
100+
}
101+
102+
// Chinese
103+
if (hasAllModels || ocrModels.contains('chinese')) {
104+
if (isBundled) {
105+
implementation 'com.google.mlkit:text-recognition-chinese:16.0.1'
106+
} else {
107+
implementation 'com.google.android.gms:play-services-mlkit-text-recognition-chinese:16.0.1'
108+
}
109+
}
110+
111+
// Devanagari
112+
if (hasAllModels || ocrModels.contains('devanagari')) {
113+
if (isBundled) {
114+
implementation 'com.google.mlkit:text-recognition-devanagari:16.0.1'
115+
} else {
116+
implementation 'com.google.android.gms:play-services-mlkit-text-recognition-devanagari:16.0.1'
117+
}
118+
}
119+
120+
// Japanese
121+
if (hasAllModels || ocrModels.contains('japanese')) {
122+
if (isBundled) {
123+
implementation 'com.google.mlkit:text-recognition-japanese:16.0.1'
124+
} else {
125+
implementation 'com.google.android.gms:play-services-mlkit-text-recognition-japanese:16.0.1'
126+
}
127+
}
128+
129+
// Korean
130+
if (hasAllModels || ocrModels.contains('korean')) {
131+
if (isBundled) {
132+
implementation 'com.google.mlkit:text-recognition-korean:16.0.1'
133+
} else {
134+
implementation 'com.google.android.gms:play-services-mlkit-text-recognition-korean:16.0.1'
135+
}
136+
}
77137
}

0 commit comments

Comments
 (0)