Skip to content

Commit

Permalink
add resize option to cropped image
Browse files Browse the repository at this point in the history
  • Loading branch information
ArthurHub committed Aug 16, 2016
1 parent 6bc436d commit e5e41db
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,24 +91,30 @@ final class BitmapCroppingWorkerTask extends AsyncTask<Void, Void, BitmapCroppin
*/
private final int mReqHeight;

/**
* The option to handle requested width/height
*/
private final CropImageView.RequestSizeOptions mReqSizeOptions;

/**
* the Android Uri to save the cropped image to
*/
private final Uri mSaveUri;

/**
* the compression format to use when writting the image
* the compression format to use when writing the image
*/
private final Bitmap.CompressFormat mSaveCompressFormat;

/**
* the quility (if applicable) to use when writting the image (0 - 100)
* the quality (if applicable) to use when writing the image (0 - 100)
*/
private final int mSaveCompressQuality;
//endregion

public BitmapCroppingWorkerTask(CropImageView cropImageView, Bitmap bitmap, float[] cropPoints,
int degreesRotated, boolean fixAspectRatio, int aspectRatioX, int aspectRatioY,
int reqWidth, int reqHeight, CropImageView.RequestSizeOptions options,
Uri saveUri, Bitmap.CompressFormat saveCompressFormat, int saveCompressQuality) {

mCropImageViewReference = new WeakReference<>(cropImageView);
Expand All @@ -120,19 +126,20 @@ public BitmapCroppingWorkerTask(CropImageView cropImageView, Bitmap bitmap, floa
mFixAspectRatio = fixAspectRatio;
mAspectRatioX = aspectRatioX;
mAspectRatioY = aspectRatioY;
mReqWidth = reqWidth;
mReqHeight = reqHeight;
mReqSizeOptions = options;
mSaveUri = saveUri;
mSaveCompressFormat = saveCompressFormat;
mSaveCompressQuality = saveCompressQuality;
mOrgWidth = 0;
mOrgHeight = 0;
mReqWidth = 0;
mReqHeight = 0;
}

public BitmapCroppingWorkerTask(CropImageView cropImageView, Uri uri, float[] cropPoints,
int degreesRotated, int orgWidth, int orgHeight,
boolean fixAspectRatio, int aspectRatioX, int aspectRatioY,
int reqWidth, int reqHeight,
int reqWidth, int reqHeight, CropImageView.RequestSizeOptions options,
Uri saveUri, Bitmap.CompressFormat saveCompressFormat, int saveCompressQuality) {

mCropImageViewReference = new WeakReference<>(cropImageView);
Expand All @@ -147,6 +154,7 @@ public BitmapCroppingWorkerTask(CropImageView cropImageView, Uri uri, float[] cr
mOrgHeight = orgHeight;
mReqWidth = reqWidth;
mReqHeight = reqHeight;
mReqSizeOptions = options;
mSaveUri = saveUri;
mSaveCompressFormat = saveCompressFormat;
mSaveCompressQuality = saveCompressQuality;
Expand Down Expand Up @@ -183,6 +191,8 @@ protected BitmapCroppingWorkerTask.Result doInBackground(Void... params) {
bitmap = BitmapUtils.cropBitmap(mBitmap, mCropPoints, mDegreesRotated, mFixAspectRatio, mAspectRatioX, mAspectRatioY);
}

bitmap = BitmapUtils.resizeBitmap(bitmap, mReqWidth, mReqHeight, mReqSizeOptions);

if (mSaveUri == null) {
return new Result(bitmap, sampleSize);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;
import android.util.Pair;

import java.io.Closeable;
Expand Down Expand Up @@ -298,6 +299,39 @@ public static void writeBitmapToUri(Context context, Bitmap bitmap, Uri uri, Bit
}
}

/**
* Resize the given bitmap to the given width/height by the given option.<br>
*/
public static Bitmap resizeBitmap(Bitmap bitmap, int reqWidth, int reqHeight, CropImageView.RequestSizeOptions options) {
try {
if (reqWidth > 0 && reqHeight > 0 && (options == CropImageView.RequestSizeOptions.RESIZE_FIT ||
options == CropImageView.RequestSizeOptions.RESIZE_INSIDE ||
options == CropImageView.RequestSizeOptions.RESIZE_EXACT)) {

Bitmap resized = null;
if (options == CropImageView.RequestSizeOptions.RESIZE_EXACT) {
resized = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, false);
} else {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float scale = Math.max(width / (float) reqWidth, height / (float) reqHeight);
if (scale > 1 || options == CropImageView.RequestSizeOptions.RESIZE_FIT) {
resized = Bitmap.createScaledBitmap(bitmap, (int) (width / scale), (int) (height / scale), false);
}
}
if (resized != null) {
if (resized != bitmap) {
bitmap.recycle();
}
return resized;
}
}
} catch (Exception e) {
Log.w("AIC", "Failed to resize cropped image, return bitmap before resize", e);
}
return bitmap;
}

//region: Private methods

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -559,25 +559,37 @@ public void resetCropRect() {
* @return a new Bitmap representing the cropped image
*/
public Bitmap getCroppedImage() {
return getCroppedImage(0, 0);
return getCroppedImage(0, 0, RequestSizeOptions.NONE);
}

/**
* Gets the cropped image based on the current crop window.<br>
* If image loaded from URI will use sample size to fit in the requested width and height down-sampling
* if required - optimization to get best size to quality.<br>
* NOTE: resulting image will not be exactly (reqWidth, reqHeight)
* see: <a href="http://developer.android.com/training/displaying-bitmaps/load-bitmap.html">Loading Large
* Bitmaps Efficiently</a>
* Uses {@link RequestSizeOptions#RESIZE_INSIDE} option.
*
* @param reqWidth the width to down-sample the cropped image to
* @param reqHeight the height to down-sample the cropped image to
* @param reqWidth the width to resize the cropped image to
* @param reqHeight the height to resize the cropped image to
* @return a new Bitmap representing the cropped image
*/
public Bitmap getCroppedImage(int reqWidth, int reqHeight) {
return getCroppedImage(0, 0, RequestSizeOptions.RESIZE_INSIDE);
}

/**
* Gets the cropped image based on the current crop window.<br>
*
* @param reqWidth the width to resize the cropped image to (see options)
* @param reqHeight the height to resize the cropped image to (see options)
* @param options the resize method to use, see its documentation
* @return a new Bitmap representing the cropped image
*/
public Bitmap getCroppedImage(int reqWidth, int reqHeight, RequestSizeOptions options) {
Bitmap croppedBitmap = null;
if (mBitmap != null) {
mImageView.clearAnimation();

reqWidth = options != RequestSizeOptions.NONE ? reqWidth : 0;
reqHeight = options != RequestSizeOptions.NONE ? reqHeight : 0;

if (mLoadedImageUri != null && mLoadedSampleSize > 1) {
int orgWidth = mBitmap.getWidth() * mLoadedSampleSize;
int orgHeight = mBitmap.getHeight() * mLoadedSampleSize;
Expand All @@ -591,6 +603,8 @@ public Bitmap getCroppedImage(int reqWidth, int reqHeight) {
croppedBitmap = BitmapUtils.cropBitmap(mBitmap, getCropPoints(), mDegreesRotated,
mCropOverlayView.isFixAspectRatio(), mCropOverlayView.getAspectRatioX(), mCropOverlayView.getAspectRatioY());
}

croppedBitmap = BitmapUtils.resizeBitmap(croppedBitmap, reqWidth, reqHeight, options);
}

return croppedBitmap;
Expand All @@ -601,26 +615,34 @@ public Bitmap getCroppedImage(int reqWidth, int reqHeight) {
* The result will be invoked to listener set by {@link #setOnGetCroppedImageCompleteListener(OnGetCroppedImageCompleteListener)}.
*/
public void getCroppedImageAsync() {
getCroppedImageAsync(0, 0);
getCroppedImageAsync(0, 0, RequestSizeOptions.NONE);
}

/**
* Gets the cropped image based on the current crop window.<br>
* If (reqWidth,reqHeight) is given AND image is loaded from URI cropping will try to use sample size to fit in
* the requested width and height down-sampling if possible - optimization to get best size to quality.<br>
* NOTE: resulting image will not be exactly (reqWidth, reqHeight)
* see: <a href="http://developer.android.com/training/displaying-bitmaps/load-bitmap.html">Loading Large
* Bitmaps Efficiently</a><br>
* Uses {@link RequestSizeOptions#RESIZE_INSIDE} option.<br>
* The result will be invoked to listener set by {@link #setOnCropImageCompleteListener(OnCropImageCompleteListener)}.
*
* @param reqWidth the width to downsample the cropped image to
* @param reqHeight the height to downsample the cropped image to
* @param reqWidth the width to resize the cropped image to
* @param reqHeight the height to resize the cropped image to
*/
public void getCroppedImageAsync(int reqWidth, int reqHeight) {
getCroppedImageAsync(reqWidth, reqHeight, RequestSizeOptions.RESIZE_INSIDE);
}

/**
* Gets the cropped image based on the current crop window.<br>
* The result will be invoked to listener set by {@link #setOnCropImageCompleteListener(OnCropImageCompleteListener)}.
*
* @param reqWidth the width to resize the cropped image to (see options)
* @param reqHeight the height to resize the cropped image to (see options)
* @param options the resize method to use, see its documentation
*/
public void getCroppedImageAsync(int reqWidth, int reqHeight, RequestSizeOptions options) {
if (mOnCropImageCompleteListener == null && mOnGetCroppedImageCompleteListener == null) {
throw new IllegalArgumentException("mOnCropImageCompleteListener is not set");
}
startCropWorkerTask(reqWidth, reqHeight, null, null, 0);
startCropWorkerTask(reqWidth, reqHeight, options, null, null, 0);
}

/**
Expand All @@ -631,41 +653,52 @@ public void getCroppedImageAsync(int reqWidth, int reqHeight) {
* @param saveUri the Android Uri to save the cropped image to
*/
public void saveCroppedImageAsync(Uri saveUri) {
saveCroppedImageAsync(saveUri, Bitmap.CompressFormat.JPEG, 90, 0, 0);
saveCroppedImageAsync(saveUri, Bitmap.CompressFormat.JPEG, 90, 0, 0, RequestSizeOptions.NONE);
}

/**
* Save the cropped image based on the current crop window to the given uri.<br>
* The result will be invoked to listener set by {@link #setOnGetCroppedImageCompleteListener(OnGetCroppedImageCompleteListener)}.
*
* @param saveUri the Android Uri to save the cropped image to
* @param saveCompressFormat the compression format to use when writting the image
* @param saveCompressQuality the quility (if applicable) to use when writting the image (0 - 100)
* @param saveCompressFormat the compression format to use when writing the image
* @param saveCompressQuality the quality (if applicable) to use when writing the image (0 - 100)
*/
public void saveCroppedImageAsync(Uri saveUri, Bitmap.CompressFormat saveCompressFormat, int saveCompressQuality) {
saveCroppedImageAsync(saveUri, saveCompressFormat, saveCompressQuality, 0, 0);
saveCroppedImageAsync(saveUri, saveCompressFormat, saveCompressQuality, 0, 0, RequestSizeOptions.NONE);
}

/**
* Save the cropped image based on the current crop window to the given uri.<br>
* If (reqWidth,reqHeight) is given AND image is loaded from URI cropping will try to use sample size to fit in
* the requested width and height down-sampling if possible - optimization to get best size to quality.<br>
* NOTE: resulting image will not be exactly (reqWidth, reqHeight)
* see: <a href="http://developer.android.com/training/displaying-bitmaps/load-bitmap.html">Loading Large
* Bitmaps Efficiently</a><br>
* Uses {@link RequestSizeOptions#RESIZE_INSIDE} option.<br>
* The result will be invoked to listener set by {@link #setOnGetCroppedImageCompleteListener(OnGetCroppedImageCompleteListener)}.
*
* @param saveUri the Android Uri to save the cropped image to
* @param saveCompressFormat the compression format to use when writting the image
* @param saveCompressQuality the quility (if applicable) to use when writting the image (0 - 100)
* @param reqWidth the width to downsample the cropped image to
* @param reqHeight the height to downsample the cropped image to
* @param saveCompressFormat the compression format to use when writing the image
* @param saveCompressQuality the quality (if applicable) to use when writing the image (0 - 100)
* @param reqWidth the width to resize the cropped image to
* @param reqHeight the height to resize the cropped image to
*/
public void saveCroppedImageAsync(Uri saveUri, Bitmap.CompressFormat saveCompressFormat, int saveCompressQuality, int reqWidth, int reqHeight) {
saveCroppedImageAsync(saveUri, saveCompressFormat, saveCompressQuality, reqWidth, reqHeight, RequestSizeOptions.RESIZE_INSIDE);
}

/**
* Save the cropped image based on the current crop window to the given uri.<br>
* The result will be invoked to listener set by {@link #setOnGetCroppedImageCompleteListener(OnGetCroppedImageCompleteListener)}.
*
* @param saveUri the Android Uri to save the cropped image to
* @param saveCompressFormat the compression format to use when writing the image
* @param saveCompressQuality the quality (if applicable) to use when writing the image (0 - 100)
* @param reqWidth the width to resize the cropped image to (see options)
* @param reqHeight the height to resize the cropped image to (see options)
* @param options the resize method to use, see its documentation
*/
public void saveCroppedImageAsync(Uri saveUri, Bitmap.CompressFormat saveCompressFormat, int saveCompressQuality, int reqWidth, int reqHeight, RequestSizeOptions options) {
if (mOnCropImageCompleteListener == null && mOnSaveCroppedImageCompleteListener == null) {
throw new IllegalArgumentException("mOnCropImageCompleteListener is not set");
}
startCropWorkerTask(reqWidth, reqHeight, saveUri, saveCompressFormat, saveCompressQuality);
startCropWorkerTask(reqWidth, reqHeight, options, saveUri, saveCompressFormat, saveCompressQuality);
}

/**
Expand Down Expand Up @@ -975,13 +1008,14 @@ private void clearImageInt() {
* the requested width and height down-sampling if possible - optimization to get best size to quality.<br>
* The result will be invoked to listener set by {@link #setOnGetCroppedImageCompleteListener(OnGetCroppedImageCompleteListener)}.
*
* @param reqWidth optional: the width to downsample the cropped image to
* @param reqHeight optional: the height to downsample the cropped image to
* @param reqWidth the width to resize the cropped image to (see options)
* @param reqHeight the height to resize the cropped image to (see options)
* @param options the resize method to use on the cropped bitmap
* @param saveUri optional: to save the cropped image to
* @param saveCompressFormat if saveUri is given, the given compression will be used for saving the image
* @param saveCompressQuality if saveUri is given, the given quiality will be used for the compression.
* @param saveCompressQuality if saveUri is given, the given quality will be used for the compression.
*/
public void startCropWorkerTask(int reqWidth, int reqHeight, Uri saveUri, Bitmap.CompressFormat saveCompressFormat, int saveCompressQuality) {
public void startCropWorkerTask(int reqWidth, int reqHeight, RequestSizeOptions options, Uri saveUri, Bitmap.CompressFormat saveCompressFormat, int saveCompressQuality) {
if (mBitmap != null) {
mImageView.clearAnimation();

Expand All @@ -991,16 +1025,22 @@ public void startCropWorkerTask(int reqWidth, int reqHeight, Uri saveUri, Bitmap
currentTask.cancel(true);
}

reqWidth = options != RequestSizeOptions.NONE ? reqWidth : 0;
reqHeight = options != RequestSizeOptions.NONE ? reqHeight : 0;

int orgWidth = mBitmap.getWidth() * mLoadedSampleSize;
int orgHeight = mBitmap.getHeight() * mLoadedSampleSize;
if (mLoadedImageUri != null && mLoadedSampleSize > 1) {
mBitmapCroppingWorkerTask = new WeakReference<>(new BitmapCroppingWorkerTask(this, mLoadedImageUri, getCropPoints(),
mDegreesRotated, orgWidth, orgHeight,
mCropOverlayView.isFixAspectRatio(), mCropOverlayView.getAspectRatioX(), mCropOverlayView.getAspectRatioY(),
reqWidth, reqHeight, saveUri, saveCompressFormat, saveCompressQuality));
reqWidth, reqHeight, options,
saveUri, saveCompressFormat, saveCompressQuality));
} else {
mBitmapCroppingWorkerTask = new WeakReference<>(new BitmapCroppingWorkerTask(this, mBitmap, getCropPoints(), mDegreesRotated,
mCropOverlayView.isFixAspectRatio(), mCropOverlayView.getAspectRatioX(), mCropOverlayView.getAspectRatioY(), saveUri, saveCompressFormat, saveCompressQuality));
mCropOverlayView.isFixAspectRatio(), mCropOverlayView.getAspectRatioX(), mCropOverlayView.getAspectRatioY(),
reqWidth, reqHeight, options,
saveUri, saveCompressFormat, saveCompressQuality));
}
mBitmapCroppingWorkerTask.get().execute();
setProgressBarVisibility();
Expand Down Expand Up @@ -1489,6 +1529,15 @@ public enum RequestSizeOptions {
*/
NONE,

/**
* Only sample the image during loading (if image set using URI) so the smallest of the image
* dimensions will be between the requested size and x2 requested size.<br>
* NOTE: resulting image will not be exactly requested width/height
* see: <a href="http://developer.android.com/training/displaying-bitmaps/load-bitmap.html">Loading Large
* Bitmaps Efficiently</a>.
*/
SAMPLING,

/**
* Resize the image uniformly (maintain the image's aspect ratio) so that both
* dimensions (width and height) of the image will be equal to or <b>less</b> than the
Expand All @@ -1505,13 +1554,11 @@ public enum RequestSizeOptions {
RESIZE_FIT,

/**
* Only sample the image during loading (if image set using URI) so the smallest of the image
* dimensions will be between the requested size and x2 requested size.<br>
* NOTE: resulting image will not be exactly requested width/height
* see: <a href="http://developer.android.com/training/displaying-bitmaps/load-bitmap.html">Loading Large
* Bitmaps Efficiently</a>.
* Resize the image to fit exactly in the given width/height.<br>
* This resize method does NOT preserve aspect ratio.<br>
* If the image is smaller than the requested size it will enlarge it.
*/
SAMPLING
RESIZE_EXACT
}
//endregion

Expand Down

0 comments on commit e5e41db

Please sign in to comment.