pull/1/head
Dylan McIntyre 8 years ago
parent 5450510b58
commit 0a4a60ac2f
  1. 29
      README.md
  2. 468
      camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java
  3. 62
      camerakit/src/main/api16/com/flurgle/camerakit/ConstantMapper.java
  4. 55
      camerakit/src/main/api16/com/flurgle/camerakit/ProcessStillTask.java
  5. 449
      camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java
  6. 10
      camerakit/src/main/base/com/flurgle/camerakit/CameraImpl.java
  7. 2
      camerakit/src/main/base/com/flurgle/camerakit/PreviewImpl.java
  8. 2
      camerakit/src/main/base/com/flurgle/camerakit/TextureViewPreview.java
  9. 9
      camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java
  10. 62
      camerakit/src/main/java/com/flurgle/camerakit/CameraView.java
  11. 4
      camerakit/src/main/res/values/attrs.xml
  12. 3
      camerakit/src/main/res/values/strings.xml
  13. 5
      camerakit/src/main/utils/com/flurgle/camerakit/CenterCrop.java
  14. 44
      camerakit/src/main/utils/com/flurgle/camerakit/Rotation.java
  15. 2
      demo/src/main/java/com/flurgle/camerakit/demo/MainActivity.java
  16. 3
      demo/src/main/res/layout/activity_main.xml

@ -24,9 +24,11 @@ Try out all the unique features using the CameraKit Demo from the Google Play st
- [`ckFacing`](#ckfacing)
- [`ckFlash`](#ckflash)
- [`ckCaptureMode`](#ckcapturemode)
- [`ckPinchToZoom`](#ckpinchtozoom)
- [`ckTapToFocus`](#cktaptofocus)
- [`ckAutoFocus`](#ckautofocus)
- [`ckCaptureSize`](#ckcapturesize)
- [`ckJpegCompression`](#ckjpegcompression)
- [Capturing Images](#capturing-images)
- [Capturing Video](#capturing-video)
- [Automatic Permissions Behavior](#automatic-permissions-behavior)
@ -44,15 +46,17 @@ Try out all the unique features using the CameraKit Demo from the Google Play st
## Features
- Image and video capture seamlessly working with the same preview session.
- Automatic use of both Camera and Camera2 APIs.
- Automatic system permission handling.
- Automatic preview scaling.
- Create a `CameraView` of any size (not just presets!).
- Automatic output cropping to match your `CameraView` bounds.
- Multiple capture modes.
- `PICTURE_MODE_QUALITY`: an image captured normally using the camera APIs.
- `PICTURE_MODE_SPEED`: a freeze frame of the `CameraView` preview (similar to SnapChat and Instagram) for devices with slower cameras.
- `PICTURE_MODE_STANDARD`: an image captured normally using the camera APIs.
- `PICTURE_MODE_STILL`: a freeze frame of the `CameraView` preview (similar to SnapChat and Instagram) for devices with slower cameras.
- Automatic picture mode determination based on measured speed.
- Built-in tap to focus and auto focus.
- Built-in pinch to zoom.
## Setup
@ -70,7 +74,7 @@ To use CameraKit, simply add a `CameraView` to your layout:
<com.flurgle.camerakit.CameraView
android:id="@+id/camera"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="wrap_content" />
```
Make sure you override `onResume` and `onPause` in your activity, and make calls respectively to `CameraView.start()` and `CameraView.stop()`.
@ -130,9 +134,11 @@ camera.setCameraListener(new CameraListener() {
camerakit:ckFacing="back"
camerakit:ckFlash="off"
camerakit:ckCaptureMode="quality"
camerakit:ckPinchToZoom="true"
camerakit:ckTapToFocus="on"
camerakit:ckAutoFocus="true"
camerakit:ckCaptureSize="8" />
camerakit:ckCaptureSize="8"
camerakit:ckJpegCompression="100" />
```
#### `ckCropOutput`
@ -149,7 +155,6 @@ camera.setCameraListener(new CameraListener() {
| `back` | Default `CameraView` preview to back camera. |
| `front` | Default `CameraView` preview to front camera. |
#### `ckFlash`
| Value | Description |
@ -166,6 +171,13 @@ camera.setCameraListener(new CameraListener() {
| `still` | Freeze the `CameraView` preview and grab a `Bitmap` of the frame. |
| `auto` (coming soon) | Default picture mode to `standard`, but fallback to `still` if capturing is determined to be too slow. |
#### `ckPinchToZoom`
| Value | Description |
| --------------| -------------|
| `true` | User can zoom using pinching gestures with their fingers. |
| `false` | Default pinch to zoom behavior disabled. |
#### `ckTapToFocus`
| Value | Description |
@ -188,6 +200,13 @@ camera.setCameraListener(new CameraListener() {
| `n <= 0` | Capture at the highest quality possible. |
| `n > 0` | Capture at a size of approximately `n` megapixels. |
#### `ckJpegCompression`
| Value | Description |
| --------------| -------------|
| `0 <= n <= 100`| Percent quality for returned JPEG data. |
### Capturing Images
To capture an image just call `CameraView.capturePicture()`. Make sure you setup a `CameraListener` to handle the image callback.

@ -2,179 +2,111 @@ package com.flurgle.camerakit;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.util.SparseArrayCompat;
import android.view.SurfaceHolder;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.Set;
import java.util.TreeSet;
@SuppressWarnings("deprecation")
public class Camera1 extends CameraImpl {
private static final SparseArrayCompat<String> FLASH_MODES = new SparseArrayCompat<>();
static {
FLASH_MODES.put(CameraKit.Constants.FLASH_OFF, Camera.Parameters.FLASH_MODE_OFF);
FLASH_MODES.put(CameraKit.Constants.FLASH_ON, Camera.Parameters.FLASH_MODE_ON);
FLASH_MODES.put(CameraKit.Constants.FLASH_AUTO, Camera.Parameters.FLASH_MODE_AUTO);
}
private static final SparseArrayCompat<Integer> FACING_MODES = new SparseArrayCompat<>();
static {
FACING_MODES.put(CameraKit.Constants.FACING_BACK, Camera.CameraInfo.CAMERA_FACING_BACK);
FACING_MODES.put(CameraKit.Constants.FACING_FRONT, Camera.CameraInfo.CAMERA_FACING_FRONT);
}
private File mVideoFile;
private int mCameraId;
private Camera mCamera;
private Camera.Parameters mCameraParameters;
private final Camera.CameraInfo mCameraInfo = new Camera.CameraInfo();
private Camera.CameraInfo mCameraInfo;
private Size mPreviewSize;
private Size mCaptureSize;
private boolean mShowingPreview;
private boolean mAutoFocus;
private int mFacing;
private int mFlash;
private boolean mContinuousFocus;
private int mDisplayOrientation;
private TreeSet<Size> mPreviewSizes;
private TreeSet<Size> mCaptureSizes;
private MediaRecorder mMediaRecorder;
private CameraListener mCameraListener;
Camera1(@NonNull CameraListener cameraListener, @NonNull PreviewImpl preview) {
super(cameraListener, preview);
this.mCameraListener = cameraListener;
this.mPreviewSizes = new TreeSet<>();
this.mCaptureSizes = new TreeSet<>();
this.mVideoFile = new File(mPreview.getView().getContext().getExternalFilesDir(null), "video.mp4");
Camera1(CameraListener callback, PreviewImpl preview) {
super(callback, preview);
preview.setCallback(new PreviewImpl.Callback() {
@Override
public void onSurfaceChanged() {
if (mCamera != null) {
setUpPreview();
setupPreview();
adjustCameraParameters();
}
}
});
mCameraInfo = new Camera.CameraInfo();
}
// CameraImpl:
@Override
void start() {
setFacingInternal(mFacing);
setFacing(mFacing);
openCamera();
if (mPreview.isReady()) {
setUpPreview();
}
mShowingPreview = true;
if (mPreview.isReady()) setupPreview();
mCamera.startPreview();
}
@Override
void stop() {
if (mCamera != null) {
mCamera.stopPreview();
}
mShowingPreview = false;
if (mCamera != null) mCamera.stopPreview();
releaseCamera();
}
@Override
boolean isCameraOpened() {
return mCamera != null;
}
@Override
void setFacing(int facing) {
if (mFacing == facing) {
void setFacing(@Facing int facing) {
int internalFacing = new ConstantMapper.Facing(facing).map();
if (internalFacing == -1) {
return;
}
if (setFacingInternal(facing) && isCameraOpened()) {
stop();
start();
}
}
private boolean setFacingInternal(int facing) {
int trueValue = FACING_MODES.get(facing, -1);
if (trueValue == -1) {
return false;
}
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
Camera.getCameraInfo(i, mCameraInfo);
if (mCameraInfo.facing == trueValue) {
if (mCameraInfo.facing == internalFacing) {
mCameraId = i;
mFacing = facing;
return true;
}
break;
}
return false;
}
@Override
void setFlash(int flash) {
if (flash == mFlash) {
return;
}
if (setFlashInternal(flash)) {
mCamera.setParameters(mCameraParameters);
if (mFacing == facing && isCameraOpened()) {
stop();
start();
}
}
private boolean setFlashInternal(int flash) {
@Override
void setFlash(@Flash int flash) {
if (isCameraOpened()) {
List<String> modes = mCameraParameters.getSupportedFlashModes();
String mode = FLASH_MODES.get(flash);
if (modes != null && modes.contains(mode)) {
mCameraParameters.setFlashMode(mode);
List<String> flashes = mCameraParameters.getSupportedFlashModes();
String internalFlash = new ConstantMapper.Flash(flash).map();
if (flashes != null && flashes.contains(internalFlash)) {
mCameraParameters.setFlashMode(internalFlash);
mFlash = flash;
return true;
}
String currentMode = FLASH_MODES.get(mFlash);
if (modes == null || !modes.contains(currentMode)) {
} else {
String currentFlash = new ConstantMapper.Flash(mFlash).map();
if (flashes == null || !flashes.contains(currentFlash)) {
mCameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
mFlash = CameraKit.Constants.FLASH_OFF;
return true;
}
return false;
} else {
mFlash = flash;
return false;
}
}
@Override
void setAutoFocus(boolean autoFocus) {
if (autoFocus == mAutoFocus) {
return;
}
if (setAutoFocusInternal(autoFocus)) {
mCamera.setParameters(mCameraParameters);
} else {
mFlash = flash;
}
}
private boolean setAutoFocusInternal(boolean autoFocus) {
mAutoFocus = autoFocus;
if (isCameraOpened()) {
@Override
void setContinuousFocus(boolean continuousFocus) {
this.mContinuousFocus = continuousFocus;
if (mCameraParameters != null) {
final List<String> modes = mCameraParameters.getSupportedFocusModes();
if (autoFocus && modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
if (mContinuousFocus && modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
@ -183,33 +115,26 @@ public class Camera1 extends CameraImpl {
} else {
mCameraParameters.setFocusMode(modes.get(0));
}
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
return true;
} else {
return false;
}
}
@Override
void captureStandard() {
if (!isCameraOpened()) {
throw new IllegalStateException("Camera is not ready. Call start() before takePicture().");
void setDisplayOrientation(int displayOrientation) {
this.mDisplayOrientation = displayOrientation;
}
if (mAutoFocus) {
mCamera.cancelAutoFocus();
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
takePictureInternal();
}
});
} else {
takePictureInternal();
void focus() {
mCamera.autoFocus(null);
}
@Override
void zoom(float percentZoom) {
}
void takePictureInternal() {
@Override
void captureStandard() {
mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
@ -227,155 +152,106 @@ public class Camera1 extends CameraImpl {
new Thread(new ProcessStillTask(data, camera, mCameraInfo, new ProcessStillTask.OnStillProcessedListener() {
@Override
public void onStillProcessed(final YuvImage yuv) {
mPreview.getView().post(new Runnable() {
@Override
public void run() {
mCameraListener.onPictureTaken(yuv);
}
});
}
})).start();
}
});
}
static class ProcessStillTask implements Runnable {
byte[] data;
Camera camera;
Camera.CameraInfo cameraInfo;
OnStillProcessedListener onStillProcessedListener;
@Override
void startVideo() {
public ProcessStillTask(byte[] data, Camera camera, Camera.CameraInfo cameraInfo, OnStillProcessedListener onStillProcessedListener) {
this.data = data;
this.camera = camera;
this.cameraInfo = cameraInfo;
this.onStillProcessedListener = onStillProcessedListener;
}
@Override
public void run() {
Camera.Parameters parameters = camera.getParameters();
int width = parameters.getPreviewSize().width;
int height = parameters.getPreviewSize().height;
int rotation = cameraInfo.orientation;
byte[] rotatedData = YuvUtils.rotateNV21(data, width, height, rotation);
int postWidth;
int postHeight;
switch (rotation) {
case 90:
case 270:
postWidth = height;
postHeight = width;
break;
void endVideo() {
case 0:
case 180:
default:
postWidth = width;
postHeight = height;
break;
}
YuvImage yuv = new YuvImage(rotatedData, parameters.getPreviewFormat(), postWidth, postHeight, null);
onStillProcessedListener.onStillProcessed(yuv);
@Override
Size getCaptureResolution() {
if (mCaptureSize == null && mCameraParameters != null) {
TreeSet<Size> sizes = new TreeSet<>();
for (Camera.Size size : mCameraParameters.getSupportedPictureSizes()) {
sizes.add(new Size(size.width, size.height));
}
interface OnStillProcessedListener {
void onStillProcessed(YuvImage yuv);
TreeSet<AspectRatio> aspectRatios = findCommonAspectRatios(
mCameraParameters.getSupportedPreviewSizes(),
mCameraParameters.getSupportedPictureSizes()
);
AspectRatio targetRatio = aspectRatios.last();
Iterator<Size> descendingSizes = sizes.descendingIterator();
Size size;
while (descendingSizes.hasNext() && mCaptureSize == null) {
size = descendingSizes.next();
if (targetRatio.matches(size)) {
mCaptureSize = size;
break;
}
}
}
return mCaptureSize;
}
@Override
void startVideo() {
try {
prepareMediaRecorder();
} catch (IOException e) {
if (mMediaRecorder != null) {
mMediaRecorder.release();
Size getPreviewResolution() {
if (mPreviewSize == null && mCameraParameters != null) {
TreeSet<Size> sizes = new TreeSet<>();
for (Camera.Size size : mCameraParameters.getSupportedPreviewSizes()) {
sizes.add(new Size(size.width, size.height));
}
return;
TreeSet<AspectRatio> aspectRatios = findCommonAspectRatios(
mCameraParameters.getSupportedPreviewSizes(),
mCameraParameters.getSupportedPictureSizes()
);
AspectRatio targetRatio = aspectRatios.last();
Iterator<Size> descendingSizes = sizes.descendingIterator();
Size size;
while (descendingSizes.hasNext() && mPreviewSize == null) {
size = descendingSizes.next();
if (targetRatio.matches(size)) {
mPreviewSize = size;
break;
}
}
}
void prepareMediaRecorder() throws IOException {
mCamera.unlock();
mMediaRecorder = new MediaRecorder();
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_480P));
mMediaRecorder.setOutputFile(mVideoFile.getAbsolutePath());
mMediaRecorder.setOrientationHint(mCameraInfo.orientation);
mMediaRecorder.prepare();
mMediaRecorder.start();
return mPreviewSize;
}
@Override
void endVideo() {
if (mMediaRecorder != null) {
mMediaRecorder.stop();
mMediaRecorder = null;
boolean isCameraOpened() {
return mCamera != null;
}
mCameraListener.onVideoTaken(mVideoFile);
// Internal:
private void openCamera() {
if (mCamera != null) {
releaseCamera();
}
@Override
void focus() {
mCamera.autoFocus(null);
}
mCamera = Camera.open(mCameraId);
mCameraParameters = mCamera.getParameters();
@Override
void setDisplayOrientation(int displayOrientation) {
if (mDisplayOrientation == displayOrientation) {
return;
}
mDisplayOrientation = displayOrientation;
if (isCameraOpened()) {
int cameraRotation = calcCameraRotation(displayOrientation);
mCameraParameters.setRotation(cameraRotation);
mCamera.setParameters(mCameraParameters);
final boolean needsToStopPreview = mShowingPreview && Build.VERSION.SDK_INT < 14;
if (needsToStopPreview) {
mCamera.stopPreview();
}
mCamera.setDisplayOrientation(cameraRotation);
if (needsToStopPreview) {
mCamera.startPreview();
}
}
}
adjustCameraParameters();
mCamera.setDisplayOrientation(
calculateCameraRotation(mDisplayOrientation)
);
private int calcCameraRotation(int rotation) {
if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
return (360 - (mCameraInfo.orientation + rotation) % 360) % 360;
} else {
return (mCameraInfo.orientation - rotation + 360) % 360;
}
mCameraListener.onCameraOpened();
}
private void setUpPreview() {
private void setupPreview() {
try {
if (mPreview.getOutputClass() == SurfaceHolder.class) {
final boolean needsToStopPreview = mShowingPreview && Build.VERSION.SDK_INT < 14;
if (needsToStopPreview) {
mCamera.stopPreview();
}
mCamera.setPreviewDisplay(mPreview.getSurfaceHolder());
if (needsToStopPreview) {
mCamera.startPreview();
}
} else {
mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
}
@ -384,110 +260,70 @@ public class Camera1 extends CameraImpl {
}
}
private void adjustCameraParameters() {
SortedSet<Size> sizes = mPreviewSizes;
mPreviewSize = chooseOptimalSize(sizes);
final Camera.Size currentSize = mCameraParameters.getPictureSize();
if (currentSize.width != mPreviewSize.getWidth() || currentSize.height != mPreviewSize.getHeight()) {
Iterator<Size> iterator = mCaptureSizes.descendingIterator();
Size pictureSize;
while ((pictureSize = iterator.next()) != null) {
if (AspectRatio.of(mPreviewSize.getWidth(), mPreviewSize.getHeight()).matches(pictureSize)) {
break;
private void releaseCamera() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
mCameraListener.onCameraClosed();
}
}
if (pictureSize == null) {
pictureSize = mCaptureSizes.last();
private int calculateCameraRotation(int rotation) {
if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
return (360 - (mCameraInfo.orientation + rotation) % 360) % 360;
} else {
return (mCameraInfo.orientation - rotation + 360) % 360;
}
mCaptureSize = pictureSize;
if (mShowingPreview) {
mCamera.stopPreview();
}
mCameraParameters.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
mPreview.setTruePreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
mCameraParameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
mCameraParameters.setRotation(calcCameraRotation(mDisplayOrientation) + (mFacing == CameraKit.Constants.FACING_FRONT ? 180 : 0));
setAutoFocusInternal(mAutoFocus);
private void adjustCameraParameters() {
mCameraParameters.setPreviewSize(
getPreviewResolution().getWidth(),
getPreviewResolution().getHeight()
);
//setFlashInternal(mFlash);
mPreview.setTruePreviewSize(
getPreviewResolution().getWidth(),
getPreviewResolution().getHeight()
);
mCamera.setParameters(mCameraParameters);
if (mShowingPreview) {
mCamera.startPreview();
}
}
}
mCameraParameters.setPictureSize(
getCaptureResolution().getWidth(),
getCaptureResolution().getHeight()
);
private Size chooseOptimalSize(SortedSet<Size> sizes) {
if (!mPreview.isReady()) { // Not yet laid out
return sizes.last(); // Return the smallest size
}
mCameraParameters.setRotation(
calculateCameraRotation(mDisplayOrientation)
+ (mFacing == CameraKit.Constants.FACING_FRONT ? 180 : 0)
);
int desiredWidth;
int desiredHeight;
final int surfaceWidth = mPreview.getWidth();
final int surfaceHeight = mPreview.getHeight();
if (mDisplayOrientation == 90 || mDisplayOrientation == 270) {
desiredWidth = surfaceHeight;
desiredHeight = surfaceWidth;
} else {
desiredWidth = surfaceWidth;
desiredHeight = surfaceHeight;
}
Size result = null;
for (Size size : sizes) { // Iterate from small to large
if (desiredWidth <= size.getWidth() && desiredHeight <= size.getHeight()) {
return size;
setContinuousFocus(mContinuousFocus);
setFlash(mFlash);
}
result = size;
}
return result;
mCamera.setParameters(mCameraParameters);
}
private void openCamera() {
if (mCamera != null) {
releaseCamera();
private TreeSet<AspectRatio> findCommonAspectRatios(List<Camera.Size> previewSizes, List<Camera.Size> captureSizes) {
Set<AspectRatio> previewAspectRatios = new HashSet<>();
for (Camera.Size size : previewSizes) {
if (size.width >= CameraKit.Internal.screenHeight && size.height >= CameraKit.Internal.screenWidth) {
previewAspectRatios.add(AspectRatio.of(size.width, size.height));
}
mCamera = Camera.open(mCameraId);
mCameraParameters = mCamera.getParameters();
// Supported preview sizes
mPreviewSizes.clear();
for (Camera.Size size : mCameraParameters.getSupportedPreviewSizes()) {
mPreviewSizes.add(new Size(size.width, size.height));
}
// Supported picture sizes;
mCaptureSizes.clear();
for (Camera.Size size : mCameraParameters.getSupportedPictureSizes()) {
mCaptureSizes.add(new Size(size.width, size.height));
}
adjustCameraParameters();
mCamera.setDisplayOrientation(calcCameraRotation(mDisplayOrientation));
mCameraListener.onCameraOpened();
Set<AspectRatio> captureAspectRatios = new HashSet<>();
for (Camera.Size size : captureSizes) {
captureAspectRatios.add(AspectRatio.of(size.width, size.height));
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
mCameraListener.onCameraClosed();
TreeSet<AspectRatio> output = new TreeSet<>();
for (AspectRatio aspectRatio : previewAspectRatios) {
if (captureAspectRatios.contains(aspectRatio)) {
output.add(aspectRatio);
}
}
@Override
Size getCaptureResolution() {
return mCaptureSize;
return output;
}
@Override
Size getPreviewResolution() {
return mPreviewSize;
}
}

@ -0,0 +1,62 @@
package com.flurgle.camerakit;
import android.hardware.Camera;
import android.support.v4.util.SparseArrayCompat;
public class ConstantMapper {
private abstract static class BaseMapper<T> {
protected int mCameraKitConstant;
protected BaseMapper(int cameraKitConstant) {
this.mCameraKitConstant = cameraKitConstant;
}
abstract T map();
}
public static class Flash extends BaseMapper<String> {
private static final SparseArrayCompat<String> FLASH_MODES = new SparseArrayCompat<>();
static {
FLASH_MODES.put(CameraKit.Constants.FLASH_OFF, Camera.Parameters.FLASH_MODE_OFF);
FLASH_MODES.put(CameraKit.Constants.FLASH_ON, Camera.Parameters.FLASH_MODE_ON);
FLASH_MODES.put(CameraKit.Constants.FLASH_AUTO, Camera.Parameters.FLASH_MODE_AUTO);
}
protected Flash(int cameraKitConstant) {
super(cameraKitConstant);
}
@Override
String map() {
return FLASH_MODES.get(mCameraKitConstant, FLASH_MODES.get(CameraKit.Constants.FLASH_OFF));
}
}
public static class Facing extends BaseMapper<Integer> {
private static final SparseArrayCompat<Integer> FACING_MODES = new SparseArrayCompat<>();
static {
FACING_MODES.put(CameraKit.Constants.FACING_BACK, Camera.CameraInfo.CAMERA_FACING_BACK);
FACING_MODES.put(CameraKit.Constants.FACING_FRONT, Camera.CameraInfo.CAMERA_FACING_FRONT);
}
protected Facing(int cameraKitConstant) {
super(cameraKitConstant);
}
@Override
Integer map() {
return FACING_MODES.get(mCameraKitConstant, FACING_MODES.get(Camera.CameraInfo.CAMERA_FACING_BACK));
}
}
}

@ -0,0 +1,55 @@
package com.flurgle.camerakit;
import android.graphics.YuvImage;
import android.hardware.Camera;
class ProcessStillTask implements Runnable {
private byte[] data;
private Camera camera;
private Camera.CameraInfo cameraInfo;
private OnStillProcessedListener onStillProcessedListener;
public ProcessStillTask(byte[] data, Camera camera, Camera.CameraInfo cameraInfo, OnStillProcessedListener onStillProcessedListener) {
this.data = data;
this.camera = camera;
this.cameraInfo = cameraInfo;
this.onStillProcessedListener = onStillProcessedListener;
}
@Override
public void run() {
Camera.Parameters parameters = camera.getParameters();
int width = parameters.getPreviewSize().width;
int height = parameters.getPreviewSize().height;
int rotation = cameraInfo.orientation;
byte[] rotatedData = new Rotation(data, width, height, rotation).getYuv();
int postWidth;
int postHeight;
switch (rotation) {
case 90:
case 270:
postWidth = height;
postHeight = width;
break;
case 0:
case 180:
default:
postWidth = width;
postHeight = height;
break;
}
YuvImage yuv = new YuvImage(rotatedData, parameters.getPreviewFormat(), postWidth, postHeight, null);
onStillProcessedListener.onStillProcessed(yuv);
}
interface OnStillProcessedListener {
void onStillProcessed(YuvImage yuv);
}
}

@ -1,493 +1,84 @@
package com.flurgle.camerakit;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.util.SparseArrayCompat;
import android.view.SurfaceHolder;
class Camera2 extends CameraImpl {
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
public class Camera2 extends CameraImpl {
private static final SparseArrayCompat<String> FLASH_MODES = new SparseArrayCompat<>();
static {
FLASH_MODES.put(CameraKit.Constants.FLASH_OFF, Camera.Parameters.FLASH_MODE_OFF);
FLASH_MODES.put(CameraKit.Constants.FLASH_ON, Camera.Parameters.FLASH_MODE_ON);
FLASH_MODES.put(CameraKit.Constants.FLASH_AUTO, Camera.Parameters.FLASH_MODE_AUTO);
}
private static final SparseArrayCompat<Integer> FACING_MODES = new SparseArrayCompat<>();
static {
FACING_MODES.put(CameraKit.Constants.FACING_BACK, Camera.CameraInfo.CAMERA_FACING_BACK);
FACING_MODES.put(CameraKit.Constants.FACING_FRONT, Camera.CameraInfo.CAMERA_FACING_FRONT);
}
private File mVideoFile;
private int mCameraId;
private Camera mCamera;
private Camera.Parameters mCameraParameters;
private final Camera.CameraInfo mCameraInfo = new Camera.CameraInfo();
private Size mPreviewSize;
private Size mCaptureSize;
private boolean mShowingPreview;
private boolean mAutoFocus;
private int mFacing;
private int mFlash;
private int mDisplayOrientation;
private TreeSet<Size> mPreviewSizes;
private TreeSet<Size> mCaptureSizes;
private MediaRecorder mMediaRecorder;
private CameraListener mCameraListener;
Camera2(@NonNull CameraListener cameraListener, @NonNull PreviewImpl preview) {
super(cameraListener, preview);
this.mCameraListener = cameraListener;
this.mPreviewSizes = new TreeSet<>();
this.mCaptureSizes = new TreeSet<>();
this.mVideoFile = new File(mPreview.getView().getContext().getExternalFilesDir(null), "video.mp4");
preview.setCallback(new PreviewImpl.Callback() {
@Override
public void onSurfaceChanged() {
if (mCamera != null) {
setUpPreview();
adjustCameraParameters();
}
}
});
Camera2(CameraListener callback, PreviewImpl preview) {
super(callback, preview);
}
@Override
void start() {
setFacingInternal(mFacing);
openCamera();
if (mPreview.isReady()) {
setUpPreview();
}
mShowingPreview = true;
mCamera.startPreview();
}
@Override
void stop() {
if (mCamera != null) {
mCamera.stopPreview();
}
mShowingPreview = false;
releaseCamera();
}
@Override
boolean isCameraOpened() {
return mCamera != null;
}
@Override
void setFacing(int facing) {
if (mFacing == facing) {
return;
}
if (setFacingInternal(facing) && isCameraOpened()) {
stop();
start();
}
}
void setFacing(@Facing int facing) {
private boolean setFacingInternal(int facing) {
int trueValue = FACING_MODES.get(facing, -1);
if (trueValue == -1) {
return false;
}
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
Camera.getCameraInfo(i, mCameraInfo);
if (mCameraInfo.facing == trueValue) {
mCameraId = i;
mFacing = facing;
return true;
}
}
return false;
}
@Override
void setFlash(int flash) {
if (flash == mFlash) {
return;
}
if (setFlashInternal(flash)) {
mCamera.setParameters(mCameraParameters);
}
}
void setFlash(@Flash int flash) {
private boolean setFlashInternal(int flash) {
if (isCameraOpened()) {
List<String> modes = mCameraParameters.getSupportedFlashModes();
String mode = FLASH_MODES.get(flash);
if (modes != null && modes.contains(mode)) {
mCameraParameters.setFlashMode(mode);
mFlash = flash;
return true;
}
String currentMode = FLASH_MODES.get(mFlash);
if (modes == null || !modes.contains(currentMode)) {
mCameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
mFlash = CameraKit.Constants.FLASH_OFF;
return true;
}
return false;
} else {
mFlash = flash;
return false;
}
}
@Override
void setAutoFocus(boolean autoFocus) {
if (autoFocus == mAutoFocus) {
return;
}
if (setAutoFocusInternal(autoFocus)) {
mCamera.setParameters(mCameraParameters);
}
}
private boolean setAutoFocusInternal(boolean autoFocus) {
mAutoFocus = autoFocus;
if (isCameraOpened()) {
final List<String> modes = mCameraParameters.getSupportedFocusModes();
if (autoFocus && modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
} else if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
} else {
mCameraParameters.setFocusMode(modes.get(0));
}
void setContinuousFocus(boolean autoFocus) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
return true;
} else {
return false;
}
}
@Override
void captureStandard() {
if (!isCameraOpened()) {
throw new IllegalStateException("Camera is not ready. Call start() before takePicture().");
}
if (mAutoFocus) {
mCamera.cancelAutoFocus();
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
takePictureInternal();
}
});
} else {
takePictureInternal();
}
}
void setDisplayOrientation(int displayOrientation) {
void takePictureInternal() {
mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
mCameraListener.onPictureTaken(data);
camera.startPreview();
}
});
}
@Override
void captureStill() {
mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
new Thread(new ProcessStillTask(data, camera, mCameraInfo, new ProcessStillTask.OnStillProcessedListener() {
@Override
public void onStillProcessed(final YuvImage yuv) {
mPreview.getView().post(new Runnable() {
@Override
public void run() {
mCameraListener.onPictureTaken(yuv);
}
});
}
})).start();
}
});
}
static class ProcessStillTask implements Runnable {
byte[] data;
Camera camera;
Camera.CameraInfo cameraInfo;
OnStillProcessedListener onStillProcessedListener;
void focus() {
public ProcessStillTask(byte[] data, Camera camera, Camera.CameraInfo cameraInfo, OnStillProcessedListener onStillProcessedListener) {
this.data = data;
this.camera = camera;
this.cameraInfo = cameraInfo;
this.onStillProcessedListener = onStillProcessedListener;
}
@Override
public void run() {
Camera.Parameters parameters = camera.getParameters();
int width = parameters.getPreviewSize().width;
int height = parameters.getPreviewSize().height;
int rotation = cameraInfo.orientation;
byte[] rotatedData = YuvUtils.rotateNV21(data, width, height, rotation);
int postWidth;
int postHeight;
switch (rotation) {
case 90:
case 270:
postWidth = height;
postHeight = width;
break;
void zoom(float percentZoom) {
case 0:
case 180:
default:
postWidth = width;
postHeight = height;
break;
}
YuvImage yuv = new YuvImage(rotatedData, parameters.getPreviewFormat(), postWidth, postHeight, null);
@Override
void captureStandard() {
onStillProcessedListener.onStillProcessed(yuv);
}
interface OnStillProcessedListener {
void onStillProcessed(YuvImage yuv);
}
@Override
void captureStill() {
}
@Override
void startVideo() {
try {
prepareMediaRecorder();
} catch (IOException e) {
if (mMediaRecorder != null) {
mMediaRecorder.release();
}
return;
}
}
void prepareMediaRecorder() throws IOException {
mCamera.unlock();
mMediaRecorder = new MediaRecorder();
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_480P));
mMediaRecorder.setOutputFile(mVideoFile.getAbsolutePath());
mMediaRecorder.setOrientationHint(mCameraInfo.orientation);
mMediaRecorder.prepare();
mMediaRecorder.start();
}
@Override
void endVideo() {
if (mMediaRecorder != null) {
mMediaRecorder.stop();
mMediaRecorder = null;
}
mCameraListener.onVideoTaken(mVideoFile);
}
@Override
void focus() {
mCamera.autoFocus(null);
Size getCaptureResolution() {
return null;
}
@Override
void setDisplayOrientation(int displayOrientation) {
if (mDisplayOrientation == displayOrientation) {
return;
}
mDisplayOrientation = displayOrientation;
if (isCameraOpened()) {
int cameraRotation = calcCameraRotation(displayOrientation);
mCameraParameters.setRotation(cameraRotation);
mCamera.setParameters(mCameraParameters);
final boolean needsToStopPreview = mShowingPreview && Build.VERSION.SDK_INT < 14;
if (needsToStopPreview) {
mCamera.stopPreview();
}
mCamera.setDisplayOrientation(cameraRotation);
if (needsToStopPreview) {
mCamera.startPreview();
}
}
}
private int calcCameraRotation(int rotation) {
if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
return (360 - (mCameraInfo.orientation + rotation) % 360) % 360;
} else {
return (mCameraInfo.orientation - rotation + 360) % 360;
}
}
private void setUpPreview() {
try {
if (mPreview.getOutputClass() == SurfaceHolder.class) {
final boolean needsToStopPreview = mShowingPreview && Build.VERSION.SDK_INT < 14;
if (needsToStopPreview) {
mCamera.stopPreview();
}
mCamera.setPreviewDisplay(mPreview.getSurfaceHolder());
if (needsToStopPreview) {
mCamera.startPreview();
}
} else {
mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void adjustCameraParameters() {
SortedSet<Size> sizes = mPreviewSizes;
mPreviewSize = chooseOptimalSize(sizes);
final Camera.Size currentSize = mCameraParameters.getPictureSize();
if (currentSize.width != mPreviewSize.getWidth() || currentSize.height != mPreviewSize.getHeight()) {
Iterator<Size> iterator = mCaptureSizes.descendingIterator();
Size pictureSize;
while ((pictureSize = iterator.next()) != null) {
if (AspectRatio.of(mPreviewSize.getWidth(), mPreviewSize.getHeight()).matches(pictureSize)) {
break;
}
}
if (pictureSize == null) {
pictureSize = mCaptureSizes.last();
}
mCaptureSize = pictureSize;
if (mShowingPreview) {
mCamera.stopPreview();
}
mCameraParameters.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
mPreview.setTruePreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
mCameraParameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
mCameraParameters.setRotation(calcCameraRotation(mDisplayOrientation) + (mFacing == CameraKit.Constants.FACING_FRONT ? 180 : 0));
setAutoFocusInternal(mAutoFocus);
//setFlashInternal(mFlash);
mCamera.setParameters(mCameraParameters);
if (mShowingPreview) {
mCamera.startPreview();
}
}
}
private Size chooseOptimalSize(SortedSet<Size> sizes) {
if (!mPreview.isReady()) { // Not yet laid out
return sizes.last(); // Return the smallest size
}
int desiredWidth;
int desiredHeight;
final int surfaceWidth = mPreview.getWidth();
final int surfaceHeight = mPreview.getHeight();
if (mDisplayOrientation == 90 || mDisplayOrientation == 270) {
desiredWidth = surfaceHeight;
desiredHeight = surfaceWidth;
} else {
desiredWidth = surfaceWidth;
desiredHeight = surfaceHeight;
}
Size result = null;
for (Size size : sizes) { // Iterate from small to large
if (desiredWidth <= size.getWidth() && desiredHeight <= size.getHeight()) {
return size;
}
result = size;
}
return result;
}
private void openCamera() {
if (mCamera != null) {
releaseCamera();
}
mCamera = Camera.open(mCameraId);
mCameraParameters = mCamera.getParameters();
// Supported preview sizes
mPreviewSizes.clear();
for (Camera.Size size : mCameraParameters.getSupportedPreviewSizes()) {
mPreviewSizes.add(new Size(size.width, size.height));
}
// Supported picture sizes;
mCaptureSizes.clear();
for (Camera.Size size : mCameraParameters.getSupportedPictureSizes()) {
mCaptureSizes.add(new Size(size.width, size.height));
}
adjustCameraParameters();
mCamera.setDisplayOrientation(calcCameraRotation(mDisplayOrientation));
mCameraListener.onCameraOpened();
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
mCameraListener.onCameraClosed();
}
Size getPreviewResolution() {
return null;
}
@Override
Size getCaptureResolution() {
return mCaptureSize;
boolean isCameraOpened() {
return false;
}
@Override
Size getPreviewResolution() {
return mPreviewSize;
}
}

@ -1,8 +1,8 @@
package com.flurgle.camerakit;
public abstract class CameraImpl {
abstract class CameraImpl {
protected CameraListener mCameraListener;
protected final CameraListener mCameraListener;
protected final PreviewImpl mPreview;
CameraImpl(CameraListener callback, PreviewImpl preview) {
@ -13,14 +13,13 @@ public abstract class CameraImpl {
abstract void start();
abstract void stop();
abstract boolean isCameraOpened();
abstract void setFacing(@Facing int facing);
abstract void setFlash(@Flash int flash);
abstract void setAutoFocus(boolean autoFocus);
abstract void setContinuousFocus(boolean autoFocus);
abstract void setDisplayOrientation(int displayOrientation);
abstract void focus();
abstract void zoom(float percentZoom);
abstract void captureStandard();
abstract void captureStill();
@ -30,5 +29,6 @@ public abstract class CameraImpl {
abstract Size getCaptureResolution();
abstract Size getPreviewResolution();
abstract boolean isCameraOpened();
}

@ -5,7 +5,7 @@ import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View;
public abstract class PreviewImpl {
abstract class PreviewImpl {
interface Callback {
void onSurfaceChanged();

@ -10,7 +10,7 @@ import android.view.View;
import android.view.ViewGroup;
@TargetApi(14)
public class TextureViewPreview extends PreviewImpl {
class TextureViewPreview extends PreviewImpl {
private final TextureView mTextureView;

@ -1,7 +1,16 @@
package com.flurgle.camerakit;
import android.content.res.Resources;
public class CameraKit {
static class Internal {
static final int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
static final int screenHeight = Resources.getSystem().getDisplayMetrics().heightPixels;
}
public static class Constants {
public static final int FACING_BACK = 0;

@ -27,13 +27,13 @@ import android.widget.FrameLayout;
import java.io.ByteArrayOutputStream;
import java.io.File;
import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_MODE_STANDARD;
import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_MODE_STILL;
import static com.flurgle.camerakit.CameraKit.Constants.FACING_BACK;
import static com.flurgle.camerakit.CameraKit.Constants.FACING_FRONT;
import static com.flurgle.camerakit.CameraKit.Constants.FLASH_AUTO;
import static com.flurgle.camerakit.CameraKit.Constants.FLASH_OFF;
import static com.flurgle.camerakit.CameraKit.Constants.FLASH_ON;
import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_MODE_STANDARD;
import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_MODE_STILL;
import static com.flurgle.camerakit.CameraKit.Constants.TAP_TO_FOCUS_VISIBLE;
public class CameraView extends FrameLayout {
@ -56,7 +56,7 @@ public class CameraView extends FrameLayout {
private boolean mCropOutput;
private boolean mAutoFocus;
private boolean mContinuousFocus;
private float mCaptureSize;
@ -80,50 +80,27 @@ public class CameraView extends FrameLayout {
public CameraView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CameraView);
final int n = a.getIndexCount();
for (int i = 0; i < n; ++i) {
int attr = a.getIndex(i);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.CameraView,
0, 0);
if (attr == R.styleable.CameraView_ckFacing) {
try {
mFacing = a.getInteger(R.styleable.CameraView_ckFacing, FACING_BACK);
}
if (attr == R.styleable.CameraView_ckFlash) {
mFlash = a.getInteger(R.styleable.CameraView_ckFlash, FLASH_OFF);
}
if (attr == R.styleable.CameraView_ckTapToFocus) {
mTapToFocus = a.getInteger(R.styleable.CameraView_ckTapToFocus, TAP_TO_FOCUS_VISIBLE);
}
if (attr == R.styleable.CameraView_ckCaptureMode) {
mCaptureMode = a.getInteger(R.styleable.CameraView_ckCaptureMode, CAPTURE_MODE_STANDARD);
}
if (attr == R.styleable.CameraView_ckCropOutput) {
mCropOutput = a.getBoolean(R.styleable.CameraView_ckCropOutput, false);
}
if (attr == R.styleable.CameraView_ckAutoFocus) {
mAutoFocus = a.getBoolean(R.styleable.CameraView_ckAutoFocus, true);
}
if (attr == R.styleable.CameraView_ckCaptureSize) {
mContinuousFocus = a.getBoolean(R.styleable.CameraView_ckContinuousFocus, true);
mCaptureSize = a.getFloat(R.styleable.CameraView_ckCaptureSize, DEFAULT_CAPTURE_SIZE);
}
if (attr == R.styleable.CameraView_ckJpegCompression) {
mJpegCompression = a.getInteger(R.styleable.CameraView_ckJpegCompression, DEFAULT_JPEG_COMPRESSION);
}
if (attr == R.styleable.CameraView_android_adjustViewBounds) {
mAdjustViewBounds = a.getBoolean(R.styleable.CameraView_android_adjustViewBounds, false);
}
}
} finally {
a.recycle();
}
}
mCameraListener = new CameraListenerMiddleWare();
@ -132,10 +109,10 @@ public class CameraView extends FrameLayout {
setFacing(mFacing);
setFlash(mFlash);
setPictureMode(mCaptureMode);
setCaptureMode(mCaptureMode);
setCropOutput(mCropOutput);
setTapToFocus(mTapToFocus);
setAutoFocus(mAutoFocus);
setContinuousFocus(mContinuousFocus);
setCaptureSize(mCaptureSize);
mDisplayOrientationDetector = new DisplayOrientationDetector(context) {
@ -241,12 +218,12 @@ public class CameraView extends FrameLayout {
return mFlash;
}
public void setPictureMode(@CaptureMode int pictureMode) {
this.mCaptureMode = pictureMode;
public void setCaptureMode(@CaptureMode int captureMode) {
this.mCaptureMode = captureMode;
}
@CaptureMode
public int getPictureMode() {
public int getCaptureMode() {
return mCaptureMode;
}
@ -263,8 +240,9 @@ public class CameraView extends FrameLayout {
}
}
public void setAutoFocus(boolean autoFocus) {
this.mAutoFocus = autoFocus;
public void setContinuousFocus(boolean continuousFocus) {
this.mContinuousFocus = continuousFocus;
mCameraImpl.setContinuousFocus(continuousFocus);
}
public void setCaptureSize(float captureSize) {

@ -22,13 +22,15 @@
<attr name="ckCropOutput" format="boolean" />
<attr name="ckPinchToZoom" format="boolean" />
<attr name="ckTapToFocus" format="enum">
<enum name="visible" value="0" />
<enum name="invisible" value="1" />
<enum name="off" value="2" />
</attr>
<attr name="ckAutoFocus" format="boolean" />
<attr name="ckContinuousFocus" format="boolean" />
<attr name="ckCaptureSize" format="float" />

@ -1,3 +0,0 @@
<resources>
<string name="app_name">CameraKit</string>
</resources>

@ -17,7 +17,7 @@ public class CenterCrop {
public CenterCrop(YuvImage yuv, AspectRatio targetRatio, int jpegCompression) {
Rect crop = getCrop(yuv.getWidth(), yuv.getHeight(), targetRatio);
ByteArrayOutputStream out = new ByteArrayOutputStream();
yuv.compressToJpeg(crop, 100, out);
yuv.compressToJpeg(crop, jpegCompression, out);
this.croppedJpeg = out.toByteArray();
}
@ -36,11 +36,10 @@ public class CenterCrop {
).decodeRegion(crop, null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
bitmap.compress(Bitmap.CompressFormat.JPEG, jpegCompression, out);
this.croppedJpeg = out.toByteArray();
} catch (IOException e) {
Log.e("CameraKit", e.toString());
return;
}
}

@ -1,40 +1,11 @@
package com.flurgle.camerakit;
import android.media.Image;
import android.util.Log;
public class Rotation {
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
private byte[] rotatedYuv;
public class YuvUtils {
public static byte[] getYUVData(Image image) {
ByteBuffer bufferY = image.getPlanes()[0].getBuffer();
byte[] y = new byte[bufferY.remaining()];
bufferY.get(y);
ByteBuffer bufferU = image.getPlanes()[1].getBuffer();
byte[] u = new byte[bufferU.remaining()];
bufferU.get(u);
ByteBuffer bufferV = image.getPlanes()[2].getBuffer();
byte[] v = new byte[bufferV.remaining()];
bufferV.get(v);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
outputStream.write(y);
outputStream.write(v);
outputStream.write(u);
} catch (IOException e) {
Log.e("CameraKit", e.toString());
}
return outputStream.toByteArray();
}
public static byte[] rotateNV21(final byte[] yuv, final int width, final int height, final int rotation) {
if (rotation == 0) return yuv;
public Rotation(final byte[] yuv, final int width, final int height, final int rotation) {
if (rotation == 0) this.rotatedYuv = yuv;
if (rotation % 90 != 0 || rotation < 0 || rotation > 270) {
throw new IllegalArgumentException("0 <= rotation < 360, rotation % 90 == 0");
}
@ -67,7 +38,12 @@ public class YuvUtils {
output[vOut] = (byte) (0xff & yuv[vIn]);
}
}
return output;
this.rotatedYuv = output;
}
public byte[] getYuv() {
return this.rotatedYuv;
}
}

@ -191,7 +191,7 @@ public class MainActivity extends AppCompatActivity {
RadioGroup.OnCheckedChangeListener captureModeChangedListener = new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
camera.setPictureMode(
camera.setCaptureMode(
checkedId == R.id.modeCaptureQuality ?
CameraKit.Constants.CAPTURE_MODE_STANDARD :
CameraKit.Constants.CAPTURE_MODE_STILL

@ -18,10 +18,11 @@
android:layout_width="match_parent"
android:layout_height="500dp"
android:layout_gravity="center_horizontal"
app:ckCaptureMode="standard"
app:ckContinuousFocus="true"
app:ckCropOutput="false"
app:ckFacing="back"
app:ckFlash="off"
app:ckCaptureMode="standard"
app:ckTapToFocus="visible" />
<LinearLayout

Loading…
Cancel
Save