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 91e65ac + 774a683 commit 205d6f7
Show file tree
Hide file tree
Showing 15 changed files with 583 additions and 111 deletions.
2 changes: 1 addition & 1 deletion BlinkCard/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@microblink/blinkcard-cordova",
"version": "2.9.0",
"version": "2.9.1",
"description": "AI-driven credit card scanning for cross-platform apps built with Cordova.",
"cordova": {
"id": "blinkcard-cordova",
Expand Down
4 changes: 2 additions & 2 deletions BlinkCard/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
id="blinkcard-cordova"
version="2.9.0">
version="2.9.1">

<name>BlinkCardScanner</name>
<description>A small and powerful credit card scanning library</description>
Expand Down Expand Up @@ -111,7 +111,7 @@
<framework src="AudioToolbox.framework" />
<framework src="OpenGLES.framework" />
<framework src="Accelerate.framework" />
<framework src="src/ios/blinkcard-ios/BlinkCard.xcframework" custom="true" embed="true"/>
<framework src="src/ios/BlinkCard.xcframework" custom="true" embed="true"/>

<preference name="CAMERA_USAGE_DESCRIPTION" default=" " />
<config-file target="*-Info.plist" parent="NSCameraUsageDescription">
Expand Down
2 changes: 1 addition & 1 deletion BlinkCard/scripts/initIOSFramework.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
HERE="$(dirname "$(test -L "$0" && readlink "$0" || echo "$0")")"
pushd "${HERE}/../src/ios/" > /dev/null

LINK='https://github.com/BlinkCard/blinkcard-ios/releases/download/v2.9.0/BlinkCard.xcframework.zip'
LINK='https://github.com/BlinkCard/blinkcard-ios/releases/download/v2.9.1/BlinkCard.xcframework.zip'
FILENAME='BlinkCard.xcframework.zip'

# BlinkCard framework will be obtained via wget or curl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import androidx.annotation.NonNull;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;

import com.microblink.blinkcard.MicroblinkSDK;
import com.microblink.blinkcard.entities.recognizers.RecognizerBundle;
Expand All @@ -19,6 +23,13 @@
import com.microblink.blinkcard.plugins.cordova.overlays.OverlaySettingsSerializers;
import com.microblink.blinkcard.plugins.cordova.recognizers.RecognizerSerializers;
import com.microblink.blinkcard.locale.LanguageUtils;
import com.microblink.blinkcard.directApi.DirectApiErrorListener;
import com.microblink.blinkcard.directApi.RecognizerRunner;
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.microblink.blinkcard.view.recognition.ScanResultListener;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
Expand All @@ -30,11 +41,13 @@ public class BlinkCardScanner extends CordovaPlugin {
private static final int REQUEST_CODE = 1337;

private static final String SCAN_WITH_CAMERA = "scanWithCamera";
private static final String SCAN_WITH_DIRECT_API = "scanWithDirectApi";
private static final String CANCELLED = "cancelled";

private static final String RESULT_LIST = "resultList";

private RecognizerBundle mRecognizerBundle;
private RecognizerRunner mRecognizerRunner;
private boolean mFirstSideScanned = false;
private CallbackContext mCallbackContext;

/**
Expand Down Expand Up @@ -70,21 +83,11 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo

try {
if (action.equals(SCAN_WITH_CAMERA)) {
JSONObject jsonOverlaySettings = args.getJSONObject(0);
JSONObject jsonRecognizerCollection = args.getJSONObject(1);
JSONObject jsonLicenses = args.getJSONObject(2);

setLicense(jsonLicenses);
setLanguage(jsonOverlaySettings.getString("language"),
jsonOverlaySettings.getString("country"));

mRecognizerBundle = RecognizerSerializers.INSTANCE.deserializeRecognizerCollection(jsonRecognizerCollection);
UISettings overlaySettings = OverlaySettingsSerializers.INSTANCE.getOverlaySettings(this.cordova.getContext(), jsonOverlaySettings, mRecognizerBundle);

// unable to use ActivityRunner because we need to use cordova's activity launcher
Intent intent = new Intent(this.cordova.getContext(), overlaySettings.getTargetActivity());
overlaySettings.saveToIntent(intent);
this.cordova.startActivityForResult(this, intent, REQUEST_CODE);
//Scan with camera
scanWithCamera(args);
} else if (action.equals(SCAN_WITH_DIRECT_API)) {
//Scan with DirectAPI
scanWithDirectApi(args);
} else {
return false;
}
Expand All @@ -95,6 +98,157 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
}
}

private void scanWithCamera(JSONArray arguments) throws JSONException{
try {
JSONObject jsonOverlaySettings = arguments.getJSONObject(0);
JSONObject jsonRecognizerCollection = arguments.getJSONObject(1);
JSONObject jsonLicenses = arguments.getJSONObject(2);

setLicense(jsonLicenses);
setLanguage(jsonOverlaySettings.getString("language"),
jsonOverlaySettings.getString("country"));
mRecognizerBundle = RecognizerSerializers.INSTANCE.deserializeRecognizerCollection(jsonRecognizerCollection);
UISettings overlaySettings = OverlaySettingsSerializers.INSTANCE.getOverlaySettings(this.cordova.getContext(), jsonOverlaySettings, mRecognizerBundle);

// unable to use ActivityRunner because we need to use cordova's activity launcher
Intent intent = new Intent(this.cordova.getContext(), overlaySettings.getTargetActivity());
overlaySettings.saveToIntent(intent);
this.cordova.startActivityForResult(this, intent, REQUEST_CODE);
} catch (JSONException e) {
mCallbackContext.error("Could not start scanWithCamera.\nJSON error: " + e);
}
}

private void scanWithDirectApi(JSONArray arguments) throws JSONException {
//DirectAPI processing
JSONObject jsonRecognizerCollection = arguments.getJSONObject(0);
JSONObject jsonLicense = arguments.getJSONObject(3);
setLicense(jsonLicense);

ScanResultListener mScanResultListenerBackSide = new ScanResultListener() {
@Override
public void onScanningDone(@NonNull RecognitionSuccessType recognitionSuccessType) {
mFirstSideScanned = false;
handleDirectApiResult(recognitionSuccessType);
}
@Override
public void onUnrecoverableError(@NonNull Throwable throwable) {
handleDirectApiError(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 (!arguments.getString(2).isEmpty() && !arguments.isNull(2)) {
processImage(arguments.getString(2), mScanResultListenerBackSide);
} else if (recognitionSuccessType != RecognitionSuccessType.UNSUCCESSFUL) {
handleDirectApiResult(recognitionSuccessType);
} else {
handleDirectApiError("Could not extract the information from the front side and the back side is empty!");
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
} else if (!mFirstSideScanned && recognitionSuccessType != RecognitionSuccessType.UNSUCCESSFUL){
//singleside recognizer used
handleDirectApiResult(recognitionSuccessType);
} else {
mFirstSideScanned = false;
handleDirectApiError("Could not extract the information with DirectAPI!");
}
}
@Override
public void onUnrecoverableError(@NonNull Throwable throwable) {
handleDirectApiError(throwable.getMessage());
}
};

setupRecognizerRunner(jsonRecognizerCollection, mFirstSideRecognitionCallback);

if (!arguments.getString(1).isEmpty() && !arguments.isNull(1)) {
processImage(arguments.getString(1), mScanResultListenerFrontSide);
} else {
handleDirectApiError("The provided image for the 'frontImage' parameter is empty!");
}
}

private void setupRecognizerRunner(JSONObject jsonRecognizerCollection, FirstSideRecognitionCallback mFirstSideRecognitionCallback) {
if (mRecognizerRunner != null) {
mRecognizerRunner.terminate();
}

mRecognizerBundle = RecognizerSerializers.INSTANCE.deserializeRecognizerCollection(jsonRecognizerCollection);

try {
mRecognizerRunner = RecognizerRunner.getSingletonInstance();
} catch (Exception e) {
handleDirectApiError("DirectAPI not supported: " + e.getMessage());
}

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

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

private void handleDirectApiResult(RecognitionSuccessType recognitionSuccessType) {
if (recognitionSuccessType != RecognitionSuccessType.UNSUCCESSFUL) {
JSONObject result = new JSONObject();
try {
result.put(CANCELLED, false);
} catch (JSONException e) {
throw new RuntimeException(e);
}
try {
JSONArray resultList = RecognizerSerializers.INSTANCE.serializeRecognizerResults(mRecognizerBundle.getRecognizers());
result.put(RESULT_LIST, resultList);
} catch(JSONException e) {
throw new RuntimeException(e);
}
mCallbackContext.success(result);

} else {
handleDirectApiError("Could not extract the information with DirectAPI!");
}
}

private void handleDirectApiError(String errorMessage) {
mCallbackContext.error(errorMessage);
mFirstSideScanned = false;
if (mRecognizerRunner != null) {
mRecognizerRunner.resetRecognitionState(true);
}
}

private void setLicense( JSONObject jsonLicense ) throws JSONException {
MicroblinkSDK.setShowTrialLicenseWarning(
jsonLicense.optBoolean("showTrialLicenseKeyWarning", true)
Expand All @@ -110,6 +264,11 @@ private void setLicense( JSONObject jsonLicense ) throws JSONException {
MicroblinkSDK.setIntentDataTransferMode(IntentDataTransferMode.PERSISTED_OPTIMISED);
}

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

private void setLanguage(String language, String country) {
LanguageUtils.setLanguageAndCountry(language, country, this.cordova.getContext());
}
Expand Down
2 changes: 1 addition & 1 deletion BlinkCard/src/android/libBlinkCard.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ repositories {
}

dependencies {
implementation('com.microblink:blinkcard:2.9.0@aar') {
implementation('com.microblink:blinkcard:2.9.3@aar') {
transitive = true
}
}
Expand Down
5 changes: 5 additions & 0 deletions BlinkCard/src/ios/sources/CDVBlinkCardScanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
* Starts the scanning process
*/
- (void)scanWithCamera:(CDVInvokedUrlCommand *)command;

/**
* Starts the image recognition process via DirectAPI
*/
- (void)scanWithDirectApi:(CDVInvokedUrlCommand *)command;
/**
* Returns successful recognition
*/
Expand Down
Loading

0 comments on commit 205d6f7

Please sign in to comment.