如何获取位图信息,然后从 internet-inputStream 解码位图? [英] how to get bitmap information and then decode bitmap from internet-inputStream?

查看:22
本文介绍了如何获取位图信息,然后从 internet-inputStream 解码位图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个来自某个图像文件的互联网的 inputStream.

suppose i have an inputStream that was originated from the internet of a certain image file.

我希望获得有关图像文件的信息,然后才能对其进行解码.

i wish to get information about the image file and only then to decode it.

它有多种用途,例如下采样以及在显示图像之前预览信息.

it's useful for multiple purposes, such as downsampling and also previewing of information before the image is shown.

我尝试通过用 BufferedInputStream 包装 inputStream 来标记和重置 inputStream,但没有奏效:

i've tried to mark&reset the inputStream by wrapping the inputStream with a BufferedInputStream , but it didn't work:

inputStream=new BufferedInputStream(inputStream);
inputStream.mark(Integer.MAX_VALUE);
final BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeStream(inputStream,null,options);
//this works fine. i get the options filled just right.

inputStream.reset();
final Bitmap bitmap=BitmapFactory.decodeStream(inputStream,null,options);
//this returns null

为了从 url 中获取 inputStream,我使用:

for getting the inputStream out of a url, i use:

public static InputStream getInputStreamFromInternet(final String urlString)
  {
  try
    {
    final URL url=new URL(urlString);
    final HttpURLConnection urlConnection=(HttpURLConnection)url.openConnection();
    final InputStream in=urlConnection.getInputStream();
    return in;
    }
  catch(final Exception e)
    {
    e.printStackTrace();
    }
  return null;
  }

问题

如何让代码处理标记重置?

the question

how can i make the code handle the marking an resetting ?

它与资源完美配合(实际上我什至不必为此创建一个新的 BufferedInputStream 即可)但不适用于来自互联网的 inputStream...

it works perfectly with resources (in fact i didn't even have to create a new BufferedInputStream for this to work) but not with inputStream from the internet...

看来我的代码很好,有点......

it seems my code is just fine, sort of...

在某些网站上(例如这个这个),重置后也无法解码图像文件.

on some websites (like this one and this one), it fails to decode the image file even after reseting.

如果你解码位图(并使用 inSampleSize),它可以很好地解码(只是需要很长时间).

if you decode the bitmap (and use inSampleSize) , it can decode it fine (just takes a long time).

现在的问题是它为什么会发生,我该如何解决.

now the question is why it happens, and how can i fix it.

推荐答案

(这里是同样问题的解决方案,但是从磁盘读取时.我一开始没有意识到您的问题是专门来自网络流.)

mark & 的问题这里的重置一般是 BitmapFactory.decodeStream() 有时 重置您的标记.因此,为了进行实际读取而进行的重置被破坏了.

The problem with mark & reset in general here is that BitmapFactory.decodeStream() sometimes resets your marks. Thus resetting in order to do the actual read is broken.

但是 BufferedInputStream 存在第二个问题:它可能导致整个图像在您实际读入的位置旁边的内存中进行缓冲.根据您的用例,这真的会降低您的性能.(大量分配意味着大量 GC)

But there is a second problem with BufferedInputStream: it can cause the entire image to be buffered in memory along side of where ever you are actually reading it into. Depending on your use case, this can really kill your performance. (Lots of allocation means lots of GC)

这里有一个非常好的解决方案:https://stackoverflow.com/a/18665678/1366

There is a really great solution here: https://stackoverflow.com/a/18665678/1366

我针对这个特定用例稍微修改了它以解决标记&重置问题:

I modified it slightly for this particular use case to solve the mark & reset problem:

public class MarkableFileInputStream extends FilterInputStream
{
    private static final String TAG = MarkableFileInputStream.class.getSimpleName();

    private FileChannel m_fileChannel;
    private long m_mark = -1;

    public MarkableFileInputStream( FileInputStream fis )
    {
        super( fis );
        m_fileChannel = fis.getChannel();
    }

    @Override
    public boolean markSupported()
    {
        return true;
    }

    @Override
    public synchronized void mark( int readlimit )
    {
        try
        {
            m_mark = m_fileChannel.position();
        }
        catch( IOException ex )
        {
            Log.d( TAG, "Mark failed" );
            m_mark = -1;
        }
    }

    @Override
    public synchronized void reset() throws IOException
    {
        // Reset to beginning if mark has not been called or was reset
        // This is a little bit of custom functionality to solve problems
        // specific to Android's Bitmap decoding, and is slightly non-standard behavior
        if( m_mark == -1 )
        {
            m_fileChannel.position( 0 );
        }
        else
        {
            m_fileChannel.position( m_mark );
            m_mark = -1;
        }
    }
}

这不会在读取过程中分配任何额外的内存,即使标记已清除也可以重置.

This won't allocate any extra memory during reads, and can be reset even if the marks have been cleared.

这篇关于如何获取位图信息,然后从 internet-inputStream 解码位图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆