2

ここでの問題は実際の画像にあると100%確信しています。しかし、私は解決策が将来他の人を助ける画像の属性であることを願っています。

画像:

問題の写真http://soundwave.robotsidekick.com/mlsphotos.jpg

この画像をいくつかの方法で読み込んでみました。ImageView私はそれをダウンロードして、 :にロードしてみました

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

私はそれをURLからロードしようとしました:

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

ブラウザ(アプリ)に画像を読み込んでみましたが、うまくいきません。

これらはどれも機能しませんが、AndroidのChromeにURLをロードすると(ブラウザではなく)正常に機能します。デスクトップブラウザ(Chrome、Firefoxなど)に画像をロードすると、正常にロードされます。mimeタイプが拡張子と一致することを確認しましたが、途方に暮れています。

編集

InputStreamストリームが完了する前にビットマップ処理でストリーム上のデータが不足する場所からの画像には、回避策があります。回避策は、この質問このバグに記載されています。

ただし、これはデータが途中で終了する破損したイメージです。私はそれが私がすでに壊れた道を進んでいることを意味することを知っています、しかし私はAndroidが私を返すよりもいくつかのより良いエラー処理をしたいと思っていますnull、そして私は負けます。iOS、Chrome(デバイスとコンピューター上)、およびその他のほとんどの場所では、エラー処理がはるかに優れているようです。破損したjpgを処理するためにAndroidでできることはありますか?

編集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

Photoshop CS6でファイルを開いたところ、ファイルが破損しているか、切り捨てられているか、不完全である可能性があるとのことでした。ファイルを開くことができます。変更を加えずにPhotoshopで保存すると、Androidでも動作します。でも、画像のどこが悪いのか正確にはわかりません。

于 2012-10-01T16:10:15.117 に答える
2

これがウィキペディアのJPGに関する重要な部分であり、最終的に私を解決策に導いた質問です

ストリームが画像データで行われていることをデコーダーに納得させるために、画像バイトの最後の2つのjpeg末尾をストリームに追加しました。JPGにはJPGが含まれている可能性があるため、この方法には欠陥があります。つまり、画像の最後のバイトを1セット追加しても、すべての画像が閉じられるとは限りません。

is以下の両方のソリューションでは、JPG画像の入力ストリームであると想定しています。また、これら2つの定数が定義されています。

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

このメソッドは、最後の2バイトが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

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 に答える