Comments (6)
@skined90 Thanks for reporting the issue. Is this happening for a particular image (dimension)? What's the min and max zoom that you have set?
from croppernocropper.
@jayrambhia It happens for all dimensions where height is greater than width (vertical images). I did not set a min/max zoom. This is the config in xml:
app:nocropper__fit_to_center="true"
app:nocropper__grid_opacity="0.8"
app:nocropper__grid_thickness="0.8dp"
app:nocropper__add_padding_to_make_square="false"
app:nocropper__grid_color="@color/colorThird"
from croppernocropper.
me too.
from croppernocropper.
Same is happening for me too and the app is crashing with following log,
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:309)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.IllegalArgumentException: x must be >= 0
at android.graphics.Bitmap.checkXYSign(Bitmap.java:363)
at android.graphics.Bitmap.createBitmap(Bitmap.java:683)
at com.fenchtose.nocropper.CropperImageView.getCroppedBitmap(CropperImageView.java:812)
at com.fenchtose.nocropper.CropperImageView.cropBitmap(CropperImageView.java:679)
at com.fenchtose.nocropper.CropperTask.doInBackground(CropperTask.java:24)
at com.fenchtose.nocropper.CropperTask.doInBackground(CropperTask.java:6)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Its an Illegal argument exception. Will be really helpful if it is fixed.
from croppernocropper.
Hello same issues I'm facing too, please fix both the issues ,
- left alignment of image when it's partially zoom (vertical) image
- top alignment of image when it's partially zoom(horizontal)
- crash when partially zoom
found the solution of above issues
include module and replace existing CropperImageView class code to this
public class CropperImageView extends ImageView {
private static final String TAG = "CropperImageView";
private float[] mMatrixValues = new float[9];
protected GestureDetector mGestureDetector;
protected ScaleGestureDetector mScaleDetector;
private float mMinZoom;
private float mMaxZoom;
private float mBaseZoom;
private float mFocusX;
private float mFocusY;
private boolean isMaxZoomSet = false;
private boolean mFirstRender = true;
private Bitmap mBitmap;
private boolean doPreScaling = false;
private float mPreScale;
private boolean mAddPaddingToMakeSquare = true;
private GestureCallback mGestureCallback;
private boolean showAnimation = true;
private boolean isAdjusting = false;
private boolean isCropping = false;
private int mPaintColor = Color.WHITE;
public boolean DEBUG = false;
private boolean gestureEnabled = true;
private boolean initWithFitToCenter = false;
public CropperImageView(Context context) {
super(context);
init(context, null);
}
public CropperImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public CropperImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CropperImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
public void setDEBUG(boolean DEBUG) {
this.DEBUG = DEBUG;
}
private void init(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.nocropper__CropperView);
if (mTypedArray != null) {
mPaintColor = mTypedArray.getColor(R.styleable.nocropper__CropperView_nocropper__padding_color, mPaintColor);
mAddPaddingToMakeSquare = mTypedArray.getBoolean(R.styleable.nocropper__CropperView_nocropper__add_padding_to_make_square, true);
mTypedArray.recycle();
}
}
GestureListener mGestureListener = new GestureListener();
mGestureDetector = new GestureDetector(context, mGestureListener, null, true);
ScaleListener mScaleListener = new ScaleListener();
mScaleDetector = new ScaleGestureDetector(context, mScaleListener);
setScaleType(ScaleType.MATRIX);
}
public boolean isInitWithFitToCenter() {
return initWithFitToCenter;
}
public void setInitWithFitToCenter(boolean initWithFitToCenter) {
this.initWithFitToCenter = initWithFitToCenter;
}
// Make Square
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int orientation = getContext().getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_PORTRAIT ||
orientation == Configuration.ORIENTATION_UNDEFINED) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
setMeasuredDimension(width, height);
} else {
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
setMeasuredDimension(width, height);
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (DEBUG) {
Log.i(TAG, "onLayout: " + changed + " [" + left + ", " + top + ", " + right + ", " + bottom + "]");
}
if (changed || mFirstRender) {
if (mFirstRender) {
final Drawable drawable = getDrawable();
if (drawable == null) {
if (DEBUG) {
Log.e(TAG, "drawable is null");
}
return;
}
mMinZoom = (float) (bottom - top) / Math.max(drawable.getIntrinsicHeight(),
drawable.getIntrinsicWidth());
mBaseZoom = (float) (bottom - top) / Math.min(drawable.getIntrinsicHeight(),
drawable.getIntrinsicWidth());
if (initWithFitToCenter) {
fitToCenter(drawable, bottom - top);
} else {
cropToCenter(drawable, bottom - top);
}
mFirstRender = false;
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isAdjusting) {
return true;
}
if (isCropping) {
Log.e(TAG, "Cropping current bitmap. Can't perform this action right now.");
return true;
}
final int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
if (mGestureCallback != null) {
mGestureCallback.onGestureStarted();
}
}
mScaleDetector.onTouchEvent(event);
if (!mScaleDetector.isInProgress()) {
mGestureDetector.onTouchEvent(event);
}
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
if (mGestureCallback != null) {
mGestureCallback.onGestureCompleted();
}
return onUp();
}
return true;
}
@Override
public void setImageBitmap(Bitmap bm) {
if (isCropping) {
Log.e(TAG, "Cropping current bitmap. Can't set bitmap now");
return;
}
mFirstRender = true;
if (bm == null) {
mBitmap = null;
super.setImageBitmap(null);
return;
}
if (bm.getHeight() > 1280 || bm.getWidth() > 1280) {
Log.w(TAG, "Bitmap size greater than 1280. This might cause memory issues");
}
mBitmap = bm;
if (doPreScaling) {
int max_param = Math.max(bm.getWidth(), bm.getHeight());
mPreScale = (float) max_param / (float) getWidth();
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bm, (int) (bm.getWidth() / mPreScale),
(int) (bm.getHeight() / mPreScale), false);
super.setImageBitmap(scaledBitmap);
} else {
mPreScale = 1f;
super.setImageBitmap(bm);
}
requestLayout();
}
public void replaceBitmap(Bitmap bitmap) {
if (bitmap == null) {
throw new NullPointerException("Can not replace with null bitmap");
}
if (mBitmap == null) {
setImageBitmap(bitmap);
return;
}
if (mBitmap.getWidth() != bitmap.getWidth() || mBitmap.getHeight() != bitmap.getHeight()) {
Log.e(TAG, "Bitmap is of different size. Not replacing");
return;
}
super.setImageBitmap(bitmap);
mBitmap = bitmap;
}
private void cropToCenter(Drawable drawable, int frameDimen) {
if (drawable == null) {
if (DEBUG) {
Log.e(TAG, "Drawable is null. I can't fit anything");
}
return;
}
if (frameDimen == 0) {
if (DEBUG) {
Log.e(TAG, "Frame Dimension is 0. I'm quite boggled by it.");
}
return;
}
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
if (DEBUG) {
Log.i(TAG, "drawable size: (" + width + " ," + height + ")");
}
int min_dimen = Math.min(width, height);
float scaleFactor = (float) min_dimen / (float) frameDimen;
Matrix matrix = new Matrix();
matrix.setScale(1f / scaleFactor, 1f / scaleFactor);
matrix.postTranslate((frameDimen - width / scaleFactor) / 2,
(frameDimen - height / scaleFactor) / 2);
setImageMatrix(matrix);
}
private void fitToCenter(Drawable drawable, int frameDimen) {
if (drawable == null) {
if (DEBUG) {
Log.e(TAG, "Drawable is null. I can't fit anything");
}
return;
}
if (frameDimen == 0) {
if (DEBUG) {
Log.e(TAG, "Frame Dimension is 0. I'm quite boggled by it.");
}
return;
}
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
if (DEBUG) {
Log.i(TAG, "drawable size: (" + width + " ," + height + ")");
}
int min_dimen = Math.max(width, height);
float scaleFactor = (float) min_dimen / (float) frameDimen;
Matrix matrix = new Matrix();
matrix.setScale(1f / scaleFactor, 1f / scaleFactor);
matrix.postTranslate((frameDimen - width / scaleFactor) / 2,
(frameDimen - height / scaleFactor) / 2);
setImageMatrix(matrix);
// If over scrolled, return back to the place.
float tx = getMatrixValue(matrix, Matrix.MTRANS_X);
float ty = getMatrixValue(matrix, Matrix.MTRANS_Y);
float scaleX = getMatrixValue(matrix, Matrix.MSCALE_X);
if (scaleX < mMinZoom) {
float xx = getWidth() / 2 - mMinZoom * drawable.getIntrinsicWidth() / 2;
float yy = getHeight() / 2 - mMinZoom * drawable.getIntrinsicHeight() / 2;
animateAdjustmentWithScale(tx, xx, ty, yy, scaleX, mMinZoom);
}
}
public boolean onScroll(float distanceX, float distanceY) {
Matrix matrix = getImageMatrix();
matrix.postTranslate(-distanceX, -distanceY);
setImageMatrix(matrix);
invalidate();
return true;
}
private boolean onUp() {
Drawable drawable = getDrawable();
if (drawable == null) {
return false;
}
// If over scrolled, return back to the place.
Matrix matrix = getImageMatrix();
float tx = getMatrixValue(matrix, Matrix.MTRANS_X);
float ty = getMatrixValue(matrix, Matrix.MTRANS_Y);
float scaleX = getMatrixValue(matrix, Matrix.MSCALE_X);
float scaleY = getMatrixValue(matrix, Matrix.MSCALE_Y);
if (DEBUG) {
Log.i(TAG, "onUp: " + tx + " " + ty);
Log.i(TAG, "scale: " + scaleX);
Log.i(TAG, "min, max, base zoom: " + mMinZoom + ", " + mMaxZoom + ", " + mBaseZoom);
Log.i(TAG, "imageview size: " + getWidth() + " " + getHeight());
Log.i(TAG, "drawable size: " + drawable.getIntrinsicWidth() + " " + drawable.getIntrinsicHeight());
Log.i(TAG, "scaled drawable size: " + scaleX * drawable.getIntrinsicWidth() + " " + scaleY * drawable.getIntrinsicHeight());
}
if (scaleX < mMinZoom) {
if (DEBUG) {
Log.i(TAG, "set scale: " + mMinZoom);
}
float xx = getWidth() / 2 - mMinZoom * drawable.getIntrinsicWidth() / 2;
float yy = getHeight() / 2 - mMinZoom * drawable.getIntrinsicHeight() / 2;
if (showAnimation()) {
animateAdjustmentWithScale(tx, xx, ty, yy, scaleX, mMinZoom);
} else {
matrix.reset();
matrix.setScale(mMinZoom, mMinZoom);
matrix.postTranslate(xx, yy);
setImageMatrix(matrix);
invalidate();
if (DEBUG) {
Log.i(TAG, "scale after invalidate: " + getScale(matrix));
}
}
return true;
} else if (scaleX < mBaseZoom) {
// align to center for the smaller dimension
int h = drawable.getIntrinsicHeight();
int w = drawable.getIntrinsicWidth();
float xTranslate;
float yTranslate;
if (h <= w) {
yTranslate = getHeight() / 2 - scaleX * h / 2;
if (tx >= 0) {
xTranslate = 0;
} else {
float xDiff = getWidth() - (scaleX) * drawable.getIntrinsicWidth();
if (tx < xDiff) {
xTranslate = xDiff;
} else {
xTranslate = tx;
}
}
} else {
xTranslate = getWidth() / 2 - scaleX * w / 2;
if (ty >= 0) {
yTranslate = 0;
} else {
float yDiff = getHeight() - (scaleY) * drawable.getIntrinsicHeight();
if (ty < yDiff) {
yTranslate = yDiff;
} else {
yTranslate = ty;
}
}
}
if (showAnimation()) {
matrix.reset();
matrix.postScale(scaleX, scaleX);
matrix.postTranslate(tx, ty);
setImageMatrix(matrix);
animateAdjustment(xTranslate - tx, yTranslate - ty);
} else {
matrix.reset();
matrix.postScale(scaleX, scaleX);
matrix.postTranslate(xTranslate, yTranslate);
setImageMatrix(matrix);
invalidate();
}
return true;
} else if (isMaxZoomSet && scaleX > mMaxZoom) {
if (DEBUG) {
Log.i(TAG, "set to max zoom");
Log.i(TAG, "isMaxZoomSet: " + isMaxZoomSet);
}
if (showAnimation()) {
animateOverMaxZoomAdjustment();
// adjustToSides();
} else {
matrix.postScale(mMaxZoom / scaleX, mMaxZoom / scaleX, mFocusX, mFocusY);
setImageMatrix(matrix);
invalidate();
adjustToSides();
}
return true;
}
if (DEBUG) {
Log.i(TAG, "adjust to sides");
}
adjustToSides();
return true;
}
private boolean adjustToSides() {
boolean changeRequired = false;
Drawable drawable = getDrawable();
if (drawable == null) {
return false;
}
Matrix matrix = getImageMatrix();
float tx = getMatrixValue(matrix, Matrix.MTRANS_X);
float ty = getMatrixValue(matrix, Matrix.MTRANS_Y);
float scaleX = getMatrixValue(matrix, Matrix.MSCALE_X);
float scaleY = getMatrixValue(matrix, Matrix.MSCALE_Y);
if (tx > 0) {
tx = -tx;
changeRequired = true;
} else {
// check if scrolled to left
float xDiff = getWidth() - (scaleX) * drawable.getIntrinsicWidth();
if (tx < xDiff) {
tx = xDiff - tx;
changeRequired = true;
} else {
tx = 0;
}
}
if (ty > 0) {
ty = -ty;
changeRequired = true;
} else {
// check if scrolled to top
float yDiff = getHeight() - (scaleY) * drawable.getIntrinsicHeight();
if (ty < yDiff) {
ty = yDiff - ty;
changeRequired = true;
} else {
ty = 0;
}
}
if (changeRequired) {
if (showAnimation()) {
animateAdjustment(tx, ty);
} else {
matrix.postTranslate(tx, ty);
setImageMatrix(matrix);
invalidate();
}
}
return changeRequired;
}
private float getMatrixValue(Matrix matrix, int whichValue) {
matrix.getValues(mMatrixValues);
return mMatrixValues[whichValue];
}
private float getScale(Matrix matrix) {
return getMatrixValue(matrix, Matrix.MSCALE_X);
}
public boolean isDoPreScaling() {
return doPreScaling;
}
public void setDoPreScaling(boolean doPreScaling) {
this.doPreScaling = doPreScaling;
}
public float getMaxZoom() {
return mMaxZoom;
}
public void setMaxZoom(float mMaxZoom) {
if (mMaxZoom <= 0) {
Log.e(TAG, "Max zoom must be greater than 0");
return;
}
this.mMaxZoom = mMaxZoom;
isMaxZoomSet = true;
}
public float getMinZoom() {
return mMinZoom;
}
public void setMinZoom(float mMInZoom) {
if (mMInZoom <= 0) {
Log.e(TAG, "Min zoom must be greater than 0");
return;
}
this.mMinZoom = mMInZoom;
}
public void cropToCenter() {
if (isCropping) {
Log.e(TAG, "Cropping current bitmap. Can't perform this action right now.");
return;
}
Drawable drawable = getDrawable();
if (drawable != null) {
cropToCenter(drawable, getWidth());
}
}
public void fitToCenter() {
if (isCropping) {
Log.e(TAG, "Cropping current bitmap. Can't perform this action right now.");
return;
}
Drawable drawable = getDrawable();
if (drawable != null) {
fitToCenter(drawable, getWidth());
}
}
public Bitmap cropBitmap() throws OutOfMemoryError {
if (isCropping) {
Log.e(TAG, "Cropping current bitmap. Can't perform this action right now.");
return null;
}
isCropping = true;
try {
Bitmap bitmap = getCroppedBitmap();
isCropping = false;
return bitmap;
} catch (OutOfMemoryError e) {
isCropping = false;
throw e;
}
}
private Bitmap getCroppedBitmap() throws OutOfMemoryError {
if (mBitmap == null) {
Log.e(TAG, "original image is not available");
return null;
}
Matrix matrix = getImageMatrix();
if (doPreScaling) {
matrix.postScale(1 / mPreScale, 1 / mPreScale);
}
float xTrans = getMatrixValue(matrix, Matrix.MTRANS_X);
float yTrans = getMatrixValue(matrix, Matrix.MTRANS_Y);
float scale = getMatrixValue(matrix, Matrix.MSCALE_X);
if (DEBUG) {
Log.i(TAG, "xTrans: " + xTrans + ", yTrans: " + yTrans + " , scale: " + scale);
}
// Load bitmap which is mutable
Bitmap bitmap = null;
if (DEBUG) {
Log.i(TAG, "old bitmap: " + mBitmap.getWidth() + " " + mBitmap.getHeight());
}
if (xTrans > 0 && yTrans > 0 && scale <= mMinZoom) {
// No scale/crop required.
// Add padding if not square
if (mAddPaddingToMakeSquare) {
try {
return BitmapUtils.addPadding(mBitmap, mPaintColor);
} catch (OutOfMemoryError e) {
Log.d(TAG, "OOM while adding padding");
throw e;
}
} else {
return mBitmap;
}
} else {
float cropY = -yTrans / scale;
float Y = getHeight() / scale;
float cropX = -xTrans / scale;
float X = getWidth() / scale;
if (DEBUG) {
Log.i(TAG, "cropY: " + cropY);
Log.i(TAG, "Y: " + Y);
Log.i(TAG, "cropX: " + cropX);
Log.i(TAG, "X: " + X);
}
if (cropY + Y > mBitmap.getHeight()) {
cropY = mBitmap.getHeight() - Y;
if (DEBUG) {
Log.i(TAG, "readjust cropY to: " + cropY);
}
} else if (cropY < 0) {
cropY = 0;
if (DEBUG) {
Log.i(TAG, "readjust cropY to: " + cropY);
}
}
if (cropX + X > mBitmap.getWidth()) {
cropX = mBitmap.getWidth() - X;
if (DEBUG) {
Log.i(TAG, "readjust cropX to: " + cropX);
}
} else if (cropX < 0) {
cropX = 0;
if (DEBUG) {
Log.i(TAG, "readjust cropX to: " + cropX);
}
}
if (mBitmap.getHeight() > mBitmap.getWidth()) {
// Height is greater than width.
if (xTrans >= 0) {
// Image is zoomed. Crop from height
Rect src = new Rect(0, (int) cropY, mBitmap.getWidth(), (int) (Y + cropY));
if (mAddPaddingToMakeSquare) {
// Crop and add padding to the same bitmap
try {
int size = (int) Y;
bitmap = Bitmap.createBitmap(size, size, mBitmap.getConfig());
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(mPaintColor);
// Put cropped bitmap into the canvas
int left = (size - mBitmap.getWidth()) / 2;
Rect dest = new Rect(left, 0, left + mBitmap.getWidth(), size);
canvas.drawBitmap(mBitmap, src, dest, null);
} catch (OutOfMemoryError e) {
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
bitmap = null;
throw e;
}
}
} else {
try {
bitmap = Bitmap.createBitmap(mBitmap, 0, (int) cropY, mBitmap.getWidth(), (int) Y,
null, true);
} catch (OutOfMemoryError e) {
bitmap = null;
throw e;
}
}
} else {
// Crop from width and height both
try {
bitmap = Bitmap.createBitmap(mBitmap, (int) cropX, (int) cropY, (int) X, (int) Y,
null, true);
} catch (OutOfMemoryError e) {
bitmap = null;
throw e;
}
}
} else {
if (yTrans >= 0) {
// Image is zoomed. Crop from width and add padding to make square
Rect src = new Rect((int) cropX, 0, (int) (cropX + X), mBitmap.getHeight());
if (mAddPaddingToMakeSquare) {
try {
// Crop and add padding to the same bitmap
int size = (int) X;
bitmap = Bitmap.createBitmap(size, size, mBitmap.getConfig());
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(mPaintColor);
// Put cropped bitmap into the canvas
int top = (size - mBitmap.getHeight()) / 2;
Rect dest = new Rect(0, top, size, top + mBitmap.getHeight());
canvas.drawBitmap(mBitmap, src, dest, null);
} catch (OutOfMemoryError e) {
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
bitmap = null;
throw e;
}
}
} else {
try {
bitmap = Bitmap.createBitmap(mBitmap, (int) cropX, 0, (int) X, mBitmap.getHeight(),
null, true);
} catch (OutOfMemoryError e) {
bitmap = null;
throw e;
}
}
} else {
// Crop from width and height both.
try {
bitmap = Bitmap.createBitmap(mBitmap, (int) cropX, (int) cropY, (int) X, (int) Y,
null, true);
} catch (OutOfMemoryError e) {
bitmap = null;
throw e;
}
}
if (DEBUG) {
Log.i(TAG, "width should be: " + mBitmap.getWidth());
if (bitmap != null) {
Log.i(TAG, "crop bitmap: " + bitmap.getWidth() + " " + bitmap.getHeight());
}
}
}
}
return bitmap;
}
public boolean showAnimation() {
return showAnimation;
}
public void setShowAnimation(boolean showAnimation) {
this.showAnimation = showAnimation;
}
public int getPaddingColor() {
return mPaintColor;
}
public void setPaddingColor(int mPaintColor) {
this.mPaintColor = mPaintColor;
}
public boolean isMakeSquare() {
return mAddPaddingToMakeSquare;
}
public void setMakeSquare(boolean mAddPaddingToMakeSquare) {
this.mAddPaddingToMakeSquare = mAddPaddingToMakeSquare;
}
public boolean isGestureEnabled() {
return gestureEnabled;
}
public void setGestureEnabled(boolean gestureEnabled) {
this.gestureEnabled = gestureEnabled;
}
public void release() {
if (isCropping) {
Log.e(TAG, "Cropping current bitmap. Can't perform this action right now.");
return;
}
setImageBitmap(null);
if (mBitmap != null) {
mBitmap.recycle();
}
}
// Scroll and Gesture Listeners
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (!gestureEnabled) {
return false;
}
if (isCropping) {
Log.e(TAG, "Cropping current bitmap. Can't perform this action right now.");
return false;
}
if (e1 == null || e2 == null) {
return false;
}
if (e1.getPointerCount() > 1 || e2.getPointerCount() > 1) {
return false;
}
CropperImageView.this.onScroll(distanceX, distanceY);
return false;
}
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
protected boolean mScaled = false;
@Override
public boolean onScale(ScaleGestureDetector detector) {
if (!gestureEnabled) {
return false;
}
if (isCropping) {
Log.e(TAG, "Cropping current bitmap. Can't perform this action right now.");
return false;
}
Matrix matrix = getImageMatrix();
// This does the trick!
mFocusX = detector.getFocusX();
mFocusY = detector.getFocusY();
matrix.postScale(detector.getScaleFactor(), detector.getScaleFactor(),
detector.getFocusX(), detector.getFocusY());
setImageMatrix(matrix);
invalidate();
return true;
}
}
public void setGestureCallback(GestureCallback mGestureCallback) {
this.mGestureCallback = mGestureCallback;
}
public interface GestureCallback {
void onGestureStarted();
void onGestureCompleted();
}
private void animateAdjustmentWithScale(final float xStart, final float xEnd,
final float yStart, final float yEnd,
final float scaleStart, final float scaleEnd) {
ValueAnimator animator = ValueAnimator.ofInt(0, 20);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Matrix matrix = getImageMatrix();
matrix.reset();
Integer value = (Integer) animation.getAnimatedValue();
matrix.postScale((scaleEnd - scaleStart) * value / 20f + scaleStart,
(scaleEnd - scaleStart) * value / 20f + scaleStart);
matrix.postTranslate((xEnd - xStart) * value / 20f + xStart,
(yEnd - yStart) * value / 20f + yStart);
setImageMatrix(matrix);
invalidate();
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
isAdjusting = true;
}
@Override
public void onAnimationEnd(Animator animation) {
isAdjusting = false;
}
@Override
public void onAnimationCancel(Animator animation) {
isAdjusting = false;
}
@Override
public void onAnimationRepeat(Animator animation) {
isAdjusting = true;
}
});
animator.start();
}
private void animateAdjustment(final float xDiff, final float yDiff) {
ValueAnimator animator = ValueAnimator.ofInt(0, 20);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Matrix matrix = getImageMatrix();
matrix.postTranslate(xDiff / 20, yDiff / 20);
setImageMatrix(matrix);
invalidate();
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
isAdjusting = true;
}
@Override
public void onAnimationEnd(Animator animation) {
isAdjusting = false;
}
@Override
public void onAnimationCancel(Animator animation) {
isAdjusting = false;
}
@Override
public void onAnimationRepeat(Animator animation) {
isAdjusting = true;
}
});
animator.start();
}
private void animateOverMaxZoomAdjustment() {
Matrix matrix = getImageMatrix();
final float scale = getScale(matrix);
final ValueAnimator animator = ValueAnimator.ofInt(0, 20);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Matrix matrix = getImageMatrix();
float currentScale = getScale(matrix);
if (currentScale <= mMaxZoom) {
// animator.cancel();
return;
}
double expScale = Math.pow(mMaxZoom / scale, 1 / 20f);
matrix.postScale((float) expScale, (float) expScale, mFocusX, mFocusY);
setImageMatrix(matrix);
invalidate();
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
isAdjusting = true;
}
@Override
public void onAnimationEnd(Animator animation) {
isAdjusting = false;
adjustToSides();
}
@Override
public void onAnimationCancel(Animator animation) {
isAdjusting = false;
}
@Override
public void onAnimationRepeat(Animator animation) {
isAdjusting = true;
}
});
animator.start();
}
}
from croppernocropper.
Fixed in 0.2.1
from croppernocropper.
Related Issues (20)
- Is there anyway to find out the max zoom for my photos? e.g I want my higher dimension images that can only be zoomed till 1024px X 1024px dimensions HOT 1
- Force not less than width or height HOT 2
- CropperView on ViewPager Swipe problem HOT 3
- minimum zoom related to Image width and height. HOT 1
- getCroppedBitmap returns BitmapResult and not a Bitmap HOT 1
- Cropped Bitmap also take black portion which is not part of Image . HOT 2
- Zoom not working inside Scrollview/Nested Scrollveiw
- save translations done on the image and restore back HOT 6
- Can Load Video in CropActivity
- How to Save Crop State
- Image Rotate issue on Some devices HOT 1
- How to set this cropper view with vertical rectangular layout?
- Can't pinch smoothly if image size is large. (Performance) HOT 2
- question HOT 1
- Cropping current bitmap. Can't perform this action right now help please
- No grid when moving HOT 1
- Applying cropping to the Rotated image was not working
- y+height must be <= bitmap.getHeight(); HOT 1
- we can crop image out of image size with transparency background? Help us please
- cropper.crop() cropping incorrectly
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from croppernocropper.