BitmapFactory.decodeStream 总是返回 null,skia 解码器显示解码返回 false

Posted

技术标签:

【中文标题】BitmapFactory.decodeStream 总是返回 null,skia 解码器显示解码返回 false【英文标题】:BitmapFactory.decodeStream always returns null and skia decoder shows decode returned false 【发布时间】:2010-09-27 10:11:51 【问题描述】:

在这里测试图像: http://images.plurk.com/tn_4134189_bf54fe8e270ce41240d534b5133884ee.gif

我尝试了几种在互联网上找到的解决方案,但没有有效的解决方案。

我正在使用以下 sn-p 代码:

Url imageUrl = new Url("http://images.plurk.com/tn_4134189_bf54fe8e270ce41240d534b5133884ee.gif");
Bitmap image = BitmapFactory.decodeStream(imageUrl.openStream());

总是得到这个日志:

DEBUG/skia(1441): --- decoder->decode returned false

有什么帮助吗? 谢谢。

编辑:

那些解码失败的图片也不能在WebView上显示。但可以查看是否在浏览器中打开。

【问题讨论】:

【参考方案1】:

试试这个作为临时解决方法:

首先添加以下类:

  public static class PlurkInputStream extends FilterInputStream 

    protected PlurkInputStream(InputStream in) 
        super(in);
    

    @Override
    public int read(byte[] buffer, int offset, int count)
        throws IOException 
        int ret = super.read(buffer, offset, count);
        for ( int i = 2; i < buffer.length; i++ ) 
            if ( buffer[i - 2] == 0x2c && buffer[i - 1] == 0x05
                && buffer[i] == 0 ) 
                buffer[i - 1] = 0;
            
        
        return ret;
    


然后用 PlurkInputStream 包装你的原始流:

Bitmap bitmap = BitmapFactory.decodeStream(new PlurkInputStream(originalInputStream));

如果这对你有帮助,请告诉我。

编辑:

抱歉,请尝试以下版本:

        for ( int i = 6; i < buffer.length - 4; i++ ) 
            if ( buffer[i] == 0x2c ) 
                if ( buffer[i + 2] == 0 && buffer[i + 1] > 0
                    && buffer[i + 1] <= 48 ) 
                    buffer[i + 1] = 0;
                
                if ( buffer[i + 4] == 0 && buffer[i + 3] > 0
                    && buffer[i + 3] <= 48 ) 
                    buffer[i + 3] = 0;
                
            
        

请注意,这不是有效的代码,也不是完整/正确的解决方案。它适用于大多数情况,但不是全部。

【讨论】:

感谢您的帮助,但仍然得到相同的结果。 10-28 18:36:03.970:调试/skia(14676):---解码器->解码返回假10-28 18:36:03.970:错误:图像为空。 images.plurk.com/… 我很好奇你为什么要重写这个方法? android skia 解码器对 gif 尺寸进行所谓的 TopLeft 检查,并且不处理超出画布边界的图像。通过覆盖 read 方法,我们将相对于画布的绘图偏移替换为零,并欺骗skia解码器接受gif文件以进行进一步解码。您可以查看适用于 Android 的 skia 源代码,并根据 GIF89a 规范对图像进行 bvi 检查。 顺便说一句,您可能需要确保仅对来自 images.plurk.com 的图像使用 PlurkInputStream 包装器。 @Wu-Man,“顺便说一句,您可能希望确保仅对来自 images.plurk.com 的图像使用 PlurkInputStream 包装器”是什么意思。什么是“完整/正确的解决方案”版本?【参考方案2】:

我有同样的问题,部分被这个类解决了:

static class FlushedInputStream extends FilterInputStream 
public FlushedInputStream(InputStream inputStream) 
    super(inputStream);


@Override
public long skip(long n) throws IOException 
    long totalBytesSkipped = 0L;
    while (totalBytesSkipped < n) 
        long bytesSkipped = in.skip(n - totalBytesSkipped);
        if (bytesSkipped == 0L) 
              int byte = read();
              if (byte < 0) 
                  break;  // we reached EOF
               else 
                  bytesSkipped = 1; // we read one byte
              
       
        totalBytesSkipped += bytesSkipped;
    
    return totalBytesSkipped;

还有:

InputStream in = null;
    try 
        in = new java.net.URL(imageUrl).openStream();
         catch (MalformedURLException e) 
        e.printStackTrace();
         catch (IOException e) 
        e.printStackTrace();
        
Bitmap image = BitmapFactory.decodeStream(new FlushedInputStream(in));

它在大多数情况下都有帮助,但这不是通用的解决方案。 更多信息请参考bugreport。

祝你好运!

【讨论】:

【参考方案3】:

我尝试了所有解决方案,但没有解决我的问题。经过一些测试,当互联网连接不稳定时,skia解码器失败的问题发生了很多。对我来说,强制重新下载图像解决了这个问题。

当图片尺寸较大时,问题也更加突出。

使用循环最多需要我重试 2 次,并且图像将被正确下载。

Bitmap bmp = null;
int retries = 0;
while(bmp == null)
    if (retries == 2)
        break;
    
    bmp = GetBmpFromURL(String imageURL);
    Log.d(TAG,"Retry...");
    retries++;

【讨论】:

【参考方案4】:

这应该可行:

URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
connection.disconnect();
input.close();

myBitmap 包含您的图像。

【讨论】:

谢谢,但还是不行。它总是返回 null。另一张测试图:images.plurk.com/…【参考方案5】:

这是由于 Android 中 InputStream 类中的错误造成的。 您可以在 http://code.google.com/p/android/issues/detail?id=6066 处找到有效的解决方法和错误描述

【讨论】:

【参考方案6】:

出于内存原因,您必须像这样实现 BitmapFactory 选项:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4; // might try 8 also

主要的下载位图功能可能是这样的:

Bitmap downloadBitmap(String url) 

    final HttpClient client = AndroidHttpClient.newInstance("Android");
    final HttpGet getRequest = new HttpGet(url);

    try 
        HttpResponse response = client.execute(getRequest);
        final int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode != HttpStatus.SC_OK) 
            if(DEBUG)Log.w("ImageDownloader", "Error " + statusCode +
                    " while retrieving bitmap from " + url);
            return null;
        

        final HttpEntity entity = response.getEntity();
        if (entity != null) 
            InputStream inputStream = null;
            try 

                inputStream = entity.getContent();
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = 4; // might try 8 also
                return BitmapFactory.decodeStream(new FlushedInputStream(inputStream),null,options);

             finally 
                if (inputStream != null) 
                    inputStream.close();
                
                entity.consumeContent();
            
        
     catch (IOException e) 
        getRequest.abort();
        if(DEBUG)Log.w(TAG, "I/O error while retrieving bitmap from " + url, e);
     catch (IllegalStateException e) 
        getRequest.abort();
        if(DEBUG)Log.w(TAG, "Incorrect URL: " + url);
     catch (Exception e) 
        getRequest.abort();
        if(DEBUG)Log.w(TAG, "Error while retrieving bitmap from " + url, e);
     finally 
        if ((client instanceof AndroidHttpClient)) 
            ((AndroidHttpClient) client).close();
        
    
    return null;

也许你必须像这样实现 AsyncTask: http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html

【讨论】:

【参考方案7】:

对我来说,问题在于图像的颜色类型:您的图像是 color=CYMK 而不是 RGB

【讨论】:

【参考方案8】:

也许这不是您的情况,但如果您尝试使用 CMYK 颜色空间而不是 RGB 颜色空间解码图像,则可能是这种情况。 CMYK 图像,如this one,Android 不支持,即使在 Android 网络浏览器中也不会显示。阅读更多关于这个here:

Unable to load JPEG-image with BitmapFactory.decodeFile. Returns null

【讨论】:

【参考方案9】:

试试这个:

HttpGet httpRequest = new HttpGet(url);
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = (HttpResponse) httpclient.execute(httpRequest);
HttpEntity entity = response.getEntity();
BufferedHttpEntity bufferedHttpEntity = new BufferedHttpEntity(entity);
InputStream is = bufferedHttpEntity.getContent();
Drawable d = Drawable.createFromStream(is, "");
//or bitmap
//Bitmap b = BitmapFactory.decodeStream(is);

【讨论】:

以上是关于BitmapFactory.decodeStream 总是返回 null,skia 解码器显示解码返回 false的主要内容,如果未能解决你的问题,请参考以下文章