Recoloring ?
Closed this issue · 4 comments
This is more of a question / discussion on the matter.
I wonder if this is possible or sensible to install a recoloring mechanism ?
I understand that one could leverage some kind of filter via paint
/ paintIcon
methods but I wonder if such modifications could be done before e.g. via SVGDocument
API ?
This is actually already possible (albeit without proper documentation). In fact there are multiple ways to achieve it:
- Using a custom
PaintParser
:Use it at load timeclass CustomColorsParserProvider extends DefaultParserProvider { @Override public @NotNull PaintParser createPaintParser() { return new CustomColorsPaintParser(super.createPaintParser()); } } class CustomColorsPaintParser implements PaintParser { private final PaintParser delegate; CustomColorsPaintParser(PaintParser delegate) { this.delegate = delegate; } @Override public @Nullable Color parseColor(@NotNull String value, @NotNull AttributeNode attributeNode) { Color c = delegate.parseColor(value, attributeNode); // adjust c to your liking return c; } @Override public @Nullable SVGPaint parsePaint(@Nullable String value, @NotNull AttributeNode attributeNode) { SVGPaint paint = delegate.parsePaint(value, attributeNode); // Adjust paint. Effectively only AwtSVGPaint needs to be handled here // (Gradients etc are already covered by `parseColor `) return paint; } }
new SVGLoader().load(url, new CustomColorsParserProvider())
. This will replace the colours once when the svg is loaded. If you want to dynamically change colours then at least for plain colours (e.g. no gradients etc) something like the following could be returned fromparsePaint
:For gradients the second approach allows a more fine-grained control (but with more setup involved).class DynamicAWTSvgPaint implements SimplePaintSVGPaint { @Override public @NotNull Paint paint() { // return whatever color you like } }
Alternatively one could employ something like this:https://github.com/weisJ/darklaf/blob/master/utils/src/main/java/com/github/weisj/darklaf/util/ColorWrapper.java
To dynamically change any color. - Using a
DomProcessor
:See https://github.com/weisJ/darklaf/blob/master/property-loader/src/main/java/com/github/weisj/darklaf/properties/icons/ThemedSVGIconParserProvider.java for an example.class CustomColorsParserProvider extends DefaultParserProvider { @Override public @Nullable DomProcessor createPreProcessor() { return new CustomColorsProcessor(); } } class CustomColorsProcessor implements DomProcessor { @Override public void process(@NotNull ParsedElement root) { processImpl(root); root.children().forEach(this::process); } private void processImpl(ParsedElement element) { SVGPaint paint = null; SVGNode node = element.node(); if (node instanceof LinearGradient) { // create a custom dynamic paint based on linear gradient // Note that at this point element.node() hasn't yet been // fully parsed. Parsing its attributes needs to be done manually. } else if (node instanceof RadialGradient) { } // and so on // Replace the paint associated to node with the new paint element.registerNamedElement(node.id(), paint); } }
For more complicated adjustments (as in the second option) I have to acknowledge that the API isn't very nice however for simple changes option 1 should work fine. I explicitly don't want to allow changing the Dom after it has been fully parsed.
Thank you very much. This is really nice! I think option 1 is good enough for my use case.
Also thank you for the link to actual examples.
Documentation has been added.
Thank you very much