/* * Copyright (C) 2015 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 com.android.camera.captureintent; import com.android.camera.app.OrientationManager; import com.android.camera.debug.Log; import com.android.camera.util.Size; import android.graphics.Matrix; import android.graphics.PointF; import android.graphics.RectF; public class PreviewTransformCalculator { private static final Log.Tag TAG = new Log.Tag("PviewTransfmCal"); private final OrientationManager mOrientationManager; public PreviewTransformCalculator(OrientationManager orientationManager) { mOrientationManager = orientationManager; } /** * Build a matrix which can be used when calling setTransform() on a * TextureView. * TODO: write unit test when roboletric is available. * * @param previewViewSize The TextureView current layout size. * @param previewStreamSize The selected preview video stream size. * @return The matrix to transform TextureView. */ public Matrix toTransformMatrix(Size previewViewSize, Size previewStreamSize) { RectF previewViewRect = new RectF(0.0f, 0.0f, previewViewSize.width(), previewViewSize.height()); PointF previewViewCenter = new PointF(previewViewRect.centerX(), previewViewRect.centerY()); // If natural orientation is portrait, rotate the buffer dimensions. Size previewBufferSize = previewStreamSize; if (mOrientationManager.getDeviceNaturalOrientation() == OrientationManager.DeviceNaturalOrientation.PORTRAIT) { previewBufferSize = new Size(previewStreamSize.height(), previewStreamSize.width()); } Matrix transformMatrix = new Matrix(); // Adjust the effective preview rect to the center of the texture view. final RectF PreviewBufferRect = new RectF(0.0f, 0.0f, previewBufferSize.width(), previewBufferSize.height()); final PointF previewBufferCenter = new PointF(PreviewBufferRect.centerX(), PreviewBufferRect.centerY()); final RectF centeredEffectivePreviewRect = new RectF(PreviewBufferRect); centeredEffectivePreviewRect.offset( previewViewCenter.x - previewBufferCenter.x, previewViewCenter.y - previewBufferCenter.y); // Undo ScaleToFit.FILL done by the surface transformMatrix.setRectToRect( previewViewRect, centeredEffectivePreviewRect, Matrix.ScaleToFit.FILL); // Rotate buffer contents to proper orientation int rotateDegree = mOrientationManager.getDisplayRotation().getDegrees(); transformMatrix.postRotate( rotateDegree, previewViewCenter.x, previewViewCenter.y); /** * Scale to fit view, cropping the longest dimension. * * surfaceTextureSize is changed with the device orientation. Since * previewStreamSize is always in landscape. To calculate the scale * factor, previewStreamSize needs to be rotated if in portrait. */ Size rotatedPreviewSize = previewStreamSize; if (mOrientationManager.isInPortrait()) { rotatedPreviewSize = new Size(previewStreamSize.height(), previewStreamSize.width()); } float scale = Math.min( (float) previewViewSize.width() / (float) rotatedPreviewSize.width(), (float) previewViewSize.height() / (float) rotatedPreviewSize.height()); transformMatrix.postScale(scale, scale, previewViewCenter.x, previewViewCenter.y); RectF scaledPreviewStreamRect = new RectF( 0.0f, 0.0f, previewStreamSize.width() * scale, previewStreamSize.height() * scale); PointF scaledPreviewStreamCenter = new PointF(scaledPreviewStreamRect.centerX(), scaledPreviewStreamRect.centerY()); transformMatrix.postTranslate( scaledPreviewStreamCenter.x - previewViewCenter.x, scaledPreviewStreamCenter.y - previewViewCenter.y); return transformMatrix; } }