I'm having issues with BitmapFactory.decodeStream(inputStream)
. When using it without options, it will return an image. But when I use it with options as in .decodeStream(inputStream, null, options)
it never returns Bitmaps.
What I'm trying to do is to downsample a Bitmap before I actually load it to save memory.
I've read some good guides, but none using .decodeStream
.
Handling large Bitmaps
And here
Image Processing in Android
WORKS JUST FINE
URL url = new URL(sUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
InputStream is = connection.getInputStream();
Bitmap img = BitmapFactory.decodeStream(is, null, options);
DOESN'T WORK
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);
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
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.
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;
}
精彩评论