|
|
|
@ -7,7 +7,8 @@ import android.graphics.BitmapFactory; |
|
|
|
|
import android.graphics.Matrix; |
|
|
|
|
import android.hardware.Camera; |
|
|
|
|
import android.os.Handler; |
|
|
|
|
import android.support.annotation.UiThread; |
|
|
|
|
import android.support.annotation.NonNull; |
|
|
|
|
import android.support.annotation.Nullable; |
|
|
|
|
import android.support.annotation.WorkerThread; |
|
|
|
|
import android.support.media.ExifInterface; |
|
|
|
|
|
|
|
|
@ -116,12 +117,17 @@ public class CameraUtils { |
|
|
|
|
* @param callback a callback to be notified |
|
|
|
|
*/ |
|
|
|
|
@SuppressWarnings("WeakerAccess") |
|
|
|
|
public static void decodeBitmap(final byte[] source, final int maxWidth, final int maxHeight, final BitmapFactory.Options options, final BitmapCallback callback) { |
|
|
|
|
public static void decodeBitmap(final byte[] source, final int maxWidth, final int maxHeight, @NonNull final BitmapFactory.Options options, final BitmapCallback callback) { |
|
|
|
|
decodeBitmap(source, maxWidth, maxHeight, options, -1, callback); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@SuppressWarnings("WeakerAccess") |
|
|
|
|
static void decodeBitmap(final byte[] source, final int maxWidth, final int maxHeight, @NonNull final BitmapFactory.Options options, final int rotation, final BitmapCallback callback) { |
|
|
|
|
final Handler ui = new Handler(); |
|
|
|
|
WorkerHandler.run(new Runnable() { |
|
|
|
|
@Override |
|
|
|
|
public void run() { |
|
|
|
|
final Bitmap bitmap = decodeBitmap(source, maxWidth, maxHeight, options); |
|
|
|
|
final Bitmap bitmap = decodeBitmap(source, maxWidth, maxHeight, options, rotation); |
|
|
|
|
ui.post(new Runnable() { |
|
|
|
|
@Override |
|
|
|
|
public void run() { |
|
|
|
@ -159,21 +165,29 @@ public class CameraUtils { |
|
|
|
|
* @param maxHeight the max allowed height |
|
|
|
|
* @param options the options to be passed to decodeByteArray |
|
|
|
|
*/ |
|
|
|
|
// TODO ignores flipping
|
|
|
|
|
@SuppressWarnings({"SuspiciousNameCombination", "WeakerAccess"}) |
|
|
|
|
@Nullable |
|
|
|
|
@WorkerThread |
|
|
|
|
public static Bitmap decodeBitmap(byte[] source, int maxWidth, int maxHeight, BitmapFactory.Options options) { |
|
|
|
|
public static Bitmap decodeBitmap(byte[] source, int maxWidth, int maxHeight, @NonNull BitmapFactory.Options options) { |
|
|
|
|
return decodeBitmap(source, maxWidth, maxHeight, options, -1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Null: got OOM
|
|
|
|
|
// TODO ignores flipping. but it should be super rare.
|
|
|
|
|
@Nullable |
|
|
|
|
static Bitmap decodeBitmap(byte[] source, int maxWidth, int maxHeight, @NonNull BitmapFactory.Options options, int rotation) { |
|
|
|
|
if (maxWidth <= 0) maxWidth = Integer.MAX_VALUE; |
|
|
|
|
if (maxHeight <= 0) maxHeight = Integer.MAX_VALUE; |
|
|
|
|
int orientation; |
|
|
|
|
boolean flip; |
|
|
|
|
if (rotation == -1) { |
|
|
|
|
InputStream stream = null; |
|
|
|
|
try { |
|
|
|
|
// http://sylvana.net/jpegcrop/exif_orientation.html
|
|
|
|
|
stream = new ByteArrayInputStream(source); |
|
|
|
|
ExifInterface exif = new ExifInterface(stream); |
|
|
|
|
int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); |
|
|
|
|
orientation = decodeExifOrientation(exifOrientation); |
|
|
|
|
orientation = readExifOrientation(exifOrientation); |
|
|
|
|
flip = exifOrientation == ExifInterface.ORIENTATION_FLIP_HORIZONTAL || |
|
|
|
|
exifOrientation == ExifInterface.ORIENTATION_FLIP_VERTICAL || |
|
|
|
|
exifOrientation == ExifInterface.ORIENTATION_TRANSPOSE || |
|
|
|
@ -185,11 +199,18 @@ public class CameraUtils { |
|
|
|
|
flip = false; |
|
|
|
|
} finally { |
|
|
|
|
if (stream != null) { |
|
|
|
|
try { stream.close(); } catch (Exception ignored) {} |
|
|
|
|
try { |
|
|
|
|
stream.close(); |
|
|
|
|
} catch (Exception ignored) { } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
orientation = rotation; |
|
|
|
|
flip = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Bitmap bitmap; |
|
|
|
|
try { |
|
|
|
|
if (maxWidth < Integer.MAX_VALUE || maxHeight < Integer.MAX_VALUE) { |
|
|
|
|
options.inJustDecodeBounds = true; |
|
|
|
|
BitmapFactory.decodeByteArray(source, 0, source.length, options); |
|
|
|
@ -197,6 +218,7 @@ public class CameraUtils { |
|
|
|
|
int outHeight = options.outHeight; |
|
|
|
|
int outWidth = options.outWidth; |
|
|
|
|
if (orientation % 180 != 0) { |
|
|
|
|
//noinspection SuspiciousNameCombination
|
|
|
|
|
outHeight = options.outWidth; |
|
|
|
|
outWidth = options.outHeight; |
|
|
|
|
} |
|
|
|
@ -211,15 +233,17 @@ public class CameraUtils { |
|
|
|
|
if (orientation != 0 || flip) { |
|
|
|
|
Matrix matrix = new Matrix(); |
|
|
|
|
matrix.setRotate(orientation); |
|
|
|
|
// matrix.postScale(1, -1) Flip... needs testing.
|
|
|
|
|
Bitmap temp = bitmap; |
|
|
|
|
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); |
|
|
|
|
temp.recycle(); |
|
|
|
|
} |
|
|
|
|
} catch (OutOfMemoryError e) { |
|
|
|
|
bitmap = null; |
|
|
|
|
} |
|
|
|
|
return bitmap; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int decodeExifOrientation(int exifOrientation) { |
|
|
|
|
static int readExifOrientation(int exifOrientation) { |
|
|
|
|
int orientation; |
|
|
|
|
switch (exifOrientation) { |
|
|
|
|
case ExifInterface.ORIENTATION_NORMAL: |
|
|
|
|