Java 设置选项时 BitmapFactory.decodeStream 返回 null

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2503628/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 08:33:25  来源:igfitidea点击:

BitmapFactory.decodeStream returning null when options are set

javaandroidimagebitmap

提问by Robert Foss

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.

我有问题BitmapFactory.decodeStream(inputStream)。在没有选项的情况下使用它时,它将返回一个图像。但是当我将它与选项一起使用时,.decodeStream(inputStream, null, options)它永远不会返回位图。

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.

我要做的是在实际加载位图之前对其进行下采样以节省内存。我读过一些很好的指南,但没有使用.decodeStream.

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

采纳答案by Robert Foss

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.

问题是,一旦您使用 HttpUrlConnection 中的 InputStream 来获取图像元数据,就无法倒带并再次使用相同的 InputStream。

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

因此,您必须为图像的实际采样创建一个新的 InputStream。

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

回答by Samuh

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).

我认为问题出在“计算比例因子”逻辑上,因为其余代码在我看来是正确的(当然假设 inputstream 不为空)。

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.

如果您可以将此例程中的所有大小计算逻辑分解为一个方法(称为calculateScaleFactor() 或其他)并首先独立测试该方法,那就更好了。

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.

并独立测试 getScaleFactor(...)。

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

如果还没有完成,它也将有助于用 try..catch{} 块包围整个代码。

回答by Jett Hsieh

Try wrap InputStream with BufferedInputStream.

尝试用 BufferedInputStream 包装 InputStream。

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

回答by Jimmy Sun

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

您可以将 InputStream 转换为字节数组,并使用 decodeByteArray()。例如,

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