/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.camera.view.transform;
import static androidx.camera.view.TransformUtils.getExifTransform;
import static androidx.camera.view.TransformUtils.getNormalizedToBuffer;
import static androidx.camera.view.TransformUtils.rectToSize;
import android.content.ContentResolver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.media.ExifInterface;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.UseCase;
import androidx.camera.core.impl.utils.Exif;
import androidx.camera.view.TransformExperimental;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Factory for extracting transform info from image files.
*
* <p> This class is for extracting a {@link OutputTransform} from an image file saved by
* {@link ImageCapture}. The {@link OutputTransform} represents the transform being applied to
* the original camera buffer, which can be used by {@link CoordinateTransform} to transform
* coordinates between {@link UseCase}s.
*
* @see OutputTransform
* @see CoordinateTransform
*/
@TransformExperimental
public final class FileTransformFactory {
private boolean mUsingExifOrientation;
/**
* Whether to include the {@link ExifInterface#TAG_ORIENTATION}.
*
* By default, this value is false, e.g. loading image with {@link BitmapFactory} does
* not apply the exif orientation to the loaded {@link Bitmap}. Only set this if the exif
* orientation is applied to the loaded file. For example, if the image is loaded by a 3P
* library that automatically applies exif orientation.
*/
public void setUsingExifOrientation(boolean usingExifOrientation) {
mUsingExifOrientation = usingExifOrientation;
}
/**
* Whether the factory respects the exif of the image file.
*/
public boolean isUsingExifOrientation() {
return mUsingExifOrientation;
}
/**
* Extracts transform info from the given {@link Uri}.
*/
@NonNull
public OutputTransform getOutputTransform(@NonNull ContentResolver contentResolver,
@NonNull Uri uri)
throws IOException {
try (InputStream inputStream = contentResolver.openInputStream(uri)) {
return getOutputTransform(inputStream);
}
}
/**
* Extracts transform info from the given {@link File}.
*/
@NonNull
public OutputTransform getOutputTransform(@NonNull File file) throws IOException {
try (InputStream inputStream = new FileInputStream(file)) {
return getOutputTransform(inputStream);
}
}
/**
* Extracts transform info from the given {@link InputStream}.
*/
@NonNull
public OutputTransform getOutputTransform(@NonNull InputStream inputStream) throws IOException {
Exif exif = Exif.createFromInputStream(inputStream);
Rect cropRect = new Rect(0, 0, exif.getWidth(), exif.getHeight());
// Map the normalized space to the image buffer.
Matrix matrix = getNormalizedToBuffer(cropRect);
if (mUsingExifOrientation) {
// Add exif transform if enabled.
matrix.postConcat(
getExifTransform(exif.getOrientation(), exif.getWidth(), exif.getHeight()));
}
return new OutputTransform(matrix, rectToSize(cropRect));
}
}