From 203eb404a7cd6a80397535e63d22b3772939f03d Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Thu, 18 Jul 2013 16:37:30 -0700 Subject: Refactoring Geometry handling. Bug: 9170644 Bug: 9366654 Bug: 9366263 - Consolidates all the geometry transforms in GeometryMathUtils and significantly reduces complexity. - Removes GeometryMetadata object and dependent code. - Removes ImageGeometry and geometry update callbacks. Change-Id: I59add51907459593244c9ebaadef585efc7486d5 --- .../gallery3d/filtershow/imageshow/ImageCrop.java | 854 ++++++--------------- 1 file changed, 215 insertions(+), 639 deletions(-) (limited to 'src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java') diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java index 0c440654c..7fee03188 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,712 +20,288 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.LinearLayout; -import android.widget.PopupMenu; +import android.util.Log; +import android.view.MotionEvent; import com.android.gallery3d.R; -import com.android.gallery3d.filtershow.crop.BoundedRect; -import com.android.gallery3d.filtershow.crop.CropExtras; +import com.android.gallery3d.filtershow.crop.CropDrawingUtils; import com.android.gallery3d.filtershow.crop.CropMath; +import com.android.gallery3d.filtershow.crop.CropObject; import com.android.gallery3d.filtershow.editors.EditorCrop; -import com.android.gallery3d.filtershow.ui.FramedTextButton; - -public class ImageCrop extends ImageGeometry { - private static final boolean LOGV = false; - - // Sides - private static final int MOVE_LEFT = 1; - private static final int MOVE_TOP = 2; - private static final int MOVE_RIGHT = 4; - private static final int MOVE_BOTTOM = 8; - private static final int MOVE_BLOCK = 16; - - // Corners - private static final int TOP_LEFT = MOVE_TOP | MOVE_LEFT; - private static final int TOP_RIGHT = MOVE_TOP | MOVE_RIGHT; - private static final int BOTTOM_RIGHT = MOVE_BOTTOM | MOVE_RIGHT; - private static final int BOTTOM_LEFT = MOVE_BOTTOM | MOVE_LEFT; - - private static int mMinSideSize = 100; - private static int mTouchTolerance = 45; - - private boolean mFirstDraw = true; - private float mAspectWidth = 1; - private float mAspectHeight = 1; - private boolean mFixAspectRatio = false; - - private float mLastRot = 0; - - private BoundedRect mBounded = null; - private int movingEdges; - private final Drawable cropIndicator; - private final int indicatorSize; - private final int mBorderColor = Color.argb(128, 255, 255, 255); - - // Offset between crop center and photo center - private float[] mOffset = { - 0, 0 - }; - private CropExtras mCropExtras = null; - private boolean mDoingCropIntentAction = false; - - private static final String LOGTAG = "ImageCrop"; - - private String mAspect = ""; - private static int mAspectTextSize = 24; - - private boolean mFixedAspect = false; - - private EditorCrop mEditorCrop; - - public static void setAspectTextSize(int textSize) { - mAspectTextSize = textSize; - } - - public void setAspectString(String a) { - mAspect = a; - } - - private static final Paint gPaint = new Paint(); +import com.android.gallery3d.filtershow.filters.FilterCropRepresentation; +import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils.GeometryHolder; + +public class ImageCrop extends ImageShow { + private static final String TAG = ImageCrop.class.getSimpleName(); + private RectF mImageBounds = new RectF(); + private RectF mScreenCropBounds = new RectF(); + private Paint mPaint = new Paint(); + private CropObject mCropObj = null; + private GeometryHolder mGeometry = new GeometryHolder(); + private GeometryHolder mUpdateHolder = new GeometryHolder(); + private Drawable mCropIndicator; + private int mIndicatorSize; + private boolean mMovingBlock = false; + private Matrix mDisplayMatrix = null; + private Matrix mDisplayCropMatrix = null; + private Matrix mDisplayMatrixInverse = null; + private float mPrevX = 0; + private float mPrevY = 0; + private int mMinSideSize = 90; + private int mTouchTolerance = 40; + private enum Mode { + NONE, MOVE + } + private Mode mState = Mode.NONE; + private boolean mValidDraw = false; + FilterCropRepresentation mLocalRep = new FilterCropRepresentation(); + EditorCrop mEditorCrop; public ImageCrop(Context context) { super(context); - Resources resources = context.getResources(); - cropIndicator = resources.getDrawable(R.drawable.camera_crop); - indicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size); + setup(context); } public ImageCrop(Context context, AttributeSet attrs) { super(context, attrs); - Resources resources = context.getResources(); - cropIndicator = resources.getDrawable(R.drawable.camera_crop); - indicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size); + setup(context); } - private void swapAspect() { - if (mDoingCropIntentAction) { - return; - } - float temp = mAspectWidth; - mAspectWidth = mAspectHeight; - mAspectHeight = temp; + public ImageCrop(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setup(context); } - /** - * Set tolerance for crop marker selection (in pixels) - */ - public static void setTouchTolerance(int tolerance) { - mTouchTolerance = tolerance; + private void setup(Context context) { + Resources rsc = context.getResources(); + mCropIndicator = rsc.getDrawable(R.drawable.camera_crop); + mIndicatorSize = (int) rsc.getDimension(R.dimen.crop_indicator_size); + mMinSideSize = (int) rsc.getDimension(R.dimen.crop_min_side); + mTouchTolerance = (int) rsc.getDimension(R.dimen.crop_touch_tolerance); } - /** - * Set minimum side length for crop box (in pixels) - */ - public static void setMinCropSize(int minHeightWidth) { - mMinSideSize = minHeightWidth; + public void setFilterCropRepresentation(FilterCropRepresentation crop) { + mLocalRep = (crop == null) ? new FilterCropRepresentation() : crop; + GeometryMathUtils.initializeHolder(mUpdateHolder, mLocalRep); + mValidDraw = true; } - public void setExtras(CropExtras e) { - mCropExtras = e; + public FilterCropRepresentation getFinalRepresentation() { + return mLocalRep; } - public void setCropActionFlag(boolean f) { - mDoingCropIntentAction = f; + private void internallyUpdateLocalRep(RectF crop, RectF image) { + FilterCropRepresentation + .findNormalizedCrop(crop, (int) image.width(), (int) image.height()); + mGeometry.crop.set(crop); + mUpdateHolder.set(mGeometry); + mLocalRep.setCrop(crop); } - public void apply(float w, float h) { - mFixAspectRatio = true; - mAspectWidth = w; - mAspectHeight = h; - setLocalCropBounds(getUntranslatedStraightenCropBounds(getLocalPhotoBounds(), - getLocalStraighten())); - cropSetup(); - saveAndSetPreset(); + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + float y = event.getY(); + if (mDisplayMatrix == null || mDisplayMatrixInverse == null) { + return true; + } + float[] touchPoint = { + x, y + }; + mDisplayMatrixInverse.mapPoints(touchPoint); + x = touchPoint[0]; + y = touchPoint[1]; + switch (event.getActionMasked()) { + case (MotionEvent.ACTION_DOWN): + if (mState == Mode.NONE) { + if (!mCropObj.selectEdge(x, y)) { + mMovingBlock = mCropObj.selectEdge(CropObject.MOVE_BLOCK); + } + mPrevX = x; + mPrevY = y; + mState = Mode.MOVE; + } + break; + case (MotionEvent.ACTION_UP): + if (mState == Mode.MOVE) { + mCropObj.selectEdge(CropObject.MOVE_NONE); + mMovingBlock = false; + mPrevX = x; + mPrevY = y; + mState = Mode.NONE; + internallyUpdateLocalRep(mCropObj.getInnerBounds(), mCropObj.getOuterBounds()); + } + break; + case (MotionEvent.ACTION_MOVE): + if (mState == Mode.MOVE) { + float dx = x - mPrevX; + float dy = y - mPrevY; + mCropObj.moveCurrentSelection(dx, dy); + mPrevX = x; + mPrevY = y; + } + break; + default: + break; + } invalidate(); + return true; } - public void applyOriginal() { - mFixAspectRatio = true; - RectF photobounds = getLocalPhotoBounds(); - float w = photobounds.width(); - float h = photobounds.height(); - float scale = Math.min(w, h); - mAspectWidth = w / scale; - mAspectHeight = h / scale; - setLocalCropBounds(getUntranslatedStraightenCropBounds(photobounds, - getLocalStraighten())); - cropSetup(); - saveAndSetPreset(); + private void clearDisplay() { + mDisplayMatrix = null; + mDisplayMatrixInverse = null; invalidate(); } - public void applyClear() { - mFixAspectRatio = false; - mAspectWidth = 1; - mAspectHeight = 1; - setLocalCropBounds(getUntranslatedStraightenCropBounds(getLocalPhotoBounds(), - getLocalStraighten())); - cropSetup(); - saveAndSetPreset(); + public void applyFreeAspect() { + mCropObj.unsetAspectRatio(); invalidate(); } - public void clear() { - if (mCropExtras != null) { - int x = mCropExtras.getAspectX(); - int y = mCropExtras.getAspectY(); - if (mDoingCropIntentAction && x > 0 && y > 0) { - apply(x, y); - } + public void applyOriginalAspect() { + RectF outer = mCropObj.getOuterBounds(); + float w = outer.width(); + float h = outer.height(); + if (w > 0 && h > 0) { + applyAspect(w, h); + mCropObj.resetBoundsTo(outer, outer); + internallyUpdateLocalRep(mCropObj.getInnerBounds(), mCropObj.getOuterBounds()); } else { - applyClear(); + Log.w(TAG, "failed to set aspect ratio original"); } - } - - private Matrix getPhotoBoundDisplayedMatrix() { - float[] displayCenter = new float[2]; - RectF scaledCrop = new RectF(); - RectF scaledPhoto = new RectF(); - float scale = getTransformState(scaledPhoto, scaledCrop, displayCenter); - Matrix m = GeometryMetadata.buildCenteredPhotoMatrix(scaledPhoto, scaledCrop, - getLocalRotation(), getLocalStraighten(), getLocalMirror(), displayCenter); - m.preScale(scale, scale); - return m; - } - - private Matrix getCropBoundDisplayedMatrix() { - float[] displayCenter = new float[2]; - RectF scaledCrop = new RectF(); - RectF scaledPhoto = new RectF(); - float scale = getTransformState(scaledPhoto, scaledCrop, displayCenter); - Matrix m1 = GeometryMetadata.buildWanderingCropMatrix(scaledPhoto, scaledCrop, - getLocalRotation(), getLocalStraighten(), getLocalMirror(), displayCenter); - m1.preScale(scale, scale); - return m1; - } - - /** - * Takes the rotated corners of a rectangle and returns the angle; sets - * unrotated to be the unrotated version of the rectangle. - */ - private static float getUnrotated(float[] rotatedRect, float[] center, RectF unrotated) { - float dy = rotatedRect[1] - rotatedRect[3]; - float dx = rotatedRect[0] - rotatedRect[2]; - float angle = (float) (Math.atan(dy / dx) * 180 / Math.PI); - Matrix m = new Matrix(); - m.setRotate(-angle, center[0], center[1]); - float[] unrotatedRect = new float[rotatedRect.length]; - m.mapPoints(unrotatedRect, rotatedRect); - unrotated.set(CropMath.trapToRect(unrotatedRect)); - return angle; - } - - /** - * Sets cropped bounds; modifies the bounds if it's smaller than the allowed - * dimensions. - */ - public boolean setCropBounds(RectF bounds) { - RectF cbounds = new RectF(bounds); - Matrix mc = getCropBoundDisplayedMatrix(); - Matrix mcInv = new Matrix(); - mc.invert(mcInv); - mcInv.mapRect(cbounds); - // Avoid cropping smaller than minimum - float newWidth = cbounds.width(); - float newHeight = cbounds.height(); - float scale = getTransformState(null, null, null); - float minWidthHeight = mMinSideSize / scale; - RectF pbounds = getLocalPhotoBounds(); - - // if photo is smaller than minimum, refuse to set crop bounds - if (pbounds.width() < minWidthHeight || pbounds.height() < minWidthHeight) { - return false; - } - - // if incoming crop is smaller than minimum, refuse to set crop bounds - if (newWidth < minWidthHeight || newHeight < minWidthHeight) { - return false; - } - - float newX = bounds.centerX() - (getWidth() / 2f); - float newY = bounds.centerY() - (getHeight() / 2f); - mOffset[0] = newX; - mOffset[1] = newY; - - setLocalCropBounds(cbounds); invalidate(); - return true; - } - - private BoundedRect getBoundedCrop(RectF crop) { - RectF photo = getLocalPhotoBounds(); - Matrix mp = getPhotoBoundDisplayedMatrix(); - float[] photoCorners = CropMath.getCornersFromRect(photo); - float[] photoCenter = { - photo.centerX(), photo.centerY() - }; - mp.mapPoints(photoCorners); - mp.mapPoints(photoCenter); - RectF scaledPhoto = new RectF(); - float angle = getUnrotated(photoCorners, photoCenter, scaledPhoto); - return new BoundedRect(angle, scaledPhoto, crop); } - private void detectMovingEdges(float x, float y) { - Matrix m = getCropBoundDisplayedMatrix(); - RectF cropped = getLocalCropBounds(); - m.mapRect(cropped); - mBounded = getBoundedCrop(cropped); - movingEdges = 0; - - float left = Math.abs(x - cropped.left); - float right = Math.abs(x - cropped.right); - float top = Math.abs(y - cropped.top); - float bottom = Math.abs(y - cropped.bottom); - - // Check left or right. - if ((left <= mTouchTolerance) && ((y + mTouchTolerance) >= cropped.top) - && ((y - mTouchTolerance) <= cropped.bottom) && (left < right)) { - movingEdges |= MOVE_LEFT; - } - else if ((right <= mTouchTolerance) && ((y + mTouchTolerance) >= cropped.top) - && ((y - mTouchTolerance) <= cropped.bottom)) { - movingEdges |= MOVE_RIGHT; - } - - // Check top or bottom. - if ((top <= mTouchTolerance) && ((x + mTouchTolerance) >= cropped.left) - && ((x - mTouchTolerance) <= cropped.right) && (top < bottom)) { - movingEdges |= MOVE_TOP; - } - else if ((bottom <= mTouchTolerance) && ((x + mTouchTolerance) >= cropped.left) - && ((x - mTouchTolerance) <= cropped.right)) { - movingEdges |= MOVE_BOTTOM; + public void applyAspect(float x, float y) { + if (x <= 0 || y <= 0) { + throw new IllegalArgumentException("Bad arguments to applyAspect"); } - if (movingEdges == 0) { - movingEdges = MOVE_BLOCK; + // If we are rotated by 90 degrees from horizontal, swap x and y + if (GeometryMathUtils.needsDimensionSwap(mGeometry.rotation)) { + float tmp = x; + x = y; + y = tmp; } - if (mFixAspectRatio && (movingEdges != MOVE_BLOCK)) { - movingEdges = fixEdgeToCorner(movingEdges); + if (!mCropObj.setInnerAspectRatio(x, y)) { + Log.w(TAG, "failed to set aspect ratio"); } + internallyUpdateLocalRep(mCropObj.getInnerBounds(), mCropObj.getOuterBounds()); invalidate(); } - private int fixEdgeToCorner(int moving_edges) { - if (moving_edges == MOVE_LEFT) { - moving_edges |= MOVE_TOP; - } - if (moving_edges == MOVE_TOP) { - moving_edges |= MOVE_LEFT; - } - if (moving_edges == MOVE_RIGHT) { - moving_edges |= MOVE_BOTTOM; - } - if (moving_edges == MOVE_BOTTOM) { - moving_edges |= MOVE_RIGHT; - } - return moving_edges; - } - - private RectF fixedCornerResize(RectF r, int moving_corner, float dx, float dy) { - RectF newCrop = null; - // Fix opposite corner in place and move sides - if (moving_corner == BOTTOM_RIGHT) { - newCrop = new RectF(r.left, r.top, r.left + r.width() + dx, r.top + r.height() - + dy); - } else if (moving_corner == BOTTOM_LEFT) { - newCrop = new RectF(r.right - r.width() + dx, r.top, r.right, r.top + r.height() - + dy); - } else if (moving_corner == TOP_LEFT) { - newCrop = new RectF(r.right - r.width() + dx, r.bottom - r.height() + dy, - r.right, r.bottom); - } else if (moving_corner == TOP_RIGHT) { - newCrop = new RectF(r.left, r.bottom - r.height() + dy, r.left - + r.width() + dx, r.bottom); - } - return newCrop; + /** + * Rotates first d bits in integer x to the left some number of times. + */ + private int bitCycleLeft(int x, int times, int d) { + int mask = (1 << d) - 1; + int mout = x & mask; + times %= d; + int hi = mout >> (d - times); + int low = (mout << times) & mask; + int ret = x & ~mask; + ret |= low; + ret |= hi; + return ret; } - private void moveEdges(float dX, float dY) { - RectF crop = mBounded.getInner(); - - Matrix mc = getCropBoundDisplayedMatrix(); - - RectF photo = getLocalPhotoBounds(); - Matrix mp = getPhotoBoundDisplayedMatrix(); - float[] photoCorners = CropMath.getCornersFromRect(photo); - float[] photoCenter = { - photo.centerX(), photo.centerY() - }; - mp.mapPoints(photoCorners); - mp.mapPoints(photoCenter); - - float minWidthHeight = mMinSideSize; - - if (movingEdges == MOVE_BLOCK) { - mBounded.moveInner(-dX, -dY); - RectF r = mBounded.getInner(); - setCropBounds(r); - return; - } else { - float dx = 0; - float dy = 0; - - if ((movingEdges & MOVE_LEFT) != 0) { - dx = Math.min(crop.left + dX, crop.right - minWidthHeight) - crop.left; - } - if ((movingEdges & MOVE_TOP) != 0) { - dy = Math.min(crop.top + dY, crop.bottom - minWidthHeight) - crop.top; - } - if ((movingEdges & MOVE_RIGHT) != 0) { - dx = Math.max(crop.right + dX, crop.left + minWidthHeight) - - crop.right; - } - if ((movingEdges & MOVE_BOTTOM) != 0) { - dy = Math.max(crop.bottom + dY, crop.top + minWidthHeight) - - crop.bottom; - } - - if (mFixAspectRatio) { - float[] l1 = { - crop.left, crop.bottom - }; - float[] l2 = { - crop.right, crop.top - }; - if (movingEdges == TOP_LEFT || movingEdges == BOTTOM_RIGHT) { - l1[1] = crop.top; - l2[1] = crop.bottom; - } - float[] b = { - l1[0] - l2[0], l1[1] - l2[1] - }; - float[] disp = { - dx, dy - }; - float[] bUnit = GeometryMath.normalize(b); - float sp = GeometryMath.scalarProjection(disp, bUnit); - dx = sp * bUnit[0]; - dy = sp * bUnit[1]; - RectF newCrop = fixedCornerResize(crop, movingEdges, dx, dy); - - mBounded.fixedAspectResizeInner(newCrop); - newCrop = mBounded.getInner(); - setCropBounds(newCrop); - return; - } else { - if ((movingEdges & MOVE_LEFT) != 0) { - crop.left += dx; - } - if ((movingEdges & MOVE_TOP) != 0) { - crop.top += dy; - } - if ((movingEdges & MOVE_RIGHT) != 0) { - crop.right += dx; - } - if ((movingEdges & MOVE_BOTTOM) != 0) { - crop.bottom += dy; - } - } + /** + * Find the selected edge or corner in screen coordinates. + */ + private int decode(int movingEdges, float rotation) { + int rot = CropMath.constrainedRotation(rotation); + switch (rot) { + case 90: + return bitCycleLeft(movingEdges, 1, 4); + case 180: + return bitCycleLeft(movingEdges, 2, 4); + case 270: + return bitCycleLeft(movingEdges, 3, 4); + default: + return movingEdges; } - mBounded.resizeInner(crop); - crop = mBounded.getInner(); - setCropBounds(crop); - } - - private void drawIndicator(Canvas canvas, Drawable indicator, float centerX, float centerY) { - int left = (int) centerX - indicatorSize / 2; - int top = (int) centerY - indicatorSize / 2; - indicator.setBounds(left, top, left + indicatorSize, top + indicatorSize); - indicator.draw(canvas); } - @Override - protected void setActionDown(float x, float y) { - super.setActionDown(x, y); - detectMovingEdges(x + mOffset[0], y + mOffset[1]); - - } - - @Override - protected void setActionUp() { - super.setActionUp(); - movingEdges = 0; - } - - @Override - protected void setActionMove(float x, float y) { - - if (movingEdges != 0) { - moveEdges(x - mCurrentX, y - mCurrentY); + private void forceStateConsistency() { + MasterImage master = MasterImage.getImage(); + Bitmap image = master.getFiltersOnlyImage(); + int width = image.getWidth(); + int height = image.getHeight(); + if (mCropObj == null || !mUpdateHolder.equals(mGeometry) + || mImageBounds.width() != width || mImageBounds.height() != height + || !mLocalRep.getCrop().equals(mUpdateHolder.crop)) { + mImageBounds.set(0, 0, width, height); + mGeometry.set(mUpdateHolder); + mLocalRep.setCrop(mUpdateHolder.crop); + RectF scaledCrop = new RectF(mUpdateHolder.crop); + FilterCropRepresentation.findScaledCrop(scaledCrop, width, height); + mCropObj = new CropObject(mImageBounds, scaledCrop, (int) mUpdateHolder.straighten); + mState = Mode.NONE; + clearDisplay(); } - super.setActionMove(x, y); - } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { - setActionUp(); - cropSetup(); - invalidate(); - } - - private void cropSetup() { - RectF crop = getLocalCropBounds(); - Matrix m = getCropBoundDisplayedMatrix(); - m.mapRect(crop); - if (mFixAspectRatio) { - CropMath.fixAspectRatio(crop, mAspectWidth, mAspectHeight); - } - float dCentX = getWidth() / 2; - float dCentY = getHeight() / 2; - - BoundedRect r = getBoundedCrop(crop); - crop = r.getInner(); - if (!setCropBounds(crop)) { - float h = mMinSideSize / 2; - float wScale = 1; - float hScale = mAspectHeight / mAspectWidth; - if (hScale < 1) { - wScale = mAspectWidth / mAspectHeight; - hScale = 1; - } - crop.set(dCentX - h * wScale, dCentY - h * hScale, dCentX + h * wScale, dCentY + h - * hScale); - if (mFixAspectRatio) { - CropMath.fixAspectRatio(crop, mAspectWidth, mAspectHeight); - } - r.setInner(crop); - crop = r.getInner(); - if (!setCropBounds(crop)) { - crop.set(dCentX - h, dCentY - h, dCentX + h, dCentY + h); - r.setInner(crop); - crop = r.getInner(); - setCropBounds(crop); - } - } - } - - @Override - public void imageLoaded() { - super.imageLoaded(); - syncLocalToMasterGeometry(); - clear(); - invalidate(); + super.onSizeChanged(w, h, oldw, oldh); + clearDisplay(); } @Override - protected void gainedVisibility() { - float rot = getLocalRotation(); - // if has changed orientation via rotate - if (((int) ((rot - mLastRot) / 90)) % 2 != 0) { - swapAspect(); - } - cropSetup(); - mFirstDraw = true; - } - - @Override - public void resetParameter() { - super.resetParameter(); - } - - @Override - protected void lostVisibility() { - mLastRot = getLocalRotation(); - } - - private void drawRuleOfThird(Canvas canvas, RectF bounds, Paint p) { - float stepX = bounds.width() / 3.0f; - float stepY = bounds.height() / 3.0f; - float x = bounds.left + stepX; - float y = bounds.top + stepY; - for (int i = 0; i < 2; i++) { - canvas.drawLine(x, bounds.top, x, bounds.bottom, p); - x += stepX; - } - for (int j = 0; j < 2; j++) { - canvas.drawLine(bounds.left, y, bounds.right, y, p); - y += stepY; - } - } - - @Override - protected void drawShape(Canvas canvas, Bitmap image) { - gPaint.setAntiAlias(true); - gPaint.setARGB(255, 255, 255, 255); - - if (mFirstDraw) { - cropSetup(); - mFirstDraw = false; - } - - RectF crop = drawTransformed(canvas, image, gPaint, mOffset); - gPaint.setColor(mBorderColor); - gPaint.setStrokeWidth(3); - gPaint.setStyle(Paint.Style.STROKE); - - boolean doThirds = true; - - if (mFixAspectRatio) { - float spotlightX = 0; - float spotlightY = 0; - if (mCropExtras != null) { - spotlightX = mCropExtras.getSpotlightX(); - spotlightY = mCropExtras.getSpotlightY(); - } - if (mDoingCropIntentAction && spotlightX > 0 && spotlightY > 0) { - float sx = crop.width() * spotlightX; - float sy = crop.height() * spotlightY; - float cx = crop.centerX(); - float cy = crop.centerY(); - RectF r1 = new RectF(cx - sx / 2, cy - sy / 2, cx + sx / 2, cy + sy / 2); - float temp = sx; - sx = sy; - sy = temp; - RectF r2 = new RectF(cx - sx / 2, cy - sy / 2, cx + sx / 2, cy + sy / 2); - canvas.drawRect(r1, gPaint); - canvas.drawRect(r2, gPaint); - doThirds = false; - } else { - float w = crop.width(); - float h = crop.height(); - float diag = (float) Math.sqrt(w * w + h * h); - - float dash_len = 20; - int num_intervals = (int) (diag / dash_len); - float[] tl = { - crop.left, crop.top - }; - float centX = tl[0] + w / 2; - float centY = tl[1] + h / 2 + 5; - float[] br = { - crop.right, crop.bottom - }; - float[] vec = GeometryMath.getUnitVectorFromPoints(tl, br); - - float[] counter = tl; - for (int x = 0; x < num_intervals; x++) { - float tempX = counter[0] + vec[0] * dash_len; - float tempY = counter[1] + vec[1] * dash_len; - if ((x % 2) == 0 && Math.abs(x - num_intervals / 2) > 2) { - canvas.drawLine(counter[0], counter[1], tempX, tempY, gPaint); - } - counter[0] = tempX; - counter[1] = tempY; - } - - gPaint.setTextAlign(Paint.Align.CENTER); - gPaint.setTextSize(mAspectTextSize); - canvas.drawText(mAspect, centX, centY, gPaint); - } - } - - if (doThirds) { - drawRuleOfThird(canvas, crop, gPaint); - + public void onDraw(Canvas canvas) { + Bitmap bitmap = MasterImage.getImage().getFiltersOnlyImage(); + if (!mValidDraw || bitmap == null) { + return; } - - RectF scaledCrop = crop; - boolean notMoving = (movingEdges == 0); - if (mFixAspectRatio) { - if ((movingEdges == TOP_LEFT) || notMoving) { - drawIndicator(canvas, cropIndicator, scaledCrop.left, scaledCrop.top); - } - if ((movingEdges == TOP_RIGHT) || notMoving) { - drawIndicator(canvas, cropIndicator, scaledCrop.right, scaledCrop.top); - } - if ((movingEdges == BOTTOM_LEFT) || notMoving) { - drawIndicator(canvas, cropIndicator, scaledCrop.left, scaledCrop.bottom); - } - if ((movingEdges == BOTTOM_RIGHT) || notMoving) { - drawIndicator(canvas, cropIndicator, scaledCrop.right, scaledCrop.bottom); - } - } else { - if (((movingEdges & MOVE_TOP) != 0) || notMoving) { - drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.top); - } - if (((movingEdges & MOVE_BOTTOM) != 0) || notMoving) { - drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.bottom); - } - if (((movingEdges & MOVE_LEFT) != 0) || notMoving) { - drawIndicator(canvas, cropIndicator, scaledCrop.left, scaledCrop.centerY()); - } - if (((movingEdges & MOVE_RIGHT) != 0) || notMoving) { - drawIndicator(canvas, cropIndicator, scaledCrop.right, scaledCrop.centerY()); + forceStateConsistency(); + mImageBounds.set(0, 0, bitmap.getWidth(), bitmap.getHeight()); + // If display matrix doesn't exist, create it and its dependencies + if (mDisplayCropMatrix == null || mDisplayMatrix == null || mDisplayMatrixInverse == null) { + mDisplayMatrix = GeometryMathUtils.getFullGeometryToScreenMatrix(mGeometry, + bitmap.getWidth(), bitmap.getHeight(), canvas.getWidth(), canvas.getHeight()); + float straighten = mGeometry.straighten; + mGeometry.straighten = 0; + mDisplayCropMatrix = GeometryMathUtils.getFullGeometryToScreenMatrix(mGeometry, + bitmap.getWidth(), bitmap.getHeight(), canvas.getWidth(), canvas.getHeight()); + mGeometry.straighten = straighten; + mDisplayMatrixInverse = new Matrix(); + mDisplayMatrixInverse.reset(); + if (!mDisplayCropMatrix.invert(mDisplayMatrixInverse)) { + Log.w(TAG, "could not invert display matrix"); + mDisplayMatrixInverse = null; + return; } + // Scale min side and tolerance by display matrix scale factor + mCropObj.setMinInnerSideSize(mDisplayMatrixInverse.mapRadius(mMinSideSize)); + mCropObj.setTouchTolerance(mDisplayMatrixInverse.mapRadius(mTouchTolerance)); } - } - - public void setAspectButton(int itemId) { - switch (itemId) { - case R.id.crop_menu_1to1: { - String t = getActivity().getString(R.string.aspect1to1_effect); - apply(1, 1); - setAspectString(t); - break; - } - case R.id.crop_menu_4to3: { - String t = getActivity().getString(R.string.aspect4to3_effect); - apply(4, 3); - setAspectString(t); - break; - } - case R.id.crop_menu_3to4: { - String t = getActivity().getString(R.string.aspect3to4_effect); - apply(3, 4); - setAspectString(t); - break; - } - case R.id.crop_menu_5to7: { - String t = getActivity().getString(R.string.aspect5to7_effect); - apply(5, 7); - setAspectString(t); - break; - } - case R.id.crop_menu_7to5: { - String t = getActivity().getString(R.string.aspect7to5_effect); - apply(7, 5); - setAspectString(t); - break; - } - case R.id.crop_menu_none: { - String t = getActivity().getString(R.string.aspectNone_effect); - applyClear(); - setAspectString(t); - break; - } - case R.id.crop_menu_original: { - String t = getActivity().getString(R.string.aspectOriginal_effect); - applyOriginal(); - setAspectString(t); - break; - } + // Draw actual bitmap + mPaint.reset(); + mPaint.setAntiAlias(true); + mPaint.setFilterBitmap(true); + canvas.drawBitmap(bitmap, mDisplayMatrix, mPaint); + mCropObj.getInnerBounds(mScreenCropBounds); + RectF outer = mCropObj.getOuterBounds(); + FilterCropRepresentation.findNormalizedCrop(mScreenCropBounds, (int) outer.width(), + (int) outer.height()); + FilterCropRepresentation.findScaledCrop(mScreenCropBounds, bitmap.getWidth(), + bitmap.getHeight()); + if (mDisplayCropMatrix.mapRect(mScreenCropBounds)) { + // Draw crop rect and markers + CropDrawingUtils.drawCropRect(canvas, mScreenCropBounds); + CropDrawingUtils.drawRuleOfThird(canvas, mScreenCropBounds); + CropDrawingUtils.drawIndicators(canvas, mCropIndicator, mIndicatorSize, + mScreenCropBounds, mCropObj.isFixedAspect(), + decode(mCropObj.getSelectState(), mGeometry.rotation.value())); } - invalidate(); - } - - public void setFixedAspect(boolean fixedAspect) { - mFixedAspect = fixedAspect; - } - - @Override - public boolean useUtilityPanel() { - // Only shows the aspect ratio popup if we are not fixed - return !mFixedAspect; } public void setEditor(EditorCrop editorCrop) { mEditorCrop = editorCrop; } - } -- cgit v1.2.3