Comments (115)
В основном, если ты 8 бит сохранишь как 10, 12, 16 размер увеличится, насколько- зависит от кодека
Можно проверить изначальный bitmap config или взять инфу о картинке и из нее битность, скорее всего в Андроиде есть готовое апи
from avif-coder.
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
from avif-coder.
Не, в беларуси я 3 года уже не живу
По работе переехал чтоль?
Я враг лукашенки, не переехал, а убежал )
Не может быть чтоб ты оригинальные грузил, тогда у тебя картинки с любого флагмана должны просто крашиться т.к. они очень большие
from avif-coder.
С ндк я ваще не тютю, так что не могу сделать все там(
Пробуй, надо с чего-то начинать, базовый вариант скейла достаточно простой только для 8 бит ARGB
from avif-coder.
Вот картинка для теста, https://backup-csh.fra1.digitaloceanspaces.com/avif10bit%20(2).avif 10 бит, должно быть 16 на андроиде или 10бит для 34+ можно, ее поворачивает крайне долго
from avif-coder.
Вот картинка для теста, https://backup-csh.fra1.digitaloceanspaces.com/avif10bit%20(2).avif 10 бит, должно быть 16 на андроиде или 10бит для 34+ можно, ее поворачивает крайне долго
Пипец конечно, я ваще изначально прогу для себя делал, но чет стрельнула
from avif-coder.
это 8 бит, не 32, битность изображения считается по размеру компонента, а не точке
from avif-coder.
A - это компонент, ARGB - это цветовая точка, размерность изображения считается по компоненте, не по точке
from avif-coder.
А, ну тогда понятно че битность теряется, пофикшу
from avif-coder.
В этих движках шейдер часто не главная проблема, заставить банально выдать картинку другого размера от входной может быть не так просто. Vulkan удачный но его чтобы просто запустить надо около 500 строк кода, а OpenGL банально на китайских или индийских устройствах может выдавать вообще другой результат от того что ты ждешь- по этой причине я бы ( как и google если внимательно читать их рекомендации о обработке фото ) не рекомендовал их использовать вообще пока тебе они не нужны прямо по какой-то очень важной причине
from avif-coder.
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
from avif-coder.
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
from avif-coder.
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
from avif-coder.
Can you explain please what is components and stride's are?
from avif-coder.
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
from avif-coder.
so i can provide as stride ‘width × compents ×(size of compents)’ and not think about rounding?
from avif-coder.
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
from avif-coder.
Thanks!
from avif-coder.
Когда закончишь, я, впринципе, могу взглянуть нормально ли все у тебя вышло
from avif-coder.
Хорошо, а ты русский знаешь что ли? 😳
from avif-coder.
Да, это ж не секретный язык )
from avif-coder.
Ты русский чтоль? Явно не через переводчик это пишешь))
from avif-coder.
Хотя я бы рекомендовал еще раз взвесить стоит ли это того, т.к. когда ты через coil / glide грузишь картинки, они уже пересжаты, и то что ты добавишь более продвинутый алгоритм на пересжатие еще раз врятли даст действительно стоящий результат
from avif-coder.
Я беларус
from avif-coder.
Я беларус
Пипец, а живешь не там, да?
from avif-coder.
Не, в беларуси я 3 года уже не живу
from avif-coder.
Хотя я бы рекомендовал еще раз взвесить стоит ли это того, т.к. когда ты через coil / glide грузишь картинки, они уже пересжаты, и то что ты добавишь более продвинутый алгоритм на пересжатие еще раз врятли даст действительно стоящий результат
У меня ж для работы с картинками прога, я изначально гружу картинку в оригинальном разрешении, и можно ее сжать/увеличить, так что норм должно быть, попросили прост чет кроме билинейного скейлинга добавить на выбор
from avif-coder.
Не, в беларуси я 3 года уже не живу
По работе переехал чтоль?
from avif-coder.
Если ты специально не продумывал загрузку оригиналов - у тебя либо креши на больших фото, либо они уже сжаты
from avif-coder.
Если ты специально не продумывал загрузку оригиналов - у тебя либо креши на больших фото, либо они уже сжаты
Нене, я показываю в качестве превью засемпленный вариант, а когда чел сохраняет, то я полноразмерную битмапу гружу, но потому что я ее не показываю, то не крешится, хотя конечно если 12к*12к и выше то может крешнуться, вот тут ваще хз как убрать это ограничение андроида, ток если все добро на ндк перенести, но я больше по котлину чем по плюсам 🐸
from avif-coder.
Даже в самом "оптимистичном" случае если тебя пропустила JVM и ты загрузил картинку как HARDWARE андроид не допускает отрисовки картинки больше чем 104МБ в памяти, это RGBA 16bit максимум 3.6kx3.6k, или 8bit умножь размер RGBA на 2
from avif-coder.
Если ты специально не продумывал загрузку оригиналов - у тебя либо креши на больших фото, либо они уже сжаты
Нене, я показываю в качестве превью засемпленный вариант, а когда чел сохраняет, то я полноразмерную битмапу гружу, но потому что я ее не показываю, то не крешится, хотя конечно если 12к*12к и выше то может крешнуться, вот тут ваще хз как убрать это ограничение андроида, ток если все добро на ндк перенести, но я больше по котлину чем по плюсам 🐸
Я тебе кажется писал уже, только сохранять все твои преобразования на превью, и потом трансформировать их в оригинал в NDK. Либо искуственно обрезать картинку чтобы она никогда не была больше 100МБ
from avif-coder.
Даже в самом "оптимистичном" случае если тебя пропустила JVM и ты загрузил картинку как HARDWARE андроид не допускает отрисовки картинки больше чем 104МБ в памяти, это RGBA 16bit максимум 3.6kx3.6k, или 8bit умножь размер RGBA на 2
А вроде у меня запрет на хардвер битмапы стоит
from avif-coder.
Если ты специально не продумывал загрузку оригиналов - у тебя либо креши на больших фото, либо они уже сжаты
Нене, я показываю в качестве превью засемпленный вариант, а когда чел сохраняет, то я полноразмерную битмапу гружу, но потому что я ее не показываю, то не крешится, хотя конечно если 12к*12к и выше то может крешнуться, вот тут ваще хз как убрать это ограничение андроида, ток если все добро на ндк перенести, но я больше по котлину чем по плюсам 🐸
Если так то - делай, правда все равно билинейный алгоритм самый оптимальный, ланцош хорош только когда ты уменьшаешь больше чем на 30-40%, а сплайны только когда картинка увеличивается хотя бы на 40%
from avif-coder.
Спокойно пережимает 10к на 10к, можешь щас чекнуть даж👀
from avif-coder.
Если ты специально не продумывал загрузку оригиналов - у тебя либо креши на больших фото, либо они уже сжаты
Нене, я показываю в качестве превью засемпленный вариант, а когда чел сохраняет, то я полноразмерную битмапу гружу, но потому что я ее не показываю, то не крешится, хотя конечно если 12к*12к и выше то может крешнуться, вот тут ваще хз как убрать это ограничение андроида, ток если все добро на ндк перенести, но я больше по котлину чем по плюсам 🐸
Я тебе кажется писал уже, только сохранять все твои преобразования на превью, и потом трансформировать их в оригинал в NDK. Либо искуственно обрезать картинку чтобы она никогда не была больше 100МБ
Ну, у меня примерно так и происходит, но я не на ндк делаю, а в джвм, от того и проблемы если картинка большая уже слишком
from avif-coder.
С ндк я ваще не тютю, так что не могу сделать все там(
from avif-coder.
И правда жмет, только поворот на больших картинках длиться по пол минуты, и оно дает во время поворота сохранять и 16 битные картинки стали 8 бит
from avif-coder.
И правда жмет, только поворот на больших картинках длиться по пол минуты, и оно дает во время поворота сохранять и 16 битные картинки стали 8 бит
Вот кста про 16 бит и 8 я хз, по-моему у меня это не предусмотрено, а че там надо в конструктор битмапы передавать, чтобы битность указать ARGB8888 это 32 бит ж ваще
from avif-coder.
С ндк я ваще не тютю, так что не могу сделать все там(
Пробуй, надо с чего-то начинать, базовый вариант скейла достаточно простой только для 8 бит ARGB
Во, седня-завтра хоть скейлер попробую написать с твоих либ, уже что-то
from avif-coder.
И правда жмет, только поворот на больших картинках длиться по пол минуты, и оно дает во время поворота сохранять и 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
from avif-coder.
Так, окей, а зачем тогда 32 битная вариация есть?
from avif-coder.
32 битная? Я о такой не слышал на телефоне, ну в теории можно в JXL какую угодно глубину цвета вбить, типа карты геоместности ( там карты глубин ) или сьемки космоса ( там тоже соотвественно карты глубин ), но это уже какая-то достаточно научная штука, не думаю что она нужна
from avif-coder.
ARGB_8888 в конфиге как раз
from avif-coder.
По-моему как будто по дефолту даж она стоит, или я не понимаю чет и это 8 бит?👀
from avif-coder.
А кстати, если у картинки изначально было 8 бит, я же не пойму это, так как по дефолту буду грузить больше бит чем надо, и сохранять по сути тоже, тип если я 8 битную сохраню как 16 бит, то размер не увеличится?
from avif-coder.
Есть еще опция можешь на сам сделать скейл на Vulkan или OpenGL, вероятно ты найдешь такие предложения, для огромных картинок он будет в 2-3 раза быстрее чем в на c++, только надо апи 26+ вроде, научиться писать шейдеры и доступ к Vulkan все равно только с c++, он будет действительно быстрый, но из-за архи сложной конфигурации Vulkan и OpenGL и если ты не знаком с шейдерами- не рекомендую
from avif-coder.
Хотя OpenGL можно в теории и без ndk сделать
from avif-coder.
С шейдерами то знаком, но ток с тем как их использовать готовые, сам писать не дорос ))
from avif-coder.
И есть опция opencv, там нету всех моих опций, зато есть куча готовых либ на андроид, и все встроиться минут за 15, ценой плюс 15-20мб к каждому бинарнику
from avif-coder.
https://docs.opencv.org/4.x/da/d54/group__imgproc__transform.html
Конечно opencv ради скейла это стрелять из пушки по воробьям, но если ты не хочешь погружаться в ndk это самая крутая опция
from avif-coder.
Open Cv весит дофига еще, в этом тож проблема
from avif-coder.
У меня опенгл ток для фильтров из gpuimage
from avif-coder.
написал такую поделку, будет работать?
#include <jni.h>
#include <android/bitmap.h>
#include <vector>
#include "JniExceptions.h"
#include "XScaler.h"
#include "Rgb1010102toF16.h"
#include "RGBAlpha.h"
#include "libyuv/convert_argb.h"
#include "libyuv/convert_from_argb.h"
using namespace std;
extern "C"
JNIEXPORT jbyteArray JNICALL
Java_com_t8rin_bitmapscaler_BitmapScaler_scaleImpl(JNIEnv *env, jobject thiz, jobject bitmap,
jint dst_width, jint dst_height,
jint scale_mode) {
AndroidBitmapInfo info;
if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) {
throwPixelsException(env);
return static_cast<jbyteArray>(nullptr);
}
void *addr;
if (AndroidBitmap_lockPixels(env, bitmap, &addr) != 0) {
throwPixelsException(env);
return static_cast<jbyteArray>(nullptr);
}
vector<uint8_t> rgbaPixels(info.stride * info.height);
memcpy(rgbaPixels.data(), addr, info.stride * info.height);
if (AndroidBitmap_unlockPixels(env, bitmap) != 0) {
string exc = "Unlocking pixels has failed";
throwException(env, exc);
return static_cast<jbyteArray>(nullptr);
}
int imageStride = (int) info.stride;
int dstStride = (int) info.stride;
if (info.format == ANDROID_BITMAP_FORMAT_RGBA_1010102) {
imageStride = (int) info.width * 4 * (int) sizeof(uint16_t);
dstStride = (int) dst_width * 4 * (int) sizeof(uint16_t);
vector<uint8_t> halfFloatPixels(imageStride * info.height);
coder::ConvertRGBA1010102toF16(reinterpret_cast<const uint8_t *>(rgbaPixels.data()),
(int) info.stride,
reinterpret_cast<uint16_t *>(halfFloatPixels.data()),
(int) imageStride,
(int) info.width,
(int) info.height);
rgbaPixels = halfFloatPixels;
} else if (info.format == ANDROID_BITMAP_FORMAT_RGB_565) {
dstStride = (int) dst_width * 4 * (int) sizeof(uint8_t);
int newStride = (int) info.width * 4 * (int) sizeof(uint8_t);
std::vector<uint8_t> rgba8888Pixels(newStride * info.height);
libyuv::RGB565ToARGB(rgbaPixels.data(), (int) info.stride,
rgba8888Pixels.data(), newStride,
(int) info.width, (int) info.height);
libyuv::ARGBToABGR(rgba8888Pixels.data(), newStride,
rgba8888Pixels.data(), newStride,
(int) info.width, (int) info.height);
imageStride = newStride;
rgbaPixels = rgba8888Pixels;
} else if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
coder::UnpremultiplyRGBA(rgbaPixels.data(), imageStride,
rgbaPixels.data(), imageStride,
(int) info.width,
(int) info.height);
}
vector<uint8_t> output(dstStride * dst_height);
int components;
if (info.format == ANDROID_BITMAP_FORMAT_RGB_565) components = 3;
else components = 4;
scaleImageU8(
rgbaPixels.data(),
imageStride,
info.width,
info.height,
output.data(),
dstStride,
dst_width,
dst_height,
components,
info.format,
static_cast<XSampler>(scale_mode)
);
jbyteArray byteArray = env->NewByteArray((jsize) output.size());
char *memBuf = (char *) ((void *) output.data());
env->SetByteArrayRegion(byteArray, 0, (jint) output.size(),
reinterpret_cast<const jbyte *>(memBuf));
output.clear();
return byteArray;
}
from avif-coder.
У меня опенгл ток для фильтров из gpuimage
Интерестно, мало того что старый опенгл, насколько я помню он же грузит тоже превью и рендерит его на экран чтобы обработать? Или ты доделывал это?
from avif-coder.
У меня он ток в качестве наложения фильтров на битмап, показываю все так же через коил, точнее на уменьшенную картинку фильтры накалываю
from avif-coder.
написал такую поделку, будет работать?
#include <jni.h> #include <android/bitmap.h> #include <vector> #include "JniExceptions.h" #include "XScaler.h" #include "Rgb1010102toF16.h" #include "RGBAlpha.h" #include "libyuv/convert_argb.h" #include "libyuv/convert_from_argb.h" using namespace std; extern "C" JNIEXPORT jbyteArray JNICALL Java_com_t8rin_bitmapscaler_BitmapScaler_scaleImpl(JNIEnv *env, jobject thiz, jobject bitmap, jint dst_width, jint dst_height, jint scale_mode) { AndroidBitmapInfo info; if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) { throwPixelsException(env); return static_cast<jbyteArray>(nullptr); } void *addr; if (AndroidBitmap_lockPixels(env, bitmap, &addr) != 0) { throwPixelsException(env); return static_cast<jbyteArray>(nullptr); } vector<uint8_t> rgbaPixels(info.stride * info.height); memcpy(rgbaPixels.data(), addr, info.stride * info.height); if (AndroidBitmap_unlockPixels(env, bitmap) != 0) { string exc = "Unlocking pixels has failed"; throwException(env, exc); return static_cast<jbyteArray>(nullptr); } int imageStride = (int) info.stride; int dstStride = (int) info.stride; if (info.format == ANDROID_BITMAP_FORMAT_RGBA_1010102) { imageStride = (int) info.width * 4 * (int) sizeof(uint16_t); dstStride = (int) dst_width * 4 * (int) sizeof(uint16_t); vector<uint8_t> halfFloatPixels(imageStride * info.height); coder::ConvertRGBA1010102toF16(reinterpret_cast<const uint8_t *>(rgbaPixels.data()), (int) info.stride, reinterpret_cast<uint16_t *>(halfFloatPixels.data()), (int) imageStride, (int) info.width, (int) info.height); rgbaPixels = halfFloatPixels; } else if (info.format == ANDROID_BITMAP_FORMAT_RGB_565) { dstStride = (int) dst_width * 4 * (int) sizeof(uint8_t); int newStride = (int) info.width * 4 * (int) sizeof(uint8_t); std::vector<uint8_t> rgba8888Pixels(newStride * info.height); libyuv::RGB565ToARGB(rgbaPixels.data(), (int) info.stride, rgba8888Pixels.data(), newStride, (int) info.width, (int) info.height); libyuv::ARGBToABGR(rgba8888Pixels.data(), newStride, rgba8888Pixels.data(), newStride, (int) info.width, (int) info.height); imageStride = newStride; rgbaPixels = rgba8888Pixels; } else if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) { coder::UnpremultiplyRGBA(rgbaPixels.data(), imageStride, rgbaPixels.data(), imageStride, (int) info.width, (int) info.height); } vector<uint8_t> output(dstStride * dst_height); int components; if (info.format == ANDROID_BITMAP_FORMAT_RGB_565) components = 3; else components = 4; scaleImageU8( rgbaPixels.data(), imageStride, info.width, info.height, output.data(), dstStride, dst_width, dst_height, components, info.format, static_cast<XSampler>(scale_mode) ); jbyteArray byteArray = env->NewByteArray((jsize) output.size()); char *memBuf = (char *) ((void *) output.data()); env->SetByteArrayRegion(byteArray, 0, (jint) output.size(), reinterpret_cast<const jbyte *>(memBuf)); output.clear(); return byteArray; }
Для ANDROID_BITMAP_FORMAT_RGBA_1010102 вариант не правильный так как ты использовал только скейл для 8 бит, u8 суффикс это для 8 битных картинок
Bitmap надо либо создать из ndk, или передать уже созданный и скопировать в него твой буфер не забыв о stride
components у тебя пока получается всегда 4, проверка для 565 не имеет смысла так как ты до этого уже конвертировал 565 в 8 бит
from avif-coder.
SetByteArrayRegion Лучше никогда не использовать, он ограничен jvm 20-30мб, надо копировать пиксели напрямую
from avif-coder.
епересете, а поч тогда у тебя так в jxl кодере написано?
from avif-coder.
Это либо баг у меня, либо ты что-то не до копировал)
from avif-coder.
да вроде все
from avif-coder.
from avif-coder.
Понятно, ты бы лучше декодер смотрел чем кодер, в энкодере финальный размер практически никогда в Jxl не будет 20мб+, по-этому тут я это проигнорировал
from avif-coder.
И здесь потом в encoder передается параметр usefloat16 чтобы он знал какой тип данных используется
from avif-coder.
Емае..., ща поправлю
from avif-coder.
Тебе нужно перевести картинку в 1 из поддерживаемых типов данных 8bit/16bit, пересжать ее, затем создать/скопировать либо в битмап с 8/16 бит, или конвертировать назад в исходный формат пикселей
from avif-coder.
лучше в байт аррей, мне так проще с ней потом будет
from avif-coder.
С байт арреем будут проблемы с jvm, без вариантов
from avif-coder.
ну а битмап все равно из него создается ж
from avif-coder.
Нет, если ты создаешь битмап в ndk, то само содержание картинки никогда не попадает в jvm, в этом и весь смысл обработки картинок без ограничений в ndk, как только ты создаешь байт аррей ты попадаешь в jvm
from avif-coder.
а вектор пикселей это не байт аррей ?
from avif-coder.
а вектор пикселей это не байт аррей ?
Нет, это нативная память, и bitmap хранит в себе ссылку по сути, на такой же вектор, они могут расширяться пока на телефоне память не кончиться, и ты можешь скопировать 1 в другой беж ограничений. А ты хочешь создать еще джава аррей, скопировать в него, а потом из него в Буффер битмапа
from avif-coder.
аа, чет понимать начал
from avif-coder.
поделка 2.0
#include <jni.h>
#include <android/bitmap.h>
#include <vector>
#include "JniExceptions.h"
#include "XScaler.h"
#include "Rgb1010102toF16.h"
#include "RGBAlpha.h"
#include "libyuv/convert_argb.h"
#include "libyuv/convert_from_argb.h"
#include "CopyUnaligned.h"
using namespace std;
extern "C"
JNIEXPORT jobject JNICALL
Java_com_t8rin_bitmapscaler_BitmapScaler_scaleImpl(JNIEnv *env, jobject thiz, jobject bitmap,
jint dst_width, jint dst_height,
jint scale_mode) {
AndroidBitmapInfo info;
if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) {
throwPixelsException(env);
return static_cast<jbyteArray>(nullptr);
}
void *addr;
if (AndroidBitmap_lockPixels(env, bitmap, &addr) != 0) {
throwPixelsException(env);
return static_cast<jbyteArray>(nullptr);
}
vector<uint8_t> rgbaPixels(info.stride * info.height);
memcpy(rgbaPixels.data(), addr, info.stride * info.height);
if (AndroidBitmap_unlockPixels(env, bitmap) != 0) {
string exc = "Unlocking pixels has failed";
throwException(env, exc);
return static_cast<jbyteArray>(nullptr);
}
int imageStride = (int) info.stride;
int dstStride = (int) info.stride;
if (info.format == ANDROID_BITMAP_FORMAT_RGBA_1010102) {
imageStride = (int) info.width * 4 * (int) sizeof(uint16_t);
dstStride = (int) dst_width * 4 * (int) sizeof(uint16_t);
vector<uint8_t> halfFloatPixels(imageStride * info.height);
coder::ConvertRGBA1010102toF16(reinterpret_cast<const uint8_t *>(rgbaPixels.data()),
(int) info.stride,
reinterpret_cast<uint16_t *>(halfFloatPixels.data()),
(int) imageStride,
(int) info.width,
(int) info.height);
rgbaPixels = halfFloatPixels;
} else if (info.format == ANDROID_BITMAP_FORMAT_RGB_565) {
dstStride = (int) dst_width * 4 * (int) sizeof(uint8_t);
int newStride = (int) info.width * 4 * (int) sizeof(uint8_t);
std::vector<uint8_t> rgba8888Pixels(newStride * info.height);
libyuv::RGB565ToARGB(rgbaPixels.data(), (int) info.stride,
rgba8888Pixels.data(), newStride,
(int) info.width, (int) info.height);
libyuv::ARGBToABGR(rgba8888Pixels.data(), newStride,
rgba8888Pixels.data(), newStride,
(int) info.width, (int) info.height);
imageStride = newStride;
rgbaPixels = rgba8888Pixels;
} else if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
coder::UnpremultiplyRGBA(rgbaPixels.data(), imageStride,
rgbaPixels.data(), imageStride,
(int) info.width,
(int) info.height);
}
bool useFloat16 = info.format == ANDROID_BITMAP_FORMAT_RGBA_F16 ||
info.format == ANDROID_BITMAP_FORMAT_RGBA_1010102;
std::vector<uint8_t> rgbPixels;
int requiredStride = (int) info.width * 4 *
(int) (useFloat16 ? sizeof(uint16_t) : sizeof(uint8_t));
if (requiredStride == info.stride) {
rgbPixels = rgbaPixels;
} else {
rgbPixels.resize(requiredStride * (int) info.height);
coder::CopyUnalignedRGBA(rgbaPixels.data(), imageStride, rgbPixels.data(),
requiredStride, (int) info.width, (int) info.height,
(int) (useFloat16 ? sizeof(uint16_t)
: sizeof(uint8_t)));
}
imageStride = requiredStride;
vector<uint8_t> output(dstStride * dst_height);
scaleImageU8(
rgbPixels.data(),
imageStride,
info.width,
info.height,
output.data(),
dstStride,
dst_width,
dst_height,
4,
info.format,
static_cast<XSampler>(scale_mode)
);
rgbPixels.clear();
std::string bitmapPixelConfig = useFloat16 ? "RGBA_F16" : "ARGB_8888";
jclass bitmapConfig = env->FindClass("android/graphics/Bitmap$Config");
jfieldID rgba8888FieldID = env->GetStaticFieldID(bitmapConfig,
bitmapPixelConfig.c_str(),
"Landroid/graphics/Bitmap$Config;");
jobject rgba8888Obj = env->GetStaticObjectField(bitmapConfig, rgba8888FieldID);
jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
jmethodID createBitmapMethodID = env->GetStaticMethodID(bitmapClass, "createBitmap",
"(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
jobject bitmapObj = env->CallStaticObjectMethod(bitmapClass, createBitmapMethodID,
static_cast<jint>(dst_width),
static_cast<jint>(dst_height),
rgba8888Obj);
if (AndroidBitmap_getInfo(env, bitmapObj, &info) < 0) {
throwPixelsException(env);
return static_cast<jbyteArray>(nullptr);
}
free(addr);
if (AndroidBitmap_lockPixels(env, bitmapObj, &addr) != 0) {
throwPixelsException(env);
return static_cast<jobject>(nullptr);
}
if (bitmapPixelConfig == "RGB_565") {
coder::CopyUnalignedRGB565(reinterpret_cast<const uint8_t *>(output.data()), dstStride,
reinterpret_cast<uint8_t *>(addr), (int) info.stride,
(int) info.width,
(int) info.height);
} else {
coder::CopyUnalignedRGBA(reinterpret_cast<const uint8_t *>(output.data()), dstStride,
reinterpret_cast<uint8_t *>(addr), (int) info.stride,
(int) info.width,
(int) info.height, useFloat16 ? 2 : 1);
}
if (AndroidBitmap_unlockPixels(env, bitmapObj) != 0) {
throwPixelsException(env);
return static_cast<jobject>(nullptr);
}
rgbaPixels.clear();
return bitmapObj;
}
from avif-coder.
If usefloat16 scaleImageU8 то ее надо на 16 битный аналог поменять ведь
и free(addr) вроде лишнее, unlock pixels сам освободить должен
остальное с большего похоже, позже я внимательней посмотрю
from avif-coder.
А вот 16 битный аналог требует 16 битный вектор, а у тебя там везде 8 бит ток есть
from avif-coder.
Это c++, там везде стоит uint8_t, но это не значит что там и правда uint8_t, сделай reinterpret_cast до uint16_t
from avif-coder.
ахах, окей, а что делать с depth? там в 16 битном аналоге нет его
from avif-coder.
А 16 half float всегда 16 бит подразумевается а сама битность не важна потому что это нормализованные числа [0,1] ( в случае hdr больше 1)
Битность нужна для 16 бит разрядности только когда данные в uint16 типе, а не с нормализованные с плавающей точкой
from avif-coder.
хорошо, чет вылетает почему-то при попытке показать картинку
from avif-coder.
from avif-coder.
Перед вторым AndroidBitmap_lockPixels запиши addr = nullptr
Еще ты там в scale передаешь info.format, мне кажется это тоже неправильно
from avif-coder.
info.format
8 битная версия просит depth это ж по-моему есть енам значение формата
from avif-coder.
info.format
8 битная версия просит depth это ж по-моему есть енам значение формата
Я думаю это неправильно, поставь лучше цифрой 8
Буффер Неверный или hardware bitmap
from avif-coder.
а кста зачем 8 битной функции глубину, если туда 8 бит по умолчанию пойдет
from avif-coder.
возможно хардвер да
from avif-coder.
Так, заработало, но чет фигню какую-то выдало
from avif-coder.
а кста зачем 8 битной функции глубину, если туда 8 бит по умолчанию пойдет
В теории она может сжимать и 6 бит картинки, ни все равно будут храниться в 8
from avif-coder.
а, понял
from avif-coder.
Попробовал побольше поставить выходной размер и упало вообще (Было 200200 стало 500500)
from avif-coder.
Так, заработало, но чет фигню какую-то выдало
С размерами картинок где-то не так, скорее всего размеры ты где-то не верно передал
from avif-coder.
а где... чет вроде все как надо
from avif-coder.
Закоммить куда-нибудь, у меня есть возможность посмотреть
from avif-coder.
оке, щас как форк сделаю
from avif-coder.
https://github.com/T8RIN/jxl-coder/blob/scaler/jxlcoder/src/main/cpp/BitmapScaler.cpp
https://github.com/T8RIN/jxl-coder/tree/scaler
from avif-coder.
![image](https://private-user-images.githubusercontent.com/17083179/294696053-a2a92f60-4702-4403-a4d7-8cc9c18ddbaf.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE2ODU3OTUsIm5iZiI6MTcyMTY4NTQ5NSwicGF0aCI6Ii8xNzA4MzE3OS8yOTQ2OTYwNTMtYTJhOTJmNjAtNDcwMi00NDAzLWE0ZDctOGNjOWMxOGRkYmFmLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA3MjIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNzIyVDIxNTgxNVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTMwY2ViMzcxYWFlMWY4N2E4Njk2NWEwOWI4MmNkNzRiMDk2ZDZkZDdiNjA2ZWYwOTEzZTZlOTY0YjdmNzcxODEmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.-bX2D4OdRBwk3d-L83di8iXYld_mMKVEIAaEyMRUzHc)
![image](https://private-user-images.githubusercontent.com/17083179/294696187-544d7a7b-bef2-4543-8775-631c780d8101.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE2ODU3OTUsIm5iZiI6MTcyMTY4NTQ5NSwicGF0aCI6Ii8xNzA4MzE3OS8yOTQ2OTYxODctNTQ0ZDdhN2ItYmVmMi00NTQzLTg3NzUtNjMxYzc4MGQ4MTAxLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA3MjIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNzIyVDIxNTgxNVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTczMTY3YjVkY2NlZmUyNGM1MDMwYzg3NjU2YTdiODkwMmZkMWVlYzI3YTNkMmQwMjM5NmU5Y2Q2NGMzM2ViZjUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.nPrB6o8r1abPD0XmPr3w59SjJKtM1RjyXHK0FbJarOQ)
Все верно сделано, кроме расчета dstStride
![image](https://private-user-images.githubusercontent.com/17083179/294696384-1863ba05-601b-4a17-a7a2-8fd673b8da5e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE2ODU3OTUsIm5iZiI6MTcyMTY4NTQ5NSwicGF0aCI6Ii8xNzA4MzE3OS8yOTQ2OTYzODQtMTg2M2JhMDUtNjAxYi00YTE3LWE3YTItOGZkNjczYjhkYTVlLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA3MjIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNzIyVDIxNTgxNVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTEzODAyNmZkYWE2MmZhYTU5YmU2NGE2MmMwZWIwNDUxZTMzYThlYzMyNDhlMDg2ZTdlNzY0NzRmNjQ3M2VkZmImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.3b9lkS0ivUNHL31b6BXJzKLhNFsnltb8wrTj0IB_T4M)
вот верный, все работает, и ты скейл пробуй не окнами хана, а Mitchell или nearest, окна хана скейлят так что тебе может показаться что там что-то не так )
from avif-coder.
Я бикубик использовал, чет на выше 400 падало
from avif-coder.
![image](https://private-user-images.githubusercontent.com/17083179/294696504-55a7daaa-5a95-4d29-b919-17a9f9dec861.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE2ODU3OTUsIm5iZiI6MTcyMTY4NTQ5NSwicGF0aCI6Ii8xNzA4MzE3OS8yOTQ2OTY1MDQtNTVhN2RhYWEtNWE5NS00ZDI5LWI5MTktMTdhOWY5ZGVjODYxLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA3MjIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNzIyVDIxNTgxNVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTQ5OGQ4MjE3NGU1YzcwNWVhZDY1N2M0YzJmZjFmMWZmMmI0MjY2MWMzMTlkYTZiZDNiNjgyZWFhNWJmNjY2YWYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.2whjW5Rpg8K68CHNARu1_qFH_XiFudMeqtdkUb6diZ4)
from avif-coder.
ахахах, я его уже поздно увидел, а когда увидел, то мне же не jxl нужно, а любую картинку
from avif-coder.
Я бикубик использовал, чет на выше 400 падало
Сделай правилньный dst stripe все работает
from avif-coder.
Related Issues (17)
- Are the prebuilt artifacts available? HOT 1
- Context in HeifCoder HOT 2
- Question HOT 5
- Add effort option HOT 1
- Cannot find package from Jitpack HOT 4
- 100% quality looks worse than 99% HOT 3
- Will it support tile encoding HOT 1
- Failed to resolve: com.github.awxkee:avif-coder:1.0.14 HOT 4
- Can the API version be adjusted to 21? HOT 5
- Compiling master encountered the following error HOT 3
- Overexposed HDR HOT 8
- Build native libs try gradle HOT 15
- Jxl support HOT 2
- Request: please put license for the repository HOT 4
- Jitpack HOT 46
- The new version doesn't work HOT 30
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from avif-coder.