Отобразить длинное растровое изображение

Мне нужно загрузить очень длинное (около 15 тыс. Пикселей) черно-белое растровое изображение с шириной экрана.

Я пробовал несколько подходов, и лучший вариант - использовать 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?

«Это было бы сложно реализовать» - используйте библиотеку, которая сделала это за вас, например Вот этот.

CommonsWare 05.01.2019 17:39

@CommonsWare Спасибо, попробую эту библиотеку

Angelina 05.01.2019 17:41

@CommonsWare Я использовал библиотеку - она ​​очень хорошо работает на многих устройствах, но не на всех. У меня проблема с Nexus 5 / Android 5.0, когда декодирование последней части растрового изображения не работает. Сообщение об ошибке следующее: E/SubsamplingScaleImageView: Failed to decode tile java.lang.RuntimeException: Skia image decoder returned null bitmap - image format may not be supported at com.davemorrissey.labs.subscaleview.decoder.SkiaImageRegionD‌​ecoder.decodeRegion(‌​SkiaImageRegionDecod‌​er.java:123)

Angelina 07.01.2019 17:51

Рассмотрите возможность публикации образца проекта и подачи отчета об ошибке автору библиотеки. Или посмотрите другие библиотеки, предлагающие масштабируемые изображения, например Вот этот. Или просто посмотрите, как они используют BitmapRegionDecoder, и создайте что-нибудь самостоятельно.

CommonsWare 07.01.2019 23:20

Помогло убрать альфа-канал из PNG

Angelina 08.01.2019 11:02
1
5
262
0

Другие вопросы по теме