Loading packages/WallpaperCropper/res/values/strings.xml +5 −0 Original line number Diff line number Diff line Loading @@ -17,4 +17,9 @@ <string name="crop_wallpaper">Crop wallpaper</string> <!-- Button label on Wallpaper picker screen; user selects this button to set a specific wallpaper --> <string name="wallpaper_instructions">Set wallpaper</string> <!-- Error message when an image is selected as a wallpaper, but the wallpaper cropper cannot load it. The user will usually see this when using another app and trying to set an image as the wallpaper --> <string name="wallpaper_load_fail">Couldn\'t load image as wallpaper</string> </resources> packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java +169 −56 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.os.Build.VERSION_CODES; import android.util.Log; import com.android.gallery3d.common.BitmapUtils; import com.android.gallery3d.common.Utils; import com.android.gallery3d.exif.ExifInterface; import com.android.gallery3d.glrenderer.BasicTexture; import com.android.gallery3d.glrenderer.BitmapTexture; Loading @@ -41,6 +42,85 @@ import java.io.FileNotFoundException; import java.io.IOException; 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[] streamCopy; Bitmap mBuffer; 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) { System.out.println("DECODING WITH SAMPLE LEVEL OF " + options.inSampleSize); return Bitmap.createBitmap( mBuffer, wantRegion.left, wantRegion.top, wantRegion.width(), wantRegion.height()); } } /** * A {@link com.android.photos.views.TiledImageRenderer.TileSource} using * {@link BitmapRegionDecoder} to wrap a local file Loading @@ -58,14 +138,16 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { public static final int MAX_PREVIEW_SIZE = GL_SIZE_LIMIT / 2; public static abstract class BitmapSource { private BitmapRegionDecoder mDecoder; private SimpleBitmapRegionDecoder mDecoder; private Bitmap mPreview; private int mPreviewSize; private int mRotation; public enum State { NOT_LOADED, LOADED, ERROR_LOADING }; private State mState = State.NOT_LOADED; public BitmapSource(int previewSize) { mPreviewSize = previewSize; } public void loadInBackground() { public boolean loadInBackground() { ExifInterface ei = new ExifInterface(); if (readExif(ei)) { Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION); Loading @@ -74,6 +156,10 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { } } mDecoder = loadBitmapRegionDecoder(); if (mDecoder == null) { mState = State.ERROR_LOADING; return false; } else { int width = mDecoder.getWidth(); int height = mDecoder.getHeight(); if (mPreviewSize != 0) { Loading @@ -87,9 +173,16 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { opts.inJustDecodeBounds = false; mPreview = loadPreviewBitmap(opts); } mState = State.LOADED; return true; } } public BitmapRegionDecoder getBitmapRegionDecoder() { public State getLoadingState() { return mState; } public SimpleBitmapRegionDecoder getBitmapRegionDecoder() { return mDecoder; } Loading @@ -106,7 +199,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { } public abstract boolean readExif(ExifInterface ei); public abstract BitmapRegionDecoder loadBitmapRegionDecoder(); public abstract SimpleBitmapRegionDecoder loadBitmapRegionDecoder(); public abstract Bitmap loadPreviewBitmap(BitmapFactory.Options options); } Loading @@ -117,13 +210,13 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { mPath = path; } @Override public BitmapRegionDecoder loadBitmapRegionDecoder() { try { return BitmapRegionDecoder.newInstance(mPath, true); } catch (IOException e) { Log.w("BitmapRegionTileSource", "getting decoder failed", e); return null; public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() { SimpleBitmapRegionDecoder d; d = SimpleBitmapRegionDecoderWrapper.newInstance(mPath, true); if (d == null) { d = DumbBitmapRegionDecoder.newInstance(mPath); } return d; } @Override public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { Loading Loading @@ -154,9 +247,17 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { return new BufferedInputStream(is); } @Override public BitmapRegionDecoder loadBitmapRegionDecoder() { public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() { try { return BitmapRegionDecoder.newInstance(regenerateInputStream(), true); InputStream is = regenerateInputStream(); SimpleBitmapRegionDecoder regionDecoder = SimpleBitmapRegionDecoderWrapper.newInstance(is, false); Utils.closeSilently(is); if (regionDecoder == null) { is = regenerateInputStream(); regionDecoder = DumbBitmapRegionDecoder.newInstance(is); } return regionDecoder; } catch (FileNotFoundException e) { Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); return null; Loading @@ -168,7 +269,10 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { @Override public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { try { return BitmapFactory.decodeStream(regenerateInputStream(), null, options); InputStream is = regenerateInputStream(); Bitmap b = BitmapFactory.decodeStream(is, null, options); Utils.closeSilently(is); return b; } catch (FileNotFoundException e) { Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); return null; Loading @@ -177,13 +281,15 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { @Override public boolean readExif(ExifInterface ei) { try { ei.readExif(regenerateInputStream()); InputStream is = regenerateInputStream(); ei.readExif(is); Utils.closeSilently(is); return true; } catch (FileNotFoundException e) { Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); return false; } catch (IOException e) { Log.e("BitmapRegionTileSource", "Failure while reading URI " + mUri, e); Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); return false; } } Loading @@ -202,13 +308,16 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { return new BufferedInputStream(is); } @Override public BitmapRegionDecoder loadBitmapRegionDecoder() { try { return BitmapRegionDecoder.newInstance(regenerateInputStream(), true); } catch (IOException e) { Log.e("BitmapRegionTileSource", "Error reading resource", e); return null; public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() { InputStream is = regenerateInputStream(); SimpleBitmapRegionDecoder regionDecoder = SimpleBitmapRegionDecoderWrapper.newInstance(is, false); Utils.closeSilently(is); if (regionDecoder == null) { is = regenerateInputStream(); regionDecoder = DumbBitmapRegionDecoder.newInstance(is); } return regionDecoder; } @Override public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { Loading @@ -217,7 +326,9 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { @Override public boolean readExif(ExifInterface ei) { try { ei.readExif(regenerateInputStream()); InputStream is = regenerateInputStream(); ei.readExif(is); Utils.closeSilently(is); return true; } catch (IOException e) { Log.e("BitmapRegionTileSource", "Error reading resource", e); Loading @@ -226,7 +337,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { } } BitmapRegionDecoder mDecoder; SimpleBitmapRegionDecoder mDecoder; int mWidth; int mHeight; int mTileSize; Loading @@ -243,6 +354,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { mTileSize = TiledImageRenderer.suggestedTileSize(context); mRotation = source.getRotation(); mDecoder = source.getBitmapRegionDecoder(); if (mDecoder != null) { mWidth = mDecoder.getWidth(); mHeight = mDecoder.getHeight(); mOptions = new BitmapFactory.Options(); Loading @@ -267,6 +379,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { } } } } @Override public int getTileSize() { Loading packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java +66 −31 Original line number Diff line number Diff line Loading @@ -41,10 +41,12 @@ import android.util.Log; import android.view.Display; import android.view.View; import android.view.WindowManager; import android.widget.Toast; import com.android.gallery3d.common.Utils; import com.android.gallery3d.exif.ExifInterface; import com.android.photos.BitmapRegionTileSource; import com.android.photos.BitmapRegionTileSource.BitmapSource; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; Loading Loading @@ -109,12 +111,24 @@ public class WallpaperCropActivity extends Activity { }); // Load image in background setCropViewTileSource( new BitmapRegionTileSource.UriBitmapSource(this, imageUri, 1024), true, false); final BitmapRegionTileSource.UriBitmapSource bitmapSource = new BitmapRegionTileSource.UriBitmapSource(this, imageUri, 1024); Runnable onLoad = new Runnable() { public void run() { if (bitmapSource.getLoadingState() != BitmapSource.State.LOADED) { Toast.makeText(WallpaperCropActivity.this, getString(R.string.wallpaper_load_fail), Toast.LENGTH_LONG).show(); finish(); } } }; setCropViewTileSource(bitmapSource, true, false, onLoad); } public void setCropViewTileSource(final BitmapRegionTileSource.BitmapSource bitmapSource, final boolean touchEnabled, final boolean moveToLeft) { public void setCropViewTileSource( final BitmapRegionTileSource.BitmapSource bitmapSource, final boolean touchEnabled, final boolean moveToLeft, final Runnable postExecute) { final Context context = WallpaperCropActivity.this; final View progressView = findViewById(R.id.loading); final AsyncTask<Void, Void, Void> loadBitmapTask = new AsyncTask<Void, Void, Void>() { Loading @@ -127,6 +141,7 @@ public class WallpaperCropActivity extends Activity { protected void onPostExecute(Void arg) { if (!isCancelled()) { progressView.setVisibility(View.INVISIBLE); if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) { mCropView.setTileSource( new BitmapRegionTileSource(context, bitmapSource), null); mCropView.setTouchEnabled(touchEnabled); Loading @@ -135,6 +150,10 @@ public class WallpaperCropActivity extends Activity { } } } if (postExecute != null) { postExecute.run(); } } }; // We don't want to show the spinner every time we load an image, because that would be // annoying; instead, only start showing the spinner if loading the image has taken Loading Loading @@ -235,10 +254,12 @@ public class WallpaperCropActivity extends Activity { InputStream is = context.getContentResolver().openInputStream(uri); BufferedInputStream bis = new BufferedInputStream(is); ei.readExif(bis); bis.close(); } else { InputStream is = res.openRawResource(resId); BufferedInputStream bis = new BufferedInputStream(is); ei.readExif(bis); bis.close(); } Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION); if (ori != null) { Loading Loading @@ -408,7 +429,6 @@ public class WallpaperCropActivity extends Activity { String mInFilePath; byte[] mInImageBytes; int mInResId = 0; InputStream mInStream; RectF mCropBounds = null; int mOutWidth, mOutHeight; int mRotation; Loading Loading @@ -481,37 +501,36 @@ public class WallpaperCropActivity extends Activity { } // Helper to setup input stream private void regenerateInputStream() { private InputStream regenerateInputStream() { if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) { Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " + "image byte array given"); } else { Utils.closeSilently(mInStream); try { if (mInUri != null) { mInStream = new BufferedInputStream( return new BufferedInputStream( mContext.getContentResolver().openInputStream(mInUri)); } else if (mInFilePath != null) { mInStream = mContext.openFileInput(mInFilePath); return mContext.openFileInput(mInFilePath); } else if (mInImageBytes != null) { mInStream = new BufferedInputStream( new ByteArrayInputStream(mInImageBytes)); return new BufferedInputStream(new ByteArrayInputStream(mInImageBytes)); } else { mInStream = new BufferedInputStream( mResources.openRawResource(mInResId)); return new BufferedInputStream(mResources.openRawResource(mInResId)); } } catch (FileNotFoundException e) { Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e); } } return null; } public Point getImageBounds() { regenerateInputStream(); if (mInStream != null) { InputStream is = regenerateInputStream(); if (is != null) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(mInStream, null, options); BitmapFactory.decodeStream(is, null, options); Utils.closeSilently(is); if (options.outWidth != 0 && options.outHeight != 0) { return new Point(options.outWidth, options.outHeight); } Loading @@ -529,22 +548,26 @@ public class WallpaperCropActivity extends Activity { public boolean cropBitmap() { boolean failure = false; regenerateInputStream(); WallpaperManager wallpaperManager = null; if (mSetWallpaper) { wallpaperManager = WallpaperManager.getInstance(mContext.getApplicationContext()); } if (mSetWallpaper && mNoCrop && mInStream != null) { if (mSetWallpaper && mNoCrop) { try { wallpaperManager.setStream(mInStream); InputStream is = regenerateInputStream(); if (is != null) { wallpaperManager.setStream(is); Utils.closeSilently(is); } } catch (IOException e) { Log.w(LOGTAG, "cannot write stream to wallpaper", e); failure = true; } return !failure; } if (mInStream != null) { } else { // Find crop bounds (scaled to original image size) Rect roundedTrueCrop = new Rect(); Matrix rotateMatrix = new Matrix(); Loading @@ -557,6 +580,11 @@ public class WallpaperCropActivity extends Activity { mCropBounds = new RectF(roundedTrueCrop); Point bounds = getImageBounds(); if (bounds == null) { Log.w(LOGTAG, "cannot get bounds for image"); failure = true; return false; } float[] rotatedBounds = new float[] { bounds.x, bounds.y }; rotateMatrix.mapPoints(rotatedBounds); Loading @@ -567,7 +595,6 @@ public class WallpaperCropActivity extends Activity { inverseRotateMatrix.mapRect(mCropBounds); mCropBounds.offset(bounds.x/2, bounds.y/2); regenerateInputStream(); } mCropBounds.roundOut(roundedTrueCrop); Loading @@ -585,7 +612,14 @@ public class WallpaperCropActivity extends Activity { // Attempt to open a region decoder BitmapRegionDecoder decoder = null; try { decoder = BitmapRegionDecoder.newInstance(mInStream, true); InputStream is = regenerateInputStream(); if (is == null) { Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString()); failure = true; return false; } decoder = BitmapRegionDecoder.newInstance(is, false); Utils.closeSilently(is); } catch (IOException e) { Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e); } Loading @@ -603,14 +637,15 @@ public class WallpaperCropActivity extends Activity { if (crop == null) { // BitmapRegionDecoder has failed, try to crop in-memory regenerateInputStream(); InputStream is = regenerateInputStream(); Bitmap fullSize = null; if (mInStream != null) { if (is != null) { BitmapFactory.Options options = new BitmapFactory.Options(); if (scaleDownSampleSize > 1) { options.inSampleSize = scaleDownSampleSize; } fullSize = BitmapFactory.decodeStream(mInStream, null, options); fullSize = BitmapFactory.decodeStream(is, null, options); Utils.closeSilently(is); } if (fullSize != null) { mCropBounds.left /= scaleDownSampleSize; Loading Loading
packages/WallpaperCropper/res/values/strings.xml +5 −0 Original line number Diff line number Diff line Loading @@ -17,4 +17,9 @@ <string name="crop_wallpaper">Crop wallpaper</string> <!-- Button label on Wallpaper picker screen; user selects this button to set a specific wallpaper --> <string name="wallpaper_instructions">Set wallpaper</string> <!-- Error message when an image is selected as a wallpaper, but the wallpaper cropper cannot load it. The user will usually see this when using another app and trying to set an image as the wallpaper --> <string name="wallpaper_load_fail">Couldn\'t load image as wallpaper</string> </resources>
packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java +169 −56 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.os.Build.VERSION_CODES; import android.util.Log; import com.android.gallery3d.common.BitmapUtils; import com.android.gallery3d.common.Utils; import com.android.gallery3d.exif.ExifInterface; import com.android.gallery3d.glrenderer.BasicTexture; import com.android.gallery3d.glrenderer.BitmapTexture; Loading @@ -41,6 +42,85 @@ import java.io.FileNotFoundException; import java.io.IOException; 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[] streamCopy; Bitmap mBuffer; 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) { System.out.println("DECODING WITH SAMPLE LEVEL OF " + options.inSampleSize); return Bitmap.createBitmap( mBuffer, wantRegion.left, wantRegion.top, wantRegion.width(), wantRegion.height()); } } /** * A {@link com.android.photos.views.TiledImageRenderer.TileSource} using * {@link BitmapRegionDecoder} to wrap a local file Loading @@ -58,14 +138,16 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { public static final int MAX_PREVIEW_SIZE = GL_SIZE_LIMIT / 2; public static abstract class BitmapSource { private BitmapRegionDecoder mDecoder; private SimpleBitmapRegionDecoder mDecoder; private Bitmap mPreview; private int mPreviewSize; private int mRotation; public enum State { NOT_LOADED, LOADED, ERROR_LOADING }; private State mState = State.NOT_LOADED; public BitmapSource(int previewSize) { mPreviewSize = previewSize; } public void loadInBackground() { public boolean loadInBackground() { ExifInterface ei = new ExifInterface(); if (readExif(ei)) { Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION); Loading @@ -74,6 +156,10 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { } } mDecoder = loadBitmapRegionDecoder(); if (mDecoder == null) { mState = State.ERROR_LOADING; return false; } else { int width = mDecoder.getWidth(); int height = mDecoder.getHeight(); if (mPreviewSize != 0) { Loading @@ -87,9 +173,16 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { opts.inJustDecodeBounds = false; mPreview = loadPreviewBitmap(opts); } mState = State.LOADED; return true; } } public BitmapRegionDecoder getBitmapRegionDecoder() { public State getLoadingState() { return mState; } public SimpleBitmapRegionDecoder getBitmapRegionDecoder() { return mDecoder; } Loading @@ -106,7 +199,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { } public abstract boolean readExif(ExifInterface ei); public abstract BitmapRegionDecoder loadBitmapRegionDecoder(); public abstract SimpleBitmapRegionDecoder loadBitmapRegionDecoder(); public abstract Bitmap loadPreviewBitmap(BitmapFactory.Options options); } Loading @@ -117,13 +210,13 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { mPath = path; } @Override public BitmapRegionDecoder loadBitmapRegionDecoder() { try { return BitmapRegionDecoder.newInstance(mPath, true); } catch (IOException e) { Log.w("BitmapRegionTileSource", "getting decoder failed", e); return null; public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() { SimpleBitmapRegionDecoder d; d = SimpleBitmapRegionDecoderWrapper.newInstance(mPath, true); if (d == null) { d = DumbBitmapRegionDecoder.newInstance(mPath); } return d; } @Override public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { Loading Loading @@ -154,9 +247,17 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { return new BufferedInputStream(is); } @Override public BitmapRegionDecoder loadBitmapRegionDecoder() { public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() { try { return BitmapRegionDecoder.newInstance(regenerateInputStream(), true); InputStream is = regenerateInputStream(); SimpleBitmapRegionDecoder regionDecoder = SimpleBitmapRegionDecoderWrapper.newInstance(is, false); Utils.closeSilently(is); if (regionDecoder == null) { is = regenerateInputStream(); regionDecoder = DumbBitmapRegionDecoder.newInstance(is); } return regionDecoder; } catch (FileNotFoundException e) { Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); return null; Loading @@ -168,7 +269,10 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { @Override public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { try { return BitmapFactory.decodeStream(regenerateInputStream(), null, options); InputStream is = regenerateInputStream(); Bitmap b = BitmapFactory.decodeStream(is, null, options); Utils.closeSilently(is); return b; } catch (FileNotFoundException e) { Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); return null; Loading @@ -177,13 +281,15 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { @Override public boolean readExif(ExifInterface ei) { try { ei.readExif(regenerateInputStream()); InputStream is = regenerateInputStream(); ei.readExif(is); Utils.closeSilently(is); return true; } catch (FileNotFoundException e) { Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); return false; } catch (IOException e) { Log.e("BitmapRegionTileSource", "Failure while reading URI " + mUri, e); Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); return false; } } Loading @@ -202,13 +308,16 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { return new BufferedInputStream(is); } @Override public BitmapRegionDecoder loadBitmapRegionDecoder() { try { return BitmapRegionDecoder.newInstance(regenerateInputStream(), true); } catch (IOException e) { Log.e("BitmapRegionTileSource", "Error reading resource", e); return null; public SimpleBitmapRegionDecoder loadBitmapRegionDecoder() { InputStream is = regenerateInputStream(); SimpleBitmapRegionDecoder regionDecoder = SimpleBitmapRegionDecoderWrapper.newInstance(is, false); Utils.closeSilently(is); if (regionDecoder == null) { is = regenerateInputStream(); regionDecoder = DumbBitmapRegionDecoder.newInstance(is); } return regionDecoder; } @Override public Bitmap loadPreviewBitmap(BitmapFactory.Options options) { Loading @@ -217,7 +326,9 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { @Override public boolean readExif(ExifInterface ei) { try { ei.readExif(regenerateInputStream()); InputStream is = regenerateInputStream(); ei.readExif(is); Utils.closeSilently(is); return true; } catch (IOException e) { Log.e("BitmapRegionTileSource", "Error reading resource", e); Loading @@ -226,7 +337,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { } } BitmapRegionDecoder mDecoder; SimpleBitmapRegionDecoder mDecoder; int mWidth; int mHeight; int mTileSize; Loading @@ -243,6 +354,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { mTileSize = TiledImageRenderer.suggestedTileSize(context); mRotation = source.getRotation(); mDecoder = source.getBitmapRegionDecoder(); if (mDecoder != null) { mWidth = mDecoder.getWidth(); mHeight = mDecoder.getHeight(); mOptions = new BitmapFactory.Options(); Loading @@ -267,6 +379,7 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { } } } } @Override public int getTileSize() { Loading
packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java +66 −31 Original line number Diff line number Diff line Loading @@ -41,10 +41,12 @@ import android.util.Log; import android.view.Display; import android.view.View; import android.view.WindowManager; import android.widget.Toast; import com.android.gallery3d.common.Utils; import com.android.gallery3d.exif.ExifInterface; import com.android.photos.BitmapRegionTileSource; import com.android.photos.BitmapRegionTileSource.BitmapSource; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; Loading Loading @@ -109,12 +111,24 @@ public class WallpaperCropActivity extends Activity { }); // Load image in background setCropViewTileSource( new BitmapRegionTileSource.UriBitmapSource(this, imageUri, 1024), true, false); final BitmapRegionTileSource.UriBitmapSource bitmapSource = new BitmapRegionTileSource.UriBitmapSource(this, imageUri, 1024); Runnable onLoad = new Runnable() { public void run() { if (bitmapSource.getLoadingState() != BitmapSource.State.LOADED) { Toast.makeText(WallpaperCropActivity.this, getString(R.string.wallpaper_load_fail), Toast.LENGTH_LONG).show(); finish(); } } }; setCropViewTileSource(bitmapSource, true, false, onLoad); } public void setCropViewTileSource(final BitmapRegionTileSource.BitmapSource bitmapSource, final boolean touchEnabled, final boolean moveToLeft) { public void setCropViewTileSource( final BitmapRegionTileSource.BitmapSource bitmapSource, final boolean touchEnabled, final boolean moveToLeft, final Runnable postExecute) { final Context context = WallpaperCropActivity.this; final View progressView = findViewById(R.id.loading); final AsyncTask<Void, Void, Void> loadBitmapTask = new AsyncTask<Void, Void, Void>() { Loading @@ -127,6 +141,7 @@ public class WallpaperCropActivity extends Activity { protected void onPostExecute(Void arg) { if (!isCancelled()) { progressView.setVisibility(View.INVISIBLE); if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) { mCropView.setTileSource( new BitmapRegionTileSource(context, bitmapSource), null); mCropView.setTouchEnabled(touchEnabled); Loading @@ -135,6 +150,10 @@ public class WallpaperCropActivity extends Activity { } } } if (postExecute != null) { postExecute.run(); } } }; // We don't want to show the spinner every time we load an image, because that would be // annoying; instead, only start showing the spinner if loading the image has taken Loading Loading @@ -235,10 +254,12 @@ public class WallpaperCropActivity extends Activity { InputStream is = context.getContentResolver().openInputStream(uri); BufferedInputStream bis = new BufferedInputStream(is); ei.readExif(bis); bis.close(); } else { InputStream is = res.openRawResource(resId); BufferedInputStream bis = new BufferedInputStream(is); ei.readExif(bis); bis.close(); } Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION); if (ori != null) { Loading Loading @@ -408,7 +429,6 @@ public class WallpaperCropActivity extends Activity { String mInFilePath; byte[] mInImageBytes; int mInResId = 0; InputStream mInStream; RectF mCropBounds = null; int mOutWidth, mOutHeight; int mRotation; Loading Loading @@ -481,37 +501,36 @@ public class WallpaperCropActivity extends Activity { } // Helper to setup input stream private void regenerateInputStream() { private InputStream regenerateInputStream() { if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) { Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " + "image byte array given"); } else { Utils.closeSilently(mInStream); try { if (mInUri != null) { mInStream = new BufferedInputStream( return new BufferedInputStream( mContext.getContentResolver().openInputStream(mInUri)); } else if (mInFilePath != null) { mInStream = mContext.openFileInput(mInFilePath); return mContext.openFileInput(mInFilePath); } else if (mInImageBytes != null) { mInStream = new BufferedInputStream( new ByteArrayInputStream(mInImageBytes)); return new BufferedInputStream(new ByteArrayInputStream(mInImageBytes)); } else { mInStream = new BufferedInputStream( mResources.openRawResource(mInResId)); return new BufferedInputStream(mResources.openRawResource(mInResId)); } } catch (FileNotFoundException e) { Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e); } } return null; } public Point getImageBounds() { regenerateInputStream(); if (mInStream != null) { InputStream is = regenerateInputStream(); if (is != null) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(mInStream, null, options); BitmapFactory.decodeStream(is, null, options); Utils.closeSilently(is); if (options.outWidth != 0 && options.outHeight != 0) { return new Point(options.outWidth, options.outHeight); } Loading @@ -529,22 +548,26 @@ public class WallpaperCropActivity extends Activity { public boolean cropBitmap() { boolean failure = false; regenerateInputStream(); WallpaperManager wallpaperManager = null; if (mSetWallpaper) { wallpaperManager = WallpaperManager.getInstance(mContext.getApplicationContext()); } if (mSetWallpaper && mNoCrop && mInStream != null) { if (mSetWallpaper && mNoCrop) { try { wallpaperManager.setStream(mInStream); InputStream is = regenerateInputStream(); if (is != null) { wallpaperManager.setStream(is); Utils.closeSilently(is); } } catch (IOException e) { Log.w(LOGTAG, "cannot write stream to wallpaper", e); failure = true; } return !failure; } if (mInStream != null) { } else { // Find crop bounds (scaled to original image size) Rect roundedTrueCrop = new Rect(); Matrix rotateMatrix = new Matrix(); Loading @@ -557,6 +580,11 @@ public class WallpaperCropActivity extends Activity { mCropBounds = new RectF(roundedTrueCrop); Point bounds = getImageBounds(); if (bounds == null) { Log.w(LOGTAG, "cannot get bounds for image"); failure = true; return false; } float[] rotatedBounds = new float[] { bounds.x, bounds.y }; rotateMatrix.mapPoints(rotatedBounds); Loading @@ -567,7 +595,6 @@ public class WallpaperCropActivity extends Activity { inverseRotateMatrix.mapRect(mCropBounds); mCropBounds.offset(bounds.x/2, bounds.y/2); regenerateInputStream(); } mCropBounds.roundOut(roundedTrueCrop); Loading @@ -585,7 +612,14 @@ public class WallpaperCropActivity extends Activity { // Attempt to open a region decoder BitmapRegionDecoder decoder = null; try { decoder = BitmapRegionDecoder.newInstance(mInStream, true); InputStream is = regenerateInputStream(); if (is == null) { Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString()); failure = true; return false; } decoder = BitmapRegionDecoder.newInstance(is, false); Utils.closeSilently(is); } catch (IOException e) { Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e); } Loading @@ -603,14 +637,15 @@ public class WallpaperCropActivity extends Activity { if (crop == null) { // BitmapRegionDecoder has failed, try to crop in-memory regenerateInputStream(); InputStream is = regenerateInputStream(); Bitmap fullSize = null; if (mInStream != null) { if (is != null) { BitmapFactory.Options options = new BitmapFactory.Options(); if (scaleDownSampleSize > 1) { options.inSampleSize = scaleDownSampleSize; } fullSize = BitmapFactory.decodeStream(mInStream, null, options); fullSize = BitmapFactory.decodeStream(is, null, options); Utils.closeSilently(is); } if (fullSize != null) { mCropBounds.left /= scaleDownSampleSize; Loading