我需要加载一个非常长的(约15K px)黑白位图,该位图具有屏幕宽度。
我尝试了几种方法,最好的方法似乎是使用Glide
:
private fun loadGlideScreenWideCompress(context: Context, imageView: AppCompatImageView) {
imageView.adjustViewBounds = true
val params = LayoutParams(MATCH_PARENT, WRAP_CONTENT)
imageView.layoutParams = params
GlideApp.with(context)
.load(imageRes)
.encodeFormat(Bitmap.CompressFormat.WEBP)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imageView)
}
问题是-图像质量丢失。图片模糊不清,文字不可读。
我尝试使用BitmapRegionDecoder
。我没有看到质量损失或内存问题。但是,它仅解码图像的一部分。我不太了解如何使用它:在滚动事件下解码下一部分?这将很难实现。测量可绘制高度,并将完整高度传递到BitmapRegionDecoder
上,直觉感觉是错误的,因为这是解码器仅用于区域。
另一个问题是图像很大,我需要它适合所有屏幕尺寸。如果我采用最大可能的大小然后进行缩放,则需要执行昂贵的位图创建操作并潜在地阻塞主线程。
常规方法不起作用,并给出OOM例外:
val bitmap = BitmapFactory.Options().run {
inJustDecodeBounds = true
inPreferredConfig = Bitmap.Config.ALPHA_8
inDensity = displayMetrics.densityDpi
BitmapFactory.decodeResource(context.resources, imageRes, this)
}
imageView.scaleType = ImageView.ScaleType.FIT_CENTER
imageView.setImageBitmap(bitmap)
代码按比例缩小:
val res = context.resources
val display = res.displayMetrics
val dr = res.getDrawable(imageRes!!)
val original = (dr as BitmapDrawable).bitmap
val scale = original.width / display.widthPixels
val scaledBitmap = BitmapDrawable(res, Bitmap.createScaledBitmap(
original,
display.widthPixels,
original.height / scale,
true
))
imageView.adjustViewBounds = true
val bos = ByteArrayOutputStream()
scaledBitmap.bitmap.compress(CompressFormat.WEBP, 100, bos)
val decoder = BitmapRegionDecoder.newInstance(
ByteArrayInputStream(bos.toByteArray()),
false
)
val rect = Rect(
0,
0,
scaledBitmap.intrinsicWidth,
scaledBitmap.intrinsicHeight
)
val bitmapFactoryOptions = BitmapFactory.Options()
bitmapFactoryOptions.inPreferredConfig = Bitmap.Config.ALPHA_8;
bitmapFactoryOptions.inDensity = display.densityDpi;
val bmp = decoder.decodeRegion(rect, bitmapFactoryOptions);
imageView.setImageBitmap(bmp)
问题是:在这种情况下最好的方法是什么?如何正确使用BitmapRegionDecoder
?