From c1c96f1342a87cc3f5b7eac5de6ff674c5815c6a Mon Sep 17 00:00:00 2001 From: Florian Minjat Date: Thu, 11 Apr 2013 11:52:08 +0200 Subject: [PATCH] Create sampled bitmap This patch is based on the Android developer training 'Loading Large Bitmaps Efficiently': http://developer.android.com/training/displaying-bitmaps/load-bitmap.html It enables to use the method AssetBitmapTextureAtlasSource.createSampled to create a scaled down version a a bitmap into memory, for example to display a thumbnail of a big image. It sets the inSampleSize of BitmapFactory.Options object of the BitmapFactory.decodeResource method. This sample value can only be integer and power of two are faster and more efficient for the decoder. --- .../source/AssetBitmapTextureAtlasSource.java | 55 ++++++++++++++++++- .../atlas/source/BaseTextureAtlasSource.java | 13 ++++- .../atlas/source/ITextureAtlasSource.java | 2 + .../texture/region/TextureRegionFactory.java | 2 +- 4 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/org/andengine/opengl/texture/atlas/bitmap/source/AssetBitmapTextureAtlasSource.java b/src/org/andengine/opengl/texture/atlas/bitmap/source/AssetBitmapTextureAtlasSource.java index 9b8462aab..08830da51 100644 --- a/src/org/andengine/opengl/texture/atlas/bitmap/source/AssetBitmapTextureAtlasSource.java +++ b/src/org/andengine/opengl/texture/atlas/bitmap/source/AssetBitmapTextureAtlasSource.java @@ -13,7 +13,7 @@ import android.graphics.BitmapFactory; /** - * (c) 2010 Nicolas Gramlich + * (c) 2010 Nicolas Gramlich * (c) 2011 Zynga Inc. * * @author Nicolas Gramlich @@ -55,9 +55,35 @@ public static AssetBitmapTextureAtlasSource create(final AssetManager pAssetMana return new AssetBitmapTextureAtlasSource(pAssetManager, pAssetPath, pTextureX, pTextureY, decodeOptions.outWidth, decodeOptions.outHeight); } + + public static AssetBitmapTextureAtlasSource createSampled(final AssetManager pAssetManager, final String pAssetPath, final int pReqWidth, final int pReqHeight) { + final BitmapFactory.Options decodeOptions = new BitmapFactory.Options(); + decodeOptions.inJustDecodeBounds = true; + + InputStream in = null; + try { + in = pAssetManager.open(pAssetPath); + BitmapFactory.decodeStream(in, null, decodeOptions); + } catch (final IOException e) { + Debug.e("Failed loading Bitmap in AssetBitmapTextureAtlasSource. AssetPath: " + pAssetPath, e); + } finally { + StreamUtils.close(in); + } + + // Calculate inSampleSize + final int lInSampleSize = calculateInSampleSize(decodeOptions, pReqWidth, pReqHeight); + final int lTextureWidth = decodeOptions.outWidth / lInSampleSize; + final int lTextureHeight = decodeOptions.outHeight / lInSampleSize; + Debug.i("createSampled(pAssetManager, pAssetPath=" + pAssetPath + ", pReqWidth=" + pReqWidth + ", pReqHeight=" + pReqHeight + ") original image of " + decodeOptions.outWidth + "x" + decodeOptions.outHeight + " lInSampleSize=" + lInSampleSize + " -> resampled to size " + lTextureWidth + "x" + lTextureHeight); + return new AssetBitmapTextureAtlasSource(pAssetManager, pAssetPath, 0, 0, lTextureWidth, lTextureHeight, lInSampleSize); + } AssetBitmapTextureAtlasSource(final AssetManager pAssetManager, final String pAssetPath, final int pTextureX, final int pTextureY, final int pTextureWidth, final int pTextureHeight) { - super(pTextureX, pTextureY, pTextureWidth, pTextureHeight); + this(pAssetManager, pAssetPath, pTextureX, pTextureY, pTextureWidth, pTextureHeight, 1); + } + + AssetBitmapTextureAtlasSource(final AssetManager pAssetManager, final String pAssetPath, final int pTextureX, final int pTextureY, final int pTextureWidth, final int pTextureHeight, final int pSampleSize) { + super(pTextureX, pTextureY, pTextureWidth, pTextureHeight, pSampleSize); this.mAssetManager = pAssetManager; this.mAssetPath = pAssetPath; @@ -82,7 +108,9 @@ public Bitmap onLoadBitmap(final Config pBitmapConfig) { try { final BitmapFactory.Options decodeOptions = new BitmapFactory.Options(); decodeOptions.inPreferredConfig = pBitmapConfig; - + if (mSampleSize != 1) { + decodeOptions.inSampleSize = mSampleSize; + } in = this.mAssetManager.open(this.mAssetPath); return BitmapFactory.decodeStream(in, null, decodeOptions); } catch (final IOException e) { @@ -101,6 +129,27 @@ public String toString() { // =========================================================== // Methods // =========================================================== + + public static int calculateInSampleSize(final BitmapFactory.Options pOptions, final int pReqWidth, final int pReqHeight) { + // Raw height and width of image + final int lHeight = pOptions.outHeight; + final int lWidth = pOptions.outWidth; + int lInSampleSize = 1; + + if (lHeight > pReqHeight || lWidth > pReqWidth) { + + // Calculate ratios of height and width to requested height and width + final int lHeightRatio = Math.round((float) lHeight / (float) pReqHeight); + final int lWidthRatio = Math.round((float) lWidth / (float) pReqWidth); + + // Choose the smallest ratio as inSampleSize value, this will guarantee + // a final image with both dimensions larger than or equal to the + // requested height and width. + lInSampleSize = lHeightRatio < lWidthRatio ? lHeightRatio : lWidthRatio; + } + + return lInSampleSize; + } // =========================================================== // Inner and Anonymous Classes diff --git a/src/org/andengine/opengl/texture/atlas/source/BaseTextureAtlasSource.java b/src/org/andengine/opengl/texture/atlas/source/BaseTextureAtlasSource.java index 47968fc59..1e322837e 100644 --- a/src/org/andengine/opengl/texture/atlas/source/BaseTextureAtlasSource.java +++ b/src/org/andengine/opengl/texture/atlas/source/BaseTextureAtlasSource.java @@ -20,16 +20,22 @@ public abstract class BaseTextureAtlasSource implements ITextureAtlasSource { protected int mTextureY; protected int mTextureWidth; protected int mTextureHeight; + protected int mSampleSize; // =========================================================== // Constructors // =========================================================== - public BaseTextureAtlasSource(final int pTextureX, final int pTextureY, final int pTextureWidth, final int pTextureHeight) { + public BaseTextureAtlasSource(final int pTextureX, final int pTextureY, final int pTextureWidth, final int pTextureHeight, final int pSampleSize) { this.mTextureX = pTextureX; this.mTextureY = pTextureY; this.mTextureWidth = pTextureWidth; this.mTextureHeight = pTextureHeight; + this.mSampleSize = pSampleSize; + } + + public BaseTextureAtlasSource(final int pTextureX, final int pTextureY, final int pTextureWidth, final int pTextureHeight) { + this(pTextureX, pTextureY, pTextureWidth, pTextureHeight, 1); } // =========================================================== @@ -80,6 +86,11 @@ public void setTextureHeight(final int pTextureHeight) { // Methods for/from SuperClass/Interfaces // =========================================================== + @Override + public int getSampleSize() { + return mSampleSize; + } + @Override public String toString() { return this.getClass().getSimpleName() + "( " + this.getTextureWidth() + "x" + this.getTextureHeight() + " @ "+ this.mTextureX + "/" + this.mTextureY + " )"; diff --git a/src/org/andengine/opengl/texture/atlas/source/ITextureAtlasSource.java b/src/org/andengine/opengl/texture/atlas/source/ITextureAtlasSource.java index 8141f6f61..659b1110d 100644 --- a/src/org/andengine/opengl/texture/atlas/source/ITextureAtlasSource.java +++ b/src/org/andengine/opengl/texture/atlas/source/ITextureAtlasSource.java @@ -26,6 +26,8 @@ public interface ITextureAtlasSource { public int getTextureHeight(); public void setTextureWidth(final int pTextureWidth); public void setTextureHeight(final int pTextureHeight); + + public int getSampleSize(); public ITextureAtlasSource deepCopy(); } \ No newline at end of file diff --git a/src/org/andengine/opengl/texture/region/TextureRegionFactory.java b/src/org/andengine/opengl/texture/region/TextureRegionFactory.java index fd4d05097..636679a22 100644 --- a/src/org/andengine/opengl/texture/region/TextureRegionFactory.java +++ b/src/org/andengine/opengl/texture/region/TextureRegionFactory.java @@ -67,7 +67,7 @@ public static TextureRegion createFromSource(fin } public static TextureRegion createFromSource(final ITextureAtlas pTextureAtlas, final T pTextureAtlasSource, final int pTextureX, final int pTextureY, final boolean pRotated) { - final TextureRegion textureRegion = new TextureRegion(pTextureAtlas, pTextureX, pTextureY, pTextureAtlasSource.getTextureWidth(), pTextureAtlasSource.getTextureHeight(), pRotated); + final TextureRegion textureRegion = new TextureRegion(pTextureAtlas, pTextureX, pTextureY, pTextureAtlasSource.getTextureWidth(), pTextureAtlasSource.getTextureHeight(), pTextureAtlasSource.getSampleSize(), pRotated); pTextureAtlas.addTextureAtlasSource(pTextureAtlasSource, pTextureX, pTextureY); return textureRegion; }