Проигрывание GIF в KMP Desktop

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Я — Денис, Middle Android-разработчик в «Black Bricks». Недавно в нашем KMP проекте возникла необходимость добавить рекламный баннер с GIF. В этой статье я расскажу, с какими трудностями мы столкнулись и как удалось реализовать этот функционал.

Исходно, стандартных решений для корректного воспроизведения GIF в Jetpack Compose мы не нашли. Основная сложность заключалась в том, что решение должно было работать одинаково стабильно как на Windows, так и на macOS. Сперва остановились на этом решении. Но уже на первых тестах стало понятно, что GIF больше 4 мегабайт эта реализация не тянет. Загрузка ЦП была под 80%.

Ещё немного пошерстив интернет, наткнулись на реализацию с загрузкой GIF из сети. Нам в целом было не принципиально откуда грузить. Но из-за специфики расположения баннера, и требований отобразить его как можно быстрее, хотелось всё же захардкодить его в сам проект.

Мы немного модифицировали решение для проигрывания из локальных ресурсов. Но так как в реализации используется библиотека javax.imageio.ImageIO, то нормально она под Windows не завелась. Долго разбираться не стали, тем более этот вариант немного лагал.

По итогу пришли к такому:

@Composable
fun GifImage() {
    val codec = remember {
        val path = "desktopApp/src/main/resources/images/sample.gif"
        val file = File(path)
        val bytes = file.readBytes()
        Codec.makeFromData(Data.makeFromBytes(bytes))
    }

    AnimatedGif(
        modifier = Modifier
            .fillMaxHeight()
            .aspectRatio(ratio = 1.5f, matchHeightConstraintsFirst = true),
        codec = codec,
    )
}

@Composable
fun AnimatedGif(codec: Codec, modifier: Modifier) {
    val transition = rememberInfiniteTransition()
    val frameIndex by transition.animateValue(
        initialValue = 0,
        targetValue = codec.frameCount - 1,
        typeConverter = Int.VectorConverter,
        animationSpec = infiniteRepeatable(
            animation = keyframes {
                durationMillis = 0
                for ((index, frame) in codec.framesInfo.withIndex()) {
                    index at durationMillis
                    durationMillis += frame.duration
                }
            }
        )
    )

    val bitmap = remember { Bitmap().apply { allocPixels(codec.imageInfo) } }
    Canvas(modifier) {
        codec.readPixels(bitmap, frameIndex)
        val imageBitmap = bitmap.asComposeImageBitmap()
        drawImage(
            image = imageBitmap,
            dstSize = IntSize(size.width.toInt(), size.height.toInt())
        )
    }
}

Эта реализация неплохо работает с GIF до 12 мегабайт, и без лагов при скролле списков.

Спасибо за чтение!

Денис Попков

Middle Android разработчик в «Black Bricks»

Если вы нашли неточности/ошибки в статье или просто хотите дополнить её своим мнением — то прошу в комментарии! Или можете написать мне в Telegram.

Источник: https://habr.com/ru/articles/841634/


Интересные статьи

Интересные статьи

Компания Orion soft успешно провела серию испытаний на совместимость собственной системы терминального доступа Termit и продукта компании «РуПост» (входит в «Группу Астра») — почтового клиента RuPost ...
  Идея моего домашнего проекта началась с простой, на первый взгляд, задачи: с потребности конвертировать файлы формата XML в формат XLS (или CSV) для последующего анализа. И я был наиве...
Всем привет! Недавно публиковал статью о создании браузерного расширения для скачивания любого видео загруженного во ВКонтакте в любом из доступных качеств.На тот момент всё ограничилось возможностью ...
О чем вы узнаете из статьи? Что такое Electron Возможности и ограничения при разработке Как работать с Electron Плюсы и минусы Известные проблемы Вывод Electron — это библиотека,...
Хочу поделиться несколькими советами по настройке удаленного подключения к рабочим местам по RDP. Расскажу как проапгрейдить древний RPC-HTTP до UDP, похвалю и поругаю Windows 10 и AVC, разберу ...