Giter Club home page Giter Club logo

Comments (115)

awxkee avatar awxkee commented on September 6, 2024 2

В основном, если ты 8 бит сохранишь как 10, 12, 16 размер увеличится, насколько- зависит от кодека

Можно проверить изначальный bitmap config или взять инфу о картинке и из нее битность, скорее всего в Андроиде есть готовое апи

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024 1

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.

awxkee avatar awxkee commented on September 6, 2024 1

Не, в беларуси я 3 года уже не живу

По работе переехал чтоль?

Я враг лукашенки, не переехал, а убежал )

Не может быть чтоб ты оригинальные грузил, тогда у тебя картинки с любого флагмана должны просто крашиться т.к. они очень большие

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024 1

С ндк я ваще не тютю, так что не могу сделать все там(

Пробуй, надо с чего-то начинать, базовый вариант скейла достаточно простой только для 8 бит ARGB

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024 1

Вот картинка для теста, https://backup-csh.fra1.digitaloceanspaces.com/avif10bit%20(2).avif 10 бит, должно быть 16 на андроиде или 10бит для 34+ можно, ее поворачивает крайне долго

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024 1

Вот картинка для теста, https://backup-csh.fra1.digitaloceanspaces.com/avif10bit%20(2).avif 10 бит, должно быть 16 на андроиде или 10бит для 34+ можно, ее поворачивает крайне долго

Пипец конечно, я ваще изначально прогу для себя делал, но чет стрельнула

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024 1

это 8 бит, не 32, битность изображения считается по размеру компонента, а не точке

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024 1

A - это компонент, ARGB - это цветовая точка, размерность изображения считается по компоненте, не по точке

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024 1

А, ну тогда понятно че битность теряется, пофикшу

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024 1

В этих движках шейдер часто не главная проблема, заставить банально выдать картинку другого размера от входной может быть не так просто. Vulkan удачный но его чтобы просто запустить надо около 500 строк кода, а OpenGL банально на китайских или индийских устройствах может выдавать вообще другой результат от того что ты ждешь- по этой причине я бы ( как и google если внимательно читать их рекомендации о обработке фото ) не рекомендовал их использовать вообще пока тебе они не нужны прямо по какой-то очень важной причине

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

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.

T8RIN avatar T8RIN commented on September 6, 2024

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.

T8RIN avatar T8RIN commented on September 6, 2024

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

Thanks for this explanations, i'll try and ask if something will not work

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

image
Can you explain please what is components and stride's are?

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

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.

T8RIN avatar T8RIN commented on September 6, 2024

so i can provide as stride ‘width × compents ×(size of compents)’ and not think about rounding?

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

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.

T8RIN avatar T8RIN commented on September 6, 2024

Thanks!

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Когда закончишь, я, впринципе, могу взглянуть нормально ли все у тебя вышло

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

Хорошо, а ты русский знаешь что ли? 😳

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Да, это ж не секретный язык )

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

Ты русский чтоль? Явно не через переводчик это пишешь))

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Хотя я бы рекомендовал еще раз взвесить стоит ли это того, т.к. когда ты через coil / glide грузишь картинки, они уже пересжаты, и то что ты добавишь более продвинутый алгоритм на пересжатие еще раз врятли даст действительно стоящий результат

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Я беларус

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

Я беларус

Пипец, а живешь не там, да?

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Не, в беларуси я 3 года уже не живу

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

Хотя я бы рекомендовал еще раз взвесить стоит ли это того, т.к. когда ты через coil / glide грузишь картинки, они уже пересжаты, и то что ты добавишь более продвинутый алгоритм на пересжатие еще раз врятли даст действительно стоящий результат

У меня ж для работы с картинками прога, я изначально гружу картинку в оригинальном разрешении, и можно ее сжать/увеличить, так что норм должно быть, попросили прост чет кроме билинейного скейлинга добавить на выбор

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

Не, в беларуси я 3 года уже не живу

По работе переехал чтоль?

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

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

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

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

Нене, я показываю в качестве превью засемпленный вариант, а когда чел сохраняет, то я полноразмерную битмапу гружу, но потому что я ее не показываю, то не крешится, хотя конечно если 12к*12к и выше то может крешнуться, вот тут ваще хз как убрать это ограничение андроида, ток если все добро на ндк перенести, но я больше по котлину чем по плюсам 🐸

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Даже в самом "оптимистичном" случае если тебя пропустила JVM и ты загрузил картинку как HARDWARE андроид не допускает отрисовки картинки больше чем 104МБ в памяти, это RGBA 16bit максимум 3.6kx3.6k, или 8bit умножь размер RGBA на 2

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

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

Нене, я показываю в качестве превью засемпленный вариант, а когда чел сохраняет, то я полноразмерную битмапу гружу, но потому что я ее не показываю, то не крешится, хотя конечно если 12к*12к и выше то может крешнуться, вот тут ваще хз как убрать это ограничение андроида, ток если все добро на ндк перенести, но я больше по котлину чем по плюсам 🐸

Я тебе кажется писал уже, только сохранять все твои преобразования на превью, и потом трансформировать их в оригинал в NDK. Либо искуственно обрезать картинку чтобы она никогда не была больше 100МБ

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

Даже в самом "оптимистичном" случае если тебя пропустила JVM и ты загрузил картинку как HARDWARE андроид не допускает отрисовки картинки больше чем 104МБ в памяти, это RGBA 16bit максимум 3.6kx3.6k, или 8bit умножь размер RGBA на 2

А вроде у меня запрет на хардвер битмапы стоит

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

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

Нене, я показываю в качестве превью засемпленный вариант, а когда чел сохраняет, то я полноразмерную битмапу гружу, но потому что я ее не показываю, то не крешится, хотя конечно если 12к*12к и выше то может крешнуться, вот тут ваще хз как убрать это ограничение андроида, ток если все добро на ндк перенести, но я больше по котлину чем по плюсам 🐸

Если так то - делай, правда все равно билинейный алгоритм самый оптимальный, ланцош хорош только когда ты уменьшаешь больше чем на 30-40%, а сплайны только когда картинка увеличивается хотя бы на 40%

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

Спокойно пережимает 10к на 10к, можешь щас чекнуть даж👀

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

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

Нене, я показываю в качестве превью засемпленный вариант, а когда чел сохраняет, то я полноразмерную битмапу гружу, но потому что я ее не показываю, то не крешится, хотя конечно если 12к*12к и выше то может крешнуться, вот тут ваще хз как убрать это ограничение андроида, ток если все добро на ндк перенести, но я больше по котлину чем по плюсам 🐸

Я тебе кажется писал уже, только сохранять все твои преобразования на превью, и потом трансформировать их в оригинал в NDK. Либо искуственно обрезать картинку чтобы она никогда не была больше 100МБ

Ну, у меня примерно так и происходит, но я не на ндк делаю, а в джвм, от того и проблемы если картинка большая уже слишком

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

С ндк я ваще не тютю, так что не могу сделать все там(

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

И правда жмет, только поворот на больших картинках длиться по пол минуты, и оно дает во время поворота сохранять и 16 битные картинки стали 8 бит

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

И правда жмет, только поворот на больших картинках длиться по пол минуты, и оно дает во время поворота сохранять и 16 битные картинки стали 8 бит

Вот кста про 16 бит и 8 я хз, по-моему у меня это не предусмотрено, а че там надо в конструктор битмапы передавать, чтобы битность указать ARGB8888 это 32 бит ж ваще

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

С ндк я ваще не тютю, так что не могу сделать все там(

Пробуй, надо с чего-то начинать, базовый вариант скейла достаточно простой только для 8 бит ARGB

Во, седня-завтра хоть скейлер попробую написать с твоих либ, уже что-то

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

И правда жмет, только поворот на больших картинках длиться по пол минуты, и оно дает во время поворота сохранять и 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.

T8RIN avatar T8RIN commented on September 6, 2024

Так, окей, а зачем тогда 32 битная вариация есть?

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

32 битная? Я о такой не слышал на телефоне, ну в теории можно в JXL какую угодно глубину цвета вбить, типа карты геоместности ( там карты глубин ) или сьемки космоса ( там тоже соотвественно карты глубин ), но это уже какая-то достаточно научная штука, не думаю что она нужна

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

ARGB_8888 в конфиге как раз

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

По-моему как будто по дефолту даж она стоит, или я не понимаю чет и это 8 бит?👀

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

А кстати, если у картинки изначально было 8 бит, я же не пойму это, так как по дефолту буду грузить больше бит чем надо, и сохранять по сути тоже, тип если я 8 битную сохраню как 16 бит, то размер не увеличится?

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Есть еще опция можешь на сам сделать скейл на Vulkan или OpenGL, вероятно ты найдешь такие предложения, для огромных картинок он будет в 2-3 раза быстрее чем в на c++, только надо апи 26+ вроде, научиться писать шейдеры и доступ к Vulkan все равно только с c++, он будет действительно быстрый, но из-за архи сложной конфигурации Vulkan и OpenGL и если ты не знаком с шейдерами- не рекомендую

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Хотя OpenGL можно в теории и без ndk сделать

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

С шейдерами то знаком, но ток с тем как их использовать готовые, сам писать не дорос ))

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

И есть опция opencv, там нету всех моих опций, зато есть куча готовых либ на андроид, и все встроиться минут за 15, ценой плюс 15-20мб к каждому бинарнику

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

https://docs.opencv.org/4.x/da/d54/group__imgproc__transform.html

Конечно opencv ради скейла это стрелять из пушки по воробьям, но если ты не хочешь погружаться в ndk это самая крутая опция

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

Open Cv весит дофига еще, в этом тож проблема

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

У меня опенгл ток для фильтров из gpuimage

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

написал такую поделку, будет работать?

#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.

awxkee avatar awxkee commented on September 6, 2024

У меня опенгл ток для фильтров из gpuimage

Интерестно, мало того что старый опенгл, насколько я помню он же грузит тоже превью и рендерит его на экран чтобы обработать? Или ты доделывал это?

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

У меня он ток в качестве наложения фильтров на битмап, показываю все так же через коил, точнее на уменьшенную картинку фильтры накалываю

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

написал такую поделку, будет работать?

#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.

awxkee avatar awxkee commented on September 6, 2024

SetByteArrayRegion Лучше никогда не использовать, он ограничен jvm 20-30мб, надо копировать пиксели напрямую

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

епересете, а поч тогда у тебя так в jxl кодере написано?

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Это либо баг у меня, либо ты что-то не до копировал)

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

да вроде все

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

image

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Понятно, ты бы лучше декодер смотрел чем кодер, в энкодере финальный размер практически никогда в Jxl не будет 20мб+, по-этому тут я это проигнорировал

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

И здесь потом в encoder передается параметр usefloat16 чтобы он знал какой тип данных используется

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

Емае..., ща поправлю

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Тебе нужно перевести картинку в 1 из поддерживаемых типов данных 8bit/16bit, пересжать ее, затем создать/скопировать либо в битмап с 8/16 бит, или конвертировать назад в исходный формат пикселей

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

лучше в байт аррей, мне так проще с ней потом будет

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

С байт арреем будут проблемы с jvm, без вариантов

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

ну а битмап все равно из него создается ж

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Нет, если ты создаешь битмап в ndk, то само содержание картинки никогда не попадает в jvm, в этом и весь смысл обработки картинок без ограничений в ndk, как только ты создаешь байт аррей ты попадаешь в jvm

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

а вектор пикселей это не байт аррей ?

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

а вектор пикселей это не байт аррей ?

Нет, это нативная память, и bitmap хранит в себе ссылку по сути, на такой же вектор, они могут расширяться пока на телефоне память не кончиться, и ты можешь скопировать 1 в другой беж ограничений. А ты хочешь создать еще джава аррей, скопировать в него, а потом из него в Буффер битмапа

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

аа, чет понимать начал

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

поделка 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.

awxkee avatar awxkee commented on September 6, 2024

If usefloat16 scaleImageU8 то ее надо на 16 битный аналог поменять ведь

и free(addr) вроде лишнее, unlock pixels сам освободить должен

остальное с большего похоже, позже я внимательней посмотрю

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

А вот 16 битный аналог требует 16 битный вектор, а у тебя там везде 8 бит ток есть

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Это c++, там везде стоит uint8_t, но это не значит что там и правда uint8_t, сделай reinterpret_cast до uint16_t

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

ахах, окей, а что делать с depth? там в 16 битном аналоге нет его

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

А 16 half float всегда 16 бит подразумевается а сама битность не важна потому что это нормализованные числа [0,1] ( в случае hdr больше 1)

Битность нужна для 16 бит разрядности только когда данные в uint16 типе, а не с нормализованные с плавающей точкой

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

хорошо, чет вылетает почему-то при попытке показать картинку

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

эт почему может быть ?
image

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Перед вторым AndroidBitmap_lockPixels запиши addr = nullptr

Еще ты там в scale передаешь info.format, мне кажется это тоже неправильно

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

info.format

8 битная версия просит depth это ж по-моему есть енам значение формата

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

info.format

8 битная версия просит depth это ж по-моему есть енам значение формата

Я думаю это неправильно, поставь лучше цифрой 8

эт почему может быть ? image

Буффер Неверный или hardware bitmap

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

а кста зачем 8 битной функции глубину, если туда 8 бит по умолчанию пойдет

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

возможно хардвер да

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

Так, заработало, но чет фигню какую-то выдало

Screenshot_20240106-170318.png

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

а кста зачем 8 битной функции глубину, если туда 8 бит по умолчанию пойдет

В теории она может сжимать и 6 бит картинки, ни все равно будут храниться в 8

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

а, понял

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

Попробовал побольше поставить выходной размер и упало вообще (Было 200200 стало 500500)

image

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Так, заработало, но чет фигню какую-то выдало

Screenshot_20240106-170318.png

С размерами картинок где-то не так, скорее всего размеры ты где-то не верно передал

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

а где... чет вроде все как надо

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Закоммить куда-нибудь, у меня есть возможность посмотреть

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

оке, щас как форк сделаю

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

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.

awxkee avatar awxkee commented on September 6, 2024
image а чем тебе он не подошел? ) image твой bitmappixelconfig никогда не будет 565

Все верно сделано, кроме расчета dstStride

image

вот верный, все работает, и ты скейл пробуй не окнами хана, а Mitchell или nearest, окна хана скейлят так что тебе может показаться что там что-то не так )

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

Я бикубик использовал, чет на выше 400 падало

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024
image и тут лучше занулять всегда, у меня нету зануления, но это скорее недоработка, но и не баг

from avif-coder.

T8RIN avatar T8RIN commented on September 6, 2024

image а чем тебе он не подошел? )

ахахах, я его уже поздно увидел, а когда увидел, то мне же не jxl нужно, а любую картинку

from avif-coder.

awxkee avatar awxkee commented on September 6, 2024

Я бикубик использовал, чет на выше 400 падало

Сделай правилньный dst stripe все работает

from avif-coder.

Related Issues (17)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.