mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
tvg_saver/tvg_loader: gradient fill in the tvg format
Introducing the gradient transform() apis and changing the grad algorithms made it possible to apply the shape's transformation before saving the tvg file, in case the shape (or its stroke) has a fill.
This commit is contained in:
parent
3b54e4797e
commit
6b132d77e8
4 changed files with 31 additions and 20 deletions
|
@ -87,6 +87,7 @@ using TvgBinFlag = TvgBinByte;
|
||||||
#define TVG_TAG_FILL_RADIAL_GRADIENT (TvgBinTag)0x61
|
#define TVG_TAG_FILL_RADIAL_GRADIENT (TvgBinTag)0x61
|
||||||
#define TVG_TAG_FILL_COLORSTOPS (TvgBinTag)0x62
|
#define TVG_TAG_FILL_COLORSTOPS (TvgBinTag)0x62
|
||||||
#define TVG_TAG_FILL_FILLSPREAD (TvgBinTag)0x63
|
#define TVG_TAG_FILL_FILLSPREAD (TvgBinTag)0x63
|
||||||
|
#define TVG_TAG_FILL_TRANSFORM (TvgBinTag)0x64
|
||||||
|
|
||||||
|
|
||||||
//Picture
|
//Picture
|
||||||
|
|
|
@ -225,6 +225,13 @@ static unique_ptr<Fill> _parseShapeFill(const char *ptr, const char *end)
|
||||||
fillGrad->colorStops(stops, stopsCnt);
|
fillGrad->colorStops(stops, stopsCnt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case TVG_TAG_FILL_TRANSFORM: {
|
||||||
|
if (!fillGrad || block.length != SIZE(Matrix)) return nullptr;
|
||||||
|
Matrix gradTransform;
|
||||||
|
memcpy(&gradTransform, block.data, SIZE(Matrix));
|
||||||
|
fillGrad->transform(gradTransform);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
TVGLOG("TVG", "Unsupported tag %d (0x%x) used as one of the fill properties, %d bytes skipped", block.type, block.type, block.length);
|
TVGLOG("TVG", "Unsupported tag %d (0x%x) used as one of the fill properties, %d bytes skipped", block.type, block.type, block.length);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -323,12 +323,12 @@ TvgBinCounter TvgSaver::writeTagProperty(TvgBinTag tag, TvgBinCounter cnt, const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TvgBinCounter TvgSaver::writeTransform(const Matrix* transform)
|
TvgBinCounter TvgSaver::writeTransform(const Matrix* transform, TvgBinTag tag)
|
||||||
{
|
{
|
||||||
if (fabs(transform->e11 - 1) > FLT_EPSILON || fabs(transform->e12) > FLT_EPSILON || fabs(transform->e13) > FLT_EPSILON ||
|
if (fabs(transform->e11 - 1) > FLT_EPSILON || fabs(transform->e12) > FLT_EPSILON || fabs(transform->e13) > FLT_EPSILON ||
|
||||||
fabs(transform->e21) > FLT_EPSILON || fabs(transform->e22 - 1) > FLT_EPSILON || fabs(transform->e23) > FLT_EPSILON ||
|
fabs(transform->e21) > FLT_EPSILON || fabs(transform->e22 - 1) > FLT_EPSILON || fabs(transform->e23) > FLT_EPSILON ||
|
||||||
fabs(transform->e31) > FLT_EPSILON || fabs(transform->e32) > FLT_EPSILON || fabs(transform->e33 - 1) > FLT_EPSILON) {
|
fabs(transform->e31) > FLT_EPSILON || fabs(transform->e32) > FLT_EPSILON || fabs(transform->e33 - 1) > FLT_EPSILON) {
|
||||||
return writeTagProperty(TVG_TAG_PAINT_TRANSFORM, SIZE(Matrix), transform);
|
return writeTagProperty(tag, SIZE(Matrix), transform);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -423,7 +423,7 @@ TvgBinCounter TvgSaver::serializeScene(const Scene* scene, const Matrix* pTransf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TvgBinCounter TvgSaver::serializeFill(const Fill* fill, TvgBinTag tag)
|
TvgBinCounter TvgSaver::serializeFill(const Fill* fill, TvgBinTag tag, const Matrix* pTransform)
|
||||||
{
|
{
|
||||||
const Fill::ColorStop* stops = nullptr;
|
const Fill::ColorStop* stops = nullptr;
|
||||||
auto stopsCnt = fill->colorStops(&stops);
|
auto stopsCnt = fill->colorStops(&stops);
|
||||||
|
@ -450,6 +450,10 @@ TvgBinCounter TvgSaver::serializeFill(const Fill* fill, TvgBinTag tag)
|
||||||
cnt += writeTagProperty(TVG_TAG_FILL_FILLSPREAD, SIZE(TvgBinFlag), &flag);
|
cnt += writeTagProperty(TVG_TAG_FILL_FILLSPREAD, SIZE(TvgBinFlag), &flag);
|
||||||
cnt += writeTagProperty(TVG_TAG_FILL_COLORSTOPS, stopsCnt * SIZE(Fill::ColorStop), stops);
|
cnt += writeTagProperty(TVG_TAG_FILL_COLORSTOPS, stopsCnt * SIZE(Fill::ColorStop), stops);
|
||||||
|
|
||||||
|
auto gTransform = fill->transform();
|
||||||
|
if (pTransform) gTransform = _multiply(pTransform, &gTransform);
|
||||||
|
cnt += writeTransform(&gTransform, TVG_TAG_FILL_TRANSFORM);
|
||||||
|
|
||||||
writeReservedCount(cnt);
|
writeReservedCount(cnt);
|
||||||
|
|
||||||
return SERIAL_DONE(cnt);
|
return SERIAL_DONE(cnt);
|
||||||
|
@ -476,7 +480,7 @@ TvgBinCounter TvgSaver::serializeStroke(const Shape* shape, const Matrix* pTrans
|
||||||
|
|
||||||
//fill
|
//fill
|
||||||
if (auto fill = shape->strokeFill()) {
|
if (auto fill = shape->strokeFill()) {
|
||||||
cnt += serializeFill(fill, TVG_TAG_SHAPE_STROKE_FILL);
|
cnt += serializeFill(fill, TVG_TAG_SHAPE_STROKE_FILL, (preTransform ? pTransform : nullptr));
|
||||||
} else {
|
} else {
|
||||||
uint8_t color[4] = {0, 0, 0, 0};
|
uint8_t color[4] = {0, 0, 0, 0};
|
||||||
shape->strokeColor(color, color + 1, color + 2, color + 3);
|
shape->strokeColor(color, color + 1, color + 2, color + 3);
|
||||||
|
@ -555,33 +559,32 @@ TvgBinCounter TvgSaver::serializeShape(const Shape* shape, const Matrix* pTransf
|
||||||
cnt = writeTagProperty(TVG_TAG_SHAPE_FILLRULE, SIZE(TvgBinFlag), &flag);
|
cnt = writeTagProperty(TVG_TAG_SHAPE_FILLRULE, SIZE(TvgBinFlag), &flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
//the pre-transformation can't be applied in the case where any fill is present or when the stroke is dashed or irregulary scaled
|
//the pre-transformation can't be applied in the case when the stroke is dashed or irregulary scaled
|
||||||
bool preTransform = true;
|
bool preTransform = true;
|
||||||
|
|
||||||
//fill
|
|
||||||
if (auto fill = shape->fill()) {
|
|
||||||
preTransform = false;
|
|
||||||
cnt += serializeFill(fill, TVG_TAG_SHAPE_FILL);
|
|
||||||
} else {
|
|
||||||
uint8_t color[4] = {0, 0, 0, 0};
|
|
||||||
shape->fillColor(color, color + 1, color + 2, color + 3);
|
|
||||||
if (color[3] > 0) cnt += writeTagProperty(TVG_TAG_SHAPE_COLOR, SIZE(color), color);
|
|
||||||
}
|
|
||||||
|
|
||||||
//stroke
|
//stroke
|
||||||
if (shape->strokeWidth() > 0) {
|
if (shape->strokeWidth() > 0) {
|
||||||
uint8_t color[4] = {0, 0, 0, 0};
|
uint8_t color[4] = {0, 0, 0, 0};
|
||||||
shape->strokeColor(color, color + 1, color + 2, color + 3);
|
shape->strokeColor(color, color + 1, color + 2, color + 3);
|
||||||
auto fill = shape->strokeFill();
|
auto fill = shape->strokeFill();
|
||||||
if (fill || color[3] > 0) {
|
if (fill || color[3] > 0) {
|
||||||
if (fill || fabsf(cTransform->e11 - cTransform->e22) > FLT_EPSILON || (fabsf(cTransform->e11) < FLT_EPSILON && fabsf(cTransform->e12 - cTransform->e21) > FLT_EPSILON) || shape->strokeDash(nullptr) > 0) preTransform = false;
|
if (fabsf(cTransform->e11 - cTransform->e22) > FLT_EPSILON || (fabsf(cTransform->e11) < FLT_EPSILON && fabsf(cTransform->e12 - cTransform->e21) > FLT_EPSILON) || shape->strokeDash(nullptr) > 0) preTransform = false;
|
||||||
cnt += serializeStroke(shape, cTransform, preTransform);
|
cnt += serializeStroke(shape, cTransform, preTransform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//fill
|
||||||
|
if (auto fill = shape->fill()) {
|
||||||
|
cnt += serializeFill(fill, TVG_TAG_SHAPE_FILL, (preTransform ? cTransform : nullptr));
|
||||||
|
} else {
|
||||||
|
uint8_t color[4] = {0, 0, 0, 0};
|
||||||
|
shape->fillColor(color, color + 1, color + 2, color + 3);
|
||||||
|
if (color[3] > 0) cnt += writeTagProperty(TVG_TAG_SHAPE_COLOR, SIZE(color), color);
|
||||||
|
}
|
||||||
|
|
||||||
cnt += serializePath(shape, cTransform, preTransform);
|
cnt += serializePath(shape, cTransform, preTransform);
|
||||||
|
|
||||||
if (!preTransform) cnt += writeTransform(cTransform);
|
if (!preTransform) cnt += writeTransform(cTransform, TVG_TAG_PAINT_TRANSFORM);
|
||||||
cnt += serializePaint(shape, pTransform);
|
cnt += serializePaint(shape, pTransform);
|
||||||
|
|
||||||
writeReservedCount(cnt);
|
writeReservedCount(cnt);
|
||||||
|
@ -636,7 +639,7 @@ TvgBinCounter TvgSaver::serializePicture(const Picture* picture, const Matrix* p
|
||||||
cnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter);
|
cnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter);
|
||||||
|
|
||||||
//Bitmap picture needs the transform info.
|
//Bitmap picture needs the transform info.
|
||||||
cnt += writeTransform(cTransform);
|
cnt += writeTransform(cTransform, TVG_TAG_PAINT_TRANSFORM);
|
||||||
|
|
||||||
cnt += serializePaint(picture, pTransform);
|
cnt += serializePaint(picture, pTransform);
|
||||||
|
|
||||||
|
|
|
@ -50,14 +50,14 @@ private:
|
||||||
void writeReservedCount(TvgBinCounter cnt);
|
void writeReservedCount(TvgBinCounter cnt);
|
||||||
TvgBinCounter writeData(const void* data, TvgBinCounter cnt);
|
TvgBinCounter writeData(const void* data, TvgBinCounter cnt);
|
||||||
TvgBinCounter writeTagProperty(TvgBinTag tag, TvgBinCounter cnt, const void* data);
|
TvgBinCounter writeTagProperty(TvgBinTag tag, TvgBinCounter cnt, const void* data);
|
||||||
TvgBinCounter writeTransform(const Matrix* transform);
|
TvgBinCounter writeTransform(const Matrix* transform, TvgBinTag tag);
|
||||||
|
|
||||||
TvgBinCounter serialize(const Paint* paint, const Matrix* pTransform, bool compTarget = false);
|
TvgBinCounter serialize(const Paint* paint, const Matrix* pTransform, bool compTarget = false);
|
||||||
TvgBinCounter serializeScene(const Scene* scene, const Matrix* pTransform, const Matrix* cTransform);
|
TvgBinCounter serializeScene(const Scene* scene, const Matrix* pTransform, const Matrix* cTransform);
|
||||||
TvgBinCounter serializeShape(const Shape* shape, const Matrix* pTransform, const Matrix* cTransform);
|
TvgBinCounter serializeShape(const Shape* shape, const Matrix* pTransform, const Matrix* cTransform);
|
||||||
TvgBinCounter serializePicture(const Picture* picture, const Matrix* pTransform, const Matrix* cTransform);
|
TvgBinCounter serializePicture(const Picture* picture, const Matrix* pTransform, const Matrix* cTransform);
|
||||||
TvgBinCounter serializePaint(const Paint* paint, const Matrix* pTransform);
|
TvgBinCounter serializePaint(const Paint* paint, const Matrix* pTransform);
|
||||||
TvgBinCounter serializeFill(const Fill* fill, TvgBinTag tag);
|
TvgBinCounter serializeFill(const Fill* fill, TvgBinTag tag, const Matrix* pTransform);
|
||||||
TvgBinCounter serializeStroke(const Shape* shape, const Matrix* pTransform, bool preTransform);
|
TvgBinCounter serializeStroke(const Shape* shape, const Matrix* pTransform, bool preTransform);
|
||||||
TvgBinCounter serializePath(const Shape* shape, const Matrix* transform, bool preTransform);
|
TvgBinCounter serializePath(const Shape* shape, const Matrix* transform, bool preTransform);
|
||||||
TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod, const Matrix* pTransform);
|
TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod, const Matrix* pTransform);
|
||||||
|
|
Loading…
Add table
Reference in a new issue