react-native-text-reader 1.5.0 → 2.0.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/README.md +71 -48
- package/android/gradle.properties +4 -4
- package/android/src/main/java/com/textreader/TextReaderModule.kt +195 -109
- package/app.plugin.js +15 -0
- package/ios/TextReader.mm +6 -0
- package/ios/TextReader.swift +195 -35
- package/lib/commonjs/NativeTextReader.js +9 -0
- package/lib/commonjs/NativeTextReader.js.map +1 -0
- package/lib/commonjs/index.js +35 -12
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/package.json +1 -0
- package/lib/module/NativeTextReader.js +5 -0
- package/lib/module/NativeTextReader.js.map +1 -0
- package/lib/module/index.js +32 -13
- package/lib/module/index.js.map +1 -1
- package/lib/module/package.json +1 -0
- package/lib/typescript/commonjs/src/NativeTextReader.d.ts +34 -0
- package/lib/typescript/commonjs/src/NativeTextReader.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +27 -2
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/NativeTextReader.d.ts +34 -0
- package/lib/typescript/module/src/NativeTextReader.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +27 -2
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/package.json +73 -43
- package/react-native.config.json +1 -0
- package/src/NativeTextReader.ts +41 -0
- package/src/index.tsx +72 -18
package/ios/TextReader.swift
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Vision
|
|
2
|
+
import UIKit
|
|
2
3
|
|
|
3
4
|
extension String {
|
|
4
5
|
func stripPrefix(_ prefix: String) -> String {
|
|
@@ -7,67 +8,226 @@ extension String {
|
|
|
7
8
|
}
|
|
8
9
|
}
|
|
9
10
|
|
|
11
|
+
private struct RecognizedLine {
|
|
12
|
+
let text: String
|
|
13
|
+
let confidence: Float
|
|
14
|
+
let frame: CGRect
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
private struct TextCandidate {
|
|
18
|
+
let text: String
|
|
19
|
+
let confidence: Float
|
|
20
|
+
let box: CGRect
|
|
21
|
+
let midY: CGFloat
|
|
22
|
+
let minX: CGFloat
|
|
23
|
+
}
|
|
24
|
+
|
|
10
25
|
@objc(TextReader)
|
|
11
26
|
class TextReader: NSObject {
|
|
12
|
-
@objc static func requiresMainQueueSetup() -> Bool { return
|
|
27
|
+
@objc static func requiresMainQueueSetup() -> Bool { return false }
|
|
13
28
|
|
|
14
29
|
@objc(read:withOptions:withResolver:withRejecter:)
|
|
15
|
-
func read(
|
|
30
|
+
func read(
|
|
31
|
+
imgPath: String,
|
|
32
|
+
options: [String: Any],
|
|
33
|
+
resolve: @escaping RCTPromiseResolveBlock,
|
|
34
|
+
reject: @escaping RCTPromiseRejectBlock
|
|
35
|
+
) {
|
|
36
|
+
recognizeText(imgPath: imgPath, options: options) { result in
|
|
37
|
+
switch result {
|
|
38
|
+
case .success(let lines):
|
|
39
|
+
resolve(lines.map { $0.text })
|
|
40
|
+
case .failure(let error):
|
|
41
|
+
reject(error.code, error.message, error.underlying)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@objc(readDetailed:withOptions:withResolver:withRejecter:)
|
|
47
|
+
func readDetailed(
|
|
48
|
+
imgPath: String,
|
|
49
|
+
options: [String: Any],
|
|
50
|
+
resolve: @escaping RCTPromiseResolveBlock,
|
|
51
|
+
reject: @escaping RCTPromiseRejectBlock
|
|
52
|
+
) {
|
|
53
|
+
recognizeText(imgPath: imgPath, options: options) { result in
|
|
54
|
+
switch result {
|
|
55
|
+
case .success(let lines):
|
|
56
|
+
let lineTexts = lines.map { $0.text }
|
|
57
|
+
let details: [[String: Any]] = lines.map { line in
|
|
58
|
+
var detail: [String: Any] = [
|
|
59
|
+
"text": line.text,
|
|
60
|
+
"confidence": line.confidence,
|
|
61
|
+
]
|
|
62
|
+
detail["frame"] = [
|
|
63
|
+
"top": Int(line.frame.origin.y * 1000),
|
|
64
|
+
"left": Int(line.frame.origin.x * 1000),
|
|
65
|
+
"width": Int(line.frame.width * 1000),
|
|
66
|
+
"height": Int(line.frame.height * 1000),
|
|
67
|
+
]
|
|
68
|
+
return detail
|
|
69
|
+
}
|
|
70
|
+
resolve([
|
|
71
|
+
"fullText": lineTexts.joined(separator: "\n"),
|
|
72
|
+
"lines": lineTexts,
|
|
73
|
+
"details": details,
|
|
74
|
+
])
|
|
75
|
+
case .failure(let error):
|
|
76
|
+
reject(error.code, error.message, error.underlying)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private struct ReaderError: Error {
|
|
82
|
+
let code: String
|
|
83
|
+
let message: String
|
|
84
|
+
let underlying: Error?
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private func recognizeText(
|
|
88
|
+
imgPath: String,
|
|
89
|
+
options: [String: Any],
|
|
90
|
+
completion: @escaping (Result<[RecognizedLine], ReaderError>) -> Void
|
|
91
|
+
) {
|
|
16
92
|
guard !imgPath.isEmpty else {
|
|
17
|
-
|
|
93
|
+
completion(.failure(ReaderError(code: "ERR_EMPTY_PATH", message: "Image path cannot be empty.", underlying: nil)))
|
|
18
94
|
return
|
|
19
95
|
}
|
|
20
96
|
|
|
21
97
|
let formattedImgPath = imgPath.stripPrefix("file://")
|
|
22
98
|
let threshold = (options["visionIgnoreThreshold"] as? NSNumber)?.floatValue ?? 0.0
|
|
23
99
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
100
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
101
|
+
do {
|
|
102
|
+
let imgData = try Data(contentsOf: URL(fileURLWithPath: formattedImgPath))
|
|
103
|
+
guard let image = self.fixedOrientationImage(from: imgData),
|
|
104
|
+
let cgImage = image.cgImage else {
|
|
105
|
+
completion(.failure(ReaderError(code: "ERR_IMAGE_PROCESSING", message: "Failed to load image from the provided path.", underlying: nil)))
|
|
106
|
+
return
|
|
107
|
+
}
|
|
30
108
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
109
|
+
let requestHandler = VNImageRequestHandler(cgImage: cgImage, options: [:])
|
|
110
|
+
let ocrRequest = VNRecognizeTextRequest { request, error in
|
|
111
|
+
if let error = error {
|
|
112
|
+
completion(.failure(ReaderError(code: "ERR_OCR", message: "Error in text recognition: \(error.localizedDescription)", underlying: error)))
|
|
113
|
+
return
|
|
114
|
+
}
|
|
35
115
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
116
|
+
guard let observations = request.results as? [VNRecognizedTextObservation] else {
|
|
117
|
+
completion(.failure(ReaderError(code: "ERR_OCR_RESULTS", message: "Failed to read text from the image.", underlying: nil)))
|
|
118
|
+
return
|
|
119
|
+
}
|
|
40
120
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
121
|
+
let lines = self.groupObservationsIntoLines(observations: observations, threshold: threshold)
|
|
122
|
+
completion(.success(lines))
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
self.applyOptions(to: ocrRequest, from: options)
|
|
126
|
+
|
|
127
|
+
try requestHandler.perform([ocrRequest])
|
|
128
|
+
} catch {
|
|
129
|
+
completion(.failure(ReaderError(code: "ERR_IMAGE_LOADING", message: "Failed to load or process the image: \(error.localizedDescription)", underlying: error)))
|
|
130
|
+
}
|
|
44
131
|
}
|
|
45
132
|
}
|
|
46
133
|
|
|
47
|
-
private func
|
|
48
|
-
if
|
|
49
|
-
|
|
50
|
-
return
|
|
134
|
+
private func applyOptions(to request: VNRecognizeTextRequest, from options: [String: Any]) {
|
|
135
|
+
if #available(iOS 16.0, *) {
|
|
136
|
+
request.automaticallyDetectsLanguage = true
|
|
51
137
|
}
|
|
52
138
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
139
|
+
if let level = options["recognitionLevel"] as? String {
|
|
140
|
+
request.recognitionLevel = level == "fast" ? .fast : .accurate
|
|
141
|
+
} else {
|
|
142
|
+
request.recognitionLevel = .accurate
|
|
56
143
|
}
|
|
57
144
|
|
|
58
|
-
if
|
|
59
|
-
|
|
60
|
-
|
|
145
|
+
if let useCorrection = options["useLanguageCorrection"] as? Bool {
|
|
146
|
+
request.usesLanguageCorrection = useCorrection
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if let languages = options["recognitionLanguages"] as? [String], !languages.isEmpty {
|
|
150
|
+
request.recognitionLanguages = languages
|
|
61
151
|
}
|
|
62
152
|
|
|
63
|
-
let
|
|
153
|
+
if let customWords = options["customWords"] as? [String], !customWords.isEmpty {
|
|
154
|
+
request.customWords = customWords
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if let minHeight = options["minimumTextHeight"] as? NSNumber {
|
|
158
|
+
request.minimumTextHeight = minHeight.floatValue
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private func fixedOrientationImage(from data: Data) -> UIImage? {
|
|
163
|
+
guard let image = UIImage(data: data) else { return nil }
|
|
164
|
+
if image.imageOrientation == .up { return image }
|
|
165
|
+
|
|
166
|
+
UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
|
|
167
|
+
image.draw(in: CGRect(origin: .zero, size: image.size))
|
|
168
|
+
let normalized = UIGraphicsGetImageFromCurrentImageContext()
|
|
169
|
+
UIGraphicsEndImageContext()
|
|
170
|
+
return normalized
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private func groupObservationsIntoLines(
|
|
174
|
+
observations: [VNRecognizedTextObservation],
|
|
175
|
+
threshold: Float
|
|
176
|
+
) -> [RecognizedLine] {
|
|
177
|
+
let candidates: [TextCandidate] = observations.compactMap { observation in
|
|
64
178
|
guard let topCandidate = observation.topCandidates(1).first else { return nil }
|
|
65
|
-
|
|
66
|
-
|
|
179
|
+
guard topCandidate.confidence >= threshold else { return nil }
|
|
180
|
+
let box = observation.boundingBox
|
|
181
|
+
return TextCandidate(
|
|
182
|
+
text: topCandidate.string,
|
|
183
|
+
confidence: topCandidate.confidence,
|
|
184
|
+
box: box,
|
|
185
|
+
midY: box.midY,
|
|
186
|
+
minX: box.minX
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
guard !candidates.isEmpty else { return [] }
|
|
191
|
+
|
|
192
|
+
let sorted = candidates.sorted { lhs, rhs in
|
|
193
|
+
if abs(lhs.midY - rhs.midY) > 0.02 {
|
|
194
|
+
return lhs.midY > rhs.midY
|
|
67
195
|
}
|
|
68
|
-
return
|
|
196
|
+
return lhs.minX < rhs.minX
|
|
69
197
|
}
|
|
70
198
|
|
|
71
|
-
|
|
199
|
+
var lines: [RecognizedLine] = []
|
|
200
|
+
var currentGroup: [TextCandidate] = []
|
|
201
|
+
var currentMidY: CGFloat?
|
|
202
|
+
|
|
203
|
+
for candidate in sorted {
|
|
204
|
+
if let midY = currentMidY, abs(candidate.midY - midY) <= 0.02 {
|
|
205
|
+
currentGroup.append(candidate)
|
|
206
|
+
} else {
|
|
207
|
+
if !currentGroup.isEmpty {
|
|
208
|
+
lines.append(self.mergeGroup(currentGroup))
|
|
209
|
+
}
|
|
210
|
+
currentGroup = [candidate]
|
|
211
|
+
currentMidY = candidate.midY
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if !currentGroup.isEmpty {
|
|
216
|
+
lines.append(self.mergeGroup(currentGroup))
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return lines
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private func mergeGroup(_ group: [TextCandidate]) -> RecognizedLine {
|
|
223
|
+
let sortedGroup = group.sorted { $0.minX < $1.minX }
|
|
224
|
+
let text = sortedGroup.map { $0.text }.joined(separator: " ")
|
|
225
|
+
let confidence = sortedGroup.map { $0.confidence }.max() ?? 0
|
|
226
|
+
let minX = sortedGroup.map { $0.box.minX }.min() ?? 0
|
|
227
|
+
let minY = sortedGroup.map { $0.box.minY }.min() ?? 0
|
|
228
|
+
let maxX = sortedGroup.map { $0.box.maxX }.max() ?? 0
|
|
229
|
+
let maxY = sortedGroup.map { $0.box.maxY }.max() ?? 0
|
|
230
|
+
let frame = CGRect(x: minX, y: minY, width: maxX - minX, height: maxY - minY)
|
|
231
|
+
return RecognizedLine(text: text, confidence: confidence, frame: frame)
|
|
72
232
|
}
|
|
73
233
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _reactNative = require("react-native");
|
|
8
|
+
var _default = exports.default = _reactNative.TurboModuleRegistry.get('TextReader');
|
|
9
|
+
//# sourceMappingURL=NativeTextReader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNative","require","_default","exports","default","TurboModuleRegistry","get"],"sourceRoot":"../../src","sources":["NativeTextReader.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAAmD,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAuCpCC,gCAAmB,CAACC,GAAG,CAAO,YAAY,CAAC","ignoreList":[]}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -5,11 +5,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = exports.ScriptOptions = void 0;
|
|
7
7
|
var _reactNative = require("react-native");
|
|
8
|
+
var _NativeTextReader = _interopRequireDefault(require("./NativeTextReader.js"));
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
10
|
const LINKING_ERROR = `The package 'react-native-text-reader' doesn't seem to be linked. Make sure: \n\n` + _reactNative.Platform.select({
|
|
9
11
|
ios: "- You have run 'pod install'\n",
|
|
10
12
|
default: ''
|
|
11
|
-
}) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
|
|
12
|
-
const
|
|
13
|
+
}) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go (use a development build instead)\n';
|
|
14
|
+
const TextReaderModule = _NativeTextReader.default ?? _reactNative.NativeModules.TextReader;
|
|
15
|
+
const TextReader = TextReaderModule ? TextReaderModule : new Proxy({}, {
|
|
13
16
|
get() {
|
|
14
17
|
throw new Error(LINKING_ERROR);
|
|
15
18
|
}
|
|
@@ -21,20 +24,40 @@ let ScriptOptions = exports.ScriptOptions = /*#__PURE__*/function (ScriptOptions
|
|
|
21
24
|
ScriptOptions["JAPANESE"] = "Japanese";
|
|
22
25
|
ScriptOptions["KOREAN"] = "Korean";
|
|
23
26
|
return ScriptOptions;
|
|
24
|
-
}({});
|
|
27
|
+
}({});
|
|
28
|
+
const DEFAULT_OPTIONS = {
|
|
29
|
+
script: ScriptOptions.LATIN
|
|
30
|
+
};
|
|
31
|
+
function normalizeDetailedResult(result) {
|
|
32
|
+
return {
|
|
33
|
+
fullText: result.fullText ?? '',
|
|
34
|
+
lines: result.lines ?? [],
|
|
35
|
+
details: (result.details ?? []).map(detail => ({
|
|
36
|
+
text: detail.text,
|
|
37
|
+
confidence: detail.confidence,
|
|
38
|
+
frame: detail.frame,
|
|
39
|
+
recognizedLanguages: detail.recognizedLanguages
|
|
40
|
+
}))
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
25
44
|
/**
|
|
26
|
-
* Extracts text from an image.
|
|
27
|
-
* @param imagePath - Image path
|
|
28
|
-
* @param options - Additional options
|
|
29
|
-
* @param options.visionIgnoreThreshold - Vision ignore threshold(iOS)
|
|
30
|
-
* @param options.script - Language script (Android)
|
|
45
|
+
* Extracts text lines from an image.
|
|
31
46
|
*/
|
|
32
47
|
async function read(imagePath, options) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
48
|
+
const detailed = await readDetailed(imagePath, options);
|
|
49
|
+
return detailed.lines;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Extracts text with confidence, bounding boxes, and language metadata.
|
|
54
|
+
*/
|
|
55
|
+
async function readDetailed(imagePath, options) {
|
|
56
|
+
const result = await TextReader.readDetailed(imagePath, options ?? DEFAULT_OPTIONS);
|
|
57
|
+
return normalizeDetailedResult(result);
|
|
36
58
|
}
|
|
37
59
|
var _default = exports.default = {
|
|
38
|
-
read
|
|
60
|
+
read,
|
|
61
|
+
readDetailed
|
|
39
62
|
};
|
|
40
63
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","
|
|
1
|
+
{"version":3,"names":["_reactNative","require","_NativeTextReader","_interopRequireDefault","e","__esModule","default","LINKING_ERROR","Platform","select","ios","TextReaderModule","NativeTextReaderModule","NativeModules","TextReader","Proxy","get","Error","ScriptOptions","exports","DEFAULT_OPTIONS","script","LATIN","normalizeDetailedResult","result","fullText","lines","details","map","detail","text","confidence","frame","recognizedLanguages","read","imagePath","options","detailed","readDetailed","_default"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AACA,IAAAC,iBAAA,GAAAC,sBAAA,CAAAF,OAAA;AAAwD,SAAAE,uBAAAC,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAExD,MAAMG,aAAa,GACjB,mFAAmF,GACnFC,qBAAQ,CAACC,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEJ,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,iEAAiE;AAEnE,MAAMK,gBAAgB,GAAGC,yBAAsB,IAAIC,0BAAa,CAACC,UAAU;AAE3E,MAAMA,UAAU,GAAGH,gBAAgB,GAC/BA,gBAAgB,GAChB,IAAII,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACV,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAAC,IAEMW,aAAa,GAAAC,OAAA,CAAAD,aAAA,0BAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAA,OAAbA,aAAa;AAAA;AA8CzB,MAAME,eAAwB,GAAG;EAC/BC,MAAM,EAAEH,aAAa,CAACI;AACxB,CAAC;AAED,SAASC,uBAAuBA,CAACC,MAAsB,EAAkB;EACvE,OAAO;IACLC,QAAQ,EAAED,MAAM,CAACC,QAAQ,IAAI,EAAE;IAC/BC,KAAK,EAAEF,MAAM,CAACE,KAAK,IAAI,EAAE;IACzBC,OAAO,EAAE,CAACH,MAAM,CAACG,OAAO,IAAI,EAAE,EAAEC,GAAG,CAAEC,MAAM,KAAM;MAC/CC,IAAI,EAAED,MAAM,CAACC,IAAI;MACjBC,UAAU,EAAEF,MAAM,CAACE,UAAU;MAC7BC,KAAK,EAAEH,MAAM,CAACG,KAAK;MACnBC,mBAAmB,EAAEJ,MAAM,CAACI;IAC9B,CAAC,CAAC;EACJ,CAAC;AACH;;AAEA;AACA;AACA;AACA,eAAeC,IAAIA,CAACC,SAAiB,EAAEC,OAAiB,EAAqB;EAC3E,MAAMC,QAAQ,GAAG,MAAMC,YAAY,CAACH,SAAS,EAAEC,OAAO,CAAC;EACvD,OAAOC,QAAQ,CAACX,KAAK;AACvB;;AAEA;AACA;AACA;AACA,eAAeY,YAAYA,CACzBH,SAAiB,EACjBC,OAAiB,EACQ;EACzB,MAAMZ,MAAM,GAAG,MAAMV,UAAU,CAACwB,YAAY,CAC1CH,SAAS,EACTC,OAAO,IAAIhB,eACb,CAAC;EACD,OAAOG,uBAAuB,CAACC,MAAM,CAAC;AACxC;AAAC,IAAAe,QAAA,GAAApB,OAAA,CAAAb,OAAA,GAEc;EAAE4B,IAAI;EAAEI;AAAa,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","get"],"sourceRoot":"../../src","sources":["NativeTextReader.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;AAuClD,eAAeA,mBAAmB,CAACC,GAAG,CAAO,YAAY,CAAC","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { NativeModules, Platform } from 'react-native';
|
|
4
|
+
import NativeTextReaderModule from "./NativeTextReader.js";
|
|
4
5
|
const LINKING_ERROR = `The package 'react-native-text-reader' doesn't seem to be linked. Make sure: \n\n` + Platform.select({
|
|
5
6
|
ios: "- You have run 'pod install'\n",
|
|
6
7
|
default: ''
|
|
7
|
-
}) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
|
|
8
|
-
const
|
|
8
|
+
}) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go (use a development build instead)\n';
|
|
9
|
+
const TextReaderModule = NativeTextReaderModule ?? NativeModules.TextReader;
|
|
10
|
+
const TextReader = TextReaderModule ? TextReaderModule : new Proxy({}, {
|
|
9
11
|
get() {
|
|
10
12
|
throw new Error(LINKING_ERROR);
|
|
11
13
|
}
|
|
@@ -18,22 +20,39 @@ export let ScriptOptions = /*#__PURE__*/function (ScriptOptions) {
|
|
|
18
20
|
ScriptOptions["KOREAN"] = "Korean";
|
|
19
21
|
return ScriptOptions;
|
|
20
22
|
}({});
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
const DEFAULT_OPTIONS = {
|
|
24
|
+
script: ScriptOptions.LATIN
|
|
25
|
+
};
|
|
26
|
+
function normalizeDetailedResult(result) {
|
|
27
|
+
return {
|
|
28
|
+
fullText: result.fullText ?? '',
|
|
29
|
+
lines: result.lines ?? [],
|
|
30
|
+
details: (result.details ?? []).map(detail => ({
|
|
31
|
+
text: detail.text,
|
|
32
|
+
confidence: detail.confidence,
|
|
33
|
+
frame: detail.frame,
|
|
34
|
+
recognizedLanguages: detail.recognizedLanguages
|
|
35
|
+
}))
|
|
36
|
+
};
|
|
37
|
+
}
|
|
23
38
|
|
|
24
39
|
/**
|
|
25
|
-
* Extracts text from an image.
|
|
26
|
-
* @param imagePath - Image path
|
|
27
|
-
* @param options - Additional options
|
|
28
|
-
* @param options.visionIgnoreThreshold - Vision ignore threshold(iOS)
|
|
29
|
-
* @param options.script - Language script (Android)
|
|
40
|
+
* Extracts text lines from an image.
|
|
30
41
|
*/
|
|
31
42
|
async function read(imagePath, options) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
const detailed = await readDetailed(imagePath, options);
|
|
44
|
+
return detailed.lines;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Extracts text with confidence, bounding boxes, and language metadata.
|
|
49
|
+
*/
|
|
50
|
+
async function readDetailed(imagePath, options) {
|
|
51
|
+
const result = await TextReader.readDetailed(imagePath, options ?? DEFAULT_OPTIONS);
|
|
52
|
+
return normalizeDetailedResult(result);
|
|
35
53
|
}
|
|
36
54
|
export default {
|
|
37
|
-
read
|
|
55
|
+
read,
|
|
56
|
+
readDetailed
|
|
38
57
|
};
|
|
39
58
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeModules","Platform","LINKING_ERROR","select","ios","default","TextReader","Proxy","get","Error","ScriptOptions","read","imagePath","options","
|
|
1
|
+
{"version":3,"names":["NativeModules","Platform","NativeTextReaderModule","LINKING_ERROR","select","ios","default","TextReaderModule","TextReader","Proxy","get","Error","ScriptOptions","DEFAULT_OPTIONS","script","LATIN","normalizeDetailedResult","result","fullText","lines","details","map","detail","text","confidence","frame","recognizedLanguages","read","imagePath","options","detailed","readDetailed"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,aAAa,EAAEC,QAAQ,QAAQ,cAAc;AACtD,OAAOC,sBAAsB,MAAM,uBAAoB;AAEvD,MAAMC,aAAa,GACjB,mFAAmF,GACnFF,QAAQ,CAACG,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,iEAAiE;AAEnE,MAAMC,gBAAgB,GAAGL,sBAAsB,IAAIF,aAAa,CAACQ,UAAU;AAE3E,MAAMA,UAAU,GAAGD,gBAAgB,GAC/BA,gBAAgB,GAChB,IAAIE,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACR,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAEL,WAAYS,aAAa,0BAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAA,OAAbA,aAAa;AAAA;AA8CzB,MAAMC,eAAwB,GAAG;EAC/BC,MAAM,EAAEF,aAAa,CAACG;AACxB,CAAC;AAED,SAASC,uBAAuBA,CAACC,MAAsB,EAAkB;EACvE,OAAO;IACLC,QAAQ,EAAED,MAAM,CAACC,QAAQ,IAAI,EAAE;IAC/BC,KAAK,EAAEF,MAAM,CAACE,KAAK,IAAI,EAAE;IACzBC,OAAO,EAAE,CAACH,MAAM,CAACG,OAAO,IAAI,EAAE,EAAEC,GAAG,CAAEC,MAAM,KAAM;MAC/CC,IAAI,EAAED,MAAM,CAACC,IAAI;MACjBC,UAAU,EAAEF,MAAM,CAACE,UAAU;MAC7BC,KAAK,EAAEH,MAAM,CAACG,KAAK;MACnBC,mBAAmB,EAAEJ,MAAM,CAACI;IAC9B,CAAC,CAAC;EACJ,CAAC;AACH;;AAEA;AACA;AACA;AACA,eAAeC,IAAIA,CAACC,SAAiB,EAAEC,OAAiB,EAAqB;EAC3E,MAAMC,QAAQ,GAAG,MAAMC,YAAY,CAACH,SAAS,EAAEC,OAAO,CAAC;EACvD,OAAOC,QAAQ,CAACX,KAAK;AACvB;;AAEA;AACA;AACA;AACA,eAAeY,YAAYA,CACzBH,SAAiB,EACjBC,OAAiB,EACQ;EACzB,MAAMZ,MAAM,GAAG,MAAMT,UAAU,CAACuB,YAAY,CAC1CH,SAAS,EACTC,OAAO,IAAIhB,eACb,CAAC;EACD,OAAOG,uBAAuB,CAACC,MAAM,CAAC;AACxC;AAEA,eAAe;EAAEU,IAAI;EAAEI;AAAa,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { TurboModule } from 'react-native';
|
|
2
|
+
export type NativeOptions = {
|
|
3
|
+
visionIgnoreThreshold?: number;
|
|
4
|
+
confidenceThreshold?: number;
|
|
5
|
+
script?: string;
|
|
6
|
+
recognitionLevel?: 'fast' | 'accurate';
|
|
7
|
+
recognitionLanguages?: string[];
|
|
8
|
+
customWords?: string[];
|
|
9
|
+
useLanguageCorrection?: boolean;
|
|
10
|
+
minimumTextHeight?: number;
|
|
11
|
+
};
|
|
12
|
+
export type NativeTextLine = {
|
|
13
|
+
text: string;
|
|
14
|
+
confidence?: number;
|
|
15
|
+
frame?: {
|
|
16
|
+
top: number;
|
|
17
|
+
left: number;
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
};
|
|
21
|
+
recognizedLanguages?: string[];
|
|
22
|
+
};
|
|
23
|
+
export type NativeDetailedResult = {
|
|
24
|
+
fullText: string;
|
|
25
|
+
lines: string[];
|
|
26
|
+
details: NativeTextLine[];
|
|
27
|
+
};
|
|
28
|
+
export interface Spec extends TurboModule {
|
|
29
|
+
read(imagePath: string, options?: NativeOptions): Promise<string[]>;
|
|
30
|
+
readDetailed(imagePath: string, options?: NativeOptions): Promise<NativeDetailedResult>;
|
|
31
|
+
}
|
|
32
|
+
declare const _default: Spec | null;
|
|
33
|
+
export default _default;
|
|
34
|
+
//# sourceMappingURL=NativeTextReader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NativeTextReader.d.ts","sourceRoot":"","sources":["../../../../src/NativeTextReader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,MAAM,aAAa,GAAG;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IACvC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACpE,YAAY,CACV,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAClC;;AAED,wBAA2D"}
|
|
@@ -5,13 +5,38 @@ export declare enum ScriptOptions {
|
|
|
5
5
|
JAPANESE = "Japanese",
|
|
6
6
|
KOREAN = "Korean"
|
|
7
7
|
}
|
|
8
|
+
export type RecognitionLevel = 'fast' | 'accurate';
|
|
9
|
+
export type TextFrame = {
|
|
10
|
+
top: number;
|
|
11
|
+
left: number;
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
};
|
|
15
|
+
export type TextLine = {
|
|
16
|
+
text: string;
|
|
17
|
+
confidence?: number;
|
|
18
|
+
frame?: TextFrame;
|
|
19
|
+
recognizedLanguages?: string[];
|
|
20
|
+
};
|
|
21
|
+
export type DetailedResult = {
|
|
22
|
+
fullText: string;
|
|
23
|
+
lines: string[];
|
|
24
|
+
details: TextLine[];
|
|
25
|
+
};
|
|
8
26
|
export type Options = {
|
|
9
27
|
visionIgnoreThreshold?: number;
|
|
28
|
+
confidenceThreshold?: number;
|
|
10
29
|
script?: ScriptOptions;
|
|
30
|
+
recognitionLevel?: RecognitionLevel;
|
|
31
|
+
recognitionLanguages?: string[];
|
|
32
|
+
customWords?: string[];
|
|
33
|
+
useLanguageCorrection?: boolean;
|
|
34
|
+
minimumTextHeight?: number;
|
|
11
35
|
};
|
|
12
|
-
type
|
|
36
|
+
type TextReaderNative = {
|
|
13
37
|
read(imagePath: string, options?: Options): Promise<string[]>;
|
|
38
|
+
readDetailed(imagePath: string, options?: Options): Promise<DetailedResult>;
|
|
14
39
|
};
|
|
15
|
-
declare const _default:
|
|
40
|
+
declare const _default: TextReaderNative;
|
|
16
41
|
export default _default;
|
|
17
42
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.tsx"],"names":[],"mappings":"AAsBA,oBAAY,aAAa;IACvB,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,UAAU,eAAe;IACzB,QAAQ,aAAa;IACrB,MAAM,WAAW;CAClB;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,UAAU,CAAC;AAEnD,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,QAAQ,EAAE,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9D,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC7E,CAAC;wBAyCuC,gBAAgB;AAAzD,wBAA0D"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { TurboModule } from 'react-native';
|
|
2
|
+
export type NativeOptions = {
|
|
3
|
+
visionIgnoreThreshold?: number;
|
|
4
|
+
confidenceThreshold?: number;
|
|
5
|
+
script?: string;
|
|
6
|
+
recognitionLevel?: 'fast' | 'accurate';
|
|
7
|
+
recognitionLanguages?: string[];
|
|
8
|
+
customWords?: string[];
|
|
9
|
+
useLanguageCorrection?: boolean;
|
|
10
|
+
minimumTextHeight?: number;
|
|
11
|
+
};
|
|
12
|
+
export type NativeTextLine = {
|
|
13
|
+
text: string;
|
|
14
|
+
confidence?: number;
|
|
15
|
+
frame?: {
|
|
16
|
+
top: number;
|
|
17
|
+
left: number;
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
};
|
|
21
|
+
recognizedLanguages?: string[];
|
|
22
|
+
};
|
|
23
|
+
export type NativeDetailedResult = {
|
|
24
|
+
fullText: string;
|
|
25
|
+
lines: string[];
|
|
26
|
+
details: NativeTextLine[];
|
|
27
|
+
};
|
|
28
|
+
export interface Spec extends TurboModule {
|
|
29
|
+
read(imagePath: string, options?: NativeOptions): Promise<string[]>;
|
|
30
|
+
readDetailed(imagePath: string, options?: NativeOptions): Promise<NativeDetailedResult>;
|
|
31
|
+
}
|
|
32
|
+
declare const _default: Spec | null;
|
|
33
|
+
export default _default;
|
|
34
|
+
//# sourceMappingURL=NativeTextReader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NativeTextReader.d.ts","sourceRoot":"","sources":["../../../../src/NativeTextReader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,MAAM,aAAa,GAAG;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IACvC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACpE,YAAY,CACV,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAClC;;AAED,wBAA2D"}
|
|
@@ -5,13 +5,38 @@ export declare enum ScriptOptions {
|
|
|
5
5
|
JAPANESE = "Japanese",
|
|
6
6
|
KOREAN = "Korean"
|
|
7
7
|
}
|
|
8
|
+
export type RecognitionLevel = 'fast' | 'accurate';
|
|
9
|
+
export type TextFrame = {
|
|
10
|
+
top: number;
|
|
11
|
+
left: number;
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
};
|
|
15
|
+
export type TextLine = {
|
|
16
|
+
text: string;
|
|
17
|
+
confidence?: number;
|
|
18
|
+
frame?: TextFrame;
|
|
19
|
+
recognizedLanguages?: string[];
|
|
20
|
+
};
|
|
21
|
+
export type DetailedResult = {
|
|
22
|
+
fullText: string;
|
|
23
|
+
lines: string[];
|
|
24
|
+
details: TextLine[];
|
|
25
|
+
};
|
|
8
26
|
export type Options = {
|
|
9
27
|
visionIgnoreThreshold?: number;
|
|
28
|
+
confidenceThreshold?: number;
|
|
10
29
|
script?: ScriptOptions;
|
|
30
|
+
recognitionLevel?: RecognitionLevel;
|
|
31
|
+
recognitionLanguages?: string[];
|
|
32
|
+
customWords?: string[];
|
|
33
|
+
useLanguageCorrection?: boolean;
|
|
34
|
+
minimumTextHeight?: number;
|
|
11
35
|
};
|
|
12
|
-
type
|
|
36
|
+
type TextReaderNative = {
|
|
13
37
|
read(imagePath: string, options?: Options): Promise<string[]>;
|
|
38
|
+
readDetailed(imagePath: string, options?: Options): Promise<DetailedResult>;
|
|
14
39
|
};
|
|
15
|
-
declare const _default:
|
|
40
|
+
declare const _default: TextReaderNative;
|
|
16
41
|
export default _default;
|
|
17
42
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.tsx"],"names":[],"mappings":"AAsBA,oBAAY,aAAa;IACvB,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,UAAU,eAAe;IACzB,QAAQ,aAAa;IACrB,MAAM,WAAW;CAClB;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,UAAU,CAAC;AAEnD,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,QAAQ,EAAE,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9D,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC7E,CAAC;wBAyCuC,gBAAgB;AAAzD,wBAA0D"}
|