rotate images based on exif information

Closes #1847
This commit is contained in:
agrajaghh
2014-08-18 14:45:31 +02:00
committed by Jake McGinty
parent d7de5415b5
commit cef203f261
6 changed files with 241 additions and 33 deletions

View File

@@ -4,6 +4,7 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
@@ -13,9 +14,15 @@ import android.util.Log;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import com.android.gallery3d.data.Exif;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.mms.PartAuthority;
public class BitmapUtil {
private static final String TAG = BitmapUtil.class.getSimpleName();
@@ -23,20 +30,15 @@ public class BitmapUtil {
private static final int MIN_COMPRESSION_QUALITY = 50;
private static final int MAX_COMPRESSION_ATTEMPTS = 4;
public static byte[] createScaledBytes(Context context, Uri uri, int maxWidth,
int maxHeight, int maxSize)
public static byte[] createScaledBytes(Context context, MasterSecret masterSecret, Uri uri, int maxWidth, int maxHeight, int maxSize)
throws IOException, BitmapDecodingException
{
Bitmap bitmap;
try {
bitmap = createScaledBitmap(context.getContentResolver().openInputStream(uri),
context.getContentResolver().openInputStream(uri),
maxWidth, maxHeight, false);
bitmap = createScaledBitmap(context, masterSecret, uri, maxWidth, maxHeight, false);
} catch(OutOfMemoryError oome) {
Log.w(TAG, "OutOfMemoryError when scaling precisely, doing rough scale to save memory instead");
bitmap = createScaledBitmap(context.getContentResolver().openInputStream(uri),
context.getContentResolver().openInputStream(uri),
maxWidth, maxHeight, true);
bitmap = createScaledBitmap(context, masterSecret, uri, maxWidth, maxHeight, true);
}
int quality = MAX_COMPRESSION_QUALITY;
int attempts = 0;
@@ -56,6 +58,37 @@ public class BitmapUtil {
else throw new IOException("Unable to scale image below: " + baos.size());
}
public static Bitmap createScaledBitmap(Context context, MasterSecret masterSecret, Uri uri, int maxWidth, int maxHeight)
throws BitmapDecodingException, FileNotFoundException
{
return createScaledBitmap(context, masterSecret, uri, maxWidth, maxHeight, false);
}
private static Bitmap createScaledBitmap(Context context, MasterSecret masterSecret, Uri uri, int maxWidth, int maxHeight, boolean constrainedMemory)
throws FileNotFoundException, BitmapDecodingException
{
return createScaledBitmap(PartAuthority.getPartStream(context, masterSecret, uri),
PartAuthority.getPartStream(context, masterSecret, uri),
PartAuthority.getPartStream(context, masterSecret, uri),
maxWidth, maxHeight, constrainedMemory);
}
private static Bitmap createScaledBitmap(InputStream measure, InputStream orientationStream, InputStream data,
int maxWidth, int maxHeight, boolean constrainedMemory)
throws BitmapDecodingException
{
Bitmap bitmap = createScaledBitmap(measure, data, maxWidth, maxHeight, constrainedMemory);
return fixOrientation(bitmap, orientationStream);
}
private static Bitmap createScaledBitmap(InputStream measure, InputStream data, int maxWidth, int maxHeight,
boolean constrainedMemory)
throws BitmapDecodingException
{
final BitmapFactory.Options options = getImageDimensions(measure);
return createScaledBitmap(data, maxWidth, maxHeight, options, constrainedMemory);
}
public static Bitmap createScaledBitmap(InputStream measure, InputStream data, float scale)
throws BitmapDecodingException
{
@@ -66,21 +99,12 @@ public class BitmapUtil {
return createScaledBitmap(data, outWidth, outHeight, options, false);
}
public static Bitmap createScaledBitmap(InputStream measure, InputStream data,
int maxWidth, int maxHeight)
public static Bitmap createScaledBitmap(InputStream measure, InputStream data, int maxWidth, int maxHeight)
throws BitmapDecodingException
{
return createScaledBitmap(measure, data, maxWidth, maxHeight, false);
}
public static Bitmap createScaledBitmap(InputStream measure, InputStream data,
int maxWidth, int maxHeight, boolean constrainedMemory)
throws BitmapDecodingException
{
final BitmapFactory.Options options = getImageDimensions(measure);
return createScaledBitmap(data, maxWidth, maxHeight, options, constrainedMemory);
}
private static Bitmap createScaledBitmap(InputStream data, int maxWidth, int maxHeight,
BitmapFactory.Options options, boolean constrainedMemory)
throws BitmapDecodingException
@@ -141,6 +165,24 @@ public class BitmapUtil {
}
}
private static Bitmap fixOrientation(Bitmap bitmap, InputStream orientationStream) {
final int orientation = Exif.getOrientation(orientationStream);
if (orientation != 0) {
return rotateBitmap(bitmap, orientation);
} else {
return bitmap;
}
}
private static Bitmap rotateBitmap(Bitmap bitmap, int angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
Bitmap rotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
if (rotated != bitmap) bitmap.recycle();
return rotated;
}
private static BitmapFactory.Options getImageDimensions(InputStream inputStream) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
@@ -160,6 +202,14 @@ public class BitmapUtil {
return getScaledCircleCroppedBitmap(bitmap, srcSize);
}
public static Bitmap getScaledCircleCroppedBitmap(Context context, Uri uri, int destSize) throws FileNotFoundException {
InputStream dataStream = context.getContentResolver().openInputStream(uri);
InputStream orientationStream = context.getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(dataStream);
return getScaledCircleCroppedBitmap(fixOrientation(bitmap, orientationStream), destSize);
}
public static Bitmap getScaledCircleCroppedBitmap(Bitmap bitmap, int destSize) {
if (bitmap == null) return null;
Bitmap output = Bitmap.createBitmap(destSize, destSize, Bitmap.Config.ARGB_8888);