2010-02-02 33 views
12

Tôi đang làm việc trên một ứng dụng Android hiển thị ảnh được tải xuống từ Flickr. Tôi có được một đối tượng bitmap từ một mảng byte, mà lần lượt được đọc từ URL Flickr có liên quan, như sau:Android: BitmapFactory.decodeByteArray cung cấp bitmap pixelated

BitmapFactory.Options opt = new BitmapFactory.Options(); 
opt.inDither = true; 
opt.inPreferredConfig = Bitmap.Config.ARGB_8888; 
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opt); 

sau đó tôi rút ra những bitmap vào một canvas trong phương pháp OnDraw của một Xem đối tượng:

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); 
canvas.drawBitmap(bitmap, 0, 0, paint); 

Vấn đề là hình ảnh kết quả là pixelated và tôi không thể hiểu tại sao; Tôi đã thử một số biến thể của các đối tượng lựa chọn và vẽ mà không có may mắn. Sự khác biệt giữa các hình ảnh hiển thị trong ứng dụng của tôi và hình ảnh tại URL ban đầu được khoảng chứng minh bằng cách như sau:

Bad image, see pixelation in top left corner http://homepages.inf.ed.ac.uk/s0677975/bad.jpg

Good picture, this is the expected result http://homepages.inf.ed.ac.uk/s0677975/good.jpg

Nhìn ví dụ tại những đám mây ở góc trên bên trái để thấy sự khác biệt.

Lưu ý rằng ảnh JPEG được tải từ tài nguyên dự án và được vẽ theo cách tương tự hiển thị tốt, tức là không có pixelation.

Ai có thể cho tôi gợi ý là tại sao điều này xảy ra?

Để xây dựng một chút, mảng byte được lấy từ Flickr như sau; điều này dựa trên mã từ ứng dụng Photostream của Romain Guy:

InputStream in = new BufferedInputStream(url.openStream(), IO_BUFFER_SIZE); 
final ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); 
out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE); 
copy(in, out); 
out.flush(); 
final byte[] data = dataStream.toByteArray(); 

PS: Tôi cũng đã đăng một biến thể của câu hỏi này trên nhóm android.developer Google.


Cảm ơn rất nhiều vì đề xuất của bạn - bây giờ tôi thực sự bối rối! Tôi đã làm như bạn đề nghị và thấy rằng hình ảnh kết quả trực tiếp từ mảng byte tải xuống thực sự là pixelated. Tuy nhiên, điều này được tải xuống từ chính xác cùng một URL, khi được truy cập trên máy tính của tôi, KHÔNG được pixelated. Dưới đây là URL Flickr tương ứng:

http://farm3.static.flickr.com/2678/4315351421_54e8cdb8e5.jpg

Ngay cả người lạ, khi tôi chạy cùng một ứng dụng trong mô phỏng hơn là trên điện thoại của tôi (một HTC Hero), không có pixelation.

Làm thế nào trên trái đất này có thể?

Dưới đây là đoạn code tôi sử dụng cho tải một bitmap từ một URL - nó được dựa trên các ứng dụng Photostream Romain Guy, và nó kết hợp đề nghị Will viết mảng byte liệu sang file:

Bitmap loadPhotoBitmap(URL url) { 
    Bitmap bitmap = null; 
     InputStream in = null; 
     BufferedOutputStream out = null; 

     try { 

      FileOutputStream fos = new FileOutputStream("/sdcard/photo-tmp.jpg"); 
      BufferedOutputStream bfs = new BufferedOutputStream(fos); 

      in = new BufferedInputStream(url.openStream(), 
        IO_BUFFER_SIZE); 

      final ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); 
      out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE); 
      copy(in, out);      
      out.flush(); 
      final byte[] data = dataStream.toByteArray(); 

      bfs.write(data, 0, data.length); 
      bfs.flush(); 

      BitmapFactory.Options opt = new BitmapFactory.Options(); 
      bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opt); 

     } catch (IOException e) { 
      android.util.Log.e(LOG_TAG, "Could not load photo: " + this, e); 
     } finally { 
      closeStream(in); 
      closeStream(out) 
      closeStream(bfs); 
     } 

     return bitmap; 
    } 

private static void copy(InputStream in, OutputStream out) throws IOException { 
    byte[] b = new byte[IO_BUFFER_SIZE]; 
    int read; 
    while ((read = in.read(b)) != -1) { 
     out.write(b, 0, read); 
    } 
} 

private static void closeStream(Closeable stream) { 
    if (stream != null) { 
     try { 
      stream.close(); 
     } catch (IOException e) { 
      android.util.Log.e(LOG_TAG, "Could not close stream", e); 
     } 
    } 
} 

Tôi có phát điên ở đây không? Tốt nhất, Michael.

+0

Tôi lấy tự do nội tuyến hình ảnh, vì điều đó thường khiến câu hỏi đẹp hơn và dễ đọc hơn. – unwind

+1

Bạn đã bao giờ tìm cách giải quyết vấn đề này chưa? Tôi đã thử các đề xuất, nhưng không may mắn. Đó là siêu gây phiền nhiễu. – blork

+0

dưới dạng chú thích cuối trang, đừng quên rằng JPEG không mất dữ liệu trong môi trường Android. mặc dù nó được hỗ trợ nhưng nó không được khuyến khích sử dụng PNG. – user836725

Trả lời

3

Viết byte thô được tìm nạp từ URL đến /sdcard/tmp.jpg và xem trên PC của bạn.

Hình ảnh JPEG được nén ở dạng 8x8 (hoặc 16x16). 'Pixelation' như bạn mô tả nó thực sự nằm trong các ô này, cho thấy hình ảnh 'xấu' là một ảnh JPEG được nén mạnh hơn ảnh kia.

Vì vậy, tôi dự đoán rằng vấn đề thực tế là hình ảnh được tải xuống là phiên bản chất lượng rất thấp, ví dụ: một dự định cho các trường hợp sử dụng hình thu nhỏ/xem trước.

+0

Tôi nghi ngờ điều này quá, nhưng kích thước tập tin thực tế của hình ảnh "xấu" là khoảng 18% * lớn hơn * so với "tốt". Sự kì lạ. – unwind

+0

Điều đó chứng minh không có gì :) – Will

4

Ok, vì vậy cuối cùng tôi đã hiểu được: có vẻ như mạng di động của tôi thực hiện nén hình ảnh để tiết kiệm băng thông.

Do đó ảnh được tải xuống từ điện thoại của tôi có chất lượng thấp hơn so với cùng một hình ảnh được tải xuống từ máy tính của tôi.

Đó là ứng dụng của tôi, nhưng tôi không cho rằng có bất kỳ điều gì tôi có thể làm. Thở dài.

Cảm ơn bạn lần nữa vì đã nhập liệu!

Tốt nhất, Michael.

+0

nó cũng có thể được nhắc bởi tiêu đề http - facebook chính nó có thể cung cấp hình ảnh chất lượng thấp cho điện thoại di động. Chỉnh sửa tiêu đề trước khi gửi - về cơ bản, xóa tất cả! – Will

+1

Bạn có thể thử đặt tiêu đề http thành gzip Accept-Encoding. Không chắc chắn, nhưng nó có thể nó sẽ nhận được xung quanh nén hình ảnh mạng. Xem http://stackoverflow.com/questions/1573391/android-http-communication-should-use-accept-encoding-gzip –

+0

Bạn đã cố xác nhận điều này thông qua tải xuống hình ảnh trong trình duyệt chưa? Tôi có cùng một vấn đề nhưng nếu tôi mở hình ảnh trong trình duyệt web, tôi sẽ nhận được một hình ảnh chưa được ghép hình. Vì vậy, phải có một cách để có được hình ảnh chính xác. – Janusz

1

Một số phiên bản Android có lỗi trong lớp Bitmap và chuyển đổi Bitmap thành RGB_565 khi một số thao tác. Điều này sẽ thể hiện chính nó trong các hiện vật tương tự như trên hình ảnh của bạn. Điều này cũng sẽ giải thích dải của bầu trời xanh. Ngoài ra, hãy nhớ rằng android cố gắng "tối ưu hóa" hình ảnh bằng cách chuyển đổi chúng thành rgb_565 khi tải và thậm chí biên dịch trong các tệp tài nguyên. Hãy xem: http://android.nakatome.net/2010/04/bitmap-basics.html

Các vấn đề liên quan