- Blur image android studio
- Latest commit
- Git stats
- Files
- README.md
- About
- Topics
- Resources
- License
- Releases
- Sponsor this project
- Packages 0
- Contributors 4
- Languages
- Пишем эффективный blur на Android
- И так, зачем?
- Приступим
- Renderscript
- FastBlur
- Оптимизируем
- Динамический blur на Android
- Как получить bitmap с контентом под BlurView?
- Собственно, blur
- Когда перерисовывать blur?
- Производительность
- How to Blur Images Efficiently with Android’s RenderScript
- Moonshoot
- The Code to Blur Images
- Preview
- Get Notified on New Future Studio Content and Platform Updates
Blur image android studio
Blurry is an easy blur library for Android
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
Blurry is an easy blur library for Android .
How do I use it?
Overlay
Parent must be ViewGroup
Into
Blur Options
- Radius
- Down Sampling
- Color Filter
- Asynchronous Support
- Animation (Overlay Only)
Get a bitmap directly
Android 5.+ (API 21)
About
Blurry is an easy blur library for Android
Topics
Resources
License
Releases
Sponsor this project
Packages 0
Contributors 4
Languages
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Источник
Пишем эффективный blur на Android
Сегодня мы попытаемся разобраться с методами размытия (blur) доступными для Android разработчиков. Прочитав определенное число статей и постов на StackOverflow, можно сказать, что мнений и способов выполнить эту задачу достаточно много. Я попытаюсь собрать все это в кучу.
И так, зачем?
Все чаще и чаще можно заметить эффект размытия в приложениях появляющихся на просторах Google Play Store. Взять хотя бы замечательное приложение Muzei от +RomanNurik или тот же Yahoo Weather. Глядя на эти приложения можно заметить, что при умелом обращении размытием можно добиться очень впечатляющих результатов.
На написание данной статьи меня подтолкнула серия статей Blurring Images, поэтому первая часть статьи будет очень схожа. На самом деле я попытаюсь копнуть немного глубже.
Вот примерно то, чего мы будем пытаться добиться:
Приступим
Для начала хочу показать с чем мы работаем. Я создал 1 activity, внутри которой расположен ViewPager . ViewPager перелистывает фрагменты. Каждый фрагмент — отдельная реализация размытия.
Вот как выглядит мой main_layout.xml :
И вот как выглядит layout фрагмента (fragment_layout.xml):
Как видим, ничего военного — обычная картинка на весь экран с текстом посередине. Также можно заметить дополнительный LinearLayout — я буду его использовать для отображения всякой служебной информации.
Наша цель — размыть фон текста, тем самым подчеркнув его. Вот общий принцип того, как мы это будем делать:
- Из картинки вырезаем тот участок, который находится непосредственно за TextView
- Размываем
- Получившийся результат ставим как фон для TextView
Renderscript
Наверное, самым популярным ответом сегодня на вопрос «как быстро размыть картинку в Android» является Renderscript. Это очень мощный инструмент для работы с изображениями. Несмотря на его кажущуюся сложность, многие его части очень даже просты в использовании. К счастью, blur — это одна из подобных частей.
Давайте разберемся что же здесь происходит:
- При создании фрагмента — создается layout, добавляется TextView в мою «сервисную панель»(я ее буду использовать чтобы отображать скорость работы алгоритма) и запускается размытие
- Внутри applyBlur() я регистрирую onPreDrawListener . Делаю я это потому, что на момент вызова этой функции мои UI элементы еще не готовы, поэтому и размывать-то особо нечего. Поэтому мне надо дождаться момента когда мой layout будет измерян и готов к отрисовке. Этот колбэк будет вызван непосредственно перед отрисовкой первого фрейма
- Внутри onPreDraw() первым делом что я обычно делаю — это меняю возвращаемое значение на true. Дело в том, что IDE генерирует false по умолчанию, а это значит, что отрисовка первого фрейма будет пропущена. В данном случае меня интересует первый фрейм, поэтому ставим true.
- Далее убираем наш колбек — нас больше не интересуют onPreDraw события
- Теперь мне надо вытащить Bitmap из моей ImageView. Заставляю ее создать drawing cache и забираю его
- Ну и, собственно, размытие. Рассмотрим этот процесс подробнее
Сразу хочу отметить, что данный код имеет ряд недостатков, о которых следует обязательно помнить:
- Данный код не «переразмывает» при изменениях layout’a. По-хорошему необходимо зарегистрировать onGlobalLayoutListener и перезапускать алгоритм при получении этого события
- Размытие производится в главном потоке. Не пытайтесь делать это в своих приложениях — подобного рода операции надо «выгружать» в отдельный поток, чтобы не блокировать UI. AsyncTask или что-то подобное справятся с этой задачей
Вернемся к blur() :
- Создается пустой Bitmap, по размеру соответствующий нашему TextView — сюда мы скопируем кусок нашего фона
- Создаем Canvas, чтобы можно было в этот Bitmap рисовать
- Смещаем систему координат на позицию, на которой находится TextView
- Рисуем кусок фона
- На этом этапе у нас есть Bitmap, который содержит кусок фона, находящийся непосредственно за TextView
- Создаем Renderscript объект
- Копируем наш Bitmap в структуру, с которой работает Renderscript
- Создаем скрипт для размытия (ScriptIntrinsicBlur)
- Выставляем параметры размытия (в моем случае радиус 20) и запускаем скрипт
- Копируем результат обратно в наш Bitmap
- Отлично, у нас есть размытый Bitmap — устанавливаем его как фон для нашего TextView
Вот что получилось:
Как видим, результат довольно неплох на вид и занял у нас 57ms. Учитывая, что на отрисовку одного фрейма не должно уходить больше 16мс (
60fps), можно посчитать, что frame rate в нашем случае упадет до 17fps на период пока выполняется размытие. Я бы сказал, неприемлимо. Имеено поэтому необходимо сгрузить размытие в отдельный поток.
Хочу также заметить, что ScriptIntrinsicBlur доступен в API > 16. Безусловно, можно использовать renderscript support library, что позволит снизить необходимый уровень API.
Но, как нетрудно догадаться, на renderscript’e свет клином не сошелся, поэтому давайте рассмотрим одну из альтернатив.
FastBlur
На самом деле размытие — ничто иное как манипуляция с пикселями, поэтому что нам мешает самим этими самыми пикселями и поманипулировать? Благо, на просторах интернета доступно довольно большое кол-во реализаций всевозможных алгоритмов размытия, поэтому наша задача сводится к тому, чтобы выбрать наиболее оптимальный.
На всезнающем StackOverflow (а точнее тут), я наткнулся на неплохую реализацию алгоритма размытия.
Давайте посмотрим что из этого получилось. Весь код приводить не буду, потому что отличаться будет только функция blur():
И вот результат:
Как видим, по качеству сложно заметить разницу с renderscript. Но вот производительность оставляет желать лучшего — 147ms! И это далеко не самый медленный алгоритм! Боюсь даже пробовать размывать по Гауссу.
Оптимизируем
Давайте на секунду задумаемся что из себя представляет размытие. По своей сути размытие очень тесно связано с «потерей» пикселей (здесь хотел бы попросить сильно не ругаться знатоков математики и графики, потому что описываю больше основываясь на свое понимание проблемы, чем на конкретные факты 🙂 ). Что же еще может легко нам помочь «потерять» пиксели? Уменьшение картинки!
Что если мы уменьшим картинку сначала, размоем ее, а потом увеличим обратно?
И так, имеем 13ms renderscript и 2ms FastBlur. Довольно неплохо, учитывая, что качество размытия осталось сравнимо по качеству с предыдущими результатами.
Давайте взглянем на код. Я опишу только вариант с FastBlur, т.к. код для Renderscript будет аналогичен (ссылка на полную версию кода доступна в конце статьи):
- scaleFactor определяет насколько сильно будем уменьшать картинку. В моем случае уменьшать будем в 8 раз. Причем учитывая что львиную долю пикселей мы потеряем при уменьшении/увеличении картинки, можно смело уменьшать радиус размытия основного алгоритма. Путем научного тыка я уменьшил до 2х
- Создаем Bitmap. В этот раз он будет меньше — в данном случае в 8 раз.
- Заметим, что при отрисовке, я выставил флаг FILTER_BITMAP_FLAG , что позволит применить сглаживание при изменении размера картинки
- Как и прежде, применяем размытие, но теперь ко много меньшей картинке и с меньшим радиусом, что позволяет ускорить алгоритм
- Ставим эту маленькую картинку как фон для TextView — она автоматически будет увеличена.
Довольно интересно, что Renderscript отработал медленнее, чем FastBlur. Произошло это из-за того, что мы сэкономили время на копировании Bitmap в Allocation и обратно.
Как результат, мы получили довольно шустрый метод размытия картинок на Android
Источник
Динамический blur на Android
Информации о том как быстро размыть картинку на Android существует предостаточно.
Но можно ли сделать это настолько эффективно, чтобы без лагов перерисовывать размытый bitmap при любом изменении контента, как это реализовано в iOS?
Итак, что хотелось бы сделать:
- ViewGroup, которая сможет размывать контент, который находится под ней и отображать в качестве своего фона. Назовем ее BlurView
- Возможность добавлять в нее детей (любые View)
- Не зависеть от какой-либо конкретной реализации родительской ViewGroup
- Перерисовывать размытый фон, если контент под нашей View меняется
- Делать полный цикл размытия и отрисовки менее чем за 16ms
- Иметь возможность изменять стратегию размытия
В статье я постараюсь обратить внимание только на ключевые моменты, за деталями прошу сюда.
Как получить bitmap с контентом под BlurView?
Создадим Canvas, Bitmap для него, и скажем всей View-иерархии нарисоваться на этом канвасе.
Теперь в internalBitmap нарисованы все View, которые видны на экране.
Проблемы:
Если у вашего rootView нет заданного фона, нужно предварительно нарисовать на канвасе фон Activity, иначе он будет прозрачным на битмапе.
Хотелось бы рисовать только ту часть иерархии, которая нам нужна. То есть под нашей BlurView, с соответствующим размером.
Кроме того, было бы неплохо уменьшить Bitmap, на котором будет происходить отрисовка. Это ускорит отрисовку View иерархии, сам blur, а так же уменьшит потребление памяти.
Добавляем поле scaleFactor, желательно, чтобы этот коэффициент был степенью двойки.
Уменьшаем bitmap в 8 раз и настраиваем матрицу канваса так, чтобы корректно на нем рисовать, учитывая позицию, размер и scale factor:
Теперь при вызове rootView.draw(internalCanvas), мы будем иметь на internalBitmap уменьшенную копию всей View-иерархии. Выглядеть она будет страшно, но это меня не очень волнует, т.к. дальше я все равно буду ее размывать.
Проблемы:
rootView скажет всем своим детям нарисоваться на канвасе, в том числе и BlurView. Этого хотелось бы избежать, BlurView не должна размывать сама себя. Для этого можно переопределить метод draw(Canvas canvas) в BlurView и делать проверку на каком канвасе ее просят отрисоваться.
Если это системный канвас — разрешаем отрисовку, если это internalCanvas — запрещаем.
Собственно, blur
Я сделал интерфейс BlurAlgorithm и возможность настройки алгоритма.
Добавил 2 реализации, StackBlur (by Mario Klingemann) и RenderScriptBlur. Вариант с RenderScript выполняется на GPU.
Чтобы сэкономить память, я записываю результат в тот же bitmap, который мне пришел на вход. Это опционально.
Так же можно попробовать кэшировать outAllocation и переиспользовать его, если размер входного изображения не изменился.
Когда перерисовывать blur?
Есть несколько вариантов:
- Вручную делать апдейт, когда вы точно знаете, что контент изменился
- Завязаться на события скролла, если BlurView находится над скроллящимся контейнером
- Слушать вызовы draw() через ViewTreeObserver
Я выбрал 3 вариант, используя OnPreDrawListener. Стоит заметить, что его метод onPreDraw дергается каждый раз, когда любая View в иерархии рисует себя. Это, конечно, не идеал, т.к. придется перерисовывать BlurView на каждый чих, но зато это не требует никакого контроля со стороны программиста.
Проблемы:
onPreDraw будет так же вызван, когда будет происходить отрисовка всей иерархии на internalCanvas, а так же при отрисовке BlurView.
Чтобы избежать этой проблемы, я завел флаг isMeDrawingNow.
Вроде все очевидно, кроме одного момента. Ставить его в false нужно через handler, т.к. диспатч отрисовки происходит асинхронно через очередь событий UI потока. Поэтому нужно так же добавить этот таск в очередь событий, чтобы он выполнился именно в конце отрисовки.
Производительность
Много статистики я не насобирал, но на Nexus 4, Nexus 5 весь цикл отрисовки занимает 1-4мс на экранах из демо-проекта.
Galaxy nexus — около 10мс.
Sony Xperia Z3 compact почему-то справляется хуже — 8-16мс.
Тем не менее, производительностью я удовлетворен, FPS держится на хорошем уровне.
Источник
How to Blur Images Efficiently with Android’s RenderScript
Moonshoot
Moonshoot is a
Student Feature.
Update: We added the section Preview to visually demonstrate the capabilities.
Recently, we have demonstrated how to integrate the RenderScript support library in Gradle-based projects. In this post, we will showcase the usefulness of having RenderScript available. A common design effect is to blur images for an exceptionally beautiful design. On Android blurring images efficiently was a hassle since the beginning due to the limitation of Java. RenderScript offers an attractive solution.
The Code to Blur Images
Let us jump right to the code:
The class provides one static function, which takes a bitmap and returns a blurred version of it. Adjust the two constants BITMAP_SCALE and BLUR_RADIUS to your needs. This solution is very fast and easy to integrate. If you need to blur views instead of bitmaps, take a look at the original version of the code on StackOverflow. Please be cautious that you import the support library version of RenderScript (package android.support.v8.renderscript.* ) in order to be compatible to older Android versions. Otherwise, this code requires at least Android API level 17 (Jellybean, Android 4.3).
Let us look at a small example. If you want to set the background of a view as a blurred version of an existing bitmap originalBitmap , use this code snippet:
Preview
Of course, code is never as exciting as a preview of the functionality. Let’s take a recipe photo from a our (discontinued) eat foody platform.
A blurry version of it, using our code from above, would look like this:
You can adjust the strength of the blurring by playing with the two constants BITMAP_SCALE and BLUR_RADIUS .
Shoot us a tweet if you liked this guide at @futurestud_io.
Get Notified on New Future Studio
Content and Platform Updates
Get your weekly push notification about new and trending
Future Studio content and recent platform enhancements
Источник