Closed Aghajari closed 5 years ago
Yes, it is. Build the library from source. Instructions see in README.md
can you build it please? :) @mymedia2
@Aghajari, You need to build it for your particular platform/OS. If you tell me what is your use case maybe I can send you steps to build and use it in your system.
@smohantty I want to use this lib in android. The lottie lib in java is really slow when i load 3 file together and i know telegram is using your lib. But i can't work with c++. Thanks for your answer.
@Aghajari , As you want to build this c++ library and package it in android . you have to work with the android studio. Luckily rlottie comes with cmake build system. So the process looks simple follow the guideline in the link below. https://developer.android.com/studio/projects/add-native-code
Note: I haven't tried it yet (coz i don't have a android studio setup)
just copy the rlottie folder to your app folder and rename it to cpp . and in the sdk tool section of android studio enable LLDB and cmake as mentioned in the above link.
Android Studio will take care of building the library and include it in your package.
Let me know if you still face some issue.
@smohantty hello again. everything works fine but the color of Lottie file is not correct. online Lottie previewer show correct color.
@Aghajari , Is the color difference for all the resource or some of the resource ? Could you send a sample resource which has the problem (lottiefiles link will also do )
@smohantty , I think my code should be wrong. all resources are wrong. for ex. the example/heart.json is purple this is my sticker : https://ufile.io/mssjgco2 original color : RED , but I see purple again.
Telegram codes :
#include <jni.h>
#include <android/bitmap.h>
#include <cstring>
#include "lz4/lz4.h"
#include <unistd.h>
#include <pthread.h>
#include "c_utils.h"
#include "inc/rlottie.h"
extern "C" {
using namespace rlottie;
typedef struct LottieInfo {
~LottieInfo() {
if (decompressBuffer != nullptr) {
delete[]decompressBuffer;
decompressBuffer = nullptr;
}
}
std::unique_ptr<Animation> animation;
size_t frameCount = 0;
int32_t fps = 30;
bool precache = false;
bool createCache = false;
std::string path;
std::string cacheFile;
uint8_t *decompressBuffer = nullptr;
uint32_t maxFrameSize = 0;
uint32_t imageSize = 0;
uint32_t fileOffset = 0;
bool nextFrameIsCacheFrame = false;
};
jlong Java_com_aghajari_lottie_RLottieDrawable_create(JNIEnv *env, jclass clazz, jstring src, jintArray data, jboolean precache) {
LottieInfo *info = new LottieInfo();
char const *srcString = env->GetStringUTFChars(src, 0);
info->path = srcString;
info->animation = rlottie::Animation::loadFromFile(info->path);
if (srcString != 0) {
env->ReleaseStringUTFChars(src, srcString);
}
if (info->animation == nullptr) {
delete info;
return 0;
}
info->frameCount = info->animation->totalFrame();
info->fps = (int) info->animation->frameRate();
if (info->fps > 60 || info->frameCount > 600) {
delete info;
return 0;
}
info->precache = precache;
if (info->precache) {
info->cacheFile = info->path;
info->cacheFile += ".cache";
FILE *precacheFile = fopen(info->cacheFile.c_str(), "r+");
if (precacheFile == nullptr) {
info->createCache = true;
} else {
uint8_t temp;
size_t read = fread(&temp, sizeof(uint8_t), 1, precacheFile);
info->createCache = read != 1 || temp == 0;
if (!info->createCache) {
fread(&(info->maxFrameSize), sizeof(uint32_t), 1, precacheFile);
fread(&(info->imageSize), sizeof(uint32_t), 1, precacheFile);
info->fileOffset = 9;
}
fclose(precacheFile);
}
}
jint *dataArr = env->GetIntArrayElements(data, 0);
if (dataArr != nullptr) {
dataArr[0] = (jint) info->frameCount;
dataArr[1] = (jint) info->animation->frameRate();
dataArr[2] = info->createCache ? 1 : 0;
env->ReleaseIntArrayElements(data, dataArr, 0);
}
return (jlong) (intptr_t) info;
}
jlong Java_com_aghajari_lottie_RLottieDrawable_createWithJson(JNIEnv *env, jclass clazz, jstring json, jstring name, jintArray data) {
LottieInfo *info = new LottieInfo();
char const *jsonString = env->GetStringUTFChars(json, 0);
char const *nameString = env->GetStringUTFChars(name, 0);
info->animation = rlottie::Animation::loadFromData(jsonString, nameString);
if (jsonString != 0) {
env->ReleaseStringUTFChars(json, jsonString);
}
if (nameString != 0) {
env->ReleaseStringUTFChars(name, nameString);
}
if (info->animation == nullptr) {
delete info;
return 0;
}
info->frameCount = info->animation->totalFrame();
info->fps = (int) info->animation->frameRate();
jint *dataArr = env->GetIntArrayElements(data, 0);
if (dataArr != nullptr) {
dataArr[0] = (int) info->frameCount;
dataArr[1] = (int) info->animation->frameRate();
dataArr[2] = 0;
env->ReleaseIntArrayElements(data, dataArr, 0);
}
return (jlong) (intptr_t) info;
}
void Java_com_aghajari_lottie_RLottieDrawable_destroy(JNIEnv *env, jclass clazz, jlong ptr) {
if (ptr == NULL) {
return;
}
LottieInfo *info = (LottieInfo *) (intptr_t) ptr;
delete info;
}
void Java_com_aghajari_lottie_RLottieDrawable_setLayerColor(JNIEnv *env, jclass clazz, jlong ptr, jstring layer, jint color) {
if (ptr == NULL || layer == nullptr) {
return;
}
LottieInfo *info = (LottieInfo *) (intptr_t) ptr;
char const *layerString = env->GetStringUTFChars(layer, 0);
info->animation->setValue<Property::FillColor>(layerString, Color(((color) & 0xff) / 255.0f, ((color >> 8) & 0xff) / 255.0f, ((color >> 16) & 0xff) / 255.0f));
if (layerString != 0) {
env->ReleaseStringUTFChars(layer, layerString);
}
}
void Java_com_aghajari_lottie_RLottieDrawable_createCache(JNIEnv *env, jclass clazz, jlong ptr, jobject bitmap, jint w, jint h, jint stride) {
if (ptr == NULL || bitmap == nullptr) {
return;
}
LottieInfo *info = (LottieInfo *) (intptr_t) ptr;
FILE *precacheFile = fopen(info->cacheFile.c_str(), "r+");
if (precacheFile != nullptr) {
uint8_t temp;
size_t read = fread(&temp, sizeof(uint8_t), 1, precacheFile);
fclose(precacheFile);
if (read == 1 && temp != 0) {
return;
}
}
void *pixels;
if (info->nextFrameIsCacheFrame && info->createCache && info->frameCount != 0 && w * 4 == stride && AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0) {
precacheFile = fopen(info->cacheFile.c_str(), "w+");
if (precacheFile != nullptr) {
fseek(precacheFile, info->fileOffset = 9, SEEK_SET);
uint32_t size;
uint32_t firstFrameSize = 0;
info->maxFrameSize = 0;
int bound = LZ4_compressBound(w * h * 4);
uint8_t *compressBuffer = new uint8_t[bound];
Surface surface((uint32_t *) pixels, (size_t) w, (size_t) h, (size_t) stride);
//int64_t time = ConnectionsManager::getInstance(0).getCurrentTimeMillis();
//int totalSize = 0;
int framesPerUpdate = info->fps < 60 ? 1 : 2;
for (size_t a = 0; a < info->frameCount; a += framesPerUpdate) {
info->animation->renderSync(a, surface);
size = (uint32_t) LZ4_compress_default((const char *) pixels, (char *) compressBuffer, w * h * 4, bound);
//totalSize += size;
if (a == 0) {
firstFrameSize = size;
}
info->maxFrameSize = MAX(info->maxFrameSize, size);
fwrite(&size, sizeof(uint32_t), 1, precacheFile);
fwrite(compressBuffer, sizeof(uint8_t), size, precacheFile);
}
delete[] compressBuffer;
//DEBUG_D("total size %s = %d, time = %lld ms", info->path.c_str(), totalSize, (ConnectionsManager::getInstance(0).getCurrentTimeMillis() - time));
fseek(precacheFile, 0, SEEK_SET);
uint8_t byte = 1;
info->imageSize = (uint32_t) w * h * 4;
fwrite(&byte, sizeof(uint8_t), 1, precacheFile);
fwrite(&info->maxFrameSize, sizeof(uint32_t), 1, precacheFile);
fwrite(&info->imageSize, sizeof(uint32_t), 1, precacheFile);
fflush(precacheFile);
int fd = fileno(precacheFile);
fsync(fd);
info->createCache = false;
info->fileOffset = 9 + sizeof(uint32_t) + firstFrameSize;
fclose(precacheFile);
}
AndroidBitmap_unlockPixels(env, bitmap);
}
}
jint Java_com_aghajari_lottie_RLottieDrawable_getFrame(JNIEnv *env, jclass clazz, jlong ptr, jint frame, jobject bitmap, jint w, jint h, jint stride) {
if (ptr == NULL || bitmap == nullptr) {
return 0;
}
LottieInfo *info = (LottieInfo *) (intptr_t) ptr;
void *pixels;
if (AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0) {
bool loadedFromCache = false;
if (info->precache && !info->createCache && w * 4 == stride && info->maxFrameSize <= w * h * 4 && info->imageSize == w * h * 4) {
FILE *precacheFile = fopen(info->cacheFile.c_str(), "r");
if (precacheFile != nullptr) {
fseek(precacheFile, info->fileOffset, SEEK_SET);
if (info->decompressBuffer == nullptr) {
info->decompressBuffer = new uint8_t[info->maxFrameSize];
}
uint32_t frameSize;
fread(&frameSize, sizeof(uint32_t), 1, precacheFile);
if (frameSize <= info->maxFrameSize) {
fread(info->decompressBuffer, sizeof(uint8_t), frameSize, precacheFile);
info->fileOffset += 4 + frameSize;
LZ4_decompress_safe((const char *) info->decompressBuffer, (char *) pixels, frameSize, w * h * 4);
loadedFromCache = true;
}
fclose(precacheFile);
int framesPerUpdate = info->fps < 60 ? 1 : 2;
if (frame + framesPerUpdate >= info->frameCount) {
info->fileOffset = 9;
}
}
}
if (!loadedFromCache) {
Surface surface((uint32_t *) pixels, (size_t) w, (size_t) h, (size_t) stride);
info->animation->renderSync((size_t) frame, surface);
info->nextFrameIsCacheFrame = true;
}
AndroidBitmap_unlockPixels(env, bitmap);
}
return frame;
}
}
NOTE : I didn't use setLayerColor.
Solved rlottie renders bgra, android uses argb
@Aghajari , rlottie always renders in ARGB32_Premultiplied format.
please check if you have set property setPremultiplied(true) on your android bitmap.
let me know if that helps.
@smohantty , can you check this link please? https://github.com/DrKLO/Telegram/tree/master/TMessagesProj/jni/rlottie
I can't compile this code when I replace tlg rLottie files. I don't know what did they change
@smohantty , finally I fixed it :) 😎 just need remove one line in vector/CMakeLists.txt :) thanks for your support. ❤️
@Aghajari No problem :) If the color issue is fixed you can close the issue .
@smohantty , finally I fixed it :) 😎 just need remove one line in vector/CMakeLists.txt :) thanks for your support. ❤️
I'm coming across the same issue about color. Can you tell me which line you removed?
I'm coming accross the same issue about color. Can you tell me which line you removed?
Hi @sonphan12 Check this AXrLottie
I'm coming accross the same issue about color. Can you tell me which line you removed?
Hi @sonphan12 Check this AXrLottie
Hi @Aghajari , AXrLottie works fine without any issues about color. But it uses an older version of rlottie. I'm using the newest version of rlottie and red is now shown as purple. Can you help me out with a little more detail? Thank you!
The issue happens only on the last updated rlottie lib code, the older version on telegram works fine. Can you help me out please @smohantty ? I'm testing on Android arm.
AXrLottie updated to 1.0.2 / synced with the latest version of rlottie from now on you can use markers too.
Thanks @smohantty
Sometimes i need to know the layer's type, or may we wanted to change the properties of a layer which the type of layer is not model::Layer::Type::Precomp
.
so i've edited the Layer class in lottiemodel.h
bool precompLayer() const {
return true; // Allows update the layer for all of the types
//return mLayerType == Type::Precomp;
}
maybe this is a wrong way, i don't know, but it works for now
and some other changes to get layer type in rlottie::layers()
:
inc\rlottie.h
:
using LayerInfoList = std::vector<std::tuple<std::string, int , int, int>>;
lottiemodel.h
using LayerInfo = std::tuple<std::string, int, int, int>;
lottiemodel.cpp
std::vector<LayerInfo> model::Composition::layerInfoList() const
{
if (!mRootLayer || mRootLayer->mChildren.empty()) return {};
std::vector<LayerInfo> result;
result.reserve(mRootLayer->mChildren.size());
for (auto it : mRootLayer->mChildren) {
auto layer = static_cast<model::Layer *>(it);
result.emplace_back(layer->name(), layer->mInFrame, layer->mOutFrame, static_cast<std::underlying_type<model::Layer::Type>::type>(layer->mLayerType));
}
return result;
}
so, if you can, keep this in mind for the next update.
And one more thing, is there anyway to get the default layer properties value? such as the default color,rotation,position,scale,... and also can we get&change the text of a Text Layer?
is there any way to build lib and release so lib?