uCrop
uCrop copied to clipboard
Master non native
package com.yalantis.ucrop.task;
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.net.Uri; import android.os.AsyncTask; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.Nullable;
import com.yalantis.ucrop.callback.BitmapLoadCallback; import com.yalantis.ucrop.model.ExifInfo; import com.yalantis.ucrop.util.BitmapLoadUtils;
import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream;
import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okio.BufferedSource; import okio.Okio; import okio.Sink;
/**
-
Creates and returns a Bitmap for a given Uri(String url).
-
inSampleSize is calculated based on requiredWidth property. However can be adjusted if OOM occurs.
-
If any EXIF config is found - bitmap is transformed properly. */ public class BitmapLoadTask extends AsyncTask<Void, Void, BitmapLoadTask.BitmapWorkerResult> {
private static final String TAG = "BitmapWorkerTask";
private final Context mContext; private Uri mInputUri; private Uri mOutputUri; private final int mRequiredWidth; private final int mRequiredHeight;
private final BitmapLoadCallback mBitmapLoadCallback;
public static class BitmapWorkerResult {
Bitmap mBitmapResult; ExifInfo mExifInfo; Exception mBitmapWorkerException; public BitmapWorkerResult(@NonNull Bitmap bitmapResult, @NonNull ExifInfo exifInfo) { mBitmapResult = bitmapResult; mExifInfo = exifInfo; } public BitmapWorkerResult(@NonNull Exception bitmapWorkerException) { mBitmapWorkerException = bitmapWorkerException; }
}
public BitmapLoadTask(@NonNull Context context, @NonNull Uri inputUri, @Nullable Uri outputUri, int requiredWidth, int requiredHeight, BitmapLoadCallback loadCallback) { mContext = context; mInputUri = inputUri; mOutputUri = outputUri; mRequiredWidth = requiredWidth; mRequiredHeight = requiredHeight; mBitmapLoadCallback = loadCallback; }
@Override @NonNull protected BitmapWorkerResult doInBackground(Void... params) { if (mInputUri == null) { return new BitmapWorkerResult(new NullPointerException("Input Uri cannot be null")); }
try { processInputUri(); } catch (NullPointerException | IOException e) { return new BitmapWorkerResult(e); } final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; try { BitmapFactory.decodeStream(mContext.getContentResolver().openInputStream(mInputUri) ,null, options); } catch (FileNotFoundException e) { e.printStackTrace(); } options.inSampleSize = BitmapLoadUtils.calculateInSampleSize(options, mRequiredWidth, mRequiredHeight); options.inJustDecodeBounds = false; Bitmap decodeSampledBitmap = null; boolean decodeAttemptSuccess = false; while (!decodeAttemptSuccess) { try { InputStream stream = mContext.getContentResolver().openInputStream(mInputUri); try { decodeSampledBitmap = BitmapFactory.decodeStream(stream, null, options); if (options.outWidth == -1 || options.outHeight == -1) { return new BitmapWorkerResult(new IllegalArgumentException("Bounds for bitmap could not be retrieved from the Uri: [" + mInputUri + "]")); } } finally { BitmapLoadUtils.close(stream); } decodeAttemptSuccess = true; } catch (OutOfMemoryError error) { Log.e(TAG, "doInBackground: BitmapFactory.decodeFileDescriptor: ", error); options.inSampleSize *= 2; } catch (IOException e) { Log.e(TAG, "doInBackground: ImageDecoder.createSource: ", e); return new BitmapWorkerResult(new IllegalArgumentException("Bitmap could not be decoded from the Uri: [" + mInputUri + "]", e)); } } if (decodeSampledBitmap == null) { return new BitmapWorkerResult(new IllegalArgumentException("Bitmap could not be decoded from the Uri: [" + mInputUri + "]")); } int exifOrientation = BitmapLoadUtils.getExifOrientation(mContext, mInputUri); int exifDegrees = BitmapLoadUtils.exifToDegrees(exifOrientation); int exifTranslation = BitmapLoadUtils.exifToTranslation(exifOrientation); ExifInfo exifInfo = new ExifInfo(exifOrientation, exifDegrees, exifTranslation); Matrix matrix = new Matrix(); if (exifDegrees != 0) { matrix.preRotate(exifDegrees); } if (exifTranslation != 1) { matrix.postScale(exifTranslation, 1); } if (!matrix.isIdentity()) { return new BitmapWorkerResult(BitmapLoadUtils.transformBitmap(decodeSampledBitmap, matrix), exifInfo); } return new BitmapWorkerResult(decodeSampledBitmap, exifInfo);
}
private void processInputUri() throws NullPointerException, IOException { String inputUriScheme = mInputUri.getScheme(); Log.d(TAG, "Uri scheme: " + inputUriScheme); if ("http".equals(inputUriScheme) || "https".equals(inputUriScheme)) { try { downloadFile(mInputUri, mOutputUri); } catch (NullPointerException | IOException e) { Log.e(TAG, "Downloading failed", e); throw e; } } else if ("content".equals(inputUriScheme)) { try { copyFile(mInputUri, mOutputUri); } catch (NullPointerException | IOException e) { Log.e(TAG, "Copying failed", e); throw e; } } else if (!"file".equals(inputUriScheme)) { Log.e(TAG, "Invalid Uri scheme " + inputUriScheme); throw new IllegalArgumentException("Invalid Uri scheme" + inputUriScheme); } }
private void copyFile(@NonNull Uri inputUri, @Nullable Uri outputUri) throws NullPointerException, IOException { Log.d(TAG, "copyFile");
if (outputUri == null) { throw new NullPointerException("Output Uri is null - cannot copy image"); } InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = mContext.getContentResolver().openInputStream(inputUri); outputStream = new FileOutputStream(new File(outputUri.getPath())); if (inputStream == null) { throw new NullPointerException("InputStream for given input Uri is null"); } byte buffer[] = new byte[1024]; int length; while ((length = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, length); } } finally { BitmapLoadUtils.close(outputStream); BitmapLoadUtils.close(inputStream); // swap uris, because input image was copied to the output destination // (cropped image will override it later) mInputUri = mOutputUri; }
}
private void downloadFile(@NonNull Uri inputUri, @Nullable Uri outputUri) throws NullPointerException, IOException { Log.d(TAG, "downloadFile");
if (outputUri == null) { throw new NullPointerException("Output Uri is null - cannot download image"); } OkHttpClient client = new OkHttpClient(); BufferedSource source = null; Sink sink = null; Response response = null; try { Request request = new Request.Builder() .url(inputUri.toString()) .build(); response = client.newCall(request).execute(); source = response.body().source(); OutputStream outputStream = mContext.getContentResolver().openOutputStream(outputUri); if (outputStream != null) { sink = Okio.sink(outputStream); source.readAll(sink); } else { throw new NullPointerException("OutputStream for given output Uri is null"); } } finally { BitmapLoadUtils.close(source); BitmapLoadUtils.close(sink); if (response != null) { BitmapLoadUtils.close(response.body()); } client.dispatcher().cancelAll(); // swap uris, because input image was downloaded to the output destination // (cropped image will override it later) mInputUri = mOutputUri; }
}
@Override protected void onPostExecute(@NonNull BitmapWorkerResult result) { if (result.mBitmapWorkerException == null) { mBitmapLoadCallback.onBitmapLoaded(result.mBitmapResult, result.mExifInfo, mInputUri.getPath(), (mOutputUri == null) ? null : mOutputUri.getPath()); } else { mBitmapLoadCallback.onFailure(result.mBitmapWorkerException); } }
}