mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
tvg_saver: optimize saving data.
This optimizes binary size by skipping the scene if it has the only child. though the reduced size is too trivial size (avg 0.4% as far as I checked our example svgs), we can reduce the loading job & runtime memory as well.
This commit is contained in:
parent
2337ea2b01
commit
abebdbe545
6 changed files with 93 additions and 31 deletions
Binary file not shown.
|
@ -32,6 +32,7 @@ namespace tvg
|
||||||
virtual ~Iterator() {}
|
virtual ~Iterator() {}
|
||||||
virtual const Paint* next() = 0;
|
virtual const Paint* next() = 0;
|
||||||
virtual uint32_t count() = 0;
|
virtual uint32_t count() = 0;
|
||||||
|
virtual void begin() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StrategyMethod
|
struct StrategyMethod
|
||||||
|
|
|
@ -33,14 +33,15 @@
|
||||||
struct PictureIterator : Iterator
|
struct PictureIterator : Iterator
|
||||||
{
|
{
|
||||||
Paint* paint = nullptr;
|
Paint* paint = nullptr;
|
||||||
|
Paint* ptr = nullptr;
|
||||||
|
|
||||||
PictureIterator(Paint* p) : paint(p) {}
|
PictureIterator(Paint* p) : paint(p) {}
|
||||||
|
|
||||||
const Paint* next() override
|
const Paint* next() override
|
||||||
{
|
{
|
||||||
auto ret = paint;
|
if (!ptr) ptr = paint;
|
||||||
paint = nullptr;
|
else ptr = nullptr;
|
||||||
return ret;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t count() override
|
uint32_t count() override
|
||||||
|
@ -48,6 +49,11 @@ struct PictureIterator : Iterator
|
||||||
if (paint) return 1;
|
if (paint) return 1;
|
||||||
else return 0;
|
else return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void begin() override
|
||||||
|
{
|
||||||
|
ptr = nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,11 @@ struct SceneIterator : Iterator
|
||||||
{
|
{
|
||||||
return paints->count;
|
return paints->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void begin() override
|
||||||
|
{
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Scene::Impl
|
struct Scene::Impl
|
||||||
|
|
|
@ -200,12 +200,59 @@ TvgBinCounter TvgSaver::serializePaint(const Paint* paint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Propagate parents properties to the child so that we can skip saving the parent. */
|
||||||
|
TvgBinCounter TvgSaver::serializeChild(const Paint* parent, const Paint* child, const Matrix* transform)
|
||||||
|
{
|
||||||
|
const Paint* compTarget = nullptr;
|
||||||
|
auto compMethod = parent->composite(&compTarget);
|
||||||
|
|
||||||
|
//If the parent & the only child have composition, we can't skip the parent....
|
||||||
|
if (compMethod != CompositeMethod::None && child->composite(nullptr) != CompositeMethod::None) return 0;
|
||||||
|
|
||||||
|
//propagate opacity
|
||||||
|
uint32_t opacity = parent->opacity();
|
||||||
|
|
||||||
|
if (opacity < 255) {
|
||||||
|
uint32_t tmp = (child->opacity() * opacity);
|
||||||
|
if (tmp > 0) tmp /= 255;
|
||||||
|
const_cast<Paint*>(child)->opacity(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
//propagate composition
|
||||||
|
if (compTarget) const_cast<Paint*>(child)->composite(unique_ptr<Paint>(compTarget->duplicate()), compMethod);
|
||||||
|
|
||||||
|
return serialize(child, transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TvgBinCounter TvgSaver::serializeScene(const Scene* scene, const Matrix* transform)
|
TvgBinCounter TvgSaver::serializeScene(const Scene* scene, const Matrix* transform)
|
||||||
{
|
{
|
||||||
|
auto it = this->iterator(scene);
|
||||||
|
if (it->count() == 0) return 0;
|
||||||
|
|
||||||
|
//Case - Only Child: Skip saving this scene.
|
||||||
|
if (it->count() == 1) {
|
||||||
|
auto cnt = serializeChild(scene, it->next(), transform);
|
||||||
|
if (cnt > 0) {
|
||||||
|
delete(it);
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it->begin();
|
||||||
|
|
||||||
|
//Case - Delegator Scene: This scene is just a delegator, we can skip this:
|
||||||
|
if (scene->composite(nullptr) == CompositeMethod::None && scene->opacity() == 255) {
|
||||||
|
return serializeChildren(it, transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Case - Serialize Scene & its children
|
||||||
writeTag(TVG_TAG_CLASS_SCENE);
|
writeTag(TVG_TAG_CLASS_SCENE);
|
||||||
reserveCount();
|
reserveCount();
|
||||||
|
|
||||||
auto cnt = serializeChildren(scene, transform) + serializePaint(scene);
|
auto cnt = serializeChildren(it, transform) + serializePaint(scene);
|
||||||
|
|
||||||
|
delete(it);
|
||||||
|
|
||||||
writeReservedCount(cnt);
|
writeReservedCount(cnt);
|
||||||
|
|
||||||
|
@ -367,34 +414,40 @@ TvgBinCounter TvgSaver::serializeShape(const Shape* shape, const Matrix* transfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Picture has either a vector scene or a bitmap. */
|
||||||
TvgBinCounter TvgSaver::serializePicture(const Picture* picture, const Matrix* transform)
|
TvgBinCounter TvgSaver::serializePicture(const Picture* picture, const Matrix* transform)
|
||||||
{
|
{
|
||||||
|
//Case - Vector Scene: Only child, Skip to save Picture...
|
||||||
|
auto it = this->iterator(picture);
|
||||||
|
if (it->count() == 1) {
|
||||||
|
auto cnt = serializeChild(picture, it->next(), transform);
|
||||||
|
delete(it);
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
delete(it);
|
||||||
|
|
||||||
|
//Case - Bitmap Image:
|
||||||
|
uint32_t w, h;
|
||||||
|
auto pixels = picture->data(&w, &h);
|
||||||
|
if (!pixels) return 0;
|
||||||
|
|
||||||
writeTag(TVG_TAG_CLASS_PICTURE);
|
writeTag(TVG_TAG_CLASS_PICTURE);
|
||||||
reserveCount();
|
reserveCount();
|
||||||
|
|
||||||
TvgBinCounter cnt = 0;
|
TvgBinCounter cnt = 0;
|
||||||
|
TvgBinCounter sizeCnt = SIZE(w);
|
||||||
|
TvgBinCounter imgSize = w * h * SIZE(pixels[0]);
|
||||||
|
|
||||||
//Bitmap Image
|
writeTag(TVG_TAG_PICTURE_RAW_IMAGE);
|
||||||
uint32_t w, h;
|
writeCount(2 * sizeCnt + imgSize);
|
||||||
|
|
||||||
if (auto pixels = picture->data(&w, &h)) {
|
cnt += writeData(&w, sizeCnt);
|
||||||
TvgBinCounter sizeCnt = SIZE(w);
|
cnt += writeData(&h, sizeCnt);
|
||||||
TvgBinCounter imgSize = w * h * SIZE(pixels[0]);
|
cnt += writeData(pixels, imgSize);
|
||||||
|
cnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter);
|
||||||
|
|
||||||
writeTag(TVG_TAG_PICTURE_RAW_IMAGE);
|
//Bitmap picture needs the transform info.
|
||||||
writeCount(2 * sizeCnt + imgSize);
|
cnt += writeTransform(transform);
|
||||||
|
|
||||||
cnt += writeData(&w, sizeCnt);
|
|
||||||
cnt += writeData(&h, sizeCnt);
|
|
||||||
cnt += writeData(pixels, imgSize);
|
|
||||||
cnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter);
|
|
||||||
|
|
||||||
//Only Bitmap picture needs the transform info.
|
|
||||||
cnt += writeTransform(transform);
|
|
||||||
//Vector Image
|
|
||||||
} else {
|
|
||||||
cnt += serializeChildren(picture, transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
cnt += serializePaint(picture);
|
cnt += serializePaint(picture);
|
||||||
|
|
||||||
|
@ -420,17 +473,13 @@ TvgBinCounter TvgSaver::serializeComposite(const Paint* cmpTarget, CompositeMeth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TvgBinCounter TvgSaver::serializeChildren(const Paint* paint, const Matrix* transform)
|
TvgBinCounter TvgSaver::serializeChildren(Iterator* it, const Matrix* transform)
|
||||||
{
|
{
|
||||||
auto it = this->iterator(paint);
|
|
||||||
if (!it) return 0;
|
|
||||||
|
|
||||||
TvgBinCounter cnt = 0;
|
TvgBinCounter cnt = 0;
|
||||||
|
|
||||||
while (auto p = it->next())
|
while (auto p = it->next()) {
|
||||||
cnt += serialize(p, transform);
|
cnt += serialize(p, transform);
|
||||||
|
}
|
||||||
delete(it);
|
|
||||||
|
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,8 @@ private:
|
||||||
TvgBinCounter serializeStroke(const Shape* shape);
|
TvgBinCounter serializeStroke(const Shape* shape);
|
||||||
TvgBinCounter serializePath(const Shape* shape, const Matrix* transform);
|
TvgBinCounter serializePath(const Shape* shape, const Matrix* transform);
|
||||||
TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod);
|
TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod);
|
||||||
TvgBinCounter serializeChildren(const Paint* paint, const Matrix* transform);
|
TvgBinCounter serializeChildren(Iterator* it, const Matrix* transform);
|
||||||
|
TvgBinCounter serializeChild(const Paint* parent, const Paint* child, const Matrix* transform);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~TvgSaver();
|
~TvgSaver();
|
||||||
|
|
Loading…
Add table
Reference in a new issue