Skip to content

Commit

Permalink
Merge pull request #11 from blinkcard/release/v2.9.1
Browse files Browse the repository at this point in the history
Release/v2.9.1
  • Loading branch information
mparadina authored May 14, 2024
2 parents 2849b9a + a8075db commit ed20825
Show file tree
Hide file tree
Showing 16 changed files with 467 additions and 34 deletions.
2 changes: 1 addition & 1 deletion BlinkCard/MicroblinkBlinkcardCapacitor.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ Pod::Spec.new do |s|
s.ios.deployment_target = '13.0'
s.dependency 'Capacitor'
s.swift_version = '5.5'
s.dependency 'MBBlinkCard', '~> 2.9.0'
s.dependency 'MBBlinkCard', '~> 2.9.1'
end
2 changes: 1 addition & 1 deletion BlinkCard/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':capacitor-android')

implementation('com.microblink:blinkcard:2.9.0@aar') {
implementation('com.microblink:blinkcard:2.9.3@aar') {
transitive = true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;

import androidx.activity.result.ActivityResult;
import androidx.annotation.NonNull;

import com.microblink.blinkcard.MicroblinkSDK;
import com.microblink.blinkcard.entities.recognizers.RecognizerBundle;
Expand All @@ -13,6 +17,14 @@
import com.microblink.blinkcard.capacitor.overlays.OverlaySettingsSerializers;
import com.microblink.blinkcard.capacitor.recognizers.RecognizerSerializers;
import com.microblink.blinkcard.locale.LanguageUtils;
import com.microblink.blinkcard.directApi.DirectApiErrorListener;
import com.microblink.blinkcard.directApi.RecognizerRunner;
import com.microblink.blinkcard.recognition.RecognitionSuccessType;
import com.microblink.blinkcard.view.recognition.ScanResultListener;
import com.microblink.blinkcard.hardware.orientation.Orientation;
import com.microblink.blinkcard.metadata.recognition.FirstSideRecognitionCallback;
import com.microblink.blinkcard.recognition.RecognitionSuccessType;
import com.microblink.blinkcard.metadata.MetadataCallbacks;
import com.getcapacitor.annotation.ActivityCallback;
import com.getcapacitor.annotation.CapacitorPlugin;
import com.getcapacitor.JSObject;
Expand All @@ -32,7 +44,8 @@ public class MicroblinkPlugin extends Plugin {
private static final String RESULT_LIST = "resultList";

private RecognizerBundle recognizerBundle;

private RecognizerRunner recognizerRunner;
private boolean mFirstSideScanned;

@PluginMethod
public void scanWithCamera(PluginCall call) {
Expand All @@ -50,6 +63,135 @@ public void scanWithCamera(PluginCall call) {
startActivityForResult(call, "handleScanResult", uiSettings);
}

@PluginMethod
public void scanWithDirectApi(PluginCall call) {
//DirectAPI processing
JSObject jsRecognizerCollection = call.getObject("recognizerCollection");
JSObject jsLicenses = call.getObject("license");
String jsFrontImage = call.getString("frontImage");
String jsBackImage = call.getString("backImage");
setLicense(jsLicenses);
ScanResultListener mScanResultListenerBackSide = new ScanResultListener() {
@Override
public void onScanningDone(@NonNull RecognitionSuccessType recognitionSuccessType) {
mFirstSideScanned = false;
handleDirectApiResult(recognitionSuccessType, call);
}
@Override
public void onUnrecoverableError(@NonNull Throwable throwable) {
call.reject(throwable.getMessage());
}
};

FirstSideRecognitionCallback mFirstSideRecognitionCallback = new FirstSideRecognitionCallback() {
@Override
public void onFirstSideRecognitionFinished() {
mFirstSideScanned = true;
}
};

ScanResultListener mScanResultListenerFrontSide = new ScanResultListener() {
@Override
public void onScanningDone(@NonNull RecognitionSuccessType recognitionSuccessType) {
if (mFirstSideScanned) {
//multiside recognizer used
try {
if (!jsBackImage.isEmpty()) {
processImage(jsBackImage, mScanResultListenerBackSide, call);
} else if (recognitionSuccessType != RecognitionSuccessType.UNSUCCESSFUL){
handleDirectApiResult(recognitionSuccessType, call);
} else {
handleDirectApiError("Could not extract the information from the front side and back side is empty!", call);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
} else if (!mFirstSideScanned && recognitionSuccessType != RecognitionSuccessType.UNSUCCESSFUL){
//singleside recognizer used
handleDirectApiResult(recognitionSuccessType, call);
} else {
mFirstSideScanned = false;
handleDirectApiError("Could not extract the information with DirectAPI!", call);
}
}
@Override
public void onUnrecoverableError(@NonNull Throwable throwable) {
handleDirectApiError(throwable.getMessage(), call);
}
};

setupRecognizerRunner(jsRecognizerCollection, mFirstSideRecognitionCallback, call);
if (!jsFrontImage.isEmpty()) {
processImage(jsFrontImage, mScanResultListenerFrontSide, call);
} else {
handleDirectApiError("The provided image for the 'frontImage' parameter is empty!", call);
}
}
private void setupRecognizerRunner(JSONObject jsonRecognizerCollection, FirstSideRecognitionCallback mFirstSideRecognitionCallback, PluginCall call) {
if (recognizerRunner != null) {
recognizerRunner.terminate();
}

recognizerBundle = RecognizerSerializers.INSTANCE.deserializeRecognizerCollection(jsonRecognizerCollection);

try {
recognizerRunner = RecognizerRunner.getSingletonInstance();
} catch (Exception e) {
handleDirectApiError("DirectAPI not support: " + e.getMessage(), call);
}

MetadataCallbacks metadataCallbacks = new MetadataCallbacks();
metadataCallbacks.setFirstSideRecognitionCallback(mFirstSideRecognitionCallback);
recognizerRunner.setMetadataCallbacks(metadataCallbacks);
recognizerRunner.initialize(getContext(), recognizerBundle, new DirectApiErrorListener() {
@Override
public void onRecognizerError(@NonNull Throwable throwable) {
handleDirectApiError("Failed to initialize recognizer with DirectAPI: " + throwable.getMessage(), call);
}
});
}

private void processImage(String base64Image, ScanResultListener scanResultListener, PluginCall call) {
Bitmap image = base64ToBitmap(base64Image);
if (image != null) {
recognizerRunner.recognizeBitmap(
base64ToBitmap(base64Image),
Orientation.ORIENTATION_LANDSCAPE_RIGHT,
scanResultListener
);
} else {
handleDirectApiError("Could not decode the Base64 image!", call);
}
}

private void handleDirectApiResult(RecognitionSuccessType recognitionSuccessType, PluginCall call) {
if (recognitionSuccessType != RecognitionSuccessType.UNSUCCESSFUL) {
JSObject result = new JSObject();
try {
result.put(CANCELLED, false);
} catch (Exception e) {
throw new RuntimeException(e);
}
try {
JSONArray resultList = RecognizerSerializers.INSTANCE.serializeRecognizerResults(recognizerBundle.getRecognizers());
result.put(RESULT_LIST, resultList);
call.resolve(result);
} catch(Exception e) {
throw new RuntimeException(e);
}

} else {
handleDirectApiError("Unexpected error with DirectAPI", call);
}
}

private void handleDirectApiError(String errorMessage, PluginCall call) {
call.reject(errorMessage);
if (recognizerRunner != null) {
recognizerRunner.resetRecognitionState(true);
}
}

@ActivityCallback
private void handleScanResult(PluginCall call, ActivityResult activityResult) {
int resultCode = activityResult.getResultCode();
Expand Down Expand Up @@ -96,11 +238,15 @@ private void setLanguage(JSONObject jsonOverlaySettings) {
} catch (Exception e) {}
}

private Bitmap base64ToBitmap(String base64String) {
byte[] decodedBytes = Base64.decode(base64String, Base64.DEFAULT);
return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
}

private void startActivityForResult(PluginCall call, String callbackMethod, UISettings settings) {
Activity activity = getActivity();
Intent intent = new Intent(activity, settings.getTargetActivity());
settings.saveToIntent(intent);
startActivityForResult(call, intent, callbackMethod);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public static JSONObject serializeDate(@Nullable Date dateResult) throws JSONExc
}

public static int serializeEnum(Enum e) {
return e.ordinal() + 1;
return e.ordinal();
}

public static JSONArray serializeStringArray(String[] strings) {
Expand Down
1 change: 1 addition & 0 deletions BlinkCard/ios/Plugin/BlinkCardPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
// each method the plugin supports using the CAP_PLUGIN_METHOD macro.
CAP_PLUGIN(BlinkCardCapacitorPlugin, "BlinkCardCapacitorPlugin",
CAP_PLUGIN_METHOD(scanWithCamera, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(scanWithDirectApi, CAPPluginReturnPromise);
)
133 changes: 133 additions & 0 deletions BlinkCard/ios/Plugin/BlinkCardPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public class BlinkCardCapacitorPlugin: CAPPlugin {

var pluginCall: CAPPluginCall?
var recognizerCollection: MBCRecognizerCollection?
var recognizerRunner: MBCRecognizerRunner?
var backImage: String?

@objc func scanWithCamera(_ call: CAPPluginCall) {

Expand Down Expand Up @@ -62,6 +64,80 @@ public class BlinkCardCapacitorPlugin: CAPPlugin {
}
}

@objc func scanWithDirectApi(_ call: CAPPluginCall) {

defer {
// Reference plugin call for resolving scanning result
pluginCall = call
}

guard let licensesObject = call.getObject("license") else {
call.reject("Must provide license for Microblink SDK!")
return
}

guard let recognizerCollectionObject = call.getObject("recognizerCollection") else {
call.reject("Must provide recognizer collection!")
return
}

guard let frontImageObject = call.getString("frontImage") else {
call.reject("The provided image for the 'frontImage' parameter is empty!")
return
}

let backImageObject = call.getString("backImage")

let jsonRecognizerCollection = sanitizeDictionary(recognizerCollectionObject)
guard let jsonLicense = sanitizeDictionary(licensesObject) else {
call.reject("Must provide license keys for Microblink SDK!")
return
}

backImage = backImageObject

setLicenseKey(license: jsonLicense)
setupRecognizerRunner(jsonRecognizerCollection)
let frontImage = convertBase64ToImage(frontImageObject)
if let frontImage = frontImage {
processImage(frontImage)
} else {
handleDirectApiError("Could not decode the Base64 image!", call)
}
}
private func setupRecognizerRunner(_ recognizerCollectionObject: [String : Any]?) {

recognizerCollection = MBCRecognizerSerializers.sharedInstance()?.deserializeRecognizerCollection(recognizerCollectionObject)
guard let recognizerCollection = recognizerCollection else {
return
}
recognizerRunner = MBCRecognizerRunner(recognizerCollection: recognizerCollection)
recognizerRunner?.scanningRecognizerRunnerDelegate = self
recognizerRunner?.metadataDelegates.firstSideFinishedRecognizerRunnerDelegate = self
}

private func processImage(_ originalImage: UIImage?) {
var image: MBCImage? = nil
if let anImage = originalImage {
image = MBCImage(uiImage: anImage)
}
image?.cameraFrame = false
image?.orientation = MBCProcessingOrientation.left

let serialQueue = DispatchQueue(label: "com.microblink.DirectAPI")
serialQueue.async(execute: {() -> Void in
self.recognizerRunner?.processImage(image!)
})
}

private func convertBase64ToImage(_ base64String: String) -> UIImage? {
if let imageData = Data(base64Encoded: base64String, options: .ignoreUnknownCharacters) {
let image = UIImage(data: imageData)
return image
}
return nil
}

@objc func setLanguage(_ call: CAPPluginCall) {
let language = call.getString("language") ?? "en"
MBCMicroblinkApp.shared().language = language
Expand Down Expand Up @@ -110,6 +186,39 @@ public class BlinkCardCapacitorPlugin: CAPPlugin {
}
return mutableDictionary
}

private func handleDirectApiResult() {
guard let recognizerListCount = recognizerCollection?.recognizerList.count else {
return
}

var resultJson = [NSDictionary]()

let isDocumentCaptureRecognizer = false

for recognizerIndex in 0..<recognizerListCount {
guard let resultDict = recognizerCollection?.recognizerList[recognizerIndex].serializeResult() else {
return
}
resultJson.append(resultDict as NSDictionary)
}

if (!isDocumentCaptureRecognizer) {
pluginCall?.resolve([
"cancelled": false,
"resultList": resultJson
])
}
recognizerCollection = nil
self.recognizerRunner = nil
pluginCall = nil
}

private func handleDirectApiError(_ errorMessage: String, _ call: CAPPluginCall) {
call.reject(errorMessage)
recognizerRunner = nil
recognizerCollection = nil
}
}

extension BlinkCardCapacitorPlugin: MBCOverlayViewControllerDelegate {
Expand Down Expand Up @@ -162,4 +271,28 @@ extension BlinkCardCapacitorPlugin: MBCOverlayViewControllerDelegate {
])
overlayViewController.dismiss(animated: true, completion: nil)
}
}

extension BlinkCardCapacitorPlugin: MBCFirstSideFinishedRecognizerRunnerDelegate, MBCScanningRecognizerRunnerDelegate {

public func recognizerRunnerDidFinishRecognition(ofFirstSide recognizerRunner: MBCRecognizerRunner) {
if let backImage = backImage {
let image = convertBase64ToImage(backImage)
if let image = image {
processImage(image)
} else {
handleDirectApiResult()
}
} else {
handleDirectApiResult()
}
}

public func recognizerRunner(_ recognizerRunner: MBCRecognizerRunner, didFinishScanningWith state:MBCRecognizerResultState) {
if (state != .empty && state != .stageValid) {
handleDirectApiResult()
} else if (state == .empty) {
pluginCall?.reject("Could not extract the information with DirectAPI!")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@

@interface MBCSerializationUtils : NSObject

+(NSDictionary * _Nonnull) serializeNSDate:(NSDate * _Nullable) value;
+(NSDictionary * _Nonnull) serializeMBCDate:(MBCDate * _Nullable) value;
+(NSDictionary * _Nonnull) serializeMBCDate:(MBCDate * _Nonnull) date;
+(NSString * _Nullable) encodeMBImage:(MBCImage * _Nullable) image;
+(NSDictionary * _Nonnull)serializeCGPoint:(CGPoint) point;
+(NSDictionary * _Nonnull) serializeMBQuadrangle:(MBCQuadrangle * _Nonnull) quad;
Expand Down
Loading

0 comments on commit ed20825

Please sign in to comment.