124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu/* 224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * Copyright (C) 2015 The Android Open Source Project 324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * 424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * Licensed under the Apache License, Version 2.0 (the "License"); 524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * you may not use this file except in compliance with the License. 624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * You may obtain a copy of the License at 724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * 824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * http://www.apache.org/licenses/LICENSE-2.0 924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * 1024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * Unless required by applicable law or agreed to in writing, software 1124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * distributed under the License is distributed on an "AS IS" BASIS, 1224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * See the License for the specific language governing permissions and 1424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * limitations under the License. 1524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu */ 1624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 1724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hupackage com.android.camera.captureintent; 1824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 1924be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport com.android.camera.app.OrientationManager; 2024be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport com.android.camera.debug.Log; 2124be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport com.android.camera.util.Size; 2224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 2324be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport android.graphics.Matrix; 2424be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport android.graphics.PointF; 2524be7cc6d138129b4087ef28f114701de54aba3cSenpo Huimport android.graphics.RectF; 2624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 2724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hupublic class PreviewTransformCalculator { 28de4e5225ea92d681f9f4c005e6285f739635d271Senpo Hu private static final Log.Tag TAG = new Log.Tag("PviewTransfmCal"); 2924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 3024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu private final OrientationManager mOrientationManager; 3124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 3224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu public PreviewTransformCalculator(OrientationManager orientationManager) { 3324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu mOrientationManager = orientationManager; 3424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } 3524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 3624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu /** 3724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * Build a matrix which can be used when calling setTransform() on a 3824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * TextureView. 3924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * TODO: write unit test when roboletric is available. 4024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * 4124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * @param previewViewSize The TextureView current layout size. 4224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * @param previewStreamSize The selected preview video stream size. 4324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * @return The matrix to transform TextureView. 4424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu */ 4524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu public Matrix toTransformMatrix(Size previewViewSize, Size previewStreamSize) { 4624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu RectF previewViewRect = 4724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu new RectF(0.0f, 0.0f, previewViewSize.width(), previewViewSize.height()); 4824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu PointF previewViewCenter = new PointF(previewViewRect.centerX(), previewViewRect.centerY()); 4924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 5024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu // If natural orientation is portrait, rotate the buffer dimensions. 5124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu Size previewBufferSize = previewStreamSize; 5224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 5324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu if (mOrientationManager.getDeviceNaturalOrientation() == OrientationManager.DeviceNaturalOrientation.PORTRAIT) { 5424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu previewBufferSize = new Size(previewStreamSize.height(), previewStreamSize.width()); 5524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } 5624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 5724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu Matrix transformMatrix = new Matrix(); 5824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 5924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu // Adjust the effective preview rect to the center of the texture view. 6024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu final RectF PreviewBufferRect = 6124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu new RectF(0.0f, 0.0f, previewBufferSize.width(), previewBufferSize.height()); 6224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu final PointF previewBufferCenter = 6324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu new PointF(PreviewBufferRect.centerX(), PreviewBufferRect.centerY()); 6424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 6524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu final RectF centeredEffectivePreviewRect = new RectF(PreviewBufferRect); 6624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu centeredEffectivePreviewRect.offset( 6724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu previewViewCenter.x - previewBufferCenter.x, 6824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu previewViewCenter.y - previewBufferCenter.y); 6924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 7024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu // Undo ScaleToFit.FILL done by the surface 7124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu transformMatrix.setRectToRect( 7224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu previewViewRect, centeredEffectivePreviewRect, Matrix.ScaleToFit.FILL); 7324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 7424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu // Rotate buffer contents to proper orientation 7524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu int rotateDegree = mOrientationManager.getDisplayRotation().getDegrees(); 7624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu transformMatrix.postRotate( 7724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu rotateDegree, 7824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu previewViewCenter.x, previewViewCenter.y); 7924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 8024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu /** 8124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * Scale to fit view, cropping the longest dimension. 8224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * 8324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * surfaceTextureSize is changed with the device orientation. Since 8424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * previewStreamSize is always in landscape. To calculate the scale 8524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu * factor, previewStreamSize needs to be rotated if in portrait. 8624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu */ 8724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu Size rotatedPreviewSize = previewStreamSize; 8824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu if (mOrientationManager.isInPortrait()) { 8924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu rotatedPreviewSize = new Size(previewStreamSize.height(), previewStreamSize.width()); 9024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } 9124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu float scale = Math.min( 9224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu (float) previewViewSize.width() / (float) rotatedPreviewSize.width(), 9324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu (float) previewViewSize.height() / (float) rotatedPreviewSize.height()); 9424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu transformMatrix.postScale(scale, scale, previewViewCenter.x, previewViewCenter.y); 9524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 9624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu RectF scaledPreviewStreamRect = new RectF( 9724be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 0.0f, 0.0f, previewStreamSize.width() * scale, previewStreamSize.height() * scale); 9824be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu PointF scaledPreviewStreamCenter = 9924be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu new PointF(scaledPreviewStreamRect.centerX(), scaledPreviewStreamRect.centerY()); 10024be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu transformMatrix.postTranslate( 10124be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu scaledPreviewStreamCenter.x - previewViewCenter.x, 10224be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu scaledPreviewStreamCenter.y - previewViewCenter.y); 10324be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu 10424be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu return transformMatrix; 10524be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu } 10624be7cc6d138129b4087ef28f114701de54aba3cSenpo Hu} 107