diff --git a/sample/src/main/java/com/yalantis/ucrop/sample/SampleActivity.java b/sample/src/main/java/com/yalantis/ucrop/sample/SampleActivity.java
index c18a2c675..bbb73fd3e 100644
--- a/sample/src/main/java/com/yalantis/ucrop/sample/SampleActivity.java
+++ b/sample/src/main/java/com/yalantis/ucrop/sample/SampleActivity.java
@@ -55,9 +55,9 @@ public class SampleActivity extends BaseActivity implements UCropFragmentCallbac
private static final String SAMPLE_CROPPED_IMAGE_NAME = "SampleCropImage";
private RadioGroup mRadioGroupAspectRatio, mRadioGroupCompressionSettings;
- private EditText mEditTextMaxWidth, mEditTextMaxHeight;
+ private EditText mEditTextMinWidth, mEditTextMinHeight, mEditTextMaxWidth, mEditTextMaxHeight;
private EditText mEditTextRatioX, mEditTextRatioY;
- private CheckBox mCheckBoxMaxSize;
+ private CheckBox mCheckBoxMinSize, mCheckBoxMaxSize;
private SeekBar mSeekBarQuality;
private TextView mTextViewQuality;
private CheckBox mCheckBoxHideBottomControls;
@@ -145,9 +145,12 @@ public void onClick(View v) {
settingsView = findViewById(R.id.settings);
mRadioGroupAspectRatio = findViewById(R.id.radio_group_aspect_ratio);
mRadioGroupCompressionSettings = findViewById(R.id.radio_group_compression_settings);
+ mCheckBoxMinSize = findViewById(R.id.checkbox_min_size);
mCheckBoxMaxSize = findViewById(R.id.checkbox_max_size);
mEditTextRatioX = findViewById(R.id.edit_text_ratio_x);
mEditTextRatioY = findViewById(R.id.edit_text_ratio_y);
+ mEditTextMinWidth = findViewById(R.id.edit_text_min_width);
+ mEditTextMinHeight = findViewById(R.id.edit_text_min_height);
mEditTextMaxWidth = findViewById(R.id.edit_text_max_width);
mEditTextMaxHeight = findViewById(R.id.edit_text_max_height);
mSeekBarQuality = findViewById(R.id.seekbar_quality);
@@ -184,6 +187,8 @@ public void onStopTrackingTouch(SeekBar seekBar) {
}
});
+ mEditTextMinHeight.addTextChangedListener(mMinSizeTextWatcher);
+ mEditTextMinWidth.addTextChangedListener(mMinSizeTextWatcher);
mEditTextMaxHeight.addTextChangedListener(mMaxSizeTextWatcher);
mEditTextMaxWidth.addTextChangedListener(mMaxSizeTextWatcher);
}
@@ -206,6 +211,26 @@ public void afterTextChanged(Editable s) {
}
};
+ private TextWatcher mMinSizeTextWatcher = new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (s != null && !s.toString().trim().isEmpty()) {
+ if (Integer.valueOf(s.toString()) < UCrop.MIN_SIZE) {
+ Toast.makeText(SampleActivity.this, String.format(getString(R.string.format_min_cropped_image_size), UCrop.MIN_SIZE), Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+ };
+
private TextWatcher mMaxSizeTextWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@@ -301,10 +326,24 @@ private UCrop basisConfig(@NonNull UCrop uCrop) {
break;
}
+ if (mCheckBoxMinSize.isChecked()) {
+ try {
+ int minWidth = Integer.valueOf(mEditTextMinWidth.getText().toString().trim());
+ int minHeight = Integer.valueOf(mEditTextMinHeight.getText().toString().trim());
+
+ if (minWidth > UCrop.MIN_SIZE && minHeight > UCrop.MIN_SIZE) {
+ uCrop = uCrop.withMinResultSize(minWidth, minHeight);
+ }
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Number please", e);
+ }
+ }
+
if (mCheckBoxMaxSize.isChecked()) {
try {
int maxWidth = Integer.valueOf(mEditTextMaxWidth.getText().toString().trim());
int maxHeight = Integer.valueOf(mEditTextMaxHeight.getText().toString().trim());
+
if (maxWidth > UCrop.MIN_SIZE && maxHeight > UCrop.MIN_SIZE) {
uCrop = uCrop.withMaxResultSize(maxWidth, maxHeight);
}
diff --git a/sample/src/main/res/layout/include_settings.xml b/sample/src/main/res/layout/include_settings.xml
index abdaae8bf..8a054785a 100644
--- a/sample/src/main/res/layout/include_settings.xml
+++ b/sample/src/main/res/layout/include_settings.xml
@@ -135,6 +135,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Dynamic
Image source
Square
+ Min cropped image size
Max cropped image size
Compression settings
UI
Width
Height
+ Resize image to min size
Resize image to max size
Hide bottom UI controls
Freestyle crop
@@ -32,6 +34,7 @@
Crop Result (%1$dx%2$d)
Quality: %d
%1$dx%2$d px
+ Min cropped image size cannot be less then %d
Max cropped image size cannot be less then %d
Permission needed
diff --git a/ucrop/src/main/java/com/yalantis/ucrop/UCrop.java b/ucrop/src/main/java/com/yalantis/ucrop/UCrop.java
index d6cd45a10..06d3f7039 100644
--- a/ucrop/src/main/java/com/yalantis/ucrop/UCrop.java
+++ b/ucrop/src/main/java/com/yalantis/ucrop/UCrop.java
@@ -48,6 +48,8 @@ public class UCrop {
public static final String EXTRA_ASPECT_RATIO_X = EXTRA_PREFIX + ".AspectRatioX";
public static final String EXTRA_ASPECT_RATIO_Y = EXTRA_PREFIX + ".AspectRatioY";
+ public static final String EXTRA_MIN_SIZE_X = EXTRA_PREFIX + ".MinSizeX";
+ public static final String EXTRA_MIN_SIZE_Y = EXTRA_PREFIX + ".MinSizeY";
public static final String EXTRA_MAX_SIZE_X = EXTRA_PREFIX + ".MaxSizeX";
public static final String EXTRA_MAX_SIZE_Y = EXTRA_PREFIX + ".MaxSizeY";
@@ -94,8 +96,30 @@ public UCrop useSourceImageAspectRatio() {
return this;
}
+ /**
+ * Set minimum size for result cropped image. Minimum size cannot be less then {@value MIN_SIZE}
+ * The priority of this method is less than the {@link #withMaxResultSize(int, int) withMaxResultSize} method.
+ *
+ * @param width min cropped image width
+ * @param height min cropped image height
+ */
+ public UCrop withMinResultSize(@IntRange(from = MIN_SIZE) int width, @IntRange(from = MIN_SIZE) int height) {
+ if (width < MIN_SIZE) {
+ width = MIN_SIZE;
+ }
+
+ if (height < MIN_SIZE) {
+ height = MIN_SIZE;
+ }
+
+ mCropOptionsBundle.putInt(EXTRA_MIN_SIZE_X, width);
+ mCropOptionsBundle.putInt(EXTRA_MIN_SIZE_Y, height);
+ return this;
+ }
+
/**
* Set maximum size for result cropped image. Maximum size cannot be less then {@value MIN_SIZE}
+ * The priority of this method is higher than the {@link #withMinResultSize(int, int) withMinResultSize} method.
*
* @param width max cropped image width
* @param height max cropped image height
@@ -545,8 +569,29 @@ public void useSourceImageAspectRatio() {
mOptionBundle.putFloat(EXTRA_ASPECT_RATIO_Y, 0);
}
+ /**
+ * Set minimum size for result cropped image.
+ * The priority of this method is less than the {@link #withMaxResultSize(int, int) withMaxResultSize} method.
+ *
+ * @param width min cropped image width
+ * @param height min cropped image height
+ */
+ public void withMinResultSize(@IntRange(from = MIN_SIZE) int width, @IntRange(from = MIN_SIZE) int height) {
+ if (width < MIN_SIZE) {
+ width = MIN_SIZE;
+ }
+
+ if (height < MIN_SIZE) {
+ height = MIN_SIZE;
+ }
+
+ mOptionBundle.putInt(EXTRA_MIN_SIZE_X, width);
+ mOptionBundle.putInt(EXTRA_MIN_SIZE_Y, height);
+ }
+
/**
* Set maximum size for result cropped image.
+ * The priority of this method is higher than the {@link #withMinResultSize(int, int) withMinResultSize} method.
*
* @param width max cropped image width
* @param height max cropped image height
diff --git a/ucrop/src/main/java/com/yalantis/ucrop/UCropActivity.java b/ucrop/src/main/java/com/yalantis/ucrop/UCropActivity.java
index 36b8b85f7..1189775a4 100644
--- a/ucrop/src/main/java/com/yalantis/ucrop/UCropActivity.java
+++ b/ucrop/src/main/java/com/yalantis/ucrop/UCropActivity.java
@@ -259,10 +259,19 @@ private void processOptions(@NonNull Intent intent) {
mGestureCropImageView.setTargetAspectRatio(CropImageView.SOURCE_IMAGE_ASPECT_RATIO);
}
+ // Result bitmap min size options
+ int minSizeX = intent.getIntExtra(UCrop.EXTRA_MIN_SIZE_X, 0);
+ int minSizeY = intent.getIntExtra(UCrop.EXTRA_MIN_SIZE_Y, 0);
+
// Result bitmap max size options
int maxSizeX = intent.getIntExtra(UCrop.EXTRA_MAX_SIZE_X, 0);
int maxSizeY = intent.getIntExtra(UCrop.EXTRA_MAX_SIZE_Y, 0);
+ if (minSizeX > 0 && minSizeY > 0) {
+ mGestureCropImageView.setMinResultImageSizeX(minSizeX);
+ mGestureCropImageView.setMinResultImageSizeY(minSizeY);
+ }
+
if (maxSizeX > 0 && maxSizeY > 0) {
mGestureCropImageView.setMaxResultImageSizeX(maxSizeX);
mGestureCropImageView.setMaxResultImageSizeY(maxSizeY);
diff --git a/ucrop/src/main/java/com/yalantis/ucrop/UCropFragment.java b/ucrop/src/main/java/com/yalantis/ucrop/UCropFragment.java
index 2e64450c4..23223927a 100644
--- a/ucrop/src/main/java/com/yalantis/ucrop/UCropFragment.java
+++ b/ucrop/src/main/java/com/yalantis/ucrop/UCropFragment.java
@@ -232,10 +232,19 @@ private void processOptions(@NonNull Bundle bundle) {
mGestureCropImageView.setTargetAspectRatio(CropImageView.SOURCE_IMAGE_ASPECT_RATIO);
}
+ // Result bitmap min size options
+ int minSizeX = bundle.getInt(UCrop.EXTRA_MIN_SIZE_X, 0);
+ int minSizeY = bundle.getInt(UCrop.EXTRA_MIN_SIZE_Y, 0);
+
// Result bitmap max size options
int maxSizeX = bundle.getInt(UCrop.EXTRA_MAX_SIZE_X, 0);
int maxSizeY = bundle.getInt(UCrop.EXTRA_MAX_SIZE_Y, 0);
+ if (minSizeX > 0 && minSizeY > 0) {
+ mGestureCropImageView.setMinResultImageSizeX(minSizeX);
+ mGestureCropImageView.setMinResultImageSizeY(minSizeY);
+ }
+
if (maxSizeX > 0 && maxSizeY > 0) {
mGestureCropImageView.setMaxResultImageSizeX(maxSizeX);
mGestureCropImageView.setMaxResultImageSizeY(maxSizeY);
diff --git a/ucrop/src/main/java/com/yalantis/ucrop/model/CropParameters.java b/ucrop/src/main/java/com/yalantis/ucrop/model/CropParameters.java
index 17d8a7e72..5dccc1053 100644
--- a/ucrop/src/main/java/com/yalantis/ucrop/model/CropParameters.java
+++ b/ucrop/src/main/java/com/yalantis/ucrop/model/CropParameters.java
@@ -7,7 +7,7 @@
*/
public class CropParameters {
- private int mMaxResultImageSizeX, mMaxResultImageSizeY;
+ private int mMinResultImageSizeX, mMinResultImageSizeY, mMaxResultImageSizeX, mMaxResultImageSizeY;
private Bitmap.CompressFormat mCompressFormat;
private int mCompressQuality;
@@ -15,9 +15,12 @@ public class CropParameters {
private ExifInfo mExifInfo;
- public CropParameters(int maxResultImageSizeX, int maxResultImageSizeY,
+ public CropParameters(int minResultImageSizeX, int minResultImageSizeY,
+ int maxResultImageSizeX, int maxResultImageSizeY,
Bitmap.CompressFormat compressFormat, int compressQuality,
String imageInputPath, String imageOutputPath, ExifInfo exifInfo) {
+ mMinResultImageSizeX = minResultImageSizeX;
+ mMinResultImageSizeY = minResultImageSizeY;
mMaxResultImageSizeX = maxResultImageSizeX;
mMaxResultImageSizeY = maxResultImageSizeY;
mCompressFormat = compressFormat;
@@ -27,6 +30,14 @@ public CropParameters(int maxResultImageSizeX, int maxResultImageSizeY,
mExifInfo = exifInfo;
}
+ public int getMinResultImageSizeX() {
+ return mMinResultImageSizeX;
+ }
+
+ public int getMinResultImageSizeY() {
+ return mMinResultImageSizeY;
+ }
+
public int getMaxResultImageSizeX() {
return mMaxResultImageSizeX;
}
diff --git a/ucrop/src/main/java/com/yalantis/ucrop/task/BitmapCropTask.java b/ucrop/src/main/java/com/yalantis/ucrop/task/BitmapCropTask.java
index 1a10b8604..7f2e1ac9e 100644
--- a/ucrop/src/main/java/com/yalantis/ucrop/task/BitmapCropTask.java
+++ b/ucrop/src/main/java/com/yalantis/ucrop/task/BitmapCropTask.java
@@ -40,8 +40,8 @@ public class BitmapCropTask extends AsyncTask {
private final RectF mCropRect;
private final RectF mCurrentImageRect;
- private float mCurrentScale, mCurrentAngle;
- private final int mMaxResultImageSizeX, mMaxResultImageSizeY;
+ private float mCurrentScale, mCurrentScaleX, mCurrentScaleY, mCurrentAngle;
+ private final int mMinResultImageSizeX, mMinResultImageSizeY, mMaxResultImageSizeX, mMaxResultImageSizeY;
private final Bitmap.CompressFormat mCompressFormat;
private final int mCompressQuality;
@@ -61,6 +61,9 @@ public BitmapCropTask(@Nullable Bitmap viewBitmap, @NonNull ImageState imageStat
mCurrentScale = imageState.getCurrentScale();
mCurrentAngle = imageState.getCurrentAngle();
+
+ mMinResultImageSizeX = cropParameters.getMinResultImageSizeX();
+ mMinResultImageSizeY = cropParameters.getMinResultImageSizeY();
mMaxResultImageSizeX = cropParameters.getMaxResultImageSizeX();
mMaxResultImageSizeY = cropParameters.getMaxResultImageSizeY();
@@ -106,34 +109,55 @@ private float resize() {
float scaleX = (swapSides ? options.outHeight : options.outWidth) / (float) mViewBitmap.getWidth();
float scaleY = (swapSides ? options.outWidth : options.outHeight) / (float) mViewBitmap.getHeight();
- float resizeScale = Math.min(scaleX, scaleY);
+// float resizeScale = Math.min(scaleX, scaleY);
+ float resizeScale = 1;
+
+// mCurrentScale /= resizeScale;
+ mCurrentScaleX = mCurrentScale / scaleX;
+ mCurrentScaleY = mCurrentScale / scaleY;
+
+// resizeScale = 1;
+
+ boolean hasMin = mMinResultImageSizeX > 0 && mMinResultImageSizeY > 0;
+ boolean hasMax = mMaxResultImageSizeX > 0 && mMaxResultImageSizeY > 0;
- mCurrentScale /= resizeScale;
+ if (hasMin || hasMax) {
+ float cropWidth = mCropRect.width() / mCurrentScaleX;
+ float cropHeight = mCropRect.height() / mCurrentScaleY;
- resizeScale = 1;
- if (mMaxResultImageSizeX > 0 && mMaxResultImageSizeY > 0) {
- float cropWidth = mCropRect.width() / mCurrentScale;
- float cropHeight = mCropRect.height() / mCurrentScale;
+ boolean scaleChanged = false;
- if (cropWidth > mMaxResultImageSizeX || cropHeight > mMaxResultImageSizeY) {
+ if (hasMin && (cropWidth < mMinResultImageSizeX || cropHeight < mMinResultImageSizeY)) {
+ scaleX = mMinResultImageSizeX / cropWidth;
+ scaleY = mMinResultImageSizeY / cropHeight;
+ scaleChanged = true;
+ }
+ if (hasMax && (cropWidth > mMaxResultImageSizeX || cropHeight > mMaxResultImageSizeY)) {
scaleX = mMaxResultImageSizeX / cropWidth;
scaleY = mMaxResultImageSizeY / cropHeight;
- resizeScale = Math.min(scaleX, scaleY);
+ scaleChanged = true;
+ }
- mCurrentScale /= resizeScale;
+ if (scaleChanged) {
+ resizeScale = Math.max(scaleX, scaleY);
+
+// mCurrentScale /= resizeScale;
+ mCurrentScaleX /= scaleX;
+ mCurrentScaleY /= scaleY;
}
}
+
return resizeScale;
}
private boolean crop(float resizeScale) throws IOException {
ExifInterface originalExif = new ExifInterface(mImageInputPath);
- cropOffsetX = Math.round((mCropRect.left - mCurrentImageRect.left) / mCurrentScale);
- cropOffsetY = Math.round((mCropRect.top - mCurrentImageRect.top) / mCurrentScale);
- mCroppedImageWidth = Math.round(mCropRect.width() / mCurrentScale);
- mCroppedImageHeight = Math.round(mCropRect.height() / mCurrentScale);
+ cropOffsetX = Math.round((mCropRect.left - mCurrentImageRect.left) / mCurrentScaleX);
+ cropOffsetY = Math.round((mCropRect.top - mCurrentImageRect.top) / mCurrentScaleY);
+ mCroppedImageWidth = Math.round(mCropRect.width() / mCurrentScaleX);
+ mCroppedImageHeight = Math.round(mCropRect.height() / mCurrentScaleY);
boolean shouldCrop = shouldCrop(mCroppedImageWidth, mCroppedImageHeight);
Log.i(TAG, "Should crop: " + shouldCrop);
diff --git a/ucrop/src/main/java/com/yalantis/ucrop/view/CropImageView.java b/ucrop/src/main/java/com/yalantis/ucrop/view/CropImageView.java
index 9d6dbd411..04c18f7bc 100644
--- a/ucrop/src/main/java/com/yalantis/ucrop/view/CropImageView.java
+++ b/ucrop/src/main/java/com/yalantis/ucrop/view/CropImageView.java
@@ -49,7 +49,7 @@ public class CropImageView extends TransformImageView {
private Runnable mWrapCropBoundsRunnable, mZoomImageToPositionRunnable = null;
private float mMaxScale, mMinScale;
- private int mMaxResultImageSizeX = 0, mMaxResultImageSizeY = 0;
+ private int mMinResultImageSizeX = 0, mMinResultImageSizeY = 0, mMaxResultImageSizeX = 0, mMaxResultImageSizeY = 0;
private long mImageToWrapCropBoundsAnimDuration = DEFAULT_IMAGE_TO_CROP_BOUNDS_ANIM_DURATION;
public CropImageView(Context context) {
@@ -78,6 +78,7 @@ public void cropAndSaveImage(@NonNull Bitmap.CompressFormat compressFormat, int
getCurrentScale(), getCurrentAngle());
final CropParameters cropParameters = new CropParameters(
+ mMinResultImageSizeX, mMinResultImageSizeY,
mMaxResultImageSizeX, mMaxResultImageSizeY,
compressFormat, compressQuality,
getImageInputPath(), getImageOutputPath(), getExifInfo());
@@ -154,8 +155,29 @@ public void setCropBoundsChangeListener(@Nullable CropBoundsChangeListener cropB
mCropBoundsChangeListener = cropBoundsChangeListener;
}
+ /**
+ * This method sets minimum width for resulting cropped image
+ * The priority of this method is less than the {@link #setMaxResultImageSizeX(int) setMaxResultImageSizeX} method.
+ *
+ * @param minResultImageSizeX - size in pixels
+ */
+ public void setMinResultImageSizeX(@IntRange(from = 10) int minResultImageSizeX) {
+ mMinResultImageSizeX = minResultImageSizeX;
+ }
+
+ /**
+ * This method sets minimum width for resulting cropped image
+ * The priority of this method is less than the {@link #setMaxResultImageSizeY(int) setMaxResultImageSizeY} method.
+ *
+ * @param minResultImageSizeY - size in pixels
+ */
+ public void setMinResultImageSizeY(@IntRange(from = 10) int minResultImageSizeY) {
+ mMinResultImageSizeY = minResultImageSizeY;
+ }
+
/**
* This method sets maximum width for resulting cropped image
+ * The priority of this method is higher than the {@link #setMinResultImageSizeX(int) setMinResultImageSizeX} method.
*
* @param maxResultImageSizeX - size in pixels
*/
@@ -165,6 +187,7 @@ public void setMaxResultImageSizeX(@IntRange(from = 10) int maxResultImageSizeX)
/**
* This method sets maximum width for resulting cropped image
+ * The priority of this method is higher than the {@link #setMinResultImageSizeY(int) setMinResultImageSizeY} method.
*
* @param maxResultImageSizeY - size in pixels
*/