From 5fbe41d58feb5e77946eb313f07061427b919e75 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 26 Oct 2021 02:07:24 +0200 Subject: [PATCH] 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. --- src/lib/tvgBinaryDesc.h | 1 + src/loaders/tvg/tvgTvgBinInterpreter.cpp | 7 ++++++ src/savers/tvg/tvgTvgSaver.cpp | 39 +++++++++++++++++--------------- src/savers/tvg/tvgTvgSaver.h | 4 ++-- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/lib/tvgBinaryDesc.h b/src/lib/tvgBinaryDesc.h index 4ef59af..30ba2d5 100644 --- a/src/lib/tvgBinaryDesc.h +++ b/src/lib/tvgBinaryDesc.h @@ -87,6 +87,7 @@ using TvgBinFlag = TvgBinByte; #define TVG_TAG_FILL_RADIAL_GRADIENT (TvgBinTag)0x61 #define TVG_TAG_FILL_COLORSTOPS (TvgBinTag)0x62 #define TVG_TAG_FILL_FILLSPREAD (TvgBinTag)0x63 +#define TVG_TAG_FILL_TRANSFORM (TvgBinTag)0x64 //Picture diff --git a/src/loaders/tvg/tvgTvgBinInterpreter.cpp b/src/loaders/tvg/tvgTvgBinInterpreter.cpp index 17d106b..383ae89 100644 --- a/src/loaders/tvg/tvgTvgBinInterpreter.cpp +++ b/src/loaders/tvg/tvgTvgBinInterpreter.cpp @@ -225,6 +225,13 @@ static unique_ptr _parseShapeFill(const char *ptr, const char *end) fillGrad->colorStops(stops, stopsCnt); 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: { TVGLOG("TVG", "Unsupported tag %d (0x%x) used as one of the fill properties, %d bytes skipped", block.type, block.type, block.length); break; diff --git a/src/savers/tvg/tvgTvgSaver.cpp b/src/savers/tvg/tvgTvgSaver.cpp index 3f9780d..ffa79e1 100644 --- a/src/savers/tvg/tvgTvgSaver.cpp +++ b/src/savers/tvg/tvgTvgSaver.cpp @@ -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 || 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) { - return writeTagProperty(TVG_TAG_PAINT_TRANSFORM, SIZE(Matrix), transform); + return writeTagProperty(tag, SIZE(Matrix), transform); } 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; 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_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); return SERIAL_DONE(cnt); @@ -476,7 +480,7 @@ TvgBinCounter TvgSaver::serializeStroke(const Shape* shape, const Matrix* pTrans //fill 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 { uint8_t color[4] = {0, 0, 0, 0}; 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); } - //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; - //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 if (shape->strokeWidth() > 0) { uint8_t color[4] = {0, 0, 0, 0}; shape->strokeColor(color, color + 1, color + 2, color + 3); auto fill = shape->strokeFill(); 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); } } + //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); - if (!preTransform) cnt += writeTransform(cTransform); + if (!preTransform) cnt += writeTransform(cTransform, TVG_TAG_PAINT_TRANSFORM); cnt += serializePaint(shape, pTransform); writeReservedCount(cnt); @@ -636,7 +639,7 @@ TvgBinCounter TvgSaver::serializePicture(const Picture* picture, const Matrix* p cnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter); //Bitmap picture needs the transform info. - cnt += writeTransform(cTransform); + cnt += writeTransform(cTransform, TVG_TAG_PAINT_TRANSFORM); cnt += serializePaint(picture, pTransform); diff --git a/src/savers/tvg/tvgTvgSaver.h b/src/savers/tvg/tvgTvgSaver.h index d92f7bc..27186b5 100644 --- a/src/savers/tvg/tvgTvgSaver.h +++ b/src/savers/tvg/tvgTvgSaver.h @@ -50,14 +50,14 @@ private: void writeReservedCount(TvgBinCounter cnt); TvgBinCounter writeData(const void* data, TvgBinCounter cnt); 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 serializeScene(const Scene* scene, 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 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 serializePath(const Shape* shape, const Matrix* transform, bool preTransform); TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod, const Matrix* pTransform); -- 2.7.4