Как стать автором
Обновить

Как Android преобразует размеры ресурсов

Время на прочтение3 мин
Количество просмотров7.5K
Размер APK файла можно уменьшить, выкинув «ненужные» LDPI ресурсы, Android все равно умеет генерировать их на лету из MDPI. Но что будет если убрать еще и MDPI каталог? И как именно будет произведена свертка: усреднением или более дешевым выбрасыванием пикселей? Перескочит ли Android через один шаг чтобы произвести потенциально более простое преобразование HDPI → LDPI? Как именно происходит уменьшение картинок в разных случаях? Чтобы ответить на эти вопросы я провел небольшой тест.

Теория


Каталоги ldpi-mdpi-hdpi-xhdpi… попарно отстоят друг от друга на ~33.(3) или 50%, то есть MDPI ресурс должен быть примерно в 1.33 раза больше LDPI, а HDPI — уже в 2 раза больше. При преобразованиях 2 → 1 и 4 → 1 теоретически возможны «дешевые» отбрасыванием каждого второго пикселя, при переходе 1.5 → 1 теоретически возможна оптимизация с отбрасыванием одного пикселя из трех, а при переходе 1.33 → 1 — одного из четырех, осталось проверить какие оптимизации и алгоритмы использует Android в действительности.

Методика тестирования


Создаем файл с повторяющимся паттерном из разноцветных полос шириной в один и два пикселя, чтобы проще было видеть результат свертки. Паттерны выглядят так:

и

и размещены со смещением 0, 1 и 2 пикселя от границы (паттерны однонаправленные, так как вертикальная и горизонтальные свертки очевидно должны использовать одинаковый алгоритм).
Помещаем картинку (одну и ту же) в каталоги LDPI, MDPI и т.д под разными именами и на каждой копии рисуем «водяной знак» обозначающий каталог, в котором она находится, чтобы знать, откуда Android взял исходник для преобразования. Отображаем картинки изо всех (MDPI-XXXDPI) каталогов на разрешениях от LDPI до XXHDPI. Смотрим под лупой, что же получилось, и отвечаем на вопросы.

Одинаков ли алгоритм свертки для переходов 1.5 → 1 и 1.33 → 1 ?


Очевидно нет, можно сравнить, как выглядит паттерн из каталога HDPI на MDPI экране и паттерн MDPI на LDPI

1.5 → 1 vs. 1.33 → 1
h->m
m->l

при этом результаты сверток x → h и m → l совпадают, что подтверждает теорию.

Отбрасывает ли Android «лишний» пиксель при свертке 1.5 → 1 ?


Судя по всему, да! Для этого сделаем другой паттерн (также со смещением 0, 1 и 2 пикселя)
и смасштабируем его из HDPI в MDPI

1.5 → 1 RGB
h->m

на итоговом паттерне поочередно выпадают то красный, то синий, то зеленый цвета, значит при калькуляции 2 пикселей из 3, один не принимается в расчёт. Итоговые цвета не чистые, значит, оставшиеся два пикселя не берутся как есть, а смешиваются в разной пропорции.

Как происходит свертка 2 → 1 ?


Простым замешиванием соседних пикселей парами в равных пропорциях. Тут результаты переходов h → l, xh → m, xxh → h идентичны.

2 → 1
h->l

Артефактов отбрасывания пикселей не замечено.

Как происходит свертка 4 → 1 ?


А вот тут Android все-таки выбрасывает часть пикселей. Судя по всему, берутся четверки пикселей, два крайних удаляются, а центральные замешиваются в равной пропорции. Примерно так:



4 → 1
xxxh->m

Именно этот алгоритм является причиной интересного артефакта — полного пропадания синего и красного цветов из паттернов и , которые отличаются только смещением.

Какой ресурс выбирает Android если вариантов несколько?


При свертке до MDPI ресурса, который имеется в HDPI и XHPI каталогах можно было бы применить потенциально более простой алгоритм 2 → 1 вместо 1.5 → 1, пропустив одну ступень, но Android всегда выбирает ближайший ресурс. Вероятно, еще и потому, что свертка 2 → 1 использует более ресурсоемкое замешивание, а не отбрасывание (как мы видели выше), и сэкономить на ней сильно не получится.

Какой из этого всего можно сделать вывод?


Ну во-первых, надо не забывать напоминать своему дизайнеру, что рисовать нужно по сетке и что 1dp != 1px: любая однопиксельная линия на всех разрешениях от MDPI и выше может превратиться в непредсказуемую размазню или вовсе пропасть. Во-вторых, SVG/XML все-таки более надежный способ экономии на графике, если характер картинки позволяет. В-третьих, если итоговая картинка на экрана должна иметь четкие грани, все разрешения должны присутствовать в проекте. Ну и наконец, Android, действительно применяет интересные оптимизации, чтобы сэкономить процессорные ресурсы, и этим можно пользоваться, если делать это с умом.

Пример работы тестового приложения на разных разрешениях (на каждой картинке написано из какого каталога, она взята, рядом с ней — в каких каталогах она присутствовала):

LDPI
l
MDPI
m
HDPI
h
XHDPI
xh
XXHDPI
xxh

→ Исходники на GitHub

Спасибо за внимание!
Теги:
Хабы:
Всего голосов 20: ↑20 и ↓0+20
Комментарии0

Публикации

Истории

Работа

Ближайшие события