1 /*
2  * Copyright 2024 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 androidx.camera.viewfinder.core
18 
19 /**
20  * Transformation information associated with the preview output.
21  *
22  * This information can be used to transform the Surface of a Viewfinder to be suitable to be
23  * displayed.
24  */
25 class TransformationInfo
26 @JvmOverloads
27 constructor(
28     /** Rotation of the source, relative to the device's natural rotation, in degrees. */
29     val sourceRotation: Int = 0,
30 
31     /**
32      * Indicates whether the source has been mirrored horizontally.
33      *
34      * This is common if the source comes from a camera that is front-facing.
35      *
36      * It is not common for both [isSourceMirroredHorizontally] and [isSourceMirroredVertically] to
37      * be set to `true`. This is equivalent to [sourceRotation] being rotated by an additional 180
38      * degrees.
39      *
40      * @see android.hardware.camera2.params.OutputConfiguration.MIRROR_MODE_AUTO
41      * @see android.hardware.camera2.params.OutputConfiguration.MIRROR_MODE_H
42      * @see androidx.camera.core.SurfaceRequest.TransformationInfo.isMirroring
43      */
44     val isSourceMirroredHorizontally: Boolean = false,
45 
46     /**
47      * Indicates whether the source has been mirrored vertically.
48      *
49      * It is not common for a camera source to be mirror vertically, and typically
50      * [isSourceMirroredHorizontally] will be the appropriate property.
51      *
52      * It is not common for both [isSourceMirroredHorizontally] and [isSourceMirroredVertically] to
53      * be set to `true`. This is equivalent to [sourceRotation] being rotated by an additional 180
54      * degrees.
55      *
56      * @see android.hardware.camera2.params.OutputConfiguration.MIRROR_MODE_V
57      */
58     val isSourceMirroredVertically: Boolean = false,
59 
60     /**
61      * Left offset of the cropRect in pixels.
62      *
63      * The offset is in the coordinates of the original surface, before rotation or mirroring.
64      *
65      * If not set, this value will default to [CROP_NONE], which is equivalent to an offset of 0.
66      */
67     val cropRectLeft: Float = CROP_NONE,
68 
69     /**
70      * Top offset of the cropRect in pixels
71      *
72      * The offset is in the coordinates of the original surface, before rotation or mirroring.
73      *
74      * If not set, this value will default to [CROP_NONE], which is equivalent to an offset of 0.
75      */
76     val cropRectTop: Float = CROP_NONE,
77 
78     /**
79      * Right offset of the cropRect in pixels
80      *
81      * The offset is in the coordinates of the original surface, before rotation or mirroring.
82      *
83      * If not set, this value will default to [CROP_NONE], which is equivalent to an offset of the
84      * width of the surface.
85      */
86     val cropRectRight: Float = CROP_NONE,
87 
88     /**
89      * Bottom offset of the cropRect in pixels
90      *
91      * The offset is in the coordinates of the original surface, before rotation or mirroring.
92      *
93      * If not set, this value will default to [CROP_NONE], which is equivalent to an offset of the
94      * height of the surface.
95      */
96     val cropRectBottom: Float = CROP_NONE
97 ) {
equalsnull98     override fun equals(other: Any?): Boolean {
99         if (this === other) return true
100         if (other !is TransformationInfo) return false
101 
102         if (sourceRotation != other.sourceRotation) return false
103         if (isSourceMirroredHorizontally != other.isSourceMirroredHorizontally) return false
104         if (isSourceMirroredVertically != other.isSourceMirroredVertically) return false
105         if (cropRectLeft != other.cropRectLeft) return false
106         if (cropRectTop != other.cropRectTop) return false
107         if (cropRectRight != other.cropRectRight) return false
108         if (cropRectBottom != other.cropRectBottom) return false
109 
110         return true
111     }
112 
hashCodenull113     override fun hashCode(): Int {
114         var result = sourceRotation
115         result = 31 * result + isSourceMirroredHorizontally.hashCode()
116         result = 31 * result + isSourceMirroredVertically.hashCode()
117         result = 31 * result + cropRectLeft.hashCode()
118         result = 31 * result + cropRectTop.hashCode()
119         result = 31 * result + cropRectRight.hashCode()
120         result = 31 * result + cropRectBottom.hashCode()
121         return result
122     }
123 
124     companion object {
125         /**
126          * A crop value specifying no crop should be applied.
127          *
128          * When used as a value for [TransformationInfo.cropRectLeft],
129          * [TransformationInfo.cropRectTop], [TransformationInfo.cropRectRight], or
130          * [TransformationInfo.cropRectBottom], the crop rect dimension will be equivalent to the
131          * resolution of the untransformed surface.
132          */
133         const val CROP_NONE: Float = Float.NaN
134 
135         /**
136          * A [TransformationInfo] with default values.
137          *
138          * This transformation info instance has no source rotation, no mirroring, and no crop
139          * rectangle.
140          */
141         @JvmField val DEFAULT: TransformationInfo = TransformationInfo()
142     }
143 }
144