1 /*
2  * Copyright 2019 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.core;
18 
19 import static androidx.camera.core.FlashState.FlashState;
20 import static androidx.camera.core.FlashState.UNKNOWN;
21 
22 import android.graphics.Matrix;
23 import android.hardware.camera2.CameraCharacteristics;
24 
25 import androidx.annotation.RestrictTo;
26 import androidx.camera.core.impl.TagBundle;
27 import androidx.camera.core.impl.utils.ExifData;
28 
29 import org.jspecify.annotations.NonNull;
30 
31 /** Metadata for an image. */
32 public interface ImageInfo {
33     /**
34      * Returns all tags stored in the metadata.
35      *
36      */
37     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
getTagBundle()38     @NonNull TagBundle getTagBundle();
39 
40     /**
41      * Returns the timestamp of the metadata.
42      *
43      * Details on the timestamp depend on the source providing the image, and the method providing
44      * the image contains more documentation.
45      *
46      * @return the timestamp of the image
47      */
getTimestamp()48     long getTimestamp();
49 
50     /**
51      * Returns the rotation needed to transform the image to the correct orientation.
52      *
53      * <p> This is a clockwise rotation in degrees that needs to be applied to the image buffer.
54      * Note that for images that are in {@link android.graphics.ImageFormat#JPEG} this value will
55      * match the rotation defined in the EXIF.
56      *
57      * <p> The target rotation is set at the time the image capture was requested.
58      *
59      * <p> The correct orientation of the image is dependent upon the producer of the image. For
60      * example, if the {@link ImageProxy} that contains this instance of ImageInfo is produced
61      * by an {@link ImageCapture}, then the rotation will be determined by
62      * {@link ImageCapture#setTargetRotation(int)} or
63      * {@link ImageCapture.Builder#setTargetRotation(int)}.
64      *
65      * @return The rotation in degrees which will be a value in {0, 90, 180, 270}.
66      * @see ImageCapture#setTargetRotation(int)
67      * @see ImageCapture.Builder#setTargetRotation(int)
68      * @see ImageAnalysis#setTargetRotation(int)
69      * @see ImageAnalysis.Builder#setTargetRotation(int)
70      */
71     // TODO(b/122806727) Need to correctly set EXIF in JPEG images
getRotationDegrees()72     int getRotationDegrees();
73 
74     /**
75      * Returns the sensor to image buffer transform matrix.
76      *
77      * <p>The returned matrix is a mapping from sensor coordinates to buffer coordinates,
78      * which is, from the value of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE} to
79      * {@code (0, 0, image.getWidth, image.getHeight)}. The matrix can be used to map the
80      * coordinates from one {@link UseCase} to another. For example, mapping coordinates of the
81      * face detected with {@link ImageAnalysis} to {@link ImageCapture}.
82      *
83      * If {@link ImageAnalysis.Builder#setOutputImageRotationEnabled} is set to false,
84      * {@link ImageInfo#getRotationDegrees()} will return the rotation degree that needs to be
85      * applied to the image buffer to user. In this case, the transform matrix can be
86      * calculated using rotation degrees.
87      *
88      * If {@link ImageAnalysis.Builder#setOutputImageRotationEnabled} is set to true, the
89      * ImageAnalysis pipeline will apply the rotation to the image buffer and
90      * {@link ImageInfo#getRotationDegrees()} will always return 0. In this case, the transform
91      * matrix cannot be calculated.
92      *
93      * This API provides the transform matrix which could handle both cases.
94      *
95      * <pre>
96      *     <code>
97      *         // Calculate the matrix
98      *         Matrix analysisToSensor = new Matrix();
99      *         analysisToSensor.invert(
100      *             imageAnalysisImageProxy.getImageInfo()
101      *                                    .getSensorToBufferTransformMatrix());
102      *         Matrix sensorToCapture = captureImageProxy.getImageInfo()
103      *                                                   .getSensorToBufferTransformMatrix();
104      *         Matrix analysisToCapture = new Matrix();
105      *         analysisToCapture.setConcat(analysisToSensor, sensorToCapture);
106      *
107      *         // Transforming the coordinates
108      *         Rect faceBoundingBoxInAnalysis;
109      *         Rect faceBoundingBoxInCapture;
110      *         analysisToCapture.mapRect(faceBoundingBoxInAnalysis, faceBoundingBoxInCapture);
111      *
112      *         // faceBoundingBoxInCapture is the desired value
113      *     </code>
114      * </pre>
115      *
116      * @return the transform matrix.
117      */
getSensorToBufferTransformMatrix()118     default @NonNull Matrix getSensorToBufferTransformMatrix() {
119         return new Matrix();
120     }
121 
122     /**
123      * Returns the {@link androidx.camera.core.FlashState} value corresponding to the image capture.
124      */
125     @FlashState
getFlashState()126     default int getFlashState() {
127         return UNKNOWN;
128     }
129 
130     /**
131      * Adds any stored EXIF information in this ImageInfo into the provided ExifData builder.
132      *
133      */
134     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
populateExifData(ExifData.@onNull Builder exifBuilder)135     void populateExifData(ExifData.@NonNull Builder exifBuilder);
136 }
137