Fixed SVG Frames export - filter

This commit is contained in:
Jindra Petřík
2023-10-16 09:36:06 +02:00
parent 2bb884487f
commit a337de4644
11 changed files with 560 additions and 14 deletions
@@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.types.BlendMode;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.filters.FILTER;
import com.jpexs.helpers.Helper;
import java.awt.Color;
import java.io.StringWriter;
@@ -239,7 +240,7 @@ public class SVGExporter {
}
private void addScalingGridUse(Matrix transform, RECT boundRect, String href, String instanceName, RECT scalingRect, String characterId, String characterName, int blendMode) {
private void addScalingGridUse(Matrix transform, RECT boundRect, String href, String instanceName, RECT scalingRect, String characterId, String characterName, int blendMode, List<FILTER> filters) {
Element image = _svg.createElement("g");
@@ -421,16 +422,41 @@ public class SVGExporter {
image.setAttribute("data-characterName", characterName);
}
setBlendMode(image, blendMode);
handleFilters(image, filters);
_svgGs.peek().appendChild(image);
}
public Element addUse(Matrix transform, RECT boundRect, String href, String instanceName, RECT scalingRect) {
return addUse(transform, boundRect, href, instanceName, scalingRect, null, null, BlendMode.NORMAL);
return addUse(transform, boundRect, href, instanceName, scalingRect, null, null, BlendMode.NORMAL, new ArrayList<>());
}
private void handleFilters(Element image, List<FILTER> filters) {
if (filters == null) {
return;
}
Element filtersElement = _svg.createElement("filter");
String filterId = getUniqueId("filter");
String in = "SourceGraphic";
boolean empty = true;
for (FILTER filter: filters) {
String result = filter.toSvg(_svg, filtersElement, this, in);
if (result != null) {
empty = false;
in = result;
}
}
if (empty) {
return;
}
filtersElement.setAttribute("id", filterId);
image.setAttribute("filter", "url(#" + filterId + ")");
_svgGs.peek().appendChild(filtersElement);
}
public Element addUse(Matrix transform, RECT boundRect, String href, String instanceName, RECT scalingRect, String characterId, String characterName, int blendMode) {
public Element addUse(Matrix transform, RECT boundRect, String href, String instanceName, RECT scalingRect, String characterId, String characterName, int blendMode, List<FILTER> filters) {
if (scalingRect != null && (transform == null || (Double.compare(transform.rotateSkew0, 0.0) == 0 && Double.compare(transform.rotateSkew1, 0.0) == 0))) {
addScalingGridUse(transform, boundRect, href, instanceName, scalingRect, characterId, characterName, blendMode);
addScalingGridUse(transform, boundRect, href, instanceName, scalingRect, characterId, characterName, blendMode, filters);
return null; //??
}
Element image = _svg.createElement("use");
@@ -451,7 +477,9 @@ public class SVGExporter {
setBlendMode(image, blendMode);
image.setAttribute("xlink:href", "#" + href);
handleFilters(image, filters);
image.setAttribute("xlink:href", "#" + href);
_svgGs.peek().appendChild(image);
return image;
}
@@ -1277,7 +1277,7 @@ public class Timeline {
exporter.endGroup();
}
Matrix mat = Matrix.getTranslateInstance(rect.xMin, rect.yMin).preConcatenate(new Matrix(layer.matrix));
exporter.addUse(mat, boundRect, assetName, layer.instanceName, scalingGrid == null ? null : scalingGrid.splitter, String.valueOf(drawable.getCharacterId()), String.join("___", drawable.getClassNames()), layer.blendMode);
exporter.addUse(mat, boundRect, assetName, layer.instanceName, scalingGrid == null ? null : scalingGrid.splitter, String.valueOf(drawable.getCharacterId()), String.join("___", drawable.getClassNames()), layer.blendMode, layer.filters);
}
}
}
@@ -16,10 +16,15 @@
*/
package com.jpexs.decompiler.flash.types.filters;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.SerializableImage;
import java.awt.Color;
import java.awt.image.BufferedImage;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* The Bevel filter creates a smooth bevel on display list objects.
@@ -121,4 +126,132 @@ public class BEVELFILTER extends FILTER {
public double getDeltaY() {
return blurY + Math.abs(distance * Math.sin(angle));
}
@Override
public String toSvg(Document document, Element filtersElement, SVGExporter exporter, String in) {
int type = Filtering.INNER;
if (onTop && !innerShadow) {
type = Filtering.FULL;
} else if (!innerShadow) {
type = Filtering.OUTER;
}
String shadowInner = null;
String hilightInner = null;
if (type != Filtering.OUTER) {
String hilight = dropShadowSvg(distance, angle, highlightColor, true, true, true, 0, 0, strength, passes, document, filtersElement, exporter, in);
String shadow = dropShadowSvg(distance, angle + Math.PI, shadowColor, true, true, true, 0, 0, strength, passes, document, filtersElement, exporter, in);
Element feComposite1 = document.createElement("feComposite");
feComposite1.setAttribute("in", hilight);
feComposite1.setAttribute("in2", shadow);
feComposite1.setAttribute("operator", "out");
hilightInner = exporter.getUniqueId("filterResult");
feComposite1.setAttribute("result", hilightInner);
filtersElement.appendChild(feComposite1);
Element feComposite2 = document.createElement("feComposite");
feComposite2.setAttribute("in", shadow);
feComposite2.setAttribute("in2", hilight);
feComposite2.setAttribute("operator", "out");
shadowInner = exporter.getUniqueId("filterResult");
feComposite2.setAttribute("result", shadowInner);
filtersElement.appendChild(feComposite2);
}
String shadowOuter = null;
String hilightOuter = null;
if (type != Filtering.INNER) {
String hilight = dropShadowSvg(distance, angle + Math.PI, highlightColor, false, true, true, 0, 0, strength, passes, document, filtersElement, exporter, in);
String shadow = dropShadowSvg(distance, angle, shadowColor, false, true, true, 0, 0, strength, passes, document, filtersElement, exporter, in);
Element feComposite1 = document.createElement("feComposite");
feComposite1.setAttribute("in", hilight);
feComposite1.setAttribute("in2", shadow);
feComposite1.setAttribute("operator", "out");
shadowOuter = exporter.getUniqueId("filterResult");
feComposite1.setAttribute("result", shadowOuter);
filtersElement.appendChild(feComposite1);
Element feComposite2 = document.createElement("feComposite");
feComposite2.setAttribute("in", shadow);
feComposite2.setAttribute("in2", hilight);
feComposite2.setAttribute("operator", "out");
hilightOuter = exporter.getUniqueId("filterResult");
feComposite2.setAttribute("result", hilightOuter);
filtersElement.appendChild(feComposite2);
}
String hilight = null;
String shadow = null;
switch (type) {
case Filtering.OUTER:
hilight = hilightOuter;
shadow = shadowOuter;
break;
case Filtering.INNER:
hilight = hilightInner;
shadow = shadowInner;
break;
case Filtering.FULL:
Element feComposite1 = document.createElement("feComposite");
feComposite1.setAttribute("in", hilightInner);
feComposite1.setAttribute("in2", hilightOuter);
feComposite1.setAttribute("operator", "over");
hilight = exporter.getUniqueId("filterResult");
feComposite1.setAttribute("result", hilight);
filtersElement.appendChild(feComposite1);
Element feComposite2 = document.createElement("feComposite");
feComposite2.setAttribute("in", shadowInner);
feComposite2.setAttribute("in2", shadowOuter);
feComposite2.setAttribute("operator", "over");
shadow = exporter.getUniqueId("filterResult");
feComposite2.setAttribute("result", shadow);
filtersElement.appendChild(feComposite2);
break;
}
Element feComposite3 = document.createElement("feComposite");
feComposite3.setAttribute("in", shadow);
feComposite3.setAttribute("in2", hilight);
feComposite3.setAttribute("operator", "over");
String result = exporter.getUniqueId("filterResult");
feComposite3.setAttribute("result", result);
filtersElement.appendChild(feComposite3);
result = blurSvg(blurX, blurY, passes, document, filtersElement, exporter, result);
if (type == Filtering.INNER) {
Element feComposite4 = document.createElement("feComposite");
feComposite4.setAttribute("in", result);
feComposite4.setAttribute("in2", in);
feComposite4.setAttribute("operator", "in");
result = exporter.getUniqueId("filterResult");
feComposite4.setAttribute("result", result);
filtersElement.appendChild(feComposite4);
}
if (type == Filtering.OUTER) {
Element feComposite4 = document.createElement("feComposite");
feComposite4.setAttribute("in", result);
feComposite4.setAttribute("in2", in);
feComposite4.setAttribute("operator", "out");
result = exporter.getUniqueId("filterResult");
feComposite4.setAttribute("result", result);
filtersElement.appendChild(feComposite4);
}
if (!knockout) {
Element feComposite4 = document.createElement("feComposite");
feComposite4.setAttribute("in", result);
feComposite4.setAttribute("in2", in);
feComposite4.setAttribute("operator", "over");
result = exporter.getUniqueId("filterResult");
feComposite4.setAttribute("result", result);
filtersElement.appendChild(feComposite4);
}
return result;
}
}
@@ -16,10 +16,16 @@
*/
package com.jpexs.decompiler.flash.types.filters;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.annotations.Reserved;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.SerializableImage;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Blur filter based on a sub-pixel precise median filter
@@ -68,4 +74,9 @@ public class BLURFILTER extends FILTER {
public double getDeltaY() {
return blurY;
}
@Override
public String toSvg(Document document, Element filtersElement, SVGExporter exporter, String in) {
return blurSvg(blurX, blurY, passes, document, filtersElement, exporter, in);
}
}
@@ -16,9 +16,14 @@
*/
package com.jpexs.decompiler.flash.types.filters;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.SerializableImage;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Applies a color transformation on the pixels of a display list object
@@ -60,4 +65,28 @@ public class COLORMATRIXFILTER extends FILTER {
public double getDeltaY() {
return 0;
}
@Override
public String toSvg(Document document, Element filtersElement, SVGExporter exporter, String in) {
Element element = document.createElement("feColorMatrix");
element.setAttribute("type", "matrix");
List<String> parts = new ArrayList<>();
for (int i = 0; i < matrix.length; i++) {
if (i % 5 == 4) {
parts.add("" + (matrix[i] / 255f));
} else {
parts.add("" + matrix[i]);
}
}
element.setAttribute("values", String.join(" ", parts));
element.setAttribute("in", in);
String result = exporter.getUniqueId("filterResult");
element.setAttribute("result", result);
filtersElement.appendChild(element);
return result;
}
}
@@ -16,12 +16,17 @@
*/
package com.jpexs.decompiler.flash.types.filters;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.annotations.Reserved;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.SerializableImage;
import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Two-dimensional discrete convolution filter.
@@ -93,11 +98,41 @@ public class CONVOLUTIONFILTER extends FILTER {
@Override
public double getDeltaX() {
return ((matrixX-1)>>1) + 1;
return ((matrixX - 1) >> 1) + 1;
}
@Override
public double getDeltaY() {
return ((matrixY-1)>>1) + 1;
return ((matrixY - 1) >> 1) + 1;
}
@Override
public String toSvg(Document document, Element filtersElement, SVGExporter exporter, String in) {
Element element = document.createElement("feConvolveMatrix");
element.setAttribute("order", "" + matrixX + " " + matrixY);
List<String> parts = new ArrayList<>();
for (int i = 0; i < matrix.length; i++) {
parts.add("" + matrix[i]);
}
element.setAttribute("kernelMatrix", String.join(" ", parts));
if (clamp) {
element.setAttribute("edgeMode", "duplicate");
} else {
element.setAttribute("edgeMode", "none");
}
element.setAttribute("preserveAlpha", preserveAlpha ? "true" : "false");
element.setAttribute("divisor", "" + divisor);
element.setAttribute("bias", "" + bias);
element.setAttribute("in", in);
String result = exporter.getUniqueId("filterResult");
element.setAttribute("result", result);
filtersElement.appendChild(element);
return result;
}
}
@@ -16,10 +16,14 @@
*/
package com.jpexs.decompiler.flash.types.filters;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.SerializableImage;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Drop shadow filter based on the same median filter as the blur filter
@@ -105,4 +109,9 @@ public class DROPSHADOWFILTER extends FILTER {
public double getDeltaY() {
return blurY + Math.abs(distance * Math.sin(angle));
}
@Override
public String toSvg(Document document, Element filtersElement, SVGExporter exporter, String in) {
return dropShadowSvg(distance, angle, dropShadowColor, innerShadow, knockout, compositeSource, blurX, blurY, strength, passes, document, filtersElement, exporter, in);
}
}
@@ -16,11 +16,17 @@
*/
package com.jpexs.decompiler.flash.types.filters;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.ConcreteClasses;
import com.jpexs.helpers.SerializableImage;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Bitmap filter
@@ -50,4 +56,195 @@ public abstract class FILTER implements Serializable {
public abstract double getDeltaX();
public abstract double getDeltaY();
public String toSvg(Document document, Element filtersElement, SVGExporter exporter, String in) {
return null;
}
protected String dropShadowSvg(
double distance,
double angle,
RGBA dropShadowColor,
boolean innerShadow,
boolean knockout,
boolean compositeSource,
double blurX,
double blurY,
double strength,
int iterations,
Document document,
Element filtersElement,
SVGExporter exporter,
String in
) {
double dx = distance * Math.cos(angle);
double dy = distance * Math.sin(angle);
if (innerShadow) {
Element feFlood = document.createElement("feFlood");
feFlood.setAttribute("flood-color", dropShadowColor.toHexRGB());
feFlood.setAttribute("flood-opacity", "" + dropShadowColor.getAlphaFloat());
filtersElement.appendChild(feFlood);
String feFloodResult = exporter.getUniqueId("filterResult");
feFlood.setAttribute("result", feFloodResult);
Element feOffset = document.createElement("feOffset");
feOffset.setAttribute("dx", "" + dx);
feOffset.setAttribute("dy", "" + dy);
feOffset.setAttribute("in", in);
String feOffsetResult = exporter.getUniqueId("filterResult");
feOffset.setAttribute("result", feOffsetResult);
filtersElement.appendChild(feOffset);
Element feComposite1 = document.createElement("feComposite");
feComposite1.setAttribute("in", feFloodResult);
feComposite1.setAttribute("in2", feOffsetResult);
feComposite1.setAttribute("operator", "out");
String feComposite1Result = exporter.getUniqueId("filterResult");
feComposite1.setAttribute("result", feComposite1Result);
filtersElement.appendChild(feComposite1);
String blurResult = blurSvg(blurX, blurY, iterations, document, filtersElement, exporter, feComposite1Result);
Element feComposite2 = document.createElement("feComposite");
feComposite2.setAttribute("in", blurResult);
feComposite2.setAttribute("in2", in);
feComposite2.setAttribute("operator", "in");
String result = exporter.getUniqueId("filterResult");
feComposite2.setAttribute("result", result);
filtersElement.appendChild(feComposite2);
if (Double.compare(strength, 1.0) != 0) {
Element feColorMatrix2 = document.createElement("feColorMatrix");
feColorMatrix2.setAttribute("type", "matrix");
feColorMatrix2.setAttribute("in", result);
feColorMatrix2.setAttribute("values",
"1 0 0 0 0,"
+ "0 1 0 0 0,"
+ "0 0 1 0 0,"
+ "0 0 0 " + strength + " 0"
);
result = exporter.getUniqueId("filterResult");
feColorMatrix2.setAttribute("result", result);
filtersElement.appendChild(feColorMatrix2);
}
if (knockout || !compositeSource) {
return result;
}
Element feComposite3 = document.createElement("feComposite");
feComposite3.setAttribute("in", result);
feComposite3.setAttribute("in2", in);
feComposite3.setAttribute("operator", "over");
result = exporter.getUniqueId("filterResult");
feComposite3.setAttribute("result", result);
filtersElement.appendChild(feComposite3);
return result;
} else {
Element feOffset = document.createElement("feOffset");
feOffset.setAttribute("dx", "" + dx);
feOffset.setAttribute("dy", "" + dy);
feOffset.setAttribute("in", in);
String feOffsetResult = exporter.getUniqueId("filterResult");
feOffset.setAttribute("result", feOffsetResult);
filtersElement.appendChild(feOffset);
Element feColorMatrix = document.createElement("feColorMatrix");
feColorMatrix.setAttribute("type", "matrix");
feColorMatrix.setAttribute("in", feOffsetResult);
feColorMatrix.setAttribute("values",
"0 0 0 0 " + (dropShadowColor.red / 255f) + ","
+ "0 0 0 0 " + (dropShadowColor.green / 255f) + ","
+ "0 0 0 0 " + (dropShadowColor.blue / 255f) + ","
+ "0 0 0 1 0"
);
String feColorMatrixResult = exporter.getUniqueId("filterResult");
feColorMatrix.setAttribute("result", feColorMatrixResult);
filtersElement.appendChild(feColorMatrix);
String result = blurSvg(blurX, blurY, iterations, document, filtersElement, exporter, feColorMatrixResult);
if (Double.compare(strength, 1.0) != 0) {
Element feColorMatrix2 = document.createElement("feColorMatrix");
feColorMatrix2.setAttribute("type", "matrix");
feColorMatrix2.setAttribute("in", result);
feColorMatrix2.setAttribute("values",
"1 0 0 0 0,"
+ "0 1 0 0 0,"
+ "0 0 1 0 0,"
+ "0 0 0 " + strength + " 0"
);
result = exporter.getUniqueId("filterResult");
feColorMatrix2.setAttribute("result", result);
filtersElement.appendChild(feColorMatrix2);
}
if (!knockout && !compositeSource) {
return result;
}
Element feComposite = document.createElement("feComposite");
if (knockout) {
feComposite.setAttribute("in", result);
feComposite.setAttribute("in2", in);
feComposite.setAttribute("operator", "out");
} else {
feComposite.setAttribute("in", in);
feComposite.setAttribute("in2", result);
feComposite.setAttribute("operator", "over");
}
result = exporter.getUniqueId("filterResult");
feComposite.setAttribute("result", result);
filtersElement.appendChild(feComposite);
return result;
}
}
protected String blurSvg(double blurX, double blurY, int iterations, Document document, Element filtersElement, SVGExporter exporter, String in) {
if (iterations == 0) {
return in;
}
if (Double.compare(blurX, 0.0) == 0 && Double.compare(blurY, 0.0) == 0) {
return in;
}
Element element = document.createElement("feConvolveMatrix");
List<String> parts = new ArrayList<>();
double divisor;
if (Double.compare(blurX, 0.0) == 0) {
int orderX = (int) Math.ceil(blurX);
divisor = orderX;
element.setAttribute("order", "" + orderX + " 1");
} else if (Double.compare(blurY, 0.0) == 0) {
int orderY = (int) Math.ceil(blurY);
divisor = orderY;
element.setAttribute("order", "1 " + orderY);
} else {
int orderX = (int) Math.ceil(blurX);
int orderY = (int) Math.ceil(blurY);
divisor = orderX * orderY;
element.setAttribute("order", "" + orderX + " " + orderY);
}
for (int i = 0; i < divisor; i++) {
parts.add("1");
}
element.setAttribute("divisor", "" + divisor);
element.setAttribute("kernelMatrix", String.join(" ", parts));
element.setAttribute("in", in);
String result = exporter.getUniqueId("filterResult");
element.setAttribute("result", result);
filtersElement.appendChild(element);
return blurSvg(blurX, blurY, iterations - 1, document, filtersElement, exporter, result);
}
}
@@ -382,7 +382,7 @@ public class Filtering {
public static SerializableImage glow(SerializableImage src, int blurX, int blurY, float strength, Color color, boolean inner, boolean knockout, int iterations) {
return new SerializableImage(dropShadow(src.getBufferedImage(), blurX, blurY, 45, 0, color, inner, iterations, strength, knockout, true));
}
}
private static Color over(Color a, Color b) {
int resultA = a.getAlpha() + b.getAlpha() * (255 - a.getAlpha()) / 255;
@@ -561,12 +561,12 @@ public class Filtering {
public static SerializableImage convolution(
SerializableImage src,
float[] matrix,
int w,
int w,
int h,
float divisor,
float bias,
Color defaultColor,
boolean clamp,
boolean clamp,
boolean preserveAlpha,
int srcX,
int srcY,
@@ -576,8 +576,8 @@ public class Filtering {
Kernel kernel = new Kernel(w, h, matrix);
BufferedImage dst = new BufferedImage(src.getWidth() + 1, src.getHeight() + 1, src.getType());
BufferedImageOp op = new ConvolveOp(
kernel,
new RenderingHints(null),
kernel,
new RenderingHints(null),
divisor,
bias,
defaultColor,
@@ -16,10 +16,14 @@
*/
package com.jpexs.decompiler.flash.types.filters;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.SerializableImage;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Glow filter
@@ -93,4 +97,103 @@ public class GLOWFILTER extends FILTER {
public double getDeltaY() {
return blurY;
}
@Override
public String toSvg(Document document, Element filtersElement, SVGExporter exporter, String in) {
/*Element element = document.createElement("feDropShadow");
element.setAttribute("dx", "0");
element.setAttribute("dy", "0");
double blur = ((blurX + blurY) / 2);
element.setAttribute("stdDeviation", "" + blur);
element.setAttribute("flood-color", glowColor.toHexRGB());
element.setAttribute("flood-opacity", "" + glowColor.getAlphaFloat());
element.setAttribute("in", in);
String result = exporter.getUniqueId("filterResult");
element.setAttribute("result", result);
filtersElement.appendChild(element);
return result;*/
if (innerGlow) {
Element feFlood = document.createElement("feFlood");
feFlood.setAttribute("flood-color", glowColor.toHexRGB());
feFlood.setAttribute("flood-opacity", "" + glowColor.getAlphaFloat());
filtersElement.appendChild(feFlood);
String feFloodResult = exporter.getUniqueId("filterResult");
feFlood.setAttribute("result", feFloodResult);
Element feComposite1 = document.createElement("feComposite");
feComposite1.setAttribute("in", feFloodResult);
feComposite1.setAttribute("in2", in);
feComposite1.setAttribute("operator", "out");
String feComposite1Result = exporter.getUniqueId("filterResult");
feComposite1.setAttribute("result", feComposite1Result);
filtersElement.appendChild(feComposite1);
String blurResult = blurSvg(blurX, blurY, passes, document, filtersElement, exporter, feComposite1Result);
Element feComposite2 = document.createElement("feComposite");
feComposite2.setAttribute("in", blurResult);
feComposite2.setAttribute("in2", in);
feComposite2.setAttribute("operator", "in");
String feComposite2Result = exporter.getUniqueId("filterResult");
feComposite2.setAttribute("result", feComposite2Result);
filtersElement.appendChild(feComposite2);
if (knockout || !compositeSource) {
return feComposite2Result;
}
Element feComposite3 = document.createElement("feComposite");
feComposite3.setAttribute("in", feComposite2Result);
feComposite3.setAttribute("in2", in);
feComposite3.setAttribute("operator", "over");
String feComposite3Result = exporter.getUniqueId("filterResult");
feComposite3.setAttribute("result", feComposite3Result);
filtersElement.appendChild(feComposite3);
return feComposite3Result;
} else {
Element feColorMatrix = document.createElement("feColorMatrix");
feColorMatrix.setAttribute("type", "matrix");
feColorMatrix.setAttribute("in", in);
feColorMatrix.setAttribute("values",
"0 0 0 0 " + (glowColor.red / 255f) + ","
+ "0 0 0 0 " + (glowColor.green / 255f) + ","
+ "0 0 0 0 " + (glowColor.blue / 255f) + ","
+ "0 0 0 1 0"
);
String feColorMatrixResult = exporter.getUniqueId("filterResult");
feColorMatrix.setAttribute("result", feColorMatrixResult);
filtersElement.appendChild(feColorMatrix);
String blurResult = blurSvg(blurX, blurY, passes, document, filtersElement, exporter, feColorMatrixResult);
if (!knockout && !compositeSource) {
return blurResult;
}
Element feComposite = document.createElement("feComposite");
if (knockout) {
feComposite.setAttribute("in", blurResult);
feComposite.setAttribute("in2", in);
feComposite.setAttribute("operator", "out");
} else {
feComposite.setAttribute("in", in);
feComposite.setAttribute("in2", blurResult);
feComposite.setAttribute("operator", "over");
}
String feCompositeResult = exporter.getUniqueId("filterResult");
feComposite.setAttribute("result", feCompositeResult);
filtersElement.appendChild(feComposite);
return feCompositeResult;
}
}
}