Skip to content

Instantly share code, notes, and snippets.

@fishkingsin
Created May 23, 2019 06:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fishkingsin/a2ce1599b165c6dbf650a62a87be82e0 to your computer and use it in GitHub Desktop.
Save fishkingsin/a2ce1599b165c6dbf650a62a87be82e0 to your computer and use it in GitHub Desktop.
ImageProcessingTask
package com.creedon.Nixplay;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.media.ExifInterface;
import android.util.Log;
import com.alinz.parkerdan.shareextension.RealPathUtil;
import com.crashlytics.android.Crashlytics;
import com.creedon.reactlibrary.imagepicker.utils.FileUtils;
import com.creedon.reactlibrary.imagepicker.utils.ImageResizer;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Date;
import java.util.Iterator;
/**
* _ _ _______ ________ _ _____ __
* | \ | |_ _\ \ / /| ___ \ | / _ \ \ / /
* | \| | | | \ V / | |_/ / | / /_\ \ V /
* | . ` | | | / \ | __/| | | _ |\ /
* | |\ |_| |_/ /^\ \| | | |____| | | || |
* \_| \_/\___/\/ \/\_| \_____/\_| |_/\_/
* <p>
* Created by jameskong on 2019-05-23.
*/
public class ImageProcessingTask extends AsyncTask<Uri, JSONObject, WritableMap> {
private static final String TAG = "NixShareModule";
private static final String URI = "uri";
private static final String IMAGES_KEY = "images";
private static final String FILEPROVIDER_KEY = "fileProvider";
private static final String FILENAME = "fileName";
private static final String FULLFILEPATH = "fullFilePath";
private static final String MIME_TYPE = "mime";
private static final String TYPE = "type";
private static final String CAPTION = "caption";
private static final String ID = "id";
private static final String META = "meta";
private static final String FILE_SIZE = "fileSize";
private static final String ERROR_KEY = "error";
private static final String LOADING_KEY = "loading";
private WeakReference<Promise> promise;
private WeakReference<Activity> currentActivity;
private long fileSizeLimit = 20000000;
private int widthLimit = 8000;
private int heightLimit = 8000;
private int maxWidth = 1820;
private int maxHeight = 1820;
ImageProcessingTask(Activity currentActivity, Promise promise,
long fileSizeLimit,
int widthLimit,
int heightLimit,
int maxWidth,
int maxHeight) {
this.fileSizeLimit = fileSizeLimit;
this.widthLimit = widthLimit;
this.heightLimit = heightLimit;
this.maxWidth = maxWidth;
this.maxHeight = maxHeight;
this.currentActivity = new WeakReference<>(currentActivity);
this.promise = new WeakReference<>(promise);
}
// Runs in UI before background thread is called
@Override
protected void onPreExecute() {
super.onPreExecute();
// Do something like display a progress bar
}
// This is run in a background thread
@Override
protected WritableMap doInBackground(Uri... uris) {
WritableMap map = Arguments.createMap();
JSONArray data = new JSONArray();
// get the string from params, which is an array
String fileProvider = "";
// Do something that takes a long time, for example:
try {
for (int i = 0; i < uris.length; i++) {
Uri uri = uris[i];
// Do things
fileProvider = uri.getAuthority();
try {
JSONObject imageDataJSON = convertToBitmapAndCreateAFile(this.currentActivity.get(), uri);
data.put(imageDataJSON);
// Call this to update your progress
publishProgress(imageDataJSON);
} catch (IOException e) {
e.printStackTrace();
map.putString(ERROR_KEY, e.toString());
} catch (JSONException e) {
e.printStackTrace();
map.putString(ERROR_KEY, e.toString());
}
}
} catch (Exception e) {
e.printStackTrace();
map.putString(ERROR_KEY, e.toString());
}
try {
map.putArray(IMAGES_KEY, convertJsonToArray(data));
} catch (Exception e) {
map.putString(ERROR_KEY, e.toString());
Crashlytics.logException(e);
e.printStackTrace();
}
map.putString(FILEPROVIDER_KEY, fileProvider);
return map;
}
// This is called from background thread but runs in UI
@Override
protected void onProgressUpdate(JSONObject... values) {
super.onProgressUpdate(values);
// Do things like update the progress bar
}
// This runs in UI when background thread finishes
@Override
protected void onPostExecute(WritableMap result) {
super.onPostExecute(result);
if (!result.hasKey(ERROR_KEY)) {
this.promise.get().resolve(result);
} else {
this.promise.get().reject(new Error(result.getString(ERROR_KEY)));
}
// Do things like hide the progress bar or change a TextView
}
private JSONObject convertToBitmapAndCreateAFile(Activity activity, Uri uri) throws IOException, JSONException {
JSONObject mDetails = new JSONObject();
File exportedFile = null;
String fileName = "";
long fileSize = fileSizeLimit;
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
options.inPurgeable = true;
options.inTempStorage = new byte[16 * 1024];
options.inSampleSize = calculateInSampleSize(options, widthLimit, heightLimit);
try {
String mimeType = FileUtils.getMimeType(activity, uri);
fileName = FileUtils.getFileName(activity, uri);
if (uri.getAuthority() != null && !uri.getAuthority().equals("0@media")) {
// create temp file first
if (FileUtils.isValidMimeType(mimeType)) {
File tempFile = new File(activity.getCacheDir(), fileName);
if (!tempFile.exists()) {
tempFile = FileUtils.copyFromUri(uri,
activity,
activity.getCacheDir(),
fileName);
}
exportedFile = resizeFileWithouAuthority(activity, Uri.fromFile(tempFile), options);
}
} else {
Log.d(TAG, "No Authority: " + uri.toString());
exportedFile = resizeFileWithouAuthority(activity, uri, options);
}
mDetails.put(ID, uri.toString());
mDetails.put(FILENAME, fileName);
mDetails.put(MIME_TYPE, mimeType);
mDetails.put(TYPE, mimeType);
mDetails.put(CAPTION, "");
mDetails.put(FILE_SIZE, fileSize);
if (exportedFile != null && exportedFile.exists() && exportedFile.length() > 0) {
Uri exportedFileUri = Uri.fromFile(exportedFile);
mDetails.put(URI, exportedFileUri.toString());
mDetails.put(FULLFILEPATH, exportedFileUri.toString());
mDetails.put(FILE_SIZE, exportedFile.length());
mDetails.put(META, new JSONObject());
} else {
JSONObject newMeta = new JSONObject();
newMeta.put(ERROR_KEY, "Unable to export file :" + uri.toString());
newMeta.put(LOADING_KEY, false);
mDetails.put(META, newMeta);
}
} catch (Exception e) {
e.printStackTrace();
throw e;
}
if (BuildConfig.DEBUG) Log.d(TAG, mDetails.toString());
return mDetails;
}
/**
@param uri assume from file://
*/
private File resizeFileWithouAuthority(Context context, Uri uri, BitmapFactory.Options options) throws IOException {
String realPath = RealPathUtil.getRealPathFromURI(context, uri);
if (realPath == null) {
throw new NullPointerException("realPath is null");
}
BitmapFactory.decodeFile(realPath, options);
int originalWidth = options.outWidth;
int originalHeight = options.outHeight;
File inputFile = new File(realPath);
ExifInterface exifInterface = null;
if (realPath != null) {
exifInterface = new ExifInterface(realPath);
}
String picturesDir = context.getCacheDir().getAbsolutePath();
long fileSize = inputFile.length();
/*
Android image criteria
1. if image file size > 21 mb downscale to both with/height < heightLimit or widthLimit
2. if resolution either with/height > 8000x8000, downscale to both with/height < widthLimit x heightLimit
3. if user turn on optimize upload resize
*/
boolean needResize = (fileSize > fileSizeLimit ||
(maxWidth > 0 && maxHeight > 0) ||
(originalWidth > widthLimit || originalHeight > heightLimit)
);
File exportedFile = null;
if (needResize) {
int width = originalWidth > widthLimit ? ((maxWidth > 0 && maxHeight > 0) ? maxWidth : widthLimit) : originalWidth;
int height = originalHeight > heightLimit ? ((maxWidth > 0 && maxHeight > 0) ? maxHeight : heightLimit) : originalHeight;
int quality = fileSize > fileSizeLimit ? 80 : 100;
try {
exportedFile = ImageResizer.createResizedImage(context,
Uri.fromFile(new File(realPath)),
width,
height,
Bitmap.CompressFormat.JPEG,
quality,
0,
picturesDir,
exifInterface);
} catch (IOException e) {
Crashlytics.logException(e);
throw e;
} finally {
if (exportedFile == null) {
exportedFile = inputFile;
}
}
} else {
if (!inputFile.getParent().equals(context.getCacheDir().getAbsolutePath())) {
File outputFile = new File(picturesDir);
exportedFile = ImageResizer.copy(inputFile, outputFile, Long.toString(new Date().getTime()), Bitmap.CompressFormat.JPEG);
} else {
exportedFile = inputFile;
}
}
return exportedFile;
}
private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
private static WritableMap convertJsonToMap(JSONObject jsonObject) throws JSONException {
WritableMap map = Arguments.createMap();
Iterator<String> iterator = jsonObject.keys();
while (iterator.hasNext()) {
String key = iterator.next();
Object value = jsonObject.get(key);
if (value instanceof JSONObject) {
map.putMap(key, convertJsonToMap((JSONObject) value));
} else if (value instanceof JSONArray) {
map.putArray(key, convertJsonToArray((JSONArray) value));
} else if (value instanceof Boolean) {
map.putBoolean(key, (Boolean) value);
} else if (value instanceof Integer) {
map.putInt(key, (Integer) value);
} else if (value instanceof Double) {
map.putDouble(key, (Double) value);
} else if (value instanceof String) {
map.putString(key, (String) value);
} else {
map.putString(key, value.toString());
}
}
return map;
}
private static WritableArray convertJsonToArray(JSONArray jsonArray) throws JSONException {
WritableArray array = new WritableNativeArray();
for (int i = 0; i < jsonArray.length(); i++) {
Object value = jsonArray.get(i);
if (value instanceof JSONObject) {
array.pushMap(convertJsonToMap((JSONObject) value));
} else if (value instanceof JSONArray) {
array.pushArray(convertJsonToArray((JSONArray) value));
} else if (value instanceof Boolean) {
array.pushBoolean((Boolean) value);
} else if (value instanceof Integer) {
array.pushInt((Integer) value);
} else if (value instanceof Double) {
array.pushDouble((Double) value);
} else if (value instanceof String) {
array.pushString((String) value);
} else {
array.pushString(value.toString());
}
}
return array;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment