Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Rn 0.47 #4

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
apply plugin: 'com.android.library'


buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
classpath 'com.google.gms:google-services:3.0.0'

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
compileSdkVersion 25
buildToolsVersion "25.0.0"

defaultConfig {
minSdkVersion 16
Expand All @@ -20,7 +34,8 @@ android {

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:appcompat-v7:25.0.0'
compile 'com.facebook.react:react-native:+'
compile 'com.google.zxing:core:3.2.0'
compile 'com.google.zxing:core:+'
compile 'com.google.android.gms:play-services-vision:10.2.0'
}
6 changes: 6 additions & 0 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.remobile.qrcodeLocalImage">
<application>
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<meta-data android:name="com.google.android.gms.vision.DEPENDENCIES" android:value="barcode"/>
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package com.remobile.qrcodeLocalImage;

import android.os.Environment;
import android.util.Log;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.content.Context;
import android.net.Uri;
import android.database.Cursor;
import android.provider.MediaStore;
import android.util.SparseArray;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
Expand All @@ -10,69 +17,123 @@
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.LuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;

import com.google.android.gms.vision.barcode.*;
import com.google.android.gms.vision.Frame;

import java.io.Reader;
import java.io.FileOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Hashtable;

import static java.security.AccessController.getContext;


public class RCTQRCodeLocalImage extends ReactContextBaseJavaModule {

private ReactApplicationContext mReactContext;

private static final int RGB_MASK = 0x00FFFFFF;

public RCTQRCodeLocalImage(ReactApplicationContext reactContext) {
super(reactContext);
mReactContext = reactContext;
}

private static final String TAG = "QR";

@Override
public String getName() {
return "RCTQRCodeLocalImage";
}

@ReactMethod
public void decode(String path, Callback callback) {
Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); // 设置二维码内容的编码
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 先获取原大小
options.inJustDecodeBounds = false; // 获取新的大小

int sampleSize = (int) (options.outHeight / (float) 200);

if (sampleSize <= 0)
sampleSize = 1;
options.inSampleSize = sampleSize;
Bitmap scanBitmap = null;
if (path.startsWith("http://")||path.startsWith("https://")) {
scanBitmap = this.getbitmap(path);
} else {
scanBitmap = BitmapFactory.decodeFile(path, options);
}
if (scanBitmap == null) {
callback.invoke("cannot load image");
return;
}
int[] intArray = new int[scanBitmap.getWidth()*scanBitmap.getHeight()];
scanBitmap.getPixels(intArray, 0, scanBitmap.getWidth(), 0, 0, scanBitmap.getWidth(), scanBitmap.getHeight());

RGBLuminanceSource source = new RGBLuminanceSource(scanBitmap.getWidth(), scanBitmap.getHeight(), intArray);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
try {
Result result = reader.decode(bitmap, hints);
if (result == null) {
callback.invoke("image format error");
Uri mediaUri = Uri.parse(path);
String realPath = getRealPathFromUri(mReactContext, mediaUri);
Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); // 设置二维码内容的编码

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 先获取原大小
options.inJustDecodeBounds = false; // 获取新的大小

int sampleSize = (int) (options.outHeight / (float) 200);

if (sampleSize <= 0)
sampleSize = 1;
options.inSampleSize = sampleSize;
Bitmap scanBitmap = null;
if (path.startsWith("http://")||path.startsWith("https://")) {
scanBitmap = this.getbitmap("https://instagram.fmvd1-1.fna.fbcdn.net/t51.2885-15/e35/18722826_1379673005443137_1152886071126654976_n.jpg");
} else {
callback.invoke(null, result.toString());
scanBitmap = BitmapFactory.decodeFile(realPath, options);
}

if (scanBitmap == null) {
callback.invoke("cannot load image");
return;
}

Bitmap scanInvertBitmap = invert(scanBitmap);
// https://code.tutsplus.com/tutorials/reading-qr-codes-using-the-mobile-vision-api--cms-24680

int[] intArray = new int[scanInvertBitmap.getWidth()*scanInvertBitmap.getHeight()];
scanInvertBitmap.getPixels(intArray, 0, scanInvertBitmap.getWidth(), 0, 0, scanInvertBitmap.getWidth(), scanInvertBitmap.getHeight());
LuminanceSource source = new RGBLuminanceSource(scanInvertBitmap.getWidth(), scanInvertBitmap.getHeight(), intArray);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();

try {
Result result = reader.decode(bitmap, hints);
Log.d(TAG, "result - " + result);
if (result == null) {
callback.invoke("Image without qr");
} else {
callback.invoke(null, result.toString());
}

} catch (Exception e) {
Log.d(TAG, "Error - " + e);
callback.invoke("Decode error");
}
} catch (Exception e) {
callback.invoke("decode error");
Log.d(TAG, "Error GENERIC - " + e);
callback.invoke("Life error");
}
}

public Bitmap invert(Bitmap original) {
// Create mutable Bitmap to invert, argument true makes it mutable
Bitmap inversion = original.copy(Bitmap.Config.ARGB_8888, true);

// Get info about Bitmap
int width = inversion.getWidth();
int height = inversion.getHeight();
int pixels = width * height;

// Get original pixels
int[] pixel = new int[pixels];
inversion.getPixels(pixel, 0, width, 0, 0, width, height);

// Modify pixels
for (int i = 0; i < pixels; i++)
pixel[i] ^= RGB_MASK;
inversion.setPixels(pixel, 0, width, 0, 0, width, height);
// Return inverted Bitmap
// saveImage(inversion, "caro");
return inversion;
}

public static Bitmap getbitmap(String imageUri) {
Bitmap bitmap = null;
try {
Expand All @@ -90,6 +151,47 @@ public static Bitmap getbitmap(String imageUri) {
e.printStackTrace();
bitmap = null;
}

return bitmap;
}

// private void saveImage(Bitmap finalBitmap, String image_name) {
//
// // Find the SD Card path
// File filepath = Environment.getExternalStorageDirectory();
//
// // Create a new folder in SD Card
// File myDir = new File(filepath.getAbsolutePath()
// + "/WhatSappIMG/");
// myDir.mkdirs();
// String fname = "/Image-" + image_name+ ".jpg";
// File file = new File(myDir, fname);
// if (file.exists()) file.delete();
// Log.d(TAG, "LOAD " + myDir + fname);
// try {
// FileOutputStream out = new FileOutputStream(file);
// finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
// out.flush();
// out.close();
// Log.d(TAG, "SaveImage ");
// } catch (Exception e) {
// e.printStackTrace();
// Log.d(TAG, "Error saveImage - " + e);
// }
// }

public static String getRealPathFromUri(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
);
}

@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList();
Expand Down
87 changes: 57 additions & 30 deletions ios/RCTQRCodeLocalImage/RCTQRCodeLocalImage.m
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,71 @@
#import <React/RCTLog.h>
#import <React/RCTUtils.h>
#import "RCTQRCodeLocalImage.h"
#import <AssetsLibrary/AssetsLibrary.h>

@implementation RCTQRCodeLocalImage
RCT_EXPORT_MODULE()

RCT_EXPORT_METHOD(decode:(NSString *)path callback:(RCTResponseSenderBlock)callback)
{
UIImage *srcImage;
if ([path hasPrefix:@"http://"] || [path hasPrefix:@"https://"]) {
srcImage = [UIImage imageWithData: [NSData dataWithContentsOfURL:[NSURL URLWithString: path]]];
} else {
srcImage = [[UIImage alloc] initWithContentsOfFile:path];
}
if (nil==srcImage){
NSLog(@"PROBLEM! IMAGE NOT LOADED\n");
callback(@[RCTMakeError(@"IMAGE NOT LOADED!", nil, nil)]);
return;
}
NSLog(@"OK - IMAGE LOADED\n");
NSDictionary *detectorOptions = @{@"CIDetectorAccuracy": @"CIDetectorAccuracyHigh"};
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:detectorOptions];
CIImage *image = [CIImage imageWithCGImage:srcImage.CGImage];
NSArray *features = [detector featuresInImage:image];
if (0==features.count) {
NSLog(@"PROBLEM! Feature size is zero!\n");
callback(@[RCTMakeError(@"Feature size is zero!", nil, nil)]);
return;
}

CIQRCodeFeature *feature = [features firstObject];

NSString *result = feature.messageString;
NSLog(@"result: %@", result);
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
{
ALAssetRepresentation *rep = [myasset defaultRepresentation];
float width = [rep dimensions].width;
float height = [rep dimensions].height;
// CGImageRef iref = CGImageCreateWithImageInRect([rep fullResolutionImage], CGRectMake(width/2, 0, width/2, height));
CGImageRef iref = rep.fullScreenImage;
if (nil==rep){
NSLog(@"PROBLEM! IMAGE NOT LOADED\n");
callback(@[RCTMakeError(@"IMAGE NOT LOADED!", nil, nil)]);
return;
}

// Write image to test

// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// NSString *fileName = [rep filename];
// NSString *combined = [NSString stringWithFormat:@"ScreenShot - %@.png", fileName];
// NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:combined];
//
// UIImage *currentImage = [UIImage imageWithCGImage:iref];
// NSData *currentImageData = UIImagePNGRepresentation(currentImage);
// [currentImageData writeToFile:filePath atomically:YES];
//
NSLog(@"OK - IMAGE LOADED\n");
NSDictionary *detectorOptions = @{@"CIDetectorAccuracy": @"CIDetectorAccuracyHigh"};
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:detectorOptions];
CIImage *image = [CIImage imageWithCGImage:iref];
NSArray *features = [detector featuresInImage:image];
if (0==features.count) {
NSLog(@"PROBLEM! Feature size is zero!\n");
callback(@[RCTMakeError(@"Feature size is zero!", nil, nil)]);
return;
}

CIQRCodeFeature *feature = [features firstObject];

NSString *result = feature.messageString;
NSLog(@"result: %@", result);

if (result) {
callback(@[[NSNull null], result]);
} else {
callback(@[RCTMakeError(@"QR Parse failed!", nil, nil)]);
return;
}
};

ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror){

//failed to get image.
};

if (result) {
callback(@[[NSNull null], result]);
} else {
callback(@[RCTMakeError(@"QR Parse failed!", nil, nil)]);
return;
}
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
NSURL *myAssetUrl = [NSURL URLWithString:[path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[assetslibrary assetForURL:myAssetUrl resultBlock:resultblock failureBlock:failureblock];
}

@end