Fix crashes for images that are not PNG or JPEG

Bug: 11341544

Change-Id: If2339b583e9a991f053a5f95f259156e3e4e9acd
This commit is contained in:
Michael Jurka
2013-10-31 10:58:28 +01:00
parent b88ae4158d
commit 9789c42eab
2 changed files with 148 additions and 32 deletions
@@ -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;