Показать длинное растровое изображение - PullRequest
0 голосов
/ 05 января 2019

Мне нужно загрузить очень длинное (около 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?

...