Android:BitmapFactory.decodeByteArray 提供像素化位图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2183808/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android: BitmapFactory.decodeByteArray gives pixelated bitmap
提问by Michael Pedersen
I am working on an Android app that displays photos which are downloaded from Flickr. I obtain a bitmap object from a byte array, which in turn is read from the relevant Flickr URL, as follows:
我正在开发一个显示从 Flickr 下载的照片的 Android 应用程序。我从字节数组中获取位图对象,然后从相关的 Flickr URL 中读取该对象,如下所示:
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inDither = true;
opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opt);
I then draw the bitmap onto a canvas in the onDraw method of a View object:
然后我在 View 对象的 onDraw 方法中将位图绘制到画布上:
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
canvas.drawBitmap(bitmap, 0, 0, paint);
The problem is that the resulting picture is pixelated and I can't figure out why; I have tried a number of variations of the opt and paint objects with no luck. The difference between the picture displayed in my app and the picture at the original URL is roughly demonstrated by the following:
问题是生成的图片是像素化的,我不知道为什么;我尝试了许多 opt 和paint 对象的变体,但都没有成功。我的app中显示的图片和原始URL中的图片的区别大致如下:
Bad image, see pixelation in top left corner http://homepages.inf.ed.ac.uk/s0677975/bad.jpg
糟糕的图像,请参阅左上角的像素化 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
好图,这是预期的结果 http://homepages.inf.ed.ac.uk/s0677975/good.jpg
Look e.g. at the clouds in the top-left corner to see the difference.
例如,看看左上角的云,看看有什么不同。
Note that JPEG pictures which are loaded from the project resources and drawn in a similar way display just fine, i.e. have no pixelation.
请注意,从项目资源加载并以类似方式绘制的 JPEG 图片显示得很好,即没有像素化。
Can anybody give me a hint as to why this is happening?
任何人都可以给我一个关于为什么会发生这种情况的提示吗?
To elaborate a little, the byte array is obtained from Flickr as follows; this is based on code from the Photostream app by Romain Guy:
稍微详细说明一下,字节数组是从Flickr获取的,如下所示;这是基于 Romain Guy 的 Photostream 应用程序中的代码:
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: I also posted a variant of this question on the android.developer Google group.
PS:我还在 android.developer Google group 上发布了这个问题的一个变体。
Thanks a lot for your suggestion -- now I am really puzzled! I did as you suggested and found that the image resulting directly from the downloaded byte array is indeed pixelated. However, this is downloaded from exactly the same URL which, when accessed on my computer, is NOT pixelated. Here is the corresponding Flickr URL:
非常感谢您的建议——现在我真的很困惑!我按照你的建议做了,发现直接从下载的字节数组产生的图像确实是像素化的。但是,这是从完全相同的 URL 下载的,在我的计算机上访问时,该 URL 没有像素化。这是相应的 Flickr 网址:
http://farm3.static.flickr.com/2678/4315351421_54e8cdb8e5.jpg
http://farm3.static.flickr.com/2678/4315351421_54e8cdb8e5.jpg
Even stranger, when I run the same app in the simulator rather than on my phone (a HTC Hero), there is no pixelation.
更奇怪的是,当我在模拟器而不是手机(HTC Hero)上运行相同的应用程序时,没有像素化。
How on earth is this possible?
这到底怎么可能?
Below is the code I use for loading a bitmap from a URL -- it is based on the Photostream app by Romain Guy, and it incorporates Will's suggestion to write the raw byte array to file:
下面是我用于从 URL 加载位图的代码——它基于 Romain Guy 的 Photostream 应用程序,它结合了 Will 将原始字节数组写入文件的建议:
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);
}
}
}
Am I going crazy here? Best, Michael.
我会在这里发疯吗?最好的,迈克尔。
采纳答案by Will
Write the raw bytes fetched from the URL to /sdcard/tmp.jpg
, and view on your PC.
将从 URL 获取的原始字节写入/sdcard/tmp.jpg
,然后在您的 PC 上查看。
JPEG images are compressed in 8x8 (or 16x16) tiles. The 'pixelation' as you describe it is actually in these tiles, suggesting that the 'bad' image is a JPEG that is more aggressively compressed than the other.
JPEG 图像以 8x8(或 16x16)图块压缩。您描述的“像素化”实际上是在这些图块中,这表明“坏”图像是比其他图像压缩得更积极的 JPEG。
So I'd anticipate that the actual issue is that the image being downloaded is a very low-quality version, e.g. one intended for thumbnailing/preview use-cases.
所以我预计实际问题是正在下载的图像是一个非常低质量的版本,例如一个用于缩略图/预览用例的版本。
回答by Michael Pedersen
Ok, so I finally get it: it appears that my mobile network does image compression to save bandwidth.
好的,我终于明白了:看来我的移动网络会进行图像压缩以节省带宽。
Hence a picture downloaded from my phone is of lower quality than the same picture downloaded from my computer.
因此,从我的手机下载的图片质量低于从我的计算机下载的相同图片。
That's a bummer for my app, but I don't suppose there is anything I can do about it. Sigh.
这对我的应用程序来说太糟糕了,但我认为我对此无能为力。叹。
Thanks again for your input though!
再次感谢您的投入!
Best, Michael.
最好的,迈克尔。
回答by Anderson
Some version of Android have a bug in Bitmap class and convert the Bitmap to RGB_565 upon some operations. This would manifest itself in artifacts similar to those on your picture. This would also explain the banding of the blue sky. Also, have in mind that android attempts to "optimize" image by converting them to rgb_565 upon loading and even compiling in resource files. Take a look at: http://android.nakatome.net/2010/04/bitmap-basics.html
某些版本的 Android 在 Bitmap 类中存在错误,并且在某些操作时将 Bitmap 转换为 RGB_565。这将体现在与您图片上的相似的工件中。这也可以解释蓝天的条纹。另外,请记住,android 试图通过在加载甚至编译资源文件时将它们转换为 rgb_565 来“优化”图像。看看:http: //android.nakatome.net/2010/04/bitmap-basics.html