Fix crashes for images that are not PNG or JPEG
Bug: 11341544 Change-Id: If2339b583e9a991f053a5f95f259156e3e4e9acd
This commit is contained in:
@@ -247,19 +247,19 @@ public class WallpaperCropActivity extends Activity {
|
|||||||
private static int getRotationFromExifHelper(
|
private static int getRotationFromExifHelper(
|
||||||
String path, Resources res, int resId, Context context, Uri uri) {
|
String path, Resources res, int resId, Context context, Uri uri) {
|
||||||
ExifInterface ei = new ExifInterface();
|
ExifInterface ei = new ExifInterface();
|
||||||
|
InputStream is = null;
|
||||||
|
BufferedInputStream bis = null;
|
||||||
try {
|
try {
|
||||||
if (path != null) {
|
if (path != null) {
|
||||||
ei.readExif(path);
|
ei.readExif(path);
|
||||||
} else if (uri != null) {
|
} else if (uri != null) {
|
||||||
InputStream is = context.getContentResolver().openInputStream(uri);
|
is = context.getContentResolver().openInputStream(uri);
|
||||||
BufferedInputStream bis = new BufferedInputStream(is);
|
bis = new BufferedInputStream(is);
|
||||||
ei.readExif(bis);
|
ei.readExif(bis);
|
||||||
bis.close();
|
|
||||||
} else {
|
} else {
|
||||||
InputStream is = res.openRawResource(resId);
|
is = res.openRawResource(resId);
|
||||||
BufferedInputStream bis = new BufferedInputStream(is);
|
bis = new BufferedInputStream(is);
|
||||||
ei.readExif(bis);
|
ei.readExif(bis);
|
||||||
bis.close();
|
|
||||||
}
|
}
|
||||||
Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION);
|
Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION);
|
||||||
if (ori != null) {
|
if (ori != null) {
|
||||||
@@ -267,6 +267,9 @@ public class WallpaperCropActivity extends Activity {
|
|||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(LOGTAG, "Getting exif data failed", e);
|
Log.w(LOGTAG, "Getting exif data failed", e);
|
||||||
|
} finally {
|
||||||
|
Utils.closeSilently(bis);
|
||||||
|
Utils.closeSilently(is);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -606,13 +609,13 @@ public class WallpaperCropActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See how much we're reducing the size of the image
|
// See how much we're reducing the size of the image
|
||||||
int scaleDownSampleSize = Math.min(roundedTrueCrop.width() / mOutWidth,
|
int scaleDownSampleSize = Math.max(1, Math.min(roundedTrueCrop.width() / mOutWidth,
|
||||||
roundedTrueCrop.height() / mOutHeight);
|
roundedTrueCrop.height() / mOutHeight));
|
||||||
|
|
||||||
// Attempt to open a region decoder
|
// Attempt to open a region decoder
|
||||||
BitmapRegionDecoder decoder = null;
|
BitmapRegionDecoder decoder = null;
|
||||||
|
InputStream is = null;
|
||||||
try {
|
try {
|
||||||
InputStream is = regenerateInputStream();
|
is = regenerateInputStream();
|
||||||
if (is == null) {
|
if (is == null) {
|
||||||
Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString());
|
Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString());
|
||||||
failure = true;
|
failure = true;
|
||||||
@@ -622,6 +625,9 @@ public class WallpaperCropActivity extends Activity {
|
|||||||
Utils.closeSilently(is);
|
Utils.closeSilently(is);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e);
|
Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e);
|
||||||
|
} finally {
|
||||||
|
Utils.closeSilently(is);
|
||||||
|
is = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bitmap crop = null;
|
Bitmap crop = null;
|
||||||
@@ -637,7 +643,7 @@ public class WallpaperCropActivity extends Activity {
|
|||||||
|
|
||||||
if (crop == null) {
|
if (crop == null) {
|
||||||
// BitmapRegionDecoder has failed, try to crop in-memory
|
// BitmapRegionDecoder has failed, try to crop in-memory
|
||||||
InputStream is = regenerateInputStream();
|
is = regenerateInputStream();
|
||||||
Bitmap fullSize = null;
|
Bitmap fullSize = null;
|
||||||
if (is != null) {
|
if (is != null) {
|
||||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ import android.graphics.Bitmap.Config;
|
|||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.BitmapRegionDecoder;
|
import android.graphics.BitmapRegionDecoder;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@@ -42,6 +45,103 @@ import java.io.FileNotFoundException;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
interface SimpleBitmapRegionDecoder {
|
||||||
|
int getWidth();
|
||||||
|
int getHeight();
|
||||||
|
Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SimpleBitmapRegionDecoderWrapper implements SimpleBitmapRegionDecoder {
|
||||||
|
BitmapRegionDecoder mDecoder;
|
||||||
|
private SimpleBitmapRegionDecoderWrapper(BitmapRegionDecoder decoder) {
|
||||||
|
mDecoder = decoder;
|
||||||
|
}
|
||||||
|
public static SimpleBitmapRegionDecoderWrapper newInstance(
|
||||||
|
String pathName, boolean isShareable) {
|
||||||
|
try {
|
||||||
|
BitmapRegionDecoder d = BitmapRegionDecoder.newInstance(pathName, isShareable);
|
||||||
|
if (d != null) {
|
||||||
|
return new SimpleBitmapRegionDecoderWrapper(d);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w("BitmapRegionTileSource", "getting decoder failed for path " + pathName, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public static SimpleBitmapRegionDecoderWrapper newInstance(
|
||||||
|
InputStream is, boolean isShareable) {
|
||||||
|
try {
|
||||||
|
BitmapRegionDecoder d = BitmapRegionDecoder.newInstance(is, isShareable);
|
||||||
|
if (d != null) {
|
||||||
|
return new SimpleBitmapRegionDecoderWrapper(d);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w("BitmapRegionTileSource", "getting decoder failed", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public int getWidth() {
|
||||||
|
return mDecoder.getWidth();
|
||||||
|
}
|
||||||
|
public int getHeight() {
|
||||||
|
return mDecoder.getHeight();
|
||||||
|
}
|
||||||
|
public Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options) {
|
||||||
|
return mDecoder.decodeRegion(wantRegion, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DumbBitmapRegionDecoder implements SimpleBitmapRegionDecoder {
|
||||||
|
//byte[] mStreamCopy;
|
||||||
|
Bitmap mBuffer;
|
||||||
|
Canvas mTempCanvas;
|
||||||
|
Paint mTempPaint;
|
||||||
|
private DumbBitmapRegionDecoder(Bitmap b) {
|
||||||
|
mBuffer = b;
|
||||||
|
}
|
||||||
|
public static DumbBitmapRegionDecoder newInstance(String pathName) {
|
||||||
|
Bitmap b = BitmapFactory.decodeFile(pathName);
|
||||||
|
if (b != null) {
|
||||||
|
return new DumbBitmapRegionDecoder(b);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public static DumbBitmapRegionDecoder newInstance(InputStream is) {
|
||||||
|
Bitmap b = BitmapFactory.decodeStream(is);
|
||||||
|
if (b != null) {
|
||||||
|
return new DumbBitmapRegionDecoder(b);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public int getWidth() {
|
||||||
|
return mBuffer.getWidth();
|
||||||
|
}
|
||||||
|
public int getHeight() {
|
||||||
|
return mBuffer.getHeight();
|
||||||
|
}
|
||||||
|
public Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options) {
|
||||||
|
if (mTempCanvas == null) {
|
||||||
|
mTempCanvas = new Canvas();
|
||||||
|
mTempPaint = new Paint();
|
||||||
|
mTempPaint.setFilterBitmap(true);
|
||||||
|
}
|
||||||
|
int sampleSize = Math.max(options.inSampleSize, 1);
|
||||||
|
Bitmap newBitmap = Bitmap.createBitmap(
|
||||||
|
wantRegion.width() / sampleSize,
|
||||||
|
wantRegion.height() / sampleSize,
|
||||||
|
Bitmap.Config.ARGB_8888);
|
||||||
|
mTempCanvas.setBitmap(newBitmap);
|
||||||
|
mTempCanvas.save();
|
||||||
|
mTempCanvas.scale(1f / sampleSize, 1f / sampleSize);
|
||||||
|
mTempCanvas.drawBitmap(mBuffer, -wantRegion.left, -wantRegion.top, mTempPaint);
|
||||||
|
mTempCanvas.restore();
|
||||||
|
mTempCanvas.setBitmap(null);
|
||||||
|
return newBitmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link com.android.photos.views.TiledImageRenderer.TileSource} using
|
* A {@link com.android.photos.views.TiledImageRenderer.TileSource} using
|
||||||
* {@link BitmapRegionDecoder} to wrap a local file
|
* {@link BitmapRegionDecoder} to wrap a local file
|
||||||
@@ -59,7 +159,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
|
|||||||
public static final int MAX_PREVIEW_SIZE = GL_SIZE_LIMIT / 2;
|
public static final int MAX_PREVIEW_SIZE = GL_SIZE_LIMIT / 2;
|
||||||
|
|
||||||
public static abstract class BitmapSource {
|
public static abstract class BitmapSource {
|
||||||
private BitmapRegionDecoder mDecoder;
|
private SimpleBitmapRegionDecoder mDecoder;
|
||||||
private Bitmap mPreview;
|
private Bitmap mPreview;
|
||||||
private int mPreviewSize;
|
private int mPreviewSize;
|
||||||
private int mRotation;
|
private int mRotation;
|
||||||
@@ -103,7 +203,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
|
|||||||
return mState;
|
return mState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BitmapRegionDecoder getBitmapRegionDecoder() {
|
public SimpleBitmapRegionDecoder getBitmapRegionDecoder() {
|
||||||
return mDecoder;
|
return mDecoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +220,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract boolean readExif(ExifInterface ei);
|
public abstract boolean readExif(ExifInterface ei);
|
||||||
public abstract BitmapRegionDecoder loadBitmapRegionDecoder();
|
public abstract SimpleBitmapRegionDecoder loadBitmapRegionDecoder();
|
||||||
public abstract Bitmap loadPreviewBitmap(BitmapFactory.Options options);
|
public abstract Bitmap loadPreviewBitmap(BitmapFactory.Options options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,13 +231,13 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
|
|||||||
mPath = path;
|
mPath = path;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public BitmapRegionDecoder loadBitmapRegionDecoder() {
|
public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() {
|
||||||
try {
|
SimpleBitmapRegionDecoder d;
|
||||||
return BitmapRegionDecoder.newInstance(mPath, true);
|
d = SimpleBitmapRegionDecoderWrapper.newInstance(mPath, true);
|
||||||
} catch (IOException e) {
|
if (d == null) {
|
||||||
Log.w("BitmapRegionTileSource", "getting decoder failed", e);
|
d = DumbBitmapRegionDecoder.newInstance(mPath);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return d;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Bitmap loadPreviewBitmap(BitmapFactory.Options options) {
|
public Bitmap loadPreviewBitmap(BitmapFactory.Options options) {
|
||||||
@@ -168,11 +268,17 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
|
|||||||
return new BufferedInputStream(is);
|
return new BufferedInputStream(is);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public BitmapRegionDecoder loadBitmapRegionDecoder() {
|
public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() {
|
||||||
try {
|
try {
|
||||||
InputStream is = regenerateInputStream();
|
InputStream is = regenerateInputStream();
|
||||||
BitmapRegionDecoder regionDecoder = BitmapRegionDecoder.newInstance(is, false);
|
SimpleBitmapRegionDecoder regionDecoder =
|
||||||
|
SimpleBitmapRegionDecoderWrapper.newInstance(is, false);
|
||||||
Utils.closeSilently(is);
|
Utils.closeSilently(is);
|
||||||
|
if (regionDecoder == null) {
|
||||||
|
is = regenerateInputStream();
|
||||||
|
regionDecoder = DumbBitmapRegionDecoder.newInstance(is);
|
||||||
|
Utils.closeSilently(is);
|
||||||
|
}
|
||||||
return regionDecoder;
|
return regionDecoder;
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
|
Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
|
||||||
@@ -196,8 +302,9 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public boolean readExif(ExifInterface ei) {
|
public boolean readExif(ExifInterface ei) {
|
||||||
|
InputStream is = null;
|
||||||
try {
|
try {
|
||||||
InputStream is = regenerateInputStream();
|
is = regenerateInputStream();
|
||||||
ei.readExif(is);
|
ei.readExif(is);
|
||||||
Utils.closeSilently(is);
|
Utils.closeSilently(is);
|
||||||
return true;
|
return true;
|
||||||
@@ -207,6 +314,8 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
|
Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
|
||||||
return false;
|
return false;
|
||||||
|
} finally {
|
||||||
|
Utils.closeSilently(is);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,16 +333,17 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
|
|||||||
return new BufferedInputStream(is);
|
return new BufferedInputStream(is);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public BitmapRegionDecoder loadBitmapRegionDecoder() {
|
public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() {
|
||||||
try {
|
InputStream is = regenerateInputStream();
|
||||||
InputStream is = regenerateInputStream();
|
SimpleBitmapRegionDecoder regionDecoder =
|
||||||
BitmapRegionDecoder regionDecoder = BitmapRegionDecoder.newInstance(is, true);
|
SimpleBitmapRegionDecoderWrapper.newInstance(is, false);
|
||||||
|
Utils.closeSilently(is);
|
||||||
|
if (regionDecoder == null) {
|
||||||
|
is = regenerateInputStream();
|
||||||
|
regionDecoder = DumbBitmapRegionDecoder.newInstance(is);
|
||||||
Utils.closeSilently(is);
|
Utils.closeSilently(is);
|
||||||
return regionDecoder;
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e("BitmapRegionTileSource", "Error reading resource", e);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return regionDecoder;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Bitmap loadPreviewBitmap(BitmapFactory.Options options) {
|
public Bitmap loadPreviewBitmap(BitmapFactory.Options options) {
|
||||||
@@ -253,7 +363,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BitmapRegionDecoder mDecoder;
|
SimpleBitmapRegionDecoder mDecoder;
|
||||||
int mWidth;
|
int mWidth;
|
||||||
int mHeight;
|
int mHeight;
|
||||||
int mTileSize;
|
int mTileSize;
|
||||||
|
|||||||
Reference in New Issue
Block a user