Tengo problemas con BitmapFactory.decodeStream(inputStream)
. Cuando se usa sin opciones, devolverá una imagen. Pero cuando lo uso con opciones, ya .decodeStream(inputStream, null, options)
que nunca devuelve Bitmaps.
Lo que intento hacer es reducir la resolución de un mapa de bits antes de cargarlo para ahorrar memoria. He leído algunas buenas guías, pero ninguna las usa .decodeStream
.
FUNCIONA MUY BIEN
URL url = new URL(sUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
InputStream is = connection.getInputStream();
Bitmap img = BitmapFactory.decodeStream(is, null, options);
NO FUNCIONA
InputStream is = connection.getInputStream();
Bitmap img = BitmapFactory.decodeStream(is, null, options);
InputStream is = connection.getInputStream();
Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
Boolean scaleByHeight = Math.abs(options.outHeight - TARGET_HEIGHT) >= Math.abs(options.outWidth - TARGET_WIDTH);
if (options.outHeight * options.outWidth * 2 >= 200*100*2){
// Load, scaling to smallest power of 2 that'll get it <= desired dimensions
double sampleSize = scaleByHeight
? options.outHeight / TARGET_HEIGHT
: options.outWidth / TARGET_WIDTH;
options.inSampleSize =
(int)Math.pow(2d, Math.floor(
Math.log(sampleSize)/Math.log(2d)));
}
// Do the actual decoding
options.inJustDecodeBounds = false;
Bitmap img = BitmapFactory.decodeStream(is, null, options);
Respuestas:
El problema es que una vez que ha utilizado un InputStream de una HttpUrlConnection para recuperar metadatos de imagen, no puede rebobinar y utilizar el mismo InputStream de nuevo.
Por lo tanto, debe crear un nuevo InputStream para el muestreo real de la imagen.
Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(is, null, options); Boolean scaleByHeight = Math.abs(options.outHeight - TARGET_HEIGHT) >= Math.abs(options.outWidth - TARGET_WIDTH); if(options.outHeight * options.outWidth * 2 >= 200*200*2){ // Load, scaling to smallest power of 2 that'll get it <= desired dimensions double sampleSize = scaleByHeight ? options.outHeight / TARGET_HEIGHT : options.outWidth / TARGET_WIDTH; options.inSampleSize = (int)Math.pow(2d, Math.floor( Math.log(sampleSize)/Math.log(2d))); } // Do the actual decoding options.inJustDecodeBounds = false; is.close(); is = getHTTPConnectionInputStream(sUrl); Bitmap img = BitmapFactory.decodeStream(is, null, options); is.close();
fuente
Intente envolver InputStream con BufferedInputStream.
InputStream is = new BufferedInputStream(conn.getInputStream()); is.mark(is.available()); // Do the bound decoding // inJustDecodeBounds =true is.reset(); // Do the actual decoding
fuente
Creo que el problema está en la lógica de "calcular-factor de escala" porque el resto del código me parece correcto (asumiendo, por supuesto, que el flujo de entrada no es nulo).
Sería mejor si pudiera factorizar toda la lógica de cálculo de tamaño de esta rutina en un método (llámelo calculateScaleFactor () o lo que sea) y pruebe ese método de forma independiente primero.
Algo como:
// Get the stream InputStream is = mUrl.openStream(); // get the Image bounds BitmapFactory.Options options=new BitmapFactory.Options(); options.inJustDecodeBounds = true; bitmap = BitmapFactory.decodeStream(is,null,options); //get actual width x height of the image and calculate the scale factor options.inSampleSize = getScaleFactor(options.outWidth,options.outHeight, view.getWidth(),view.getHeight()); options.inJustDecodeBounds = false; bitmap=BitmapFactory.decodeStream(mUrl.openStream(),null,options);
y pruebe getScaleFactor (...) de forma independiente.
También ayudará rodear todo el código con el bloque try..catch {}, si aún no lo ha hecho.
fuente
Puede convertir InputStream en una matriz de bytes y usar decodeByteArray (). Por ejemplo,
public static Bitmap decodeSampledBitmapFromStream(InputStream inputStream, int reqWidth, int reqHeight) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { int n; byte[] buffer = new byte[1024]; while ((n = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, n); } return decodeSampledBitmapFromByteArray(outputStream.toByteArray(), reqWidth, reqHeight); } catch (IOException e) { e.printStackTrace(); } finally { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } public static Bitmap decodeSampledBitmapFromByteArray(byte[] data, int reqWidth, int reqHeight) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(data, 0, data.length, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds = false; return BitmapFactory.decodeByteArray(data, 0, data.length, options); } private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { int width = options.outWidth; int height = options.outHeight; int inSampleSize = 1; if (width > reqWidth || height > reqHeight) { int halfWidth = width / 2; int halfHeight = height / 2; while (halfWidth / inSampleSize >= reqWidth && halfHeight / inSampleSize >= reqHeight) { inSampleSize *= 2; } } return inSampleSize; }
fuente