2

我 100% 确定这里的问题出在实际图像上。但是我希望解决方案是图像的某些属性,它将在未来帮助其他人。

图片:

有问题的照片 http://soundwave.robotsidekick.com/mlsphotos.jpg

我尝试以多种方式加载此图像。我已经下载并尝试将其加载到ImageView

    final ImageView v = (ImageView) findViewById(R.id.image);
    v.setImageResource(R.drawable.photo);
    v.invalidate();

我试过从一个网址加载它:

    final String[] params = new String[] {
            "",
    };

    (new AsyncTask<String, Bitmap, Bitmap>()
            {
        @Override
        protected Bitmap doInBackground(final String... params)
        {
            Bitmap ret = null;
            for (final String url : params)
            {
                try
                {
                    Log.e(TAG, url);
                    ret = BitmapFactory.decodeStream((new URL(url)).openStream());
                    publishProgress(ret);
                }
                catch (final MalformedURLException e)
                {
                    Log.e(TAG, "Malformed URL", e);
                }
                catch (final IOException e)
                {
                    Log.e(TAG, "IO Exception", e);
                }
            }
            return ret;
        }

        @Override
        protected void onProgressUpdate(final Bitmap... values)
        {
            super.onProgressUpdate(values);

            for (final Bitmap result : values)
            {
                if (result != null)
                {
                    final ImageView v = (ImageView) MainActivity.this.findViewById(R.id.image);
                    v.setImageBitmap(result);
                    v.invalidate();
                }
            }
        }
    }).execute(params);

我也尝试过WebView像这样加载图像:

    final WebView webview = (WebView) findViewById(R.id.webview);
    webview.loadData("<html><body><img src=\"" + url + "\"></body></html>", "text/html", "utf-8");
    webview.invalidate();

我也尝试在浏览器(应用程序)中加载图像,但这不起作用。

这些都不起作用,但是如果我将 url 加载到 Android 上的 Chrome 中,它会很好用(不是在浏览器中),如果我在桌面浏览器(Chrome、Firefox 等)上加载图像,它会很好地加载。我已经检查了 mime 类型是否与扩展名匹配,但我很茫然。

编辑

对于来自InputStream位图处理在流完成之前用完流上的数据的图像,有一种解决方法。解决方法记录在这个问题这个错误中。

然而,这是一个损坏的图像,其数据过早结束。我知道这意味着我已经走下坡路了,但我希望能有更好的错误处理,而不是 Android 把我传回去null,我输了。iOS、Chrome(在设备和计算机上)以及大多数其他地方似乎有更好的错误处理。我可以在 Android 上做些什么来处理损坏的 jpg 文件吗?

编辑 2

这里必须有一个解决方案,因为我设备上的 Chrome 可以优雅地处理这种情况。然而,我能解决这个问题的最接近的是以下代码:

final InputStream is = (new URL(url)).openStream();
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final int size = 1024;
int len = -1;
byte[] buf = new byte[size];
while ((len = is.read(buf, 0, size)) != -1)
{
    bos.write(buf, 0, len);
}
buf = bos.toByteArray();

// buf is now filled with the corrupted bytes of the image

ret = BitmapFactory.decodeByteArray(buf, 0, buf.length);

// ret is null because it was a corrupt jpg

使用该代码,我可以检查是否有字节并且图像没有被解码。然后至少我可以告诉我有一个损坏的图像(或不是图像),并且可以向用户报告一些对用户更有用的东西(嘿,我这里有一个 16K 的图像,但我肯定不知道如何处理它) .

任何人都知道 Chrome 如何在损坏之前设法解码尽可能多的图像?

4

3 回答 3

2

这是来自 Wikipedia 的关于 JPG的重要信息,这是一个最终导致我找到解决方案的问题

我只是将图像字节的两个结束 jpeg 结尾附加到流中,以使解码器相信流是使用图像数据完成的。这种方法是有缺陷的,因为 JPG 可以在其中包含 JPG,这意味着附加一组图像结尾字节,并不能保证我们关闭了所有图像。

在下面的两个解决方案中,我假设is是 JPG 图像的输入流。还定义了这两个常量:

private static final int JPEG_EOI_1 = 0xFF;
private static final int JPEG_EOI_2 = 0xD9;

这种方法我们将所有字节读入内存然后尝试解码字节:

final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final int size = 1024;
int len = -1;
final byte[] buf = new byte[size];
try
{
    while ((len = is.read(buf, 0, size)) != -1)
    {
        bos.write(buf, 0, len);
    }
    bos.write(JPEG_EOI_1);
    bos.write(JPEG_EOI_2);

    final byte[] bytes = bos.toByteArray();

    return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
catch (final IOException ex)
{
    return null;
}
catch (final Exception ex)
{
    return null;
}

此方法创建一个流包装器,确保最后两个字节是图像字节的 JPG 结尾:

return BitmapFactory.decodeStream(new JpegClosedInputStream(is));

// And here's the stream wrapper
class JpegClosedInputStream extends InputStream
{
    private final InputStream inputStream;
    private int bytesPastEnd;

    private JpegClosedInputStream(final InputStream iInputStream)
    {
        inputStream = iInputStream;
        bytesPastEnd = 0;
    }

    @Override
    public int read() throws IOException
    {
        int buffer = inputStream.read();
        if (buffer == -1)
        {
            if (bytesPastEnd > 0)
            {
                buffer = JPEG_EOI_2;
            }
            else
            {
                ++bytesPastEnd;
                buffer = JPEG_EOI_1;
            }
        }

        return buffer;
    }
}
于 2012-10-03T14:30:40.170 回答
2

我在 Photoshop CS6 中打开文件,它说文件可能已损坏、可能被截断或不完整。该文件可以打开。如果我将它保存在 Photoshop 中而不做任何更改,它就可以在 Android 中使用。恐怕我不知道图像到底出了什么问题。

于 2012-10-01T16:10:15.117 回答
-2

做 setcontentview 并像这样从 xml 显示它:

//photo.xml
  <ImageView
        android:id="@+id/picture"
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:layout_gravity="center"
        android:src="@drawable/photo" />
/>
//Photo.java
setContentView(R.layout.photo);
于 2012-10-01T16:06:35.223 回答