Closed T8RIN closed 10 months ago
Hi, can you implement bitmap scaling based on ffmpeg libswscale, because it can choose between some algorhytms, like bicubic, bilenear, lancoz and others, if you can here is abandoned project that support only two archs and not starts on api 24 and abov
Hello there,
The project as default using a provided libheif scaling when it needs to be downscaled that is bicubic algorithm.
Not really sure that is good idea trying to compile part of FFmpeg for this one.
In jxl-coder you may found a class XScaler.cpp
that contains already done scaling for float16 bitmap format and argb 8-bit with ready to go algorithms - nearest neighbor, bcubic, bilinear, Mitchell-Netravalli, Catmull Rom, lanczos and hann window and hermite spline and some math tricks like fast sin/cos via chebyshev polynoms and etc. And I may say that algorithms not worse than libswscale especially for arm64 platforms.
If you are thinking about dedicated library, I'm not really into it, but you may easily find all the required code in my projects.
I may say you before you start that default android scaling is bilinear was chosen for a reason. It has awesome performance on a not quite powerful devices and do especially well when you need a scale that not changing image dimensions too much. There are not so many real world cases an android when you need a Spline that do really well when you need a scale more than 2x or original dimensions and have 2+ times performance degradation against bilinear. And also not so much cases when you need a Lanczos that do well on scale like 0.1x of original dimensions and require computational power at least 3-4 times more than bilinear
Hm, thanks for pointing to XScale.cpp , didn't know that it exists in your code already, but as you know i'm noob at ndk, so how can i connect this scaler with bitmaps? Like i can just use BitmapScaler.scale(bitmap, width, height, algo) and here we go
For this function you'll need in NDK. Use AndroidBitmap_getInfo
to get bitmap info, use AndroidBitmap_lockPixels
to get bitmap pixels in your memory buffer ( not forget to AndroidBitmap_unlockPixels
after), then create a new memory buffer where scale to, pass both buffer to a scaler, create a new JVM bitmap object and copy your destination buffer to a new bitmap also using AndroidBitmap_lockPixels
and AndroidBitmap_unlockPixels
For this function you'll need in NDK. Use
AndroidBitmap_getInfo
to get bitmap info, useAndroidBitmap_lockPixels
to get bitmap pixels in your memory buffer ( not forget toAndroidBitmap_unlockPixels
after), then create a new memory buffer where scale to, pass both buffer to a scaler, create a new JVM bitmap object and copy your destination buffer to a new bitmap also usingAndroidBitmap_lockPixels
andAndroidBitmap_unlockPixels
Thanks for this explanations, i'll try and ask if something will not work
Can you explain please what is components and stride's are?
Components is the count of color components in the image, surprisingly but RGB will have 3 components and Rgba have 4 components. Stride is a row length of the image, you may thinks that it’s equal to width × components. × (size of component) but it often doesn’t due to optimization trick, because L1 cache of the processor is aligned at least to 64 bytes most of libraries will try to round your real row length ‘width × compents ×(size of compents)’ to be dividable for 64 ( or anything else value, it depends) and just ignore this bytes after. So you have to ignore this aligned bytes, but have to consider that really allocated memory for the image row can be a little bigger than image row really is
so i can provide as stride ‘width × compents ×(size of compents)’ and not think about rounding?
You have to provide stride that really is, stride of the original bitmap you may obtain from bitmap info. For your destination buffer yes, you may allocate bytes for exact row size
Thanks!
Когда закончишь, я, впринципе, могу взглянуть нормально ли все у тебя вышло
Хорошо, а ты русский знаешь что ли? 😳
Да, это ж не секретный язык )
Ты русский чтоль? Явно не через переводчик это пишешь))
Хотя я бы рекомендовал еще раз взвесить стоит ли это того, т.к. когда ты через coil / glide грузишь картинки, они уже пересжаты, и то что ты добавишь более продвинутый алгоритм на пересжатие еще раз врятли даст действительно стоящий результат
Я беларус
Я беларус
Пипец, а живешь не там, да?
Не, в беларуси я 3 года уже не живу
Хотя я бы рекомендовал еще раз взвесить стоит ли это того, т.к. когда ты через coil / glide грузишь картинки, они уже пересжаты, и то что ты добавишь более продвинутый алгоритм на пересжатие еще раз врятли даст действительно стоящий результат
У меня ж для работы с картинками прога, я изначально гружу картинку в оригинальном разрешении, и можно ее сжать/увеличить, так что норм должно быть, попросили прост чет кроме билинейного скейлинга добавить на выбор
Не, в беларуси я 3 года уже не живу
По работе переехал чтоль?
Не, в беларуси я 3 года уже не живу
По работе переехал чтоль?
Я враг лукашенки, не переехал, а убежал )
Не может быть чтоб ты оригинальные грузил, тогда у тебя картинки с любого флагмана должны просто крашиться т.к. они очень большие
Если ты специально не продумывал загрузку оригиналов - у тебя либо креши на больших фото, либо они уже сжаты
Если ты специально не продумывал загрузку оригиналов - у тебя либо креши на больших фото, либо они уже сжаты
Нене, я показываю в качестве превью засемпленный вариант, а когда чел сохраняет, то я полноразмерную битмапу гружу, но потому что я ее не показываю, то не крешится, хотя конечно если 12к*12к и выше то может крешнуться, вот тут ваще хз как убрать это ограничение андроида, ток если все добро на ндк перенести, но я больше по котлину чем по плюсам 🐸
Даже в самом "оптимистичном" случае если тебя пропустила JVM и ты загрузил картинку как HARDWARE андроид не допускает отрисовки картинки больше чем 104МБ в памяти, это RGBA 16bit максимум 3.6kx3.6k, или 8bit умножь размер RGBA на 2
Если ты специально не продумывал загрузку оригиналов - у тебя либо креши на больших фото, либо они уже сжаты
Нене, я показываю в качестве превью засемпленный вариант, а когда чел сохраняет, то я полноразмерную битмапу гружу, но потому что я ее не показываю, то не крешится, хотя конечно если 12к*12к и выше то может крешнуться, вот тут ваще хз как убрать это ограничение андроида, ток если все добро на ндк перенести, но я больше по котлину чем по плюсам 🐸
Я тебе кажется писал уже, только сохранять все твои преобразования на превью, и потом трансформировать их в оригинал в NDK. Либо искуственно обрезать картинку чтобы она никогда не была больше 100МБ
Даже в самом "оптимистичном" случае если тебя пропустила JVM и ты загрузил картинку как HARDWARE андроид не допускает отрисовки картинки больше чем 104МБ в памяти, это RGBA 16bit максимум 3.6kx3.6k, или 8bit умножь размер RGBA на 2
А вроде у меня запрет на хардвер битмапы стоит
Если ты специально не продумывал загрузку оригиналов - у тебя либо креши на больших фото, либо они уже сжаты
Нене, я показываю в качестве превью засемпленный вариант, а когда чел сохраняет, то я полноразмерную битмапу гружу, но потому что я ее не показываю, то не крешится, хотя конечно если 12к*12к и выше то может крешнуться, вот тут ваще хз как убрать это ограничение андроида, ток если все добро на ндк перенести, но я больше по котлину чем по плюсам 🐸
Если так то - делай, правда все равно билинейный алгоритм самый оптимальный, ланцош хорош только когда ты уменьшаешь больше чем на 30-40%, а сплайны только когда картинка увеличивается хотя бы на 40%
Спокойно пережимает 10к на 10к, можешь щас чекнуть даж👀
Если ты специально не продумывал загрузку оригиналов - у тебя либо креши на больших фото, либо они уже сжаты
Нене, я показываю в качестве превью засемпленный вариант, а когда чел сохраняет, то я полноразмерную битмапу гружу, но потому что я ее не показываю, то не крешится, хотя конечно если 12к*12к и выше то может крешнуться, вот тут ваще хз как убрать это ограничение андроида, ток если все добро на ндк перенести, но я больше по котлину чем по плюсам 🐸
Я тебе кажется писал уже, только сохранять все твои преобразования на превью, и потом трансформировать их в оригинал в NDK. Либо искуственно обрезать картинку чтобы она никогда не была больше 100МБ
Ну, у меня примерно так и происходит, но я не на ндк делаю, а в джвм, от того и проблемы если картинка большая уже слишком
С ндк я ваще не тютю, так что не могу сделать все там(
И правда жмет, только поворот на больших картинках длиться по пол минуты, и оно дает во время поворота сохранять и 16 битные картинки стали 8 бит
С ндк я ваще не тютю, так что не могу сделать все там(
Пробуй, надо с чего-то начинать, базовый вариант скейла достаточно простой только для 8 бит ARGB
И правда жмет, только поворот на больших картинках длиться по пол минуты, и оно дает во время поворота сохранять и 16 битные картинки стали 8 бит
Вот кста про 16 бит и 8 я хз, по-моему у меня это не предусмотрено, а че там надо в конструктор битмапы передавать, чтобы битность указать ARGB8888 это 32 бит ж ваще
Вот картинка для теста, https://backup-csh.fra1.digitaloceanspaces.com/avif10bit%20(2).avif 10 бит, должно быть 16 на андроиде или 10бит для 34+ можно, ее поворачивает крайне долго
С ндк я ваще не тютю, так что не могу сделать все там(
Пробуй, надо с чего-то начинать, базовый вариант скейла достаточно простой только для 8 бит ARGB
Во, седня-завтра хоть скейлер попробую написать с твоих либ, уже что-то
Вот картинка для теста, https://backup-csh.fra1.digitaloceanspaces.com/avif10bit%20(2).avif 10 бит, должно быть 16 на андроиде или 10бит для 34+ можно, ее поворачивает крайне долго
Пипец конечно, я ваще изначально прогу для себя делал, но чет стрельнула
И правда жмет, только поворот на больших картинках длиться по пол минуты, и оно дает во время поворота сохранять и 16 битные картинки стали 8 бит
Вот кста про 16 бит и 8 я хз, по-моему у меня это не предусмотрено, а че там надо в конструктор битмапы передавать, чтобы битность указать ARGB8888 это 32 бит ж ваще
Bitmap.Config.RGBA_F16 для получения 16 бит картинок где тип данных half float
, флоат не должно тебя вводить в заблуждение, это не float, а другой тип данных, у меня в проектах есть half.hpp класс где есть все что для него нужно в NDK, и в проектах примеры, работает на андроиде толи с 26,+ толи с 28+, памяти нужно ровно в 2 раза больше чем для 8bit, этот тип необходимо без вариантов использовать для HDR фото, как фото выше, для отображения
RGBA_1010102 доступен с 34+ или 33+, это 10bit R канал, 10bit канал, 10 - B канал, и 2 бита на A, соответсвенно а может быть равно только 0, 1, 2, 3, это хорошо подходит когда у тебя нет альфа каначала и фото больше 8бит, изображение соотвественно будет считаться 10 битным, но памяти нужно столько же сколько для ARGB 8
Так, окей, а зачем тогда 32 битная вариация есть?
32 битная? Я о такой не слышал на телефоне, ну в теории можно в JXL какую угодно глубину цвета вбить, типа карты геоместности ( там карты глубин ) или сьемки космоса ( там тоже соотвественно карты глубин ), но это уже какая-то достаточно научная штука, не думаю что она нужна
ARGB_8888 в конфиге как раз
По-моему как будто по дефолту даж она стоит, или я не понимаю чет и это 8 бит?👀
это 8 бит, не 32, битность изображения считается по размеру компонента, а не точке
A - это компонент, ARGB - это цветовая точка, размерность изображения считается по компоненте, не по точке
А, ну тогда понятно че битность теряется, пофикшу
А кстати, если у картинки изначально было 8 бит, я же не пойму это, так как по дефолту буду грузить больше бит чем надо, и сохранять по сути тоже, тип если я 8 битную сохраню как 16 бит, то размер не увеличится?
В основном, если ты 8 бит сохранишь как 10, 12, 16 размер увеличится, насколько- зависит от кодека
Можно проверить изначальный bitmap config или взять инфу о картинке и из нее битность, скорее всего в Андроиде есть готовое апи
Есть еще опция можешь на сам сделать скейл на Vulkan или OpenGL, вероятно ты найдешь такие предложения, для огромных картинок он будет в 2-3 раза быстрее чем в на c++, только надо апи 26+ вроде, научиться писать шейдеры и доступ к Vulkan все равно только с c++, он будет действительно быстрый, но из-за архи сложной конфигурации Vulkan и OpenGL и если ты не знаком с шейдерами- не рекомендую
Хотя OpenGL можно в теории и без ndk сделать
С шейдерами то знаком, но ток с тем как их использовать готовые, сам писать не дорос ))
В этих движках шейдер часто не главная проблема, заставить банально выдать картинку другого размера от входной может быть не так просто. Vulkan удачный но его чтобы просто запустить надо около 500 строк кода, а OpenGL банально на китайских или индийских устройствах может выдавать вообще другой результат от того что ты ждешь- по этой причине я бы ( как и google если внимательно читать их рекомендации о обработке фото ) не рекомендовал их использовать вообще пока тебе они не нужны прямо по какой-то очень важной причине
И есть опция opencv, там нету всех моих опций, зато есть куча готовых либ на андроид, и все встроиться минут за 15, ценой плюс 15-20мб к каждому бинарнику
Hi, can you implement bitmap scaling based on ffmpeg libswscale, because it can choose between some algorhytms, like bicubic, bilenear, lancoz and others, if you can here is abandoned project that support only two archs and not starts on api 24 and abov