ImageCrop.java revision f46da69aefd9afe0b4326a2fcea8e33c294136bb
18537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk/* 28537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * Copyright (C) 2012 The Android Open Source Project 38537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * 48537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * Licensed under the Apache License, Version 2.0 (the "License"); 58537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * you may not use this file except in compliance with the License. 68537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * You may obtain a copy of the License at 78537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * 88537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * http://www.apache.org/licenses/LICENSE-2.0 98537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * 108537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * Unless required by applicable law or agreed to in writing, software 118537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * distributed under the License is distributed on an "AS IS" BASIS, 128537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * See the License for the specific language governing permissions and 148537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * limitations under the License. 158537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk */ 168537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 178537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkpackage com.android.gallery3d.filtershow.imageshow; 188537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 198537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.content.Context; 208537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.content.res.Resources; 218537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.graphics.Bitmap; 228537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.graphics.Canvas; 23c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroardimport android.graphics.Color; 248537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.graphics.Matrix; 258537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.graphics.Paint; 268537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.graphics.RectF; 278537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.graphics.drawable.Drawable; 288537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.util.AttributeSet; 298537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.util.Log; 30c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard 31e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroardimport com.android.gallery3d.R; 328537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 338537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkpublic class ImageCrop extends ImageGeometry { 348537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private static final boolean LOGV = false; 358537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private static final int MOVE_LEFT = 1; 368537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private static final int MOVE_TOP = 2; 378537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private static final int MOVE_RIGHT = 4; 388537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private static final int MOVE_BOTTOM = 8; 398537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private static final int MOVE_BLOCK = 16; 408537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 410f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk //Corners 420f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk private static final int TOP_LEFT = MOVE_TOP | MOVE_LEFT; 430f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk private static final int TOP_RIGHT = MOVE_TOP | MOVE_RIGHT; 440f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk private static final int BOTTOM_RIGHT = MOVE_BOTTOM | MOVE_RIGHT; 450f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk private static final int BOTTOM_LEFT = MOVE_BOTTOM | MOVE_LEFT; 460f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk 478537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private static final float MIN_CROP_WIDTH_HEIGHT = 0.1f; 48f46da69aefd9afe0b4326a2fcea8e33c294136bbRuben Brunk private static int mTouchTolerance = 45; 498537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 5062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk private boolean mFirstDraw = true; 5162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk private float mAspectWidth = 1; 5262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk private float mAspectHeight = 1; 5362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk private boolean mFixAspectRatio = false; 548537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 55a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk private float mLastRot = 0; 568537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private final Paint borderPaint; 578537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 588537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private int movingEdges; 598537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private final Drawable cropIndicator; 608537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private final int indicatorSize; 61104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard private final int mBorderColor = Color.argb(128, 255, 255, 255); 628537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 638537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private static final String LOGTAG = "ImageCrop"; 648537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 658537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private static final Paint gPaint = new Paint(); 668537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 678537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk public ImageCrop(Context context) { 688537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk super(context); 698537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk Resources resources = context.getResources(); 70c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard cropIndicator = resources.getDrawable(R.drawable.camera_crop); 718537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk indicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size); 728537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk borderPaint = new Paint(); 738537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk borderPaint.setStyle(Paint.Style.STROKE); 74104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard borderPaint.setColor(mBorderColor); 758537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk borderPaint.setStrokeWidth(2f); 768537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 778537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 788537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk public ImageCrop(Context context, AttributeSet attrs) { 798537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk super(context, attrs); 808537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk Resources resources = context.getResources(); 81c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard cropIndicator = resources.getDrawable(R.drawable.camera_crop); 828537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk indicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size); 838537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk borderPaint = new Paint(); 848537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk borderPaint.setStyle(Paint.Style.STROKE); 85104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard borderPaint.setColor(mBorderColor); 868537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk borderPaint.setStrokeWidth(2f); 878537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 888537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 89d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard @Override 90d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard public String getName() { 910a32b7afc5286a5c7aa334b9338591d61a49731fRuben Brunk return getContext().getString(R.string.crop); 92d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard } 93d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard 94a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk private void swapAspect(){ 95a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk float temp = mAspectWidth; 96a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk mAspectWidth = mAspectHeight; 97a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk mAspectHeight = temp; 98a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk } 99a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk 100f46da69aefd9afe0b4326a2fcea8e33c294136bbRuben Brunk public static void setTouchTolerance(int tolerance){ 101f46da69aefd9afe0b4326a2fcea8e33c294136bbRuben Brunk mTouchTolerance = tolerance; 102f46da69aefd9afe0b4326a2fcea8e33c294136bbRuben Brunk } 103f46da69aefd9afe0b4326a2fcea8e33c294136bbRuben Brunk 1040f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk private boolean switchCropBounds(int moving_corner, RectF dst) { 1050f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk RectF crop = getCropBoundsDisplayed(); 1060f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float dx1 = 0; 1070f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float dy1 = 0; 1080f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float dx2 = 0; 1090f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float dy2 = 0; 1100f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if ((moving_corner & MOVE_RIGHT) != 0) { 1110f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk dx1 = mCurrentX - crop.right; 1120f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } else if ((moving_corner & MOVE_LEFT) != 0) { 1130f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk dx1 = mCurrentX - crop.left; 1140f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 1150f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if ((moving_corner & MOVE_BOTTOM) != 0) { 1160f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk dy1 = mCurrentY - crop.bottom; 1170f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } else if ((moving_corner & MOVE_TOP) != 0) { 1180f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk dy1 = mCurrentY - crop.top; 1190f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 1200f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk RectF newCrop = null; 1210f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk //Fix opposite corner in place and move sides 1220f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (moving_corner == BOTTOM_RIGHT) { 1230f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk newCrop = new RectF(crop.left, crop.top, crop.left + crop.height(), crop.top 1240f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk + crop.width()); 1250f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } else if (moving_corner == BOTTOM_LEFT) { 1260f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk newCrop = new RectF(crop.right - crop.height(), crop.top, crop.right, crop.top 1270f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk + crop.width()); 1280f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } else if (moving_corner == TOP_LEFT) { 1290f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk newCrop = new RectF(crop.right - crop.height(), crop.bottom - crop.width(), 1300f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk crop.right, crop.bottom); 1310f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } else if (moving_corner == TOP_RIGHT) { 1320f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk newCrop = new RectF(crop.left, crop.bottom - crop.width(), crop.left 1330f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk + crop.height(), crop.bottom); 1340f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 1350f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if ((moving_corner & MOVE_RIGHT) != 0) { 1360f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk dx2 = mCurrentX - newCrop.right; 1370f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } else if ((moving_corner & MOVE_LEFT) != 0) { 1380f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk dx2 = mCurrentX - newCrop.left; 1390f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 1400f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if ((moving_corner & MOVE_BOTTOM) != 0) { 1410f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk dy2 = mCurrentY - newCrop.bottom; 1420f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } else if ((moving_corner & MOVE_TOP) != 0) { 1430f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk dy2 = mCurrentY - newCrop.top; 1440f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 1450f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (Math.sqrt(dx1*dx1 + dy1*dy1) > Math.sqrt(dx2*dx2 + dy2*dy2)){ 1460f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk Matrix m = getCropBoundDisplayMatrix(); 1470f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk Matrix m0 = new Matrix(); 1480f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (!m.invert(m0)){ 1490f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (LOGV) 1500f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk Log.v(LOGTAG, "FAILED TO INVERT CROP MATRIX"); 1510f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return false; 1520f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 1530f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (!m0.mapRect(newCrop)){ 1540f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (LOGV) 1550f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk Log.v(LOGTAG, "FAILED TO MAP RECTANGLE TO RECTANGLE"); 1560f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return false; 1570f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 158a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk swapAspect(); 1590f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk dst.set(newCrop); 1600f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return true; 1610f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 1620f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return false; 1630f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 1640f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk 1650f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk public void apply(float w, float h){ 1660f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk mFixAspectRatio = true; 1670f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk mAspectWidth = w; 1680f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk mAspectHeight = h; 1690f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk setLocalCropBounds(getUntranslatedStraightenCropBounds(getLocalPhotoBounds(), 1700f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk getLocalStraighten())); 1710f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk cropSetup(); 1720f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk saveAndSetPreset(); 1730f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk invalidate(); 1740f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 1750f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk 1760f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk public void applyOriginal() { 1770f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk mFixAspectRatio = true; 1780f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk RectF photobounds = getLocalPhotoBounds(); 1790f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float w = photobounds.width(); 1800f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float h = photobounds.height(); 1810f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float scale = Math.min(w, h); 1820f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk mAspectWidth = w / scale; 1830f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk mAspectHeight = h / scale; 1840f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk setLocalCropBounds(getUntranslatedStraightenCropBounds(photobounds, 1850f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk getLocalStraighten())); 1860f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk cropSetup(); 1870f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk saveAndSetPreset(); 1880f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk invalidate(); 1890f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 1900f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk 1910f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk public void applyClear() { 1920f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk mFixAspectRatio = false; 1930f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk setLocalCropBounds(getUntranslatedStraightenCropBounds(getLocalPhotoBounds(), 1940f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk getLocalStraighten())); 1950f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk cropSetup(); 1960f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk saveAndSetPreset(); 1970f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk invalidate(); 1980f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 1990f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk 2008537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private float getScaledMinWidthHeight() { 20162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF disp = new RectF(0, 0, getWidth(), getHeight()); 2028537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float scaled = Math.min(disp.width(), disp.height()) * MIN_CROP_WIDTH_HEIGHT 20362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk / computeScale(getWidth(), getHeight()); 2048537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return scaled; 2058537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2068537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 20762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected Matrix getCropRotationMatrix(float rotation, RectF localImage) { 20862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk Matrix m = getLocalGeoFlipMatrix(localImage.width(), localImage.height()); 20962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk m.postRotate(rotation, localImage.centerX(), localImage.centerY()); 2108537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (!m.rectStaysRect()) { 2118537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return null; 2128537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2138537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return m; 2148537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2158537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2160f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk protected Matrix getCropBoundDisplayMatrix(){ 2170f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk Matrix m = getCropRotationMatrix(getLocalRotation(), getLocalPhotoBounds()); 2180f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (m == null) { 2190f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (LOGV) 2200f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk Log.v(LOGTAG, "FAILED TO MAP CROP BOUNDS TO RECTANGLE"); 2210f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk m = new Matrix(); 2220f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 2230f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float zoom = computeScale(getWidth(), getHeight()); 2240f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk m.postTranslate(mXOffset, mYOffset); 2250f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk m.postScale(zoom, zoom, mCenterX, mCenterY); 2260f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return m; 2270f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 2280f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk 2298537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected RectF getCropBoundsDisplayed() { 2308537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk RectF bounds = getLocalCropBounds(); 2318537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk RectF crop = new RectF(bounds); 2328537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk Matrix m = getCropRotationMatrix(getLocalRotation(), getLocalPhotoBounds()); 2338537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2348537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (m == null) { 2358537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (LOGV) 2368537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk Log.v(LOGTAG, "FAILED TO MAP CROP BOUNDS TO RECTANGLE"); 2378537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk m = new Matrix(); 2388537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } else { 2398537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk m.mapRect(crop); 2408537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2418537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk m = new Matrix(); 24262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float zoom = computeScale(getWidth(), getHeight()); 2438537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk m.setScale(zoom, zoom, mCenterX, mCenterY); 2448537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk m.preTranslate(mXOffset, mYOffset); 2458537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk m.mapRect(crop); 2468537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return crop; 2478537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2488537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2498537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private RectF getRotatedCropBounds() { 2508537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk RectF bounds = getLocalCropBounds(); 2518537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk RectF crop = new RectF(bounds); 2528537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk Matrix m = getCropRotationMatrix(getLocalRotation(), getLocalPhotoBounds()); 2538537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2548537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (m == null) { 2558537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (LOGV) 2568537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk Log.v(LOGTAG, "FAILED TO MAP CROP BOUNDS TO RECTANGLE"); 2578537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return null; 2588537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } else { 2598537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk m.mapRect(crop); 2608537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2618537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return crop; 2628537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2638537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 26462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk private RectF getUnrotatedCropBounds(RectF cropBounds) { 26562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk Matrix m = getCropRotationMatrix(getLocalRotation(), getLocalPhotoBounds()); 26662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 26762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (m == null) { 26862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (LOGV) 26962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk Log.v(LOGTAG, "FAILED TO GET ROTATION MATRIX"); 27062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return null; 27162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 27262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk Matrix m0 = new Matrix(); 27362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (!m.invert(m0)) { 27462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (LOGV) 27562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk Log.v(LOGTAG, "FAILED TO INVERT ROTATION MATRIX"); 27662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return null; 27762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 27862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF crop = new RectF(cropBounds); 27962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (!m0.mapRect(crop)) { 28062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (LOGV) 28162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk Log.v(LOGTAG, "FAILED TO UNROTATE CROPPING BOUNDS"); 28262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return null; 28362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 28462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return crop; 28562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 28662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 28762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk private RectF getRotatedStraightenBounds() { 28862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF straightenBounds = getUntranslatedStraightenCropBounds(getLocalPhotoBounds(), 28962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk getLocalStraighten()); 29062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk Matrix m = getCropRotationMatrix(getLocalRotation(), getLocalPhotoBounds()); 29162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 29262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (m == null) { 29362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (LOGV) 29462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk Log.v(LOGTAG, "FAILED TO MAP STRAIGHTEN BOUNDS TO RECTANGLE"); 29562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return null; 29662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } else { 29762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk m.mapRect(straightenBounds); 29862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 29962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return straightenBounds; 30062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 30162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 3028537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk /** 3038537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * Sets cropped bounds; modifies the bounds if it's smaller than the allowed 3048537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk * dimensions. 3058537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk */ 3068537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk public void setCropBounds(RectF bounds) { 3078537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk // Avoid cropping smaller than minimum width or height. 3088537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk RectF cbounds = new RectF(bounds); 3098537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float minWidthHeight = getScaledMinWidthHeight(); 31062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float aw = mAspectWidth; 31162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float ah = mAspectHeight; 31262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (mFixAspectRatio) { 31362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk minWidthHeight /= aw * ah; 31462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk int r = (int) (getLocalRotation() / 90); 31562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (r % 2 != 0) { 31662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float temp = aw; 31762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk aw = ah; 31862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk ah = temp; 31962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 32062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 3218537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3228537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float newWidth = cbounds.width(); 3238537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float newHeight = cbounds.height(); 32462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (mFixAspectRatio) { 32562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (newWidth < (minWidthHeight * aw) || newHeight < (minWidthHeight * ah)) { 32662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk newWidth = minWidthHeight * aw; 32762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk newHeight = minWidthHeight * ah; 32862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 32962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } else { 33062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (newWidth < minWidthHeight) { 33162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk newWidth = minWidthHeight; 33262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 33362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (newHeight < minWidthHeight) { 33462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk newHeight = minWidthHeight; 33562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 3368537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3378537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk RectF pbounds = getLocalPhotoBounds(); 3388537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (pbounds.width() < minWidthHeight) { 3398537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk newWidth = pbounds.width(); 3408537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3418537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (pbounds.height() < minWidthHeight) { 3428537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk newHeight = pbounds.height(); 3438537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3448537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3458537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk cbounds.set(cbounds.left, cbounds.top, cbounds.left + newWidth, cbounds.top + newHeight); 34662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF straightenBounds = getUntranslatedStraightenCropBounds(getLocalPhotoBounds(), 34762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk getLocalStraighten()); 34862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk cbounds.intersect(straightenBounds); 349e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard 3508537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (mFixAspectRatio) { 35162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk fixAspectRatio(cbounds, aw, ah); 3528537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 35362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk setLocalCropBounds(cbounds); 3548537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk invalidate(); 3558537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3568537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3578537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private void detectMovingEdges(float x, float y) { 3588537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk RectF cropped = getCropBoundsDisplayed(); 3598537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk movingEdges = 0; 3608537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3618537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk // Check left or right. 3628537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float left = Math.abs(x - cropped.left); 3638537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float right = Math.abs(x - cropped.right); 364f46da69aefd9afe0b4326a2fcea8e33c294136bbRuben Brunk if ((left <= mTouchTolerance) && (left < right)) { 3658537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk movingEdges |= MOVE_LEFT; 3668537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 367f46da69aefd9afe0b4326a2fcea8e33c294136bbRuben Brunk else if (right <= mTouchTolerance) { 3688537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk movingEdges |= MOVE_RIGHT; 3698537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3708537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3718537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk // Check top or bottom. 3728537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float top = Math.abs(y - cropped.top); 3738537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float bottom = Math.abs(y - cropped.bottom); 374f46da69aefd9afe0b4326a2fcea8e33c294136bbRuben Brunk if ((top <= mTouchTolerance) & (top < bottom)) { 3758537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk movingEdges |= MOVE_TOP; 3768537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 377f46da69aefd9afe0b4326a2fcea8e33c294136bbRuben Brunk else if (bottom <= mTouchTolerance) { 3788537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk movingEdges |= MOVE_BOTTOM; 3798537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 38062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk // Check inside block. 38162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (cropped.contains(x, y) && (movingEdges == 0)) { 38262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk movingEdges = MOVE_BLOCK; 38362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 3840f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (mFixAspectRatio && (movingEdges != MOVE_BLOCK)) { 3850f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk movingEdges = fixEdgeToCorner(movingEdges); 3860f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 3878537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk invalidate(); 3888537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3898537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3900f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk private int fixEdgeToCorner(int moving_edges){ 3910f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (moving_edges == MOVE_LEFT) { 3920f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk moving_edges |= MOVE_TOP; 3930f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 3940f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (moving_edges == MOVE_TOP) { 3950f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk moving_edges |= MOVE_LEFT; 3960f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 3970f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (moving_edges == MOVE_RIGHT) { 3980f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk moving_edges |= MOVE_BOTTOM; 3990f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 4000f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (moving_edges == MOVE_BOTTOM) { 4010f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk moving_edges |= MOVE_RIGHT; 4020f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 4030f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return moving_edges; 4040f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 4050f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk 4060f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk private RectF fixedCornerResize(RectF r, int moving_corner, float dx, float dy){ 4070f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk RectF newCrop = null; 4080f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk //Fix opposite corner in place and move sides 4090f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (moving_corner == BOTTOM_RIGHT) { 4100f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk newCrop = new RectF(r.left, r.top, r.left + r.width() + dx, r.top + r.height() 4110f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk + dy); 4120f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } else if (moving_corner == BOTTOM_LEFT) { 4130f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk newCrop = new RectF(r.right - r.width() + dx, r.top, r.right, r.top + r.height() 4140f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk + dy); 4150f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } else if (moving_corner == TOP_LEFT) { 4160f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk newCrop = new RectF(r.right - r.width() + dx, r.bottom - r.height() + dy, 4170f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk r.right, r.bottom); 4180f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } else if (moving_corner == TOP_RIGHT) { 4190f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk newCrop = new RectF(r.left, r.bottom - r.height() + dy, r.left 4200f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk + r.width() + dx, r.bottom); 4210f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 4220f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return newCrop; 4230f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 4240f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk 4258537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private void moveEdges(float dX, float dY) { 4268537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk RectF cropped = getRotatedCropBounds(); 4278537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float minWidthHeight = getScaledMinWidthHeight(); 42862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float scale = computeScale(getWidth(), getHeight()); 4298537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float deltaX = dX / scale; 4308537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float deltaY = dY / scale; 43162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk int select = movingEdges; 43262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (mFixAspectRatio && (select != MOVE_BLOCK)) { 4330f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (select == MOVE_LEFT) { 43462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk select |= MOVE_TOP; 43562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 4360f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (select == MOVE_TOP) { 43762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk select |= MOVE_LEFT; 43862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 4390f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (select == MOVE_RIGHT) { 44062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk select |= MOVE_BOTTOM; 44162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 4420f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (select == MOVE_BOTTOM) { 44362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk select |= MOVE_RIGHT; 4440f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 4450f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk RectF blank = new RectF(); 4460f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if(switchCropBounds(select, blank)){ 4470f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk setCropBounds(blank); 4480f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return; 44962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 45062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 45162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 45262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (select == MOVE_BLOCK) { 45362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF straight = getRotatedStraightenBounds(); 45462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk // Move the whole cropped bounds within the photo display bounds. 45562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk deltaX = (deltaX > 0) ? Math.min(straight.right - cropped.right, deltaX) 45662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk : Math.max(straight.left - cropped.left, deltaX); 45762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk deltaY = (deltaY > 0) ? Math.min(straight.bottom - cropped.bottom, deltaY) 45862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk : Math.max(straight.top - cropped.top, deltaY); 45962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk cropped.offset(deltaX, deltaY); 4608537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } else { 46162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float dx = 0; 46262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float dy = 0; 4630f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk 46462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if ((select & MOVE_LEFT) != 0) { 46562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk dx = Math.min(cropped.left + deltaX, cropped.right - minWidthHeight) - cropped.left; 46662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 46762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if ((select & MOVE_TOP) != 0) { 46862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk dy = Math.min(cropped.top + deltaY, cropped.bottom - minWidthHeight) - cropped.top; 46962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 47062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if ((select & MOVE_RIGHT) != 0) { 47162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk dx = Math.max(cropped.right + deltaX, cropped.left + minWidthHeight) 47262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk - cropped.right; 4738537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 47462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if ((select & MOVE_BOTTOM) != 0) { 47562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk dy = Math.max(cropped.bottom + deltaY, cropped.top + minWidthHeight) 47662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk - cropped.bottom; 4778537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 47862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 47962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (mFixAspectRatio) { 4800f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk RectF crop = getCropBoundsDisplayed(); 4810f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float [] l1 = {crop.left, crop.bottom}; 4820f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float [] l2 = {crop.right, crop.top}; 4830f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if(movingEdges == TOP_LEFT || movingEdges == BOTTOM_RIGHT){ 4840f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk l1[1] = crop.top; 4850f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk l2[1] = crop.bottom; 4860f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 4870f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float[] b = { l1[0] - l2[0], l1[1] - l2[1] }; 4880f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float[] disp = {dx, dy}; 4890f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float[] bUnit = GeometryMath.normalize(b); 4900f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float sp = GeometryMath.scalarProjection(disp, bUnit); 4910f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk dx = sp * bUnit[0]; 4920f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk dy = sp * bUnit[1]; 4930f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk RectF newCrop = fixedCornerResize(crop, select, dx * scale, dy * scale); 4940f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk Matrix m = getCropBoundDisplayMatrix(); 4950f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk Matrix m0 = new Matrix(); 4960f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (!m.invert(m0)){ 4970f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (LOGV) 4980f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk Log.v(LOGTAG, "FAILED TO INVERT CROP MATRIX"); 4990f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return; 5000f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 5010f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (!m0.mapRect(newCrop)){ 5020f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (LOGV) 5030f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk Log.v(LOGTAG, "FAILED TO MAP RECTANGLE TO RECTANGLE"); 5040f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return; 5050f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 5060f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk setCropBounds(newCrop); 5070f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return; 5080f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } else { 5090f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if ((select & MOVE_LEFT) != 0) { 5100f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk cropped.left += dx; 5110f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 5120f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if ((select & MOVE_TOP) != 0) { 5130f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk cropped.top += dy; 5140f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 5150f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if ((select & MOVE_RIGHT) != 0) { 5160f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk cropped.right += dx; 5170f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 5180f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if ((select & MOVE_BOTTOM) != 0) { 5190f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk cropped.bottom += dy; 52062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 5218537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5228537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5230f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk movingEdges = select; 5248537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk Matrix m = getCropRotationMatrix(getLocalRotation(), getLocalPhotoBounds()); 5258537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk Matrix m0 = new Matrix(); 5268537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (!m.invert(m0)) { 5278537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (LOGV) 5288537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk Log.v(LOGTAG, "FAILED TO INVERT ROTATION MATRIX"); 5298537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5308537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (!m0.mapRect(cropped)) { 5318537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (LOGV) 5328537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk Log.v(LOGTAG, "FAILED TO UNROTATE CROPPING BOUNDS"); 5338537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5348537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk setCropBounds(cropped); 5358537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5368537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 5378537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private void drawIndicator(Canvas canvas, Drawable indicator, float centerX, float centerY) { 5388537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk int left = (int) centerX - indicatorSize / 2; 5398537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk int top = (int) centerY - indicatorSize / 2; 5408537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk indicator.setBounds(left, top, left + indicatorSize, top + indicatorSize); 5418537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk indicator.draw(canvas); 5428537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5438537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 5448537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk @Override 5458537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void setActionDown(float x, float y) { 5468537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk super.setActionDown(x, y); 5478537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk detectMovingEdges(x, y); 54862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 54962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 55062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk @Override 55162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected void setActionUp() { 55262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk super.setActionUp(); 55362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk movingEdges = 0; 5548537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5558537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 5568537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk @Override 5578537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void setActionMove(float x, float y) { 5580f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (movingEdges != 0){ 5598537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk moveEdges(x - mCurrentX, y - mCurrentY); 5600f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 56162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk super.setActionMove(x, y); 56262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 56362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 56462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk private void cropSetup() { 56562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (mFixAspectRatio) { 56662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF cb = getRotatedCropBounds(); 56762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk fixAspectRatio(cb, mAspectWidth, mAspectHeight); 56862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF cb0 = getUnrotatedCropBounds(cb); 56962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk setCropBounds(cb0); 5708537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } else { 57162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk setCropBounds(getLocalCropBounds()); 5728537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5738537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5748537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 5758537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk @Override 5768537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void gainedVisibility() { 577a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk float rot = getLocalRotation(); 578a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk // if has changed orientation via rotate 579a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk if( ((int) ((rot - mLastRot) / 90)) % 2 != 0 ){ 580a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk swapAspect(); 581a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk } 58262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk cropSetup(); 58362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk mFirstDraw = true; 5848537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5858537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 58662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk @Override 58762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk public void resetParameter() { 58862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk super.resetParameter(); 58962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk cropSetup(); 59062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 591e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard 59262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk @Override 59362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected void lostVisibility() { 594a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk mLastRot = getLocalRotation(); 5958537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5968537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 597a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk private void drawRuleOfThird(Canvas canvas, RectF bounds, Paint p) { 598104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard float stepX = bounds.width() / 3.0f; 599104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard float stepY = bounds.height() / 3.0f; 600104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard float x = bounds.left + stepX; 601104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard float y = bounds.top + stepY; 602104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard for (int i = 0; i < 2; i++) { 603a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk canvas.drawLine(x, bounds.top, x, bounds.bottom, p); 604104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard x += stepX; 605104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard } 606104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard for (int j = 0; j < 2; j++) { 607a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk canvas.drawLine(bounds.left, y, bounds.right, y, p); 608104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard y += stepY; 609104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard } 610104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard } 611104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard 6128537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk @Override 6138537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void drawShape(Canvas canvas, Bitmap image) { 61462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk // TODO: move style to xml 6158537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk gPaint.setAntiAlias(true); 6168537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk gPaint.setFilterBitmap(true); 6178537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk gPaint.setDither(true); 6188537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk gPaint.setARGB(255, 255, 255, 255); 6198537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 62062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (mFirstDraw) { 62162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk cropSetup(); 62262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk mFirstDraw = false; 62362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 624e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard float rotation = getLocalRotation(); 625a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk 626a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk RectF crop = drawTransformed(canvas, image, gPaint); 627a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk gPaint.setColor(mBorderColor); 628a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk gPaint.setStrokeWidth(3); 629a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk gPaint.setStyle(Paint.Style.STROKE); 630a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk drawRuleOfThird(canvas, crop, gPaint); 63162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 632104165f1f9858bdebb2d219b077f5227203f7c02nicolasroard gPaint.setColor(mBorderColor); 63362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk gPaint.setStrokeWidth(3); 63462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk gPaint.setStyle(Paint.Style.STROKE); 63562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk drawStraighten(canvas, gPaint); 636a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk 63762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk int decoded_moving = decoder(movingEdges, rotation); 63862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.save(); 63962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.rotate(rotation, mCenterX, mCenterY); 640a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk RectF scaledCrop = unrotatedCropBounds(); 64162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk boolean notMoving = decoded_moving == 0; 64262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (((decoded_moving & MOVE_TOP) != 0) || notMoving) { 643e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.top); 6448537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 64562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (((decoded_moving & MOVE_BOTTOM) != 0) || notMoving) { 646e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.bottom); 6478537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 64862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (((decoded_moving & MOVE_LEFT) != 0) || notMoving) { 649e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard drawIndicator(canvas, cropIndicator, scaledCrop.left, scaledCrop.centerY()); 6508537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 65162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (((decoded_moving & MOVE_RIGHT) != 0) || notMoving) { 652e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard drawIndicator(canvas, cropIndicator, scaledCrop.right, scaledCrop.centerY()); 6538537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 65462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.restore(); 65562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 65662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 6570f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk private int bitCycleLeft(int x, int times, int d) { 65862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk int mask = (1 << d) - 1; 65962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk int mout = x & mask; 66062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk times %= d; 66162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk int hi = mout >> (d - times); 66262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk int low = (mout << times) & mask; 66362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk int ret = x & ~mask; 66462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk ret |= low; 66562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk ret |= hi; 66662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return ret; 6678537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 6688537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 66962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected int decoder(int movingEdges, float rotation) { 67062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk int rot = constrainedRotation(rotation); 6710f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk switch (rot) { 67262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk case 90: 67362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return bitCycleLeft(movingEdges, 3, 4); 67462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk case 180: 67562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return bitCycleLeft(movingEdges, 2, 4); 67662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk case 270: 67762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return bitCycleLeft(movingEdges, 1, 4); 67862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk default: 67962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return movingEdges; 68062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 68162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 6820f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk} 683