mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-09 06:04:03 +00:00
lottie/slot: Support image overriding
This commit is contained in:
parent
ce3bee7a3f
commit
98fbc90f9b
6 changed files with 101 additions and 44 deletions
|
@ -61,8 +61,6 @@ void LottieLoader::release()
|
||||||
free((char*)content);
|
free((char*)content);
|
||||||
content = nullptr;
|
content = nullptr;
|
||||||
}
|
}
|
||||||
free(dirName);
|
|
||||||
dirName = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,6 +83,8 @@ LottieLoader::~LottieLoader()
|
||||||
//TODO: correct position?
|
//TODO: correct position?
|
||||||
delete(comp);
|
delete(comp);
|
||||||
delete(builder);
|
delete(builder);
|
||||||
|
|
||||||
|
free(dirName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,14 @@ void LottieSlot::reset()
|
||||||
static_cast<LottieTextDoc*>(pair->prop)->frames = nullptr;
|
static_cast<LottieTextDoc*>(pair->prop)->frames = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case LottieProperty::Type::Image: {
|
||||||
|
static_cast<LottieImage*>(pair->obj)->data.release();
|
||||||
|
static_cast<LottieImage*>(pair->obj)->data = *static_cast<LottieBitmap*>(pair->prop);
|
||||||
|
static_cast<LottieBitmap*>(pair->prop)->b64Data = nullptr;
|
||||||
|
static_cast<LottieBitmap*>(pair->prop)->mimeType = nullptr;
|
||||||
|
static_cast<LottieImage*>(pair->obj)->prepare();
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
delete(pair->prop);
|
delete(pair->prop);
|
||||||
|
@ -108,6 +116,14 @@ void LottieSlot::assign(LottieObject* target)
|
||||||
pair->obj->override(&static_cast<LottieText*>(target)->doc);
|
pair->obj->override(&static_cast<LottieText*>(target)->doc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case LottieProperty::Type::Image: {
|
||||||
|
if (!overridden) {
|
||||||
|
pair->prop = new LottieBitmap;
|
||||||
|
*static_cast<LottieBitmap*>(pair->prop) = static_cast<LottieImage*>(pair->obj)->data;
|
||||||
|
}
|
||||||
|
pair->obj->override(&static_cast<LottieImage*>(target)->data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,13 +168,6 @@ float LottieTextRange::factor(float frameNo, float totalLen, float idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LottieImage::~LottieImage()
|
|
||||||
{
|
|
||||||
free(b64Data);
|
|
||||||
free(mimeType);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LottieImage::prepare()
|
void LottieImage::prepare()
|
||||||
{
|
{
|
||||||
LottieObject::type = LottieObject::Image;
|
LottieObject::type = LottieObject::Image;
|
||||||
|
@ -168,14 +177,15 @@ void LottieImage::prepare()
|
||||||
//force to load a picture on the same thread
|
//force to load a picture on the same thread
|
||||||
TaskScheduler::async(false);
|
TaskScheduler::async(false);
|
||||||
|
|
||||||
if (size > 0) picture->load((const char*)b64Data, size, mimeType, false);
|
if (data.size > 0) picture->load((const char*)data.b64Data, data.size, data.mimeType, false);
|
||||||
else picture->load(path);
|
else picture->load(data.path);
|
||||||
|
|
||||||
TaskScheduler::async(true);
|
TaskScheduler::async(true);
|
||||||
|
|
||||||
picture->size(width, height);
|
picture->size(data.width, data.height);
|
||||||
PP(picture)->ref();
|
PP(picture)->ref();
|
||||||
|
|
||||||
|
pooler.reset();
|
||||||
pooler.push(picture);
|
pooler.push(picture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -649,16 +649,14 @@ struct LottieGradientStroke : LottieGradient, LottieStroke
|
||||||
|
|
||||||
struct LottieImage : LottieObject, LottieRenderPooler<tvg::Picture>
|
struct LottieImage : LottieObject, LottieRenderPooler<tvg::Picture>
|
||||||
{
|
{
|
||||||
union {
|
LottieBitmap data;
|
||||||
char* b64Data = nullptr;
|
|
||||||
char* path;
|
void override(LottieProperty* prop) override
|
||||||
};
|
{
|
||||||
char* mimeType = nullptr;
|
this->data = *static_cast<LottieBitmap*>(prop);
|
||||||
uint32_t size = 0;
|
this->prepare();
|
||||||
float width = 0.0f;
|
}
|
||||||
float height = 0.0f;
|
|
||||||
|
|
||||||
~LottieImage();
|
|
||||||
void prepare();
|
void prepare();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -486,10 +486,8 @@ void LottieParser::parsePropertyInternal(T& prop)
|
||||||
|
|
||||||
|
|
||||||
template<LottieProperty::Type type>
|
template<LottieProperty::Type type>
|
||||||
void LottieParser::registerSlot(LottieObject* obj)
|
void LottieParser::registerSlot(LottieObject* obj, char* sid)
|
||||||
{
|
{
|
||||||
auto sid = getStringCopy();
|
|
||||||
|
|
||||||
//append object if the slot already exists.
|
//append object if the slot already exists.
|
||||||
for (auto slot = comp->slots.begin(); slot < comp->slots.end(); ++slot) {
|
for (auto slot = comp->slots.begin(); slot < comp->slots.end(); ++slot) {
|
||||||
if (strcmp((*slot)->sid, sid)) continue;
|
if (strcmp((*slot)->sid, sid)) continue;
|
||||||
|
@ -506,7 +504,7 @@ void LottieParser::parseProperty(T& prop, LottieObject* obj)
|
||||||
enterObject();
|
enterObject();
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (KEY_AS("k")) parsePropertyInternal(prop);
|
if (KEY_AS("k")) parsePropertyInternal(prop);
|
||||||
else if (obj && KEY_AS("sid")) registerSlot<type>(obj);
|
else if (obj && KEY_AS("sid")) registerSlot<type>(obj, getStringCopy());
|
||||||
else if (KEY_AS("x")) prop.exp = _expression(getStringCopy(), comp, context.layer, context.parent, &prop);
|
else if (KEY_AS("x")) prop.exp = _expression(getStringCopy(), comp, context.layer, context.parent, &prop);
|
||||||
else if (KEY_AS("ix")) prop.ix = getInt();
|
else if (KEY_AS("ix")) prop.ix = getInt();
|
||||||
else skip(key);
|
else skip(key);
|
||||||
|
@ -761,7 +759,7 @@ void LottieParser::parseColorStop(LottieGradient* gradient)
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (KEY_AS("p")) gradient->colorStops.count = getInt();
|
if (KEY_AS("p")) gradient->colorStops.count = getInt();
|
||||||
else if (KEY_AS("k")) parseProperty<LottieProperty::Type::ColorStop>(gradient->colorStops, gradient);
|
else if (KEY_AS("k")) parseProperty<LottieProperty::Type::ColorStop>(gradient->colorStops, gradient);
|
||||||
else if (KEY_AS("sid")) registerSlot<LottieProperty::Type::ColorStop>(gradient);
|
else if (KEY_AS("sid")) registerSlot<LottieProperty::Type::ColorStop>(gradient, getStringCopy());
|
||||||
else skip(key);
|
else skip(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -931,45 +929,39 @@ void LottieParser::parseObject(Array<LottieObject*>& parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LottieImage* LottieParser::parseImage(const char* data, const char* subPath, bool embedded, float width, float height)
|
void LottieParser::parseImage(LottieImage* image, const char* data, const char* subPath, bool embedded, float width, float height)
|
||||||
{
|
{
|
||||||
//Used for Image Asset
|
|
||||||
auto image = new LottieImage;
|
|
||||||
|
|
||||||
//embedded image resource. should start with "data:"
|
//embedded image resource. should start with "data:"
|
||||||
//header look like "data:image/png;base64," so need to skip till ','.
|
//header look like "data:image/png;base64," so need to skip till ','.
|
||||||
if (embedded && !strncmp(data, "data:", 5)) {
|
if (embedded && !strncmp(data, "data:", 5)) {
|
||||||
//figure out the mimetype
|
//figure out the mimetype
|
||||||
auto mimeType = data + 11;
|
auto mimeType = data + 11;
|
||||||
auto needle = strstr(mimeType, ";");
|
auto needle = strstr(mimeType, ";");
|
||||||
image->mimeType = strDuplicate(mimeType, needle - mimeType);
|
image->data.mimeType = strDuplicate(mimeType, needle - mimeType);
|
||||||
//b64 data
|
//b64 data
|
||||||
auto b64Data = strstr(data, ",") + 1;
|
auto b64Data = strstr(data, ",") + 1;
|
||||||
size_t length = strlen(data) - (b64Data - data);
|
size_t length = strlen(data) - (b64Data - data);
|
||||||
image->size = b64Decode(b64Data, length, &image->b64Data);
|
image->data.size = b64Decode(b64Data, length, &image->data.b64Data);
|
||||||
//external image resource
|
//external image resource
|
||||||
} else {
|
} else {
|
||||||
auto len = strlen(dirName) + strlen(subPath) + strlen(data) + 1;
|
auto len = strlen(dirName) + strlen(subPath) + strlen(data) + 1;
|
||||||
image->path = static_cast<char*>(malloc(len));
|
image->data.path = static_cast<char*>(malloc(len));
|
||||||
snprintf(image->path, len, "%s%s%s", dirName, subPath, data);
|
snprintf(image->data.path, len, "%s%s%s", dirName, subPath, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
image->width = width;
|
image->data.width = width;
|
||||||
image->height = height;
|
image->data.height = height;
|
||||||
image->prepare();
|
image->prepare();
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LottieObject* LottieParser::parseAsset()
|
LottieObject* LottieParser::parseAsset()
|
||||||
{
|
{
|
||||||
enterObject();
|
|
||||||
|
|
||||||
LottieObject* obj = nullptr;
|
LottieObject* obj = nullptr;
|
||||||
unsigned long id = 0;
|
unsigned long id = 0;
|
||||||
|
|
||||||
//Used for Image Asset
|
//Used for Image Asset
|
||||||
|
char* sid = nullptr;
|
||||||
const char* data = nullptr;
|
const char* data = nullptr;
|
||||||
const char* subPath = nullptr;
|
const char* subPath = nullptr;
|
||||||
float width = 0.0f;
|
float width = 0.0f;
|
||||||
|
@ -991,9 +983,14 @@ LottieObject* LottieParser::parseAsset()
|
||||||
else if (KEY_AS("w")) width = getFloat();
|
else if (KEY_AS("w")) width = getFloat();
|
||||||
else if (KEY_AS("h")) height = getFloat();
|
else if (KEY_AS("h")) height = getFloat();
|
||||||
else if (KEY_AS("e")) embedded = getInt();
|
else if (KEY_AS("e")) embedded = getInt();
|
||||||
|
else if (KEY_AS("sid")) sid = getStringCopy();
|
||||||
else skip(key);
|
else skip(key);
|
||||||
}
|
}
|
||||||
if (data) obj = parseImage(data, subPath, embedded, width, height);
|
if (data) {
|
||||||
|
obj = new LottieImage;
|
||||||
|
parseImage(static_cast<LottieImage*>(obj), data, subPath, embedded, width, height);
|
||||||
|
if (sid) registerSlot<LottieProperty::Type::Image>(obj, sid);
|
||||||
|
}
|
||||||
if (obj) obj->id = id;
|
if (obj) obj->id = id;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
@ -1021,6 +1018,7 @@ void LottieParser::parseAssets()
|
||||||
{
|
{
|
||||||
enterArray();
|
enterArray();
|
||||||
while (nextArrayValue()) {
|
while (nextArrayValue()) {
|
||||||
|
enterObject();
|
||||||
auto asset = parseAsset();
|
auto asset = parseAsset();
|
||||||
if (asset) comp->assets.push(asset);
|
if (asset) comp->assets.push(asset);
|
||||||
else TVGERR("LOTTIE", "Invalid Asset!");
|
else TVGERR("LOTTIE", "Invalid Asset!");
|
||||||
|
@ -1478,6 +1476,11 @@ bool LottieParser::apply(LottieSlot* slot)
|
||||||
parseSlotProperty<LottieProperty::Type::TextDoc>(static_cast<LottieText*>(obj)->doc);
|
parseSlotProperty<LottieProperty::Type::TextDoc>(static_cast<LottieText*>(obj)->doc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case LottieProperty::Type::Image: {
|
||||||
|
obj = parseAsset();
|
||||||
|
context.parent = obj;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
bool apply(LottieSlot* slot);
|
bool apply(LottieSlot* slot);
|
||||||
const char* sid(bool first = false);
|
const char* sid(bool first = false);
|
||||||
void captureSlots(const char* key);
|
void captureSlots(const char* key);
|
||||||
template<LottieProperty::Type type = LottieProperty::Type::Invalid> void registerSlot(LottieObject* obj);
|
template<LottieProperty::Type type = LottieProperty::Type::Invalid> void registerSlot(LottieObject* obj, char* sid);
|
||||||
|
|
||||||
LottieComposition* comp = nullptr;
|
LottieComposition* comp = nullptr;
|
||||||
const char* dirName = nullptr; //base resource directory
|
const char* dirName = nullptr; //base resource directory
|
||||||
|
@ -77,7 +77,7 @@ private:
|
||||||
|
|
||||||
LottieObject* parseObject();
|
LottieObject* parseObject();
|
||||||
LottieObject* parseAsset();
|
LottieObject* parseAsset();
|
||||||
LottieImage* parseImage(const char* data, const char* subPath, bool embedded, float width, float height);
|
void parseImage(LottieImage* image, const char* data, const char* subPath, bool embedded, float width, float height);
|
||||||
LottieLayer* parseLayer(LottieLayer* precomp);
|
LottieLayer* parseLayer(LottieLayer* precomp);
|
||||||
LottieObject* parseGroup();
|
LottieObject* parseGroup();
|
||||||
LottieRect* parseRect();
|
LottieRect* parseRect();
|
||||||
|
|
|
@ -112,7 +112,7 @@ struct LottieVectorFrame
|
||||||
//Property would have an either keyframes or single value.
|
//Property would have an either keyframes or single value.
|
||||||
struct LottieProperty
|
struct LottieProperty
|
||||||
{
|
{
|
||||||
enum class Type : uint8_t { Point = 0, Float, Opacity, Color, PathSet, ColorStop, Position, TextDoc, Invalid };
|
enum class Type : uint8_t { Point = 0, Float, Opacity, Color, PathSet, ColorStop, Position, TextDoc, Image, Invalid };
|
||||||
|
|
||||||
LottieExpression* exp = nullptr;
|
LottieExpression* exp = nullptr;
|
||||||
Type type;
|
Type type;
|
||||||
|
@ -828,6 +828,52 @@ struct LottieTextDoc : LottieProperty
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieBitmap : LottieProperty
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
char* b64Data = nullptr;
|
||||||
|
char* path;
|
||||||
|
};
|
||||||
|
char* mimeType = nullptr;
|
||||||
|
uint32_t size = 0;
|
||||||
|
float width = 0.0f;
|
||||||
|
float height = 0.0f;
|
||||||
|
|
||||||
|
~LottieBitmap()
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void release()
|
||||||
|
{
|
||||||
|
free(b64Data);
|
||||||
|
free(mimeType);
|
||||||
|
|
||||||
|
b64Data = nullptr;
|
||||||
|
mimeType = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t frameCnt() override { return 0; }
|
||||||
|
uint32_t nearest(float time) override { return 0; }
|
||||||
|
float frameNo(int32_t key) override { return 0; }
|
||||||
|
|
||||||
|
LottieBitmap& operator=(const LottieBitmap& other)
|
||||||
|
{
|
||||||
|
//shallow copy, used for slot overriding
|
||||||
|
if (other.mimeType) b64Data = other.b64Data;
|
||||||
|
else path = other.path;
|
||||||
|
mimeType = other.mimeType;
|
||||||
|
size = other.size;
|
||||||
|
width = other.width;
|
||||||
|
height = other.height;
|
||||||
|
|
||||||
|
const_cast<LottieBitmap&>(other).b64Data = nullptr;
|
||||||
|
const_cast<LottieBitmap&>(other).mimeType = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
using LottiePoint = LottieGenericProperty<Point>;
|
using LottiePoint = LottieGenericProperty<Point>;
|
||||||
using LottieFloat = LottieGenericProperty<float>;
|
using LottieFloat = LottieGenericProperty<float>;
|
||||||
using LottieOpacity = LottieGenericProperty<uint8_t>;
|
using LottieOpacity = LottieGenericProperty<uint8_t>;
|
||||||
|
|
Loading…
Add table
Reference in a new issue