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 3f8f919b0..c4446326f 100644 --- a/sample/src/main/java/com/yalantis/ucrop/sample/SampleActivity.java +++ b/sample/src/main/java/com/yalantis/ucrop/sample/SampleActivity.java @@ -366,6 +366,7 @@ Tune everything (ノ◕ヮ◕)ノ*:・゚✧ options.setCropGridColor(Color.GREEN); options.setCropGridColumnCount(2); options.setCropGridRowCount(1); + options.setCropViewRectInImageSpace(new RectF(100, 100, 500, 500)); options.setToolbarCropDrawable(R.drawable.your_crop_icon); options.setToolbarCancelDrawable(R.drawable.your_cancel_icon); diff --git a/ucrop/src/main/java/com/yalantis/ucrop/UCrop.java b/ucrop/src/main/java/com/yalantis/ucrop/UCrop.java index 357ace2d9..cd94612e9 100644 --- a/ucrop/src/main/java/com/yalantis/ucrop/UCrop.java +++ b/ucrop/src/main/java/com/yalantis/ucrop/UCrop.java @@ -6,6 +6,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; +import android.graphics.RectF; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -280,6 +281,7 @@ public static class Options { public static final String EXTRA_CROP_GRID_COLUMN_COUNT = EXTRA_PREFIX + ".CropGridColumnCount"; public static final String EXTRA_CROP_GRID_COLOR = EXTRA_PREFIX + ".CropGridColor"; public static final String EXTRA_CROP_GRID_STROKE_WIDTH = EXTRA_PREFIX + ".CropGridStrokeWidth"; + public static final String EXTRA_CROP_VIEW_RECT_IN_IMAGE_SPACE = EXTRA_PREFIX + ".CropViewRectInImageSpace"; public static final String EXTRA_TOOL_BAR_COLOR = EXTRA_PREFIX + ".ToolbarColor"; public static final String EXTRA_STATUS_BAR_COLOR = EXTRA_PREFIX + ".StatusBarColor"; @@ -433,6 +435,29 @@ public void setCropGridStrokeWidth(@IntRange(from = 0) int width) { mOptionBundle.putInt(EXTRA_CROP_GRID_STROKE_WIDTH, width); } + /** + *

This method will accept a RectF with coordinates from the image space.


+ * + *

Example: Useful if you want want to process the image and detect objects within before + * opening uCrop in order to highlight desired cropping area, like for example document + * detection and you want to display the cropping Rect over the detected document when + * uCrop starts.


+ * + *

Passing your desired RectF will result in the + * {@link com.yalantis.ucrop.view.OverlayView}'s highlighting the desired area. + * This rect will be automatically converted to a RectF that corresponds with the image's + * coordinates inside the view.


+ * + *

This must be used in combination with {@link #setMaxBitmapSize} to set a greater bitmap + * size, otherwise bigger images will be downscaled and coordinates of objects detected + * in input image space won't match with the new downscaled image ones.


+ * + * @param rect - desired crop view rect in image space. + */ + public void setCropViewRectInImageSpace(@NonNull RectF rect) { + mOptionBundle.putParcelable(EXTRA_CROP_VIEW_RECT_IN_IMAGE_SPACE, rect); + } + /** * @param color - desired resolved color of the toolbar */ diff --git a/ucrop/src/main/java/com/yalantis/ucrop/UCropActivity.java b/ucrop/src/main/java/com/yalantis/ucrop/UCropActivity.java index a48969fcc..66136c112 100644 --- a/ucrop/src/main/java/com/yalantis/ucrop/UCropActivity.java +++ b/ucrop/src/main/java/com/yalantis/ucrop/UCropActivity.java @@ -4,6 +4,7 @@ import android.content.Intent; import android.graphics.Bitmap; import android.graphics.PorterDuff; +import android.graphics.RectF; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -27,6 +28,7 @@ import com.yalantis.ucrop.callback.BitmapCropCallback; import com.yalantis.ucrop.model.AspectRatio; +import com.yalantis.ucrop.util.RectUtils; import com.yalantis.ucrop.util.SelectedStateListDrawable; import com.yalantis.ucrop.view.CropImageView; import com.yalantis.ucrop.view.GestureCropImageView; @@ -380,6 +382,17 @@ public void onScale(float currentScale) { @Override public void onLoadComplete() { mUCropView.animate().alpha(1).setDuration(300).setInterpolator(new AccelerateInterpolator()); + if (getIntent().hasExtra(UCrop.Options.EXTRA_CROP_VIEW_RECT_IN_IMAGE_SPACE)) { + RectF rectInImageSpace = getIntent().getParcelableExtra(UCrop.Options.EXTRA_CROP_VIEW_RECT_IN_IMAGE_SPACE); + + int viewWidth = mGestureCropImageView.getWidth(); + int viewHeight = mGestureCropImageView.getHeight(); + + Drawable drawable = mGestureCropImageView.getDrawable(); + + RectF cropViewRect = RectUtils.convertImageSpaceRectToCropViewRect(rectInImageSpace, viewWidth, viewHeight, drawable); + mOverlayView.setCropViewRect(cropViewRect); + } mBlockingView.setClickable(false); mShowLoader = false; supportInvalidateOptionsMenu(); diff --git a/ucrop/src/main/java/com/yalantis/ucrop/UCropFragment.java b/ucrop/src/main/java/com/yalantis/ucrop/UCropFragment.java index 9d33f8089..89f5a2e51 100644 --- a/ucrop/src/main/java/com/yalantis/ucrop/UCropFragment.java +++ b/ucrop/src/main/java/com/yalantis/ucrop/UCropFragment.java @@ -4,6 +4,8 @@ import android.content.Intent; import android.graphics.Bitmap; import android.graphics.PorterDuff; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; @@ -19,6 +21,7 @@ import com.yalantis.ucrop.callback.BitmapCropCallback; import com.yalantis.ucrop.model.AspectRatio; +import com.yalantis.ucrop.util.RectUtils; import com.yalantis.ucrop.util.SelectedStateListDrawable; import com.yalantis.ucrop.view.CropImageView; import com.yalantis.ucrop.view.GestureCropImageView; @@ -284,6 +287,17 @@ public void onScale(float currentScale) { @Override public void onLoadComplete() { mUCropView.animate().alpha(1).setDuration(300).setInterpolator(new AccelerateInterpolator()); + if (getArguments().containsKey(UCrop.Options.EXTRA_CROP_VIEW_RECT_IN_IMAGE_SPACE)) { + RectF rectInImageSpace = getArguments().getParcelable(UCrop.Options.EXTRA_CROP_VIEW_RECT_IN_IMAGE_SPACE); + + int viewWidth = mGestureCropImageView.getWidth(); + int viewHeight = mGestureCropImageView.getHeight(); + + Drawable drawable = mGestureCropImageView.getDrawable(); + + RectF cropViewRect = RectUtils.convertImageSpaceRectToCropViewRect(rectInImageSpace, viewWidth, viewHeight, drawable); + mOverlayView.setCropViewRect(cropViewRect); + } mBlockingView.setClickable(false); callback.loadingProgress(false); } diff --git a/ucrop/src/main/java/com/yalantis/ucrop/util/RectUtils.java b/ucrop/src/main/java/com/yalantis/ucrop/util/RectUtils.java index 050e8dd2a..a84c2b300 100644 --- a/ucrop/src/main/java/com/yalantis/ucrop/util/RectUtils.java +++ b/ucrop/src/main/java/com/yalantis/ucrop/util/RectUtils.java @@ -1,6 +1,7 @@ package com.yalantis.ucrop.util; import android.graphics.RectF; +import android.graphics.drawable.Drawable; public class RectUtils { @@ -69,4 +70,32 @@ public static RectF trapToRect(float[] array) { return r; } + /** + * Takes an rect in image space (received rect can only be in image space, since you can't + * know the view's width and height from the outside). So in case you want to process the image + * outside uCrop, you will only have coordinates in image space and not in uCrop's view space. + * Those need to be converted. + * + * @param rectInImageSpace RectF in image space + * @param viewWidth The view's width + * @param viewHeight The view's height + * @param drawable The drawable object to retrieve drawable width and height + * + * @return A new RectF object representing how the RectF should be drawn on screen. + */ + public static RectF convertImageSpaceRectToCropViewRect(RectF rectInImageSpace, int viewWidth, int viewHeight, Drawable drawable) { + int drawableWidth = drawable.getIntrinsicWidth(); + int drawableHeight = drawable.getIntrinsicHeight(); + + double widthAspectRatio = (double) viewWidth / drawableWidth; + double heightAspectRatio = (double) viewHeight / drawableHeight; + + return new RectF( + (float) (rectInImageSpace.left * widthAspectRatio), + (float) (rectInImageSpace.top * heightAspectRatio), + (float) (rectInImageSpace.right * widthAspectRatio), + (float) (rectInImageSpace.bottom * heightAspectRatio) + ); + } + } \ No newline at end of file diff --git a/ucrop/src/main/java/com/yalantis/ucrop/view/OverlayView.java b/ucrop/src/main/java/com/yalantis/ucrop/view/OverlayView.java index eb5397015..3ea5e9d80 100644 --- a/ucrop/src/main/java/com/yalantis/ucrop/view/OverlayView.java +++ b/ucrop/src/main/java/com/yalantis/ucrop/view/OverlayView.java @@ -105,6 +105,13 @@ public RectF getCropViewRect() { return mCropViewRect; } + /** + * Setter for mCropViewRect. Can be used to set an initial value for the mCropViewRect. + */ + public void setCropViewRect(RectF rect) { + mCropViewRect.set(rect); + } + @Deprecated /*** * Please use the new method {@link #getFreestyleCropMode() getFreestyleCropMode} method as we have more than 1 freestyle crop mode. @@ -233,16 +240,18 @@ public void setTargetAspectRatio(final float targetAspectRatio) { * {@link #mCropViewRect} is used to draw crop bounds - uses padding. */ public void setupCropBounds() { - int height = (int) (mThisWidth / mTargetAspectRatio); - if (height > mThisHeight) { - int width = (int) (mThisHeight * mTargetAspectRatio); - int halfDiff = (mThisWidth - width) / 2; - mCropViewRect.set(getPaddingLeft() + halfDiff, getPaddingTop(), - getPaddingLeft() + width + halfDiff, getPaddingTop() + mThisHeight); - } else { - int halfDiff = (mThisHeight - height) / 2; - mCropViewRect.set(getPaddingLeft(), getPaddingTop() + halfDiff, - getPaddingLeft() + mThisWidth, getPaddingTop() + height + halfDiff); + if (mCropViewRect.isEmpty()) { + int height = (int) (mThisWidth / mTargetAspectRatio); + if (height > mThisHeight) { + int width = (int) (mThisHeight * mTargetAspectRatio); + int halfDiff = (mThisWidth - width) / 2; + mCropViewRect.set(getPaddingLeft() + halfDiff, getPaddingTop(), + getPaddingLeft() + width + halfDiff, getPaddingTop() + mThisHeight); + } else { + int halfDiff = (mThisHeight - height) / 2; + mCropViewRect.set(getPaddingLeft(), getPaddingTop() + halfDiff, + getPaddingLeft() + mThisWidth, getPaddingTop() + height + halfDiff); + } } if (mCallback != null) {