summaryrefslogtreecommitdiff
path: root/basegfx
diff options
context:
space:
mode:
authorArmin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de>2023-04-13 12:13:19 +0200
committerArmin Le Grand <Armin.Le.Grand@me.com>2023-04-14 11:56:46 +0200
commit70684ab604c5fb32a16614c708f986671dd2da3c (patch)
tree50b68b1256983c0fffa7d5efdd275d09b8bcc8d8 /basegfx
parent8b8a2844addbd262befb1a2d193dfb590dfa20be (diff)
MCGR: Adaptions to oox export
This is a 1st version and might need more fine-tuning, so it is still 'hidden' behind the MCGR_TEST env var being set (as the import is, too). Still, when used, it can now import a MCGR with transparence and export it again. I will now do extended testing/experimenting, fine-tuning where needed and prepare final change/drive forward. The current state in master should not be changed as long as the mentioned env var is not set, but this will need to be checked, too, due to changes to the export api in oox. Corrected an error in GetAlphaFromTransparenceGradient method(s), css::rendering::RGBColor is [0.0 .. 1.0] Corercted an error in WriteSolidFill where transparence gradient gets checked. This should really check if TrGr is used, but only checks for 'empty/unused' color instead (assuming COL_BLACK is 'unused'). All usages of GetAlphaFromTransparenceGradient should be checked and adapted. Change-Id: If59d7a06b9207e2efe9e71f3f8ddeca4476408f3 Change-Id: If97f8abdd0e1597aa1fd865b7e884e06a22b71f5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150391 Tested-by: Jenkins Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'basegfx')
-rw-r--r--basegfx/source/tools/gradienttools.cxx260
1 files changed, 250 insertions, 10 deletions
diff --git a/basegfx/source/tools/gradienttools.cxx b/basegfx/source/tools/gradienttools.cxx
index ca315f33f973..46d8fc7ca216 100644
--- a/basegfx/source/tools/gradienttools.cxx
+++ b/basegfx/source/tools/gradienttools.cxx
@@ -264,6 +264,237 @@ namespace basegfx
namespace utils
{
+ /* Tooling method to extract data from given awt::Gradient2
+ to ColorStops, doing some corrections, partitally based
+ on given SingleColor.
+ This will do quite some preparations for the gradient
+ as follows:
+ - It will check for single color (resetting rSingleColor when
+ this is the case) and return with empty ColorStops
+ - It will blend ColorStops to Intensity if StartIntensity/
+ EndIntensity != 100 is set in awt::Gradient2, so applying
+ that value(s) to the gadient directly
+ - It will adapt to Border if Border != 0 is set at the
+ given awt::Gradient2, so applying that value to the gadient
+ directly
+ */
+ void prepareColorStops(
+ const com::sun::star::awt::Gradient2& rGradient,
+ ColorStops& rColorStops,
+ BColor& rSingleColor)
+ {
+ fillColorStopsFromGradient2(rColorStops, rGradient);
+
+ if (isSingleColor(rColorStops, rSingleColor))
+ {
+ // when single color, preserve value in rSingleColor
+ // and clear the ColorStops, done.
+ rColorStops.clear();
+ return;
+ }
+
+ if (rGradient.StartIntensity != 100 || rGradient.EndIntensity != 100)
+ {
+ // apply 'old' blend stuff, blend against black
+ blendColorStopsToIntensity(
+ rColorStops,
+ rGradient.StartIntensity * 0.01,
+ rGradient.EndIntensity * 0.01,
+ basegfx::BColor()); // COL_BLACK
+
+ // can lead to single color (e.g. both zero, so all black),
+ // so check again
+ if (isSingleColor(rColorStops, rSingleColor))
+ {
+ rColorStops.clear();
+ return;
+ }
+ }
+
+ if (rGradient.Border != 0)
+ {
+ // apply Border if set
+ // NOTE: no new start node is added. If this is needed,
+ // do that in the caller
+ const double fFactor(rGradient.Border * 0.01);
+ ColorStops aNewStops;
+
+ for (const auto& candidate : rColorStops)
+ {
+ aNewStops.emplace_back(candidate.getStopOffset() * fFactor, candidate.getStopColor());
+ }
+
+ rColorStops = aNewStops;
+ }
+ }
+
+ /* Tooling method to synchronize the given ColorStops.
+ The intention is that a color GradientStops and an
+ alpha/transparence GradientStops gets synchronized
+ for export.
+ Fo the corrections the single values for color and
+ alpha may be used, e.g. when ColorStops is given
+ and not empty, but AlphaStops is empty, it will get
+ sycronized so that it will have the same number and
+ offsets in AlphaStops as in ColorStops, but with
+ the given SingleAlpha as value.
+ At return it guarantees that both have the same
+ number of entries with the same StopOffsets, so
+ that synchonized pair of ColorStops can e.g. be used
+ to export a Gradient with defined/adapted alpha
+ being 'coupled' indirectly using the
+ 'FillTransparenceGradient' method (at import time).
+ */
+ void synchronizeColorStops(
+ ColorStops& rColorStops,
+ ColorStops& rAlphaStops,
+ const BColor& rSingleColor,
+ const BColor& rSingleAlpha)
+ {
+ if (rColorStops.empty())
+ {
+ if (rAlphaStops.empty())
+ {
+ // no AlphaStops and no ColorStops
+ // create two-stop fallbacks for both
+ rColorStops = ColorStops {
+ ColorStop(0.0, rSingleColor),
+ ColorStop(1.0, rSingleColor) };
+ rAlphaStops = ColorStops {
+ ColorStop(0.0, rSingleAlpha),
+ ColorStop(1.0, rSingleAlpha) };
+ }
+ else
+ {
+ // AlphaStops but no ColorStops
+ // create fallback synched with existing AlphaStops
+ for (const auto& cand : rAlphaStops)
+ {
+ rColorStops.emplace_back(cand.getStopOffset(), rSingleColor);
+ }
+ }
+
+ // preparations complete, we are done
+ return;
+ }
+ else if (rAlphaStops.empty())
+ {
+ // ColorStops but no AlphaStops
+ // create fallback AlphaStops synched with existing ColorStops using SingleAlpha
+ for (const auto& cand : rColorStops)
+ {
+ rAlphaStops.emplace_back(cand.getStopOffset(), rSingleAlpha);
+ }
+
+ // preparations complete, we are done
+ return;
+ }
+
+ // here we have ColorStops and AlphaStops not empty. Check if we need to
+ // synchronize both or if they are already usable/in a synched state so
+ // that they have same count and same StopOffsets
+ bool bNeedToSyncronize(rColorStops.size() != rAlphaStops.size());
+
+ if (!bNeedToSyncronize)
+ {
+ // check for same StopOffsets
+ ColorStops::const_iterator aCurrColor(rColorStops.begin());
+ ColorStops::const_iterator aCurrAlpha(rAlphaStops.begin());
+
+ while (!bNeedToSyncronize &&
+ aCurrColor != rColorStops.end() &&
+ aCurrAlpha != rAlphaStops.end())
+ {
+ if (fTools::equal(aCurrColor->getStopOffset(), aCurrAlpha->getStopOffset()))
+ {
+ aCurrColor++;
+ aCurrAlpha++;
+ }
+ else
+ {
+ bNeedToSyncronize = true;
+ }
+ }
+ }
+
+ if (bNeedToSyncronize)
+ {
+ // synchronize sizes & StopOffsets
+ ColorStops::const_iterator aCurrColor(rColorStops.begin());
+ ColorStops::const_iterator aCurrAlpha(rAlphaStops.begin());
+ ColorStops aNewColor;
+ ColorStops aNewAlpha;
+ ColorStopRange aColorStopRange;
+ ColorStopRange aAlphaStopRange;
+ bool bRealChange(false);
+
+ do {
+ const bool bColor(aCurrColor != rColorStops.end());
+ const bool bAlpha(aCurrAlpha != rAlphaStops.end());
+
+ if (bColor && bAlpha)
+ {
+ const double fColorOff(aCurrColor->getStopOffset());
+ const double fAlphaOff(aCurrAlpha->getStopOffset());
+
+ if (fTools::less(fColorOff, fAlphaOff))
+ {
+ // copy color, create alpha
+ aNewColor.emplace_back(fColorOff, aCurrColor->getStopColor());
+ aNewAlpha.emplace_back(fColorOff, utils::modifyBColor(rAlphaStops, fColorOff, 0, aAlphaStopRange));
+ bRealChange = true;
+ aCurrColor++;
+ }
+ else if (fTools::more(fColorOff, fAlphaOff))
+ {
+ // copy alpha, create color
+ aNewColor.emplace_back(fAlphaOff, utils::modifyBColor(rColorStops, fAlphaOff, 0, aColorStopRange));
+ aNewAlpha.emplace_back(fAlphaOff, aCurrAlpha->getStopColor());
+ bRealChange = true;
+ aCurrAlpha++;
+ }
+ else
+ {
+ // equal: copy both, advance
+ aNewColor.emplace_back(fColorOff, aCurrColor->getStopColor());
+ aNewAlpha.emplace_back(fAlphaOff, aCurrAlpha->getStopColor());
+ aCurrColor++;
+ aCurrAlpha++;
+ }
+ }
+ else if (bColor)
+ {
+ const double fColorOff(aCurrColor->getStopOffset());
+ aNewAlpha.emplace_back(fColorOff, utils::modifyBColor(rAlphaStops, fColorOff, 0, aAlphaStopRange));
+ bRealChange = true;
+ aCurrColor++;
+ }
+ else if (bAlpha)
+ {
+ const double fAlphaOff(aCurrAlpha->getStopOffset());
+ aNewColor.emplace_back(fAlphaOff, utils::modifyBColor(rColorStops, fAlphaOff, 0, aColorStopRange));
+ bRealChange = true;
+ aCurrAlpha++;
+ }
+ else
+ {
+ // no more input, break do..while loop
+ break;
+ }
+ }
+ while(true);
+
+ if (bRealChange)
+ {
+ // copy on 'real' change, that means data was added.
+ // This should always be the cease and should have been
+ // detected as such above, see bNeedToSyncronize
+ rColorStops = aNewColor;
+ rAlphaStops = aNewColor;
+ }
+ }
+ }
+
/* Tooling method to linearly blend the Colors contained in
a given ColorStop vector against a given Color using the
given intensity values.
@@ -345,18 +576,13 @@ namespace basegfx
candidate = ColorStop(1.0 - candidate.getStopOffset(), candidate.getStopColor());
}
- /* Tooling method to convert UNO API data to ColorStops
+ /* Tooling method to convert UNO API data to ColorStops.
This will try to extract ColorStop data from the given
- Any, so if it's of type awt::Gradient2 that data will be
- extracted, converted and copied into the given ColorStops.
+ awt::Gradient2.
*/
- void fillColorStopsFromAny(ColorStops& rColorStops, const css::uno::Any& rVal)
+ void fillColorStopsFromGradient2(ColorStops& rColorStops, const com::sun::star::awt::Gradient2& rGradient)
{
- css::awt::Gradient2 aGradient2;
- if (!(rVal >>= aGradient2))
- return;
-
- const sal_Int32 nLen(aGradient2.ColorStops.getLength());
+ const sal_Int32 nLen(rGradient.ColorStops.getLength());
if (0 == nLen)
return;
@@ -364,7 +590,7 @@ namespace basegfx
// we have ColorStops
rColorStops.clear();
rColorStops.reserve(nLen);
- const css::awt::ColorStop* pSourceColorStop(aGradient2.ColorStops.getConstArray());
+ const css::awt::ColorStop* pSourceColorStop(rGradient.ColorStops.getConstArray());
for (sal_Int32 a(0); a < nLen; a++, pSourceColorStop++)
{
@@ -374,6 +600,20 @@ namespace basegfx
}
}
+ /* Tooling method to convert UNO API data to ColorStops.
+ This will try to extract ColorStop data from the given
+ Any, so if it's of type awt::Gradient2 that data will be
+ extracted, converted and copied into the given ColorStops.
+ */
+ void fillColorStopsFromAny(ColorStops& rColorStops, const css::uno::Any& rVal)
+ {
+ css::awt::Gradient2 aGradient2;
+ if (!(rVal >>= aGradient2))
+ return;
+
+ fillColorStopsFromGradient2(rColorStops, aGradient2);
+ }
+
/* Tooling method to fill a awt::ColorStopSequence with
the data from the given ColorStops. This is used in
UNO API implementations.