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

Java 设置选项时返回null的BitmapFactory.decodeStream,java,android,image,bitmap,Java,Android,Image,Bitmap,我在BitmapFactory.decodeStream(inputStream)方面遇到问题。如果在没有选项的情况下使用它,它将返回一个图像。但是当我将它与.decodeStream(inputStream,null,options)中的选项一起使用时,它永远不会返回位图 我想做的是在加载位图之前先对其进行降采样以节省内存。 我读过一些很好的指南,但没有一本是使用.decodeStream的 工作正常 URL url = new URL(sUrl); HttpURLConnectio

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

我想做的是在加载位图之前先对其进行降采样以节省内存。 我读过一些很好的指南,但没有一本是使用
.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);
InputStream is=connection.getInputStream();
位图img=BitmapFactory.decodeStream(is,null,options);
InputStream is=connection.getInputStream();
Options=new-BitmapFactory.Options();
options.inJustDecodeBounds=true;
解码流(is,null,options);
布尔scaleByHeight=Math.abs(options.outHeight-TARGET\u HEIGHT)>=Math.abs(options.outWidth-TARGET\u WIDTH);
如果(options.outHeight*options.outHeight*2>=200*100*2){

//加载,缩放到最小的2次方,这将得到它我认为问题在于“计算比例因子”逻辑,因为其余代码在我看来是正确的(当然假设inputstream不是null)

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

比如:

// 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);
并独立测试getScaleFactor(…)


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

问题是,一旦您使用了来自HttpUrlConnection的InputStream来获取图像元数据,就不能倒带并再次使用相同的InputStream

因此,您必须为图像的实际采样创建一个新的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();
Options=new-BitmapFactory.Options();
options.inJustDecodeBounds=true;
解码流(is,null,options);
布尔scaleByHeight=Math.abs(options.outHeight-TARGET\u HEIGHT)>=Math.abs(options.outWidth-TARGET\u WIDTH);
如果(options.outHeight*options.outHeight*2>=200*200*2){

//加载,缩放到最小的2次方,将得到它尝试使用BufferedInputStream包装InputStream

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

您可以将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;
}


System.out.println(“Samplesize:…)语句的输出是什么?表明options.inSampleSize是一个可接受的值?是的,它每次都返回一个可接受的值。由于正在调试,因此删除了该语句。感谢发布您的解决方案,但还有一件事要做。此问题仍然出现在“未解决的问题”列表,因为您没有将响应标记为“已接受”。您可以通过单击答案旁边的勾号图标来完成此操作。如果您觉得Samuh的答案有助于您找到解决方案,您可以接受它,或者您可以发布自己的答案并接受它。(通常情况下,您会将解决方案放在答案中,但由于您已经通过编辑问题将其包括在内,因此您可以将其引用到问题中。)感谢您帮助新用户融入社区:)非常感谢您的回答!我尝试设置一个最终的int值,如“options.inSampleSize=2”。但它会导致相同的问题。对于我尝试解码的每个图像,Logcat都会读取“SkImageDecoder::Factory返回null”。在try/catch块中运行代码对我没有帮助,因为它不会抛出任何东西,对吗?但是BitmapFactory.de如果码流不能创建img,它会返回null,这在我尝试使用sampleSize时是不能的。这很奇怪。你能尝试调整捆绑在你的资源中的位图的大小吗?比如打开一个资源文件并尝试解码。如果你能做到这一点,可能是远程流出现了一些问题,导致解码失败。BitmapFactory.decodeResource(this.getResources(),R.drawable.icon,选项)==null)可以很好地进行重新采样。第一个BitmapFactory.decodeStream with options.inJustDecodeBounds=true可以很好地工作并返回选项。但是下面的BitmapFactory.decodeStream with options.inJustDecodeBounds=false每次都失败。我恐怕无法理解这一点……我想知道可能会出现什么问题因为我使用的是类似的代码,对我来说效果很好。好的。我已经解决了。问题在于http连接。当您从HttpUrlConnection提供的输入流读取了一次后,您就不能再读取它了,必须重新连接才能执行第二个解码流()。这是否意味着图像必须下载两次?一次是为了获取大小,一次是为了获取像素数据?@Robert你可能应该解释一下这种特殊的行为,以便其他用户能够清楚地了解这一点。我想知道为什么它不能与相同的输入流一起工作,谢谢你的简短解释。贾斯汀,你不必重新创建它g重置它可以解决问题。请看我的回答。我不得不说Android的位图类很糟糕。它使用起来太令人困惑和沮丧了。它对你一直有效吗?出于某种原因,我在一些非常特殊的情况下使用这种方法得到空值。我在这里写了一篇关于它的帖子:它有效,所以我对它进行了升级,但它是可用的()doc附带警告,它应该只用于检查流是否为空,而不用于计算大小,因为这是不可靠的。向下投票,但所讨论的inputstream连接是HTTP连接,reset()将不起作用。。。。