1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.camera.captureintent;
18 
19 import com.android.camera.app.OrientationManager;
20 import com.android.camera.debug.Log;
21 import com.android.camera.util.Size;
22 
23 import android.graphics.Matrix;
24 import android.graphics.PointF;
25 import android.graphics.RectF;
26 
27 public class PreviewTransformCalculator {
28     private static final Log.Tag TAG = new Log.Tag("PviewTransfmCal");
29 
30     private final OrientationManager mOrientationManager;
31 
PreviewTransformCalculator(OrientationManager orientationManager)32     public PreviewTransformCalculator(OrientationManager orientationManager) {
33         mOrientationManager = orientationManager;
34     }
35 
36     /**
37      * Build a matrix which can be used when calling setTransform() on a
38      * TextureView.
39      * TODO: write unit test when roboletric is available.
40      *
41      * @param previewViewSize The TextureView current layout size.
42      * @param previewStreamSize The selected preview video stream size.
43      * @return The matrix to transform TextureView.
44      */
toTransformMatrix(Size previewViewSize, Size previewStreamSize)45     public Matrix toTransformMatrix(Size previewViewSize, Size previewStreamSize) {
46         RectF previewViewRect =
47                 new RectF(0.0f, 0.0f, previewViewSize.width(), previewViewSize.height());
48         PointF previewViewCenter = new PointF(previewViewRect.centerX(), previewViewRect.centerY());
49 
50         // If natural orientation is portrait, rotate the buffer dimensions.
51         Size previewBufferSize = previewStreamSize;
52 
53         if (mOrientationManager.getDeviceNaturalOrientation() == OrientationManager.DeviceNaturalOrientation.PORTRAIT) {
54             previewBufferSize = new Size(previewStreamSize.height(), previewStreamSize.width());
55         }
56 
57         Matrix transformMatrix = new Matrix();
58 
59         // Adjust the effective preview rect to the center of the texture view.
60         final RectF PreviewBufferRect =
61                 new RectF(0.0f, 0.0f, previewBufferSize.width(), previewBufferSize.height());
62         final PointF previewBufferCenter =
63                 new PointF(PreviewBufferRect.centerX(), PreviewBufferRect.centerY());
64 
65         final RectF centeredEffectivePreviewRect = new RectF(PreviewBufferRect);
66         centeredEffectivePreviewRect.offset(
67                 previewViewCenter.x - previewBufferCenter.x,
68                 previewViewCenter.y - previewBufferCenter.y);
69 
70         // Undo ScaleToFit.FILL done by the surface
71         transformMatrix.setRectToRect(
72                 previewViewRect, centeredEffectivePreviewRect, Matrix.ScaleToFit.FILL);
73 
74         // Rotate buffer contents to proper orientation
75         int rotateDegree = mOrientationManager.getDisplayRotation().getDegrees();
76         transformMatrix.postRotate(
77                 rotateDegree,
78                 previewViewCenter.x, previewViewCenter.y);
79 
80         /**
81          * Scale to fit view, cropping the longest dimension.
82          *
83          * surfaceTextureSize is changed with the device orientation. Since
84          * previewStreamSize is always in landscape. To calculate the scale
85          * factor, previewStreamSize needs to be rotated if in portrait.
86          */
87         Size rotatedPreviewSize = previewStreamSize;
88         if (mOrientationManager.isInPortrait()) {
89             rotatedPreviewSize = new Size(previewStreamSize.height(), previewStreamSize.width());
90         }
91         float scale = Math.min(
92                 (float) previewViewSize.width() / (float) rotatedPreviewSize.width(),
93                 (float) previewViewSize.height() / (float) rotatedPreviewSize.height());
94         transformMatrix.postScale(scale, scale, previewViewCenter.x, previewViewCenter.y);
95 
96         RectF scaledPreviewStreamRect = new RectF(
97                 0.0f, 0.0f, previewStreamSize.width() * scale, previewStreamSize.height() * scale);
98         PointF scaledPreviewStreamCenter =
99                 new PointF(scaledPreviewStreamRect.centerX(), scaledPreviewStreamRect.centerY());
100         transformMatrix.postTranslate(
101                 scaledPreviewStreamCenter.x - previewViewCenter.x,
102                 scaledPreviewStreamCenter.y - previewViewCenter.y);
103 
104         return transformMatrix;
105     }
106 }
107