Add toFile utility in CameraUtils and in PictureResult

v2
Mattia Iavarone 6 years ago
parent 147f175ba8
commit fcf41c8d2c
  1. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraListener.java
  2. 21
      cameraview/src/main/java/com/otaliastudios/cameraview/PictureResult.java
  3. 63
      cameraview/src/main/utils/com/otaliastudios/cameraview/CameraUtils.java
  4. 25
      cameraview/src/main/utils/com/otaliastudios/cameraview/FileCallback.java
  5. 2
      demo/src/main/java/com/otaliastudios/cameraview/demo/PicturePreviewActivity.java
  6. 14
      docs/_posts/2018-12-20-getting-started.md
  7. 2
      docs/_posts/2018-12-20-v1-migration-guide.md

@ -48,7 +48,7 @@ public abstract class CameraListener {
* Notifies that a picture previously captured with {@link CameraView#takePicture()} * Notifies that a picture previously captured with {@link CameraView#takePicture()}
* or {@link CameraView#takePictureSnapshot()} is ready to be shown or saved to file. * or {@link CameraView#takePictureSnapshot()} is ready to be shown or saved to file.
* *
* If planning to show a bitmap, you can use {@link PictureResult#asBitmap(int, int, BitmapCallback)} * If planning to show a bitmap, you can use {@link PictureResult#toBitmap(int, int, BitmapCallback)}
* to decode the byte array taking care about orientation and threading. * to decode the byte array taking care about orientation and threading.
* *
* @param result captured picture * @param result captured picture

@ -1,6 +1,9 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.location.Location; import android.location.Location;
import java.io.File;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -93,7 +96,7 @@ public class PictureResult {
* @param maxHeight the max. height of final bitmap * @param maxHeight the max. height of final bitmap
* @param callback a callback to be notified of image decoding * @param callback a callback to be notified of image decoding
*/ */
public void asBitmap(int maxWidth, int maxHeight, @NonNull BitmapCallback callback) { public void toBitmap(int maxWidth, int maxHeight, @NonNull BitmapCallback callback) {
CameraUtils.decodeBitmap(getData(), maxWidth, maxHeight, rotation, callback); CameraUtils.decodeBitmap(getData(), maxWidth, maxHeight, rotation, callback);
} }
@ -104,9 +107,19 @@ public class PictureResult {
* *
* @param callback a callback to be notified of image decoding * @param callback a callback to be notified of image decoding
*/ */
public void asBitmap(@NonNull BitmapCallback callback) { public void toBitmap(@NonNull BitmapCallback callback) {
asBitmap(-1, -1, callback); toBitmap(-1, -1, callback);
} }
// TODO toFile /**
* Shorthand for {@link CameraUtils#writeToFile(byte[], File, FileCallback)}.
* This writes this picture to file on a background thread and posts the result in the UI
* thread using the given callback.
*
* @param file the file to write into
* @param callback a callback
*/
public void toFile(@NonNull File file, @NonNull FileCallback callback) {
CameraUtils.writeToFile(getData(), file, callback);
}
} }

@ -12,9 +12,14 @@ import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread; import androidx.annotation.WorkerThread;
import androidx.exifinterface.media.ExifInterface; import androidx.exifinterface.media.ExifInterface;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
/** /**
* Static utilities for dealing with camera I/O, orientations, etc. * Static utilities for dealing with camera I/O, orientations, etc.
@ -57,6 +62,59 @@ public class CameraUtils {
} }
/**
* Simply writes the given data to the given file. It is done synchronously. If you are
* running on the UI thread, please use {@link #writeToFile(byte[], File, FileCallback)}
* and pass a file callback.
*
* If any error is encountered, this returns null.
*
* @param data the data to be written
* @param file the file to write into
* @return the source file, or null if error
*/
@SuppressWarnings("WeakerAccess")
@Nullable
@WorkerThread
public static File writeToFile(@NonNull final byte[] data, @NonNull File file) {
if (file.exists() && !file.delete()) return null;
try (OutputStream stream = new BufferedOutputStream(new FileOutputStream(file))) {
stream.write(data);
stream.flush();
return file;
} catch (IOException e) {
return null;
}
}
/**
* Writes the given data to the given file in a background thread, returning on the
* original thread (typically the UI thread) once writing is done.
* If some error is encountered, the {@link FileCallback} will return null instead of the
* original file.
*
* @param data the data to be written
* @param file the file to write into
* @param callback a callback
*/
@SuppressWarnings("WeakerAccess")
public static void writeToFile(@NonNull final byte[] data, @NonNull final File file, @NonNull final FileCallback callback) {
final Handler ui = new Handler();
WorkerHandler.run(new Runnable() {
@Override
public void run() {
final File result = writeToFile(data, file);
ui.post(new Runnable() {
@Override
public void run() {
callback.onFileReady(result);
}
});
}
});
}
/** /**
* Decodes an input byte array and outputs a Bitmap that is ready to be displayed. * 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)} * The difference with {@link android.graphics.BitmapFactory#decodeByteArray(byte[], int, int)}
@ -65,9 +123,10 @@ public class CameraUtils {
* @param source a JPEG byte array * @param source a JPEG byte array
*/ */
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
@Nullable
@WorkerThread @WorkerThread
public static void decodeBitmap(@NonNull final byte[] source) { public static Bitmap decodeBitmap(@NonNull final byte[] source) {
decodeBitmap(source, Integer.MAX_VALUE, Integer.MAX_VALUE); return decodeBitmap(source, Integer.MAX_VALUE, Integer.MAX_VALUE);
} }
/** /**

@ -0,0 +1,25 @@
package com.otaliastudios.cameraview;
import android.graphics.Bitmap;
import java.io.File;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
/**
* Receives callbacks about a file saving operation.
*/
public interface FileCallback {
/**
* Notifies that the data was succesfully written to file.
* This is run on the UI thread.
* Returns a null object if an exception was encountered, for example
* if you don't have permissions to write to file.
*
* @param file the written file, or null
*/
@UiThread
void onFileReady(@Nullable File file);
}

@ -39,7 +39,7 @@ public class PicturePreviewActivity extends Activity {
captureLatency.setTitleAndMessage("Approx. latency", delay + " milliseconds"); captureLatency.setTitleAndMessage("Approx. latency", delay + " milliseconds");
captureResolution.setTitleAndMessage("Resolution", result.getSize() + " (" + ratio + ")"); captureResolution.setTitleAndMessage("Resolution", result.getSize() + " (" + ratio + ")");
exifRotation.setTitleAndMessage("EXIF rotation", result.getRotation() + ""); exifRotation.setTitleAndMessage("EXIF rotation", result.getRotation() + "");
result.asBitmap(1000, 1000, new BitmapCallback() { result.toBitmap(1000, 1000, new BitmapCallback() {
@Override @Override
public void onBitmapReady(Bitmap bitmap) { public void onBitmapReady(Bitmap bitmap) {
imageView.setImageBitmap(bitmap); imageView.setImageBitmap(bitmap);

@ -73,12 +73,16 @@ camera.addCameraListener(new CameraListener() {
@Override @Override
public void onPictureTaken(PictureResult result) { public void onPictureTaken(PictureResult result) {
// Picture was taken! // Picture was taken!
// If planning to save a file, just get the jpeg array.
byte[] jpeg = result.getJpeg();
// If planning to show a Bitmap, we will take care of // If planning to show a Bitmap, we will take care of
// EXIF rotation and background threading for you... // EXIF rotation and background threading for you...
result.asBitmap(maxWidth, maxHeight, callback); result.toBitmap(maxWidth, maxHeight, callback);
// If planning to save a file on a background thread,
// just use toFile. Ensure you have permissions.
result.toFile(file, callback);
// Access the raw data if needed.
byte[] data = result.getData();
} }
}); });
camera.takePicture(); camera.takePicture();
@ -124,7 +128,7 @@ For runtime permissions and Manifest setup, please read the [permissions page]()
If you are not using support libraries and you can't resolve the LifecycleOwner interface, If you are not using support libraries and you can't resolve the LifecycleOwner interface,
make sure you override `onResume`, `onPause` and `onDestroy` in your activity (`onDestroyView` make sure you override `onResume`, `onPause` and `onDestroy` in your activity (`onDestroyView`
in your fragment), and call `CameraView.open()`, `close()` and `destroy()`. in your fragment), and call `open()`, `close()` and `destroy()`.
```java ```java
@Override @Override

@ -156,7 +156,7 @@ The listener interface brings two breaking signature changes:
- `onPictureTaken()` now returns a `PictureResult`. Use `result.getJpeg()` to access the jpeg stream. - `onPictureTaken()` now returns a `PictureResult`. Use `result.getJpeg()` to access the jpeg stream.
The result class includes rich information about the picture (or picture snapshot) that was taken, The result class includes rich information about the picture (or picture snapshot) that was taken,
plus handy utilities (`result.asBitmap()`...) plus handy utilities (`result.toBitmap()`, `result.toFile()`...)
- `onVideoTaken()` now returns a `VideoResult`. Use `result.getFile()` to access the video file. - `onVideoTaken()` now returns a `VideoResult`. Use `result.getFile()` to access the video file.
The result class includes rich information about the video (or video snapshot) that was taken. The result class includes rich information about the video (or video snapshot) that was taken.

Loading…
Cancel
Save