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 */
160d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
170d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardpackage com.android.gallery3d.filtershow.imageshow;
180d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
197a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroardimport android.animation.ValueAnimator;
200d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.content.Context;
210d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.graphics.Bitmap;
220d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.graphics.Canvas;
23b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkimport android.graphics.Color;
24b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkimport android.graphics.Matrix;
250d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.graphics.Paint;
26b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkimport android.graphics.Paint.Style;
27b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkimport android.graphics.Path;
280d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.graphics.RectF;
290d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.util.AttributeSet;
30b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkimport android.view.MotionEvent;
3192e2341248e99c691f38820503984bc5e2f18811nicolasroard
32805a7fe57da2534462f4720abc7fe9cdb8f7ecc9John Hofordimport com.android.gallery3d.filtershow.crop.CropDrawingUtils;
33d61a2f9fcaad0309132b6b9b666c3dc6df62fed7John Hofordimport com.android.gallery3d.filtershow.editors.EditorStraighten;
34b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkimport com.android.gallery3d.filtershow.filters.FilterCropRepresentation;
35b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkimport com.android.gallery3d.filtershow.filters.FilterRepresentation;
36b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkimport com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation;
37b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkimport com.android.gallery3d.filtershow.imageshow.GeometryMathUtils.GeometryHolder;
380a32b7afc5286a5c7aa334b9338591d61a49731fRuben Brunk
39b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkimport java.util.ArrayList;
40b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkimport java.util.Collection;
410d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
42b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk
43b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunkpublic class ImageStraighten extends ImageShow {
44b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private static final String TAG = ImageStraighten.class.getSimpleName();
450d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private float mBaseAngle = 0;
460d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private float mAngle = 0;
47b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private float mInitialAngle = 0;
48805a7fe57da2534462f4720abc7fe9cdb8f7ecc9John Hoford    private static final int NBLINES = 16;
49b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private boolean mFirstDrawSinceUp = false;
50d61a2f9fcaad0309132b6b9b666c3dc6df62fed7John Hoford    private EditorStraighten mEditorStraighten;
51b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private FilterStraightenRepresentation mLocalRep = new FilterStraightenRepresentation();
52b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private RectF mPriorCropAtUp = new RectF();
53b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private RectF mDrawRect = new RectF();
54b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private Path mDrawPath = new Path();
55b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private GeometryHolder mDrawHolder = new GeometryHolder();
56b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private enum MODES {
57b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        NONE, MOVE
58b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    }
59b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private MODES mState = MODES.NONE;
607a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard    private ValueAnimator mAnimator = null;
617a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard    private int mDefaultGridAlpha = 60;
627a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard    private float mGridAlpha = 1f;
637a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard    private int mOnStartAnimDelay = 1000;
647a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard    private int mAnimDelay = 500;
65b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private static final float MAX_STRAIGHTEN_ANGLE
66b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        = FilterStraightenRepresentation.MAX_STRAIGHTEN_ANGLE;
67b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private static final float MIN_STRAIGHTEN_ANGLE
68b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        = FilterStraightenRepresentation.MIN_STRAIGHTEN_ANGLE;
69b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private float mCurrentX;
70b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private float mCurrentY;
71b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private float mTouchCenterX;
72b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private float mTouchCenterY;
73b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private RectF mCrop = new RectF();
74b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private final Paint mPaint = new Paint();
750d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
760d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    public ImageStraighten(Context context) {
770d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        super(context);
780d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
790d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
800d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    public ImageStraighten(Context context, AttributeSet attrs) {
810d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        super(context, attrs);
820d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
830d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
847a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard    @Override
857a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard    public void attach() {
867a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard        super.attach();
877a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard        mGridAlpha = 1f;
887a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard        hidesGrid(mOnStartAnimDelay);
897a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard    }
907a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard
917a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard    private void hidesGrid(int delay) {
927a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard        mAnimator = ValueAnimator.ofFloat(1, 0);
937a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard        mAnimator.setStartDelay(delay);
947a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard        mAnimator.setDuration(mAnimDelay);
957a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
967a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard            @Override
977a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard            public void onAnimationUpdate(ValueAnimator animation) {
987a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard                mGridAlpha = ((Float) animation.getAnimatedValue());
997a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard                invalidate();
1007a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard            }
1017a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard        });
1027a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard        mAnimator.start();
1037a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard    }
1047a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard
105b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    public void setFilterStraightenRepresentation(FilterStraightenRepresentation rep) {
106b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mLocalRep = (rep == null) ? new FilterStraightenRepresentation() : rep;
107b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mInitialAngle = mBaseAngle = mAngle = mLocalRep.getStraighten();
10892e2341248e99c691f38820503984bc5e2f18811nicolasroard    }
10992e2341248e99c691f38820503984bc5e2f18811nicolasroard
110b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    public Collection<FilterRepresentation> getFinalRepresentation() {
111b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        ArrayList<FilterRepresentation> reps = new ArrayList<FilterRepresentation>(2);
112b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        reps.add(mLocalRep);
113b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        if (mInitialAngle != mLocalRep.getStraighten()) {
114b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            reps.add(new FilterCropRepresentation(mCrop));
115b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        }
116b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        return reps;
11762e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk    }
11862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk
11992e2341248e99c691f38820503984bc5e2f18811nicolasroard    @Override
120b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    public boolean onTouchEvent(MotionEvent event) {
121b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float x = event.getX();
122b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float y = event.getY();
123b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk
124b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        switch (event.getActionMasked()) {
125b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            case (MotionEvent.ACTION_DOWN):
126b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                if (mState == MODES.NONE) {
127b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    mTouchCenterX = x;
128b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    mTouchCenterY = y;
129b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    mCurrentX = x;
130b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    mCurrentY = y;
131b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    mState = MODES.MOVE;
132b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    mBaseAngle = mAngle;
133b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                }
134b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                break;
135b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            case (MotionEvent.ACTION_UP):
136b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                if (mState == MODES.MOVE) {
137b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    mState = MODES.NONE;
138b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    mCurrentX = x;
139b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    mCurrentY = y;
140b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    computeValue();
141b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    mFirstDrawSinceUp = true;
1427a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard                    hidesGrid(0);
143b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                }
144b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                break;
145b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            case (MotionEvent.ACTION_MOVE):
146b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                if (mState == MODES.MOVE) {
147b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    mCurrentX = x;
148b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    mCurrentY = y;
149b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                    computeValue();
150b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                }
151b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                break;
152b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            default:
153b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                break;
154b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        }
155b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        invalidate();
156b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        return true;
157b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    }
158b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk
159b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private static float angleFor(float dx, float dy) {
160b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        return (float) (Math.atan2(dx, dy) * 180 / Math.PI);
161b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    }
162b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk
163b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private float getCurrentTouchAngle() {
164b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float centerX = getWidth() / 2f;
165b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float centerY = getHeight() / 2f;
166b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        if (mCurrentX == mTouchCenterX && mCurrentY == mTouchCenterY) {
167b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            return 0;
168b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        }
169b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float dX1 = mTouchCenterX - centerX;
170b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float dY1 = mTouchCenterY - centerY;
171b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float dX2 = mCurrentX - centerX;
172b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float dY2 = mCurrentY - centerY;
173b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float angleA = angleFor(dX1, dY1);
174b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float angleB = angleFor(dX2, dY2);
175b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        return (angleB - angleA) % 360;
1760d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
1770d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
1780d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    private void computeValue() {
1790f7dc6ef6e736c0993240450b50b91721c79c43eRuben Brunk        float angle = getCurrentTouchAngle();
1800d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        mAngle = (mBaseAngle - angle) % 360;
1818537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk        mAngle = Math.max(MIN_STRAIGHTEN_ANGLE, mAngle);
1828537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk        mAngle = Math.min(MAX_STRAIGHTEN_ANGLE, mAngle);
1830d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
1840d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
185430e46b06f8e7ee1ca3e7ecdcef3e0a978637c03nicolasroard    public static void getUntranslatedStraightenCropBounds(RectF outRect, float straightenAngle) {
186b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float deg = straightenAngle;
187b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        if (deg < 0) {
188b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            deg = -deg;
189b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        }
190b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        double a = Math.toRadians(deg);
191b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        double sina = Math.sin(a);
192b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        double cosa = Math.cos(a);
193b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        double rw = outRect.width();
194b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        double rh = outRect.height();
195b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        double h1 = rh * rh / (rw * sina + rh * cosa);
196b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        double h2 = rh * rw / (rw * cosa + rh * sina);
197b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        double hh = Math.min(h1, h2);
198b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        double ww = hh * rw / rh;
199b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float left = (float) ((rw - ww) * 0.5f);
200b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float top = (float) ((rh - hh) * 0.5f);
201b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float right = (float) (left + ww);
202b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        float bottom = (float) (top + hh);
203b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        outRect.set(left, top, right, bottom);
2048537d097f8827caedc8c39564de54d36eae8b16fRuben Brunk    }
2050d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
206b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    private void updateCurrentCrop(Matrix m, GeometryHolder h, RectF tmp, int imageWidth,
207b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            int imageHeight, int viewWidth, int viewHeight) {
208ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford        tmp.set(0, 0, imageHeight, imageWidth);
209ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford        m.mapRect(tmp);
210ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford        float top = tmp.top;
211ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford        float bottom = tmp.bottom;
212ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford        float left = tmp.left;
213ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford        float right = tmp.right;
214ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford        m.mapRect(tmp);
215ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford        int iw,ih;
216b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        if (GeometryMathUtils.needsDimensionSwap(h.rotation)) {
217b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            tmp.set(0, 0, imageHeight, imageWidth);
218ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford            iw = imageHeight;
219ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford            ih = imageWidth;
220b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        } else {
221b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            tmp.set(0, 0, imageWidth, imageHeight);
222ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford            iw = imageWidth;
223ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford            ih = imageHeight;
224b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        }
225ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford        float scale = GeometryMathUtils.scale(iw, ih, viewWidth, viewHeight);
226ec1f915006e5ec2db8be633b5d3d73e568951da4John Hoford        scale *= GeometryMathUtils.SHOW_SCALE;
227b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        GeometryMathUtils.scaleRect(tmp, scale);
228b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        getUntranslatedStraightenCropBounds(tmp, mAngle);
229b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        tmp.offset(viewWidth / 2f - tmp.centerX(), viewHeight / 2f - tmp.centerY());
230b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        h.straighten = 0;
231b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        Matrix m1 = GeometryMathUtils.getFullGeometryToScreenMatrix(h, imageWidth,
232b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                imageHeight, viewWidth, viewHeight);
233b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        m.reset();
234b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        m1.invert(m);
235b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mCrop.set(tmp);
236b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        m.mapRect(mCrop);
237b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        FilterCropRepresentation.findNormalizedCrop(mCrop, imageWidth, imageHeight);
23862e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk    }
23962e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk
24062e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk
24162e962bcb9fc03f3cfeac5ece8d3e95fc2dd0718Ruben Brunk    @Override
242b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk    public void onDraw(Canvas canvas) {
243b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        MasterImage master = MasterImage.getImage();
244b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        Bitmap image = master.getFiltersOnlyImage();
245b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        if (image == null) {
24680b216d5c8e17e0358cf1508a1e177ccada8383fnicolasroard            MasterImage.getImage().invalidateFiltersOnly();
247b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            return;
248b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        }
249b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        GeometryMathUtils.initializeHolder(mDrawHolder, mLocalRep);
250b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mDrawHolder.straighten = mAngle;
251b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        int imageWidth = image.getWidth();
252b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        int imageHeight = image.getHeight();
253b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        int viewWidth = canvas.getWidth();
254b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        int viewHeight = canvas.getHeight();
2550d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
256b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        // Get matrix for drawing bitmap
257b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        Matrix m = GeometryMathUtils.getFullGeometryToScreenMatrix(mDrawHolder, imageWidth,
258b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                imageHeight, viewWidth, viewHeight);
259b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mPaint.reset();
260b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mPaint.setAntiAlias(true);
261b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mPaint.setFilterBitmap(true);
262b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        canvas.drawBitmap(image, m, mPaint);
2630d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
264b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mPaint.setFilterBitmap(false);
265b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mPaint.setColor(Color.WHITE);
266b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mPaint.setStrokeWidth(2);
267b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
268b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        updateCurrentCrop(m, mDrawHolder, mDrawRect, imageWidth,
269b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                imageHeight, viewWidth, viewHeight);
270b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        if (mFirstDrawSinceUp) {
271b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            mPriorCropAtUp.set(mCrop);
272b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            mLocalRep.setStraighten(mAngle);
273b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            mFirstDrawSinceUp = false;
274b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        }
275805a7fe57da2534462f4720abc7fe9cdb8f7ecc9John Hoford        CropDrawingUtils.drawShade(canvas, mDrawRect);
276e533f65961ed601ded1803caeab6cef0a778d2f2nicolasroard        // Draw the grid
2777a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard        if (mState == MODES.MOVE || mGridAlpha > 0) {
2780d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            canvas.save();
279b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk            canvas.clipRect(mDrawRect);
280805a7fe57da2534462f4720abc7fe9cdb8f7ecc9John Hoford
2817a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard            float step = Math.max(viewWidth, viewHeight) / NBLINES;
2820d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            float p = 0;
283805a7fe57da2534462f4720abc7fe9cdb8f7ecc9John Hoford            for (int i = 1; i < NBLINES; i++) {
2840d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard                p = i * step;
2857a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard                int alpha = (int) (mDefaultGridAlpha * mGridAlpha);
2867a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard                if (alpha == 0 && mState == MODES.MOVE) {
2877a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard                    alpha = mDefaultGridAlpha;
2887a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard                }
2897a53c3d54ed06cc2fe0440fcaa01fa879d19dc88nicolasroard                mPaint.setAlpha(alpha);
290b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk                canvas.drawLine(p, 0, p, viewHeight, mPaint);
291998defa31aeb510a1c3c784719100f9cfbf50474John Hoford                canvas.drawLine(0, p, viewWidth, p, mPaint);
2920d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            }
2930d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard            canvas.restore();
2940d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard        }
295b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mPaint.reset();
296b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mPaint.setColor(Color.WHITE);
297b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mPaint.setStyle(Style.STROKE);
298b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mPaint.setStrokeWidth(3);
299b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mDrawPath.reset();
300805a7fe57da2534462f4720abc7fe9cdb8f7ecc9John Hoford
301805a7fe57da2534462f4720abc7fe9cdb8f7ecc9John Hoford
302b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        mDrawPath.addRect(mDrawRect, Path.Direction.CW);
303b0f7a8f7f7d95ae12e92f529fd9a8a37f75b105cRuben Brunk        canvas.drawPath(mDrawPath, mPaint);
3040d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard    }
3050d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard
306d61a2f9fcaad0309132b6b9b666c3dc6df62fed7John Hoford    public void setEditor(EditorStraighten editorStraighten) {
307d61a2f9fcaad0309132b6b9b666c3dc6df62fed7John Hoford        mEditorStraighten = editorStraighten;
308d61a2f9fcaad0309132b6b9b666c3dc6df62fed7John Hoford    }
309d61a2f9fcaad0309132b6b9b666c3dc6df62fed7John Hoford
3100d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard}
311