1 /*
2  * Copyright (C) 2014 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.ui.focus;
18 
19 import android.graphics.Matrix;
20 import android.graphics.RectF;
21 
22 /**
23  * Transform coordinates to and from preview coordinate space and camera driver
24  * coordinate space.
25  */
26 public class CameraCoordinateTransformer {
27     // http://developer.android.com/guide/topics/media/camera.html#metering-focus-areas
28     private static final RectF CAMERA_DRIVER_RECT = new RectF(-1000, -1000, 1000, 1000);
29 
30     private final Matrix mCameraToPreviewTransform;
31     private final Matrix mPreviewToCameraTransform;
32 
33     /**
34      * Convert rectangles to / from camera coordinate and preview coordinate space.
35      *
36      * @param mirrorX if the preview is mirrored along the X axis.
37      * @param displayOrientation orientation in degrees.
38      * @param previewRect the preview rectangle size and position.
39      */
CameraCoordinateTransformer(boolean mirrorX, int displayOrientation, RectF previewRect)40     public CameraCoordinateTransformer(boolean mirrorX, int displayOrientation,
41           RectF previewRect) {
42         if (!hasNonZeroArea(previewRect)) {
43             throw new IllegalArgumentException("previewRect");
44         }
45 
46         mCameraToPreviewTransform = cameraToPreviewTransform(mirrorX, displayOrientation,
47               previewRect);
48         mPreviewToCameraTransform = inverse(mCameraToPreviewTransform);
49     }
50 
51     /**
52      * Transform a rectangle in camera space into a new rectangle in preview
53      * view space.
54      *
55      * @param source the rectangle in camera space
56      * @return the rectangle in preview view space.
57      */
toPreviewSpace(RectF source)58     public RectF toPreviewSpace(RectF source) {
59         RectF result = new RectF();
60         mCameraToPreviewTransform.mapRect(result, source);
61         return result;
62     }
63 
64     /**
65      * Transform a rectangle in preview view space into a new rectangle in
66      * camera view space.
67      *
68      * @param source the rectangle in preview view space
69      * @return the rectangle in camera view space.
70      */
toCameraSpace(RectF source)71     public RectF toCameraSpace(RectF source) {
72         RectF result = new RectF();
73         mPreviewToCameraTransform.mapRect(result, source);
74         return result;
75     }
76 
cameraToPreviewTransform(boolean mirrorX, int displayOrientation, RectF previewRect)77     private Matrix cameraToPreviewTransform(boolean mirrorX, int displayOrientation,
78           RectF previewRect) {
79         Matrix transform = new Matrix();
80 
81         // Need mirror for front camera.
82         transform.setScale(mirrorX ? -1 : 1, 1);
83 
84         // Apply a rotate transform.
85         // This is the value for android.hardware.Camera.setDisplayOrientation.
86         transform.postRotate(displayOrientation);
87 
88         // Map camera driver coordinates to preview rect coordinates
89         Matrix fill = new Matrix();
90         fill.setRectToRect(CAMERA_DRIVER_RECT,
91               previewRect,
92               Matrix.ScaleToFit.FILL);
93 
94         // Concat the previous transform on top of the fill behavior.
95         transform.setConcat(fill, transform);
96 
97         return transform;
98     }
99 
inverse(Matrix source)100     private Matrix inverse(Matrix source) {
101         Matrix newMatrix = new Matrix();
102         source.invert(newMatrix);
103         return newMatrix;
104     }
105 
hasNonZeroArea(RectF rect)106     private boolean hasNonZeroArea(RectF rect) {
107         return rect.width() != 0 && rect.height() != 0;
108     }
109 }
110