getPictureSize and getPreviewSize now return sizes in the output reference

v2
Mattia Iavarone 7 years ago
parent fca9d3fbd8
commit 0c51d63e9c
  1. 18
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CropHelperTest.java
  2. 2
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/MockCameraController.java
  3. 43
      cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java
  4. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/Camera2.java
  5. 77
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java
  6. 29
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  7. 31
      cameraview/src/main/utils/com/otaliastudios/cameraview/CropHelper.java
  8. 26
      cameraview/src/main/utils/com/otaliastudios/cameraview/RotationHelper.java
  9. 15
      demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java

@ -1,37 +1,23 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.YuvImage;
import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@SmallTest @SmallTest
public class YuvHelperTest extends BaseTest { public class CropHelperTest extends BaseTest {
@Test @Test
public void testCrop() { public void testCrop() {
@ -42,7 +28,7 @@ public class YuvHelperTest extends BaseTest {
private void testCrop(final Size inSize, final AspectRatio outRatio) { private void testCrop(final Size inSize, final AspectRatio outRatio) {
AspectRatio inRatio = AspectRatio.of(inSize.getWidth(), inSize.getHeight()); AspectRatio inRatio = AspectRatio.of(inSize.getWidth(), inSize.getHeight());
Rect out = YuvHelper.computeCrop(inSize, outRatio); Rect out = CropHelper.computeCrop(inSize, outRatio);
Size outSize = new Size(out.width(), out.height()); Size outSize = new Size(out.width(), out.height());
assertTrue(outRatio.matches(outSize)); assertTrue(outRatio.matches(outSize));

@ -97,7 +97,7 @@ public class MockCameraController extends CameraController {
} }
@Override @Override
void takePictureSnapshot(boolean shouldCrop, AspectRatio viewAspectRatio) { void takePictureSnapshot(AspectRatio viewAspectRatio) {
} }
@Override @Override

@ -138,11 +138,8 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
LOG.i(log, "Dispatching onCameraPreviewSizeChanged."); LOG.i(log, "Dispatching onCameraPreviewSizeChanged.");
mCameraCallbacks.onCameraPreviewSizeChanged(); mCameraCallbacks.onCameraPreviewSizeChanged();
boolean invertPreviewSizes = shouldFlipSizes(); Size previewSize = getPreviewSize(REF_VIEW);
mPreview.setDesiredSize( mPreview.setDesiredSize(previewSize.getWidth(), previewSize.getHeight());
invertPreviewSizes ? mPreviewSize.getHeight() : mPreviewSize.getWidth(),
invertPreviewSizes ? mPreviewSize.getWidth() : mPreviewSize.getHeight()
);
Camera.Parameters params = mCamera.getParameters(); Camera.Parameters params = mCamera.getParameters();
mPreviewFormat = params.getPreviewFormat(); mPreviewFormat = params.getPreviewFormat();
@ -183,7 +180,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
// Set parameters that might have been set before the camera was opened. // Set parameters that might have been set before the camera was opened.
LOG.i("onStart:", "Applying default parameters."); LOG.i("onStart:", "Applying default parameters.");
Camera.Parameters params = mCamera.getParameters(); Camera.Parameters params = mCamera.getParameters();
mCameraOptions = new CameraOptions(params, shouldFlipSizes()); mCameraOptions = new CameraOptions(params, flip(REF_SENSOR, REF_VIEW));
applyDefaultFocus(params); applyDefaultFocus(params);
mergeFlash(params, Flash.DEFAULT); mergeFlash(params, Flash.DEFAULT);
mergeLocation(params, null); mergeLocation(params, null);
@ -194,7 +191,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
mCamera.setParameters(params); mCamera.setParameters(params);
// Try starting preview. // Try starting preview.
mCamera.setDisplayOrientation(computeSensorToViewOffset()); // <- not allowed during preview mCamera.setDisplayOrientation(offset(REF_SENSOR, REF_VIEW)); // <- not allowed during preview
if (shouldBindToSurface()) bindToSurface(); if (shouldBindToSurface()) bindToSurface();
LOG.i("onStart:", "Ended"); LOG.i("onStart:", "Ended");
} }
@ -511,13 +508,8 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
if (mIsCapturingVideo && !mCameraOptions.isVideoSnapshotSupported()) return; if (mIsCapturingVideo && !mCameraOptions.isVideoSnapshotSupported()) return;
mIsCapturingImage = true; mIsCapturingImage = true;
final int sensorToOutput = computeSensorToOutputOffset(); final int sensorToOutput = offset(REF_SENSOR, REF_OUTPUT);
int outputWidth = mPictureSize.getWidth(); final Size outputSize = getPictureSize(REF_OUTPUT);
int outputHeight = mPictureSize.getHeight();
//noinspection SuspiciousNameCombination
final Size outputSize = sensorToOutput % 180 == 0 ?
new Size(outputWidth, outputHeight) :
new Size(outputHeight, outputWidth);
Camera.Parameters params = mCamera.getParameters(); Camera.Parameters params = mCamera.getParameters();
params.setRotation(sensorToOutput); params.setRotation(sensorToOutput);
mCamera.setParameters(params); mCamera.setParameters(params);
@ -559,7 +551,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
@Override @Override
void takePictureSnapshot(final boolean shouldCrop, final AspectRatio viewAspectRatio) { void takePictureSnapshot(final AspectRatio viewAspectRatio) {
LOG.v("takePictureSnapshot: scheduling"); LOG.v("takePictureSnapshot: scheduling");
schedule(null, true, new Runnable() { schedule(null, true, new Runnable() {
@Override @Override
@ -582,12 +574,9 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
// Got to rotate the preview frame, since byte[] data here does not include // Got to rotate the preview frame, since byte[] data here does not include
// EXIF tags automatically set by camera. So either we add EXIF, or we rotate. // EXIF tags automatically set by camera. So either we add EXIF, or we rotate.
// Adding EXIF to a byte array, unfortunately, is hard. // Adding EXIF to a byte array, unfortunately, is hard.
final int sensorToOutput = computeSensorToOutputOffset(); final int sensorToOutput = offset(REF_SENSOR, REF_OUTPUT);
final int sensorToView = computeSensorToViewOffset(); final AspectRatio outputRatio = flip(REF_OUTPUT, REF_VIEW) ? viewAspectRatio.inverse() : viewAspectRatio;
final boolean outputMatchesView = (sensorToOutput + sensorToView + 180) % 180 == 0; final Size outputSize = getPreviewSize(REF_OUTPUT);
final Size originalSize = new Size(mPreviewSize.getWidth(), mPreviewSize.getHeight());
final Size outputSize = sensorToOutput % 180 == 0 ? originalSize : originalSize.flip();
final AspectRatio outputRatio = outputMatchesView ? viewAspectRatio : viewAspectRatio.inverse();
final int format = mPreviewFormat; final int format = mPreviewFormat;
WorkerHandler.run(new Runnable() { WorkerHandler.run(new Runnable() {
@Override @Override
@ -595,12 +584,12 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
// Rotate the picture, because no one will write EXIF data, // Rotate the picture, because no one will write EXIF data,
// then crop if needed. In both cases, transform yuv to jpeg. // then crop if needed. In both cases, transform yuv to jpeg.
LOG.v("takePictureSnapshot:", "rotating."); LOG.v("takePictureSnapshot:", "rotating.");
byte[] data = YuvHelper.rotate(yuv, originalSize, sensorToOutput); byte[] data = RotationHelper.rotate(yuv, mPreviewSize, sensorToOutput);
YuvImage yuv = new YuvImage(data, format, outputSize.getWidth(), outputSize.getHeight(), null); YuvImage yuv = new YuvImage(data, format, outputSize.getWidth(), outputSize.getHeight(), null);
LOG.v("takePictureSnapshot:", "rotated. Cropping and transforming to jpeg."); LOG.v("takePictureSnapshot:", "rotated. Cropping and transforming to jpeg.");
ByteArrayOutputStream stream = new ByteArrayOutputStream(); ByteArrayOutputStream stream = new ByteArrayOutputStream();
Rect outputRect = YuvHelper.computeCrop(outputSize, outputRatio); Rect outputRect = CropHelper.computeCrop(outputSize, outputRatio);
yuv.compressToJpeg(outputRect, 90, stream); yuv.compressToJpeg(outputRect, 90, stream);
data = stream.toByteArray(); data = stream.toByteArray();
@ -630,7 +619,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
public void onPreviewFrame(byte[] data, Camera camera) { public void onPreviewFrame(byte[] data, Camera camera) {
Frame frame = mFrameManager.getFrame(data, Frame frame = mFrameManager.getFrame(data,
System.currentTimeMillis(), System.currentTimeMillis(),
computeSensorToOutputOffset(), offset(REF_SENSOR, REF_OUTPUT),
mPreviewSize, mPreviewSize,
mPreviewFormat); mPreviewFormat);
mCameraCallbacks.dispatchFrame(frame); mCameraCallbacks.dispatchFrame(frame);
@ -677,8 +666,8 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
mVideoResult.isSnapshot = false; mVideoResult.isSnapshot = false;
mVideoResult.codec = mVideoCodec; mVideoResult.codec = mVideoCodec;
mVideoResult.location = mLocation; mVideoResult.location = mLocation;
mVideoResult.rotation = computeSensorToOutputOffset(); mVideoResult.rotation = offset(REF_SENSOR, REF_OUTPUT);
mVideoResult.size = mVideoResult.rotation % 180 == 0 ? videoSize : videoSize.flip(); mVideoResult.size = flip(REF_SENSOR, REF_OUTPUT) ? videoSize.flip() : videoSize;
// Initialize the media recorder // Initialize the media recorder
mCamera.unlock(); mCamera.unlock();
@ -871,7 +860,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
if (!mCameraOptions.isAutoFocusSupported()) return; if (!mCameraOptions.isAutoFocusSupported()) return;
final PointF p = new PointF(point.x, point.y); // copy. final PointF p = new PointF(point.x, point.y); // copy.
List<Camera.Area> meteringAreas2 = computeMeteringAreas(p.x, p.y, List<Camera.Area> meteringAreas2 = computeMeteringAreas(p.x, p.y,
viewWidthF, viewHeightF, computeSensorToViewOffset()); viewWidthF, viewHeightF, offset(REF_SENSOR, REF_VIEW));
List<Camera.Area> meteringAreas1 = meteringAreas2.subList(0, 1); List<Camera.Area> meteringAreas1 = meteringAreas2.subList(0, 1);
// At this point we are sure that camera supports auto focus... right? Look at CameraView.onTouchEvent(). // At this point we are sure that camera supports auto focus... right? Look at CameraView.onTouchEvent().

@ -91,7 +91,7 @@ class Camera2 extends CameraController {
} }
@Override @Override
void takePictureSnapshot(boolean shouldCrop, AspectRatio viewAspectRatio) { void takePictureSnapshot(AspectRatio viewAspectRatio) {
} }

@ -30,6 +30,10 @@ abstract class CameraController implements
static final int STATE_STARTING = 1; // Camera is about to start. static final int STATE_STARTING = 1; // Camera is about to start.
static final int STATE_STARTED = 2; // Camera is available and we can set parameters. static final int STATE_STARTED = 2; // Camera is available and we can set parameters.
static final int REF_SENSOR = 0;
static final int REF_VIEW = 1;
static final int REF_OUTPUT = 2;
protected final CameraView.CameraCallbacks mCameraCallbacks; protected final CameraView.CameraCallbacks mCameraCallbacks;
protected CameraPreview mPreview; protected CameraPreview mPreview;
protected WorkerHandler mHandler; protected WorkerHandler mHandler;
@ -326,7 +330,7 @@ abstract class CameraController implements
abstract void takePicture(); abstract void takePicture();
abstract void takePictureSnapshot(boolean shouldCrop, AspectRatio viewAspectRatio); abstract void takePictureSnapshot(AspectRatio viewAspectRatio);
abstract void takeVideo(@NonNull File file); abstract void takeVideo(@NonNull File file);
@ -393,10 +397,6 @@ abstract class CameraController implements
return mPictureSizeSelector; return mPictureSizeSelector;
} }
final Size getPictureSize() {
return mPictureSize;
}
final float getZoomValue() { final float getZoomValue() {
return mZoomValue; return mZoomValue;
} }
@ -405,10 +405,6 @@ abstract class CameraController implements
return mExposureCorrectionValue; return mExposureCorrectionValue;
} }
final Size getPreviewSize() {
return mPreviewSize;
}
final boolean isTakingVideo() { final boolean isTakingVideo() {
return mIsCapturingVideo; return mIsCapturingVideo;
} }
@ -417,37 +413,15 @@ abstract class CameraController implements
//region Orientation utils //region Orientation utils
/** private int computeSensorToViewOffset() {
* The result of this should not change after start() is called: the sensor offset is the same,
* and the display offset does not change.
*/
final boolean shouldFlipSizes() {
int offset = computeSensorToViewOffset();
LOG.i("shouldFlipSizes:", "displayOffset=", mDisplayOffset, "sensorOffset=", mSensorOffset);
LOG.i("shouldFlipSizes:", "sensorToDisplay=", offset);
return offset % 180 != 0;
}
/**
* Returns how much should the sensor image be rotated before being shown.
* It is meant to be fed to Camera.setDisplayOrientation().
* The result of this should not change after start() is called: the sensor offset is the same,
* and the display offset does not change.
*/
protected final int computeSensorToViewOffset() {
if (mFacing == Facing.FRONT) { if (mFacing == Facing.FRONT) {
// Here we had ((mSensorOffset - mDisplayOffset) + 360 + 180) % 360
// And it seemed to give the same results for various combinations, but not for all (e.g. 0 - 270).
return (360 - ((mSensorOffset + mDisplayOffset) % 360)) % 360; return (360 - ((mSensorOffset + mDisplayOffset) % 360)) % 360;
} else { } else {
return (mSensorOffset - mDisplayOffset + 360) % 360; return (mSensorOffset - mDisplayOffset + 360) % 360;
} }
} }
/** private int computeSensorToOutputOffset() {
* Returns the orientation to be set as a exif tag.
*/
protected final int computeSensorToOutputOffset() {
if (mFacing == Facing.FRONT) { if (mFacing == Facing.FRONT) {
return (mSensorOffset - mDeviceOrientation + 360) % 360; return (mSensorOffset - mDeviceOrientation + 360) % 360;
} else { } else {
@ -455,6 +429,39 @@ abstract class CameraController implements
} }
} }
// Returns the offset between two reference systems.
final int offset(int fromReference, int toReference) {
if (fromReference == toReference) return 0;
// We only know how to compute offsets with respect to REF_SENSOR.
// That's why we separate the two cases.
if (fromReference == REF_SENSOR) {
return toReference == REF_VIEW ?
computeSensorToViewOffset() :
computeSensorToOutputOffset();
}
// Maybe the sensor is the other.
if (toReference == REF_SENSOR) {
return -offset(toReference, fromReference) + 360;
}
// None of them is the sensor. Use a difference.
return (offset(REF_SENSOR, toReference) - offset(REF_SENSOR, fromReference) + 360) % 360;
}
final boolean flip(int reference1, int reference2) {
return offset(reference1, reference2) % 180 != 0;
}
final Size getPictureSize(int reference) {
if (mPictureSize == null) return null;
return flip(REF_SENSOR, reference) ? mPictureSize.flip() : mPictureSize;
}
final Size getPreviewSize(int reference) {
if (mPreviewSize == null) return null;
return flip(REF_SENSOR, reference) ? mPreviewSize.flip() : mPreviewSize;
}
//endregion //endregion
//region Size utils //region Size utils
@ -469,7 +476,7 @@ abstract class CameraController implements
protected final Size computePictureSize() { protected final Size computePictureSize() {
// The external selector is expecting stuff in the view world, not in the sensor world. // The external selector is expecting stuff in the view world, not in the sensor world.
// Use the list in the camera options, then flip the result if needed. // Use the list in the camera options, then flip the result if needed.
boolean flip = shouldFlipSizes(); boolean flip = flip(REF_SENSOR, REF_VIEW);
SizeSelector selector; SizeSelector selector;
if (mSessionType == SessionType.PICTURE) { if (mSessionType == SessionType.PICTURE) {
@ -500,7 +507,7 @@ abstract class CameraController implements
protected final Size computePreviewSize(List<Size> previewSizes) { protected final Size computePreviewSize(List<Size> previewSizes) {
// instead of flipping everything to the view world, we can just flip the // instead of flipping everything to the view world, we can just flip the
// surface size to the sensor world // surface size to the sensor world
boolean flip = shouldFlipSizes(); boolean flip = flip(REF_SENSOR, REF_VIEW);
AspectRatio targetRatio = AspectRatio.of(mPictureSize.getWidth(), mPictureSize.getHeight()); AspectRatio targetRatio = AspectRatio.of(mPictureSize.getWidth(), mPictureSize.getHeight());
Size targetMinSize = mPreview.getSurfaceSize(); Size targetMinSize = mPreview.getSurfaceSize();
if (flip) targetMinSize = targetMinSize.flip(); if (flip) targetMinSize = targetMinSize.flip();

@ -15,6 +15,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.PointF; import android.graphics.PointF;
import android.graphics.Rect;
import android.location.Location; import android.location.Location;
import android.media.MediaActionSound; import android.media.MediaActionSound;
import android.os.Build; import android.os.Build;
@ -260,7 +261,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
*/ */
@Override @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Size previewSize = getPreviewSize(); Size previewSize = mCameraController.getPreviewSize(CameraController.REF_VIEW);
if (previewSize == null) { if (previewSize == null) {
LOG.w("onMeasure:", "surface is not ready. Calling default behavior."); LOG.w("onMeasure:", "surface is not ready. Calling default behavior.");
super.onMeasure(widthMeasureSpec, heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@ -272,9 +273,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int widthValue = MeasureSpec.getSize(widthMeasureSpec); final int widthValue = MeasureSpec.getSize(widthMeasureSpec);
final int heightValue = MeasureSpec.getSize(heightMeasureSpec); final int heightValue = MeasureSpec.getSize(heightMeasureSpec);
final boolean flip = mCameraController.shouldFlipSizes(); final float previewWidth = previewSize.getWidth();
final float previewWidth = flip ? previewSize.getHeight() : previewSize.getWidth(); final float previewHeight = previewSize.getHeight();
final float previewHeight = flip ? previewSize.getWidth() : previewSize.getHeight();
// Pre-process specs // Pre-process specs
final ViewGroup.LayoutParams lp = getLayoutParams(); final ViewGroup.LayoutParams lp = getLayoutParams();
@ -1144,9 +1144,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
* @see #takePicture() * @see #takePicture()
*/ */
public void takePictureSnapshot() { public void takePictureSnapshot() {
mCameraController.takePictureSnapshot( if (getWidth() == 0 || getHeight() == 0) return;
mCameraPreview.isCropping(), mCameraController.takePictureSnapshot(AspectRatio.of(getWidth(), getHeight()));
AspectRatio.of(getWidth(), getHeight()));
} }
@ -1222,7 +1221,19 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
*/ */
@Nullable @Nullable
public Size getPreviewSize() { public Size getPreviewSize() {
return mCameraController != null ? mCameraController.getPreviewSize() : null; if (getWidth() == 0 || getHeight() == 0) return null;
// Get the preview size and crop according to the current view size.
// It's better to do calculations in the REF_VIEW reference, and then flip if needed.
Size preview = mCameraController.getPreviewSize(CameraController.REF_VIEW);
AspectRatio viewRatio = AspectRatio.of(getWidth(), getHeight());
Rect crop = CropHelper.computeCrop(preview, viewRatio);
Size cropSize = new Size(crop.width(), crop.height());
if (mCameraController.flip(CameraController.REF_VIEW, CameraController.REF_OUTPUT)) {
return cropSize.flip();
} else {
return cropSize;
}
} }
@ -1234,7 +1245,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
*/ */
@Nullable @Nullable
public Size getPictureSize() { public Size getPictureSize() {
return mCameraController != null ? mCameraController.getPictureSize() : null; return mCameraController.getPictureSize(CameraController.REF_OUTPUT);
} }

@ -0,0 +1,31 @@
package com.otaliastudios.cameraview;
import android.graphics.Rect;
class CropHelper {
static Rect computeCrop(Size currentSize, AspectRatio targetRatio) {
int currentWidth = currentSize.getWidth();
int currentHeight = currentSize.getHeight();
if (targetRatio.matches(currentSize)) {
return new Rect(0, 0, currentWidth, currentHeight);
}
// They are not equal. Compute.
AspectRatio currentRatio = AspectRatio.of(currentWidth, currentHeight);
int x, y, width, height;
if (currentRatio.toFloat() > targetRatio.toFloat()) {
height = currentHeight;
width = (int) (height * targetRatio.toFloat());
y = 0;
x = (currentWidth - width) / 2;
} else {
width = currentWidth;
height = (int) (width / targetRatio.toFloat());
y = (currentHeight - height) / 2;
x = 0;
}
return new Rect(x, y, x + width, y + height);
}
}

@ -2,31 +2,7 @@ package com.otaliastudios.cameraview;
import android.graphics.Rect; import android.graphics.Rect;
class YuvHelper { class RotationHelper {
static Rect computeCrop(Size currentSize, AspectRatio targetRatio) {
int currentWidth = currentSize.getWidth();
int currentHeight = currentSize.getHeight();
if (targetRatio.matches(currentSize)) {
return new Rect(0, 0, currentWidth, currentHeight);
}
// They are not equal. Compute.
AspectRatio currentRatio = AspectRatio.of(currentWidth, currentHeight);
int x, y, width, height;
if (currentRatio.toFloat() > targetRatio.toFloat()) {
height = currentHeight;
width = (int) (height * targetRatio.toFloat());
y = 0;
x = (currentWidth - width) / 2;
} else {
width = currentWidth;
height = (int) (width / targetRatio.toFloat());
y = (currentHeight - height) / 2;
x = 0;
}
return new Rect(x, y, x + width, y + height);
}
static byte[] rotate(final byte[] yuv, final Size size, final int rotation) { static byte[] rotate(final byte[] yuv, final Size size, final int rotation) {
if (rotation == 0) return yuv; if (rotation == 0) return yuv;

@ -34,7 +34,6 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
private boolean mCapturingVideo; private boolean mCapturingVideo;
// To show stuff in the callback // To show stuff in the callback
private Size mCaptureNativeSize;
private long mCaptureTime; private long mCaptureTime;
@Override @Override
@ -94,27 +93,24 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
} }
} }
private void onPicture(byte[] jpeg) { private void onPicture(PictureResult result) {
mCapturingPicture = false; mCapturingPicture = false;
long callbackTime = System.currentTimeMillis(); long callbackTime = System.currentTimeMillis();
if (mCapturingVideo) { if (mCapturingVideo) {
message("Captured while taking video. Size="+mCaptureNativeSize, false); message("Captured while taking video. Size=" + result.getSize(), false);
return; return;
} }
// This can happen if picture was taken with a gesture. // This can happen if picture was taken with a gesture.
if (mCaptureTime == 0) mCaptureTime = callbackTime - 300; if (mCaptureTime == 0) mCaptureTime = callbackTime - 300;
if (mCaptureNativeSize == null) mCaptureNativeSize = camera.getPictureSize(); PicturePreviewActivity.setImage(result.getJpeg());
PicturePreviewActivity.setImage(jpeg);
Intent intent = new Intent(CameraActivity.this, PicturePreviewActivity.class); Intent intent = new Intent(CameraActivity.this, PicturePreviewActivity.class);
intent.putExtra("delay", callbackTime - mCaptureTime); intent.putExtra("delay", callbackTime - mCaptureTime);
intent.putExtra("nativeWidth", mCaptureNativeSize.getWidth()); intent.putExtra("nativeWidth", result.getSize().getWidth());
intent.putExtra("nativeHeight", mCaptureNativeSize.getHeight()); intent.putExtra("nativeHeight", result.getSize().getHeight());
startActivity(intent); startActivity(intent);
mCaptureTime = 0; mCaptureTime = 0;
mCaptureNativeSize = null;
} }
private void onVideo(File video) { private void onVideo(File video) {
@ -153,7 +149,6 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
if (mCapturingPicture) return; if (mCapturingPicture) return;
mCapturingPicture = true; mCapturingPicture = true;
mCaptureTime = System.currentTimeMillis(); mCaptureTime = System.currentTimeMillis();
mCaptureNativeSize = camera.getPictureSize();
message("Capturing picture...", false); message("Capturing picture...", false);
camera.takePicture(); camera.takePicture();
} }

Loading…
Cancel
Save