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.graphics.Bitmap; 218537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.graphics.Canvas; 22e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroardimport android.graphics.Color; 238537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.graphics.Matrix; 248537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.graphics.Paint; 25e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroardimport android.graphics.Paint.Style; 268537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.graphics.Path; 278537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.graphics.RectF; 288537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.util.AttributeSet; 298537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.view.MotionEvent; 308537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport android.view.View; 318537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 328537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport com.android.gallery3d.filtershow.imageshow.GeometryMetadata.FLIP; 338537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkimport com.android.gallery3d.filtershow.presets.ImagePreset; 348537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 358537d097f8827caedc8c39564de54d36eae8b16fRuben Brunkpublic abstract class ImageGeometry extends ImageSlave { 368537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private boolean mVisibilityGained = false; 378537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private boolean mHasDrawn = false; 388537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 398537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected static final float MAX_STRAIGHTEN_ANGLE = 45; 408537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected static final float MIN_STRAIGHTEN_ANGLE = -45; 418537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 428537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected float mCenterX; 438537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected float mCenterY; 448537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 458537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected float mCurrentX; 468537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected float mCurrentY; 478537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected float mTouchCenterX; 488537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected float mTouchCenterY; 498537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 508537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk // Local geometry data 5162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk private GeometryMetadata mLocalGeometry = null; 528537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private RectF mLocalDisplayBounds = null; 538537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected float mXOffset = 0; 548537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected float mYOffset = 0; 558537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 568537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected enum MODES { 578537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk NONE, DOWN, UP, MOVE 588537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 598537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 608537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected MODES mMode = MODES.NONE; 618537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 628537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private static final String LOGTAG = "ImageGeometry"; 638537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 648537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk public ImageGeometry(Context context, AttributeSet attrs) { 658537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk super(context, attrs); 668537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 678537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 688537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk public ImageGeometry(Context context) { 698537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk super(context); 708537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 718537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 728537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private void setupLocalDisplayBounds(RectF b) { 738537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mLocalDisplayBounds = b; 748537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk calculateLocalScalingFactorAndOffset(); 758537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 768537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 770f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk protected static float angleFor(float dx, float dy) { 780f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return (float) (Math.atan2(dx, dy) * 180 / Math.PI); 790f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 800f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk 810f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk protected static int snappedAngle(float angle) { 820f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float remainder = angle % 90; 830f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk int current = (int) (angle / 90); // truncates 840f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (remainder < -45) { 850f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk --current; 860f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } else if (remainder > 45) { 870f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk ++current; 880f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 890f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return current * 90; 900f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 910f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk 92eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk protected float getCurrentTouchAngle() { 930f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk if (mCurrentX == mTouchCenterX && mCurrentY == mTouchCenterY) { 940f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return 0; 950f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 960f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float dX1 = mTouchCenterX - mCenterX; 970f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float dY1 = mTouchCenterY - mCenterY; 980f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float dX2 = mCurrentX - mCenterX; 990f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float dY2 = mCurrentY - mCenterY; 1000f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk 1010f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float angleA = angleFor(dX1, dY1); 1020f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk float angleB = angleFor(dX2, dY2); 1030f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk return (angleB - angleA) % 360; 1040f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk } 1050f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk 10662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected float computeScale(float width, float height) { 10762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float imageWidth = mLocalGeometry.getPhotoBounds().width(); 10862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float imageHeight = mLocalGeometry.getPhotoBounds().height(); 109eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk return GeometryMath.scale(imageWidth, imageHeight, width, height); 110e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard } 111e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard 1128537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk private void calculateLocalScalingFactorAndOffset() { 11362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (mLocalGeometry == null || mLocalDisplayBounds == null) 1148537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return; 11562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF imageBounds = mLocalGeometry.getPhotoBounds(); 1168537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float imageWidth = imageBounds.width(); 1178537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float imageHeight = imageBounds.height(); 1188537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float displayWidth = mLocalDisplayBounds.width(); 1198537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float displayHeight = mLocalDisplayBounds.height(); 1208537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 1218537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mCenterX = displayWidth / 2; 1228537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mCenterY = displayHeight / 2; 1238537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mYOffset = (displayHeight - imageHeight) / 2.0f; 1248537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mXOffset = (displayWidth - imageWidth) / 2.0f; 12562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk updateScale(); 1268537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 1278537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 1288537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk @Override 1298537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk public void resetParameter() { 1308537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk super.resetParameter(); 1318537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk setLocalRotation(0); 1328537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk setLocalStraighten(0); 1338537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk setLocalCropBounds(getLocalPhotoBounds()); 1348537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk setLocalFlip(FLIP.NONE); 1358537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk saveAndSetPreset(); 1368537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk invalidate(); 1378537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 1388537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 1398537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk // Overwrites local with master 1408537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void syncLocalToMasterGeometry() { 14162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk mLocalGeometry = getMaster().getGeometry(); 1428537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk calculateLocalScalingFactorAndOffset(); 1438537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 1448537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 1458537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected RectF getLocalPhotoBounds() { 14662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return mLocalGeometry.getPhotoBounds(); 1478537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 1488537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 1498537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected RectF getLocalCropBounds() { 150b470b229fbfd782db6758f331e4a6f918e305b02nicolasroard return mLocalGeometry.getPreviewCropBounds(); 1518537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 1528537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 1538537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected RectF getLocalDisplayBounds() { 1548537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return new RectF(mLocalDisplayBounds); 1558537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 1568537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 1578537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected float getLocalScale() { 15862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return mLocalGeometry.getScaleFactor(); 1598537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 1608537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 1618537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected float getLocalRotation() { 16262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return mLocalGeometry.getRotation(); 1638537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 1648537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 1658537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected float getLocalStraighten() { 16662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return mLocalGeometry.getStraightenRotation(); 1678537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 1688537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 1698537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void setLocalScale(float s) { 17062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk mLocalGeometry.setScaleFactor(s); 1718537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 1728537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 17362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected void updateScale() { 17462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF bounds = getUntranslatedStraightenCropBounds(mLocalGeometry.getPhotoBounds(), 175e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard getLocalStraighten()); 176e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard float zoom = computeScale(bounds.width(), bounds.height()); 177e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard setLocalScale(zoom); 178e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard } 179e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard 1808537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void setLocalRotation(float r) { 18162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk mLocalGeometry.setRotation(r); 18246163a396828fa000b4a53cf87811e4111e3cb88Ruben Brunk updateScale(); 18346163a396828fa000b4a53cf87811e4111e3cb88Ruben Brunk } 18446163a396828fa000b4a53cf87811e4111e3cb88Ruben Brunk 18562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk /** 18662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk * Constrains rotation to be in [0, 90, 180, 270]. 18762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk */ 18862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected int constrainedRotation(float rotation) { 18962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk int r = (int) ((rotation % 360) / 90); 19062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk r = (r < 0) ? (r + 4) : r; 19162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return r * 90; 19262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 19362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 19462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected Matrix getLocalGeoFlipMatrix(float width, float height) { 19562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return mLocalGeometry.getFlipMatrix(width, height); 1968537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 1978537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 1988537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void setLocalStraighten(float r) { 19962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk mLocalGeometry.setStraightenRotation(r); 20046163a396828fa000b4a53cf87811e4111e3cb88Ruben Brunk updateScale(); 2018537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2028537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2038537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void setLocalCropBounds(RectF c) { 20462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk mLocalGeometry.setCropBounds(c); 20562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk updateScale(); 2068537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2078537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2088537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected FLIP getLocalFlip() { 20962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return mLocalGeometry.getFlipType(); 2108537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2118537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2128537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void setLocalFlip(FLIP flip) { 21362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk mLocalGeometry.setFlipType(flip); 2148537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2158537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2168537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected float getTotalLocalRotation() { 2178537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return getLocalRotation() + getLocalStraighten(); 2188537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2198537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2208537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected static float[] getCornersFromRect(RectF r) { 2218537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk // Order is: 2228537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk // 0------->1 22362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk // ^ | 22462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk // | v 2258537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk // 3<-------2 2268537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float[] corners = { 2278537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk r.left, r.top, // 0 2288537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk r.right, r.top, // 1 2298537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk r.right, r.bottom,// 2 23062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk r.left, r.bottom // 3 231e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard }; 2328537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return corners; 2338537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2348537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2358537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk // If edge point [x, y] in array [x0, y0, x1, y1, ...] is outside of the 2368537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk // image bound rectangle, clamps it to the edge of the rectangle. 2378537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected static void getEdgePoints(RectF imageBound, float[] array) { 2388537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (array.length < 2) 2398537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return; 2408537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk for (int x = 0; x < array.length; x += 2) { 2410f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk array[x] = GeometryMath.clamp(array[x], imageBound.left, imageBound.right); 2420f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk array[x + 1] = GeometryMath.clamp(array[x + 1], imageBound.top, imageBound.bottom); 2438537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2448537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2458537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2468537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected static Path drawClosedPath(Canvas canvas, Paint paint, float[] points) { 2478537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk Path crop = new Path(); 2488537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk crop.moveTo(points[0], points[1]); 2498537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk crop.lineTo(points[2], points[3]); 2508537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk crop.lineTo(points[4], points[5]); 2518537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk crop.lineTo(points[6], points[7]); 2528537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk crop.close(); 2538537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk canvas.drawPath(crop, paint); 2548537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return crop; 2558537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2568537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2578537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected static void fixAspectRatio(RectF r, float w, float h) { 2588537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float scale = Math.min(r.width() / w, r.height() / h); 25962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float centX = r.centerX(); 26062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float centY = r.centerY(); 26162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float hw = scale * w / 2; 26262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float hh = scale * h / 2; 26362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk r.set(centX - hw, centY - hh, centX + hw, centY + hh); 26462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 2658537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2668537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2678537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected static float getNewHeightForWidthAspect(float width, float w, float h) { 2688537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return width * h / w; 2698537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2708537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2718537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected static float getNewWidthForHeightAspect(float height, float w, float h) { 2728537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return height * w / h; 2738537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2748537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2758537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk @Override 2768537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void onVisibilityChanged(View changedView, int visibility) { 2778537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk super.onVisibilityChanged(changedView, visibility); 2788537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (visibility == View.VISIBLE) { 2798537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mVisibilityGained = true; 2808537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk syncLocalToMasterGeometry(); 28162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk updateScale(); 2828537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk gainedVisibility(); 2838537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } else { 2848537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (mVisibilityGained == true && mHasDrawn == true) { 2858537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk lostVisibility(); 2868537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2878537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mVisibilityGained = false; 2888537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mHasDrawn = false; 2898537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2908537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2918537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2928537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void gainedVisibility() { 2938537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk // TODO: Override this stub. 2948537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2958537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 2968537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void lostVisibility() { 2978537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk // TODO: Override this stub. 2988537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 2998537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3008537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk @Override 3018537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void onSizeChanged(int w, int h, int oldw, int oldh) { 3028537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk super.onSizeChanged(w, h, oldw, oldh); 3038537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk setupLocalDisplayBounds(new RectF(0, 0, w, h)); 3048537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3058537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3068537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk @Override 3078537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk public boolean onTouchEvent(MotionEvent event) { 3088537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk switch (event.getActionMasked()) { 3098537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk case (MotionEvent.ACTION_DOWN): 3108537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk setActionDown(event.getX(), event.getY()); 3118537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk break; 3128537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk case (MotionEvent.ACTION_UP): 3138537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk setActionUp(); 3148537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk saveAndSetPreset(); 3158537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk break; 3168537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk case (MotionEvent.ACTION_MOVE): 3178537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk setActionMove(event.getX(), event.getY()); 3188537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk break; 3198537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk default: 3208537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk setNoAction(); 3218537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3228537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (getPanelController() != null) { 323e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard getPanelController().onNewValue(getLocalValue()); 3248537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3258537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk invalidate(); 3268537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return true; 3278537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3288537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3298537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected int getLocalValue() { 3308537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return 0; // TODO: Override this 3318537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3328537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3338537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void setActionDown(float x, float y) { 3348537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mTouchCenterX = x; 3358537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mTouchCenterY = y; 3368537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mCurrentX = x; 3378537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mCurrentY = y; 3388537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mMode = MODES.DOWN; 3398537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3408537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3418537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void setActionMove(float x, float y) { 3428537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mCurrentX = x; 3438537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mCurrentY = y; 3448537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mMode = MODES.MOVE; 3458537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3468537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3478537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void setActionUp() { 3488537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mMode = MODES.UP; 3498537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3508537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3518537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void setNoAction() { 3528537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mMode = MODES.NONE; 3538537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3548537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3558537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk @Override 3568537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk public boolean showTitle() { 3578537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return false; 3588537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3598537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 360d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard public String getName() { 361d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard return "Geometry"; 362d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard } 363d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard 3647f999551167ce313e36ba35e3682593f8cf80e52Ruben Brunk public void saveAndSetPreset() { 365d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard ImagePreset lastHistoryItem = getHistory().getLast(); 366d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard if (lastHistoryItem != null && lastHistoryItem.historyName().equalsIgnoreCase(getName())) { 367d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard getImagePreset().setGeometry(mLocalGeometry); 36831529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard resetImageCaches(this); 369d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard } else { 370a2a4c9a985d789e853211f21cd265460f16d2de1John Hoford if (mLocalGeometry.hasModifications()) { 371a2a4c9a985d789e853211f21cd265460f16d2de1John Hoford ImagePreset copy = new ImagePreset(getImagePreset()); 372a2a4c9a985d789e853211f21cd265460f16d2de1John Hoford copy.setGeometry(mLocalGeometry); 373a2a4c9a985d789e853211f21cd265460f16d2de1John Hoford copy.setHistoryName(getName()); 374a2a4c9a985d789e853211f21cd265460f16d2de1John Hoford copy.setIsFx(false); 375a2a4c9a985d789e853211f21cd265460f16d2de1John Hoford setImagePreset(copy, true); 376a2a4c9a985d789e853211f21cd265460f16d2de1John Hoford } 377d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard } 378d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard invalidate(); 3798537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3808537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 381a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk public static RectF getUntranslatedStraightenCropBounds(RectF imageRect, float straightenAngle) { 3828537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float deg = straightenAngle; 3838537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (deg < 0) { 3848537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk deg = -deg; 3858537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 3868537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk double a = Math.toRadians(deg); 3878537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk double sina = Math.sin(a); 3888537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk double cosa = Math.cos(a); 3898537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3908537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk double rw = imageRect.width(); 3918537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk double rh = imageRect.height(); 3928537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk double h1 = rh * rh / (rw * sina + rh * cosa); 3938537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk double h2 = rh * rw / (rw * cosa + rh * sina); 3948537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk double hh = Math.min(h1, h2); 3958537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk double ww = hh * rw / rh; 3968537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 3978537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float left = (float) ((rw - ww) * 0.5f); 3988537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float top = (float) ((rh - hh) * 0.5f); 3998537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float right = (float) (left + ww); 4008537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk float bottom = (float) (top + hh); 4018537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 402a66df0c9e8106ef6a275e20ab2a47286e054fe7cRuben Brunk return new RectF(left, top, right, bottom); 4038537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 4048537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 40562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected Matrix getGeoMatrix(RectF r, boolean onlyRotate) { 406eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk RectF pbounds = getLocalPhotoBounds(); 407eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk float scale = GeometryMath 408eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk .scale(pbounds.width(), pbounds.height(), getWidth(), getHeight()); 409eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk if (((int) (getLocalRotation() / 90)) % 2 != 0) { 410eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk scale = GeometryMath.scale(pbounds.width(), pbounds.height(), getHeight(), getWidth()); 411eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk } 41262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float yoff = getHeight() / 2; 41362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float xoff = getWidth() / 2; 41462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float w = r.left * 2 + r.width(); 41562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float h = r.top * 2 + r.height(); 41662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return mLocalGeometry.buildGeometryMatrix(w, h, scale, xoff, yoff, onlyRotate); 41762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 41862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 41962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected void drawImageBitmap(Canvas canvas, Bitmap bitmap, Paint paint, Matrix m) { 420e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard canvas.save(); 42162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.drawBitmap(bitmap, m, paint); 422e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard canvas.restore(); 423e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard } 424e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard 42562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected void drawImageBitmap(Canvas canvas, Bitmap bitmap, Paint paint) { 42662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float scale = computeScale(getWidth(), getHeight()); 42762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float yoff = getHeight() / 2; 42862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float xoff = getWidth() / 2; 42962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk Matrix m = mLocalGeometry.buildGeometryUIMatrix(scale, xoff, yoff); 43062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk drawImageBitmap(canvas, bitmap, paint, m); 431e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard } 432e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard 43362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected RectF straightenBounds() { 434e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard RectF bounds = getUntranslatedStraightenCropBounds(getLocalPhotoBounds(), 435e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard getLocalStraighten()); 43662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk Matrix m = getGeoMatrix(bounds, true); 43762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk m.mapRect(bounds); 43862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return bounds; 439e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard } 440e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard 44162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected void drawStraighten(Canvas canvas, Paint paint) { 44262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF bounds = straightenBounds(); 44346163a396828fa000b4a53cf87811e4111e3cb88Ruben Brunk canvas.save(); 44462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.drawRect(bounds, paint); 44562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.restore(); 44646163a396828fa000b4a53cf87811e4111e3cb88Ruben Brunk } 44746163a396828fa000b4a53cf87811e4111e3cb88Ruben Brunk 44862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected RectF unrotatedCropBounds() { 44962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF bounds = getLocalCropBounds(); 45062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF pbounds = getLocalPhotoBounds(); 45162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float scale = computeScale(getWidth(), getHeight()); 45262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float yoff = getHeight() / 2; 45362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float xoff = getWidth() / 2; 454eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk Matrix m = mLocalGeometry.buildGeometryMatrix(pbounds.width(), pbounds.height(), scale, 455eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk xoff, yoff, 0); 45662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk m.mapRect(bounds); 45762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return bounds; 45862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 45962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 46062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected RectF cropBounds() { 46162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF bounds = getLocalCropBounds(); 46262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk Matrix m = getGeoMatrix(getLocalPhotoBounds(), true); 46362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk m.mapRect(bounds); 46462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk return bounds; 46562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 46662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk 46762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk // Fails for non-90 degree 46862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected void drawCrop(Canvas canvas, Paint paint) { 46962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF bounds = cropBounds(); 470e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard canvas.save(); 471e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard canvas.drawRect(bounds, paint); 472e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard canvas.restore(); 47362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } 474e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard 47562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected void drawCropSafe(Canvas canvas, Paint paint) { 47662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk Matrix m = getGeoMatrix(getLocalPhotoBounds(), true); 47762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF crop = getLocalCropBounds(); 47862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk if (!m.rectStaysRect()) { 47962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float[] corners = getCornersFromRect(crop); 48062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk m.mapPoints(corners); 48162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk drawClosedPath(canvas, paint, corners); 48262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk } else { 48362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk m.mapRect(crop); 48462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk Path path = new Path(); 48562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk path.addRect(crop, Path.Direction.CCW); 48662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.drawPath(path, paint); 487e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard } 488e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard } 489e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard 49062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected void drawTransformedBitmap(Canvas canvas, Bitmap bitmap, Paint paint, boolean clip) { 49162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk paint.setARGB(255, 0, 0, 0); 49262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk drawImageBitmap(canvas, bitmap, paint); 49362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk paint.setColor(Color.WHITE); 49462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk paint.setStyle(Style.STROKE); 49562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk paint.setStrokeWidth(2); 49662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk drawCropSafe(canvas, paint); 4978d8cdf7f67db69309fd740ca301fbeaadac8a9f0nicolasroard paint.setColor(getDefaultBackgroundColor()); 49862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk paint.setStyle(Paint.Style.FILL); 49962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk drawShadows(canvas, paint, unrotatedCropBounds()); 500e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard } 501e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard 50262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected void drawShadows(Canvas canvas, Paint p, RectF innerBounds) { 50362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk RectF display = new RectF(0, 0, getWidth(), getHeight()); 50462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk drawShadows(canvas, p, innerBounds, display, getLocalRotation(), getWidth() / 2, 50562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk getHeight() / 2); 506e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard } 507e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard 50862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk protected static void drawShadows(Canvas canvas, Paint p, RectF innerBounds, RectF outerBounds, 50962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float rotation, float centerX, float centerY) { 51062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.save(); 51162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.rotate(rotation, centerX, centerY); 512e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard 51362e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float x = (outerBounds.left - outerBounds.right); 51462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float y = (outerBounds.top - outerBounds.bottom); 51562e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float longest = (float) Math.sqrt(x * x + y * y) / 2; 51662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float minX = centerX - longest; 51762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float maxX = centerX + longest; 51862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float minY = centerY - longest; 51962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk float maxY = centerY + longest; 52062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.drawRect(minX, minY, innerBounds.right, innerBounds.top, p); 52162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.drawRect(minX, innerBounds.top, innerBounds.left, maxY, p); 52262e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.drawRect(innerBounds.left, innerBounds.bottom, maxX, maxY, 5238537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk p); 52462e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.drawRect(innerBounds.right, minY, maxX, 5258537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk innerBounds.bottom, p); 52662e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.rotate(-rotation, centerX, centerY); 52762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk canvas.restore(); 5288537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5298537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 5308537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk @Override 5318537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk public void onDraw(Canvas canvas) { 5328537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (getDirtyGeometryFlag()) { 5338537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk syncLocalToMasterGeometry(); 5348537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk clearDirtyGeometryFlag(); 5358537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 53631529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard requestFilteredImages(); 53731529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard Bitmap image = getMaster().getFiltersOnlyImage(); 5388537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk if (image == null) { 53931529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard invalidate(); 5408537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk return; 5418537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5428537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk mHasDrawn = true; 5438537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk drawShape(canvas, image); 5448537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 5458537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk 5468537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk protected void drawShape(Canvas canvas, Bitmap image) { 5478537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk // TODO: Override this stub. 5488537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk } 549a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk 550eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk protected RectF drawTransformed(Canvas canvas, Bitmap photo, Paint p) { 551a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk p.setARGB(255, 0, 0, 0); 552a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk RectF photoBounds = getLocalPhotoBounds(); 553a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk RectF cropBounds = getLocalCropBounds(); 554a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk float scale = computeScale(getWidth(), getHeight()); 555eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk // checks if local rotation is an odd multiple of 90. 556eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk if (((int) (getLocalRotation() / 90)) % 2 != 0) { 557eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk scale = computeScale(getHeight(), getWidth()); 558eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk } 559a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk // put in screen coordinates 560a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk RectF scaledCrop = GeometryMath.scaleRect(cropBounds, scale); 561a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk RectF scaledPhoto = GeometryMath.scaleRect(photoBounds, scale); 562eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk float[] displayCenter = { 563eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk getWidth() / 2f, getHeight() / 2f 564eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk }; 565a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk Matrix m = GeometryMetadata.buildCenteredPhotoMatrix(scaledPhoto, scaledCrop, 566a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk getLocalRotation(), getLocalStraighten(), getLocalFlip(), displayCenter); 567a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk 568a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk Matrix m1 = GeometryMetadata.buildWanderingCropMatrix(scaledPhoto, scaledCrop, 569a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk getLocalRotation(), getLocalStraighten(), getLocalFlip(), displayCenter); 570a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk m1.mapRect(scaledCrop); 571a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk Path path = new Path(); 572a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk path.addRect(scaledCrop, Path.Direction.CCW); 573a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk 574a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk m.preScale(scale, scale); 575a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk canvas.save(); 576a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk canvas.drawBitmap(photo, m, p); 577a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk canvas.restore(); 578a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk 579a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk p.setColor(Color.WHITE); 580a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk p.setStyle(Style.STROKE); 581a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk p.setStrokeWidth(2); 582a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk canvas.drawPath(path, p); 583a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk return scaledCrop; 584a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk } 585a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk 586eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk protected void drawTransformedCropped(Canvas canvas, Bitmap photo, Paint p) { 587a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk RectF photoBounds = getLocalPhotoBounds(); 588a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk RectF cropBounds = getLocalCropBounds(); 589a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk float imageWidth = cropBounds.width(); 590a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk float imageHeight = cropBounds.height(); 591eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk float scale = GeometryMath.scale(imageWidth, imageHeight, getWidth(), getHeight()); 592eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk // checks if local rotation is an odd multiple of 90. 593eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk if (((int) (getLocalRotation() / 90)) % 2 != 0) { 594eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk scale = GeometryMath.scale(imageWidth, imageHeight, getHeight(), getWidth()); 595a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk } 596a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk // put in screen coordinates 597a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk RectF scaledCrop = GeometryMath.scaleRect(cropBounds, scale); 598a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk RectF scaledPhoto = GeometryMath.scaleRect(photoBounds, scale); 599eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk float[] displayCenter = { 600eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk getWidth() / 2f, getHeight() / 2f 601eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk }; 602a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk Matrix m1 = GeometryMetadata.buildWanderingCropMatrix(scaledPhoto, scaledCrop, 603a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk getLocalRotation(), getLocalStraighten(), getLocalFlip(), displayCenter); 604eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk float[] cropCenter = { 605eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk scaledCrop.centerX(), scaledCrop.centerY() 606eb75699bcd5762a9ffd7ee0d4d14a4e5eb2e2389Ruben Brunk }; 607a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk m1.mapPoints(cropCenter); 608a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk GeometryMetadata.concatRecenterMatrix(m1, cropCenter, displayCenter); 609a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk m1.preRotate(getLocalStraighten(), scaledPhoto.centerX(), scaledPhoto.centerY()); 610a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk m1.preScale(scale, scale); 611a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk 612a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk p.setARGB(255, 0, 0, 0); 613a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk canvas.save(); 614a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk canvas.drawBitmap(photo, m1, p); 615a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk canvas.restore(); 616a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk 6178d8cdf7f67db69309fd740ca301fbeaadac8a9f0nicolasroard p.setColor(getDefaultBackgroundColor()); 618a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk p.setStyle(Paint.Style.FILL); 619a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk scaledCrop.offset(displayCenter[0] - scaledCrop.centerX(), displayCenter[1] 620a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk - scaledCrop.centerY()); 621a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk drawShadows(canvas, p, scaledCrop); 622a41224997ef9be9c0d04534f7b6b9c6b933bfe05Ruben Brunk } 6238537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk} 624