Fix snapshot cropOutput, crop only when needed

pull/1/head
Mattia Iavarone 7 years ago
parent fa9fba1f90
commit 2c0bc641eb
  1. 16
      camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java
  2. 20
      camerakit/src/main/base/com/flurgle/camerakit/PreviewImpl.java
  3. 27
      camerakit/src/main/java/com/flurgle/camerakit/CameraView.java
  4. 6
      camerakit/src/main/utils/com/flurgle/camerakit/CropHelper.java

@ -388,7 +388,7 @@ class Camera1 extends CameraImpl {
public void onPictureTaken(byte[] data, Camera camera) {
mIsCapturingImage = false;
camera.startPreview(); // This is needed, read somewhere in the docs.
mCameraListener.processJpegPicture(data, consistentWithView, exifFlip);
mCameraListener.processImage(data, consistentWithView, exifFlip);
}
});
}
@ -405,10 +405,12 @@ class Camera1 extends CameraImpl {
public void onPreviewFrame(final byte[] data, Camera camera) {
// 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.
// TODO: add exif, and also care about flipping.
// Adding EXIF to a byte array, unfortunately, is hard.
Camera.Parameters params = mCamera.getParameters();
final int rotation = computeExifRotation();
final boolean flip = rotation % 180 != 0;
final int sensorToDevice = computeExifRotation();
final int sensorToDisplay = computeSensorToDisplayOffset();
final boolean exifFlip = computeExifFlip();
final boolean flip = sensorToDevice % 180 != 0;
final int preWidth = mPreviewSize.getWidth();
final int preHeight = mPreviewSize.getHeight();
final int postWidth = flip ? preHeight : preWidth;
@ -417,9 +419,11 @@ class Camera1 extends CameraImpl {
new Thread(new Runnable() {
@Override
public void run() {
byte[] rotatedData = RotationHelper.rotate(data, preWidth, preHeight, rotation);
final boolean consistentWithView = (sensorToDevice + sensorToDisplay + 180) % 180 == 0;
byte[] rotatedData = RotationHelper.rotate(data, preWidth, preHeight, sensorToDevice);
YuvImage yuv = new YuvImage(rotatedData, format, postWidth, postHeight, null);
mCameraListener.processYuvPicture(yuv);
mCameraListener.processSnapshot(yuv, consistentWithView, exifFlip);
mIsCapturingImage = false;
}
}).start();

@ -49,7 +49,7 @@ abstract class PreviewImpl {
void setDesiredSize(int width, int height) {
this.mDesiredWidth = width;
this.mDesiredHeight = height;
refreshScale();
crop();
}
final Size getSurfaceSize() {
@ -64,7 +64,7 @@ abstract class PreviewImpl {
protected final void onSurfaceAvailable(int width, int height) {
mSurfaceWidth = width;
mSurfaceHeight = height;
refreshScale();
crop();
mSurfaceCallback.onSurfaceAvailable();
}
@ -75,7 +75,7 @@ abstract class PreviewImpl {
if (width != mSurfaceWidth || height != mSurfaceHeight) {
mSurfaceWidth = width;
mSurfaceHeight = height;
refreshScale();
crop();
mSurfaceCallback.onSurfaceChanged();
}
}
@ -84,7 +84,7 @@ abstract class PreviewImpl {
protected final void onSurfaceDestroyed() {
mSurfaceWidth = 0;
mSurfaceHeight = 0;
refreshScale();
crop();
}
@ -93,7 +93,7 @@ abstract class PreviewImpl {
* to match the desired aspect ratio.
* This means that the external part of the surface will be cropped by the outer view.
*/
private final void refreshScale() {
private final void crop() {
getView().post(new Runnable() {
@Override
public void run() {
@ -116,4 +116,14 @@ abstract class PreviewImpl {
}
});
}
/**
* Whether we are cropping the output.
* If false, this means that the output image will match the visible bounds.
* @return true if cropping
*/
final boolean isCropping() {
return getView().getScaleX() > 1 || getView().getScaleY() > 1;
}
}

@ -983,23 +983,20 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
* @param consistentWithView is the final image (decoded respecting EXIF data) consistent with
* the view width and height? Or should we flip dimensions to have a
* consistent measure?
* @param flipPicture whether this picture should be flipped horizontally after decoding,
* because it was taken with the front camera.
* @param flipHorizontally whether this picture should be flipped horizontally after decoding,
* because it was taken with the front camera.
*/
public void processJpegPicture(final byte[] jpeg, final boolean consistentWithView, final boolean flipPicture) {
public void processImage(final byte[] jpeg, final boolean consistentWithView, final boolean flipHorizontally) {
getWorkerHandler().post(new Runnable() {
@Override
public void run() {
byte[] jpeg2 = jpeg;
if (mCropOutput) {
if (mCropOutput && mPreviewImpl.isCropping()) {
// If consistent, dimensions of the jpeg Bitmap and dimensions of getWidth(), getHeight()
// Live in the same reference system.
AspectRatio targetRatio;
if (consistentWithView) {
targetRatio = AspectRatio.of(getWidth(), getHeight());
} else {
targetRatio = AspectRatio.of(getHeight(), getWidth());
}
int w = consistentWithView ? getWidth() : getHeight();
int h = consistentWithView ? getHeight() : getWidth();
AspectRatio targetRatio = AspectRatio.of(w, h);
Log.e(TAG, "is Consistent? " + consistentWithView);
Log.e(TAG, "viewWidth? " + getWidth() + ", viewHeight? " + getHeight());
jpeg2 = CropHelper.cropToJpeg(jpeg, targetRatio, mJpegQuality);
@ -1010,11 +1007,13 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
public void processYuvPicture(YuvImage yuv) {
public void processSnapshot(YuvImage yuv, boolean consistentWithView, boolean flipHorizontally) {
byte[] jpeg;
if (mCropOutput) {
AspectRatio outputRatio = AspectRatio.of(getWidth(), getHeight());
jpeg = CropHelper.cropToJpeg(yuv, outputRatio, mJpegQuality);
if (mCropOutput && mPreviewImpl.isCropping()) {
int w = consistentWithView ? getWidth() : getHeight();
int h = consistentWithView ? getHeight() : getWidth();
AspectRatio targetRatio = AspectRatio.of(w, h);
jpeg = CropHelper.cropToJpeg(yuv, targetRatio, mJpegQuality);
} else {
ByteArrayOutputStream out = new ByteArrayOutputStream();
yuv.compressToJpeg(new Rect(0, 0, yuv.getWidth(), yuv.getHeight()), mJpegQuality, out);

@ -24,8 +24,8 @@ public class CropHelper {
// This reads a rotated Bitmap thanks to CameraUtils. Then crops and returns a byte array.
// In doing so, EXIF data is deleted.
public static byte[] cropToJpeg(byte[] jpeg, AspectRatio targetRatio, int jpegCompression) {
Bitmap image = CameraUtils.decodeBitmap(jpeg);
Log.e("CropHelper", "decoded image has width="+image.getWidth()+", height="+image.getHeight());
Rect cropRect = computeCrop(image.getWidth(), image.getHeight(), targetRatio);
Bitmap crop = Bitmap.createBitmap(image, cropRect.left, cropRect.top, cropRect.width(), cropRect.height());
image.recycle();
@ -44,10 +44,10 @@ public class CropHelper {
x = (currentWidth - width) / 2;
} else {
width = currentWidth;
height = (int) (width * targetRatio.inverse().toFloat());
height = (int) (width / targetRatio.toFloat());
y = (currentHeight - height) / 2;
x = 0;
}
return new Rect(x, y, x+width, y+height);
return new Rect(x, y, x + width, y + height);
}
}

Loading…
Cancel
Save