mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-03 05:03:45 +00:00
lottie: Added support for rendering embedded image resource
Change-Id: I330ee46e7bccabbebe2b15b54d21582212c1f020
This commit is contained in:
parent
ecb0b9748c
commit
3db9cd3b15
1
example/resource/image_embedded.json
Executable file
1
example/resource/image_embedded.json
Executable file
File diff suppressed because one or more lines are too long
@ -23,7 +23,6 @@
|
||||
#include "vdasher.h"
|
||||
#include "vpainter.h"
|
||||
#include "vraster.h"
|
||||
#include "vimageloader.h"
|
||||
|
||||
/* Lottie Layer Rules
|
||||
* 1. time stretch is pre calculated and applied to all the properties of the
|
||||
@ -703,11 +702,8 @@ void LOTImageLayerItem::updateContent()
|
||||
// load image
|
||||
//@TODO find a better way to load
|
||||
// so that can be shared by multiple layers
|
||||
if (!mLayerData->mAsset->mImagePath.empty()) {
|
||||
VBitmap img = VImageLoader::instance().load(mLayerData->mAsset->mImagePath.c_str());
|
||||
VBrush brush(img);
|
||||
mRenderNode->setBrush(brush);
|
||||
}
|
||||
VBrush brush(mLayerData->mAsset->bitmap());
|
||||
mRenderNode->setBrush(brush);
|
||||
}
|
||||
|
||||
if (flag() & DirtyFlagBit::Matrix) {
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
|
||||
#include "lottiemodel.h"
|
||||
#include "vline.h"
|
||||
#include "vimageloader.h"
|
||||
#include <cassert>
|
||||
#include <stack>
|
||||
|
||||
@ -317,3 +318,15 @@ void LOTGradient::update(std::unique_ptr<VGradient> &grad, int frameNo)
|
||||
grad->radial.fradius = 0;
|
||||
}
|
||||
}
|
||||
|
||||
VBitmap
|
||||
LOTAsset::bitmap() const
|
||||
{
|
||||
if (!mImageData.empty()) {
|
||||
return VImageLoader::instance().load(mImageData.c_str(), mImageData.length());
|
||||
} else if (!mImagePath.empty()) {
|
||||
return VImageLoader::instance().load(mImagePath.c_str());
|
||||
} else {
|
||||
return VBitmap();
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,12 +339,12 @@ public:
|
||||
class LOTLayerData;
|
||||
struct LOTAsset
|
||||
{
|
||||
enum class Type {
|
||||
enum class Type : unsigned char{
|
||||
Precomp,
|
||||
Image,
|
||||
Char
|
||||
};
|
||||
|
||||
VBitmap bitmap() const;
|
||||
Type mAssetType{Type::Precomp};
|
||||
std::string mRefId; // ref id
|
||||
std::vector<std::shared_ptr<LOTData>> mLayers;
|
||||
@ -352,6 +352,7 @@ struct LOTAsset
|
||||
int mWidth{0};
|
||||
int mHeight{0};
|
||||
std::string mImagePath;
|
||||
std::string mImageData;
|
||||
};
|
||||
|
||||
class LOTLayerData : public LOTGroupData
|
||||
|
||||
@ -626,6 +626,56 @@ void LottieParserImpl::parseAssets(LOTCompositionData *composition)
|
||||
// update the precomp layers with the actual layer object
|
||||
}
|
||||
|
||||
static constexpr const unsigned char B64index[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0,
|
||||
0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 };
|
||||
|
||||
std::string b64decode(const void* data, const size_t len)
|
||||
{
|
||||
unsigned char* p = (unsigned char*)data;
|
||||
int pad = len > 0 && (len % 4 || p[len - 1] == '=');
|
||||
const size_t L = ((len + 3) / 4 - pad) * 4;
|
||||
std::string str(L / 4 * 3 + pad, '\0');
|
||||
|
||||
for (size_t i = 0, j = 0; i < L; i += 4)
|
||||
{
|
||||
int n = B64index[p[i]] << 18 | B64index[p[i + 1]] << 12 | B64index[p[i + 2]] << 6 | B64index[p[i + 3]];
|
||||
str[j++] = n >> 16;
|
||||
str[j++] = n >> 8 & 0xFF;
|
||||
str[j++] = n & 0xFF;
|
||||
}
|
||||
if (pad)
|
||||
{
|
||||
int n = B64index[p[L]] << 18 | B64index[p[L + 1]] << 12;
|
||||
str[str.size() - 1] = n >> 16;
|
||||
|
||||
if (len > L + 2 && p[L + 2] != '=')
|
||||
{
|
||||
n |= B64index[p[L + 2]] << 6;
|
||||
str.push_back(n >> 8 & 0xFF);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static std::string
|
||||
convertFromBase64(const std::string &str)
|
||||
{
|
||||
// usual header look like "data:image/png;base64,"
|
||||
// so need to skip till ','.
|
||||
int startIndex = str.find(",", 0);
|
||||
startIndex += 1; // skip ","
|
||||
int length = str.length() - startIndex;
|
||||
|
||||
const char *b64Data = str.c_str() + startIndex;
|
||||
|
||||
return b64decode(b64Data, length);
|
||||
}
|
||||
|
||||
/*
|
||||
* https://github.com/airbnb/lottie-web/blob/master/docs/json/layers/shape.json
|
||||
*
|
||||
@ -637,6 +687,7 @@ std::shared_ptr<LOTAsset> LottieParserImpl::parseAsset()
|
||||
LOTAsset * asset = sharedAsset.get();
|
||||
std::string filename;
|
||||
std::string relativePath;
|
||||
bool embededResource = false;
|
||||
EnterObject();
|
||||
while (const char *key = NextObjectKey()) {
|
||||
if (0 == strcmp(key, "w")) {
|
||||
@ -652,6 +703,8 @@ std::shared_ptr<LOTAsset> LottieParserImpl::parseAsset()
|
||||
} else if (0 == strcmp(key, "u")) { /* relative image path */
|
||||
RAPIDJSON_ASSERT(PeekType() == kStringType);
|
||||
relativePath = std::string(GetString());
|
||||
} else if (0 == strcmp(key, "e")) { /* relative image path */
|
||||
embededResource = GetInt();
|
||||
} else if (0 == strcmp(key, "id")) { /* reference id*/
|
||||
if (PeekType() == kStringType) {
|
||||
asset->mRefId = std::string(GetString());
|
||||
@ -674,8 +727,13 @@ std::shared_ptr<LOTAsset> LottieParserImpl::parseAsset()
|
||||
Skip(key);
|
||||
}
|
||||
}
|
||||
// its an image asset
|
||||
if (!filename.empty()) {
|
||||
|
||||
if (embededResource) {
|
||||
// embeder resource should start with "data:"
|
||||
if (filename.find("data:", 0) == 0) {
|
||||
asset->mImageData = convertFromBase64(filename);
|
||||
}
|
||||
} else {
|
||||
asset->mImagePath = mDirPath + relativePath + filename;
|
||||
}
|
||||
return sharedAsset;
|
||||
|
||||
@ -49,6 +49,13 @@ lottie_image_load(char const *filename, int *x, int *y, int *comp, int req_comp)
|
||||
return stbi_load(filename, x, y, comp, req_comp);
|
||||
}
|
||||
|
||||
LOT_EXPORT unsigned char *
|
||||
lottie_image_load_from_data(const char *imageData, int len, int *x, int *y, int *comp, int req_comp)
|
||||
{
|
||||
unsigned char *data = (unsigned char *)imageData;
|
||||
return stbi_load_from_memory(data, len, x, y, comp, req_comp);
|
||||
}
|
||||
|
||||
LOT_EXPORT void
|
||||
lottie_image_free(unsigned char *data)
|
||||
{
|
||||
|
||||
@ -3,7 +3,8 @@
|
||||
#include <dlfcn.h>
|
||||
#include <cstring>
|
||||
|
||||
using lottie_image_load_f = unsigned char* (*)(char const *filename, int *x, int *y, int *comp, int req_comp);
|
||||
using lottie_image_load_f = unsigned char* (*)(const char *filename, int *x, int *y, int *comp, int req_comp);
|
||||
using lottie_image_load_data_f = unsigned char* (*)(const char *data, int len, int *x, int *y, int *comp, int req_comp);
|
||||
using lottie_image_free_f = void (*)(unsigned char *);
|
||||
|
||||
struct VImageLoader::Impl
|
||||
@ -11,6 +12,7 @@ struct VImageLoader::Impl
|
||||
void *dl_handle{nullptr};
|
||||
lottie_image_load_f lottie_image_load{nullptr};
|
||||
lottie_image_free_f lottie_image_free{nullptr};
|
||||
lottie_image_load_data_f lottie_image_load_data{nullptr};
|
||||
|
||||
Impl()
|
||||
{
|
||||
@ -27,24 +29,19 @@ struct VImageLoader::Impl
|
||||
lottie_image_free = (lottie_image_free_f) dlsym(dl_handle, "lottie_image_free");
|
||||
if (!lottie_image_free)
|
||||
vWarning<<"Failed to find symbol lottie_image_free in librlottie-image-loader library";
|
||||
lottie_image_load_data = (lottie_image_load_data_f) dlsym(dl_handle, "lottie_image_load_from_data");
|
||||
if (!lottie_image_load_data)
|
||||
vWarning<<"Failed to find symbol lottie_image_load_data in librlottie-image-loader library";
|
||||
}
|
||||
~Impl()
|
||||
{
|
||||
if (dl_handle) dlclose(dl_handle);
|
||||
}
|
||||
VBitmap load(const char *fileName)
|
||||
|
||||
VBitmap createBitmap(unsigned char *data, int width, int height, int channel)
|
||||
{
|
||||
if (!lottie_image_load) return VBitmap();
|
||||
|
||||
int width, height, n;
|
||||
unsigned char *data = lottie_image_load(fileName, &width, &height, &n, 4);
|
||||
|
||||
if (!data) {
|
||||
return VBitmap();
|
||||
}
|
||||
|
||||
// premultiply alpha
|
||||
if (n == 4)
|
||||
if (channel == 4)
|
||||
convertToBGRAPremul(data, width, height);
|
||||
else
|
||||
convertToBGRA(data, width, height);
|
||||
@ -60,6 +57,34 @@ struct VImageLoader::Impl
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VBitmap load(const char *fileName)
|
||||
{
|
||||
if (!lottie_image_load) return VBitmap();
|
||||
|
||||
int width, height, n;
|
||||
unsigned char *data = lottie_image_load(fileName, &width, &height, &n, 4);
|
||||
|
||||
if (!data) {
|
||||
return VBitmap();
|
||||
}
|
||||
|
||||
return createBitmap(data, width, height, n);
|
||||
}
|
||||
|
||||
VBitmap load(const char *imageData, int len)
|
||||
{
|
||||
if (!lottie_image_load_data) return VBitmap();
|
||||
|
||||
int width, height, n;
|
||||
unsigned char *data = lottie_image_load_data(imageData, len, &width, &height, &n, 4);
|
||||
|
||||
if (!data) {
|
||||
return VBitmap();
|
||||
}
|
||||
|
||||
return createBitmap(data, width, height, n);
|
||||
}
|
||||
/*
|
||||
* convert from RGBA to BGRA and premultiply
|
||||
*/
|
||||
@ -114,3 +139,8 @@ VBitmap VImageLoader::load(const char *fileName)
|
||||
return mImpl->load(fileName);
|
||||
}
|
||||
|
||||
VBitmap VImageLoader::load(const char *data, int len)
|
||||
{
|
||||
return mImpl->load(data, len);
|
||||
}
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ public:
|
||||
}
|
||||
|
||||
VBitmap load(const char *fileName);
|
||||
VBitmap load(const char *data, int len);
|
||||
~VImageLoader();
|
||||
private:
|
||||
VImageLoader();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user