mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-09 21:04:30 +00:00
SVG export - Gradient glow filter
SVG filters refactoring
This commit is contained in:
@@ -129,11 +129,13 @@ public class BEVELFILTER extends FILTER {
|
||||
|
||||
@Override
|
||||
public String toSvg(Document document, Element filtersElement, SVGExporter exporter, String in) {
|
||||
RGBA shadowColorTransparent = new RGBA(shadowColor);
|
||||
shadowColorTransparent.alpha = 0;
|
||||
RGBA highlightColorTransparent = new RGBA(highlightColor);
|
||||
highlightColorTransparent.alpha = 0;
|
||||
return bevelSvg(distance, angle, new RGBA[]{shadowColor, shadowColorTransparent, highlightColorTransparent, highlightColor}, new int[]{0, 127, 128, 255}, knockout, onTop, innerShadow, blurX, blurY, strength, passes, document, filtersElement, exporter, in);
|
||||
int type = Filtering.INNER;
|
||||
if (onTop && !innerShadow) {
|
||||
type = Filtering.FULL;
|
||||
} else if (!innerShadow) {
|
||||
type = Filtering.OUTER;
|
||||
}
|
||||
return SvgFiltering.bevel(distance, angle, highlightColor, shadowColor, knockout, compositeSource, type, blurX, blurY, strength, passes, document, filtersElement, exporter, in);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -80,7 +80,7 @@ public class BLURFILTER extends FILTER {
|
||||
|
||||
@Override
|
||||
public String toSvg(Document document, Element filtersElement, SVGExporter exporter, String in) {
|
||||
return blurSvg(blurX, blurY, passes, document, filtersElement, exporter, in);
|
||||
return SvgFiltering.blur(blurX, blurY, passes, document, filtersElement, exporter, in);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -116,6 +116,5 @@ public class BLURFILTER extends FILTER {
|
||||
}
|
||||
return this.reserved == other.reserved;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -172,6 +172,7 @@ public final class BlendComposite implements Composite {
|
||||
|
||||
/**
|
||||
* Gets alpha.
|
||||
*
|
||||
* @return Alpha
|
||||
*/
|
||||
public float getAlpha() {
|
||||
|
||||
@@ -119,5 +119,4 @@ public class COLORMATRIXFILTER extends FILTER {
|
||||
return Arrays.equals(this.matrix, other.matrix);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -194,6 +194,5 @@ public class CONVOLUTIONFILTER extends FILTER {
|
||||
}
|
||||
return Objects.equals(this.defaultColor, other.defaultColor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public class DROPSHADOWFILTER extends FILTER {
|
||||
|
||||
@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);
|
||||
return SvgFiltering.dropShadow(distance, angle, dropShadowColor, innerShadow, knockout, compositeSource, blurX, blurY, strength, passes, document, filtersElement, exporter, in);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -173,6 +173,5 @@ public class DROPSHADOWFILTER extends FILTER {
|
||||
}
|
||||
return Objects.equals(this.dropShadowColor, other.dropShadowColor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,20 +16,13 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types.filters;
|
||||
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
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.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.helpers.ConcreteClasses;
|
||||
import com.jpexs.helpers.GradientUtil;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Color;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
@@ -101,293 +94,6 @@ public abstract class FILTER implements Serializable {
|
||||
*/
|
||||
public abstract String toSvg(Document document, Element filtersElement, SVGExporter exporter, String in);
|
||||
|
||||
/**
|
||||
* Converts drop shadow to SVG.
|
||||
*
|
||||
* @param distance Distance
|
||||
* @param angle Angle
|
||||
* @param dropShadowColor Drop shadow color
|
||||
* @param innerShadow Inner shadow
|
||||
* @param knockout Knockout
|
||||
* @param compositeSource Composite source
|
||||
* @param blurX Blur X
|
||||
* @param blurY Blur Y
|
||||
* @param strength Strength
|
||||
* @param iterations Iterations
|
||||
* @param document Document
|
||||
* @param filtersElement Filters element
|
||||
* @param exporter SVG exporter
|
||||
* @param in Input
|
||||
* @return SVG id of the drop shadow
|
||||
*/
|
||||
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
|
||||
) {
|
||||
return dropShadowSvg(
|
||||
distance,
|
||||
angle,
|
||||
new RGBA[]{dropShadowColor},
|
||||
new int[0],
|
||||
innerShadow,
|
||||
knockout,
|
||||
compositeSource,
|
||||
blurX,
|
||||
blurY,
|
||||
strength,
|
||||
iterations,
|
||||
document,
|
||||
filtersElement,
|
||||
exporter,
|
||||
in
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts drop shadow to SVG.
|
||||
*
|
||||
* @param distance Distance
|
||||
* @param angle Angle
|
||||
* @param dropShadowColor Drop shadow color
|
||||
* @param innerShadow Inner shadow
|
||||
* @param knockout Knockout
|
||||
* @param compositeSource Composite source
|
||||
* @param blurX Blur X
|
||||
* @param blurY Blur Y
|
||||
* @param strength Strength
|
||||
* @param iterations Iterations
|
||||
* @param document Document
|
||||
* @param filtersElement Filters element
|
||||
* @param exporter SVG exporter
|
||||
* @param in Input
|
||||
* @return SVG id of the drop shadow
|
||||
*/
|
||||
protected String dropShadowSvg(
|
||||
double distance,
|
||||
double angle,
|
||||
RGBA[] gradientColors,
|
||||
int[] gradientRatio,
|
||||
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);
|
||||
|
||||
RGBA dropShadowColor = gradientColors.length == 1 ? gradientColors[0] : new RGBA(0, 0, 0, 255);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts blur to SVG.
|
||||
*
|
||||
* @param blurX Blur X
|
||||
* @param blurY Blur Y
|
||||
* @param iterations Iterations
|
||||
* @param document Document
|
||||
* @param filtersElement Filters element
|
||||
* @param exporter SVG exporter
|
||||
* @param in Input
|
||||
* @return SVG id of the blur
|
||||
*/
|
||||
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;
|
||||
if (Configuration.svgExportGaussianBlur.get()) {
|
||||
double blurXScaled = blurX * exporter.getZoom();
|
||||
double blurYScaled = blurY * exporter.getZoom();
|
||||
|
||||
double deviationX = Math.sqrt((blurXScaled * blurXScaled - 1) / 12);
|
||||
double deviationY = Math.sqrt((blurYScaled * blurYScaled - 1) / 12);
|
||||
|
||||
element = document.createElement("feGaussianBlur");
|
||||
|
||||
element.setAttribute("stdDeviation", "" + deviationX + " " + deviationY);
|
||||
} else {
|
||||
element = document.createElement("feConvolveMatrix");
|
||||
|
||||
List<String> parts = new ArrayList<>();
|
||||
|
||||
int orderX = (int) Math.ceil(blurX * exporter.getZoom());
|
||||
int orderY = (int) Math.ceil(blurY * exporter.getZoom());
|
||||
|
||||
if (orderX % 2 == 0) {
|
||||
orderX++;
|
||||
}
|
||||
|
||||
if (orderY % 2 == 0) {
|
||||
orderY++;
|
||||
}
|
||||
|
||||
double 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("kernelUnitLength", "1");
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts gradient ratios to Java format float ratios.
|
||||
*
|
||||
@@ -431,226 +137,4 @@ public abstract class FILTER implements Serializable {
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
protected String bevelSvg(double distance, double angle, RGBA[] gradientColors, int[] gradientRatio, boolean knockout, boolean onTop, boolean innerShadow, double blurX, double blurY, double strength, int passes, Document document, Element filtersElement, SVGExporter exporter, String in) {
|
||||
RGBA highlightColor = new RGBA(255, 0, 0, 255);
|
||||
RGBA shadowColor = new RGBA(0, 0, 255, 255);
|
||||
|
||||
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");
|
||||
hilightOuter = exporter.getUniqueId("filterResult");
|
||||
feComposite1.setAttribute("result", hilightOuter);
|
||||
filtersElement.appendChild(feComposite1);
|
||||
|
||||
Element feComposite2 = document.createElement("feComposite");
|
||||
feComposite2.setAttribute("in", shadow);
|
||||
feComposite2.setAttribute("in2", hilight);
|
||||
feComposite2.setAttribute("operator", "out");
|
||||
shadowOuter = exporter.getUniqueId("filterResult");
|
||||
feComposite2.setAttribute("result", shadowOuter);
|
||||
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 feFlood = document.createElement("feFlood");
|
||||
feFlood.setAttribute("flood-color", "black");
|
||||
feFlood.setAttribute("flood-opacity", "1");
|
||||
String black = exporter.getUniqueId("filterResult");
|
||||
feFlood.setAttribute("result", black);
|
||||
filtersElement.appendChild(feFlood);
|
||||
|
||||
String result;
|
||||
|
||||
Element feComposite4 = document.createElement("feComposite");
|
||||
feComposite4.setAttribute("in", shadow);
|
||||
feComposite4.setAttribute("in2", black);
|
||||
feComposite4.setAttribute("operator", "over");
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feComposite4.setAttribute("result", result);
|
||||
filtersElement.appendChild(feComposite4);
|
||||
|
||||
Element feComposite5 = document.createElement("feComposite");
|
||||
feComposite5.setAttribute("in", hilight);
|
||||
feComposite5.setAttribute("in2", result);
|
||||
feComposite5.setAttribute("operator", "over");
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feComposite5.setAttribute("result", result);
|
||||
filtersElement.appendChild(feComposite5);
|
||||
|
||||
result = blurSvg(blurX, blurY, passes, document, filtersElement, exporter, result);
|
||||
|
||||
Element feColorMatrix = document.createElement("feColorMatrix");
|
||||
feColorMatrix.setAttribute("type", "matrix");
|
||||
feColorMatrix.setAttribute("in", result);
|
||||
double halfStrength = strength / 2;
|
||||
String matrixRow = "" + halfStrength + " 0 " + (-halfStrength) + " 0 0.5";
|
||||
feColorMatrix.setAttribute("values",
|
||||
matrixRow + " "
|
||||
+ matrixRow + " "
|
||||
+ matrixRow + " "
|
||||
+ matrixRow
|
||||
);
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feColorMatrix.setAttribute("result", result);
|
||||
filtersElement.appendChild(feColorMatrix);
|
||||
|
||||
result = prepareFeComponentTransfer(gradientColors, gradientRatio, document, filtersElement, exporter, result);
|
||||
|
||||
if (type == Filtering.INNER) {
|
||||
Element feComposite6 = document.createElement("feComposite");
|
||||
feComposite6.setAttribute("in", result);
|
||||
feComposite6.setAttribute("in2", in);
|
||||
feComposite6.setAttribute("operator", "in");
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feComposite6.setAttribute("result", result);
|
||||
filtersElement.appendChild(feComposite6);
|
||||
}
|
||||
if (type == Filtering.OUTER) {
|
||||
Element feComposite6 = document.createElement("feComposite");
|
||||
feComposite6.setAttribute("in", result);
|
||||
feComposite6.setAttribute("in2", in);
|
||||
feComposite6.setAttribute("operator", "out");
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feComposite6.setAttribute("result", result);
|
||||
filtersElement.appendChild(feComposite6);
|
||||
}
|
||||
|
||||
if (!knockout) {
|
||||
Element feComposite7 = document.createElement("feComposite");
|
||||
feComposite7.setAttribute("in", result);
|
||||
feComposite7.setAttribute("in2", in);
|
||||
feComposite7.setAttribute("operator", "over");
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feComposite7.setAttribute("result", result);
|
||||
filtersElement.appendChild(feComposite7);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String prepareFeComponentTransfer(RGBA[] gradientColors, int[] gradientRatio, Document document, Element filtersElement, SVGExporter exporter, String in) {
|
||||
Element feComponentTransfer = document.createElement("feComponentTransfer");
|
||||
feComponentTransfer.setAttribute("in", in);
|
||||
|
||||
List<String> redValues = new ArrayList<>();
|
||||
List<String> greenValues = new ArrayList<>();
|
||||
List<String> blueValues = new ArrayList<>();
|
||||
List<String> alphaValues = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
RGBA color = GradientUtil.colorAt(gradientColors, gradientRatio, i, GradientUtil.ColorInterpolation.SRGB);
|
||||
redValues.add("" + (color.red / 255f));
|
||||
greenValues.add("" + (color.green / 255f));
|
||||
blueValues.add("" + (color.blue / 255f));
|
||||
alphaValues.add("" + color.getAlphaFloat());
|
||||
}
|
||||
|
||||
/*
|
||||
//In case we want to map 128 to center
|
||||
|
||||
for (int i = 0; i < 126; i++) { //126 colors
|
||||
RGBA color = GradientUtil.colorAt(gradientColors, gradientRatio, i * 127f / 125f, GradientUtil.ColorInterpolation.SRGB);
|
||||
redValues.add("" + (color.red / 255f));
|
||||
greenValues.add("" + (color.green / 255f));
|
||||
blueValues.add("" + (color.blue / 255f));
|
||||
alphaValues.add("" + color.getAlphaFloat());
|
||||
}
|
||||
for (int i = 128; i < 256; i++) { //1 center + 126 colors
|
||||
RGBA color = GradientUtil.colorAt(gradientColors, gradientRatio, i, GradientUtil.ColorInterpolation.SRGB);
|
||||
redValues.add("" + (color.red / 255f));
|
||||
greenValues.add("" + (color.green / 255f));
|
||||
blueValues.add("" + (color.blue / 255f));
|
||||
alphaValues.add("" + color.getAlphaFloat());
|
||||
}
|
||||
*/
|
||||
Element feFuncR = document.createElement("feFuncR");
|
||||
feFuncR.setAttribute("type", "table");
|
||||
feFuncR.setAttribute("tableValues", String.join(" ", redValues));
|
||||
Element feFuncG = document.createElement("feFuncG");
|
||||
feFuncG.setAttribute("type", "table");
|
||||
feFuncG.setAttribute("tableValues", String.join(" ", greenValues));
|
||||
Element feFuncB = document.createElement("feFuncB");
|
||||
feFuncB.setAttribute("type", "table");
|
||||
feFuncB.setAttribute("tableValues", String.join(" ", blueValues));
|
||||
Element feFuncA = document.createElement("feFuncA");
|
||||
feFuncA.setAttribute("type", "table");
|
||||
feFuncA.setAttribute("tableValues", String.join(" ", alphaValues));
|
||||
feComponentTransfer.appendChild(feFuncR);
|
||||
feComponentTransfer.appendChild(feFuncG);
|
||||
feComponentTransfer.appendChild(feFuncB);
|
||||
feComponentTransfer.appendChild(feFuncA);
|
||||
|
||||
String result = exporter.getUniqueId("filterResult");
|
||||
feComponentTransfer.setAttribute("result", result);
|
||||
filtersElement.appendChild(feComponentTransfer);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,101 +101,7 @@ public class GLOWFILTER extends FILTER {
|
||||
|
||||
@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;
|
||||
}
|
||||
return SvgFiltering.glow(glowColor, knockout, innerGlow, compositeSource, blurX, blurY, strength, passes, document, filtersElement, exporter, in);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -247,6 +153,5 @@ public class GLOWFILTER extends FILTER {
|
||||
}
|
||||
return Objects.equals(this.glowColor, other.glowColor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -143,7 +143,13 @@ public class GRADIENTBEVELFILTER extends FILTER {
|
||||
|
||||
@Override
|
||||
public String toSvg(Document document, Element filtersElement, SVGExporter exporter, String in) {
|
||||
return bevelSvg(distance, angle, gradientColors, gradientRatio, knockout, onTop, innerShadow, blurX, blurY, strength, passes, document, filtersElement, exporter, in);
|
||||
int type = Filtering.INNER;
|
||||
if (onTop && !innerShadow) {
|
||||
type = Filtering.FULL;
|
||||
} else if (!innerShadow) {
|
||||
type = Filtering.OUTER;
|
||||
}
|
||||
return SvgFiltering.gradientBevel(distance, angle, gradientColors, gradientRatio, knockout, compositeSource, type, blurX, blurY, strength, passes, document, filtersElement, exporter, in);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -122,7 +122,7 @@ public class GRADIENTGLOWFILTER extends FILTER {
|
||||
colorsArr[i] = gradientColors[i].toColor();
|
||||
}
|
||||
float[] ratiosArr = convertRatiosToJavaGradient(gradientRatio);
|
||||
|
||||
|
||||
int type = Filtering.INNER;
|
||||
if (onTop && !innerShadow) {
|
||||
type = Filtering.FULL;
|
||||
@@ -145,7 +145,13 @@ public class GRADIENTGLOWFILTER extends FILTER {
|
||||
|
||||
@Override
|
||||
public String toSvg(Document document, Element filtersElement, SVGExporter exporter, String in) {
|
||||
return null; //NOT SUPPORTED
|
||||
int type = Filtering.INNER;
|
||||
if (onTop && !innerShadow) {
|
||||
type = Filtering.FULL;
|
||||
} else if (!innerShadow) {
|
||||
type = Filtering.OUTER;
|
||||
}
|
||||
return SvgFiltering.gradientGlow(distance, angle, gradientColors, gradientRatio, knockout, type, compositeSource, innerShadow, blurX, blurY, strength, passes, document, filtersElement, exporter, in);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -213,6 +219,5 @@ public class GRADIENTGLOWFILTER extends FILTER {
|
||||
}
|
||||
return Arrays.equals(this.gradientRatio, other.gradientRatio);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2026 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types.filters;
|
||||
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import com.jpexs.helpers.GradientUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* SVG filtering
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SvgFiltering {
|
||||
|
||||
/**
|
||||
* Blur filter
|
||||
*
|
||||
* @param blurX Blur X
|
||||
* @param blurY Blur Y
|
||||
* @param iterations Iterations
|
||||
* @param document Document
|
||||
* @param filtersElement Filters element
|
||||
* @param exporter SVG exporter
|
||||
* @param in Input
|
||||
* @return SVG id of the blur
|
||||
*/
|
||||
public static String blur(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;
|
||||
if (Configuration.svgExportGaussianBlur.get()) {
|
||||
double blurXScaled = blurX * exporter.getZoom();
|
||||
double blurYScaled = blurY * exporter.getZoom();
|
||||
|
||||
double deviationX = Math.sqrt((blurXScaled * blurXScaled - 1) / 12);
|
||||
double deviationY = Math.sqrt((blurYScaled * blurYScaled - 1) / 12);
|
||||
|
||||
element = document.createElement("feGaussianBlur");
|
||||
|
||||
element.setAttribute("stdDeviation", "" + deviationX + " " + deviationY);
|
||||
} else {
|
||||
element = document.createElement("feConvolveMatrix");
|
||||
|
||||
List<String> parts = new ArrayList<>();
|
||||
|
||||
int orderX = (int) Math.ceil(blurX * exporter.getZoom());
|
||||
int orderY = (int) Math.ceil(blurY * exporter.getZoom());
|
||||
|
||||
if (orderX % 2 == 0) {
|
||||
orderX++;
|
||||
}
|
||||
|
||||
if (orderY % 2 == 0) {
|
||||
orderY++;
|
||||
}
|
||||
|
||||
double 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("kernelUnitLength", "1");
|
||||
}
|
||||
element.setAttribute("in", in);
|
||||
|
||||
String result = exporter.getUniqueId("filterResult");
|
||||
element.setAttribute("result", result);
|
||||
|
||||
filtersElement.appendChild(element);
|
||||
|
||||
return blur(blurX, blurY, iterations - 1, document, filtersElement, exporter, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose result according to INNER/OUTER/FULL
|
||||
*
|
||||
* @param src Source
|
||||
* @param result Result
|
||||
* @param type Type
|
||||
* @param knockout Knockout
|
||||
* @param compositeSource Composite source
|
||||
* @param document Document
|
||||
* @param filtersElement Filters element
|
||||
* @param exporter Exporter
|
||||
* @return Result
|
||||
*/
|
||||
private static String compose(
|
||||
String src,
|
||||
String result,
|
||||
int type,
|
||||
boolean knockout,
|
||||
boolean compositeSource,
|
||||
Document document,
|
||||
Element filtersElement,
|
||||
SVGExporter exporter
|
||||
) {
|
||||
String in = "";
|
||||
String in2 = "";
|
||||
String operator = "";
|
||||
String dst = result;
|
||||
|
||||
if (type == Filtering.FULL && !knockout && compositeSource) {
|
||||
operator = "over";
|
||||
in = dst;
|
||||
in2 = src;
|
||||
//dstover
|
||||
} else if (type == Filtering.INNER) {
|
||||
if (knockout || !compositeSource) {
|
||||
operator = "in";
|
||||
//dstin
|
||||
} else {
|
||||
operator = "atop";
|
||||
//dstatop
|
||||
}
|
||||
in = dst;
|
||||
in2 = src;
|
||||
} else if (type == Filtering.OUTER) {
|
||||
if (knockout) {
|
||||
in = dst;
|
||||
in2 = src;
|
||||
operator = "out";
|
||||
//dstout
|
||||
} else if (compositeSource) {
|
||||
in = src;
|
||||
in2 = dst;
|
||||
operator = "over";
|
||||
//srcover
|
||||
}
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
|
||||
Element feComposite = document.createElement("feComposite");
|
||||
feComposite.setAttribute("in", in);
|
||||
feComposite.setAttribute("in2", in2);
|
||||
feComposite.setAttribute("operator", operator);
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feComposite.setAttribute("result", result);
|
||||
filtersElement.appendChild(feComposite);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Glow filter
|
||||
*
|
||||
* @param glowColor Glow color
|
||||
* @param knockout Knockout
|
||||
* @param innerGlow Inner glow
|
||||
* @param compositeSource Composite source
|
||||
* @param blurX Blur X
|
||||
* @param blurY Blur Y
|
||||
* @param strength Strength
|
||||
* @param iterations Iterations
|
||||
* @param document Document
|
||||
* @param filtersElement Filters element
|
||||
* @param exporter Exporter
|
||||
* @param in In
|
||||
* @return Result
|
||||
*/
|
||||
public static String glow(RGBA glowColor, boolean knockout, boolean innerGlow, boolean compositeSource, double blurX, double blurY, double strength, int iterations, Document document, Element filtersElement, SVGExporter exporter, String in) {
|
||||
return dropShadow(0, 45, glowColor, innerGlow, knockout, true, blurX, blurY, strength, iterations, document, filtersElement, exporter, in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gradient glow
|
||||
*
|
||||
* @param distance Distance
|
||||
* @param angle Angle
|
||||
* @param gradientColors Gradient colors
|
||||
* @param gradientRatio Gradient ratio
|
||||
* @param knockout Knockout
|
||||
* @param type Type
|
||||
* @param compositeSource Composite source
|
||||
* @param innerGlow Inner glow
|
||||
* @param blurX Blur X
|
||||
* @param blurY Blur Y
|
||||
* @param strength Strength
|
||||
* @param iterations Iterations
|
||||
* @param document Document
|
||||
* @param filtersElement Filters element
|
||||
* @param exporter Exporter
|
||||
* @param in In
|
||||
* @return Result
|
||||
*/
|
||||
public static String gradientGlow(double distance, double angle, RGBA[] gradientColors, int[] gradientRatio, boolean knockout, int type, boolean compositeSource, boolean innerGlow, double blurX, double blurY, double strength, int iterations, Document document, Element filtersElement, SVGExporter exporter, String in) {
|
||||
RGBA glowColor = new RGBA(255, 0, 0, 255);
|
||||
|
||||
double dx = distance * exporter.getZoom() * Math.cos(angle);
|
||||
double dy = distance * exporter.getZoom() * Math.sin(angle);
|
||||
|
||||
Element feFloodBlack = document.createElement("feFlood");
|
||||
feFloodBlack.setAttribute("flood-color", "black");
|
||||
feFloodBlack.setAttribute("flood-opacity", "1");
|
||||
String black = exporter.getUniqueId("filterResult");
|
||||
feFloodBlack.setAttribute("result", black);
|
||||
filtersElement.appendChild(feFloodBlack);
|
||||
|
||||
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);
|
||||
|
||||
String result;
|
||||
|
||||
Element feColorMatrix = document.createElement("feColorMatrix");
|
||||
feColorMatrix.setAttribute("type", "matrix");
|
||||
feColorMatrix.setAttribute("in", feOffsetResult);
|
||||
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 " + (glowColor.alpha / 255f) + " 0" //Note: it is not last one here
|
||||
);
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feColorMatrix.setAttribute("result", result);
|
||||
filtersElement.appendChild(feColorMatrix);
|
||||
|
||||
Element feComposite = document.createElement("feComposite");
|
||||
feComposite.setAttribute("in", result);
|
||||
feComposite.setAttribute("in2", black);
|
||||
feComposite.setAttribute("operator", "over");
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feComposite.setAttribute("result", result);
|
||||
filtersElement.appendChild(feComposite);
|
||||
|
||||
if (Double.compare(blurX, 0.0) != 0 || Double.compare(blurY, 0.0) != 0) {
|
||||
result = blur(blurX, blurY, iterations, document, filtersElement, exporter, result);
|
||||
}
|
||||
|
||||
Element feColorMatrix2 = document.createElement("feColorMatrix");
|
||||
feColorMatrix2.setAttribute("type", "matrix");
|
||||
feColorMatrix2.setAttribute("in", result);
|
||||
String matrixRow = "" + strength + " 0 0 0 0";
|
||||
feColorMatrix2.setAttribute("values",
|
||||
matrixRow + " "
|
||||
+ matrixRow + " "
|
||||
+ matrixRow + " "
|
||||
+ matrixRow
|
||||
);
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feColorMatrix2.setAttribute("result", result);
|
||||
filtersElement.appendChild(feColorMatrix2);
|
||||
|
||||
result = prepareFeComponentTransfer(gradientColors, gradientRatio, document, filtersElement, exporter, result);
|
||||
|
||||
return compose(in, result, type, knockout, compositeSource, document, filtersElement, exporter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bevel filter
|
||||
*
|
||||
* @param distance Distance
|
||||
* @param angle Angle
|
||||
* @param highlightColor Highlight color
|
||||
* @param shadowColor Shadow color
|
||||
* @param knockout Knockout
|
||||
* @param compositeSource Composite source
|
||||
* @param type Type
|
||||
* @param blurX Blur X
|
||||
* @param blurY Blur Y
|
||||
* @param strength Strength
|
||||
* @param iterations Iterations
|
||||
* @param document Document
|
||||
* @param filtersElement Filters element
|
||||
* @param exporter Exporter
|
||||
* @param in In
|
||||
* @return Result
|
||||
*/
|
||||
public static String bevel(double distance, double angle, RGBA highlightColor, RGBA shadowColor, boolean knockout, boolean compositeSource, int type, double blurX, double blurY, double strength, int iterations, Document document, Element filtersElement, SVGExporter exporter, String in) {
|
||||
RGBA shadowColorTransparent = new RGBA(shadowColor);
|
||||
shadowColorTransparent.alpha = 0;
|
||||
RGBA highlightColorTransparent = new RGBA(highlightColor);
|
||||
highlightColorTransparent.alpha = 0;
|
||||
|
||||
return SvgFiltering.gradientBevel(distance, angle, new RGBA[]{shadowColor, shadowColorTransparent, highlightColorTransparent, highlightColor}, new int[]{0, 127, 128, 255}, knockout, compositeSource, type, blurX, blurY, strength, iterations, document, filtersElement, exporter, in);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gradient bevel
|
||||
*
|
||||
* @param distance Distance
|
||||
* @param angle Angle
|
||||
* @param gradientColors Gradient colors
|
||||
* @param gradientRatio Gradient ratio
|
||||
* @param knockout Knockout
|
||||
* @param compositeSource Composite source
|
||||
* @param type Type
|
||||
* @param blurX Blur X
|
||||
* @param blurY Blur Y
|
||||
* @param strength Strength
|
||||
* @param iterations Iterations
|
||||
* @param document Document
|
||||
* @param filtersElement Filters element
|
||||
* @param exporter Exporter
|
||||
* @param in In
|
||||
* @return Result
|
||||
*/
|
||||
public static String gradientBevel(double distance, double angle, RGBA[] gradientColors, int[] gradientRatio, boolean knockout, boolean compositeSource, int type, double blurX, double blurY, double strength, int iterations, Document document, Element filtersElement, SVGExporter exporter, String in) {
|
||||
RGBA highlightColor = new RGBA(255, 0, 0, 255);
|
||||
RGBA shadowColor = new RGBA(0, 0, 255, 255);
|
||||
|
||||
String shadowInner = null;
|
||||
String hilightInner = null;
|
||||
if (type != Filtering.OUTER) {
|
||||
String hilight = dropShadow(distance, angle, highlightColor, true, true, true, 0, 0, strength, iterations, document, filtersElement, exporter, in);
|
||||
String shadow = dropShadow(distance, angle + Math.PI, shadowColor, true, true, true, 0, 0, strength, iterations, 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 = dropShadow(distance, angle + Math.PI, highlightColor, false, true, true, 0, 0, strength, iterations, document, filtersElement, exporter, in);
|
||||
String shadow = dropShadow(distance, angle, shadowColor, false, true, true, 0, 0, strength, iterations, document, filtersElement, exporter, in);
|
||||
|
||||
Element feComposite1 = document.createElement("feComposite");
|
||||
feComposite1.setAttribute("in", hilight);
|
||||
feComposite1.setAttribute("in2", shadow);
|
||||
feComposite1.setAttribute("operator", "out");
|
||||
hilightOuter = exporter.getUniqueId("filterResult");
|
||||
feComposite1.setAttribute("result", hilightOuter);
|
||||
filtersElement.appendChild(feComposite1);
|
||||
|
||||
Element feComposite2 = document.createElement("feComposite");
|
||||
feComposite2.setAttribute("in", shadow);
|
||||
feComposite2.setAttribute("in2", hilight);
|
||||
feComposite2.setAttribute("operator", "out");
|
||||
shadowOuter = exporter.getUniqueId("filterResult");
|
||||
feComposite2.setAttribute("result", shadowOuter);
|
||||
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 feFlood = document.createElement("feFlood");
|
||||
feFlood.setAttribute("flood-color", "black");
|
||||
feFlood.setAttribute("flood-opacity", "1");
|
||||
String black = exporter.getUniqueId("filterResult");
|
||||
feFlood.setAttribute("result", black);
|
||||
filtersElement.appendChild(feFlood);
|
||||
|
||||
String result;
|
||||
|
||||
Element feComposite4 = document.createElement("feComposite");
|
||||
feComposite4.setAttribute("in", shadow);
|
||||
feComposite4.setAttribute("in2", black);
|
||||
feComposite4.setAttribute("operator", "over");
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feComposite4.setAttribute("result", result);
|
||||
filtersElement.appendChild(feComposite4);
|
||||
|
||||
Element feComposite5 = document.createElement("feComposite");
|
||||
feComposite5.setAttribute("in", hilight);
|
||||
feComposite5.setAttribute("in2", result);
|
||||
feComposite5.setAttribute("operator", "over");
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feComposite5.setAttribute("result", result);
|
||||
filtersElement.appendChild(feComposite5);
|
||||
|
||||
result = blur(blurX, blurY, iterations, document, filtersElement, exporter, result);
|
||||
|
||||
Element feColorMatrix = document.createElement("feColorMatrix");
|
||||
feColorMatrix.setAttribute("type", "matrix");
|
||||
feColorMatrix.setAttribute("in", result);
|
||||
double halfStrength = strength / 2;
|
||||
String matrixRow = "" + halfStrength + " 0 " + (-halfStrength) + " 0 0.5";
|
||||
feColorMatrix.setAttribute("values",
|
||||
matrixRow + " "
|
||||
+ matrixRow + " "
|
||||
+ matrixRow + " "
|
||||
+ matrixRow
|
||||
);
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feColorMatrix.setAttribute("result", result);
|
||||
filtersElement.appendChild(feColorMatrix);
|
||||
|
||||
result = prepareFeComponentTransfer(gradientColors, gradientRatio, document, filtersElement, exporter, result);
|
||||
|
||||
return compose(in, result, type, knockout, compositeSource, document, filtersElement, exporter);
|
||||
}
|
||||
|
||||
private static String prepareFeComponentTransfer(RGBA[] gradientColors, int[] gradientRatio, Document document, Element filtersElement, SVGExporter exporter, String in) {
|
||||
Element feComponentTransfer = document.createElement("feComponentTransfer");
|
||||
feComponentTransfer.setAttribute("in", in);
|
||||
|
||||
List<String> redValues = new ArrayList<>();
|
||||
List<String> greenValues = new ArrayList<>();
|
||||
List<String> blueValues = new ArrayList<>();
|
||||
List<String> alphaValues = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
RGBA color = GradientUtil.colorAt(gradientColors, gradientRatio, i, GradientUtil.ColorInterpolation.SRGB);
|
||||
redValues.add("" + (color.red / 255f));
|
||||
greenValues.add("" + (color.green / 255f));
|
||||
blueValues.add("" + (color.blue / 255f));
|
||||
alphaValues.add("" + color.getAlphaFloat());
|
||||
}
|
||||
|
||||
/*
|
||||
//In case we want to map 128 to center
|
||||
|
||||
for (int i = 0; i < 126; i++) { //126 colors
|
||||
RGBA color = GradientUtil.colorAt(gradientColors, gradientRatio, i * 127f / 125f, GradientUtil.ColorInterpolation.SRGB);
|
||||
redValues.add("" + (color.red / 255f));
|
||||
greenValues.add("" + (color.green / 255f));
|
||||
blueValues.add("" + (color.blue / 255f));
|
||||
alphaValues.add("" + color.getAlphaFloat());
|
||||
}
|
||||
for (int i = 128; i < 256; i++) { //1 center + 126 colors
|
||||
RGBA color = GradientUtil.colorAt(gradientColors, gradientRatio, i, GradientUtil.ColorInterpolation.SRGB);
|
||||
redValues.add("" + (color.red / 255f));
|
||||
greenValues.add("" + (color.green / 255f));
|
||||
blueValues.add("" + (color.blue / 255f));
|
||||
alphaValues.add("" + color.getAlphaFloat());
|
||||
}
|
||||
*/
|
||||
Element feFuncR = document.createElement("feFuncR");
|
||||
feFuncR.setAttribute("type", "table");
|
||||
feFuncR.setAttribute("tableValues", String.join(" ", redValues));
|
||||
Element feFuncG = document.createElement("feFuncG");
|
||||
feFuncG.setAttribute("type", "table");
|
||||
feFuncG.setAttribute("tableValues", String.join(" ", greenValues));
|
||||
Element feFuncB = document.createElement("feFuncB");
|
||||
feFuncB.setAttribute("type", "table");
|
||||
feFuncB.setAttribute("tableValues", String.join(" ", blueValues));
|
||||
Element feFuncA = document.createElement("feFuncA");
|
||||
feFuncA.setAttribute("type", "table");
|
||||
feFuncA.setAttribute("tableValues", String.join(" ", alphaValues));
|
||||
feComponentTransfer.appendChild(feFuncR);
|
||||
feComponentTransfer.appendChild(feFuncG);
|
||||
feComponentTransfer.appendChild(feFuncB);
|
||||
feComponentTransfer.appendChild(feFuncA);
|
||||
|
||||
String result = exporter.getUniqueId("filterResult");
|
||||
feComponentTransfer.setAttribute("result", result);
|
||||
filtersElement.appendChild(feComponentTransfer);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop shadow
|
||||
*
|
||||
* @param distance Distance
|
||||
* @param angle Angle
|
||||
* @param dropShadowColor Drop shadow color
|
||||
* @param innerShadow Inner shadow
|
||||
* @param knockout Knockout
|
||||
* @param compositeSource Composite source
|
||||
* @param blurX Blur X
|
||||
* @param blurY Blur Y
|
||||
* @param strength Strength
|
||||
* @param iterations Iterations
|
||||
* @param document Document
|
||||
* @param filtersElement Filters element
|
||||
* @param exporter SVG exporter
|
||||
* @param in Input
|
||||
* @return SVG id of the drop shadow
|
||||
*/
|
||||
public static String dropShadow(
|
||||
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 * exporter.getZoom() * Math.cos(angle);
|
||||
double dy = distance * exporter.getZoom() * Math.sin(angle);
|
||||
|
||||
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);
|
||||
|
||||
String result;
|
||||
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 feComposite1 = document.createElement("feComposite");
|
||||
feComposite1.setAttribute("in", feFloodResult);
|
||||
feComposite1.setAttribute("in2", feOffsetResult);
|
||||
feComposite1.setAttribute("operator", "out");
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feComposite1.setAttribute("result", result);
|
||||
filtersElement.appendChild(feComposite1);
|
||||
} else {
|
||||
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 " + (dropShadowColor.alpha / 255f) + " 0" //Note: it is not last one here
|
||||
);
|
||||
result = exporter.getUniqueId("filterResult");
|
||||
feColorMatrix.setAttribute("result", result);
|
||||
filtersElement.appendChild(feColorMatrix);
|
||||
}
|
||||
|
||||
if (Double.compare(blurX, 0.0) != 0 || Double.compare(blurY, 0.0) != 0) {
|
||||
result = blur(blurX, blurY, iterations, document, filtersElement, exporter, result);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return compose(in, result, innerShadow ? Filtering.INNER : Filtering.OUTER, knockout, compositeSource, document, filtersElement, exporter);
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
package com.jpexs.helpers;
|
||||
|
||||
|
||||
import com.jpexs.decompiler.flash.types.RGBA;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -107,8 +106,9 @@ public final class GradientUtil {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static final class SplitResult {
|
||||
|
||||
public final RGBA[] colorsA;
|
||||
public final int[] ratioA;
|
||||
public final RGBA[] colorsB;
|
||||
@@ -123,14 +123,12 @@ public final class GradientUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a gradient into two halves:
|
||||
* - A: original positions 0..127 mapped to 0..255
|
||||
* - B: original positions 128..255 mapped to 0..255
|
||||
* Splits a gradient into two halves: - A: original positions 0..127 mapped
|
||||
* to 0..255 - B: original positions 128..255 mapped to 0..255
|
||||
*
|
||||
* Notes:
|
||||
* - Stop lookup is based on original ratio[].
|
||||
* - Boundary stops at 127 (A) and 128 (B) are ensured (interpolated if missing).
|
||||
* - ratio[] is assumed sorted ascending.
|
||||
* Notes: - Stop lookup is based on original ratio[]. - Boundary stops at
|
||||
* 127 (A) and 128 (B) are ensured (interpolated if missing). - ratio[] is
|
||||
* assumed sorted ascending.
|
||||
*/
|
||||
public static SplitResult splitIntoHalves(
|
||||
RGBA[] colors, int[] ratio, ColorInterpolation mode
|
||||
@@ -152,18 +150,19 @@ public final class GradientUtil {
|
||||
}
|
||||
|
||||
// ----- Internal representation of stops -----
|
||||
|
||||
private static final class Stops {
|
||||
|
||||
final List<RGBA> colors = new ArrayList<>();
|
||||
final List<Integer> ratio = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts all stops within [from..to] (inclusive), and ensures stops at both ends exist.
|
||||
* If an endpoint stop is missing, it is computed via SvgGradient.colorAt(...).
|
||||
* Extracts all stops within [from..to] (inclusive), and ensures stops at
|
||||
* both ends exist. If an endpoint stop is missing, it is computed via
|
||||
* SvgGradient.colorAt(...).
|
||||
*/
|
||||
private static Stops extractRange(RGBA[] colors, int[] ratio, int from, int to,
|
||||
ColorInterpolation mode) {
|
||||
ColorInterpolation mode) {
|
||||
Stops out = new Stops();
|
||||
|
||||
// Ensure start stop
|
||||
@@ -184,19 +183,22 @@ public final class GradientUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is an existing stop exactly at pos, returns its color;
|
||||
* otherwise computes the color by interpolation at that position.
|
||||
* If there is an existing stop exactly at pos, returns its color; otherwise
|
||||
* computes the color by interpolation at that position.
|
||||
*/
|
||||
private static RGBA stopColorAtOrExisting(RGBA[] colors, int[] ratio, int pos,
|
||||
ColorInterpolation mode) {
|
||||
ColorInterpolation mode) {
|
||||
for (int i = 0; i < ratio.length; i++) {
|
||||
if (ratio[i] == pos) return colors[i];
|
||||
if (ratio[i] == pos) {
|
||||
return colors[i];
|
||||
}
|
||||
}
|
||||
return colorAt(colors, ratio, pos, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a stop keeping order; if the same position already exists, it overwrites the color.
|
||||
* Adds a stop keeping order; if the same position already exists, it
|
||||
* overwrites the color.
|
||||
*/
|
||||
private static void addStop(Stops stops, int pos, RGBA color) {
|
||||
// Insert in ascending order (ratio is small, linear insert is fine)
|
||||
@@ -217,8 +219,8 @@ public final class GradientUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remaps original integer positions in [from..to] to [0..255].
|
||||
* Uses rounding and clamps, guaranteeing endpoints map to 0 and 255.
|
||||
* Remaps original integer positions in [from..to] to [0..255]. Uses
|
||||
* rounding and clamps, guaranteeing endpoints map to 0 and 255.
|
||||
*/
|
||||
private static int[] remap(List<Integer> original, int from, int to) {
|
||||
int span = to - from; // for 0..127 and 128..255 span is 127
|
||||
|
||||
Reference in New Issue
Block a user