CameraUtils for decoding bitmaps in background, ExifInterface library

pull/1/head
Mattia Iavarone 7 years ago
parent 6a0795c1b3
commit fe33c1fa7a
  1. 9
      README.md
  2. 5
      camerakit/build.gradle
  3. 6
      camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java
  4. 107
      camerakit/src/main/java/com/flurgle/camerakit/CameraUtils.java

@ -57,11 +57,11 @@ CameraKit is an easy to use utility to work with the Android Camera APIs. Everyt
- While taking pictures, image is captured normally using the camera APIs.
- While shooting videos, image is captured as a freeze frame of the `CameraView` preview (similar to SnapChat and Instagram)
- Built-in tap to focus
- `CameraUtils` to help with Bitmaps and orientations
- EXIF support
- Automatically detected orientation tag
- Plug in location tags with `CameraView.setLocation(double, double)`
- Control the camera parameters via XML or programmatically
- TODO: Built-in pinch to zoom
- Control the camera parameters via XML or programmatically
## Setup
@ -109,7 +109,8 @@ camera.setCameraListener(new CameraListener() {
@Override
public void onPictureTaken(byte[] picture) {
// Create a bitmap or a file...
Bitmap result = BitmapFactory.decodeByteArray(picture, 0, picture.length);
// CameraUtils will read EXIF orientation for you.
CameraUtils.decodeBitmap(picture, ...);
}
});
@ -376,7 +377,7 @@ The library manifest file is not strict and only asks for camera permissions. Th
android:required="true"/>
```
If you don't request this feature, you can use `CameraKit.hasCameras()` to detect if current device has cameras, and then start the camera view.
If you don't request this feature, you can use `CameraUtils.hasCameras()` to detect if current device has cameras, and then start the camera view.
## Roadmap

@ -32,9 +32,8 @@ android {
}
dependencies {
compile 'com.android.support:appcompat-v7:25.2.0'
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:exifinterface:25.3.1'
compile 'android.arch.lifecycle:runtime:1.0.0-alpha1'
compile 'android.arch.lifecycle:extensions:1.0.0-alpha1'
annotationProcessor 'android.arch.lifecycle:compiler:1.0.0-alpha1'

@ -5,12 +5,6 @@ import android.content.pm.PackageManager;
public class CameraKit {
public static boolean hasCameras(Context context) {
PackageManager manager = context.getPackageManager();
// There's also FEATURE_CAMERA_EXTERNAL , should we support it?
return manager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
|| manager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
}
public static class Constants {

@ -0,0 +1,107 @@
package com.flurgle.camerakit;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Handler;
import android.support.media.ExifInterface;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Static utilities for dealing with camera I/O, orientation, etc.
*/
public class CameraUtils {
/**
* Determines whether the device has valid camera sensors, so the library
* can be used.
*
* @param context a valid Context
* @return whether device has cameras
*/
public static boolean hasCameras(Context context) {
PackageManager manager = context.getPackageManager();
// There's also FEATURE_CAMERA_EXTERNAL , should we support it?
return manager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
|| manager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
}
/**
* Decodes an input byte array and outputs a Bitmap that is ready to be displayed.
* The difference with {@link android.graphics.BitmapFactory#decodeByteArray(byte[], int, int)}
* is that this cares about orientation, reading it from the EXIF header.
* This is executed in a background thread, and returns the result to the original thread.
*
* This ignores flipping at the moment.
* TODO care about flipping using Matrix.scale()
*
* @param source a JPEG byte array
* @param callback a callback to be notified
*/
public static void decodeBitmap(final byte[] source, final BitmapCallback callback) {
final Handler ui = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
int orientation = 0;
try {
// http://sylvana.net/jpegcrop/exif_orientation.html
ExifInterface exif = new ExifInterface(new ByteArrayInputStream(source));
Integer exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (exifOrientation) {
case ExifInterface.ORIENTATION_NORMAL:
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
orientation = 0; break;
case ExifInterface.ORIENTATION_ROTATE_180:
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
orientation = 180; break;
case ExifInterface.ORIENTATION_ROTATE_90:
case ExifInterface.ORIENTATION_TRANSPOSE:
orientation = 90; break;
case ExifInterface.ORIENTATION_ROTATE_270:
case ExifInterface.ORIENTATION_TRANSVERSE:
orientation = 270; break;
default: orientation = 0;
}
} catch (IOException e) {
e.printStackTrace();
orientation = 0;
}
Bitmap bitmap = BitmapFactory.decodeByteArray(source, 0, source.length);
if (orientation != 0) {
Matrix matrix = new Matrix();
matrix.setRotate(orientation);
Bitmap temp = bitmap;
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
temp.recycle();
}
final Bitmap result = bitmap;
ui.post(new Runnable() {
@Override
public void run() {
callback.onBitmapReady(result);
}
});
}
}).start();
}
public interface BitmapCallback {
void onBitmapReady(Bitmap bitmap);
}
}
Loading…
Cancel
Save