当设置选项时返回 null

我对 BitmapFactory.decodeStream(inputStream)有意见。如果使用它时没有选项,它将返回一个图像。但是当我使用 .decodeStream(inputStream, null, options)中的选项时,它永远不会返回位图。

我试图做的是在实际加载一个 Bitmap 以节省内存之前减少它的采样。 我读过一些不错的指南,但没有一本是使用 .decodeStream的。

没问题

URL url = new URL(sUrl);
HttpURLConnection connection  = (HttpURLConnection) url.openConnection();


InputStream is = connection.getInputStream();
Bitmap img = BitmapFactory.decodeStream(is, null, options);

没用的

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);
73073 次浏览

I think the problem is with the "calculate-scale-factor" logic because rest of the code looks correct to me (assuming of course that inputstream is not null).

It would be better if you can factor out all the size calculation logic from this routine into a method(call it calculateScaleFactor() or whatever) and test that method independently first.

Something like:

// 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);

and test getScaleFactor(...) independently.

It will also help to surround the entire code with try..catch{} block, if not done already.

The problem was that once you've used an InputStream from a HttpUrlConnection to fetch image metadata, you can't rewind and use the same InputStream again.

Therefore you have to create a new InputStream for the actual sampling of the image.

  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();

Try wrap InputStream with BufferedInputStream.

InputStream is = new BufferedInputStream(conn.getInputStream());
is.mark(is.available());
// Do the bound decoding
// inJustDecodeBounds =true
is.reset();
// Do the actual decoding

You can convert the InputStream to a byte array, and use the decodeByteArray(). For example,

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;
}