SurfaceRequest.TransformationInfo


@AutoValue
public abstract class SurfaceRequest.TransformationInfo


Transformation associated the preview output.

The TransformationInfo can be used transform the Surface provided via provideSurface. The info is based on the camera sensor rotation, preview target rotation and the ViewPort associated with the Preview. The application of the info depends on the source of the Surface. For detailed example, please check out the source code of PreviewView in androidx.camera.view artifact.

The info is also needed to transform coordinates across use cases. In a face detection example, one common scenario is running a face detection algorithm against a ImageAnalysis use case, and highlight the detected face in the preview. Below is a code sample to get the transformation Matrix based on the ImageProxy from ImageAnalysis and the TransformationInfo from Preview:

    // Get rotation transformation.
    val transformation = Matrix()
    transformation.setRotate(info.getRotationDegrees())

    // Get rotated crop rect and cropping transformation.
    val rotatedRect = new RectF()
    rotation.mapRect(rotatedRect, RectF(imageProxy.getCropRect()))
    rotatedRect.sort()
    val cropTransformation = Matrix()
    cropTransformation.setRectToRect(
         RectF(imageProxy.getCropRect()), rotatedRect, ScaleToFit.FILL)

    // Concatenate the rotation and cropping transformations.
    transformation.postConcat(cropTransformation)

Summary

Public methods

abstract @NonNull Rect

Returns the crop rect rectangle.

abstract int

Returns the rotation needed to transform the output from sensor to the target rotation.

abstract @NonNull Matrix

Returns the sensor to image buffer transform matrix.

abstract boolean

Whether the Surface contains the camera transform.

abstract boolean

Returns whether the buffer should be mirrored.

Public methods

getCropRect

Added in 1.0.0
public abstract @NonNull Rect getCropRect()

Returns the crop rect rectangle.

The returned value dictates how the Surface provided in provideSurface should be displayed. The crop rectangle specifies the region of valid pixels in the buffer, using coordinates from (0, 0) to the (width, height) of getResolution. The caller should arrange the UI so that only the valid region is visible to app users.

If Preview is configured with a ViewPort, this value is calculated based on the configuration of ViewPort; if not, it returns the full rect of the buffer. For code sample on how to apply the crop rect, please see FIT.

See also
ViewPort

getRotationDegrees

Added in 1.0.0
public abstract int getRotationDegrees()

Returns the rotation needed to transform the output from sensor to the target rotation.

This is a clockwise rotation in degrees that needs to be applied to the sensor buffer. The rotation will be determined by CameraCharacteristics, setTargetRotation and setTargetRotation. This value is useful for transforming coordinates across use cases.

This value is most useful for transforming coordinates across use cases, e.g. in preview, highlighting a pattern detected in image analysis. For correcting the preview itself, usually the source of the Surface handles the rotation without needing this value. For SurfaceView, it automatically corrects the preview to match the display rotation. For TextureView, the only additional rotation needed is the display rotation. For detailed example, please check out the source code of PreviewView in androidx.camera .view artifact.

Returns
int

The rotation in degrees which will be a value in {0, 90, 180, 270}.

getSensorToBufferTransform

Added in 1.4.0
public abstract @NonNull Matrix getSensorToBufferTransform()

Returns the sensor to image buffer transform matrix.

The value is a mapping from sensor coordinates to buffer coordinates, which is, from the rect of SENSOR_INFO_ACTIVE_ARRAY_SIZE to the rect defined by (0, 0, #getResolution#getWidth(), #getResolution#getHeight()). The matrix can be used to map the coordinates from one UseCase to another. For example, detecting face with ImageAnalysis, and then highlighting the face in Preview.

Code sample

 // Get the transformation from sensor to effect input.
 Matrix sensorToEffect = surfaceRequest.getSensorToBufferTransform();
 // Get the transformation from sensor to ImageAnalysis.
 Matrix sensorToAnalysis = imageProxy.getSensorToBufferTransform();
 // Concatenate the two matrices to get the transformation from ImageAnalysis to effect.
 Matrix analysisToEffect = Matrix()
 sensorToAnalysis.invert(analysisToEffect);
 analysisToEffect.postConcat(sensorToEffect);

hasCameraTransform

Added in 1.4.0
public abstract boolean hasCameraTransform()

Whether the Surface contains the camera transform.

When the Surface is connected to the camera directly, camera writes the camera orientation value to the Surface. For example, the value can be retrieved via getTransformMatrix. Android components such as TextureView and SurfaceView use the value to transform the output. When the Surface is not connect to the camera directly, for example, when it was copied with OpenGL, the Surface will not contain the camera orientation value.

The app may need to transform the UI differently based on this flag. If this value is true, the app only needs to apply the Surface transformation; otherwise, the app needs to apply the value of getRotationDegrees. For example, if the preview is displayed in a TextureView:

int rotationDegrees;
if (surfaceRequest.hasCameraTransform()) {
  switch (textureView.getDisplay().getRotation()) {
    case Surface.ROTATION_0:
      rotationDegrees = 0;
      break;
    case Surface.ROTATION_90:
      rotationDegrees = 90;
      break;
    case Surface.ROTATION_180:
      rotationDegrees = 180;
      break;
    case Surface.ROTATION_270:
      rotationDegrees = 270;
      break;
    }
} else {
  rotationDegrees = transformationInfo.getRotationDegrees();
}
Matrix textureViewTransform = new Matrix();
textureViewTransform.postRotate(rotationDegrees);
textureView.setTransform(textureViewTransform);
Returns
boolean

true if the Surface contains the camera transformation.

isMirroring

Added in 1.4.0
public abstract boolean isMirroring()

Returns whether the buffer should be mirrored.

This flag indicates whether the buffer needs to be mirrored across the vertical axis. For example, for front camera preview, the buffer should usually be mirrored. The mirroring should be applied after the getRotationDegrees is applied.