2

Google Example Pageを使用して、URL から画像をダウンロードしようとしています。BitmapFactory.decodeStream メソッドで InputStream を使用すると読みましたが、2 回使用することはできません。私はそれをやろうとしていますが、デコードされた画像で null を返すためうまくいきません。何ができるかわかりません。

これは私のコードです:

この部分は AsyncTask クラスの doInBackground メソッドにあります

Bitmap bitmapImage;
URL imageUrl = null;
try {
imageUrl = new URL(url[0]);

HttpGet httpRequest = null;
httpRequest = new HttpGet(imageUrl.toURI());

HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = (HttpResponse) httpclient.execute(httpRequest);

HttpEntity entity = response.getEntity();
BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity);
InputStream instream = bufHttpEntity.getContent();

    bitmapImage = CommonMethods.decodeSampledBitmapFromResource(instream, thumb_width, thumb_width);

instream.close();
return bitmapImage;

 } catch (URISyntaxException e) {
    e.printStackTrace();
    return null;
 } catch (MalformedURLException e) {
    e.printStackTrace();
    return null;
 } catch (IOException e) {
    e.printStackTrace();
    return null;
 }


 public static Bitmap decodeSampledBitmapFromResource(InputStream instream,
        int reqWidth, int reqHeight) throws IOException {

    //Copy instream for decode twice 
ByteArrayOutputStream out = new ByteArrayOutputStream();
    copy(instream,out);
    ByteArrayInputStream instream2 = new ByteArrayInputStream(out.toByteArray());

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(instream, null, options);
    instream2.close();

    options.inJustDecodeBounds = false;

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    return BitmapFactory.decodeStream(instream, null, options);
 }

 public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {

     // Raw height and width of image
     final int height = options.outHeight;
     final int width = options.outWidth;
     int inSampleSize = 1;

     if (height > reqHeight || width > reqWidth) {
         if (width > height) {
         inSampleSize = Math.round((float) height / (float) reqHeight);
     } else {
             inSampleSize = Math.round((float) width / (float) reqWidth);
     }
     }

     return inSampleSize;
}

//Copy instream method
public static void copy(InputStream input, OutputStream output) throws IOException{

     byte[] buffer = new byte[Constants.IO_BUFFER_SIZE];

 int n = 0;

 while (-1 != (n = input.read(buffer))) {

     output.write(buffer, 0, n);
 }
 }
4

5 に答える 5

6

BitmapFactory.decodeStream は null を返します。これは、入力ストリームが 2 回使用されているためです。コードは試していませんが、継ぎ目は問題ないか、間違っている可能性があります。とにかく、私はより良い解決策を持っています。BufferedInputStream を使用して inputStream をラップし、2 回目の読み取りの前に、最初に「リセット」を呼び出します。通常の inputStreams は「リセット」をサポートしていないことに注意してください。呼び出すことはできますが、何も起こりません。私のコード:

    public static Bitmap decodeSampledBitmapFromStream(InputStream inputStream,
                                                   int reqWidth, int reqHeight)
                             throws IOException {
    if (!widthHeightCheck(reqWidth, reqHeight)) 
        return BitmapFactory.decodeStream(inputStream);
    // First decode with inJustDecodeBounds=true to check dimensions
    if (!(inputStream instanceof BufferedInputStream)) {
        inputStream = new BufferedInputStream(inputStream);
    }
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    Rect rect = new Rect(-1, -1, -1, -1);
    BitmapFactory.decodeStream(inputStream, rect, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    inputStream.reset();
    return BitmapFactory.decodeStream(inputStream, rect, options);
}
于 2013-11-04T03:38:49.940 に答える
1

httpEntity から取得したストリームをカスタムの WrappedStream にラップすることで、これを実現できると思います。この WrappedStream は、元のストリームを読み取りながら、2 番目の入力ストリームをフィードします。(これは PipedStream で行われます)

このコードで画像サイズを取得した後:

options.inJustDecodeBounds = true;
WrappedStream wrappedStream = new WrappedStream(instream);
BitmapFactory.decodeStream(wrappedStream, null, options);

あなたは呼び出すことができます

InputStream reReadStream = wrappedStream.getReReadStream();
options.inJustDecodeBounds = false;
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

// Decode bitmap with inSampleSize set
return BitmapFactory.decodeStream(reReadStream, null, options);

最後に、WrappedStream の実装を次に示します (ラップされた inputStream へのすべての呼び出しを委任し、読み取られた (またはスキップされた) すべてのバイトを pipedOutputStream に書き込むだけです)。

import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

/** Simple class wrapping an InputStream and feeding a secondary InputStream
 *  to re-read the data that was originally available in the inputStream.
**/

public class WrappedStream extends InputStream {

private InputStream urlStream;
private PipedOutputStream pipedStream;

public WrappedStream(InputStream urlStream) {
    this.urlStream = urlStream;
    this.pipedStream = new PipedOutputStream();
}

/**
 * return a fresh InputStream to re-read the data
 */
public InputStream getReReadStream() throws IOException {
    return new PipedInputStream(pipedStream);
}
@Override
public int available() throws IOException {
    return urlStream.available();
}

@Override
public void close() throws IOException {
    urlStream.close();
}

@Override
public void mark(int readlimit) {
    urlStream.mark(readlimit);
}

@Override
public boolean markSupported() {
    return urlStream.markSupported();
}

@Override
public int read() throws IOException {
    int b = urlStream.read();
    pipedStream.write(b);
    return b;
}

@Override
public int read(byte[] buffer) throws IOException {
    int l = urlStream.read(buffer);
    pipedStream.write(buffer);
    return l;
}

@Override
public int read(byte[] buffer, int offset, int length) throws IOException {
    int l = urlStream.read(buffer, offset, length);
    pipedStream.write(buffer, offset, length);
    return l;
}

@Override
public void reset() throws IOException {
    urlStream.reset();
}

@Override
//bytes skipped must available on the re-read stream so we read and write them.
public long skip(long byteCount) throws IOException {
    long bytesToSkip = byteCount;
    long skippedBytes = 0;
//ugly trick required to not loosing bytes if we ever skip more than Integer.MAX_VALUE bytes
    while(bytesToSkip>Integer.MAX_VALUE){
        _skip(Integer.MAX_VALUE);
        bytesToSkip -=Integer.MAX_VALUE;
        skippedBytes +=Integer.MAX_VALUE;
    }
    byte[] b = new byte[(int)bytesToSkip];
    skippedBytes += read(b);
    return skippedBytes;
}

private int _skip(int byteCount) throws IOException {
    byte[] b = new byte[(int)byteCount];
    return read(b);
}
}

このコードはテストしていないことに注意してください。これは、問題を解決する方法についていくつかのアイデアを提供するためのものです。

別のポイント: このコードが巨大なビットマップを作成しない場合でも、スケーリングされたビットマップが構築されるまで、ストリーム全体がメモリに保持されます。

于 2012-12-06T13:02:43.557 に答える
0

これは、要件を満たすことができるより少ないコードでサーバーからビットマップをダウンロードする方法です

Bitmap downloadBitmap(String url)
        {
            Bitmap image = null;
            InputStream in = null;
            try
                {
                    in = new java.net.URL(url).openStream();
                    BitmapFactory.Options opts = new BitmapFactory.Options();
                    opts.inSampleSize = 2;
                    image = BitmapFactory.decodeStream(new FlushedInputStream(in),null,opts);
                    in.close();
                }
            catch (MalformedURLException e)
                {
                    e.printStackTrace();
                }
            catch (IOException e)
                {
                    e.printStackTrace();
                }
            return image;
        }

上記のコードでは、opts.inSampleSize = 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 byte1 = read();
                                    if (byte1 < 0)
                                        {
                                            break; // we reached EOF
                                        }
                                    else
                                        {
                                            bytesSkipped = 1; // we read one byte
                                        }
                                }
                            totalBytesSkipped += bytesSkipped;
                        }
                    return totalBytesSkipped;
                }
        }
于 2012-12-06T12:00:35.837 に答える
0

あなたのために働くコードを見つけました

final HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream inputStream = null;
                try {
                    inputStream = entity.getContent();
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    //options.inSampleSize = 2;
                    final Bitmap bitmap = BitmapFactory
                            .decodeStream(inputStream, null, options);
                    return bitmap;
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                    entity.consumeContent();
                }
            }

適切な変数を置き換えてください。画像をスケーリングしたい場合は、ビットマップを取得した後にスケーリングできます。

于 2012-12-06T12:01:23.093 に答える
0

以下のコードを使用して、画像をダウンロードして imageview に表示してください。

public class image extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Bitmap bitmap = DownloadImage("http://www.gophoto.it/view.php?i=http://1.bp.blogspot.com/-2LTvCCufBKc/T3L3KgcTj2I/AAAAAAAABbQ/Ki60e1LU9sE/s1600/Sachin%2BTendulkar.png");
        ImageView img = (ImageView) findViewById(R.id.img);
        img.setImageBitmap(bitmap);
    }

    private InputStream OpenHttpConnection(String urlString) throws IOException {
        InputStream in = null;
        int response = -1;

        URL url = new URL(urlString);
        URLConnection conn = url.openConnection();

        if (!(conn instanceof HttpURLConnection))
            throw new IOException("Not an HTTP connection");

        try {
            HttpURLConnection httpConn = (HttpURLConnection) conn;
            httpConn.setAllowUserInteraction(false);
            httpConn.setInstanceFollowRedirects(true);
            httpConn.setRequestMethod("GET");
            httpConn.connect();
            response = httpConn.getResponseCode();
            if (response == HttpURLConnection.HTTP_OK) {
                in = httpConn.getInputStream();
            }
        } catch (Exception ex) {
            throw new IOException("Error connecting");
        }
        return in;
    }

    private Bitmap DownloadImage(String URL) {
        Bitmap bitmap = null;
        InputStream in = null;
        try {
            in = OpenHttpConnection(URL);
            bitmap = BitmapFactory.decodeStream(in);
            in.close();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        return bitmap;
    }
}
于 2012-12-06T12:02:13.503 に答える