package org.itsnat.droid.impl.xmlinflater; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Rect; import android.util.TypedValue; import org.itsnat.droid.ItsNatDroidException; import org.itsnat.droid.impl.dom.ParsedResourceImage; import org.itsnat.droid.impl.dom.ResourceDesc; import org.itsnat.droid.impl.dom.ResourceDescCompiled; import org.itsnat.droid.impl.dom.ResourceDescDynamic; import org.itsnat.droid.impl.util.MiscUtil; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; /** * Created by jmarranz on 19/10/2016. */ public class BitmapUtil { public static Bitmap getBitmapNoScale(ResourceDesc resourceDesc, Context ctx, XMLInflaterRegistry xmlInflaterRegistry) { return getBitmap(resourceDesc, -1, ctx, xmlInflaterRegistry); } public static Bitmap getBitmap(ResourceDesc resourceDesc,int bitmapDensityReference,Context ctx,XMLInflaterRegistry xmlInflaterRegistry) { if (resourceDesc instanceof ResourceDescDynamic) { // http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.3_r1/android/graphics/drawable/Drawable.java#Drawable.createFromXmlInner%28android.content.res.Resources%2Corg.xmlpull.v1.XmlPullParser%2Candroid.util.AttributeSet%29 ResourceDescDynamic resourceDescDyn = (ResourceDescDynamic)resourceDesc; ParsedResourceImage resource = (ParsedResourceImage)resourceDescDyn.getParsedResource(); byte[] byteArray = resource.getImgBytes(); Resources res = ctx.getResources(); return createBitmap(byteArray, bitmapDensityReference, res); } else if (resourceDesc instanceof ResourceDescCompiled) { String resourceDescValue = resourceDesc.getResourceDescValue(); if (XMLInflaterRegistry.isResource(resourceDescValue)) { // http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.3_r1/android/graphics/drawable/NinePatchDrawable.java#240 int resId = xmlInflaterRegistry.getIdentifierCompiled(resourceDescValue,ctx); // Si no se encuentra da error, no devuelve 0 TypedValue value = new TypedValue(); Resources res = ctx.getResources(); InputStream is = res.openRawResource(resId, value); return createBitmap(is,value,res); } throw new ItsNatDroidException("Cannot process " + resourceDescValue); } else throw MiscUtil.internalError(); } public static Bitmap createBitmap(byte[] byteArray,int bitmapDensityReference,Resources res) { // bitmapDensityReference es necesario para escalar adecuadamente un bitmap (no nine patch) // En ItsNat cuando los bitmaps son remotos no hay manera de elegir densidades por lo que // las imágenes se definen con una densidad concreta "que valga para todos los dispositivos", // los prototipos de layouts por ej se pueden testear poniéndo las imágenes en la carpeta drawable-densidad que se // quiera por ejemplo drawable-xhdpi (320 dpi), Android sabe de qué carpeta carga el bitmap y por tanto sabe // qué densidad tiene la imagen original de acuerdo a la carpeta (Options.inDensity) y sabe // si tiene que escalar o no según la densidad del dispositivo (Options.inTargetDensity) // Eso mismo lo tiene que hacer ItsNat para que el resultado sea el mismo que en un layout // compilado por ello hay que proporcionar la densidad de referencia usada durante el diseño (Options.inDensity) // para que el escalado se haga en memoria de forma programática por parte de ItsNat Droid /* http://developer.android.com/guide/practices/screens_support.html ldpi (low) ~120dpi mdpi (medium) ~160dpi hdpi (high) ~240dpi xhdpi (extra-high) ~320dpi xxhdpi (extra-extra-high) ~480dpi xxxhdpi (extra-extra-extra-high) ~640dpi */ // http://stackoverflow.com/questions/16773604/android-bitmap-scale-using-bitmapfactory-options // https://code.google.com/p/android/issues/detail?id=7538 // http://stackoverflow.com/questions/8048603/android-scaling-of-images-to-screen-density // http://stackoverflow.com/questions/13482946/supporting-multiple-screens-using-bitmap-factory-options BitmapFactory.Options options = new BitmapFactory.Options(); boolean scale = bitmapDensityReference > 0; if (scale) { /* options.inJustDecodeBounds = true; Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length, options); int bmpWidth = options.outWidth; int bmpHeight = options.outHeight; */ options.inScaled = true; options.inDensity = bitmapDensityReference; options.inTargetDensity = res.getDisplayMetrics().densityDpi; } // decodeByteArray NO escala las imágenes aunque se use BitmapFactory.Options return BitmapFactory.decodeStream(new ByteArrayInputStream(byteArray), null, options); } public static Bitmap createBitmap(InputStream is,TypedValue value,Resources res) { // No hace falta pasar Options ni escalar, ya lo hace Android pues por ejemplo la densidad de referencia la obtiene de donde obtiene el recurso (xhdpi, mdpi etc) final Rect padding = new Rect(); try { return BitmapFactory.decodeResourceStream(res, value, is, padding, null); } finally { try { is.close(); } catch (IOException e) { throw new ItsNatDroidException(e); } } } }