diff --git a/lib/src/main/java/com/soundcloud/android/crop/Crop.java b/lib/src/main/java/com/soundcloud/android/crop/Crop.java index 564f5b52..65dc0b69 100644 --- a/lib/src/main/java/com/soundcloud/android/crop/Crop.java +++ b/lib/src/main/java/com/soundcloud/android/crop/Crop.java @@ -26,6 +26,19 @@ interface Extra { String MAX_X = "max_x"; String MAX_Y = "max_y"; String ERROR = "error"; + String SCALE_METHOD = "scale_method"; + } + + public enum ScaleMethod { + /** + * Using the exact dimensions provided and using a scaling function for creating a scale bitmap. When scaling a large amount, the quality can suffer. + */ + EXACT, + /** + * This approach uses sampling while decoding the image which provides better results; however, this requires the image be scaled by powers of 2 and cannot provide + * dimensions exactly requested. This will result in better quality images when the scale amount is large. + */ + BETTER_QUALITY_BEST_FIT; } private Intent cropIntent; @@ -44,6 +57,7 @@ private Crop(Uri source, Uri destination) { cropIntent = new Intent(); cropIntent.setData(source); cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, destination); + cropIntent.putExtra(Extra.SCALE_METHOD, ScaleMethod.EXACT.ordinal()); } /** @@ -79,6 +93,16 @@ public Crop withMaxSize(int width, int height) { return this; } + /** + * Set how the image will be scaled when providing {@link Extra#MAX_X} and {@link Extra#MAX_Y} with the {@link #withMaxSize(int, int)} + * @param type + * @return + */ + public Crop withScaleMethod(ScaleMethod type) { + cropIntent.putExtra(Extra.SCALE_METHOD, type.ordinal()); + return this; + } + /** * Send the crop Intent from an Activity * diff --git a/lib/src/main/java/com/soundcloud/android/crop/CropImageActivity.java b/lib/src/main/java/com/soundcloud/android/crop/CropImageActivity.java index 97a0466a..26358a5d 100644 --- a/lib/src/main/java/com/soundcloud/android/crop/CropImageActivity.java +++ b/lib/src/main/java/com/soundcloud/android/crop/CropImageActivity.java @@ -21,7 +21,9 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapRegionDecoder; +import android.graphics.Canvas; import android.graphics.Matrix; +import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.net.Uri; @@ -56,6 +58,7 @@ public class CropImageActivity extends MonitoredActivity { private int maxX; private int maxY; private int exifRotation; + private Crop.ScaleMethod scaleMethod; private Uri sourceUri; private Uri saveUri; @@ -126,6 +129,7 @@ private void loadInput() { maxX = extras.getInt(Crop.Extra.MAX_X); maxY = extras.getInt(Crop.Extra.MAX_Y); saveUri = extras.getParcelable(MediaStore.EXTRA_OUTPUT); + scaleMethod = Crop.ScaleMethod.values()[extras.getInt(Crop.Extra.SCALE_METHOD, 0)]; } sourceUri = intent.getData(); @@ -343,11 +347,29 @@ private Bitmap decodeRegionCrop(Rect rect, int outWidth, int outHeight) { } try { - croppedImage = decoder.decodeRegion(rect, new BitmapFactory.Options()); - if (croppedImage != null && (rect.width() > outWidth || rect.height() > outHeight)) { - Matrix matrix = new Matrix(); - matrix.postScale((float) outWidth / rect.width(), (float) outHeight / rect.height()); - croppedImage = Bitmap.createBitmap(croppedImage, 0, 0, croppedImage.getWidth(), croppedImage.getHeight(), matrix, true); + BitmapFactory.Options options = new BitmapFactory.Options(); + if ((rect.width() > outWidth || rect.height() > outHeight)) { + switch (scaleMethod) { + case EXACT: + croppedImage = decoder.decodeRegion(rect, options); + Matrix matrix = new Matrix(); + matrix.postScale((float) outWidth / rect.width(), (float) outHeight / rect.height()); + croppedImage = Bitmap.createBitmap(croppedImage, 0, 0, croppedImage.getWidth(), croppedImage.getHeight(), matrix, true); + break; + case BETTER_QUALITY_BEST_FIT: + int w, h; + int inSampleSize = 1; + do { + inSampleSize *= 2; + w = rect.width() / inSampleSize; + h = rect.height() / inSampleSize; + } while(w > outWidth && h > outHeight); + options.inSampleSize = inSampleSize; + croppedImage = decoder.decodeRegion(rect, options); + break; + } + } else { + croppedImage = decoder.decodeRegion(rect, options); } } catch (IllegalArgumentException e) { // Rethrow with some extra information @@ -433,5 +455,4 @@ private void setResultUri(Uri uri) { private void setResultException(Throwable throwable) { setResult(Crop.RESULT_ERROR, new Intent().putExtra(Crop.Extra.ERROR, throwable)); } - }