Compare commits

..

No commits in common. "dev" and "main" have entirely different histories.
dev ... main

92 changed files with 2639 additions and 3449 deletions

51
.classpath Normal file
View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src">
<attributes>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="resources"/>
<classpathentry including="**/*.java" kind="src" output="out/eclipse/classes-test" path="test/src">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-14">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5">
<attributes>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/atriasoft-etk">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/scenarium-logger">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/atriasoft-exml">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/atriasoft-egami">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/atriasoft-png-encoder">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="out/eclipse/classes"/>
</classpath>

3
.gitignore vendored
View File

@ -1,5 +1,3 @@
/__pycache__/
/bin/ /bin/
/Operator/ /Operator/
/DrawerProperties/ /DrawerProperties/
@ -17,4 +15,3 @@ build.number
/.settings/ /.settings/
/junit/ /junit/
/target/ /target/
/testResult/

24
.project Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>atriasoft-esvg</name>
<comment></comment>
<projects>
<project>atriasoft-esvg</project>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
</natures>
</projectDescription>

11
esvg.iml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,105 +0,0 @@
#!/usr/bin/python
import realog.debug as debug
import lutin.tools as tools
import realog.debug as debug
import lutin.image as image
import os
import lutin.multiprocess as lutinMultiprocess
def get_type():
return "LIBRARY_DYNAMIC"
def get_desc():
return "Ewol Tool Kit"
def get_licence():
return "MPL-2"
def get_compagny_type():
return "org"
def get_compagny_name():
return "atria-soft"
#def get_maintainer():
# return "authors.txt"
#def get_version():
# return "version.txt"
def configure(target, my_module):
my_module.add_src_file([
'src/module-info.java',
'src/org/atriasoft/esvg/LinearGradient.java',
'src/org/atriasoft/esvg/Circle.java',
'src/org/atriasoft/esvg/Group.java',
'src/org/atriasoft/esvg/Base.java',
'src/org/atriasoft/esvg/Text.java',
'src/org/atriasoft/esvg/RadialGradient.java',
'src/org/atriasoft/esvg/internal/LOGGER.java',
'src/org/atriasoft/esvg/font/Kerning.java',
'src/org/atriasoft/esvg/font/Glyph.java',
'src/org/atriasoft/esvg/Renderer.java',
'src/org/atriasoft/esvg/EsvgFont.java',
'src/org/atriasoft/esvg/FontCache.java',
'src/org/atriasoft/esvg/Ellipse.java',
'src/org/atriasoft/esvg/Esvg.java',
'src/org/atriasoft/esvg/render/ElementLineToH.java',
'src/org/atriasoft/esvg/render/DynamicColor.java',
'src/org/atriasoft/esvg/render/Point.java',
'src/org/atriasoft/esvg/render/Scanline.java',
'src/org/atriasoft/esvg/render/PathType.java',
'src/org/atriasoft/esvg/render/ElementLineToV.java',
'src/org/atriasoft/esvg/render/PointList.java',
'src/org/atriasoft/esvg/render/ElementMoveTo.java',
'src/org/atriasoft/esvg/render/SegmentList.java',
'src/org/atriasoft/esvg/render/Segment.java',
'src/org/atriasoft/esvg/render/ElementElliptic.java',
'src/org/atriasoft/esvg/render/ElementStop.java',
'src/org/atriasoft/esvg/render/Weight.java',
'src/org/atriasoft/esvg/render/ElementBezierSmoothCurveTo.java',
'src/org/atriasoft/esvg/render/DynamicColorSpecial.java',
'src/org/atriasoft/esvg/render/PathModel.java',
'src/org/atriasoft/esvg/render/ElementBezierCurveTo.java',
'src/org/atriasoft/esvg/render/RenderingConfig.java',
'src/org/atriasoft/esvg/render/ElementLineTo.java',
'src/org/atriasoft/esvg/render/PointType.java',
'src/org/atriasoft/esvg/render/ElementCurveTo.java',
'src/org/atriasoft/esvg/render/ElementClose.java',
'src/org/atriasoft/esvg/render/DynamicColorUni.java',
'src/org/atriasoft/esvg/render/Element.java',
'src/org/atriasoft/esvg/render/ElementSmoothCurveTo.java',
'src/org/atriasoft/esvg/PaintState.java',
'src/org/atriasoft/esvg/PaintMode.java',
'src/org/atriasoft/esvg/CapMode.java',
'src/org/atriasoft/esvg/Path.java',
'src/org/atriasoft/esvg/Polygon.java',
'src/org/atriasoft/esvg/Rectangle.java',
'src/org/atriasoft/esvg/JoinMode.java',
'src/org/atriasoft/esvg/SpreadMethod.java',
'src/org/atriasoft/esvg/EsvgDocument.java',
'src/org/atriasoft/esvg/Line.java',
'src/org/atriasoft/esvg/GraphicContext.java',
'src/org/atriasoft/esvg/GradientUnits.java',
'src/org/atriasoft/esvg/Polyline.java',
])
my_module.add_path('src/', type='java')
my_module.add_depend([
'org-atriasoft-exml',
'org-atriasoft-pngencoder',
'org-atriasoft-egami',
])
#my_module.add_path([
# 'lib/spotbugs-annotations-4.2.2.jar'
# ],
# type='java',
# export=True
#);
my_module.add_flag('java', "RELEASE_15_PREVIEW");
return True

160
pom.xml
View File

@ -1,160 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.atriasoft</groupId>
<artifactId>esvg</artifactId>
<version>0.1.0</version>
<licenses>
<license>
<name>Mozilla Public License 2.0</name>
<url>https://opensource.org/licenses/MPL-2.0</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>dev1</id>
<name>Edouard DUPIN</name>
<email>edouard.dupin@proton.me</email>
<roles>
<role>Lead Developer</role>
</roles>
</developer>
</developers>
<repositories>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/org.atriasoft/maven</url>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/org.atriasoft/maven</url>
</repository>
<snapshotRepository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/org.atriasoft/maven</url>
</snapshotRepository>
</distributionManagement>
<dependencies>
<dependency>
<groupId>org.atriasoft</groupId>
<artifactId>exml</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>org.atriasoft</groupId>
<artifactId>png-encoder</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>org.atriasoft</groupId>
<artifactId>egami</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.1.0-alpha1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.atriasoft</groupId>
<artifactId>aknot</artifactId>
<version>0.1.0</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main</sourceDirectory>
<resources>
<resource>
<directory>src/resources</directory>
</resource>
</resources>
<testSourceDirectory>src/test</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
<!-- Create the source bundle -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- junit results -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<!-- Java-doc generation for stand-alone site -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<show>private</show>
<nohelp>true</nohelp>
</configuration>
</plugin>
</plugins>
</build>
<!-- Generate Java-docs As Part Of Project Reports -->
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<show>public</show>
</configuration>
</plugin>
</plugins>
</reporting>
</project>

View File

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

Before

Width:  |  Height:  |  Size: 697 KiB

After

Width:  |  Height:  |  Size: 697 KiB

View File

Before

Width:  |  Height:  |  Size: 737 KiB

After

Width:  |  Height:  |  Size: 737 KiB

View File

Before

Width:  |  Height:  |  Size: 897 KiB

After

Width:  |  Height:  |  Size: 897 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

Before

Width:  |  Height:  |  Size: 795 KiB

After

Width:  |  Height:  |  Size: 795 KiB

View File

Before

Width:  |  Height:  |  Size: 791 KiB

After

Width:  |  Height:  |  Size: 791 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 4.9 MiB

After

Width:  |  Height:  |  Size: 4.9 MiB

16
src/module-info.java Normal file
View File

@ -0,0 +1,16 @@
/** Basic module interface.
*
* @author Edouard DUPIN */
open module org.atriasoft.esvg {
exports org.atriasoft.esvg;
exports org.atriasoft.esvg.font;
exports org.atriasoft.esvg.render;
requires transitive io.scenarium.logger;
requires transitive org.atriasoft.etk;
requires transitive org.atriasoft.exml;
requires org.atriasoft.pngencoder;
requires java.desktop;
requires org.atriasoft.egami;
}

View File

@ -2,6 +2,7 @@ package org.atriasoft.esvg;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color; import org.atriasoft.etk.Color;
import org.atriasoft.etk.Distance; import org.atriasoft.etk.Distance;
import org.atriasoft.etk.math.FMath; import org.atriasoft.etk.math.FMath;
@ -10,8 +11,6 @@ import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -20,7 +19,6 @@ import org.slf4j.LoggerFactory;
*/ */
public class Base { public class Base {
static final Logger LOGGER = LoggerFactory.getLogger(Base.class);
public static float kappa90 = 0.5522847493f; //!< proportional lenght to the radius of a bezier handle for 90° arcs. public static float kappa90 = 0.5522847493f; //!< proportional lenght to the radius of a bezier handle for 90° arcs.
@ -32,7 +30,7 @@ public class Base {
} }
posStart += base.length(); posStart += base.length();
if (value.length() < posStart + 2) { if (value.length() < posStart + 2) {
LOGGER.error("Not enought spece in the String to have transform value for ' (' or '()' in '" + value + "'"); Log.error("Not enought spece in the String to have transform value for ' (' or '()' in '" + value + "'");
return ""; return "";
} }
if (value.charAt(posStart) == '(') { if (value.charAt(posStart) == '(') {
@ -41,19 +39,19 @@ public class Base {
} else if (value.charAt(posStart) == ' ' && value.charAt(posStart + 1) == '(') { } else if (value.charAt(posStart) == ' ' && value.charAt(posStart + 1) == '(') {
posStart += 2; posStart += 2;
} else { } else {
LOGGER.error("Can not indexOf ' (' or '(' in '" + value.substring(posStart) + "' for '" + value + "'"); Log.error("Can not indexOf ' (' or '(' in '" + value.substring(posStart) + "' for '" + value + "'");
return ""; return "";
} }
if (value.length() < posStart + 1) { if (value.length() < posStart + 1) {
LOGGER.error("Not enought spece in the String to have transform value for ')' in '" + value + "'"); Log.error("Not enought spece in the String to have transform value for ')' in '" + value + "'");
return ""; return "";
} }
final int posEnd = value.indexOf(')', posStart); int posEnd = value.indexOf(')', posStart);
if (posEnd == -1) { if (posEnd == -1) {
LOGGER.error("Missing element ')' in '" + value + "' for " + base); Log.error("Missing element ')' in '" + value + "' for " + base);
return ""; return "";
} }
LOGGER.trace("indexOf : '" + value.substring(posStart, posEnd) + "' for " + base); Log.verbose("indexOf : '" + value.substring(posStart, posEnd) + "' for " + base);
return value.substring(posStart, posEnd); return value.substring(posStart, posEnd);
} }
@ -85,14 +83,10 @@ public class Base {
* @param level Level of the tree * @param level Level of the tree
*/ */
void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
LOGGER.warn(spacingDist(level) + "DRAW esvg::Base ... ==> No drawing availlable"); Log.warning(spacingDist(level) + "DRAW esvg::Base ... ==> No drawing availlable");
} }
public void drawShapePoints( public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans) {
final List<List<Vector2f>> out,
final int recurtionMax,
final float threshold,
final Matrix2x3f basicTrans) {
drawShapePoints(out, recurtionMax, threshold, basicTrans, 1); drawShapePoints(out, recurtionMax, threshold, basicTrans, 1);
} }
@ -101,15 +95,10 @@ public class Base {
* @param out where the lines are added * @param out where the lines are added
* @param recurtionMax interpolation recurtion max * @param recurtionMax interpolation recurtion max
* @param threshold threshold to stop recurtion * @param threshold threshold to stop recurtion
* @param basicTrans Parant transformation of the environement * @param basicTrans Parant transformation of the environement
* @param level Level of the tree * @param level Level of the tree
*/ */
void drawShapePoints( void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
final List<List<Vector2f>> out,
final int recurtionMax,
final float threshold,
final Matrix2x3f basicTrans,
final int level) {
} }
@ -128,24 +117,22 @@ public class Base {
*/ */
Pair<Color, String> parseColor(final String inputData) { Pair<Color, String> parseColor(final String inputData) {
Pair<Color, String> localColor = new Pair<>(Color.WHITE, ""); Pair<Color, String> localColor = new Pair<>(Color.WHITE, "");
if (inputData.length() > 4 && inputData.charAt(0) == 'u' && inputData.charAt(1) == 'r' if (inputData.length() > 4 && inputData.charAt(0) == 'u' && inputData.charAt(1) == 'r' && inputData.charAt(2) == 'l' && inputData.charAt(3) == '(') {
&& inputData.charAt(2) == 'l' && inputData.charAt(3) == '(') {
if (inputData.charAt(4) == '#') { if (inputData.charAt(4) == '#') {
final String color = inputData.substring(5, inputData.length() - 1); String color = inputData.substring(5, inputData.length() - 1);
localColor = new Pair<>(Color.NONE, color); localColor = new Pair<>(Color.NONE, color);
} else { } else {
LOGGER.error( Log.error("Problem in parsing the color : '" + inputData + "' == > url(XXX) is not supported now ...");
"Problem in parsing the color : '" + inputData + "' == > url(XXX) is not supported now ...");
} }
} else { } else {
try { try {
localColor = new Pair<>(Color.valueOf256(inputData), ""); localColor = new Pair<>(Color.valueOf256(inputData), "");
} catch (final Exception e) { } catch (Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
} }
LOGGER.trace("Parse color : \"" + inputData + "\" == > " + localColor.first + " " + localColor.second); Log.verbose("Parse color : \"" + inputData + "\" == > " + localColor.first + " " + localColor.second);
return localColor; return localColor;
} }
@ -155,21 +142,31 @@ public class Base {
* @return standard number of pixels * @return standard number of pixels
*/ */
float parseLength(final String dataInput) { float parseLength(final String dataInput) {
final Pair<Float, Distance> value = parseLength2(dataInput); Pair<Float, Distance> value = parseLength2(dataInput);
LOGGER.trace(" lenght : '" + value.first + "' => unit=" + value.second); Log.verbose(" lenght : '" + value.first + "' => unit=" + value.second);
final float fontsize = 20.0f; float fontsize = 20.0f;
return switch (value.second) { switch (value.second) {
case POURCENT -> value.first; // / 100.0 * this.paint.viewPort.x(); case POURCENT:
case ELEMENT -> value.first * fontsize; return value.first;// / 100.0 * this.paint.viewPort.x();
case EX -> value.first / 2.0f * fontsize; case ELEMENT:
case PIXEL -> value.first; return value.first * fontsize;
case POINT -> value.first * 1.25f; case EX:
case PC -> value.first * 15.0f; return value.first / 2.0f * fontsize;
case MILLIMETER -> value.first * 3.543307f; case PIXEL:
case CENTIMETER -> value.first * 35.43307f; return value.first;
case INCH -> value.first * 90.0f; case POINT:
default -> 0.0f; return value.first * 1.25f;
}; case PC:
return value.first * 15.0f;
case MILLIMETER:
return value.first * 3.543307f;
case CENTIMETER:
return value.first * 35.43307f;
case INCH:
return value.first * 90.0f;
default:
return 0.0f;
}
} }
Pair<Float, Distance> parseLength2(String config) { Pair<Float, Distance> parseLength2(String config) {
@ -238,7 +235,7 @@ public class Base {
} else { } else {
if (content.length() != 0) { if (content.length() != 0) {
this.paint.stroke = parseColor(content); this.paint.stroke = parseColor(content);
//LOGGER.trace("Parse color : " + this.paint.stroke); Log.error("Parse color : " + this.paint.stroke);
} }
content = element.getAttribute("stroke-width", ""); content = element.getAttribute("stroke-width", "");
if (content.length() != 0) { if (content.length() != 0) {
@ -256,7 +253,7 @@ public class Base {
if (content.equals("none")) { if (content.equals("none")) {
// OK, Nothing to do ... // OK, Nothing to do ...
} else { } else {
LOGGER.info("TODO 'stroke-dasharray' not implemented ..."); Log.todo(" 'stroke-dasharray' not implemented ...");
} }
} }
content = element.getAttribute("stroke-linecap", ""); content = element.getAttribute("stroke-linecap", "");
@ -269,7 +266,7 @@ public class Base {
this.paint.lineCap = CapMode.SQUARE; this.paint.lineCap = CapMode.SQUARE;
} else { } else {
this.paint.lineCap = CapMode.BUTT; this.paint.lineCap = CapMode.BUTT;
LOGGER.error("not know stroke-linecap value : '" + content + "', not in [butt,round,square]"); Log.error("not know stroke-linecap value : '" + content + "', not in [butt,round,square]");
} }
} }
content = element.getAttribute("stroke-linejoin", ""); content = element.getAttribute("stroke-linejoin", "");
@ -282,12 +279,12 @@ public class Base {
this.paint.lineJoin = JoinMode.BEVEL; this.paint.lineJoin = JoinMode.BEVEL;
} else { } else {
this.paint.lineJoin = JoinMode.MITER; this.paint.lineJoin = JoinMode.MITER;
LOGGER.error("not know stroke-linejoin value : '" + content + "', not in [miter,round,bevel]"); Log.error("not know stroke-linejoin value : '" + content + "', not in [miter,round,bevel]");
} }
} }
content = element.getAttribute("stroke-miterlimit", ""); content = element.getAttribute("stroke-miterlimit", "");
if (content.length() != 0) { if (content.length() != 0) {
final float tmp = parseLength(content); float tmp = parseLength(content);
this.paint.miterLimit = FMath.max(0.0f, tmp); this.paint.miterLimit = FMath.max(0.0f, tmp);
} }
} }
@ -312,7 +309,7 @@ public class Base {
} else if (content.equals("evenodd")) { } else if (content.equals("evenodd")) {
this.paint.flagEvenOdd = true; this.paint.flagEvenOdd = true;
} else { } else {
LOGGER.error("not know fill-rule value : \"" + content + "\", not in [nonzero,evenodd]"); Log.error("not know fill-rule value : \"" + content + "\", not in [nonzero,evenodd]");
} }
} }
// ---------------- opacity ---------------- // ---------------- opacity ----------------
@ -332,56 +329,51 @@ public class Base {
if (inputString.length() == 0) { if (inputString.length() == 0) {
return; return;
} }
//LOGGER.trace("indexOf transform : '" + inputString + "'"); Log.verbose("indexOf transform : '" + inputString + "'");
inputString = inputString.replace(',', ' '); inputString = inputString.replace(',', ' ');
//LOGGER.trace("indexOf transform : '" + inputString + "'"); Log.verbose("indexOf transform : '" + inputString + "'");
// need to indexOf elements in order ... // need to indexOf elements in order ...
String data = Base.extractTransformData(inputString, "matrix"); String data = Base.extractTransformData(inputString, "matrix");
if (data.length() != 0) { if (data.length() != 0) {
final double[] matrix = FMath.getTableDouble(data, " ", 6); double[] matrix = FMath.getTableDouble(data, " ", 6);
if (matrix != null) { if (matrix != null) {
this.transformMatrix = new Matrix2x3f(matrix); this.transformMatrix = new Matrix2x3f(matrix);
// indexOf a matrix : simply exit ... // indexOf a matrix : simply exit ...
return; return;
} }
LOGGER.error("Parsing matrix() with wrong data ... '" + data + "'"); Log.error("Parsing matrix() with wrong data ... '" + data + "'");
} }
data = Base.extractTransformData(inputString, "translate"); data = Base.extractTransformData(inputString, "translate");
if (data.length() != 0) { if (data.length() != 0) {
final float[] elements = FMath.getTableFloat(data, " ", 2); float[] elements = FMath.getTableFloat(data, " ", 2);
if (elements != null) { if (elements != null) {
this.transformMatrix = this.transformMatrix this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createTranslate(new Vector2f(elements[0], elements[1])));
.multiply(Matrix2x3f.createTranslate(new Vector2f(elements[0], elements[1]))); Log.verbose("Translate : " + elements[0] + ", " + elements[1]);
//LOGGER.trace("Translate : " + elements[0] + ", " + elements[1]);
} else { } else {
final float elem = Float.parseFloat(data); float elem = Float.parseFloat(data);
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createTranslate(new Vector2f(elem, 0))); this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createTranslate(new Vector2f(elem, 0)));
} }
} }
data = Base.extractTransformData(inputString, "scale"); data = Base.extractTransformData(inputString, "scale");
if (data.length() != 0) { if (data.length() != 0) {
final float[] elements = FMath.getTableFloat(data, " ", 2); float[] elements = FMath.getTableFloat(data, " ", 2);
if (elements != null) { if (elements != null) {
this.transformMatrix = this.transformMatrix this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createScale(new Vector2f(elements[0], elements[1])));
.multiply(Matrix2x3f.createScale(new Vector2f(elements[0], elements[1]))); Log.verbose("Translate : " + elements[0] + ", " + elements[1]);
//LOGGER.trace("Translate : " + elements[0] + ", " + elements[1]);
} else { } else {
final float elem = Float.parseFloat(data); float elem = Float.parseFloat(data);
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createScale(elem)); this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createScale(elem));
} }
} }
data = Base.extractTransformData(inputString, "rotate"); data = Base.extractTransformData(inputString, "rotate");
if (data.length() != 0) { if (data.length() != 0) {
final float[] elements = FMath.getTableFloat(data, " ", 3); float[] elements = FMath.getTableFloat(data, " ", 3);
if (elements != null) { if (elements != null) {
final float angle = (float) Math.toRadians(elements[0]); float angle = (float) Math.toRadians(elements[0]);
this.transformMatrix = this.transformMatrix this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createTranslate(new Vector2f(-elements[1], -elements[2])));
.multiply(Matrix2x3f.createTranslate(new Vector2f(-elements[1], -elements[2])));
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createRotate(angle)); this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createRotate(angle));
this.transformMatrix = this.transformMatrix this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createTranslate(new Vector2f(elements[1], elements[2])));
.multiply(Matrix2x3f.createTranslate(new Vector2f(elements[1], elements[2]))); this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createScale(new Vector2f(elements[0], elements[1])));
this.transformMatrix = this.transformMatrix
.multiply(Matrix2x3f.createScale(new Vector2f(elements[0], elements[1])));
} else { } else {
float elem = Float.parseFloat(data); float elem = Float.parseFloat(data);
elem = (float) Math.toRadians(elem); elem = (float) Math.toRadians(elem);
@ -463,7 +455,7 @@ public class Base {
} }
protected String spacingDist(final int spacing) { protected String spacingDist(final int spacing) {
final StringBuilder out = new StringBuilder(); StringBuilder out = new StringBuilder();
for (int iii = 0; iii < spacing; iii++) { for (int iii = 0; iii < spacing; iii++) {
out.append(" "); out.append(" ");
} }

View File

@ -3,6 +3,7 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
@ -13,8 +14,6 @@ import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -23,61 +22,55 @@ import org.slf4j.LoggerFactory;
*/ */
public class Circle extends Base { public class Circle extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Circle.class);
private Vector2f position; //!< Position of the Circle private Vector2f position; //!< Position of the Circle
private float radius; //!< Radius of the Circle private float radius; //!< Radius of the Circle
public Circle(final PaintState parentPaintState) { public Circle(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
} }
public Circle(final Vector2f position, final float radius, final PaintState parentPaintState) { public Circle(final Vector2f position, final float radius, final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
this.position = position; this.position = position;
this.radius = radius; this.radius = radius;
} }
private PathModel createPath() { private PathModel createPath() {
final PathModel out = new PathModel(); PathModel out = new PathModel();
out.moveTo(false, this.position.addX(this.radius)); out.moveTo(false, this.position.addX(this.radius));
out.curveTo(false, this.position.add(this.radius, this.radius * Base.kappa90), out.curveTo(false, this.position.add(this.radius, this.radius * Base.kappa90), this.position.add(this.radius * Base.kappa90, this.radius), this.position.addY(this.radius));
this.position.add(this.radius * Base.kappa90, this.radius), this.position.addY(this.radius)); out.curveTo(false, this.position.add(-this.radius * Base.kappa90, this.radius), this.position.add(-this.radius, this.radius * Base.kappa90), this.position.lessX(this.radius));
out.curveTo(false, this.position.add(-this.radius * Base.kappa90, this.radius), out.curveTo(false, this.position.add(-this.radius, -this.radius * Base.kappa90), this.position.add(-this.radius * Base.kappa90, -this.radius), this.position.lessY(this.radius));
this.position.add(-this.radius, this.radius * Base.kappa90), this.position.lessX(this.radius)); out.curveTo(false, this.position.add(this.radius * Base.kappa90, -this.radius), this.position.add(this.radius, -this.radius * Base.kappa90), this.position.addX(this.radius));
out.curveTo(false, this.position.add(-this.radius, -this.radius * Base.kappa90),
this.position.add(-this.radius * Base.kappa90, -this.radius), this.position.lessY(this.radius));
out.curveTo(false, this.position.add(this.radius * Base.kappa90, -this.radius),
this.position.add(this.radius, -this.radius * Base.kappa90), this.position.addX(this.radius));
out.close(); out.close();
return out; return out;
} }
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
LOGGER.debug(spacingDist(spacing) + "Circle " + this.position + " radius=" + this.radius); Log.debug(spacingDist(spacing) + "Circle " + this.position + " radius=" + this.radius);
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
LOGGER.trace(spacingDist(level) + "DRAW esvg::Circle"); Log.verbose(spacingDist(level) + "DRAW esvg::Circle");
if (this.radius <= 0.0f) { if (this.radius <= 0.0f) {
LOGGER.trace(spacingDist(level + 1) + "Too small radius" + this.radius); Log.verbose(spacingDist(level + 1) + "Too small radius" + this.radius);
return; return;
} }
final PathModel listElement = createPath(); PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix; Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans); mtx = mtx.multiply(basicTrans);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx); //listPoints.applyMatrix(mtx);
final SegmentList listSegmentFill = new SegmentList(); SegmentList listSegmentFill = new SegmentList();
final SegmentList listSegmentStroke = new SegmentList(); SegmentList listSegmentStroke = new SegmentList();
final Weight tmpFill = new Weight(); Weight tmpFill = new Weight();
final Weight tmpStroke = new Weight(); Weight tmpStroke = new Weight();
final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
@ -92,8 +85,7 @@ public class Circle extends Base {
} }
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -104,30 +96,25 @@ public class Circle extends Base {
//myRenderer.addDebugSegment(listSegmentFill); //myRenderer.addDebugSegment(listSegmentFill);
//myRenderer.addDebugSegment(listSegmentStroke); //myRenderer.addDebugSegment(listSegmentStroke);
} }
@Override @Override
public void drawShapePoints( public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
final List<List<Vector2f>> out, Log.verbose(spacingDist(level) + "DRAW Shape esvg::Circle");
final int recurtionMax, PathModel listElement = createPath();
final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Circle");
final PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix; Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans); mtx = mtx.multiply(basicTrans);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, recurtionMax, threshold); listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx); listPoints.applyMatrix(mtx);
for (final List<Point> it : listPoints.data) { for (List<Point> it : listPoints.data) {
final List<Vector2f> listPoint = new ArrayList<>(); List<Vector2f> listPoint = new ArrayList<>();
for (final Point itDot : it) { for (Point itDot : it) {
listPoint.add(itDot.pos); listPoint.add(itDot.pos);
} }
out.add(listPoint); out.add(listPoint);
} }
} }
@Override @Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) { public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
this.radius = 0.0f; this.radius = 0.0f;
@ -137,10 +124,10 @@ public class Circle extends Base {
} }
parseTransform(element); parseTransform(element);
parsePaintAttr(element); parsePaintAttr(element);
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
String content = element.getAttribute("cx", ""); String content = element.getAttribute("cx", "");
if (content.length() != 0) { if (content.length() != 0) {
this.position = this.position.withX(parseLength(content)); this.position = this.position.withX(parseLength(content));
@ -151,13 +138,13 @@ public class Circle extends Base {
} }
content = element.getAttribute("r", ""); content = element.getAttribute("r", "");
if (content.length() == 0) { if (content.length() == 0) {
LOGGER.error("Circle \"r\" is not present"); Log.error("Circle \"r\" is not present");
return false; return false;
} }
this.radius = parseLength(content); this.radius = parseLength(content);
if (0 > this.radius) { if (0 > this.radius) {
this.radius = 0; this.radius = 0;
LOGGER.error("Circle \"r\" is negative"); Log.error("Circle \"r\" is negative");
return false; return false;
} }
sizeMax.value = new Vector2f(this.position.x() + this.radius, this.position.y() + this.radius); sizeMax.value = new Vector2f(this.position.x() + this.radius, this.position.y() + this.radius);

View File

@ -2,7 +2,7 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
@ -13,8 +13,6 @@ import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -23,61 +21,55 @@ import org.slf4j.LoggerFactory;
*/ */
public class Ellipse extends Base { public class Ellipse extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Ellipse.class);
private Vector2f c; //!< Center property of the ellipse private Vector2f c; //!< Center property of the ellipse
private Vector2f r; //!< Radius property of the ellipse private Vector2f r; //!< Radius property of the ellipse
public Ellipse(final PaintState parentPaintState) { public Ellipse(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
} }
public Ellipse(final Vector2f center, final Vector2f radius, final PaintState parentPaintState) { public Ellipse(final Vector2f center, final Vector2f radius, final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
this.c = center; this.c = center;
this.r = radius; this.r = radius;
} }
PathModel createPath() { PathModel createPath() {
final PathModel out = new PathModel(); PathModel out = new PathModel();
out.moveTo(false, this.c.add(this.r.x(), 0.0f)); out.moveTo(false, this.c.add(this.r.x(), 0.0f));
out.curveTo(false, this.c.add(this.r.x(), this.r.y() * Base.kappa90), out.curveTo(false, this.c.add(this.r.x(), this.r.y() * Base.kappa90), this.c.add(this.r.x() * Base.kappa90, this.r.y()), this.c.add(0.0f, this.r.y()));
this.c.add(this.r.x() * Base.kappa90, this.r.y()), this.c.add(0.0f, this.r.y())); out.curveTo(false, this.c.add(-this.r.x() * Base.kappa90, this.r.y()), this.c.add(-this.r.x(), this.r.y() * Base.kappa90), this.c.add(-this.r.x(), 0.0f));
out.curveTo(false, this.c.add(-this.r.x() * Base.kappa90, this.r.y()), out.curveTo(false, this.c.add(-this.r.x(), -this.r.y() * Base.kappa90), this.c.add(-this.r.x() * Base.kappa90, -this.r.y()), this.c.add(0.0f, -this.r.y()));
this.c.add(-this.r.x(), this.r.y() * Base.kappa90), this.c.add(-this.r.x(), 0.0f)); out.curveTo(false, this.c.add(this.r.x() * Base.kappa90, -this.r.y()), this.c.add(this.r.x(), -this.r.y() * Base.kappa90), this.c.add(this.r.x(), 0.0f));
out.curveTo(false, this.c.add(-this.r.x(), -this.r.y() * Base.kappa90),
this.c.add(-this.r.x() * Base.kappa90, -this.r.y()), this.c.add(0.0f, -this.r.y()));
out.curveTo(false, this.c.add(this.r.x() * Base.kappa90, -this.r.y()),
this.c.add(this.r.x(), -this.r.y() * Base.kappa90), this.c.add(this.r.x(), 0.0f));
out.close(); out.close();
return out; return out;
} }
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
LOGGER.debug(spacingDist(spacing) + "Ellipse c=" + this.c + " r=" + this.r); Log.debug(spacingDist(spacing) + "Ellipse c=" + this.c + " r=" + this.r);
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
LOGGER.trace(spacingDist(level) + "DRAW esvg::Ellipse"); Log.verbose(spacingDist(level) + "DRAW esvg::Ellipse");
if (this.r.x() <= 0.0f || this.r.y() <= 0.0f) { if (this.r.x() <= 0.0f || this.r.y() <= 0.0f) {
LOGGER.trace(spacingDist(level + 1) + "Too small radius" + this.r); Log.verbose(spacingDist(level + 1) + "Too small radius" + this.r);
return; return;
} }
final PathModel listElement = createPath(); PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix; Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans); mtx = mtx.multiply(basicTrans);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx); //listPoints.applyMatrix(mtx);
final SegmentList listSegmentFill = new SegmentList(); SegmentList listSegmentFill = new SegmentList();
final SegmentList listSegmentStroke = new SegmentList(); SegmentList listSegmentStroke = new SegmentList();
final Weight tmpFill = new Weight(); Weight tmpFill = new Weight();
final Weight tmpStroke = new Weight(); Weight tmpStroke = new Weight();
final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
@ -92,8 +84,7 @@ public class Ellipse extends Base {
} }
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -104,30 +95,25 @@ public class Ellipse extends Base {
//myRenderer.addDebugSegment(listSegmentFill); //myRenderer.addDebugSegment(listSegmentFill);
//myRenderer.addDebugSegment(listSegmentStroke) //myRenderer.addDebugSegment(listSegmentStroke)
} }
@Override @Override
public void drawShapePoints( public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
final List<List<Vector2f>> out, Log.verbose(spacingDist(level) + "DRAW Shape esvg::Ellipse");
final int recurtionMax, PathModel listElement = createPath();
final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Ellipse");
final PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix; Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans); mtx = mtx.multiply(basicTrans);
PointList listPoints; PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold); listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx); listPoints.applyMatrix(mtx);
for (final List<Point> it : listPoints.data) { for (List<Point> it : listPoints.data) {
final List<Vector2f> listPoint = new ArrayList<>(); List<Vector2f> listPoint = new ArrayList<>();
for (final Point itDot : it) { for (Point itDot : it) {
listPoint.add(itDot.pos); listPoint.add(itDot.pos);
} }
out.add(listPoint); out.add(listPoint);
} }
} }
@Override @Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) { public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
if (element == null) { if (element == null) {
@ -135,13 +121,13 @@ public class Ellipse extends Base {
} }
parseTransform(element); parseTransform(element);
parsePaintAttr(element); parsePaintAttr(element);
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
this.c = Vector2f.ZERO; this.c = Vector2f.ZERO;
this.r = Vector2f.ZERO; this.r = Vector2f.ZERO;
String content = element.getAttribute("cx", ""); String content = element.getAttribute("cx", "");
if (content.length() != 0) { if (content.length() != 0) {
this.c = this.c.withX(parseLength(content)); this.c = this.c.withX(parseLength(content));
@ -152,18 +138,18 @@ public class Ellipse extends Base {
} }
content = element.getAttribute("rx", ""); content = element.getAttribute("rx", "");
if (content.length() == 0) { if (content.length() == 0) {
LOGGER.error("Ellipse \"rx\" is not present"); Log.error("Ellipse \"rx\" is not present");
return false; return false;
} }
this.r = this.r.withX(parseLength(content)); this.r = this.r.withX(parseLength(content));
content = element.getAttribute("ry", ""); content = element.getAttribute("ry", "");
if (content.length() == 0) { if (content.length() == 0) {
LOGGER.error("Ellipse \"ry\" is not present"); Log.error("Ellipse \"ry\" is not present");
return false; return false;
} }
this.r = this.r.withY(parseLength(content)); this.r = this.r.withY(parseLength(content));
sizeMax.value = new Vector2f(this.c.x() + this.r.x(), this.c.y() + this.r.y()); sizeMax.value = new Vector2f(this.c.x() + this.r.x(), this.c.y() + this.r.y());
return true; return true;
} }
} }

View File

@ -3,23 +3,20 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.egami.ImageFloatRGBA; import org.atriasoft.egami.ImageFloatRGBA;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.etk.math.Matrix2x3f; import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i; import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.Exml; import org.atriasoft.exml.Exml;
import org.atriasoft.exml.exception.ExmlException; import org.atriasoft.exml.exception.ExmlBuilderException;
import org.atriasoft.exml.exception.ExmlNodeDoesNotExist; import org.atriasoft.exml.exception.ExmlNodeDoesNotExist;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode; import org.atriasoft.exml.model.XmlNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EsvgDocument extends Base { public class EsvgDocument extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(EsvgDocument.class);
private boolean loadOK = false; private boolean loadOK = false;
private final List<Base> refList = new ArrayList<>(); private final List<Base> refList = new ArrayList<>();
private Vector2f size = Vector2f.ZERO; private Vector2f size = Vector2f.ZERO;
@ -27,7 +24,6 @@ public class EsvgDocument extends Base {
private String title = ""; //!< sub-element list private String title = ""; //!< sub-element list
private Uri uri = null; //!< reference elements ... private Uri uri = null; //!< reference elements ...
private String version = "0.0"; private String version = "0.0";
private static final boolean envDisplayRefs = "true".equals(System.getenv("ESQG_DISPLAY_REFS"));
public EsvgDocument() { public EsvgDocument() {
@ -46,19 +42,19 @@ public class EsvgDocument extends Base {
*/ */
public boolean cleanStyleProperty(final XmlElement root) { public boolean cleanStyleProperty(final XmlElement root) {
// for each nodes: // for each nodes:
for (final XmlNode it : root.getNodes()) { for (XmlNode it : root.getNodes()) {
if (!(it instanceof final XmlElement child)) { if (!(it instanceof XmlElement child)) {
continue; continue;
} }
// get attribute style: // get attribute style:
if (child.existAttribute("style")) { if (child.existAttribute("style")) {
final String content = child.getAttribute("style", ""); String content = child.getAttribute("style", "");
if (content.length() != 0) { if (content.length() != 0) {
final String[] listStyle = content.split(";"); String[] listStyle = content.split(";");
for (final String it1 : listStyle) { for (String it1 : listStyle) {
final String[] value = it1.split(":"); String[] value = it1.split(":");
if (value.length != 2) { if (value.length != 2) {
LOGGER.error("parsing style with a wrong patern : " + it1 + " missing ':'"); Log.error("parsing style with a wrong patern : " + it1 + " missing ':'");
continue; continue;
} }
// TODO Check if the attibute already exist ... // TODO Check if the attibute already exist ...
@ -86,39 +82,34 @@ public class EsvgDocument extends Base {
* Display all the node in the svg file. * Display all the node in the svg file.
*/ */
public void displayDebug() { public void displayDebug() {
LOGGER.debug("Main SVG: size=" + this.size); Log.debug("Main SVG: size=" + this.size);
LOGGER.debug(" refs:"); Log.debug(" refs:");
for (final Base element : this.refList) { for (int iii = 0; iii < this.refList.size(); iii++) {
if (element != null) { if (this.refList.get(iii) != null) {
element.display(2); this.refList.get(iii).display(2);
} }
} }
LOGGER.debug(" Nodes:"); Log.debug(" Nodes:");
for (final Base element : this.subElementList) { for (int iii = 0; iii < this.subElementList.size(); iii++) {
if (element != null) { if (this.subElementList.get(iii) != null) {
element.display(2); this.subElementList.get(iii).display(2);
} }
} }
} }
@Override @Override
protected void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { protected void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
for (final Base element : this.subElementList) { for (int iii = 0; iii < this.subElementList.size(); iii++) {
if (element != null) { if (this.subElementList.get(iii) != null) {
element.draw(myRenderer, basicTrans); this.subElementList.get(iii).draw(myRenderer, basicTrans);
} }
} }
} }
@Override @Override
protected void drawShapePoints( protected void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
final List<List<Vector2f>> out, Log.verbose(spacingDist(level) + "DRAW shape EsvgDocument");
final int recurtionMax, for (Base it : this.subElementList) {
final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW shape EsvgDocument");
for (final Base it : this.subElementList) {
if (it != null) { if (it != null) {
it.drawShapePoints(out, recurtionMax, threshold, basicTrans, level + 1); it.drawShapePoints(out, recurtionMax, threshold, basicTrans, level + 1);
} }
@ -135,27 +126,26 @@ public class EsvgDocument extends Base {
} }
public List<List<Vector2f>> getLines(Vector2f size) { public List<List<Vector2f>> getLines(Vector2f size) {
final List<List<Vector2f>> out = new ArrayList<>(); List<List<Vector2f>> out = new ArrayList<>();
if (size.x() <= 0) { if (size.x() <= 0) {
size = size.withX(this.size.x()); size = size.withX(this.size.x());
} }
if (size.y() <= 0) { if (size.y() <= 0) {
size = size.withY(this.size.y()); size = size.withY(this.size.y());
} }
LOGGER.debug("lineification size " + size); Log.debug("lineification size " + size);
// create the first element matrix modification ... // create the first element matrix modification ...
final Matrix2x3f basicTrans = Matrix2x3f.IDENTITY Matrix2x3f basicTrans = Matrix2x3f.IDENTITY.multiply(Matrix2x3f.createScale(new Vector2f(size.x() / this.size.x(), size.y() / this.size.y())));
.multiply(Matrix2x3f.createScale(new Vector2f(size.x() / this.size.x(), size.y() / this.size.y())));
drawShapePoints(out, 10, 0.25f, basicTrans); drawShapePoints(out, 10, 0.25f, basicTrans);
return out; return out;
} }
public Base getReference(final String name) { public Base getReference(final String name) {
if (name.isEmpty()) { if (name.isEmpty()) {
LOGGER.error("request a reference with no name ... "); Log.error("request a reference with no name ... ");
return null; return null;
} }
for (final Base it : this.refList) { for (Base it : this.refList) {
if (it == null) { if (it == null) {
continue; continue;
} }
@ -163,7 +153,7 @@ public class EsvgDocument extends Base {
return it; return it;
} }
} }
LOGGER.error("Can not find reference name : '" + name + "'"); Log.error("Can not find reference name : '" + name + "'");
return null; return null;
} }
@ -220,18 +210,18 @@ public class EsvgDocument extends Base {
XmlNode doc = null; XmlNode doc = null;
try { try {
doc = Exml.parse(uri); doc = Exml.parse(uri);
} catch (final ExmlException | AknotException e) { } catch (ExmlBuilderException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
return false; return false;
} }
if (doc instanceof final XmlElement elem && elem.existNode("svg")) { if (doc instanceof XmlElement elem && elem.existNode("svg")) {
try { try {
if (elem.getNode("svg") instanceof final XmlElement rootElement) { if (elem.getNode("svg") instanceof XmlElement rootElement) {
cleanStyleProperty(rootElement); cleanStyleProperty(rootElement);
this.loadOK = parseXMLData(rootElement); this.loadOK = parseXMLData(rootElement);
} }
} catch (final ExmlNodeDoesNotExist e) { } catch (ExmlNodeDoesNotExist e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
return false; return false;
@ -252,18 +242,18 @@ public class EsvgDocument extends Base {
XmlNode doc = null; XmlNode doc = null;
try { try {
doc = Exml.parse(data); doc = Exml.parse(data);
} catch (final ExmlException | AknotException e) { } catch (ExmlBuilderException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
return false; return false;
} }
if (doc instanceof final XmlElement elem && elem.existNode("svg")) { if (doc instanceof XmlElement elem && elem.existNode("svg")) {
try { try {
if (elem.getNode("svg") instanceof final XmlElement rootElement) { if (elem.getNode("svg") instanceof XmlElement rootElement) {
cleanStyleProperty(rootElement); cleanStyleProperty(rootElement);
this.loadOK = parseXMLData(rootElement); this.loadOK = parseXMLData(rootElement);
} }
} catch (final ExmlNodeDoesNotExist e) { } catch (ExmlNodeDoesNotExist e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
return false; return false;
@ -286,16 +276,16 @@ public class EsvgDocument extends Base {
pos = parseXmlPosition(root); pos = parseXmlPosition(root);
this.size = parseXmlSize(root); this.size = parseXmlSize(root);
parsePaintAttr(root); parsePaintAttr(root);
LOGGER.trace("parsed .ROOT trans: " + this.transformMatrix); Log.verbose("parsed .ROOT trans: " + this.transformMatrix);
} else { } else {
LOGGER.trace("Parse Reference section ... (no attibute)"); Log.verbose("Parse Reference section ... (no attibute)");
} }
Vector2f maxSize = Vector2f.ZERO; Vector2f maxSize = Vector2f.ZERO;
final Dynamic<Vector2f> size = new Dynamic<>(Vector2f.ZERO); Dynamic<Vector2f> size = new Dynamic<>(Vector2f.ZERO);
// parse all sub node: // parse all sub node:
for (final XmlNode it : root.getNodes()) { for (XmlNode it : root.getNodes()) {
if (!(it instanceof final XmlElement child)) { if (!(it instanceof XmlElement child)) {
// comment can be here... // comment can be here...
continue; continue;
} }
@ -303,7 +293,7 @@ public class EsvgDocument extends Base {
if (child.getValue().equals("g")) { if (child.getValue().equals("g")) {
elementParser = new Group(this.paint); elementParser = new Group(this.paint);
} else if (child.getValue().equals("a")) { } else if (child.getValue().equals("a")) {
LOGGER.info("Note : 'a' balise is parsed like a g balise ..."); Log.info("Note : 'a' balise is parsed like a g balise ...");
elementParser = new Group(this.paint); elementParser = new Group(this.paint);
} else if (child.getValue().equals("title")) { } else if (child.getValue().equals("title")) {
this.title = "TODO : set the title here ..."; this.title = "TODO : set the title here ...";
@ -326,22 +316,22 @@ public class EsvgDocument extends Base {
elementParser = new Text(this.paint); elementParser = new Text(this.paint);
} else if (child.getValue().equals("radialGradient")) { } else if (child.getValue().equals("radialGradient")) {
if (!isReference) { if (!isReference) {
LOGGER.error("'" + child.getValue() + "' node must not be defined outside a defs Section"); Log.error("'" + child.getValue() + "' node must not be defined outside a defs Section");
continue; continue;
} }
elementParser = new RadialGradient(this.paint); elementParser = new RadialGradient(this.paint);
} else if (child.getValue().equals("linearGradient")) { } else if (child.getValue().equals("linearGradient")) {
if (!isReference) { if (!isReference) {
LOGGER.error("'" + child.getValue() + "' node must not be defined outside a defs Section"); Log.error("'" + child.getValue() + "' node must not be defined outside a defs Section");
continue; continue;
} }
elementParser = new LinearGradient(this.paint); elementParser = new LinearGradient(this.paint);
} else if (child.getValue().equals("defs")) { } else if (child.getValue().equals("defs")) {
if (isReference) { if (isReference) {
LOGGER.error("'" + child.getValue() + "' node must not be defined in a defs Section"); Log.error("'" + child.getValue() + "' node must not be defined in a defs Section");
continue; continue;
} }
final boolean retRefs = parseXMLData(child, true); boolean retRefs = parseXMLData(child, true);
// TODO Use retRefs ... // TODO Use retRefs ...
continue; continue;
} else if (child.getValue().equals("sodipodi:namedview")) { } else if (child.getValue().equals("sodipodi:namedview")) {
@ -351,15 +341,14 @@ public class EsvgDocument extends Base {
// Node ignore : generaly inkscape data // Node ignore : generaly inkscape data
continue; continue;
} else { } else {
LOGGER.error("node not suported : '" + child.getValue() Log.error("node not suported : '" + child.getValue() + "' must be [title,g,a,path,rect,circle,ellipse,line,polyline,polygon,text,metadata]");
+ "' must be [title,g,a,path,rect,circle,ellipse,line,polyline,polygon,text,metadata]");
} }
if (elementParser == null) { if (elementParser == null) {
LOGGER.error("error on node: '" + child.getValue() + "' allocation error or not supported ..."); Log.error("error on node: '" + child.getValue() + "' allocation error or not supported ...");
continue; continue;
} }
if (!elementParser.parseXML(child, this.transformMatrix, size)) { if (!elementParser.parseXML(child, this.transformMatrix, size)) {
LOGGER.error("error on node: '" + child.getValue() + "' Sub Parsing ERROR"); Log.error("error on node: '" + child.getValue() + "' Sub Parsing ERROR");
elementParser = null; elementParser = null;
continue; continue;
} }
@ -381,7 +370,7 @@ public class EsvgDocument extends Base {
} else { } else {
this.size = Vector2f.clipInt(this.size); this.size = Vector2f.clipInt(this.size);
} }
if (envDisplayRefs && !isReference) { if (!isReference) {
displayDebug(); displayDebug();
} }
return true; return true;
@ -403,12 +392,12 @@ public class EsvgDocument extends Base {
size = size.withY((int) this.size.y()); size = size.withY((int) this.size.y());
} }
} }
LOGGER.debug("Generate size " + size); Log.debug("Generate size " + size);
Renderer renderedElement = new Renderer(size, this, visualDebug); Renderer renderedElement = new Renderer(size, this, visualDebug);
// create the first element matrix modification ... // create the first element matrix modification ...
Matrix2x3f basicTrans = Matrix2x3f.IDENTITY.multiply(Matrix2x3f.createScale(new Vector2f(size.x() / this.size.x(), size.y() / this.size.y()))); Matrix2x3f basicTrans = Matrix2x3f.IDENTITY.multiply(Matrix2x3f.createScale(new Vector2f(size.x() / this.size.x(), size.y() / this.size.y())));
draw(renderedElement, basicTrans); draw(renderedElement, basicTrans);
// direct return the generated data ... // direct return the generated data ...
return renderedElement.getData(); return renderedElement.getData();
} }
@ -427,23 +416,16 @@ public class EsvgDocument extends Base {
size = new Vector2i((int) this.size.x(), (int) this.size.y()); size = new Vector2i((int) this.size.x(), (int) this.size.y());
} else { } else {
if (size.x() <= 0) { if (size.x() <= 0) {
size = size.withX((int) Math.abs(this.size.x())); size = size.withX((int) this.size.x());
} }
if (size.y() <= 0) { if (size.y() <= 0) {
size = size.withY((int) Math.abs(this.size.y())); size = size.withY((int) this.size.y());
} }
} }
if (size.x() <= 0) { Log.debug("Generate size " + size);
LOGGER.error("Generate size " + size); Renderer renderedElement = new Renderer(size, this, visualDebug);
}
if (size.y() <= 0) {
LOGGER.error("Generate size " + size);
}
LOGGER.trace("Generate size " + size);
final Renderer renderedElement = new Renderer(size, this, visualDebug);
// create the first element matrix modification ... // create the first element matrix modification ...
final Matrix2x3f basicTrans = Matrix2x3f.IDENTITY Matrix2x3f basicTrans = Matrix2x3f.IDENTITY.multiply(Matrix2x3f.createScale(new Vector2f(size.x() / this.size.x(), size.y() / this.size.y())));
.multiply(Matrix2x3f.createScale(new Vector2f(size.x() / this.size.x(), size.y() / this.size.y())));
draw(renderedElement, basicTrans); draw(renderedElement, basicTrans);
// direct return the generated data ... // direct return the generated data ...

View File

@ -1,13 +1,13 @@
package org.atriasoft.esvg; package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.esvg.font.Glyph; import org.atriasoft.esvg.font.Glyph;
import org.atriasoft.esvg.font.Kerning; import org.atriasoft.esvg.font.Kerning;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.RenderingConfig; import org.atriasoft.esvg.render.RenderingConfig;
import org.atriasoft.esvg.render.Weight; import org.atriasoft.esvg.render.Weight;
@ -17,69 +17,66 @@ import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i; import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.atriasoft.exml.Exml; import org.atriasoft.exml.Exml;
import org.atriasoft.exml.exception.ExmlException; import org.atriasoft.exml.exception.ExmlBuilderException;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode; import org.atriasoft.exml.model.XmlNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// https://www.w3.org/TR/SVGTiny12/fonts.html // https://www.w3.org/TR/SVGTiny12/fonts.html
/* /*
| | | | | | | |
| | | | | | | |
| | | | | | | |
Y | | | | Y | | | |
^ |------------| |------------| ^ |------------| |------------|
| |
advance.y: /-> | advance.y: /-> |
| | | |
| | | |
sizeTex.x /-> | | |------------| |------------| sizeTex.x /-> | | |------------| |------------|
| | | | | | | | | | | | | |
| | | | | | | | | | | | | |
| | | | | | | | | | | | | |
| | | | | | | | | | | | | |
| | | | A | | G | | | | | A | | G |
| | | | | | | | | | | | | |
| | | | | | | | | | | | | |
| | | | | | | | | | | | | |
| | | | | | | | | | | | | |
\-> | | |------------| |------------| \-> | | |------------| |------------|
/--> | | /--> | |
\--> \-> | \--> \-> |
bearing.y | bearing.y |
|>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> X |>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> X
<------------------------> : advance.x <------------------------> : advance.x
<------------> : sizeTexture.x <------------> : sizeTexture.x
<---> : bearing.x <---> : bearing.x
_
_ *----------------------* ^ ==> calculateFontRealHeight(fontSize);
*----------------------* ^ ==> calculateFontRealHeight(fontSize); | | | ^ ==> getAscent(fontSize);
| | | ^ ==> getAscent(fontSize); | | | | _
| | | | _ | /\ | | | ^ ==> Font Height (height of a capital letter) = fontSize
| /\ | | | ^ ==> Font Height (height of a capital letter) = fontSize | / \ | | | |
| / \ | | | | | / \ | | | |
| / \ | | | | | /------\ | | | |
| /------\ | | | | | / \ | | | |
| / \ | | | |
| / \ | |___|____|________________________==> render line | / \ | |___|____|________________________==> render line
| | | ^ | | | ^
| | | | | | | |
| | | |==> getDescent(fontSize); | | | |==> getDescent(fontSize);
| | | | | | | |
*----------------------* | | *----------------------* | |
*/ */
public class EsvgFont { public class EsvgFont {
static final Logger LOGGER = LoggerFactory.getLogger(EsvgFont.class);
/** /**
* Load the file that might contain the svg * Load the file that might contain the svg
* @param uri File of the svg * @param uri File of the svg
@ -87,43 +84,38 @@ public class EsvgFont {
* @return true : Parsing is OK * @return true : Parsing is OK
*/ */
public static EsvgFont load(final Uri uri) { public static EsvgFont load(final Uri uri) {
final EsvgFont font = new EsvgFont(); EsvgFont font = new EsvgFont();
XmlNode doc = null; XmlNode doc = null;
try { try {
doc = Exml.parse(uri); doc = Exml.parse(uri);
} catch (final ExmlException e) { } catch (ExmlBuilderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} catch (final AknotException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
return null; return null;
} }
if (!(doc instanceof final XmlElement root)) { if (!(doc instanceof XmlElement root)) {
LOGGER.error("can not load the SVG font ==> wrong root node"); Log.error("can not load the SVG font ==> wrong root node");
return null; return null;
} }
if (!root.existNode("svg") || !(root.getNodeNoExcept("svg") instanceof final XmlElement svgNode)) { if (!root.existNode("svg") || !(root.getNodeNoExcept("svg") instanceof XmlElement svgNode)) {
LOGGER.error("can not load Node <svg> in svg document"); Log.error("can not load Node <svg> in svg document");
return null; return null;
} }
if (!svgNode.existNode("defs") || !(svgNode.getNodeNoExcept("defs") instanceof final XmlElement defsNode)) { if (!svgNode.existNode("defs") || !(svgNode.getNodeNoExcept("defs") instanceof XmlElement defsNode)) {
LOGGER.error("can not load Node <defs> in svg document"); Log.error("can not load Node <defs> in svg document");
return null; return null;
} }
if (!defsNode.existNode("font") if (!defsNode.existNode("font") || !(defsNode.getNodeNoExcept("font") instanceof XmlElement fontElement)) {
|| !(defsNode.getNodeNoExcept("font") instanceof final XmlElement fontElement)) { Log.error("can not load Node <font> in svg document");
LOGGER.error("can not load Node <font> in svg document");
return null; return null;
} }
font.horizAdvX = Integer.parseInt(fontElement.getAttribute("horiz-adv-x", "100")); font.horizAdvX = Integer.parseInt(fontElement.getAttribute("horiz-adv-x", "100"));
int nbGlyph = 0; int nbGlyph = 0;
for (final XmlNode values : fontElement.getNodes()) { for (XmlNode values : fontElement.getNodes()) {
if (values.getValue().equals("font-face")) { if (values.getValue().equals("font-face")) {
if (values instanceof final XmlElement fontFace) { if (values instanceof XmlElement fontFace) {
font.fontFamily = fontFace.getAttribute("font-family", "unknown"); font.fontFamily = fontFace.getAttribute("font-family", "unknown");
font.fontStretch = fontFace.getAttribute("font-stretch", "normal"); font.fontStretch = fontFace.getAttribute("font-stretch", "normal");
font.fontWeight = Integer.parseInt(fontFace.getAttribute("font-weight", "400")); font.fontWeight = Integer.parseInt(fontFace.getAttribute("font-weight", "400"));
@ -151,17 +143,17 @@ public class EsvgFont {
//unicode-range="U+0020-1F093" //unicode-range="U+0020-1F093"
tmp = fontFace.getAttribute("unicode-range", null); tmp = fontFace.getAttribute("unicode-range", null);
tmpSplit = tmp.split("-"); tmpSplit = tmp.split("-");
final int start = Integer.parseInt(tmpSplit[0].substring(2), 16); int start = Integer.parseInt(tmpSplit[0].substring(2), 16);
final int stop = Integer.parseInt(tmpSplit[1], 16); int stop = Integer.parseInt(tmpSplit[1], 16);
font.unicodeRange = new Pair<>(start, stop); font.unicodeRange = new Pair<>(start, stop);
} }
} }
} }
for (final XmlNode values : fontElement.getNodes()) { for (XmlNode values : fontElement.getNodes()) {
if (values.getValue().equals("glyph")) { if (values.getValue().equals("glyph")) {
nbGlyph++; nbGlyph++;
//LOGGER.info("find flyph: " + nbGlyph); //Log.info("find flyph: " + nbGlyph);
final Glyph tmp = Glyph.valueOf(values.toElement(), font); Glyph tmp = Glyph.valueOf(values.toElement(), font);
if (tmp != null) { if (tmp != null) {
font.glyphs.put(tmp.getUnicodeValue(), tmp); font.glyphs.put(tmp.getUnicodeValue(), tmp);
} }
@ -172,37 +164,37 @@ public class EsvgFont {
} else if (values.getValue().equals("font-face")) { } else if (values.getValue().equals("font-face")) {
// already done ... // already done ...
} else { } else {
LOGGER.warn("unsupported node name :" + values.getValue()); Log.warning("unsupported node name :" + values.getValue());
} }
} }
for (final XmlNode values : fontElement.getNodes()) { for (XmlNode values : fontElement.getNodes()) {
if (values.getValue().equals("hkern")) { if (values.getValue().equals("hkern")) {
if (values instanceof final XmlElement kernElem) { if (values instanceof XmlElement kernElem) {
final String g1 = kernElem.getAttribute("g1", null); String g1 = kernElem.getAttribute("g1", null);
final String g2 = kernElem.getAttribute("g2", null); String g2 = kernElem.getAttribute("g2", null);
if (g1 == null || g2 == null) { if (g1 == null || g2 == null) {
continue; continue;
} }
final float offset = Float.parseFloat(kernElem.getAttribute("k", "0")); float offset = Float.parseFloat(kernElem.getAttribute("k", "0"));
if (offset == 0.0f) { if (offset == 0.0f) {
continue; continue;
} }
final String[] g1Splited = g1.split(","); String[] g1Splited = g1.split(",");
final String[] g2Splited = g2.split(","); String[] g2Splited = g2.split(",");
// create the list of kerning of the next elements // create the list of kerning of the next elements
final List<Kerning> elementsKerning = new ArrayList<>(); List<Kerning> elementsKerning = new ArrayList<>();
for (final String element : g2Splited) { for (int iii = 0; iii < g2Splited.length; iii++) {
for (final Map.Entry<Integer, Glyph> entry : font.glyphs.entrySet()) { for (Map.Entry<Integer, Glyph> entry : font.glyphs.entrySet()) {
if (entry.getValue().getName().equals(element)) { if (entry.getValue().getName().equals(g2Splited[iii])) {
elementsKerning.add(new Kerning(offset, entry.getKey())); elementsKerning.add(new Kerning(offset, entry.getKey()));
break; break;
} }
} }
} }
// add it on the // add it on the
for (final String element : g1Splited) { for (int iii = 0; iii < g1Splited.length; iii++) {
for (final Map.Entry<Integer, Glyph> entry : font.glyphs.entrySet()) { for (Map.Entry<Integer, Glyph> entry : font.glyphs.entrySet()) {
if (entry.getValue().getName().equals(element)) { if (entry.getValue().getName().equals(g1Splited[iii])) {
entry.getValue().addKerning(elementsKerning); entry.getValue().addKerning(elementsKerning);
font.hasKerning = true; font.hasKerning = true;
break; break;
@ -214,7 +206,7 @@ public class EsvgFont {
} }
return font; return font;
} }
// The maximum accented height of the font within the font coordinate system. // The maximum accented height of the font within the font coordinate system.
private int ascent = 800; // this is the height of the font (on top...) private int ascent = 800; // this is the height of the font (on top...)
private int[] bbox = { -879, -545, 1767, 934 }; private int[] bbox = { -879, -545, 1767, 934 };
@ -238,41 +230,149 @@ public class EsvgFont {
private int unitsPerEm = 1000; // full size of the font private int unitsPerEm = 1000; // full size of the font
// The height of lowercase glyphs in the font within the font coordinate system. // The height of lowercase glyphs in the font within the font coordinate system.
private int xHeight = 450; private int xHeight = 450;
/** /**
* Get the font real size use (height) for all the characters. * Get the font real size use (height) for all the characters.
* @param fontSize size of the font the user require * @param fontSize size of the font the user require
* @return Real size in pixel of element can impact the output * @return Real size in pixel of element can impact the output
*/ */
public int calculateFontRealHeight(final int fontSize) { public int calculateFontRealHeight(final int fontSize) {
return fontSize * this.unitsPerEm / this.capHeight; return fontSize * this.unitsPerEm / this.capHeight;
} }
public float calculateFontSizeWithHeight(final float fontHeight) { public float calculateFontSizeWithHeight(final float fontHeight) {
return fontHeight * this.capHeight / this.unitsPerEm; return fontHeight * this.capHeight / this.unitsPerEm;
} }
public Vector2f calculateRenderOffset(final int fontSize) { public Vector2f calculateRenderOffset(final int fontSize) {
final int realSize = calculateFontRealHeight(fontSize); int realSize = calculateFontRealHeight(fontSize);
final float deltaY = realSize * this.ascent / this.unitsPerEm; float deltaY = realSize * this.ascent / this.unitsPerEm;
return new Vector2f(0, deltaY); return new Vector2f(0, deltaY);
} }
public float calculateSclaleFactor(final int fontSize) { public float calculateSclaleFactor(final int fontSize) {
final int realSize = calculateFontRealHeight(fontSize); int realSize = calculateFontRealHeight(fontSize);
return (float) realSize / (float) this.unitsPerEm; return (float) realSize / (float) this.unitsPerEm;
} }
public Vector2i calculateTextSize(final int fontSize, final String data) { public int calculateWidth(final int uVal, final int fontSize) {
final boolean withKerning = true; Glyph glyph = getGlyph(uVal);
final int widthOut = calculateWidth(data, fontSize, withKerning); if (glyph == null) {
return 0;
final int realSize = calculateFontRealHeight(fontSize); }
return new Vector2i(widthOut, realSize); int realSize = calculateFontRealHeight(fontSize);
/*
float scale = (float) realSize / (float) this.unitsPerEm; float scale = (float) realSize / (float) this.unitsPerEm;
return (int) (glyph.getHorizAdvX() * scale);
}
public int calculateWidth(final String uVal, final int fontSize) {
return calculateWidth(uVal, fontSize, true);
}
public int calculateWidth(final String data, final int fontSize, final boolean withKerning) {
int realSize = calculateFontRealHeight(fontSize);
float scale = (float) realSize / (float) this.unitsPerEm;
int out = 0;
int lastValue = 0;
for (char uVal : data.toCharArray()) {
Glyph glyph = getGlyph(uVal);
if (glyph == null) {
lastValue = uVal;
continue;
}
if (withKerning) {
out -= glyph.getKerning(lastValue) * scale;
lastValue = uVal;
}
out += glyph.getHorizAdvX() * scale;
}
return out;
}
/**
* Get the rendering size of the specific glyph (size rendered in the Weight class).
* @param unicodeValue Unicode value to render
* @param fontSize Size of the font
* @return the size in pixel of the rendering elements
*/
public Vector2i calculateWidthRendering(final Integer unicodeValue, final int fontSize) {
return new Vector2i(calculateWidth(unicodeValue, fontSize), calculateFontRealHeight(fontSize));
}
public int getDescent() {
return this.descent;
}
public Glyph getGlyph(final int glyphIndex) {
Glyph out = this.glyphs.get(glyphIndex);
if (out == null) {
return this.missingGlyph;
}
return out;
}
public Glyph getGlyphNullIfMissing(final int glyphIndex) {
Glyph out = this.glyphs.get(glyphIndex);
if (out == null) {
return null;
}
return out;
}
public int getHorizAdvX() {
return this.horizAdvX;
}
/**
* Get the number of available glyph in the Font
* @return the glyph count.
*/
public int getNumGlyphs() {
return this.glyphs.size();
}
public float getUnitsPerEm() {
return this.unitsPerEm;
}
/**
* Check if the font have some kerning data
* @return true if kerning is availlable.
*/
public boolean hasKerning() {
return this.hasKerning;
}
public Weight render(final int uVal, final int fontSize) {
int realSize = calculateFontRealHeight(fontSize);
Glyph glyph = getGlyph(uVal);
if (glyph == null) {
return null;
}
float scale = (float) realSize / (float) this.unitsPerEm;
RenderingConfig config = new RenderingConfig(10, 0.25f, 8);
Matrix2x3f transform = Matrix2x3f.createTranslate(new Vector2f(0, -this.descent)).multiply(Matrix2x3f.createScale(scale));
PathModel model = glyph.getModel();
if (model == null) {
return null;
}
Weight data = glyph.getModel().drawFill(calculateWidthRendering(uVal, fontSize), transform, 8, config);
return data;
}
public Weight render(final String uVal, final int fontSize) {
return render(uVal, fontSize, true);
}
public Weight render(final String data, final int fontSize, final boolean withKerning) {
int widthOut = calculateWidth(data, fontSize, withKerning);
int realSize = calculateFontRealHeight(fontSize);
float scale = (float) realSize / (float) this.unitsPerEm;
Weight weight = new Weight(new Vector2i(widthOut, realSize));
int offsetWriting = 0; int offsetWriting = 0;
int lastValue = 0; int lastValue = 0;
for (char uVal : data.toCharArray()) { for (char uVal : data.toCharArray()) {
@ -283,166 +383,21 @@ public class EsvgFont {
} }
if (withKerning) { if (withKerning) {
offsetWriting -= glyph.getKerning(lastValue) * scale; offsetWriting -= glyph.getKerning(lastValue) * scale;
Log.info(" ==> kerning offset = " + (glyph.getKerning(lastValue) * scale));
lastValue = uVal; lastValue = uVal;
} }
float advenceXLocal = glyph.getHorizAdvX() * scale; float advenceXLocal = glyph.getHorizAdvX() * scale;
// No generation of output ...
offsetWriting += advenceXLocal; RenderingConfig config = new RenderingConfig(10, 0.25f, 8);
} Matrix2x3f transform = Matrix2x3f.createTranslate(new Vector2f(0, -this.descent)).multiply(Matrix2x3f.createScale(scale));
return new Vector2i(offsetWriting, realSize); PathModel model = glyph.getModel();
*/
}
public int calculateWidth(final int uVal, final int fontSize) {
final Glyph glyph = getGlyph(uVal);
if (glyph == null) {
return 0;
}
final int realSize = calculateFontRealHeight(fontSize);
final float scale = (float) realSize / (float) this.unitsPerEm;
return (int) (glyph.getHorizAdvX() * scale);
}
public int calculateWidth(final String uVal, final int fontSize) {
return calculateWidth(uVal, fontSize, true);
}
public int calculateWidth(final String data, final int fontSize, final boolean withKerning) {
final int realSize = calculateFontRealHeight(fontSize);
final float scale = (float) realSize / (float) this.unitsPerEm;
//LOGGER.error("scale =" + scale+ " font size = " + fontSize + " realSize=" + realSize);
float offsetWriting = 0;
int lastValue = 0;
for (final char uVal : data.toCharArray()) {
final Glyph glyph = getGlyph(uVal);
if (glyph == null) {
lastValue = uVal;
continue;
}
if (withKerning) {
offsetWriting -= glyph.getKerning(lastValue) * scale;
lastValue = uVal;
}
final float advenceXLocal = glyph.getHorizAdvX() * scale;
offsetWriting += advenceXLocal;
//LOGGER.error("offset X =" + offsetWriting + " + " + advenceXLocal + " " + uVal);
}
return (int) offsetWriting;
}
/**
* Get the rendering size of the specific glyph (size rendered in the Weight class).
* @param unicodeValue Unicode value to render
* @param fontSize Size of the font
* @return the size in pixel of the rendering elements
*/
public Vector2i calculateWidthRendering(final Integer unicodeValue, final int fontSize) {
return new Vector2i(calculateWidth(unicodeValue, fontSize), calculateFontRealHeight(fontSize));
}
public int getDescent() {
return this.descent;
}
public Glyph getGlyph(final int glyphIndex) {
final Glyph out = this.glyphs.get(glyphIndex);
if (out == null) {
return this.missingGlyph;
}
return out;
}
public Glyph getGlyphNullIfMissing(final int glyphIndex) {
final Glyph out = this.glyphs.get(glyphIndex);
if (out == null) {
return null;
}
return out;
}
public int getHorizAdvX() {
return this.horizAdvX;
}
/**
* Get the number of available glyph in the Font
* @return the glyph count.
*/
public int getNumGlyphs() {
return this.glyphs.size();
}
public float getUnitsPerEm() {
return this.unitsPerEm;
}
/**
* Check if the font have some kerning data
* @return true if kerning is availlable.
*/
public boolean hasKerning() {
return this.hasKerning;
}
public Weight render(final int uVal, final int fontSize) {
final int realSize = calculateFontRealHeight(fontSize);
final Glyph glyph = getGlyph(uVal);
if (glyph == null) {
return null;
}
final float scale = (float) realSize / (float) this.unitsPerEm;
final RenderingConfig config = new RenderingConfig(10, 0.25f, 8);
final Matrix2x3f transform = Matrix2x3f.createTranslate(new Vector2f(0, -this.descent))
.multiply(Matrix2x3f.createScale(scale));
final PathModel model = glyph.getModel();
if (model == null) {
return null;
}
final Weight data = glyph.getModel().drawFill(calculateWidthRendering(uVal, fontSize), transform, 8, config);
return data;
}
public Weight render(final String uVal, final int fontSize) {
return render(uVal, fontSize, true);
}
public Weight render(final String data, final int fontSize, final boolean withKerning) {
final int widthOut = calculateWidth(data, fontSize, withKerning);
final int realSize = calculateFontRealHeight(fontSize);
final float scale = (float) realSize / (float) this.unitsPerEm;
final Weight weight = new Weight(new Vector2i(widthOut, realSize));
float offsetWriting = 0;
int lastValue = 0;
for (final char uVal : data.toCharArray()) {
final Glyph glyph = getGlyph(uVal);
if (glyph == null) {
lastValue = uVal;
continue;
}
if (withKerning) {
offsetWriting -= glyph.getKerning(lastValue) * scale;
LOGGER.info(" ==> kerning offset = " + (glyph.getKerning(lastValue) * scale));
lastValue = uVal;
}
final float advenceXLocal = glyph.getHorizAdvX() * scale;
final RenderingConfig config = new RenderingConfig(10, 0.25f, 8);
final Matrix2x3f transform = Matrix2x3f.createTranslate(new Vector2f(0, -this.descent))
.multiply(Matrix2x3f.createScale(scale));
final PathModel model = glyph.getModel();
if (model != null) { if (model != null) {
final Weight redered = model.drawFill(calculateWidthRendering((int) uVal, fontSize), transform, 8, Weight redered = model.drawFill(calculateWidthRendering((int) uVal, fontSize), transform, 8, config);
config); weight.fusion(redered, offsetWriting, 0);
weight.fusion(redered, (int) offsetWriting, 0);
} }
offsetWriting += advenceXLocal; offsetWriting += advenceXLocal;
} }
return weight; return weight;
} }

View File

@ -0,0 +1,255 @@
package org.atriasoft.esvg;
import org.atriasoft.egami.ImageByteRGBA;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.etk.Color;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i;
/**
* Graphic context is used to manage dynamic
* @author heero
*
*/
public class GraphicContext {
private EsvgDocument document;
PaintState paintState;
private PathModel path = null;
private Vector2i size = Vector2i.VALUE_32;
public GraphicContext() {
clear();
}
public void circle(final Vector2f position, final float radius) {
this.document.addElement(new Circle(position, radius, this.paintState.clone()));
}
public void clear() {
this.document = new EsvgDocument(this.size);
this.paintState = new PaintState();
}
/**
* Clear the fill color (disable fill ==> better that set it transparent)
*/
public void clearColorFill() {
this.paintState.fill = null;
}
/**
* Clear the Stroke color (disable stroke)
*/
public void clearColorStroke() {
this.paintState.clearStroke();
}
public void ellipse(final Vector2f center, final Vector2f radius) {
this.document.addElement(new Ellipse(center, radius, this.paintState.clone()));
}
/**
* Get the fill color.
* @return fill color.
*/
public Color getColorFill() {
return this.paintState.getFill();
}
/**
* Get the stroke color.
* @return Stroke color.
*/
public Color getColorStroke() {
return this.paintState.getStroke();
}
public CapMode getLineCap() {
return this.paintState.getLineCap();
}
public JoinMode getLineJoin() {
return this.paintState.getLineJoin();
}
public float getMiterLimit() {
return this.paintState.getMiterLimit();
}
public float getOpacity() {
return this.paintState.getOpacity();
}
public float getStrokeWidth() {
return this.paintState.getStrokeWidth();
}
public void line(final Vector2f origin, final Vector2f destination) {
this.document.addElement(new Line(origin, destination, this.paintState.clone()));
}
public void lineRel(final Vector2f origin, final Vector2f relativeDestination) {
this.document.addElement(new Line(origin, origin.add(relativeDestination), this.paintState.clone()));
}
public void pathLine(final Vector2f pos) {
if (this.path == null) {
Log.error("Empty path... Need call pathStart() before");
return;
}
this.path.lineTo(false, pos);
}
public void pathLineTo(final Vector2f pos) {
if (this.path == null) {
Log.error("Empty path... Need call pathStart() before");
return;
}
this.path.lineTo(true, pos);
}
public void pathMove(final Vector2f pos) {
if (this.path == null) {
Log.error("Empty path... Need call pathStart() before");
return;
}
this.path.moveTo(false, pos);
}
public void pathMoveTo(final Vector2f pos) {
if (this.path == null) {
Log.error("Empty path... Need call pathStart() before");
return;
}
this.path.moveTo(true, pos);
}
public void pathStart() {
pathStop();
this.path = new PathModel();
}
public void pathStop() {
if (this.path == null) {
return;
}
this.path.close(false);
this.document.addElement(new Path(this.path, this.paintState.clone()));
this.path = null;
}
public void pathStopLinked() {
if (this.path == null) {
return;
}
this.path.close(true);
this.document.addElement(new Path(this.path, this.paintState.clone()));
this.path = null;
}
public void rectangle(final Vector2f position, final Vector2f destination) {
if (this.path != null) {
Log.error("Path not empty ... Need call pathStart() before");
pathStop();
}
this.document.addElement(new Rectangle(position, destination.less(position), this.paintState.clone()));
}
public void rectangleRounded(final Vector2f position, final Vector2f destination, final Vector2f ruound) {
if (this.path != null) {
Log.error("Path not empty ... Need call pathStart() before");
pathStop();
}
this.document.addElement(new Rectangle(position, destination.less(position), ruound, this.paintState.clone()));
}
public void rectangleRoundedWidth(final Vector2f position, final Vector2f width, final Vector2f ruound) {
if (this.path != null) {
Log.error("Path not empty ... Need call pathStart() before");
pathStop();
}
this.document.addElement(new Rectangle(position, width, ruound, this.paintState.clone()));
}
public void rectangleWidth(final Vector2f position, final Vector2f width) {
if (this.path != null) {
Log.error("Path not empty ... Need call pathStart() before");
pathStop();
}
this.document.addElement(new Rectangle(position, width, this.paintState.clone()));
}
public ImageByteRGBA render() {
return null;
}
public String renderSvg() {
return null;
}
/**
* set the fill color
* @param color Color to set on fill
* @apiNote use clearFill() if you want to remove drawing of fill
*/
public void setColorFill(final Color color) {
this.paintState.setFill(color);
}
/**
* set the stroke color
* @param color Color to set on stroke
* @apiNote use clearStroke() if you want to remove drawing of stroke
*/
public void setColorStroke(final Color color) {
this.paintState.setStroke(color);
}
public void setLineCap(final CapMode lineCap) {
this.paintState.setLineCap(lineCap);
}
public void setLineJoin(final JoinMode lineJoin) {
this.paintState.setLineJoin(lineJoin);
}
public void setMiterLimit(final float miterLimit) {
this.paintState.setMiterLimit(miterLimit);
}
public void setOpacity(final float opacity) {
this.paintState.setOpacity(opacity);
}
/**
* Set global size of the Graphic context (output render size)
* @param xxx Width of the image
* @param yyy Height of the image
* @apiNote It will clear the current context.
*/
public void setSize(final int xxx, final int yyy) {
setSize(new Vector2i(xxx, yyy));
}
/**
* Set global size of the Graphic contexct (output render size)
* @param vector2i New size of the image
* @apiNote It will clear the current context.
*/
private void setSize(final Vector2i size) {
this.size = size;
clear();
}
public void setStrokeWidth(final float strokeWidth) {
this.paintState.setStrokeWidth(strokeWidth);
}
public void text(final Vector2f position, final float height, final String data) {
this.document.addElement(new Text(position, height, data, this.paintState.clone()));
}
}

View File

@ -3,13 +3,12 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.math.Matrix2x3f; import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode; import org.atriasoft.exml.model.XmlNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -17,51 +16,44 @@ import org.slf4j.LoggerFactory;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class Group extends Base { public class Group extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Group.class);
private final List<Base> subElementList = new ArrayList<>(); //!< sub elements ... private final List<Base> subElementList = new ArrayList<>(); //!< sub elements ...
public Group(final PaintState parentPaintState) { public Group(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
} }
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
LOGGER.debug(spacingDist(spacing) + "Group (START) fill=" + this.paint.fill.first + "/" + this.paint.fill.second Log.debug(spacingDist(spacing) + "Group (START) fill=" + this.paint.fill.first + "/" + this.paint.fill.second + " stroke=" + this.paint.stroke.first + "/" + this.paint.stroke.second
+ " stroke=" + this.paint.stroke.first + "/" + this.paint.stroke.second + " stroke-width=" + " stroke-width=" + this.paint.strokeWidth);
+ this.paint.strokeWidth);
for (final Base it : this.subElementList) { for (final Base it : this.subElementList) {
if (it != null) { if (it != null) {
it.display(spacing + 1); it.display(spacing + 1);
} }
} }
LOGGER.debug(spacingDist(spacing) + "Group (STOP)"); Log.debug(spacingDist(spacing) + "Group (STOP)");
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
LOGGER.trace(spacingDist(level) + "DRAW esvg::group"); Log.verbose(spacingDist(level) + "DRAW esvg::group");
for (final Base it : this.subElementList) { for (Base it : this.subElementList) {
if (it != null) { if (it != null) {
it.draw(myRenderer, basicTrans, level + 1); it.draw(myRenderer, basicTrans, level + 1);
} }
} }
} }
@Override @Override
public void drawShapePoints( public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
final List<List<Vector2f>> out, Log.verbose(spacingDist(level) + "DRAW shape esvg::group");
final int recurtionMax, for (Base it : this.subElementList) {
final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW shape esvg::group");
for (final Base it : this.subElementList) {
if (it != null) { if (it != null) {
it.drawShapePoints(out, recurtionMax, threshold, basicTrans, level + 1); it.drawShapePoints(out, recurtionMax, threshold, basicTrans, level + 1);
} }
} }
} }
@Override @Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) { public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
if (element == null) { if (element == null) {
@ -74,18 +66,18 @@ public class Group extends Base {
pos = parseXmlPosition(element); pos = parseXmlPosition(element);
size = parseXmlSize(element); size = parseXmlSize(element);
parsePaintAttr(element); parsePaintAttr(element);
LOGGER.trace("parsed G1. trans : " + this.transformMatrix); Log.verbose("parsed G1. trans : " + this.transformMatrix);
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
LOGGER.trace("parsed G2. trans : " + this.transformMatrix); Log.verbose("parsed G2. trans : " + this.transformMatrix);
sizeMax.value = Vector2f.ZERO; sizeMax.value = Vector2f.ZERO;
final Dynamic<Vector2f> tmpPos = new Dynamic<>(Vector2f.ZERO); Dynamic<Vector2f> tmpPos = new Dynamic<Vector2f>(Vector2f.ZERO);
// parse all sub node : // parse all sub node :
for (final XmlNode it : element.getNodes()) { for (XmlNode it : element.getNodes()) {
if (!(it instanceof final XmlElement child)) { if (!(it instanceof XmlElement child)) {
// can be a comment ... // can be a comment ...
continue; continue;
} }
@ -111,15 +103,14 @@ public class Group extends Base {
} else if (child.getValue().equals("text")) { } else if (child.getValue().equals("text")) {
elementParser = new Text(this.paint); elementParser = new Text(this.paint);
} else { } else {
LOGGER.error("node not suported : '" + child.getValue() Log.error("node not suported : '" + child.getValue() + "' must be [g,a,path,rect,circle,ellipse,line,polyline,polygon,text]");
+ "' must be [g,a,path,rect,circle,ellipse,line,polyline,polygon,text]");
} }
if (elementParser == null) { if (elementParser == null) {
LOGGER.error("error on node: '" + child.getValue() + "' allocation error or not supported ..."); Log.error("error on node: '" + child.getValue() + "' allocation error or not supported ...");
continue; continue;
} }
if (!elementParser.parseXML(child, this.transformMatrix, tmpPos)) { if (!elementParser.parseXML(child, this.transformMatrix, tmpPos)) {
LOGGER.error(" error on node: '" + child.getValue() + "' Sub Parsing ERROR"); Log.error(" error on node: '" + child.getValue() + "' Sub Parsing ERROR");
elementParser = null; elementParser = null;
continue; continue;
} }

View File

@ -3,6 +3,7 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
@ -13,8 +14,6 @@ import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -22,49 +21,47 @@ import org.slf4j.LoggerFactory;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class Line extends Base { public class Line extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Line.class);
private Vector2f startPos = Vector2f.ZERO; //!< Start line position private Vector2f startPos = Vector2f.ZERO; //!< Start line position
private Vector2f stopPos = Vector2f.ZERO; //!< Stop line position private Vector2f stopPos = Vector2f.ZERO; //!< Stop line position
public Line(final PaintState parentPaintState) { public Line(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
} }
public Line(final Vector2f startPos, final Vector2f stopPos, final PaintState parentPaintState) { public Line(final Vector2f startPos, final Vector2f stopPos, final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
this.startPos = startPos; this.startPos = startPos;
this.stopPos = stopPos; this.stopPos = stopPos;
} }
private PathModel createPath() { private PathModel createPath() {
final PathModel out = new PathModel(); PathModel out = new PathModel();
out.clear(); out.clear();
out.moveTo(false, this.startPos); out.moveTo(false, this.startPos);
out.lineTo(false, this.stopPos); out.lineTo(false, this.stopPos);
out.stop(); out.stop();
return out; return out;
} }
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
LOGGER.debug(spacingDist(spacing) + "Line " + this.startPos + " to " + this.stopPos); Log.debug(spacingDist(spacing) + "Line " + this.startPos + " to " + this.stopPos);
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
LOGGER.trace(spacingDist(level) + "DRAW esvg::Line"); Log.verbose(spacingDist(level) + "DRAW esvg::Line");
final PathModel listElement = createPath(); PathModel listElement = createPath();
final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans); Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
myRenderer.getInterpolationThreshold()); SegmentList listSegmentStroke = new SegmentList();
final SegmentList listSegmentStroke = new SegmentList(); Weight tmpFill = new Weight();
final Weight tmpFill = new Weight(); Weight tmpStroke = new Weight();
final Weight tmpStroke = new Weight(); DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
@ -73,8 +70,7 @@ public class Line extends Base {
// No background ... // No background ...
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -83,29 +79,24 @@ public class Line extends Base {
// add on images: // add on images:
myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity); myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity);
} }
@Override @Override
public void drawShapePoints( public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
final List<List<Vector2f>> out, Log.verbose(spacingDist(level) + "DRAW Shape esvg::Line");
final int recurtionMax, PathModel listElement = createPath();
final float threshold, Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Line");
final PathModel listElement = createPath();
final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints; PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold); listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx); listPoints.applyMatrix(mtx);
for (final List<Point> it : listPoints.data) { for (List<Point> it : listPoints.data) {
final List<Vector2f> listPoint = new ArrayList<>(); List<Vector2f> listPoint = new ArrayList<>();
for (final Point itDot : it) { for (Point itDot : it) {
listPoint.add(itDot.pos); listPoint.add(itDot.pos);
} }
out.add(listPoint); out.add(listPoint);
} }
} }
@Override @Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) { public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
// line must have a minimum size... // line must have a minimum size...
@ -115,10 +106,10 @@ public class Line extends Base {
} }
parseTransform(element); parseTransform(element);
parsePaintAttr(element); parsePaintAttr(element);
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
String content = element.getAttribute("x1", ""); String content = element.getAttribute("x1", "");
if (content.length() != 0) { if (content.length() != 0) {
this.startPos = this.startPos.withX(parseLength(content)); this.startPos = this.startPos.withX(parseLength(content));

View File

@ -3,8 +3,9 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color; import org.atriasoft.etk.Color;
import org.atriasoft.etk.Dimension2f; import org.atriasoft.etk.Dimension;
import org.atriasoft.etk.Distance; import org.atriasoft.etk.Distance;
import org.atriasoft.etk.math.FMath; import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Matrix2x3f; import org.atriasoft.etk.math.Matrix2x3f;
@ -13,8 +14,6 @@ import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode; import org.atriasoft.exml.model.XmlNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -23,64 +22,63 @@ import org.slf4j.LoggerFactory;
*/ */
public class LinearGradient extends Base { public class LinearGradient extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(LinearGradient.class);
private final List<Pair<Float, Color>> data = new ArrayList<>(); //!< gradient position x1 y1 private final List<Pair<Float, Color>> data = new ArrayList<>(); //!< gradient position x1 y1
private String href = ""; //!< gradient position x2 y2 private String href = ""; //!< gradient position x2 y2
private Dimension2f pos1 = new Dimension2f(new Vector2f(50, 50), Distance.POURCENT); private Dimension pos1 = new Dimension(new Vector2f(50, 50), Distance.POURCENT);
private Dimension2f pos2 = new Dimension2f(new Vector2f(50, 50), Distance.POURCENT); private Dimension pos2 = new Dimension(new Vector2f(50, 50), Distance.POURCENT);
public SpreadMethod spread = SpreadMethod.PAD; //!< in case of using a single gradient in multiple gradient, the gradient is store in an other element... public SpreadMethod spread = SpreadMethod.PAD; //!< in case of using a single gradient in multiple gradient, the gradient is store in an other element...
public GradientUnits unit = GradientUnits.GRADIENT_UNITS_OBJECT_BOUNDING_BOX; //!< incompatible with href public GradientUnits unit = GradientUnits.GRADIENT_UNITS_OBJECT_BOUNDING_BOX; //!< incompatible with href
public LinearGradient(final PaintState parentPaintState) { public LinearGradient(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
} }
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
LOGGER.debug(spacingDist(spacing) + "LinearGradient " + this.pos1 + " to " + this.pos2); Log.debug(spacingDist(spacing) + "LinearGradient " + this.pos1 + " to " + this.pos2);
for (final Pair<Float, Color> it : this.data) { for (Pair<Float, Color> it : this.data) {
LOGGER.debug(spacingDist(spacing + 1) + "STOP: offset=" + it.first + " color=" + it.second); Log.debug(spacingDist(spacing + 1) + "STOP: offset=" + it.first + " color=" + it.second);
} }
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
LOGGER.trace(spacingDist(level) + "DRAW esvg::LinearGradient"); Log.verbose(spacingDist(level) + "DRAW esvg::LinearGradient");
} }
public List<Pair<Float, Color>> getColors(final EsvgDocument document) { public List<Pair<Float, Color>> getColors(final EsvgDocument document) {
if (this.href.isEmpty()) { if (this.href.isEmpty()) {
return this.data; return this.data;
} }
if (document == null) { if (document == null) {
LOGGER.error("Get null input for document"); Log.error("Get null input for document");
return this.data; return this.data;
} }
final Base base = document.getReference(this.href); Base base = document.getReference(this.href);
if (base == null) { if (base == null) {
LOGGER.error("Can not get base : '" + this.href + "'"); Log.error("Can not get base : '" + this.href + "'");
return this.data; return this.data;
} }
if (base instanceof final RadialGradient gradientR) { if (base instanceof RadialGradient gradientR) {
return gradientR.getColors(document); return gradientR.getColors(document);
} }
if (base instanceof final LinearGradient gradientL) { if (base instanceof LinearGradient gradientL) {
return gradientL.getColors(document); return gradientL.getColors(document);
} }
return this.data; return this.data;
} }
public Dimension2f getPosition1() { public Dimension getPosition1() {
return this.pos1; return this.pos1;
} }
public Dimension2f getPosition2() { public Dimension getPosition2() {
return this.pos2; return this.pos2;
} }
@Override @Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) { public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
{ {
@ -89,25 +87,25 @@ public class LinearGradient extends Base {
if (element == null) { if (element == null) {
return false; return false;
} }
// ---------------- get unique ID ---------------- // ---------------- get unique ID ----------------
this.id = element.getAttribute("id", ""); this.id = element.getAttribute("id", "");
//parseTransform(element); //parseTransform(element);
//parsePaintAttr(element); //parsePaintAttr(element);
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
String contentX = element.getAttribute("x1", ""); String contentX = element.getAttribute("x1", "");
String contentY = element.getAttribute("y1", ""); String contentY = element.getAttribute("y1", "");
if (!contentX.isEmpty() && !contentY.isEmpty()) { if (!contentX.isEmpty() && !contentY.isEmpty()) {
this.pos1 = Dimension2f.valueOf(contentX, contentY); this.pos1 = Dimension.valueOf(contentX, contentY);
} }
contentX = element.getAttribute("x2", ""); contentX = element.getAttribute("x2", "");
contentY = element.getAttribute("y2", ""); contentY = element.getAttribute("y2", "");
if (!contentX.isEmpty() && !contentY.isEmpty()) { if (!contentX.isEmpty() && !contentY.isEmpty()) {
this.pos2 = Dimension2f.valueOf(contentX, contentY); this.pos2 = Dimension.valueOf(contentX, contentY);
} }
contentX = element.getAttribute("gradientUnits", ""); contentX = element.getAttribute("gradientUnits", "");
if (contentX.equals("userSpaceOnUse")) { if (contentX.equals("userSpaceOnUse")) {
@ -115,8 +113,7 @@ public class LinearGradient extends Base {
} else { } else {
this.unit = GradientUnits.GRADIENT_UNITS_OBJECT_BOUNDING_BOX; this.unit = GradientUnits.GRADIENT_UNITS_OBJECT_BOUNDING_BOX;
if (contentX.length() != 0 && contentX != "objectBoundingBox") { if (contentX.length() != 0 && contentX != "objectBoundingBox") {
LOGGER.error("Parsing error of 'gradientUnits' ==> not suported value: '" + contentX Log.error("Parsing error of 'gradientUnits' ==> not suported value: '" + contentX + "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox");
+ "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox");
} }
} }
contentX = element.getAttribute("spreadMethod", ""); contentX = element.getAttribute("spreadMethod", "");
@ -127,8 +124,7 @@ public class LinearGradient extends Base {
} else { } else {
this.spread = SpreadMethod.PAD; this.spread = SpreadMethod.PAD;
if (contentX.length() != 0 && !contentX.equals("pad")) { if (contentX.length() != 0 && !contentX.equals("pad")) {
LOGGER.error("Parsing error of 'spreadMethod' ==> not suported value: '" + contentX Log.error("Parsing error of 'spreadMethod' ==> not suported value: '" + contentX + "' not in : {reflect/repeate/pad} use pad");
+ "' not in : {reflect/repeate/pad} use pad");
} }
} }
// note: xlink:href is incompatible with subNode "stop" // note: xlink:href is incompatible with subNode "stop"
@ -137,20 +133,19 @@ public class LinearGradient extends Base {
this.href = this.href.substring(1); this.href = this.href.substring(1);
} }
// parse all sub node : // parse all sub node :
for (final XmlNode it : element.getNodes()) { for (XmlNode it : element.getNodes()) {
if (it instanceof final XmlElement child) { if (it instanceof XmlElement child) {
if (child.getValue().equals("stop")) { if (child.getValue().equals("stop")) {
float offset = 100; float offset = 100;
Color stopColor = Color.NONE; Color stopColor = Color.NONE;
String content = child.getAttribute("offset", ""); String content = child.getAttribute("offset", "");
if (content.length() != 0) { if (content.length() != 0) {
final Pair<Float, Distance> tmp = parseLength2(content); Pair<Float, Distance> tmp = parseLength2(content);
if (tmp.second == Distance.PIXEL) { if (tmp.second == Distance.PIXEL) {
// special case ==> all time % then no type define ==> % in [0.0 .. 1.0] // special case ==> all time % then no type define ==> % in [0.0 .. 1.0]
offset = tmp.first * 100.0f; offset = tmp.first * 100.0f;
} else if (tmp.second != Distance.POURCENT) { } else if (tmp.second != Distance.POURCENT) {
LOGGER.error("offset : " + content + " res=" + tmp.first + "," + tmp.second Log.error("offset : " + content + " res=" + tmp.first + "," + tmp.second + " Not support other than pourcent %");
+ " Not support other than pourcent %");
} else { } else {
offset = tmp.first; offset = tmp.first;
} }
@ -158,30 +153,29 @@ public class LinearGradient extends Base {
content = child.getAttribute("stop-color", ""); content = child.getAttribute("stop-color", "");
if (content.length() != 0) { if (content.length() != 0) {
stopColor = parseColor(content).first; stopColor = parseColor(content).first;
LOGGER.trace(" color : '" + content + "' == > " + stopColor); Log.verbose(" color : '" + content + "' == > " + stopColor);
} }
content = child.getAttribute("stop-opacity", ""); content = child.getAttribute("stop-opacity", "");
if (content.length() != 0) { if (content.length() != 0) {
float opacity = parseLength(content); float opacity = parseLength(content);
opacity = FMath.avg(0.0f, opacity, 1.0f); opacity = FMath.avg(0.0f, opacity, 1.0f);
stopColor = stopColor.withA(opacity); stopColor = stopColor.withA(opacity);
LOGGER.trace(" opacity : '" + content + "' == > " + stopColor); Log.verbose(" opacity : '" + content + "' == > " + stopColor);
} }
this.data.add(new Pair<>(offset, stopColor)); this.data.add(new Pair<Float, Color>(offset, stopColor));
} else { } else {
LOGGER.error(" node not suported : '" + child.getValue() + "' must be [stop]"); Log.error(" node not suported : '" + child.getValue() + "' must be [stop]");
} }
} }
} }
if (this.data.size() != 0) { if (this.data.size() != 0) {
if (!this.href.isEmpty()) { if (!this.href.isEmpty()) {
LOGGER.error( Log.error(" node can not have an xlink:href element with sub node named: stop ==> removing href");
" node can not have an xlink:href element with sub node named: stop ==> removing href");
this.href = ""; this.href = "";
} }
} }
return true; return true;
} }
} }
} }

View File

@ -3,19 +3,18 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
import org.atriasoft.esvg.render.PointList; import org.atriasoft.esvg.render.PointList;
import org.atriasoft.esvg.render.SegmentList;
import org.atriasoft.esvg.render.Weight; import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.Tools; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.SegmentList;
import org.atriasoft.etk.math.Matrix2x3f; import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.slf4j.Logger; import org.atriasoft.exml.parser.Tools;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -23,8 +22,6 @@ import org.slf4j.LoggerFactory;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class Path extends Base { public class Path extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Path.class);
private record Command( private record Command(
char cmd, char cmd,
String[] listElem, String[] listElem,
@ -34,43 +31,42 @@ public class Path extends Base {
this.listElem = listElem; this.listElem = listElem;
this.offset = offset; this.offset = offset;
} }
Command(final char cmd, final int offset) { Command(final char cmd, final int offset) {
this(cmd, null, offset); this(cmd, null, offset);
} }
} }
public static PathModel createPathModel(final String d) { public static PathModel createPathModel(final String d) {
final PathModel out = new PathModel(); PathModel out = new PathModel();
LOGGER.trace("Parse Path : \"" + d + "\""); Log.verbose("Parse Path : \"" + d + "\"");
final List<String> commandsSplited = Path.splitCommand(d); List<String> commandsSplited = Path.splitCommand(d);
String[] listDot = null; String[] listDot = null;
// TODO REWORK this, can be done with a simple split and search in a list... // TODO REWORK this, can be done with a simple split and search in a list...
for (Command sss = Path.extractCmd(commandsSplited, 0); sss != null; for (Command sss = Path.extractCmd(commandsSplited, 0); sss != null; sss = Path.extractCmd(commandsSplited, sss.offset())) {
sss = Path.extractCmd(commandsSplited, sss.offset())) {
boolean relative = false; boolean relative = false;
listDot = sss.listElem(); listDot = sss.listElem();
// LOGGER.trace("Find new command : '" + sss.cmd + "'"); // Log.verbose("Find new command : '" + sss.cmd + "'");
// if (listDot != null) { // if (listDot != null) {
// for (int jjj = 0; jjj < listDot.length; jjj++) { // for (int jjj = 0; jjj < listDot.length; jjj++) {
// LOGGER.trace(" -> '" + listDot[jjj] + "'"); // Log.verbose(" -> '" + listDot[jjj] + "'");
// } // }
// } else { // } else {
// LOGGER.trace(" -> no elements"); // Log.verbose(" -> no elements");
// } // }
switch (sss.cmd) { switch (sss.cmd) {
case 'm': // Move to (relative) case 'm': // Move to (relative)
relative = true; relative = true;
case 'M': // Move to (absolute) case 'M': // Move to (absolute)
if (listDot == null) { if (listDot == null) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
if (listDot.length % 2 != 0) { if (listDot.length % 2 != 0) {
LOGGER.warn("the PATH command " + sss.cmd + " must be a multiple of 2"); Log.warning("the PATH command " + sss.cmd + " must be a multiple of 2");
break; break;
} }
// 2 Elements ... // 2 Elements ...
@ -78,145 +74,134 @@ public class Path extends Base {
out.moveTo(relative, new Vector2f(Float.parseFloat(listDot[0]), Float.parseFloat(listDot[1]))); out.moveTo(relative, new Vector2f(Float.parseFloat(listDot[0]), Float.parseFloat(listDot[1])));
} }
for (int iii = 2; iii < listDot.length; iii += 2) { for (int iii = 2; iii < listDot.length; iii += 2) {
out.lineTo(relative, out.lineTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])));
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])));
} }
break; break;
case 'l': // Line to (relative) case 'l': // Line to (relative)
relative = true; relative = true;
case 'L': // Line to (absolute) case 'L': // Line to (absolute)
if (listDot == null) { if (listDot == null) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
if (listDot.length % 2 != 0) { if (listDot.length % 2 != 0) {
LOGGER.warn("the PATH command " + sss.cmd + " must be a multiple of 2"); Log.warning("the PATH command " + sss.cmd + " must be a multiple of 2");
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 2) { for (int iii = 0; iii < listDot.length; iii += 2) {
out.lineTo(relative, out.lineTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])));
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])));
} }
break; break;
case 'v': // Vertical Line to (relative) case 'v': // Vertical Line to (relative)
relative = true; relative = true;
case 'V': // Vertical Line to (absolute) case 'V': // Vertical Line to (absolute)
// 1 Element ... // 1 Element ...
if (listDot == null) { if (listDot == null) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
for (final String element : listDot) { for (int iii = 0; iii < listDot.length; iii++) {
out.lineToV(relative, Float.parseFloat(element)); out.lineToV(relative, Float.parseFloat(listDot[iii]));
} }
break; break;
case 'h': // Horizantal Line to (relative) case 'h': // Horizantal Line to (relative)
relative = true; relative = true;
case 'H': // Horizantal Line to (absolute) case 'H': // Horizantal Line to (absolute)
// 1 Element ... // 1 Element ...
if (listDot == null) { if (listDot == null) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
for (final String element : listDot) { for (int iii = 0; iii < listDot.length; iii++) {
out.lineToH(relative, Float.parseFloat(element)); out.lineToH(relative, Float.parseFloat(listDot[iii]));
} }
break; break;
case 'q': // Quadratic Bezier curve (relative) case 'q': // Quadratic Bezier curve (relative)
relative = true; relative = true;
case 'Q': // Quadratic Bezier curve (absolute) case 'Q': // Quadratic Bezier curve (absolute)
if (listDot == null) { if (listDot == null) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
// 4 Elements ... // 4 Elements ...
if (listDot.length % 4 != 0) { if (listDot.length % 4 != 0) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length + " (must have 4 numbers)");
+ listDot.length + " (must have 4 numbers)");
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 4) { for (int iii = 0; iii < listDot.length; iii += 4) {
out.bezierCurveTo(relative, out.bezierCurveTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])),
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])),
new Vector2f(Float.parseFloat(listDot[iii + 2]), Float.parseFloat(listDot[iii + 3]))); new Vector2f(Float.parseFloat(listDot[iii + 2]), Float.parseFloat(listDot[iii + 3])));
} }
break; break;
case 't': // smooth quadratic Bezier curve to (relative) case 't': // smooth quadratic Bezier curve to (relative)
relative = true; relative = true;
case 'T': // smooth quadratic Bezier curve to (absolute) case 'T': // smooth quadratic Bezier curve to (absolute)
if (listDot == null) { if (listDot == null) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
// 4 Elements ... // 4 Elements ...
if (listDot.length % 2 != 0) { if (listDot.length % 2 != 0) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length + " (must have 2 numbers)");
+ listDot.length + " (must have 2 numbers)");
break; break;
} }
// 2 Elements ... // 2 Elements ...
for (int iii = 0; iii < listDot.length; iii += 2) { for (int iii = 0; iii < listDot.length; iii += 2) {
out.bezierSmoothCurveTo(relative, out.bezierSmoothCurveTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])));
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])));
} }
break; break;
case 'c': // curve to (relative) case 'c': // curve to (relative)
relative = true; relative = true;
case 'C': // curve to (absolute) case 'C': // curve to (absolute)
if (listDot == null) { if (listDot == null) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
// 6 Elements ... // 6 Elements ...
if (listDot.length % 6 != 0) { if (listDot.length % 6 != 0) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length + "(Must be a multiple of 6)");
+ listDot.length + "(Must be a multiple of 6)");
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 6) { for (int iii = 0; iii < listDot.length; iii += 6) {
out.curveTo(relative, out.curveTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])),
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])),
new Vector2f(Float.parseFloat(listDot[iii + 2]), Float.parseFloat(listDot[iii + 3])), new Vector2f(Float.parseFloat(listDot[iii + 2]), Float.parseFloat(listDot[iii + 3])),
new Vector2f(Float.parseFloat(listDot[iii + 4]), Float.parseFloat(listDot[iii + 5]))); new Vector2f(Float.parseFloat(listDot[iii + 4]), Float.parseFloat(listDot[iii + 5])));
} }
break; break;
case 's': // smooth curve to (relative) case 's': // smooth curve to (relative)
relative = true; relative = true;
case 'S': // smooth curve to (absolute) case 'S': // smooth curve to (absolute)
if (listDot == null) { if (listDot == null) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
// 4 Elements ... // 4 Elements ...
if (listDot.length % 4 != 0) { if (listDot.length % 4 != 0) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length + "(Must be a multiple of 4)");
+ listDot.length + "(Must be a multiple of 4)");
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 4) { for (int iii = 0; iii < listDot.length; iii += 4) {
out.smoothCurveTo(relative, out.smoothCurveTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])),
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])),
new Vector2f(Float.parseFloat(listDot[iii + 2]), Float.parseFloat(listDot[iii + 3]))); new Vector2f(Float.parseFloat(listDot[iii + 2]), Float.parseFloat(listDot[iii + 3])));
} }
break; break;
case 'a': // elliptical Arc (relative) case 'a': // elliptical Arc (relative)
relative = true; relative = true;
case 'A': // elliptical Arc (absolute) case 'A': // elliptical Arc (absolute)
if (listDot == null) { if (listDot == null) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
// 4 element ff,ff f i,i ff,ff Elements ... // 4 element ff,ff f i,i ff,ff Elements ...
if (listDot.length % 7 != 0) { if (listDot.length % 7 != 0) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
+ listDot.length);
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 7) { for (int iii = 0; iii < listDot.length; iii += 7) {
@ -228,9 +213,7 @@ public class Path extends Base {
if (Integer.parseInt(listDot[iii + 4]) == 0) { if (Integer.parseInt(listDot[iii + 4]) == 0) {
sweepFlag = false; sweepFlag = false;
} }
out.ellipticTo(relative, out.ellipticTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])), Float.parseFloat(listDot[iii + 2]), largeArcFlag, sweepFlag,
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])),
Float.parseFloat(listDot[iii + 2]), largeArcFlag, sweepFlag,
new Vector2f(Float.parseFloat(listDot[iii + 5]), Float.parseFloat(listDot[iii + 6]))); new Vector2f(Float.parseFloat(listDot[iii + 5]), Float.parseFloat(listDot[iii + 6])));
} }
break; break;
@ -239,69 +222,68 @@ public class Path extends Base {
case 'Z': // closepath (absolute) case 'Z': // closepath (absolute)
// 0 Element ... // 0 Element ...
if (listDot != null) { if (listDot != null) {
LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
+ listDot.length);
break; break;
} }
out.close(relative); out.close(relative);
break; break;
default: default:
LOGGER.error("Unknow error : '" + sss.cmd + "'"); Log.error("Unknow error : '" + sss.cmd + "'");
} }
} }
return out; return out;
} }
//return the next char position ... (after 'X' or NULL) //return the next char position ... (after 'X' or NULL)
private static Command extractCmd(final List<String> input, final int offset) { private static Command extractCmd(final List<String> input, final int offset) {
if (input.size() <= offset) { if (input.size() <= offset) {
// LOGGER.warn("parse command : END"); // Log.warning("parse command : END");
return null; return null;
} }
// LOGGER.warn("parse command : (rest) " + offset); // Log.warning("parse command : (rest) " + offset);
// for (int iii = offset; iii < input.size(); iii++) { // for (int iii = offset; iii < input.size(); iii++) {
// LOGGER.warn(" -[" + iii + "] '" + input.get(iii) + "'"); // Log.warning(" -[" + iii + "] '" + input.get(iii) + "'");
// } // }
if (input.get(offset).length() != 1) { if (input.get(offset).length() != 1) {
LOGGER.error("Error in the SVG Path : '" + input.get(offset) + "' [" + Integer.toString(offset)); Log.error("Error in the SVG Path : '" + input.get(offset) + "' [" + Integer.toString(offset));
return null; return null;
} }
final char cmd = input.get(offset).charAt(0); char cmd = input.get(offset).charAt(0);
if (!((cmd <= 'Z' && cmd >= 'A') || (cmd <= 'z' && cmd >= 'a'))) { if (!((cmd <= 'Z' && cmd >= 'A') || (cmd <= 'z' && cmd >= 'a'))) {
LOGGER.error("Error in the SVG Path : '" + cmd + "' [" + Integer.toString(offset)); Log.error("Error in the SVG Path : '" + cmd + "' [" + Integer.toString(offset));
return null; return null;
} }
//LOGGER.trace("Find command : " + cmd); //Log.verbose("Find command : " + cmd);
if (input.size() == offset) { if (input.size() == offset) {
return new Command(cmd, offset + 1); return new Command(cmd, offset + 1);
} }
int iii; int iii;
for (iii = offset + 1; iii < input.size(); iii++) { for (iii = offset + 1; iii < input.size(); iii++) {
final char startElem = input.get(iii).charAt(0); char startElem = input.get(iii).charAt(0);
if ((startElem <= 'Z' && startElem >= 'A') || (startElem <= 'z' && startElem >= 'a')) { if ((startElem <= 'Z' && startElem >= 'A') || (startElem <= 'z' && startElem >= 'a')) {
// find end of elements // find end of elements
break; break;
} }
} }
final int length = iii - (offset + 1); int length = iii - (offset + 1);
if (length == 0) { if (length == 0) {
return new Command(cmd, null, iii); return new Command(cmd, null, iii);
} }
final String[] outputList = new String[length]; String[] outputList = new String[length];
for (int jjj = 0; jjj < length; jjj++) { for (int jjj = 0; jjj < length; jjj++) {
outputList[jjj] = input.get(offset + 1 + jjj); outputList[jjj] = input.get(offset + 1 + jjj);
} }
return new Command(cmd, outputList, iii); return new Command(cmd, outputList, iii);
} }
static List<String> splitCommand(final String data) { static List<String> splitCommand(final String data) {
final List<String> out = new ArrayList<>(); List<String> out = new ArrayList<>();
final StringBuilder tmpString = new StringBuilder(20); StringBuilder tmpString = new StringBuilder(20);
boolean isNumber = false; boolean isNumber = false;
for (final char it : data.toCharArray()) { for (char it : data.toCharArray()) {
// ',' is here beause some people oprefer the ' ' instead of ',' // ',' is here beause some people oprefer the ' ' instead of ','
if (it == ' ' || it == '\t' || it == '\r' || it == '\n' || it == ',') { if (it == ' ' || it == '\t' || it == '\r' || it == '\n' || it == ',') {
final String elements = tmpString.toString(); String elements = tmpString.toString();
if (!elements.isEmpty()) { if (!elements.isEmpty()) {
out.add(elements); out.add(elements);
} }
@ -318,47 +300,46 @@ public class Path extends Base {
isNumber = false; isNumber = false;
out.add(Character.toString(it)); out.add(Character.toString(it));
} else { } else {
LOGGER.error("Can not parse path : '" + it + "'"); Log.error("Can not parse path : '" + it + "'");
} }
} }
final String elements = tmpString.toString(); String elements = tmpString.toString();
if (!elements.isEmpty()) { if (!elements.isEmpty()) {
out.add(elements); out.add(elements);
} }
return out; return out;
} }
public PathModel listElement = new PathModel(); public PathModel listElement = new PathModel();
public Path(final PaintState parentPaintState) { public Path(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
} }
public Path(final PathModel elements, final PaintState parentPaintState) { public Path(final PathModel elements, final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
this.listElement = elements; this.listElement = elements;
} }
@Override @Override
void display(final int spacing) { void display(final int spacing) {
this.listElement.display(spacing); this.listElement.display(spacing);
} }
@Override @Override
void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
LOGGER.trace(spacingDist(level) + "DRAW esvg::Path"); Log.verbose(spacingDist(level) + "DRAW esvg::Path");
final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans); Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = this.listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), listPoints = this.listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx); //listPoints.applyMatrix(mtx);
final SegmentList listSegmentFill = new SegmentList(); SegmentList listSegmentFill = new SegmentList();
final SegmentList listSegmentStroke = new SegmentList(); SegmentList listSegmentStroke = new SegmentList();
final Weight tmpFill = new Weight(); Weight tmpFill = new Weight();
final Weight tmpStroke = new Weight(); Weight tmpStroke = new Weight();
final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
@ -373,8 +354,7 @@ public class Path extends Base {
} }
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -386,32 +366,27 @@ public class Path extends Base {
//myRenderer.addDebugSegment(listSegmentStroke); //myRenderer.addDebugSegment(listSegmentStroke);
//this.listElement.debugInformation.applyMatrix(mtx); //this.listElement.debugInformation.applyMatrix(mtx);
//myRenderer.addDebugSegment(this.listElement.debugInformation); //myRenderer.addDebugSegment(this.listElement.debugInformation);
} }
@Override @Override
void drawShapePoints( void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
final List<List<Vector2f>> out, Log.verbose(spacingDist(level) + "DRAW Shape esvg::Path");
final int recurtionMax,
final float threshold, Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Path");
final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = this.listElement.generateListPoints(level, recurtionMax, threshold); listPoints = this.listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx); listPoints.applyMatrix(mtx);
for (final List<Point> it : listPoints.data) { for (List<Point> it : listPoints.data) {
final List<Vector2f> listPoint = new ArrayList<>(); List<Vector2f> listPoint = new ArrayList<Vector2f>();
for (final Point itDot : it) { for (Point itDot : it) {
listPoint.add(itDot.pos); listPoint.add(itDot.pos);
} }
out.add(listPoint); out.add(listPoint);
} }
} }
@Override @Override
boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) { boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
if (element == null) { if (element == null) {
@ -419,17 +394,17 @@ public class Path extends Base {
} }
parseTransform(element); parseTransform(element);
parsePaintAttr(element); parsePaintAttr(element);
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
final String elementXML1 = element.getAttribute("d", ""); String elementXML1 = element.getAttribute("d", "");
if (elementXML1.length() == 0) { if (elementXML1.length() == 0) {
LOGGER.warn("path: missing 'd' attribute or empty"); Log.warning("path: missing 'd' attribute or empty");
return false; return false;
} }
this.listElement = Path.createPathModel(elementXML1); this.listElement = Path.createPathModel(elementXML1);
return this.listElement != null; return this.listElement != null;
} }
} }

View File

@ -1,8 +1,5 @@
package org.atriasoft.esvg; package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
@ -13,8 +10,11 @@ import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -23,15 +23,14 @@ import org.slf4j.LoggerFactory;
*/ */
public class Polygon extends Base { public class Polygon extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Polygon.class);
private final List<Vector2f> listPoint = new ArrayList<>(); //!< list of all point of the polygone private final List<Vector2f> listPoint = new ArrayList<>(); //!< list of all point of the polygone
public Polygon(final PaintState parentPaintState) { public Polygon(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
} }
private PathModel createPath() { private PathModel createPath() {
final PathModel out = new PathModel(); PathModel out = new PathModel();
out.moveTo(false, this.listPoint.get(0)); out.moveTo(false, this.listPoint.get(0));
for (int iii = 1; iii < this.listPoint.size(); iii++) { for (int iii = 1; iii < this.listPoint.size(); iii++) {
out.lineTo(false, this.listPoint.get(iii)); out.lineTo(false, this.listPoint.get(iii));
@ -39,29 +38,28 @@ public class Polygon extends Base {
out.close(); out.close();
return out; return out;
} }
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
LOGGER.debug(spacingDist(spacing) + "Polygon nbPoint=" + this.listPoint.size()); Log.debug(spacingDist(spacing) + "Polygon nbPoint=" + this.listPoint.size());
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
LOGGER.trace(spacingDist(level) + "DRAW esvg::Polygon"); Log.verbose(spacingDist(level) + "DRAW esvg::Polygon");
final PathModel listElement = createPath(); PathModel listElement = createPath();
final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans); Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx); //listPoints.applyMatrix(mtx);
final SegmentList listSegmentFill = new SegmentList(); SegmentList listSegmentFill = new SegmentList();
final SegmentList listSegmentStroke = new SegmentList(); SegmentList listSegmentStroke = new SegmentList();
final Weight tmpFill = new Weight(); Weight tmpFill = new Weight();
final Weight tmpStroke = new Weight(); Weight tmpStroke = new Weight();
final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
@ -76,8 +74,7 @@ public class Polygon extends Base {
} }
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -88,29 +85,24 @@ public class Polygon extends Base {
//myRenderer.addDebugSegment(listSegmentFill); //myRenderer.addDebugSegment(listSegmentFill);
//myRenderer.addDebugSegment(listSegmentStroke); //myRenderer.addDebugSegment(listSegmentStroke);
} }
@Override @Override
public void drawShapePoints( public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
final List<List<Vector2f>> out, Log.verbose(spacingDist(level) + "DRAW Shape esvg::Polygon");
final int recurtionMax, PathModel listElement = createPath();
final float threshold, Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Polygon");
final PathModel listElement = createPath();
final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints; PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold); listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx); listPoints.applyMatrix(mtx);
for (final List<Point> it : listPoints.data) { for (List<Point> it : listPoints.data) {
final List<Vector2f> listPoint = new ArrayList<>(); List<Vector2f> listPoint = new ArrayList<>();
for (final Point itDot : it) { for (Point itDot : it) {
listPoint.add(itDot.pos); listPoint.add(itDot.pos);
} }
out.add(listPoint); out.add(listPoint);
} }
} }
@Override @Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) { public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
if (element == null) { if (element == null) {
@ -118,25 +110,25 @@ public class Polygon extends Base {
} }
parseTransform(element); parseTransform(element);
parsePaintAttr(element); parsePaintAttr(element);
LOGGER.trace("parsed P1. trans: " + this.transformMatrix); Log.verbose("parsed P1. trans: " + this.transformMatrix);
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
LOGGER.trace("parsed P2. trans: " + this.transformMatrix); Log.verbose("parsed P2. trans: " + this.transformMatrix);
final String sss1 = element.getAttribute("points", ""); String sss1 = element.getAttribute("points", "");
if (sss1.length() == 0) { if (sss1.length() == 0) {
LOGGER.error("(l "/*+element.Pos()*/ + ") polygon: missing points attribute"); Log.error("(l "/*+element.Pos()*/ + ") polygon: missing points attribute");
return false; return false;
} }
sizeMax.value = Vector2f.ZERO; sizeMax.value = Vector2f.ZERO;
LOGGER.trace("Parse polyline : '" + sss1 + "'"); Log.verbose("Parse polyline : '" + sss1 + "'");
final String[] elems = sss1.split(" "); String[] elems = sss1.split(" ");
for (final String elem : elems) { for (String elem : elems) {
final Vector2f pos = Vector2f.valueOf(elem); Vector2f pos = Vector2f.valueOf(elem);
this.listPoint.add(pos); this.listPoint.add(pos);
sizeMax.value = Vector2f.max(sizeMax.value, pos); sizeMax.value = Vector2f.max(sizeMax.value, pos);
} }

View File

@ -1,8 +1,5 @@
package org.atriasoft.esvg; package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
@ -13,8 +10,11 @@ import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -22,15 +22,14 @@ import org.slf4j.LoggerFactory;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class Polyline extends Base { public class Polyline extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Polyline.class);
private final List<Vector2f> listPoint = new ArrayList<>(); //!< list of all point of the polyline private final List<Vector2f> listPoint = new ArrayList<>(); //!< list of all point of the polyline
public Polyline(final PaintState parentPaintState) { public Polyline(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
} }
private PathModel createPath() { private PathModel createPath() {
final PathModel out = new PathModel(); PathModel out = new PathModel();
out.clear(); out.clear();
out.moveTo(false, this.listPoint.get(0)); out.moveTo(false, this.listPoint.get(0));
for (int iii = 1; iii < this.listPoint.size(); iii++) { for (int iii = 1; iii < this.listPoint.size(); iii++) {
@ -39,29 +38,28 @@ public class Polyline extends Base {
out.stop(); out.stop();
return out; return out;
} }
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
LOGGER.debug(spacingDist(spacing) + "Polyline nbPoint=" + this.listPoint.size()); Log.debug(spacingDist(spacing) + "Polyline nbPoint=" + this.listPoint.size());
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
LOGGER.trace(spacingDist(level) + "DRAW esvg::Polyline"); Log.verbose(spacingDist(level) + "DRAW esvg::Polyline");
final PathModel listElement = createPath(); PathModel listElement = createPath();
final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans); Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints; PointList listPoints;
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx); //listPoints.applyMatrix(mtx);
final SegmentList listSegmentFill = new SegmentList(); SegmentList listSegmentFill = new SegmentList();
final SegmentList listSegmentStroke = new SegmentList(); SegmentList listSegmentStroke = new SegmentList();
final Weight tmpFill = new Weight(); Weight tmpFill = new Weight();
final Weight tmpStroke = new Weight(); Weight tmpStroke = new Weight();
final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
@ -76,8 +74,7 @@ public class Polyline extends Base {
} }
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -88,29 +85,24 @@ public class Polyline extends Base {
//myRenderer.addDebugSegment(listSegmentFill); //myRenderer.addDebugSegment(listSegmentFill);
//myRenderer.addDebugSegment(listSegmentStroke); //myRenderer.addDebugSegment(listSegmentStroke);
} }
@Override @Override
public void drawShapePoints( public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
final List<List<Vector2f>> out, Log.verbose(spacingDist(level) + "DRAW Shape esvg::Polyline");
final int recurtionMax, PathModel listElement = createPath();
final float threshold, Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Polyline");
final PathModel listElement = createPath();
final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints; PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold); listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx); listPoints.applyMatrix(mtx);
for (final List<Point> it : listPoints.data) { for (List<Point> it : listPoints.data) {
final List<Vector2f> listPoint = new ArrayList<>(); List<Vector2f> listPoint = new ArrayList<>();
for (final Point itDot : it) { for (Point itDot : it) {
listPoint.add(itDot.pos); listPoint.add(itDot.pos);
} }
out.add(listPoint); out.add(listPoint);
} }
} }
@Override @Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) { public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
// line must have a minimum size... // line must have a minimum size...
@ -120,20 +112,20 @@ public class Polyline extends Base {
} }
parseTransform(element); parseTransform(element);
parsePaintAttr(element); parsePaintAttr(element);
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
final String sss1 = element.getAttribute("points", ""); String sss1 = element.getAttribute("points", "");
if (sss1.length() == 0) { if (sss1.length() == 0) {
LOGGER.error("polyline: missing points attribute"); Log.error("polyline: missing points attribute");
return false; return false;
} }
sizeMax.value = Vector2f.ZERO; sizeMax.value = Vector2f.ZERO;
LOGGER.trace("Parse polyline : '" + sss1 + "'"); Log.verbose("Parse polyline : '" + sss1 + "'");
final String[] elems = sss1.split(" "); String[] elems = sss1.split(" ");
for (final String elem : elems) { for (String elem : elems) {
final Vector2f pos = Vector2f.valueOf(elem); Vector2f pos = Vector2f.valueOf(elem);
this.listPoint.add(pos); this.listPoint.add(pos);
sizeMax.value = Vector2f.max(sizeMax.value, pos); sizeMax.value = Vector2f.max(sizeMax.value, pos);
} }

View File

@ -3,19 +3,18 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color; import org.atriasoft.etk.Color;
import org.atriasoft.etk.Dimension1f;
import org.atriasoft.etk.Dimension2f;
import org.atriasoft.etk.Distance;
import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode; import org.atriasoft.exml.model.XmlNode;
import org.slf4j.Logger; import org.atriasoft.etk.Dimension;
import org.slf4j.LoggerFactory; import org.atriasoft.etk.Dimension1D;
import org.atriasoft.etk.Distance;
import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -23,67 +22,65 @@ import org.slf4j.LoggerFactory;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class RadialGradient extends Base { public class RadialGradient extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(RadialGradient.class); private Dimension center = new Dimension(new Vector2f(50, 50), Distance.POURCENT); //!< gradient position cx cy
private Dimension2f center = new Dimension2f(new Vector2f(50, 50), Distance.POURCENT); //!< gradient position cx cy
private final List<Pair<Float, Color>> data = new ArrayList<>(); //!< incompatible with href private final List<Pair<Float, Color>> data = new ArrayList<>(); //!< incompatible with href
private Dimension2f focal = new Dimension2f(new Vector2f(50, 50), Distance.POURCENT); //!< gradient Focal fx fy private Dimension focal = new Dimension(new Vector2f(50, 50), Distance.POURCENT); //!< gradient Focal fx fy
private String href = ""; //!< in case of using a single gradient in multiple gradient, the gradient is store in an other element... private String href = ""; //!< in case of using a single gradient in multiple gradient, the gradient is store in an other element...
private Dimension1f radius = new Dimension1f(50, Distance.POURCENT); //!< Radius of the gradient private Dimension1D radius = new Dimension1D(50, Distance.POURCENT); //!< Radius of the gradient
public SpreadMethod spread = SpreadMethod.PAD; public SpreadMethod spread = SpreadMethod.PAD;
public GradientUnits unit = GradientUnits.GRADIENT_UNITS_OBJECT_BOUNDING_BOX; public GradientUnits unit = GradientUnits.GRADIENT_UNITS_OBJECT_BOUNDING_BOX;
public RadialGradient(final PaintState parentPaintState) { public RadialGradient(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
} }
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
LOGGER.debug(spacingDist(spacing) + "RadialGradient center=" + this.center + " focal=" + this.focal + " radius=" Log.debug(spacingDist(spacing) + "RadialGradient center=" + this.center + " focal=" + this.focal + " radius=" + this.radius);
+ this.radius); for (Pair<Float, Color> it : this.data) {
for (final Pair<Float, Color> it : this.data) { Log.debug(spacingDist(spacing + 1) + "STOP: offset=" + it.first + " color=" + it.second);
LOGGER.debug(spacingDist(spacing + 1) + "STOP: offset=" + it.first + " color=" + it.second);
} }
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
LOGGER.trace(spacingDist(level) + "DRAW esvg::RadialGradient"); Log.verbose(spacingDist(level) + "DRAW esvg::RadialGradient");
} }
public Dimension2f getCenter() { public Dimension getCenter() {
return this.center; return this.center;
} }
public List<Pair<Float, Color>> getColors(final EsvgDocument document) { public List<Pair<Float, Color>> getColors(final EsvgDocument document) {
if (this.href.isEmpty()) { if (this.href.isEmpty()) {
return this.data; return this.data;
} }
if (document == null) { if (document == null) {
LOGGER.error("Get null input for document"); Log.error("Get null input for document");
return this.data; return this.data;
} }
final Base base = document.getReference(this.href); Base base = document.getReference(this.href);
if (base == null) { if (base == null) {
LOGGER.error("Can not get base : '" + this.href + "'"); Log.error("Can not get base : '" + this.href + "'");
return this.data; return this.data;
} }
if (base instanceof final RadialGradient gradientR) { if (base instanceof RadialGradient gradientR) {
return gradientR.getColors(document); return gradientR.getColors(document);
} }
if (base instanceof final LinearGradient gradientL) { if (base instanceof LinearGradient gradientL) {
return gradientL.getColors(document); return gradientL.getColors(document);
} }
return this.data; return this.data;
} }
public Dimension2f getFocal() { public Dimension getFocal() {
return this.focal; return this.focal;
} }
public Dimension1f getRadius() { public Dimension1D getRadius() {
return this.radius; return this.radius;
} }
@Override @Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) { public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
// line must have a minimum size... // line must have a minimum size...
@ -91,29 +88,29 @@ public class RadialGradient extends Base {
if (element == null) { if (element == null) {
return false; return false;
} }
// ---------------- get unique ID ---------------- // ---------------- get unique ID ----------------
this.id = element.getAttribute("id", ""); this.id = element.getAttribute("id", "");
//parseTransform(element); //parseTransform(element);
//parsePaintAttr(element); //parsePaintAttr(element);
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
String contentX = element.getAttribute("cx", ""); String contentX = element.getAttribute("cx", "");
String contentY = element.getAttribute("cy", ""); String contentY = element.getAttribute("cy", "");
if (!contentX.isEmpty() && !contentY.isEmpty()) { if (!contentX.isEmpty() && !contentY.isEmpty()) {
this.center = Dimension2f.valueOf(contentX, contentY); this.center = Dimension.valueOf(contentX, contentY);
} }
contentX = element.getAttribute("r", ""); contentX = element.getAttribute("r", "");
if (contentX != "") { if (contentX != "") {
this.radius = Dimension1f.valueOf(contentX); this.radius = Dimension1D.valueOf(contentX);
} }
contentX = element.getAttribute("fx", ""); contentX = element.getAttribute("fx", "");
contentY = element.getAttribute("fy", ""); contentY = element.getAttribute("fy", "");
if (!contentX.isEmpty() && !contentY.isEmpty()) { if (!contentX.isEmpty() && !contentY.isEmpty()) {
this.focal = Dimension2f.valueOf(contentX, contentY); this.focal = Dimension.valueOf(contentX, contentY);
} }
contentX = element.getAttribute("gradientUnits", ""); contentX = element.getAttribute("gradientUnits", "");
if (contentX.equals("userSpaceOnUse")) { if (contentX.equals("userSpaceOnUse")) {
@ -121,8 +118,7 @@ public class RadialGradient extends Base {
} else { } else {
this.unit = GradientUnits.GRADIENT_UNITS_OBJECT_BOUNDING_BOX; this.unit = GradientUnits.GRADIENT_UNITS_OBJECT_BOUNDING_BOX;
if (contentX.length() != 0 && contentX != "objectBoundingBox") { if (contentX.length() != 0 && contentX != "objectBoundingBox") {
LOGGER.error("Parsing error of 'gradientUnits' ==> not suported value: '" + contentX Log.error("Parsing error of 'gradientUnits' ==> not suported value: '" + contentX + "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox");
+ "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox");
} }
} }
contentX = element.getAttribute("spreadMethod", ""); contentX = element.getAttribute("spreadMethod", "");
@ -133,8 +129,7 @@ public class RadialGradient extends Base {
} else { } else {
this.spread = SpreadMethod.PAD; this.spread = SpreadMethod.PAD;
if (contentX.length() != 0 && !contentX.equals("pad")) { if (contentX.length() != 0 && !contentX.equals("pad")) {
LOGGER.error("Parsing error of 'spreadMethod' ==> not suported value: '" + contentX Log.error("Parsing error of 'spreadMethod' ==> not suported value: '" + contentX + "' not in : {reflect/repeate/pad} use pad");
+ "' not in : {reflect/repeate/pad} use pad");
} }
} }
// note: xlink:href is incompatible with subNode "stop" // note: xlink:href is incompatible with subNode "stop"
@ -143,20 +138,19 @@ public class RadialGradient extends Base {
this.href = this.href.substring(1); this.href = this.href.substring(1);
} }
// parse all sub node : // parse all sub node :
for (final XmlNode it : element.getNodes()) { for (XmlNode it : element.getNodes()) {
if (it instanceof final XmlElement child) { if (it instanceof XmlElement child) {
if (child.getValue().equals("stop")) { if (child.getValue().equals("stop")) {
float offset = 100; float offset = 100;
Color stopColor = Color.NONE; Color stopColor = Color.NONE;
String content = child.getAttribute("offset", ""); String content = child.getAttribute("offset", "");
if (content.length() != 0) { if (content.length() != 0) {
final Pair<Float, Distance> tmp = parseLength2(content); Pair<Float, Distance> tmp = parseLength2(content);
if (tmp.second == Distance.PIXEL) { if (tmp.second == Distance.PIXEL) {
// special case ==> all time % then no type define ==> % in [0.0 .. 1.0] // special case ==> all time % then no type define ==> % in [0.0 .. 1.0]
offset = tmp.first * 100.0f; offset = tmp.first * 100.0f;
} else if (tmp.second != Distance.POURCENT) { } else if (tmp.second != Distance.POURCENT) {
LOGGER.error("offset : " + content + " res=" + tmp.first + "," + tmp.second Log.error("offset : " + content + " res=" + tmp.first + "," + tmp.second + " Not support other than pourcent %");
+ " Not support other than pourcent %");
} else { } else {
offset = tmp.first; offset = tmp.first;
} }
@ -164,28 +158,28 @@ public class RadialGradient extends Base {
content = child.getAttribute("stop-color", ""); content = child.getAttribute("stop-color", "");
if (content.length() != 0) { if (content.length() != 0) {
stopColor = parseColor(content).first; stopColor = parseColor(content).first;
LOGGER.trace(" color : \"" + content + "\" == > " + stopColor); Log.verbose(" color : \"" + content + "\" == > " + stopColor);
} }
content = child.getAttribute("stop-opacity", ""); content = child.getAttribute("stop-opacity", "");
if (content.length() != 0) { if (content.length() != 0) {
float opacity = parseLength(content); float opacity = parseLength(content);
opacity = FMath.avg(0.0f, opacity, 1.0f); opacity = FMath.avg(0.0f, opacity, 1.0f);
stopColor = stopColor.withA(opacity); stopColor = stopColor.withA(opacity);
LOGGER.trace(" opacity : '" + content + "' == > " + stopColor); Log.verbose(" opacity : '" + content + "' == > " + stopColor);
} }
this.data.add(new Pair<>(offset, stopColor)); this.data.add(new Pair<Float, Color>(offset, stopColor));
} else { } else {
LOGGER.error("node not suported : '" + child.getValue() + "' must be [stop]"); Log.error("node not suported : '" + child.getValue() + "' must be [stop]");
} }
} }
} }
if (this.data.size() != 0) { if (this.data.size() != 0) {
if (!this.href.isEmpty()) { if (!this.href.isEmpty()) {
LOGGER.error("node can not have an xlink:href element with sub node named: stop ==> removing href"); Log.error("node can not have an xlink:href element with sub node named: stop ==> removing href");
this.href = ""; this.href = "";
} }
} }
return true; return true;
} }
} }

View File

@ -1,20 +1,20 @@
package org.atriasoft.esvg; package org.atriasoft.esvg;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.exml.model.XmlElement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
import org.atriasoft.esvg.render.PointList; import org.atriasoft.esvg.render.PointList;
import org.atriasoft.esvg.render.SegmentList; import org.atriasoft.esvg.render.SegmentList;
import org.atriasoft.esvg.render.Weight; import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -22,31 +22,29 @@ import org.slf4j.LoggerFactory;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class Rectangle extends Base { public class Rectangle extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Rectangle.class);
private Vector2f position = Vector2f.ZERO; //!< position of the rectangle private Vector2f position = Vector2f.ZERO; //!< position of the rectangle
private Vector2f roundedCorner = Vector2f.ZERO; //!< property of the rounded corner private Vector2f roundedCorner = Vector2f.ZERO; //!< property of the rounded corner
private Vector2f size = Vector2f.ZERO; //!< size of the rectangle private Vector2f size = Vector2f.ZERO; //!< size of the rectangle
public Rectangle(final PaintState parentPaintState) { public Rectangle(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
} }
public Rectangle(final Vector2f position, final Vector2f size, final PaintState parentPaintState) { public Rectangle(final Vector2f position, final Vector2f size, final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
this.position = position; this.position = position;
this.size = size; this.size = size;
} }
public Rectangle(final Vector2f position, final Vector2f size, final Vector2f roundedCorner, public Rectangle(final Vector2f position, final Vector2f size, final Vector2f roundedCorner, final PaintState parentPaintState) {
final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
this.position = position; this.position = position;
this.size = size; this.size = size;
this.roundedCorner = roundedCorner; this.roundedCorner = roundedCorner;
} }
private PathModel createPath() { private PathModel createPath() {
final PathModel out = new PathModel(); PathModel out = new PathModel();
out.clear(); out.clear();
if (this.roundedCorner.x() == 0.0f || this.roundedCorner.y() == 0.0f) { if (this.roundedCorner.x() == 0.0f || this.roundedCorner.y() == 0.0f) {
out.moveTo(false, this.position); out.moveTo(false, this.position);
@ -57,50 +55,43 @@ public class Rectangle extends Base {
// Rounded rectangle // Rounded rectangle
out.moveTo(false, this.position.add(this.roundedCorner.x(), 0.0f)); out.moveTo(false, this.position.add(this.roundedCorner.x(), 0.0f));
out.lineToH(true, this.size.x() - this.roundedCorner.x() * 2.0f); out.lineToH(true, this.size.x() - this.roundedCorner.x() * 2.0f);
out.curveTo(true, new Vector2f(this.roundedCorner.x() * Base.kappa90, 0.0f), out.curveTo(true, new Vector2f(this.roundedCorner.x() * Base.kappa90, 0.0f), new Vector2f(this.roundedCorner.x(), this.roundedCorner.y() * (1.0f - Base.kappa90)),
new Vector2f(this.roundedCorner.x(), this.roundedCorner.y() * (1.0f - Base.kappa90)),
new Vector2f(this.roundedCorner.x(), this.roundedCorner.y())); new Vector2f(this.roundedCorner.x(), this.roundedCorner.y()));
out.lineToV(true, this.size.y() - this.roundedCorner.y() * 2.0f); out.lineToV(true, this.size.y() - this.roundedCorner.y() * 2.0f);
out.curveTo(true, new Vector2f(0.0f, this.roundedCorner.y() * Base.kappa90), out.curveTo(true, new Vector2f(0.0f, this.roundedCorner.y() * Base.kappa90), new Vector2f(-this.roundedCorner.x() * (1.0f - Base.kappa90), this.roundedCorner.y()),
new Vector2f(-this.roundedCorner.x() * (1.0f - Base.kappa90), this.roundedCorner.y()),
new Vector2f(-this.roundedCorner.x(), this.roundedCorner.y())); new Vector2f(-this.roundedCorner.x(), this.roundedCorner.y()));
out.lineToH(true, -(this.size.x() - this.roundedCorner.x() * 2.0f)); out.lineToH(true, -(this.size.x() - this.roundedCorner.x() * 2.0f));
out.curveTo(true, new Vector2f(-this.roundedCorner.x() * Base.kappa90, 0.0f), out.curveTo(true, new Vector2f(-this.roundedCorner.x() * Base.kappa90, 0.0f), new Vector2f(-this.roundedCorner.x(), -this.roundedCorner.y() * (1.0f - Base.kappa90)),
new Vector2f(-this.roundedCorner.x(), -this.roundedCorner.y() * (1.0f - Base.kappa90)),
new Vector2f(-this.roundedCorner.x(), -this.roundedCorner.y())); new Vector2f(-this.roundedCorner.x(), -this.roundedCorner.y()));
out.lineToV(true, -(this.size.y() - this.roundedCorner.y() * 2.0f)); out.lineToV(true, -(this.size.y() - this.roundedCorner.y() * 2.0f));
out.curveTo(true, new Vector2f(0.0f, -this.roundedCorner.y() * Base.kappa90), out.curveTo(true, new Vector2f(0.0f, -this.roundedCorner.y() * Base.kappa90), new Vector2f(this.roundedCorner.x() * (1.0f - Base.kappa90), -this.roundedCorner.y()),
new Vector2f(this.roundedCorner.x() * (1.0f - Base.kappa90), -this.roundedCorner.y()),
new Vector2f(this.roundedCorner.x(), -this.roundedCorner.y())); new Vector2f(this.roundedCorner.x(), -this.roundedCorner.y()));
} }
out.close(); out.close();
return out; return out;
} }
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
LOGGER.debug(spacingDist(spacing) + "Rectangle : pos=" + this.position + " size=" + this.size + " corner=" Log.debug(spacingDist(spacing) + "Rectangle : pos=" + this.position + " size=" + this.size + " corner=" + this.roundedCorner);
+ this.roundedCorner);
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
LOGGER.trace(spacingDist(level) + "DRAW esvg::Rectangle: fill=" + this.paint.fill.first + "/" Log.verbose(spacingDist(level) + "DRAW esvg::Rectangle: fill=" + this.paint.fill.first + "/" + this.paint.fill.second + " stroke=" + this.paint.stroke.first + "/" + this.paint.stroke.second);
+ this.paint.fill.second + " stroke=" + this.paint.stroke.first + "/" + this.paint.stroke.second); PathModel listElement = createPath();
final PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix; Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans); mtx = mtx.multiply(basicTrans);
listElement.display(2); listElement.display(2);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx); //listPoints.applyMatrix(mtx);
final SegmentList listSegmentFill = new SegmentList(); SegmentList listSegmentFill = new SegmentList();
final SegmentList listSegmentStroke = new SegmentList(); SegmentList listSegmentStroke = new SegmentList();
final Weight tmpFill = new Weight(); Weight tmpFill = new Weight();
final Weight tmpStroke = new Weight(); Weight tmpStroke = new Weight();
final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
@ -115,8 +106,7 @@ public class Rectangle extends Base {
} }
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -126,32 +116,27 @@ public class Rectangle extends Base {
myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity); myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity);
//myRenderer.addDebugSegment(listSegmentFill); //myRenderer.addDebugSegment(listSegmentFill);
//myRenderer.addDebugSegment(listSegmentStroke) //myRenderer.addDebugSegment(listSegmentStroke)
} }
@Override @Override
public void drawShapePoints( public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
final List<List<Vector2f>> out, Log.verbose(spacingDist(level) + "DRAW Shape esvg::Rectangle");
final int recurtionMax, PathModel listElement = createPath();
final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Rectangle");
final PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix; Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans); mtx = mtx.multiply(basicTrans);
PointList listPoints; PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold); listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx); listPoints.applyMatrix(mtx);
for (final List<Point> it : listPoints.data) { for (List<Point> it : listPoints.data) {
final List<Vector2f> listPoint = new ArrayList<>(); List<Vector2f> listPoint = new ArrayList<>();
for (final Point itDot : it) { for (Point itDot : it) {
listPoint.add(itDot.pos); listPoint.add(itDot.pos);
} }
out.add(listPoint); out.add(listPoint);
} }
} }
@Override @Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) { public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
if (element == null) { if (element == null) {
@ -160,16 +145,16 @@ public class Rectangle extends Base {
this.position = Vector2f.ZERO; this.position = Vector2f.ZERO;
this.size = Vector2f.ZERO; this.size = Vector2f.ZERO;
this.roundedCorner = Vector2f.ZERO; this.roundedCorner = Vector2f.ZERO;
parseTransform(element); parseTransform(element);
parsePaintAttr(element); parsePaintAttr(element);
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
this.position = parseXmlPosition(element); this.position = parseXmlPosition(element);
this.size = parseXmlSize(element); this.size = parseXmlSize(element);
String content = element.getAttribute("rx", ""); String content = element.getAttribute("rx", "");
if (content.length() != 0) { if (content.length() != 0) {
this.roundedCorner = this.roundedCorner.withX(parseLength(content)); this.roundedCorner = this.roundedCorner.withX(parseLength(content));
@ -178,8 +163,7 @@ public class Rectangle extends Base {
if (content.length() != 0) { if (content.length() != 0) {
this.roundedCorner = this.roundedCorner.withY(parseLength(content)); this.roundedCorner = this.roundedCorner.withY(parseLength(content));
} }
sizeMax.value = new Vector2f(this.position.x() + this.size.x() + this.paint.strokeWidth, sizeMax.value = new Vector2f(this.position.x() + this.size.x() + this.paint.strokeWidth, this.position.y() + this.size.y() + this.paint.strokeWidth);
this.position.y() + this.size.y() + this.paint.strokeWidth);
return true; return true;
} }
} }

View File

@ -14,8 +14,6 @@ import org.atriasoft.etk.Color;
import org.atriasoft.etk.math.FMath; import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i; import org.atriasoft.etk.math.Vector2i;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -23,24 +21,23 @@ import org.slf4j.LoggerFactory;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class Renderer { public class Renderer {
private static final Logger LOGGER = LoggerFactory.getLogger(Renderer.class);
private static final boolean DEBUG_MODE = false; private static final boolean DEBUG_MODE = false;
protected ImageFloatRGBA buffer; // for debug protected ImageFloatRGBA buffer; // for debug
protected EsvgDocument document; // for debug protected EsvgDocument document; // for debug
private int factor = 1; private int factor = 1;
protected int interpolationRecurtionMax = 10; protected int interpolationRecurtionMax = 10;
protected float interpolationThreshold = 0.25f; protected float interpolationThreshold = 0.25f;
protected int nbSubScanLine = 8; protected int nbSubScanLine = 8;
protected Vector2i size; protected Vector2i size;
private final boolean visualDebug = false; private final boolean visualDebug = false;
public Renderer(final Vector2i size, final EsvgDocument document) { public Renderer(final Vector2i size, final EsvgDocument document) {
this(size, document, false); this(size, document, false);
} }
public Renderer(final Vector2i size, final EsvgDocument document, final boolean visualDebug) { public Renderer(final Vector2i size, final EsvgDocument document, final boolean visualDebug) {
this.size = size; this.size = size;
this.document = document; this.document = document;
@ -51,38 +48,37 @@ public class Renderer {
} }
setSize(size); setSize(size);
} }
void addDebugSegment(final SegmentList listSegment) { void addDebugSegment(final SegmentList listSegment) {
if (!this.visualDebug) { if (!this.visualDebug) {
return; return;
} }
final Vector2i dynamicSize = this.size.multiply(this.factor); Vector2i dynamicSize = this.size.multiply(this.factor);
// for each lines: // for each lines:
for (int yyy = 0; yyy < dynamicSize.y(); ++yyy) { for (int yyy = 0; yyy < dynamicSize.y(); ++yyy) {
// Reduce the number of lines in the subsampling parsing: // Reduce the number of lines in the subsampling parsing:
final List<Segment> availlableSegmentPixel = new ArrayList<>(); List<Segment> availlableSegmentPixel = new ArrayList<>();
for (final Segment it : listSegment.data) { for (Segment it : listSegment.data) {
if (it.p0.y() * this.factor <= yyy + 1 && it.p1.y() * this.factor >= (yyy)) { if (it.p0.y() * this.factor <= yyy + 1 && it.p1.y() * this.factor >= (yyy)) {
availlableSegmentPixel.add(it); availlableSegmentPixel.add(it);
} }
} }
//find all the segment that cross the middle of the line of the center of the pixel line: //find all the segment that cross the middle of the line of the center of the pixel line:
final float subSamplingCenterPos = yyy + 0.5f; float subSamplingCenterPos = yyy + 0.5f;
final List<Segment> availlableSegment = new ArrayList<>(); List<Segment> availlableSegment = new ArrayList<>();
// find in the subList ... // find in the subList ...
for (final Segment it : availlableSegmentPixel) { for (Segment it : availlableSegmentPixel) {
if (it.p0.y() * this.factor <= subSamplingCenterPos if (it.p0.y() * this.factor <= subSamplingCenterPos && it.p1.y() * this.factor >= subSamplingCenterPos) {
&& it.p1.y() * this.factor >= subSamplingCenterPos) {
availlableSegment.add(it); availlableSegment.add(it);
} }
} }
// x position, angle // x position, angle
for (final Segment it : availlableSegment) { for (Segment it : availlableSegment) {
final Vector2f delta = it.p0.multiply(this.factor).less(it.p1.multiply(this.factor)); Vector2f delta = it.p0.multiply(this.factor).less(it.p1.multiply(this.factor));
// x = coefficent*y+bbb; // x = coefficent*y+bbb;
final float coefficient = delta.x() / delta.y(); float coefficient = delta.x() / delta.y();
final float bbb = it.p0.x() * this.factor - coefficient * it.p0.y() * this.factor; float bbb = it.p0.x() * this.factor - coefficient * it.p0.y() * this.factor;
final float xpos = coefficient * subSamplingCenterPos + bbb; float xpos = coefficient * subSamplingCenterPos + bbb;
if (xpos >= 0 && xpos < dynamicSize.x() && yyy >= 0 && yyy < dynamicSize.y()) { if (xpos >= 0 && xpos < dynamicSize.x() && yyy >= 0 && yyy < dynamicSize.y()) {
if (it.direction == 1.0f) { if (it.direction == 1.0f) {
this.buffer.setColor((int) xpos, yyy, Color.BLUE); this.buffer.setColor((int) xpos, yyy, Color.BLUE);
@ -95,34 +91,32 @@ public class Renderer {
// for each colomn: // for each colomn:
for (int xxx = 0; xxx < dynamicSize.x(); ++xxx) { for (int xxx = 0; xxx < dynamicSize.x(); ++xxx) {
// Reduce the number of lines in the subsampling parsing: // Reduce the number of lines in the subsampling parsing:
final List<Segment> availlableSegmentPixel = new ArrayList<>(); List<Segment> availlableSegmentPixel = new ArrayList<>();
for (final Segment it : listSegment.data) { for (Segment it : listSegment.data) {
if ((it.p0.x() * this.factor <= xxx + 1 && it.p1.x() * this.factor >= (xxx)) if ((it.p0.x() * this.factor <= xxx + 1 && it.p1.x() * this.factor >= (xxx)) || (it.p0.x() * this.factor >= xxx + 1 && it.p1.x() * this.factor <= (xxx))) {
|| (it.p0.x() * this.factor >= xxx + 1 && it.p1.x() * this.factor <= (xxx))) {
availlableSegmentPixel.add(it); availlableSegmentPixel.add(it);
} }
} }
//find all the segment that cross the middle of the line of the center of the pixel line: //find all the segment that cross the middle of the line of the center of the pixel line:
final float subSamplingCenterPos = xxx + 0.5f; float subSamplingCenterPos = xxx + 0.5f;
final List<Segment> availlableSegment = new ArrayList<>(); List<Segment> availlableSegment = new ArrayList<>();
// find in the subList ... // find in the subList ...
for (final Segment it : availlableSegmentPixel) { for (Segment it : availlableSegmentPixel) {
if ((it.p0.x() * this.factor <= subSamplingCenterPos && it.p1.x() * this.factor >= subSamplingCenterPos) if ((it.p0.x() * this.factor <= subSamplingCenterPos && it.p1.x() * this.factor >= subSamplingCenterPos)
|| (it.p0.x() * this.factor >= subSamplingCenterPos || (it.p0.x() * this.factor >= subSamplingCenterPos && it.p1.x() * this.factor <= subSamplingCenterPos)) {
&& it.p1.x() * this.factor <= subSamplingCenterPos)) {
availlableSegment.add(it); availlableSegment.add(it);
} }
} }
// x position, angle // x position, angle
for (final Segment it : availlableSegment) { for (Segment it : availlableSegment) {
final Vector2f delta = it.p0.multiply(this.factor).less(it.p1.multiply(this.factor)); Vector2f delta = it.p0.multiply(this.factor).less(it.p1.multiply(this.factor));
// x = coefficent*y+bbb; // x = coefficent*y+bbb;
if (delta.x() == 0) { if (delta.x() == 0) {
continue; continue;
} }
final float coefficient = delta.y() / delta.x(); float coefficient = delta.y() / delta.x();
final float bbb = it.p0.y() * this.factor - coefficient * it.p0.x() * this.factor; float bbb = it.p0.y() * this.factor - coefficient * it.p0.x() * this.factor;
final float ypos = coefficient * subSamplingCenterPos + bbb; float ypos = coefficient * subSamplingCenterPos + bbb;
if (ypos >= 0 && ypos < dynamicSize.y() && xxx >= 0 && xxx < dynamicSize.y()) { if (ypos >= 0 && ypos < dynamicSize.y() && xxx >= 0 && xxx < dynamicSize.y()) {
if (it.direction == 1.0f) { if (it.direction == 1.0f) {
this.buffer.setColor(xxx, (int) ypos, Color.BLUE); this.buffer.setColor(xxx, (int) ypos, Color.BLUE);
@ -133,31 +127,31 @@ public class Renderer {
} }
} }
} }
ImageFloatRGBA getData() { ImageFloatRGBA getData() {
return this.buffer; return this.buffer;
} }
int getInterpolationRecurtionMax() { int getInterpolationRecurtionMax() {
return this.interpolationRecurtionMax; return this.interpolationRecurtionMax;
} }
float getInterpolationThreshold() { float getInterpolationThreshold() {
return this.interpolationThreshold; return this.interpolationThreshold;
} }
public EsvgDocument getMainDocument() { public EsvgDocument getMainDocument() {
return this.document; return this.document;
} }
int getNumberSubScanLine() { int getNumberSubScanLine() {
return this.nbSubScanLine; return this.nbSubScanLine;
} }
Vector2i getSize() { Vector2i getSize() {
return this.size; return this.size;
} }
protected Color mergeColor(final Color base, final Color integration) { protected Color mergeColor(final Color base, final Color integration) {
/* /*
if (integration.a() < base.a()) { if (integration.a() < base.a()) {
@ -166,7 +160,6 @@ public class Renderer {
base = result; base = result;
} }
*/ */
/*
float r = (integration.a() * integration.r() + base.a() * (1.0f - integration.a()) * base.r()); float r = (integration.a() * integration.r() + base.a() * (1.0f - integration.a()) * base.r());
float g = (integration.a() * integration.g() + base.a() * (1.0f - integration.a()) * base.g()); float g = (integration.a() * integration.g() + base.a() * (1.0f - integration.a()) * base.g());
float b = (integration.a() * integration.b() + base.a() * (1.0f - integration.a()) * base.b()); float b = (integration.a() * integration.b() + base.a() * (1.0f - integration.a()) * base.b());
@ -178,27 +171,9 @@ public class Renderer {
b *= reverse; b *= reverse;
} }
return new Color(r, g, b, a); return new Color(r, g, b, a);
*/
final float a1 = integration.a(); // alpha over
final float a0 = base.a(); // alpha under
final float a = a1 + a0 * (1 - a1);
final float aCalc = a != 0 ? 1 / a : 1;
final float r = (integration.r() * a1 + base.r() * a0 * (1 - a1)) * aCalc;
final float g = (integration.g() * a1 + base.g() * a0 * (1 - a1)) * aCalc;
final float b = (integration.b() * a1 + base.b() * a0 * (1 - a1)) * aCalc;
return new Color(r, g, b, a);
} }
public void print( public void print(final Weight weightFill, final DynamicColor colorFill, final Weight weightStroke, final DynamicColor colorStroke, final float opacity) {
final Weight weightFill,
final DynamicColor colorFill,
final Weight weightStroke,
final DynamicColor colorStroke,
final float opacity) {
final long startTime = System.currentTimeMillis();
if (colorFill != null) { if (colorFill != null) {
//colorFill.setViewPort(Pair<Vector2f, Vector2f>(new Vector2f(0,0), Vector2f(sizeX, sizeY))); //colorFill.setViewPort(Pair<Vector2f, Vector2f>(new Vector2f(0,0), Vector2f(sizeX, sizeY)));
colorFill.generate(this.document); colorFill.generate(this.document);
@ -209,16 +184,14 @@ public class Renderer {
} }
// all together // all together
for (int yyy = 0; yyy < this.size.y(); ++yyy) { for (int yyy = 0; yyy < this.size.y(); ++yyy) {
final long stopTime2 = System.currentTimeMillis();
LOGGER.trace("take time to gnerate: " + (stopTime2 - startTime) + " for " + yyy + "/" + this.size.y());
for (int xxx = 0; xxx < this.size.x(); ++xxx) { for (int xxx = 0; xxx < this.size.x(); ++xxx) {
final Vector2i pos = new Vector2i(xxx, yyy); Vector2i pos = new Vector2i(xxx, yyy);
final float valueFill = weightFill.get(pos); float valueFill = weightFill.get(pos);
final float valueStroke = weightStroke.get(pos); float valueStroke = weightStroke.get(pos);
// calculate merge of stroke and fill value: // calculate merge of stroke and fill value:
Color intermediateColorFill = Color.NONE; Color intermediateColorFill = Color.NONE;
Color intermediateColorStroke = Color.NONE; Color intermediateColorStroke = Color.NONE;
if (colorFill != null && valueFill != 0.0f) { if (colorFill != null && valueFill != 0.0f) {
intermediateColorFill = colorFill.getColor(pos); intermediateColorFill = colorFill.getColor(pos);
@ -233,8 +206,8 @@ public class Renderer {
if (Renderer.DEBUG_MODE) { if (Renderer.DEBUG_MODE) {
for (int deltaY = 0; deltaY < this.factor; deltaY++) { for (int deltaY = 0; deltaY < this.factor; deltaY++) {
for (int deltaX = 0; deltaX < this.factor; deltaX++) { for (int deltaX = 0; deltaX < this.factor; deltaX++) {
final int idx = xxx * this.factor + deltaX; int idx = xxx * this.factor + deltaX;
final int idy = yyy * this.factor + deltaY; int idy = yyy * this.factor + deltaY;
this.buffer.mergeColor(idx, idy, intermediateColor); this.buffer.mergeColor(idx, idy, intermediateColor);
} }
} }
@ -243,23 +216,17 @@ public class Renderer {
} }
} }
} }
if (Renderer.DEBUG_MODE) { if (Renderer.DEBUG_MODE) {
// display the gradient position: // display the gradient position:
if (colorFill instanceof final DynamicColorSpecial tmpColor) { if (colorFill instanceof DynamicColorSpecial tmpColor) {
final SegmentList listSegment = new SegmentList(); SegmentList listSegment = new SegmentList();
// Display bounding box // Display bounding box
listSegment.addSegment(new Point(tmpColor.viewPort.first), listSegment.addSegment(new Point(tmpColor.viewPort.first), new Point(new Vector2f(tmpColor.viewPort.first.x(), tmpColor.viewPort.second.y())), false);
new Point(new Vector2f(tmpColor.viewPort.first.x(), tmpColor.viewPort.second.y())), false); listSegment.addSegment(new Point(new Vector2f(tmpColor.viewPort.first.x(), tmpColor.viewPort.second.y())), new Point(tmpColor.viewPort.second), false);
listSegment.addSegment( listSegment.addSegment(new Point(tmpColor.viewPort.second), new Point(new Vector2f(tmpColor.viewPort.second.x(), tmpColor.viewPort.first.y())), false);
new Point(new Vector2f(tmpColor.viewPort.first.x(), tmpColor.viewPort.second.y())), listSegment.addSegment(new Point(new Vector2f(tmpColor.viewPort.second.x(), tmpColor.viewPort.first.y())), new Point(tmpColor.viewPort.first), false);
new Point(tmpColor.viewPort.second), false);
listSegment.addSegment(new Point(tmpColor.viewPort.second),
new Point(new Vector2f(tmpColor.viewPort.second.x(), tmpColor.viewPort.first.y())), false);
listSegment.addSegment(
new Point(new Vector2f(tmpColor.viewPort.second.x(), tmpColor.viewPort.first.y())),
new Point(tmpColor.viewPort.first), false);
listSegment.applyMatrix(tmpColor.matrix); listSegment.applyMatrix(tmpColor.matrix);
// display the gradient axis // display the gradient axis
listSegment.addSegment(new Point(tmpColor.pos1), new Point(tmpColor.pos2), false); listSegment.addSegment(new Point(tmpColor.pos1), new Point(tmpColor.pos2), false);
@ -272,22 +239,20 @@ public class Renderer {
addDebugSegment(listSegment); addDebugSegment(listSegment);
} }
} }
final long stopTime = System.currentTimeMillis();
LOGGER.trace("take time to generate: " + (stopTime - startTime));
} }
public void setInterpolationRecurtionMax(final int value) { public void setInterpolationRecurtionMax(final int value) {
this.interpolationRecurtionMax = FMath.avg(1, value, 200); this.interpolationRecurtionMax = FMath.avg(1, value, 200);
} }
void setInterpolationThreshold(final float value) { void setInterpolationThreshold(final float value) {
this.interpolationThreshold = FMath.avg(0.0f, value, 20000.0f); this.interpolationThreshold = FMath.avg(0.0f, value, 20000.0f);
} }
void setNumberSubScanLine(final int value) { void setNumberSubScanLine(final int value) {
this.nbSubScanLine = FMath.avg(1, value, 200); this.nbSubScanLine = FMath.avg(1, value, 200);
} }
public void setSize(final Vector2i size) { public void setSize(final Vector2i size) {
this.size = size; this.size = size;
if (Renderer.DEBUG_MODE) { if (Renderer.DEBUG_MODE) {
@ -296,5 +261,5 @@ public class Renderer {
this.buffer = new ImageFloatRGBA(this.size.multiply(this.factor)); this.buffer = new ImageFloatRGBA(this.size.multiply(this.factor));
} }
} }
} }

View File

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.font.Glyph; import org.atriasoft.esvg.font.Glyph;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.PointList; import org.atriasoft.esvg.render.PointList;
@ -15,8 +16,6 @@ import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode; import org.atriasoft.exml.model.XmlNode;
import org.atriasoft.exml.model.XmlText; import org.atriasoft.exml.model.XmlText;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -24,116 +23,98 @@ import org.slf4j.LoggerFactory;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class Text extends Base { public class Text extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Text.class);
private float fontSize = 42; private float fontSize = 42;
private Vector2f position = Vector2f.ZERO; private Vector2f position = Vector2f.ZERO;
private final List<TextSpan> texts = new ArrayList<>(); private final List<TextSpan> texts = new ArrayList<>();
public Text(final PaintState parentPaintState) { public Text(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
} }
public Text(final Vector2f position, final float fontSize, final String decoratedText, public Text(final Vector2f position, final float fontSize, final String decoratedText, final PaintState parentPaintState) {
final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
this.position = position; this.position = position;
this.fontSize = fontSize; this.fontSize = fontSize;
this.texts.add(new TextSpan(position, decoratedText, FontProperty.DEFAULT_FONT.withSize(fontSize), this.texts.add(new TextSpan(position, decoratedText, FontProperty.DEFAULT_FONT, parentPaintState.clone()));
parentPaintState.clone()));
} }
public Text(final Vector2f position, final String fontName, final float fontSize, final String decoratedText,
final PaintState parentPaintState) {
super(parentPaintState);
this.position = position;
this.fontSize = fontSize;
this.texts.add(new TextSpan(position, decoratedText,
FontProperty.DEFAULT_FONT.withSize(fontSize).withFontName(fontName), parentPaintState.clone()));
}
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
LOGGER.trace(spacingDist(spacing) + "Text : "); Log.debug(spacingDist(spacing) + "Text : ");
for (final TextSpan elem : this.texts) { for (TextSpan elem : this.texts) {
LOGGER.debug(spacingDist(spacing + 1) + elem.toString()); Log.debug(spacingDist(spacing + 1) + elem.toString());
} }
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
LOGGER.trace(spacingDist(level) + "DRAW esvg::Text ==> position = " + this.position); Log.warning(spacingDist(level) + "DRAW esvg::Text ==> position = " + this.position);
if (this.texts.size() == 0) { if (this.texts.size() == 0) {
LOGGER.trace(spacingDist(level + 1) + "No text ..."); Log.verbose(spacingDist(level + 1) + "No text ...");
return; return;
} }
final boolean withKerning = true; boolean withKerning = true;
for (final TextSpan elem : this.texts) { for (TextSpan elem : this.texts) {
// get the font or a generic font of the program. // get the font or a generic font of the program.
final EsvgFont font = FontCache.getFont(elem.fontState().fontName(), elem.fontState().bold(), EsvgFont font = FontCache.getFont(elem.fontState().fontName(), elem.fontState().bold(), elem.fontState().italic());
elem.fontState().italic());
if (font == null) { if (font == null) {
LOGGER.error("Can not get the font :" + elem.fontState()); Log.error("Can not get the font :" + elem.fontState());
return; return;
} }
final int realSize = font.calculateFontRealHeight((int) elem.fontState().fontSize()); int realSize = font.calculateFontRealHeight((int) elem.fontState().fontSize());
final float scale = realSize / font.getUnitsPerEm(); float scale = realSize / font.getUnitsPerEm();
//LOGGER.warn("elem.fontState() =" + elem.fontState());
//LOGGER.warn("scale =" + scale + " font size = " + elem.fontState().fontSize() + " realSize=" + realSize);
float offsetWriting = 0; float offsetWriting = 0;
int lastValue = 0; int lastValue = 0;
for (final char uVal : elem.text().toCharArray()) { for (char uVal : elem.text().toCharArray()) {
LOGGER.trace( Log.warning(spacingDist(level) + " elem.position = " + elem.position());
spacingDist(level) + " elem.position = " + elem.position()); Glyph glyph = font.getGlyph(uVal);
final Glyph glyph = font.getGlyph(uVal);
if (glyph == null) { if (glyph == null) {
//lastValue = uVal; lastValue = uVal;
continue; continue;
} }
if (withKerning) { if (withKerning) {
offsetWriting -= glyph.getKerning(lastValue) * scale; //offsetWriting -= glyph.getKerning(lastValue) * scale;
LOGGER.trace(" ==> kerning offset = " + (glyph.getKerning(lastValue) * scale)); Log.info(" ==> kerning offset = " + (glyph.getKerning(lastValue) * scale));
lastValue = uVal; lastValue = uVal;
} }
final float advenceXLocal = glyph.getHorizAdvX() * scale; float advenceXLocal = glyph.getHorizAdvX() * scale;
//Matrix2x3f mtx = this.transformMatrix; //Matrix2x3f mtx = this.transformMatrix;
final Vector2f tranlate = new Vector2f(elem.position().x() + offsetWriting, Vector2f tranlate = new Vector2f(elem.position().x() + offsetWriting, elem.position().y() - font.getDescent() * scale);
elem.position().y() - font.getDescent() * scale); Log.warning("translate : " + tranlate);
LOGGER.trace("translate : " + tranlate); Matrix2x3f translateGlyph = Matrix2x3f.createTranslate(tranlate);
final Matrix2x3f translateGlyph = Matrix2x3f.createTranslate(tranlate); Matrix2x3f scaleGlyph = Matrix2x3f.createScale(new Vector2f(scale, -scale));
final Matrix2x3f scaleGlyph = Matrix2x3f.createScale(new Vector2f(scale, -scale));
//Matrix2x3f translateGlyph = Matrix2x3f.createTranslate(tranlate).multiply(Matrix2x3f.createScale(scale)); //Matrix2x3f translateGlyph = Matrix2x3f.createTranslate(tranlate).multiply(Matrix2x3f.createScale(scale));
//mtx = translateGlyph.multiply(this.transformMatrix); //mtx = translateGlyph.multiply(this.transformMatrix);
//mtx = mtx.multiply(translateGlyph); //mtx = mtx.multiply(translateGlyph);
//mtx = mtx.multiply(basicTrans); //mtx = mtx.multiply(basicTrans);
//Matrix2x3f mtx = this.transformMatrix; //Matrix2x3f mtx = this.transformMatrix;
//mtx = mtx.multiply(basicTrans); //mtx = mtx.multiply(basicTrans);
Matrix2x3f mtx = scaleGlyph; Matrix2x3f mtx = scaleGlyph;
mtx = mtx.multiply(translateGlyph); mtx = mtx.multiply(translateGlyph);
mtx = mtx.multiply(this.transformMatrix); mtx = mtx.multiply(this.transformMatrix);
mtx = mtx.multiply(basicTrans); mtx = mtx.multiply(basicTrans);
//Matrix2x3f mtx = this.transformMatrix; //Matrix2x3f mtx = this.transformMatrix;
//mtx = mtx.multiply(basicTrans); //mtx = mtx.multiply(basicTrans);
final PathModel listElement = glyph.getModel(); PathModel listElement = glyph.getModel();
if (listElement != null) { if (listElement != null) {
//-------------------------------------------------- //--------------------------------------------------
// -- Generate Fill weight // -- Generate Fill weight
//-------------------------------------------------- //--------------------------------------------------
final PointList listPoints = listElement.generateListPoints(level, PointList listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold()); DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); Weight tmpFill = new Weight();
final Weight tmpFill = new Weight();
// Check if we need to display background // Check if we need to display background
if (colorFill != null) { if (colorFill != null) {
final SegmentList listSegmentFill = new SegmentList(); SegmentList listSegmentFill = new SegmentList();
listSegmentFill.createSegmentList(listPoints); listSegmentFill.createSegmentList(listPoints);
colorFill.setViewPort(listSegmentFill.getViewPort()); colorFill.setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx); listSegmentFill.applyMatrix(mtx);
@ -141,38 +122,32 @@ public class Text extends Base {
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentFill); tmpFill.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentFill);
} }
//-------------------------------------------------- //--------------------------------------------------
// -- Generate Stroke weight // -- Generate Stroke weight
//-------------------------------------------------- //--------------------------------------------------
final Weight tmpStroke = new Weight(); Weight tmpStroke = new Weight();
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
if (colorStroke == null) { // check if we need to display stroke:
LOGGER.trace("Color stroke is null: ..."); SegmentList listSegmentStroke = new SegmentList();
} else { listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
// check if we need to display stroke: colorStroke.setViewPort(listSegmentStroke.getViewPort());
final SegmentList listSegmentStroke = new SegmentList(); listSegmentStroke.applyMatrix(mtx);
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit); tmpStroke.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentStroke);
colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(),
listSegmentStroke);
}
} }
// add on images: // add on images:
myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity); myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity);
} }
offsetWriting += advenceXLocal; offsetWriting += advenceXLocal;
//LOGGER.warn("offset X =" + offsetWriting + " + " + advenceXLocal + " " + uVal); Log.error("offset X =" + offsetWriting + " + " + advenceXLocal + " " + uVal);
} }
} }
} }
@Override @Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) { public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
// line must have a minimum size... // line must have a minimum size...
@ -182,37 +157,37 @@ public class Text extends Base {
} }
parseTransform(element); parseTransform(element);
parsePaintAttr(element); parsePaintAttr(element);
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
boolean italic = false; boolean italic = false;
final String fontStyle = element.getAttribute("font-style", "normal"); String fontStyle = element.getAttribute("font-style", "normal");
if ("italic".equals(fontStyle)) { if ("italic".equals(fontStyle)) {
italic = true; italic = true;
} else if ("normal".equals(fontStyle)) { } else if ("normal".equals(fontStyle)) {
italic = false; italic = false;
} else { } else {
LOGGER.error("can not parse font-style='" + fontStyle + "' support ['normal', 'italic']"); Log.error("can not parse font-style='" + fontStyle + "' support ['normal', 'italic']");
} }
boolean bold = false; boolean bold = false;
final String fontWeight = element.getAttribute("font-weight", "normal"); String fontWeight = element.getAttribute("font-weight", "normal");
if ("bold".equals(fontWeight)) { if ("bold".equals(fontWeight)) {
bold = true; bold = true;
} else if ("normal".equals(fontWeight)) { } else if ("normal".equals(fontWeight)) {
bold = false; bold = false;
} else { } else {
LOGGER.error("can not parse font-weight='" + fontWeight + "' support ['normal', 'bold']"); Log.error("can not parse font-weight='" + fontWeight + "' support ['normal', 'bold']");
} }
String fontFamily = element.getAttribute("font-family", "FreeSans"); String fontFamily = element.getAttribute("font-family", "FreeSans");
if (fontStyle.contains(";")) { if (fontStyle.contains(";")) {
fontFamily = fontFamily.split(";")[0]; fontFamily = fontFamily.split(";")[0];
} }
LOGGER.info("Get font family: '" + fontFamily + "'"); Log.info("Get font family: '" + fontFamily + "'");
final float fontSize = parseLength(element.getAttribute("font-size", "50")); float fontSize = parseLength(element.getAttribute("font-size", "50"));
this.position = Vector2f.ZERO; this.position = Vector2f.ZERO;
String content = element.getAttribute("x", ""); String content = element.getAttribute("x", "");
if (content.length() != 0) { if (content.length() != 0) {
this.position = this.position.withX(parseLength(content)); this.position = this.position.withX(parseLength(content));
@ -221,32 +196,31 @@ public class Text extends Base {
if (content.length() != 0) { if (content.length() != 0) {
this.position = this.position.withY(parseLength(content)); this.position = this.position.withY(parseLength(content));
} }
// parse all subElement in the Text <TSPAN/> // parse all subElement in the Text <TSPAN/>
for (final XmlNode elem : element.getNodes()) { for (XmlNode elem : element.getNodes()) {
if (elem instanceof final XmlElement elementSpan && "tspan".equals(elementSpan.getValue())) { if (elem instanceof XmlElement elementSpan && "tspan".equals(elementSpan.getValue())) {
} else if (elem instanceof final XmlText elementText) { } else if (elem instanceof XmlText elementText) {
this.texts.add(new TextSpan(this.position, elementText.getValue(), this.texts.add(new TextSpan(this.position, elementText.getValue(), new FontProperty(fontFamily, fontSize, bold, italic), this.paint.clone()));
new FontProperty(fontFamily, fontSize, bold, italic), this.paint.clone()));
} else { } else {
LOGGER.warn("not managed element : " + elem); Log.warning("not managed element : " + elem);
} }
} }
//sizeMax.value = Vector2f.max(this.startPos, this.stopPos); //sizeMax.value = Vector2f.max(this.startPos, this.stopPos);
return true; return true;
} }
/* /*
public Weight render(final String data, final int fontSize, final boolean withKerning) { public Weight render(final String data, final int fontSize, final boolean withKerning) {
int widthOut = calculateWidth(data, fontSize, withKerning); int widthOut = calculateWidth(data, fontSize, withKerning);
int realSize = calculateFontRealHeight(fontSize); int realSize = calculateFontRealHeight(fontSize);
float scale = realSize / (float) this.unitsPerEm; float scale = realSize / (float) this.unitsPerEm;
Weight weight = new Weight(new Vector2i(widthOut, realSize)); Weight weight = new Weight(new Vector2i(widthOut, realSize));
int offsetWriting = 0; int offsetWriting = 0;
int lastValue = 0; int lastValue = 0;
for (char uVal : data.toCharArray()) { for (char uVal : data.toCharArray()) {
@ -257,12 +231,12 @@ public class Text extends Base {
} }
if (withKerning) { if (withKerning) {
offsetWriting -= glyph.getKerning(lastValue) * scale; offsetWriting -= glyph.getKerning(lastValue) * scale;
LOGGER.info(" ==> kerning offset = " + (glyph.getKerning(lastValue) * scale)); Log.info(" ==> kerning offset = " + (glyph.getKerning(lastValue) * scale));
lastValue = uVal; lastValue = uVal;
} }
float advenceXLocal = glyph.getHorizAdvX() * scale; float advenceXLocal = glyph.getHorizAdvX() * scale;
RenderingConfig config = new RenderingConfig(10, 0.25f, 8); RenderingConfig config = new RenderingConfig(10, 0.25f, 8);
Matrix2x3f transform = Matrix2x3f.createTranslate(new Vector2f(0, -this.descent)).multiply(Matrix2x3f.createScale(scale)); Matrix2x3f transform = Matrix2x3f.createTranslate(new Vector2f(0, -this.descent)).multiply(Matrix2x3f.createScale(scale));
PathModel model = glyph.getModel(); PathModel model = glyph.getModel();
@ -271,7 +245,7 @@ public class Text extends Base {
weight.fusion(redered, offsetWriting, 0); weight.fusion(redered, offsetWriting, 0);
} }
offsetWriting += advenceXLocal; offsetWriting += advenceXLocal;
} }
return weight; return weight;
} }
@ -283,24 +257,7 @@ record FontProperty(
float fontSize, float fontSize,
boolean bold, boolean bold,
boolean italic) { boolean italic) {
public static final FontProperty DEFAULT_FONT = new FontProperty("FreeSans", 15, false, false); public static final FontProperty DEFAULT_FONT = new FontProperty("FreeSans", 15, false, false);
public FontProperty withSize(final float fontSize) {
return new FontProperty(this.fontName, fontSize, this.bold, this.italic);
}
public FontProperty withFontName(final String fontName) {
return new FontProperty(fontName, this.fontSize, this.bold, this.italic);
}
public FontProperty withBold(final boolean bold) {
return new FontProperty(this.fontName, this.fontSize, bold, this.italic);
}
public FontProperty withSize(final boolean italic) {
return new FontProperty(this.fontName, this.fontSize, this.bold, italic);
}
} }
record TextSpan( record TextSpan(

View File

@ -5,80 +5,77 @@ import java.util.List;
import org.atriasoft.esvg.EsvgFont; import org.atriasoft.esvg.EsvgFont;
import org.atriasoft.esvg.Path; import org.atriasoft.esvg.Path;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Glyph { public class Glyph {
private static final boolean LAZY_MODE = true; private static final boolean LAZY_MODE = true;
static final Logger LOGGER = LoggerFactory.getLogger(Glyph.class);
public static Glyph valueOf(final XmlElement element) { public static Glyph valueOf(final XmlElement element) {
return Glyph.valueOf(element, null); return Glyph.valueOf(element, null);
} }
public static Glyph valueOf(final XmlElement element, final EsvgFont font) { public static Glyph valueOf(final XmlElement element, final EsvgFont font) {
if (element == null) { if (element == null) {
return null; return null;
} }
final String name = element.getAttribute("glyph-name", null); String name = element.getAttribute("glyph-name", null);
LOGGER.trace("get glyph name = '" + name + "'"); Log.verbose("get glyph name = '" + name + "'");
final String tmpValue = element.getAttribute("horiz-adv-x", null); String tmpValue = element.getAttribute("horiz-adv-x", null);
int horizAdvX = font == null ? 100 : font.getHorizAdvX(); int horizAdvX = font == null ? 100 : font.getHorizAdvX();
if (tmpValue != null && tmpValue.length() != 0) { if (tmpValue != null && tmpValue.length() != 0) {
horizAdvX = Integer.parseInt(tmpValue); horizAdvX = Integer.parseInt(tmpValue);
} }
LOGGER.trace(" horizAdvX= '" + horizAdvX + "'"); Log.verbose(" horizAdvX= '" + horizAdvX + "'");
final String unicode = element.getAttribute("unicode", null); String unicode = element.getAttribute("unicode", null);
LOGGER.trace(" unicode= '" + unicode + "'"); Log.verbose(" unicode= '" + unicode + "'");
if (unicode == null) { if (unicode == null) {
LOGGER.debug("Not manage glyph : '" + name + "' (missing unicode value)"); Log.debug("Not manage glyph : '" + name + "' (missing unicode value)");
return null; return null;
} }
final String d = element.getAttribute("d", null); String d = element.getAttribute("d", null);
LOGGER.trace(" d= '" + d + "'"); Log.verbose(" d= '" + d + "'");
int unicodeValue = 0; int unicodeValue = 0;
if (unicode.startsWith("&#x") && unicode.endsWith(";")) { if (unicode.startsWith("&#x") && unicode.endsWith(";")) {
final String subElement = unicode.substring(3, unicode.length() - 1); String subElement = unicode.substring(3, unicode.length() - 1);
if (subElement.indexOf("&") != -1) { if (subElement.indexOf("&") != -1) {
LOGGER.debug("not supported glyph concatenarion" + name + " value='" + unicode + "'"); Log.debug("not supported glyph concatenarion" + name + " value='" + unicode + "'");
return null; return null;
} }
unicodeValue = Integer.parseInt(subElement, 16); unicodeValue = Integer.parseInt(subElement, 16);
} else if (unicode.startsWith("&#") && unicode.endsWith(";")) { } else if (unicode.startsWith("&#") && unicode.endsWith(";")) {
final String subElement = unicode.substring(2, unicode.length() - 1); String subElement = unicode.substring(2, unicode.length() - 1);
if (subElement.indexOf("&") != -1) { if (subElement.indexOf("&") != -1) {
LOGGER.debug("not supported glyph concatenarion" + name + " value='" + unicode + "'"); Log.debug("not supported glyph concatenarion" + name + " value='" + unicode + "'");
return null; return null;
} }
unicodeValue = Integer.parseInt(subElement, 16); unicodeValue = Integer.parseInt(subElement, 16);
} else if (unicode.length() != 1) { } else if (unicode.length() != 1) {
LOGGER.debug("not supported glyph concatenarion" + name + " value='" + unicode + "'"); Log.debug("not supported glyph concatenarion" + name + " value='" + unicode + "'");
return null; return null;
} else { } else {
unicodeValue = unicode.charAt(0); unicodeValue = unicode.charAt(0);
} }
LOGGER.trace(" unicodeValue= '" + unicodeValue + "'"); Log.verbose(" unicodeValue= '" + unicodeValue + "'");
final Glyph out = new Glyph(horizAdvX, d, name, unicode, unicodeValue); Glyph out = new Glyph(horizAdvX, d, name, unicode, unicodeValue);
if (!Glyph.LAZY_MODE) { if (!Glyph.LAZY_MODE) {
// when not in lazy mode we force the parsing of the model, this permit to check the whole font... otherwise many font is really big > 8000 glyph, then it is a waste of time... // when not in lazy mode we force the parsing of the model, this permit to check the whole font... otherwise many font is really big > 8000 glyph, then it is a waste of time...
out.getModel(); out.getModel();
} }
return out; return out;
} }
private int horizAdvX; private int horizAdvX;
private List<Kerning> kernings = new ArrayList<>(); private List<Kerning> kernings = new ArrayList<>();
private PathModel model; private PathModel model;
private String name; private String name;
private final String path; private final String path;
private String unicode; private String unicode;
private int unicodeValue; private int unicodeValue;
public Glyph(final int horizAdvX, final PathModel model, final String name, final String unicode, public Glyph(final int horizAdvX, final PathModel model, final String name, final String unicode, final int unicodeValue) {
final int unicodeValue) {
this.horizAdvX = horizAdvX; this.horizAdvX = horizAdvX;
this.model = model; this.model = model;
this.path = null; this.path = null;
@ -86,9 +83,8 @@ public class Glyph {
this.unicode = unicode; this.unicode = unicode;
this.unicodeValue = unicodeValue; this.unicodeValue = unicodeValue;
} }
public Glyph(final int horizAdvX, final String path, final String name, final String unicode, public Glyph(final int horizAdvX, final String path, final String name, final String unicode, final int unicodeValue) {
final int unicodeValue) {
this.horizAdvX = horizAdvX; this.horizAdvX = horizAdvX;
this.model = null; this.model = null;
this.path = path; this.path = path;
@ -96,74 +92,73 @@ public class Glyph {
this.unicode = unicode; this.unicode = unicode;
this.unicodeValue = unicodeValue; this.unicodeValue = unicodeValue;
} }
public void addKerning(final List<Kerning> elementsKerning) { public void addKerning(final List<Kerning> elementsKerning) {
this.kernings.addAll(elementsKerning); this.kernings.addAll(elementsKerning);
} }
public int getHorizAdvX() { public int getHorizAdvX() {
return this.horizAdvX; return this.horizAdvX;
} }
public float getKerning(final int unicodeValue) { public float getKerning(final int unicodeValue) {
if (unicodeValue == 0) { if (unicodeValue == 0) {
return 0.0f; return 0.0f;
} }
for (final Kerning elem : this.kernings) { for (Kerning elem : this.kernings) {
if (elem.unicode() == unicodeValue) { if (elem.unicode() == unicodeValue) {
LOGGER.trace("Get kerning between : '" + (char) this.unicodeValue + "' and '" + (char) unicodeValue Log.verbose("Get kerning between : '" + (char) this.unicodeValue + "' and '" + (char) unicodeValue + "' => " + elem.offset());
+ "' => " + elem.offset());
return elem.offset(); return elem.offset();
} }
} }
return 0; return 0;
} }
public List<Kerning> getKernings() { public List<Kerning> getKernings() {
return this.kernings; return this.kernings;
} }
public PathModel getModel() { public PathModel getModel() {
if (this.model == null && this.path != null) { if (this.model == null && this.path != null) {
this.model = Path.createPathModel(this.path); this.model = Path.createPathModel(this.path);
} }
return this.model; return this.model;
} }
public String getName() { public String getName() {
return this.name; return this.name;
} }
public String getUnicode() { public String getUnicode() {
return this.unicode; return this.unicode;
} }
public Integer getUnicodeValue() { public Integer getUnicodeValue() {
return this.unicodeValue; return this.unicodeValue;
} }
public void setHorizAdvX(final int horizAdvX) { public void setHorizAdvX(final int horizAdvX) {
this.horizAdvX = horizAdvX; this.horizAdvX = horizAdvX;
} }
public void setKernings(final List<Kerning> kernings) { public void setKernings(final List<Kerning> kernings) {
this.kernings = kernings; this.kernings = kernings;
} }
public void setModel(final PathModel model) { public void setModel(final PathModel model) {
this.model = model; this.model = model;
} }
public void setName(final String name) { public void setName(final String name) {
this.name = name; this.name = name;
} }
public void setUnicode(final String unicode) { public void setUnicode(final String unicode) {
this.unicode = unicode; this.unicode = unicode;
} }
public void setUnicodeValue(final int unicodeValue) { public void setUnicodeValue(final int unicodeValue) {
this.unicodeValue = unicodeValue; this.unicodeValue = unicodeValue;
} }
} }

View File

@ -0,0 +1,69 @@
package org.atriasoft.esvg.internal;
import io.scenarium.logger.LogLevel;
import io.scenarium.logger.Logger;
public class Log {
private static final boolean FORCE_ALL = false;
private static final String LIB_NAME = "esvg";
private static final String LIB_NAME_DRAW = Logger.getDrawableName(Log.LIB_NAME);
private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.CRITICAL);
private static final boolean PRINT_DEBUG = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.DEBUG);
private static final boolean PRINT_ERROR = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.ERROR);
private static final boolean PRINT_INFO = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.INFO);
private static final boolean PRINT_PRINT = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.PRINT);
private static final boolean PRINT_TODO = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.TODO);
private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.VERBOSE);
private static final boolean PRINT_WARNING = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.WARNING);
public static void critical(final String data) {
if (Log.PRINT_CRITICAL || Log.FORCE_ALL) {
Logger.critical(Log.LIB_NAME_DRAW, data);
}
}
public static void debug(final String data) {
if (Log.PRINT_DEBUG || Log.FORCE_ALL) {
Logger.debug(Log.LIB_NAME_DRAW, data);
}
}
public static void error(final String data) {
if (Log.PRINT_ERROR || Log.FORCE_ALL) {
Logger.error(Log.LIB_NAME_DRAW, data);
}
}
public static void info(final String data) {
if (Log.PRINT_INFO || Log.FORCE_ALL) {
Logger.info(Log.LIB_NAME_DRAW, data);
}
}
public static void print(final String data) {
if (Log.PRINT_PRINT || Log.FORCE_ALL) {
Logger.print(Log.LIB_NAME_DRAW, data);
}
}
public static void todo(final String data) {
if (Log.PRINT_TODO || Log.FORCE_ALL) {
Logger.todo(Log.LIB_NAME_DRAW, data);
}
}
public static void verbose(final String data) {
if (Log.PRINT_VERBOSE || Log.FORCE_ALL) {
Logger.verbose(Log.LIB_NAME_DRAW, data);
}
}
public static void warning(final String data) {
if (Log.PRINT_WARNING || Log.FORCE_ALL) {
Logger.warning(Log.LIB_NAME_DRAW, data);
}
}
private Log() {}
}

View File

@ -1,13 +1,12 @@
package org.atriasoft.esvg.render; package org.atriasoft.esvg.render;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Color;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i; import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.slf4j.Logger; import org.atriasoft.etk.math.Matrix2x3f;
import org.slf4j.LoggerFactory; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -16,24 +15,22 @@ import org.slf4j.LoggerFactory;
*/ */
public interface DynamicColor { public interface DynamicColor {
static final Logger LOGGER = LoggerFactory.getLogger(DynamicColor.class);
public static DynamicColor createColor(final Pair<Color, String> color, final Matrix2x3f mtx) { public static DynamicColor createColor(final Pair<Color, String> color, final Matrix2x3f mtx) {
// Check if need to create a color: // Check if need to create a color:
if (color.first.a() == 0 && color.second.isEmpty()) { if (color.first.a() == 0 && color.second.isEmpty()) {
return null; return null;
} }
if (color.second.isEmpty()) { if (color.second.isEmpty()) {
LOGGER.trace("use stroke color :" + color); Log.error("use stroke color :" + color);
return new DynamicColorUni(color.first); return new DynamicColorUni(color.first);
} }
return new DynamicColorSpecial(color.second, mtx); return new DynamicColorSpecial(color.second, mtx);
} }
void generate(EsvgDocument document); void generate(EsvgDocument document);
public Color getColor(Vector2i pos); public Color getColor(Vector2i pos);
public void setViewPort(Pair<Vector2f, Vector2f> viewPort); public void setViewPort(Pair<Vector2f, Vector2f> viewPort);
} }

View File

@ -2,69 +2,54 @@ package org.atriasoft.esvg.render;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.SpreadMethod;
import org.atriasoft.esvg.Base; import org.atriasoft.esvg.Base;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.esvg.GradientUnits; import org.atriasoft.esvg.GradientUnits;
import org.atriasoft.esvg.LinearGradient; import org.atriasoft.esvg.LinearGradient;
import org.atriasoft.esvg.RadialGradient; import org.atriasoft.esvg.RadialGradient;
import org.atriasoft.esvg.SpreadMethod; import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color; import org.atriasoft.etk.Color;
import org.atriasoft.etk.Dimension1f; import org.atriasoft.etk.Dimension;
import org.atriasoft.etk.Dimension2f; import org.atriasoft.etk.Dimension1D;
import org.atriasoft.etk.Distance; import org.atriasoft.etk.Distance;
import org.atriasoft.etk.math.FMath; import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i; import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DynamicColorSpecial implements DynamicColor { public class DynamicColorSpecial implements DynamicColor {
static final Logger LOGGER = LoggerFactory.getLogger(DynamicColorSpecial.class); protected static Vector2f getIntersect(final Vector2f point1, final Vector2f vect1, final Vector2f point2, final Vector2f vect2) {
float diviseur = vect1.x() * vect2.y() - vect1.y() * vect2.x();
protected static Vector2f getIntersect(
final Vector2f point1,
final Vector2f vect1,
final Vector2f point2,
final Vector2f vect2) {
final float diviseur = vect1.x() * vect2.y() - vect1.y() * vect2.x();
if (diviseur != 0.0f) { if (diviseur != 0.0f) {
final float mmm = (vect1.x() * point1.y() - vect1.x() * point2.y() - vect1.y() * point1.x() float mmm = (vect1.x() * point1.y() - vect1.x() * point2.y() - vect1.y() * point1.x() + vect1.y() * point2.x()) / diviseur;
+ vect1.y() * point2.x()) / diviseur;
return point2.add(vect2.multiply(mmm)); return point2.add(vect2.multiply(mmm));
} }
LOGGER.error("Get divider / 0.0f"); Log.error("Get divider / 0.0f");
return point2; return point2;
} }
protected static Pair<Vector2f, Vector2f> intersectLineToCircle(final Vector2f pos1, final Vector2f pos2) { protected static Pair<Vector2f, Vector2f> intersectLineToCircle(final Vector2f pos1, final Vector2f pos2) {
return DynamicColorSpecial.intersectLineToCircle(pos1, pos2, Vector2f.ZERO); return DynamicColorSpecial.intersectLineToCircle(pos1, pos2, Vector2f.ZERO);
} }
protected static Pair<Vector2f, Vector2f> intersectLineToCircle( protected static Pair<Vector2f, Vector2f> intersectLineToCircle(final Vector2f pos1, final Vector2f pos2, final Vector2f center) {
final Vector2f pos1,
final Vector2f pos2,
final Vector2f center) {
return DynamicColorSpecial.intersectLineToCircle(pos1, pos2, center, 1.0f); return DynamicColorSpecial.intersectLineToCircle(pos1, pos2, center, 1.0f);
} }
protected static Pair<Vector2f, Vector2f> intersectLineToCircle( protected static Pair<Vector2f, Vector2f> intersectLineToCircle(final Vector2f pos1, final Vector2f pos2, final Vector2f center, final float radius) {
final Vector2f pos1,
final Vector2f pos2,
final Vector2f center,
final float radius) {
Vector2f v1; Vector2f v1;
Vector2f v2; Vector2f v2;
//vector2D from point 1 to point 2 //vector2D from point 1 to point 2
v1 = pos2.less(pos1); v1 = pos2.less(pos1);
//vector2D from point 1 to the circle's center //vector2D from point 1 to the circle's center
v2 = center.less(pos1); v2 = center.less(pos1);
final float dot = v1.dot(v2); float dot = v1.dot(v2);
final Vector2f proj1 = new Vector2f(((dot / (v1.length2())) * v1.x()), ((dot / (v1.length2())) * v1.y())); Vector2f proj1 = new Vector2f(((dot / (v1.length2())) * v1.x()), ((dot / (v1.length2())) * v1.y()));
final Vector2f midpt = pos1.add(proj1); Vector2f midpt = pos1.add(proj1);
float distToCenter = midpt.less(center).length2(); float distToCenter = midpt.less(center).length2();
if (distToCenter > radius * radius) { if (distToCenter > radius * radius) {
return new Pair<>(Vector2f.ZERO, Vector2f.ZERO); return new Pair<>(Vector2f.ZERO, Vector2f.ZERO);
@ -84,7 +69,7 @@ public class DynamicColorSpecial implements DynamicColor {
v1 = v1.multiply(distToIntersection); v1 = v1.multiply(distToIntersection);
return new Pair<>(midpt.add(v1), midpt.less(v1)); return new Pair<>(midpt.add(v1), midpt.less(v1));
} }
public Vector2f axeX; public Vector2f axeX;
public Vector2f axeY; public Vector2f axeY;
public Vector2f baseSize; public Vector2f baseSize;
@ -96,56 +81,56 @@ public class DynamicColorSpecial implements DynamicColor {
public float focalLength; public float focalLength;
public boolean linear; public boolean linear;
public Matrix2x3f matrix; public Matrix2x3f matrix;
public Vector2f pos1; // in radius ==> center public Vector2f pos1; // in radius ==> center
public Vector2f pos2; // in radius ==> radius end position public Vector2f pos2; // in radius ==> radius end position
public SpreadMethod spread; public SpreadMethod spread;
public GradientUnits unit; public GradientUnits unit;
public Pair<Vector2f, Vector2f> viewPort; public Pair<Vector2f, Vector2f> viewPort;
public DynamicColorSpecial(final String link, final Matrix2x3f mtx) { public DynamicColorSpecial(final String link, final Matrix2x3f mtx) {
this.linear = true; this.linear = true;
this.colorName = link; this.colorName = link;
this.matrix = mtx; this.matrix = mtx;
this.viewPort = new Pair<>(Vector2f.MAX_VALUE, Vector2f.MAX_VALUE); this.viewPort = new Pair<>(Vector2f.MAX_VALUE, Vector2f.MAX_VALUE);
} }
@Override @Override
public void generate(final EsvgDocument document) { public void generate(final EsvgDocument document) {
if (document == null) { if (document == null) {
LOGGER.error("Get null input for document"); Log.error("Get null input for document");
} }
final Base base = document.getReference(this.colorName); Base base = document.getReference(this.colorName);
if (base == null) { if (base == null) {
LOGGER.error("Can not get base : '" + this.colorName + "'"); Log.error("Can not get base : '" + this.colorName + "'");
return; return;
} }
// Now we can know if we use linear or radial gradient ... // Now we can know if we use linear or radial gradient ...
if (base instanceof final LinearGradient gradient) { if (base instanceof LinearGradient gradient) {
this.linear = true; this.linear = true;
LOGGER.trace("get for color linear:"); Log.verbose("get for color linear:");
gradient.display(2); gradient.display(2);
this.unit = gradient.unit; this.unit = gradient.unit;
this.spread = gradient.spread; this.spread = gradient.spread;
LOGGER.trace(" viewport = {" + this.viewPort.first + "," + this.viewPort.second + "}"); Log.verbose(" viewport = {" + this.viewPort.first + "," + this.viewPort.second + "}");
final Vector2f size = this.viewPort.second.less(this.viewPort.first); Vector2f size = this.viewPort.second.less(this.viewPort.first);
final Dimension2f dimPos1 = gradient.getPosition1(); Dimension dimPos1 = gradient.getPosition1();
this.pos1 = dimPos1.getPixel(size); this.pos1 = dimPos1.getPixel(size);
if (dimPos1.getType() == Distance.POURCENT) { if (dimPos1.getType() == Distance.POURCENT) {
this.pos1 = this.pos1.add(this.viewPort.first); this.pos1 = this.pos1.add(this.viewPort.first);
} }
final Dimension2f dimPos2 = gradient.getPosition2(); Dimension dimPos2 = gradient.getPosition2();
this.pos2 = dimPos2.getPixel(size); this.pos2 = dimPos2.getPixel(size);
if (dimPos2.getType() == Distance.POURCENT) { if (dimPos2.getType() == Distance.POURCENT) {
this.pos2 = this.pos2.add(this.viewPort.first); this.pos2 = this.pos2.add(this.viewPort.first);
} }
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object.. // in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
final Vector2f delta = this.pos2.less(this.pos1); Vector2f delta = this.pos2.less(this.pos1);
if (delta.x() < 0.0f) { if (delta.x() < 0.0f) {
this.axeX = new Vector2f(-1.0f, 0.0f); this.axeX = new Vector2f(-1.0f, 0.0f);
} else { } else {
@ -162,41 +147,41 @@ public class DynamicColorSpecial implements DynamicColor {
this.axeX = this.matrix.applyScaleRotation(this.axeX); this.axeX = this.matrix.applyScaleRotation(this.axeX);
this.axeY = this.matrix.applyScaleRotation(this.axeY); this.axeY = this.matrix.applyScaleRotation(this.axeY);
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object.. // in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
final Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, this.pos2, this.axeY); Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, this.pos2, this.axeY);
final Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, this.pos2, this.axeX); Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, this.pos2, this.axeX);
this.baseSize = new Vector2f((this.pos1.less(intersecX)).length(), (this.pos1.less(intersecY)).length()); this.baseSize = new Vector2f((this.pos1.less(intersecX)).length(), (this.pos1.less(intersecY)).length());
// get all the colors // get all the colors
this.data = gradient.getColors(document); this.data = gradient.getColors(document);
} else { } else {
this.linear = false; this.linear = false;
if (!(base instanceof final RadialGradient gradient)) { if (!(base instanceof RadialGradient gradient)) {
LOGGER.error("Can not cast in a linear gradient: '" + this.colorName + "' ==> wrong type"); Log.error("Can not cast in a linear gradient: '" + this.colorName + "' ==> wrong type");
return; return;
} }
LOGGER.trace("get for color Radial:"); Log.verbose("get for color Radial:");
gradient.display(2); gradient.display(2);
this.unit = gradient.unit; this.unit = gradient.unit;
this.spread = gradient.spread; this.spread = gradient.spread;
LOGGER.trace(" viewport = {" + this.viewPort.first + "," + this.viewPort.second + "}"); Log.verbose(" viewport = {" + this.viewPort.first + "," + this.viewPort.second + "}");
final Vector2f size = this.viewPort.second.less(this.viewPort.first); Vector2f size = this.viewPort.second.less(this.viewPort.first);
final Dimension2f dimCenter = gradient.getCenter(); Dimension dimCenter = gradient.getCenter();
Vector2f center = dimCenter.getPixel(size); Vector2f center = dimCenter.getPixel(size);
if (dimCenter.getType() == Distance.POURCENT) { if (dimCenter.getType() == Distance.POURCENT) {
center = center.add(this.viewPort.first); center = center.add(this.viewPort.first);
} }
final Dimension2f dimFocal = gradient.getFocal(); Dimension dimFocal = gradient.getFocal();
Vector2f focal = dimFocal.getPixel(size); Vector2f focal = dimFocal.getPixel(size);
if (dimFocal.getType() == Distance.POURCENT) { if (dimFocal.getType() == Distance.POURCENT) {
focal = focal.add(this.viewPort.first); focal = focal.add(this.viewPort.first);
} }
final Dimension1f dimRadius = gradient.getRadius(); Dimension1D dimRadius = gradient.getRadius();
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object).. // in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object)..
if (center == focal) { if (center == focal) {
this.centerIsFocal = true; this.centerIsFocal = true;
this.pos2 = new Vector2f(dimRadius.getPixel(size.x()), dimRadius.getPixel(size.y())); this.pos2 = new Vector2f(dimRadius.getPixel(size.x()), dimRadius.getPixel(size.y()));
this.pos2 = this.pos2.add(center); this.pos2 = this.pos2.add(center);
final Vector2f delta = center.less(this.pos2); Vector2f delta = center.less(this.pos2);
if (delta.x() < 0.0f) { if (delta.x() < 0.0f) {
this.axeX = new Vector2f(-1.0f, 0.0f); this.axeX = new Vector2f(-1.0f, 0.0f);
} else { } else {
@ -212,9 +197,8 @@ public class DynamicColorSpecial implements DynamicColor {
this.centerIsFocal = false; this.centerIsFocal = false;
this.axeX = center.less(focal).safeNormalize(); this.axeX = center.less(focal).safeNormalize();
this.axeY = new Vector2f(this.axeX.y(), -this.axeX.x()); this.axeY = new Vector2f(this.axeX.y(), -this.axeX.x());
this.pos2 = this.axeX.multiply(dimRadius.getPixel(size.x())) this.pos2 = this.axeX.multiply(dimRadius.getPixel(size.x())).add(this.axeY.multiply(dimRadius.getPixel(size.y())));
.add(this.axeY.multiply(dimRadius.getPixel(size.y())));
this.pos2 = this.pos2.add(center); this.pos2 = this.pos2.add(center);
this.pos1 = center; this.pos1 = center;
} }
@ -225,26 +209,25 @@ public class DynamicColorSpecial implements DynamicColor {
this.axeX = this.matrix.applyScaleRotation(this.axeX); this.axeX = this.matrix.applyScaleRotation(this.axeX);
this.axeY = this.matrix.applyScaleRotation(this.axeY); this.axeY = this.matrix.applyScaleRotation(this.axeY);
// in the basic version of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object.. // in the basic version of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
final Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, this.pos2, this.axeY); Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, this.pos2, this.axeY);
final Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, this.pos2, this.axeX); Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, this.pos2, this.axeX);
this.baseSize = new Vector2f((intersecX.less(this.pos1)).length(), (intersecY.less(this.pos1)).length()); this.baseSize = new Vector2f((intersecX.less(this.pos1)).length(), (intersecY.less(this.pos1)).length());
if (!this.centerIsFocal) { if (!this.centerIsFocal) {
this.focalLength = (center.less(this.matrix.multiply(focal))).length(); this.focalLength = (center.less(this.matrix.multiply(focal))).length();
if (this.focalLength >= this.baseSize.x()) { if (this.focalLength >= this.baseSize.x()) {
LOGGER.debug("Change position of the Focal ... ==> set it inside the circle"); Log.debug("Change position of the Focal ... ==> set it inside the circle");
this.focalLength = this.baseSize.x() * 0.999998f; this.focalLength = this.baseSize.x() * 0.999998f;
this.clipOut = true; this.clipOut = true;
} else { } else {
this.clipOut = false; this.clipOut = false;
} }
} }
LOGGER.trace("baseSize=" + this.baseSize + " this.pos1=" + this.pos1 + " dim=" + dimCenter Log.verbose("baseSize=" + this.baseSize + " this.pos1=" + this.pos1 + " dim=" + dimCenter + " this.focal=" + this.focal + " this.pos2=" + this.pos2 + " dim=" + dimRadius);
+ " this.focal=" + this.focal + " this.pos2=" + this.pos2 + " dim=" + dimRadius);
// get all the colors // get all the colors
this.data = gradient.getColors(document); this.data = gradient.getColors(document);
} }
} }
@Override @Override
public Color getColor(final Vector2i pos) { public Color getColor(final Vector2i pos) {
if (this.data.size() < 2) { if (this.data.size() < 2) {
@ -255,17 +238,16 @@ public class DynamicColorSpecial implements DynamicColor {
} }
return getColorRadial(pos); return getColorRadial(pos);
} }
private Color getColorLinear(final Vector2i pos) { private Color getColorLinear(final Vector2i pos) {
float ratio = 0.0f; float ratio = 0.0f;
if (this.unit == GradientUnits.GRADIENT_UNITS_USER_SPACE_ON_USE) { if (this.unit == GradientUnits.GRADIENT_UNITS_USER_SPACE_ON_USE) {
final Vector2f vectorBase = this.pos2.less(this.pos1); Vector2f vectorBase = this.pos2.less(this.pos1);
final Vector2f vectorOrtho = new Vector2f(vectorBase.y(), -vectorBase.x()); Vector2f vectorOrtho = new Vector2f(vectorBase.y(), -vectorBase.x());
final Vector2f intersec = DynamicColorSpecial.getIntersect(this.pos1, vectorBase, Vector2f intersec = DynamicColorSpecial.getIntersect(this.pos1, vectorBase, new Vector2f(pos.x(), pos.y()), vectorOrtho);
new Vector2f(pos.x(), pos.y()), vectorOrtho); float baseSize = vectorBase.length();
final float baseSize = vectorBase.length(); Vector2f vectorBaseDraw = intersec.less(this.pos1);
final Vector2f vectorBaseDraw = intersec.less(this.pos1); float baseDraw = vectorBaseDraw.length();
final float baseDraw = vectorBaseDraw.length();
ratio = baseDraw / baseSize; ratio = baseDraw / baseSize;
switch (this.spread) { switch (this.spread) {
default: default:
@ -285,7 +267,7 @@ public class DynamicColorSpecial implements DynamicColor {
ratio *= -1.0; ratio *= -1.0;
} }
ratio -= ((int) (ratio)); ratio -= ((int) (ratio));
if (ratio < 0.0f) { if (ratio < 0.0f) {
ratio = 1.0f - FMath.abs(ratio); ratio = 1.0f - FMath.abs(ratio);
} }
@ -293,12 +275,10 @@ public class DynamicColorSpecial implements DynamicColor {
} }
} else { } else {
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object.. // in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
final Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, new Vector2f(pos.x(), pos.y()), this.axeY);
new Vector2f(pos.x(), pos.y()), this.axeY); Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, new Vector2f(pos.x(), pos.y()), this.axeX);
final Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, Vector2f vectorBaseDrawX = intersecX.less(this.pos1);
new Vector2f(pos.x(), pos.y()), this.axeX); Vector2f vectorBaseDrawY = intersecY.less(this.pos1);
final Vector2f vectorBaseDrawX = intersecX.less(this.pos1);
final Vector2f vectorBaseDrawY = intersecY.less(this.pos1);
float baseDrawX = vectorBaseDrawX.length(); float baseDrawX = vectorBaseDrawX.length();
float baseDrawY = vectorBaseDrawY.length(); float baseDrawY = vectorBaseDrawY.length();
if (this.axeX.dot(vectorBaseDrawX) < 0) { if (this.axeX.dot(vectorBaseDrawX) < 0) {
@ -309,8 +289,7 @@ public class DynamicColorSpecial implements DynamicColor {
} }
if (this.baseSize.x() + this.baseSize.y() != 0.0f) { if (this.baseSize.x() + this.baseSize.y() != 0.0f) {
if (this.baseSize.x() != 0.0f && this.baseSize.y() != 0.0f) { if (this.baseSize.x() != 0.0f && this.baseSize.y() != 0.0f) {
ratio = (baseDrawX * this.baseSize.y() + baseDrawY * this.baseSize.x()) ratio = (baseDrawX * this.baseSize.y() + baseDrawY * this.baseSize.x()) / (this.baseSize.x() * this.baseSize.y() * 2.0f);
/ (this.baseSize.x() * this.baseSize.y() * 2.0f);
} else if (this.baseSize.x() != 0.0f) { } else if (this.baseSize.x() != 0.0f) {
ratio = baseDrawX / this.baseSize.x(); ratio = baseDrawX / this.baseSize.x();
} else { } else {
@ -349,29 +328,22 @@ public class DynamicColorSpecial implements DynamicColor {
if (ratio <= this.data.get(iii).first * 0.01f) { if (ratio <= this.data.get(iii).first * 0.01f) {
float localRatio = ratio - this.data.get(iii - 1).first * 0.01f; float localRatio = ratio - this.data.get(iii - 1).first * 0.01f;
localRatio = localRatio / ((this.data.get(iii).first - this.data.get(iii - 1).first) * 0.01f); localRatio = localRatio / ((this.data.get(iii).first - this.data.get(iii - 1).first) * 0.01f);
return new Color( return new Color(this.data.get(iii - 1).second.r() * (1.0 - localRatio) + this.data.get(iii).second.r() * localRatio,
this.data.get(iii - 1).second.r() * (1.0 - localRatio) this.data.get(iii - 1).second.g() * (1.0 - localRatio) + this.data.get(iii).second.g() * localRatio,
+ this.data.get(iii).second.r() * localRatio, this.data.get(iii - 1).second.b() * (1.0 - localRatio) + this.data.get(iii).second.b() * localRatio,
this.data.get(iii - 1).second.g() * (1.0 - localRatio) this.data.get(iii - 1).second.a() * (1.0 - localRatio) + this.data.get(iii).second.a() * localRatio);
+ this.data.get(iii).second.g() * localRatio,
this.data.get(iii - 1).second.b() * (1.0 - localRatio)
+ this.data.get(iii).second.b() * localRatio,
this.data.get(iii - 1).second.a() * (1.0 - localRatio)
+ this.data.get(iii).second.a() * localRatio);
} }
} }
return Color.GREEN; return Color.GREEN;
} }
private Color getColorRadial(final Vector2i pos) { private Color getColorRadial(final Vector2i pos) {
float ratio = 0.0f; float ratio = 0.0f;
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object).. // in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object)..
final Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, new Vector2f(pos.x(), pos.y()), this.axeY);
new Vector2f(pos.x(), pos.y()), this.axeY); Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, new Vector2f(pos.x(), pos.y()), this.axeX);
final Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, Vector2f vectorBaseDrawX = intersecX.less(this.pos1);
new Vector2f(pos.x(), pos.y()), this.axeX); Vector2f vectorBaseDrawY = intersecY.less(this.pos1);
final Vector2f vectorBaseDrawX = intersecX.less(this.pos1);
final Vector2f vectorBaseDrawY = intersecY.less(this.pos1);
float baseDrawX = vectorBaseDrawX.length(); float baseDrawX = vectorBaseDrawX.length();
float baseDrawY = vectorBaseDrawY.length(); float baseDrawY = vectorBaseDrawY.length();
// specal case when focal == center (this is faster ...) // specal case when focal == center (this is faster ...)
@ -404,16 +376,15 @@ public class DynamicColorSpecial implements DynamicColor {
if (this.clipOut && baseDrawX <= -1.0f) { if (this.clipOut && baseDrawX <= -1.0f) {
ratio = 1.0f; ratio = 1.0f;
} else { } else {
final float tmpLength = -this.focalLength / this.baseSize.x(); float tmpLength = -this.focalLength / this.baseSize.x();
final Vector2f focalCenter = new Vector2f(tmpLength, 0.0f); Vector2f focalCenter = new Vector2f(tmpLength, 0.0f);
final Vector2f currentPoint = new Vector2f(baseDrawX, baseDrawY); Vector2f currentPoint = new Vector2f(baseDrawX, baseDrawY);
if (focalCenter == currentPoint) { if (focalCenter == currentPoint) {
ratio = 0.0f; ratio = 0.0f;
} else { } else {
final Pair<Vector2f, Vector2f> positions = DynamicColorSpecial.intersectLineToCircle(focalCenter, Pair<Vector2f, Vector2f> positions = DynamicColorSpecial.intersectLineToCircle(focalCenter, currentPoint);
currentPoint); float lenghtBase = currentPoint.less(focalCenter).length();
final float lenghtBase = currentPoint.less(focalCenter).length(); float lenghtBorder1 = positions.first.less(focalCenter).length();
final float lenghtBorder1 = positions.first.less(focalCenter).length();
//float lenghtBorder2 = positions.second.less(focalCenter).length(); //float lenghtBorder2 = positions.second.less(focalCenter).length();
ratio = lenghtBase / lenghtBorder1; ratio = lenghtBase / lenghtBorder1;
} }
@ -447,20 +418,15 @@ public class DynamicColorSpecial implements DynamicColor {
if (ratio <= this.data.get(iii).first * 0.01f) { if (ratio <= this.data.get(iii).first * 0.01f) {
float localRatio = ratio - this.data.get(iii - 1).first * 0.01f; float localRatio = ratio - this.data.get(iii - 1).first * 0.01f;
localRatio = localRatio / ((this.data.get(iii).first - this.data.get(iii - 1).first) * 0.01f); localRatio = localRatio / ((this.data.get(iii).first - this.data.get(iii - 1).first) * 0.01f);
return new Color( return new Color(this.data.get(iii - 1).second.r() * (1.0 - localRatio) + this.data.get(iii).second.r() * localRatio,
this.data.get(iii - 1).second.r() * (1.0 - localRatio) this.data.get(iii - 1).second.g() * (1.0 - localRatio) + this.data.get(iii).second.g() * localRatio,
+ this.data.get(iii).second.r() * localRatio, this.data.get(iii - 1).second.b() * (1.0 - localRatio) + this.data.get(iii).second.b() * localRatio,
this.data.get(iii - 1).second.g() * (1.0 - localRatio) this.data.get(iii - 1).second.a() * (1.0 - localRatio) + this.data.get(iii).second.a() * localRatio);
+ this.data.get(iii).second.g() * localRatio,
this.data.get(iii - 1).second.b() * (1.0 - localRatio)
+ this.data.get(iii).second.b() * localRatio,
this.data.get(iii - 1).second.a() * (1.0 - localRatio)
+ this.data.get(iii).second.a() * localRatio);
} }
} }
return Color.GREEN; return Color.GREEN;
} }
@Override @Override
public void setViewPort(final Pair<Vector2f, Vector2f> viewPort) { public void setViewPort(final Pair<Vector2f, Vector2f> viewPort) {
this.viewPort = viewPort; this.viewPort = viewPort;

View File

@ -5,12 +5,11 @@ import java.util.List;
import org.atriasoft.esvg.CapMode; import org.atriasoft.esvg.CapMode;
import org.atriasoft.esvg.JoinMode; import org.atriasoft.esvg.JoinMode;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.math.FMath; import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Matrix2x3f; import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i; import org.atriasoft.etk.math.Vector2i;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -19,43 +18,31 @@ import org.slf4j.LoggerFactory;
*/ */
public class PathModel { public class PathModel {
static final Logger LOGGER = LoggerFactory.getLogger(PathModel.class); private static void interpolateCubicBezier(final List<Point> listPoint, final int recurtionMax, final float threshold, final Vector2f pos1, final Vector2f pos2, final Vector2f pos3,
final Vector2f pos4, final int level, final PointType type) {
private static void interpolateCubicBezier(
final List<Point> listPoint,
final int recurtionMax,
final float threshold,
final Vector2f pos1,
final Vector2f pos2,
final Vector2f pos3,
final Vector2f pos4,
final int level,
final PointType type) {
if (level > recurtionMax) { if (level > recurtionMax) {
return; return;
} }
final Vector2f pos12 = pos1.add(pos2).multiply(0.5f); Vector2f pos12 = pos1.add(pos2).multiply(0.5f);
final Vector2f pos23 = pos2.add(pos3).multiply(0.5f); Vector2f pos23 = pos2.add(pos3).multiply(0.5f);
final Vector2f pos34 = pos3.add(pos4).multiply(0.5f); Vector2f pos34 = pos3.add(pos4).multiply(0.5f);
final Vector2f delta = pos4.less(pos1); Vector2f delta = pos4.less(pos1);
final float distance2 = Math.abs(((pos2.x() - pos4.x()) * delta.y() - (pos2.y() - pos4.y()) * delta.x())); float distance2 = Math.abs(((pos2.x() - pos4.x()) * delta.y() - (pos2.y() - pos4.y()) * delta.x()));
final float distance3 = Math.abs(((pos3.x() - pos4.x()) * delta.y() - (pos3.y() - pos4.y()) * delta.x())); float distance3 = Math.abs(((pos3.x() - pos4.x()) * delta.y() - (pos3.y() - pos4.y()) * delta.x()));
if ((distance2 + distance3) * (distance2 + distance3) < threshold * delta.length2()) { if ((distance2 + distance3) * (distance2 + distance3) < threshold * delta.length2()) {
listPoint.add(new Point(pos4, type)); listPoint.add(new Point(pos4, type));
return; return;
} }
final Vector2f pos123 = pos12.add(pos23).multiply(0.5f); Vector2f pos123 = pos12.add(pos23).multiply(0.5f);
final Vector2f pos234 = pos23.add(pos34).multiply(0.5f); Vector2f pos234 = pos23.add(pos34).multiply(0.5f);
final Vector2f pos1234 = pos123.add(pos234).multiply(0.5f); Vector2f pos1234 = pos123.add(pos234).multiply(0.5f);
PathModel.interpolateCubicBezier(listPoint, recurtionMax, threshold, pos1, pos12, pos123, pos1234, level + 1, PathModel.interpolateCubicBezier(listPoint, recurtionMax, threshold, pos1, pos12, pos123, pos1234, level + 1, PointType.interpolation);
PointType.interpolation); PathModel.interpolateCubicBezier(listPoint, recurtionMax, threshold, pos1234, pos234, pos34, pos4, level + 1, type);
PathModel.interpolateCubicBezier(listPoint, recurtionMax, threshold, pos1234, pos234, pos34, pos4, level + 1,
type);
} }
/** /**
* add indentation of the string input. * add indentation of the string input.
* @param data String where the indentation is done. * @param data String where the indentation is done.
@ -68,64 +55,60 @@ public class PathModel {
} }
return data.toString(); return data.toString();
} }
private static float vectorAngle(Vector2f uuu, Vector2f vvv) { private static float vectorAngle(Vector2f uuu, Vector2f vvv) {
uuu = uuu.safeNormalize(); uuu = uuu.safeNormalize();
vvv = vvv.safeNormalize(); vvv = vvv.safeNormalize();
return (float) Math.atan2(uuu.cross(vvv), uuu.dot(vvv)); return (float) Math.atan2(uuu.cross(vvv), uuu.dot(vvv));
} }
SegmentList debugInformation; SegmentList debugInformation;
public List<Element> listElement = new ArrayList<>(); public List<Element> listElement = new ArrayList<>();
public PathModel() { public PathModel() {
} }
public void bezierCurveTo(final boolean relative, final Vector2f pos1, final Vector2f pos) { public void bezierCurveTo(final boolean relative, final Vector2f pos1, final Vector2f pos) {
this.listElement.add(new ElementBezierCurveTo(relative, pos1, pos)); this.listElement.add(new ElementBezierCurveTo(relative, pos1, pos));
} }
public void bezierSmoothCurveTo(final boolean relative, final Vector2f pos) { public void bezierSmoothCurveTo(final boolean relative, final Vector2f pos) {
this.listElement.add(new ElementBezierSmoothCurveTo(relative, pos)); this.listElement.add(new ElementBezierSmoothCurveTo(relative, pos));
} }
public void clear() { public void clear() {
this.listElement.clear(); this.listElement.clear();
} }
public void close() { public void close() {
close(false); close(false);
} }
public void close(final boolean relative) { public void close(final boolean relative) {
this.listElement.add(new ElementClose(relative)); this.listElement.add(new ElementClose(relative));
} }
public void curveTo(final boolean relative, final Vector2f pos1, final Vector2f pos2, final Vector2f pos) { public void curveTo(final boolean relative, final Vector2f pos1, final Vector2f pos2, final Vector2f pos) {
this.listElement.add(new ElementCurveTo(relative, pos1, pos2, pos)); this.listElement.add(new ElementCurveTo(relative, pos1, pos2, pos));
} }
public void display(final int spacing) { public void display(final int spacing) {
//LOGGER.trace(PathModel.spacingDist(spacing) + "Path"); Log.warning(PathModel.spacingDist(spacing) + "Path");
for (final Element it : this.listElement) { for (Element it : this.listElement) {
if (it == null) { if (it == null) {
continue; continue;
} }
//LOGGER.trace(PathModel.spacingDist(spacing + 1) + it); Log.warning(PathModel.spacingDist(spacing + 1) + it);
} }
} }
public Weight drawFill( public Weight drawFill(final Vector2i size, final Matrix2x3f basicTrans, final int level, final RenderingConfig config) {
final Vector2i size,
final Matrix2x3f basicTrans,
final int level,
final RenderingConfig config) {
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = generateListPoints(level, config.recurtionMax(), config.interpolationThreshold()); listPoints = generateListPoints(level, config.recurtionMax(), config.interpolationThreshold());
final SegmentList listSegment = new SegmentList(); SegmentList listSegment = new SegmentList();
final Weight weight = new Weight(); Weight weight = new Weight();
// Check if we need to display background // Check if we need to display background
listSegment.createSegmentList(listPoints); listSegment.createSegmentList(listPoints);
listSegment.applyMatrix(basicTrans); listSegment.applyMatrix(basicTrans);
@ -133,17 +116,12 @@ public class PathModel {
weight.generate(size, config.numberOfScanline(), listSegment); weight.generate(size, config.numberOfScanline(), listSegment);
return weight; return weight;
} }
public Weight drawStroke( public Weight drawStroke(final Vector2i size, final Matrix2x3f basicTrans, final int level, final float strokeWidth, final RenderingConfig config) {
final Vector2i size,
final Matrix2x3f basicTrans,
final int level,
final float strokeWidth,
final RenderingConfig config) {
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = generateListPoints(level, config.recurtionMax(), config.interpolationThreshold()); listPoints = generateListPoints(level, config.recurtionMax(), config.interpolationThreshold());
final SegmentList listSegment = new SegmentList(); SegmentList listSegment = new SegmentList();
final Weight weight = new Weight(); Weight weight = new Weight();
// Check if we need to display background // Check if we need to display background
listSegment.createSegmentListStroke(listPoints, strokeWidth, CapMode.BUTT, JoinMode.MITER, 4.0f); listSegment.createSegmentListStroke(listPoints, strokeWidth, CapMode.BUTT, JoinMode.MITER, 4.0f);
listSegment.applyMatrix(basicTrans); listSegment.applyMatrix(basicTrans);
@ -151,43 +129,36 @@ public class PathModel {
weight.generate(size, config.numberOfScanline(), listSegment); weight.generate(size, config.numberOfScanline(), listSegment);
return weight; return weight;
} }
public void ellipticTo( public void ellipticTo(final boolean relative, final Vector2f radius, final float angle, final boolean largeArcFlag, final boolean sweepFlag, final Vector2f pos) {
final boolean relative,
final Vector2f radius,
final float angle,
final boolean largeArcFlag,
final boolean sweepFlag,
final Vector2f pos) {
this.listElement.add(new ElementElliptic(relative, radius, angle, largeArcFlag, sweepFlag, pos)); this.listElement.add(new ElementElliptic(relative, radius, angle, largeArcFlag, sweepFlag, pos));
} }
public PointList generateListPoints(final int level) { public PointList generateListPoints(final int level) {
return generateListPoints(level, 10); return generateListPoints(level, 10);
} }
public PointList generateListPoints(final int level, final int recurtionMax) { public PointList generateListPoints(final int level, final int recurtionMax) {
return generateListPoints(level, recurtionMax, 0.25f); return generateListPoints(level, recurtionMax, 0.25f);
} }
public PointList generateListPoints(final int level, final int recurtionMax, final float threshold) { public PointList generateListPoints(final int level, final int recurtionMax, final float threshold) {
LOGGER.trace(PathModel.spacingDist(level) + "Generate List Points ... from a path"); Log.verbose(PathModel.spacingDist(level) + "Generate List Points ... from a path");
final PointList out = new PointList(); PointList out = new PointList();
List<Point> tmpListPoint = new ArrayList<>(); List<Point> tmpListPoint = new ArrayList<>();
Vector2f lastPosition = Vector2f.ZERO; Vector2f lastPosition = Vector2f.ZERO;
Vector2f lastAngle = Vector2f.ZERO; Vector2f lastAngle = Vector2f.ZERO;
// Foreach element, we move in the path: // Foreach element, we move in the path:
for (final Element it : this.listElement) { for (Element it : this.listElement) {
if (it == null) { if (it == null) {
continue; continue;
} }
LOGGER.trace(PathModel.spacingDist(level + 1) + " Draw : " + it.toString()); Log.verbose(PathModel.spacingDist(level + 1) + " Draw : " + it.toString());
switch (it.getType()) { switch (it.getType()) {
case STOP: case STOP:
if (tmpListPoint.size() != 0) { if (tmpListPoint.size() != 0) {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
LOGGER.warn( Log.warning(PathModel.spacingDist(level + 1) + " Request path stop of not starting path ...");
PathModel.spacingDist(level + 1) + " Request path stop of not starting path ...");
} else { } else {
tmpListPoint.get(tmpListPoint.size() - 1).setEndPath(); tmpListPoint.get(tmpListPoint.size() - 1).setEndPath();
out.addList(tmpListPoint); out.addList(tmpListPoint);
@ -200,17 +171,14 @@ public class PathModel {
case CLOSE: case CLOSE:
if (tmpListPoint.size() != 0) { if (tmpListPoint.size() != 0) {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
LOGGER.warn( Log.warning(PathModel.spacingDist(level + 1) + " Request path close of not starting path ...");
PathModel.spacingDist(level + 1) + " Request path close of not starting path ...");
} else { } else {
// find the previous tart of the path ... // find the previous tart of the path ...
tmpListPoint.get(0).type = PointType.join; tmpListPoint.get(0).type = PointType.join;
// Remove the last point if it is the same position... // Remove the last point if it is the same position...
final Vector2f delta = (tmpListPoint.get(0).pos Vector2f delta = (tmpListPoint.get(0).pos.less(tmpListPoint.get(tmpListPoint.size() - 1).pos)).abs();
.less(tmpListPoint.get(tmpListPoint.size() - 1).pos)).abs();
if (delta.x() <= 0.00001 && delta.y() <= 0.00001) { if (delta.x() <= 0.00001 && delta.y() <= 0.00001) {
LOGGER.trace(" Remove point Z property : " Log.verbose(" Remove point Z property : " + tmpListPoint.get(tmpListPoint.size() - 1).pos + " with delta=" + delta);
+ tmpListPoint.get(tmpListPoint.size() - 1).pos + " with delta=" + delta);
tmpListPoint.remove(tmpListPoint.size() - 1); tmpListPoint.remove(tmpListPoint.size() - 1);
} }
out.addList(tmpListPoint); out.addList(tmpListPoint);
@ -276,15 +244,14 @@ public class PathModel {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join)); tmpListPoint.add(new Point(lastPosition, PointType.join));
} { } {
final Vector2f lastPosStore = lastPosition; Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) { if (!it.getRelative()) {
lastPosition = Vector2f.ZERO; lastPosition = Vector2f.ZERO;
} }
final Vector2f pos1 = lastPosition.add(it.getPos1()); Vector2f pos1 = lastPosition.add(it.getPos1());
final Vector2f pos2 = lastPosition.add(it.getPos2()); Vector2f pos2 = lastPosition.add(it.getPos2());
final Vector2f pos = lastPosition.add(it.getPos()); Vector2f pos = lastPosition.add(it.getPos());
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, pos, 0, PointType.join);
pos, 0, PointType.join);
lastPosition = pos; lastPosition = pos;
lastAngle = pos2; lastAngle = pos2;
} }
@ -294,16 +261,15 @@ public class PathModel {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join)); tmpListPoint.add(new Point(lastPosition, PointType.join));
} { } {
final Vector2f lastPosStore = lastPosition; Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) { if (!it.getRelative()) {
lastPosition = Vector2f.ZERO; lastPosition = Vector2f.ZERO;
} }
final Vector2f pos2 = lastPosition.add(it.getPos2()); Vector2f pos2 = lastPosition.add(it.getPos2());
final Vector2f pos = lastPosition.add(it.getPos()); Vector2f pos = lastPosition.add(it.getPos());
// generate Pos 1 // generate Pos 1
final Vector2f pos1 = lastPosStore.multiply(2.0f).less(lastAngle); Vector2f pos1 = lastPosStore.multiply(2.0f).less(lastAngle);
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, pos, 0, PointType.join);
pos, 0, PointType.join);
lastPosition = pos; lastPosition = pos;
lastAngle = pos2; lastAngle = pos2;
} }
@ -313,17 +279,16 @@ public class PathModel {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join)); tmpListPoint.add(new Point(lastPosition, PointType.join));
} { } {
final Vector2f lastPosStore = lastPosition; Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) { if (!it.getRelative()) {
lastPosition = Vector2f.ZERO; lastPosition = Vector2f.ZERO;
} }
final Vector2f pos = lastPosition.add(it.getPos()); Vector2f pos = lastPosition.add(it.getPos());
final Vector2f tmp1 = lastPosition.add(it.getPos1()); Vector2f tmp1 = lastPosition.add(it.getPos1());
// generate pos1 and pos2 // generate pos1 and pos2
final Vector2f pos1 = lastPosStore.add(tmp1.less(lastPosStore).multiply(0.666666666f)); Vector2f pos1 = lastPosStore.add(tmp1.less(lastPosStore).multiply(0.666666666f));
final Vector2f pos2 = pos.add(tmp1.less(pos).multiply(0.666666666f)); Vector2f pos2 = pos.add(tmp1.less(pos).multiply(0.666666666f));
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, pos, 0, PointType.join);
pos, 0, PointType.join);
lastPosition = pos; lastPosition = pos;
lastAngle = tmp1; lastAngle = tmp1;
} }
@ -333,17 +298,16 @@ public class PathModel {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join)); tmpListPoint.add(new Point(lastPosition, PointType.join));
} { } {
final Vector2f lastPosStore = lastPosition; Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) { if (!it.getRelative()) {
lastPosition = Vector2f.ZERO; lastPosition = Vector2f.ZERO;
} }
final Vector2f pos = lastPosition.add(it.getPos()); Vector2f pos = lastPosition.add(it.getPos());
final Vector2f tmp1 = lastPosStore.multiply(2.0f).less(lastAngle); Vector2f tmp1 = lastPosStore.multiply(2.0f).less(lastAngle);
// generate pos1 and pos2 // generate pos1 and pos2
final Vector2f pos1 = lastPosStore.add(tmp1.less(lastPosStore).multiply(0.666666666f)); Vector2f pos1 = lastPosStore.add(tmp1.less(lastPosStore).multiply(0.666666666f));
final Vector2f pos2 = pos.add(tmp1.less(pos).multiply(0.66666666f)); Vector2f pos2 = pos.add(tmp1.less(pos).multiply(0.66666666f));
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, pos, 0, PointType.join);
pos, 0, PointType.join);
lastPosition = pos; lastPosition = pos;
lastAngle = tmp1; lastAngle = tmp1;
} }
@ -353,28 +317,25 @@ public class PathModel {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join)); tmpListPoint.add(new Point(lastPosition, PointType.join));
} { } {
final ElementElliptic tmpIt = (ElementElliptic) it; ElementElliptic tmpIt = (ElementElliptic) it;
LOGGER.info( Log.todo(PathModel.spacingDist(level + 1) + " Elliptic arc: radius=" + tmpIt.getPos1());
"TODO:" + PathModel.spacingDist(level + 1) + " Elliptic arc: radius=" + tmpIt.getPos1()); Log.todo(PathModel.spacingDist(level + 1) + " angle=" + tmpIt.angle);
LOGGER.info("TODO:" + PathModel.spacingDist(level + 1) + " angle=" + tmpIt.angle); Log.todo(PathModel.spacingDist(level + 1) + " this.largeArcFlag=" + tmpIt.largeArcFlag);
LOGGER.info("TODO:" + PathModel.spacingDist(level + 1) + " this.largeArcFlag=" Log.todo(PathModel.spacingDist(level + 1) + " this.sweepFlag=" + tmpIt.sweepFlag);
+ tmpIt.largeArcFlag);
LOGGER.info("TODO:" + PathModel.spacingDist(level + 1) + " this.sweepFlag=" Vector2f lastPosStore = lastPosition;
+ tmpIt.sweepFlag);
final Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) { if (!it.getRelative()) {
lastPosition = Vector2f.ZERO; lastPosition = Vector2f.ZERO;
} }
final Vector2f pos = lastPosition.add(it.getPos()); Vector2f pos = lastPosition.add(it.getPos());
final float rotationX = tmpIt.angle * ((float) Math.PI / 180.0f); float rotationX = tmpIt.angle * ((float) Math.PI / 180.0f);
Vector2f radius = tmpIt.getPos1(); Vector2f radius = tmpIt.getPos1();
//this.debugInformation.addSegment(lastPosStore, pos); //this.debugInformation.addSegment(lastPosStore, pos);
Vector2f delta = lastPosStore.less(pos); Vector2f delta = lastPosStore.less(pos);
float ddd = delta.length(); float ddd = delta.length();
if (ddd < 1e-6f || radius.x() < 1e-6f || radius.y() < 1e-6f) { if (ddd < 1e-6f || radius.x() < 1e-6f || radius.y() < 1e-6f) {
LOGGER.warn("Degenerate arc in Line"); Log.warning("Degenerate arc in Line");
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join)); tmpListPoint.add(new Point(lastPosition, PointType.join));
} }
@ -384,21 +345,18 @@ public class PathModel {
// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
// procedure describe here : http://www.w3.org/TR/SVG11/implnote.html#ArcConversionCenterToEndpoint // procedure describe here : http://www.w3.org/TR/SVG11/implnote.html#ArcConversionCenterToEndpoint
// Compute delta' // Compute delta'
final Matrix2x3f matrixRotationCenter = Matrix2x3f.createRotate(-rotationX); Matrix2x3f matrixRotationCenter = Matrix2x3f.createRotate(-rotationX);
final Vector2f deltaPrim = matrixRotationCenter.multiply(delta.multiply(0.5f)); Vector2f deltaPrim = matrixRotationCenter.multiply(delta.multiply(0.5f));
ddd = (deltaPrim.x() * deltaPrim.x()) / (radius.x() * radius.x()) ddd = (deltaPrim.x() * deltaPrim.x()) / (radius.x() * radius.x()) + (deltaPrim.y() * deltaPrim.y()) / (radius.y() * radius.y());
+ (deltaPrim.y() * deltaPrim.y()) / (radius.y() * radius.y());
if (ddd > 1.0f) { if (ddd > 1.0f) {
ddd = (float) Math.sqrt(ddd); ddd = (float) Math.sqrt(ddd);
radius = radius.multiply(ddd); radius = radius.multiply(ddd);
} }
// Compute center' // Compute center'
float sss = 0.0f; float sss = 0.0f;
float ssa = radius.x() * radius.x() * radius.y() * radius.y() float ssa = radius.x() * radius.x() * radius.y() * radius.y() - radius.x() * radius.x() * deltaPrim.y() * deltaPrim.y()
- radius.x() * radius.x() * deltaPrim.y() * deltaPrim.y()
- radius.y() * radius.y() * deltaPrim.x() * deltaPrim.x(); - radius.y() * radius.y() * deltaPrim.x() * deltaPrim.x();
final float ssb = radius.x() * radius.x() * deltaPrim.y() * deltaPrim.y() float ssb = radius.x() * radius.x() * deltaPrim.y() * deltaPrim.y() + radius.y() * radius.y() * deltaPrim.x() * deltaPrim.x();
+ radius.y() * radius.y() * deltaPrim.x() * deltaPrim.x();
if (ssa < 0.0f) { if (ssa < 0.0f) {
ssa = 0.0f; ssa = 0.0f;
} }
@ -408,21 +366,19 @@ public class PathModel {
if (tmpIt.largeArcFlag == tmpIt.sweepFlag) { if (tmpIt.largeArcFlag == tmpIt.sweepFlag) {
sss *= -1.0f; sss *= -1.0f;
} }
final Vector2f centerPrime = new Vector2f(sss * radius.x() * deltaPrim.y() / radius.y(), Vector2f centerPrime = new Vector2f(sss * radius.x() * deltaPrim.y() / radius.y(), sss * -radius.y() * deltaPrim.x() / radius.x());
sss * -radius.y() * deltaPrim.x() / radius.x());
// Compute center from center' // Compute center from center'
final Matrix2x3f matrix = Matrix2x3f.createRotate(rotationX); Matrix2x3f matrix = Matrix2x3f.createRotate(rotationX);
final Vector2f center = lastPosStore.multiply(pos).multiply(0.5f) Vector2f center = lastPosStore.multiply(pos).multiply(0.5f).add(matrix.multiply(centerPrime));
.add(matrix.multiply(centerPrime));
//this.debugInformation.addSegment(center-Vector2f(3.0,3.0), center+Vector2f(3.0,3.0)); //this.debugInformation.addSegment(center-Vector2f(3.0,3.0), center+Vector2f(3.0,3.0));
// this.debugInformation.addSegment(center-Vector2f(3.0,-3.0), center+Vector2f(3.0,-3.0)); // this.debugInformation.addSegment(center-Vector2f(3.0,-3.0), center+Vector2f(3.0,-3.0));
// Calculate theta1, and delta theta. // Calculate theta1, and delta theta.
final Vector2f vectorA = deltaPrim.less(centerPrime).devide(radius); Vector2f vectorA = deltaPrim.less(centerPrime).devide(radius);
final Vector2f vectorB = deltaPrim.add(centerPrime).devide(radius.multiply(-1.0f)); Vector2f vectorB = deltaPrim.add(centerPrime).devide(radius.multiply(-1.0f));
//this.debugInformation.addSegment(center, center+vectorA*radius.x()); //this.debugInformation.addSegment(center, center+vectorA*radius.x());
//this.debugInformation.addSegment(center, center+vectorB*radius.y()); //this.debugInformation.addSegment(center, center+vectorB*radius.y());
// Initial angle // Initial angle
final float theta1 = PathModel.vectorAngle(new Vector2f(1.0f, 0.0f), vectorA); float theta1 = PathModel.vectorAngle(new Vector2f(1.0f, 0.0f), vectorA);
// Delta angle // Delta angle
float deltaTheta = PathModel.vectorAngle(vectorA, vectorB); float deltaTheta = PathModel.vectorAngle(vectorA, vectorB);
// special case of invert angle... // special case of invert angle...
@ -441,9 +397,9 @@ public class PathModel {
matrix.translate(center); matrix.translate(center);
// Split arc into max 90 degree segments. // Split arc into max 90 degree segments.
// The loop assumes an iteration per end point (including start and end), this +1. // The loop assumes an iteration per end point (including start and end), this +1.
final int ndivs = (int) (Math.abs(deltaTheta) / ((float) Math.PI * 0.5f)) + 1; int ndivs = (int) (Math.abs(deltaTheta) / ((float) Math.PI * 0.5f)) + 1;
final float hda = (deltaTheta / ndivs) * 0.5f; float hda = (deltaTheta / ndivs) * 0.5f;
float kappa = (float) Math.abs(4.0f / 3.0f * (1.0f - Math.cos(hda)) / Math.sin(hda)); float kappa = (float) Math.abs(4.0f / 3.0f * (1.0f - Math.cos(hda)) / Math.sin(hda));
if (deltaTheta < 0.0f) { if (deltaTheta < 0.0f) {
kappa = -kappa; kappa = -kappa;
@ -451,24 +407,21 @@ public class PathModel {
Vector2f pointPosPrevious = Vector2f.ZERO; Vector2f pointPosPrevious = Vector2f.ZERO;
Vector2f tangentPrevious = Vector2f.ZERO; Vector2f tangentPrevious = Vector2f.ZERO;
for (int iii = 0; iii <= ndivs; ++iii) { for (int iii = 0; iii <= ndivs; ++iii) {
final float a = theta1 + deltaTheta * ((float) iii / (float) ndivs); float a = theta1 + deltaTheta * ((float) iii / (float) ndivs);
delta = new Vector2f(FMath.cos(a), FMath.sin(a)); delta = new Vector2f(FMath.cos(a), FMath.sin(a));
// position // position
final Vector2f pointPos = matrix Vector2f pointPos = matrix.multiply(new Vector2f(delta.x() * radius.x(), delta.y() * radius.y()));
.multiply(new Vector2f(delta.x() * radius.x(), delta.y() * radius.y()));
// tangent // tangent
final Vector2f tangent = matrix.applyScaleRotation( Vector2f tangent = matrix.applyScaleRotation(new Vector2f(-delta.y() * radius.x() * kappa, delta.x() * radius.y() * kappa));
new Vector2f(-delta.y() * radius.x() * kappa, delta.x() * radius.y() * kappa));
if (iii > 0) { if (iii > 0) {
final Vector2f zlastPosStore = lastPosition; Vector2f zlastPosStore = lastPosition;
if (!it.getRelative()) { if (!it.getRelative()) {
lastPosition = Vector2f.ZERO; lastPosition = Vector2f.ZERO;
} }
final Vector2f zpos1 = pointPosPrevious.add(tangentPrevious); Vector2f zpos1 = pointPosPrevious.add(tangentPrevious);
final Vector2f zpos2 = pointPos.less(tangent); Vector2f zpos2 = pointPos.less(tangent);
final Vector2f zpos = pointPos; Vector2f zpos = pointPos;
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, zlastPosStore, PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, zlastPosStore, zpos1, zpos2, zpos, 0, PointType.join);
zpos1, zpos2, zpos, 0, PointType.join);
lastPosition = zpos; lastPosition = zpos;
lastAngle = zpos2; lastAngle = zpos2;
} }
@ -480,13 +433,13 @@ public class PathModel {
} }
break; break;
default: default:
LOGGER.error(PathModel.spacingDist(level + 1) + " Unknow PATH commant (internal error)"); Log.error(PathModel.spacingDist(level + 1) + " Unknow PATH commant (internal error)");
break; break;
} }
} }
// special case : No request end of path ==> open path: // special case : No request end of path ==> open path:
if (tmpListPoint.size() != 0) { if (tmpListPoint.size() != 0) {
LOGGER.trace("Auto-end PATH"); Log.verbose("Auto-end PATH");
tmpListPoint.get(tmpListPoint.size() - 1).setEndPath(); tmpListPoint.get(tmpListPoint.size() - 1).setEndPath();
out.addList(tmpListPoint); out.addList(tmpListPoint);
tmpListPoint = new ArrayList<>(); tmpListPoint = new ArrayList<>();
@ -494,29 +447,29 @@ public class PathModel {
out.display(); out.display();
return out; return out;
} }
public void lineTo(final boolean relative, final Vector2f pos) { public void lineTo(final boolean relative, final Vector2f pos) {
this.listElement.add(new ElementLineTo(relative, pos)); this.listElement.add(new ElementLineTo(relative, pos));
} }
public void lineToH(final boolean relative, final float posX) { public void lineToH(final boolean relative, final float posX) {
this.listElement.add(new ElementLineToH(relative, posX)); this.listElement.add(new ElementLineToH(relative, posX));
} }
public void lineToV(final boolean relative, final float posY) { public void lineToV(final boolean relative, final float posY) {
this.listElement.add(new ElementLineToV(relative, posY)); this.listElement.add(new ElementLineToV(relative, posY));
} }
public void moveTo(final boolean relative, final Vector2f pos) { public void moveTo(final boolean relative, final Vector2f pos) {
this.listElement.add(new ElementMoveTo(relative, pos)); this.listElement.add(new ElementMoveTo(relative, pos));
} }
public void smoothCurveTo(final boolean relative, final Vector2f pos2, final Vector2f pos) { public void smoothCurveTo(final boolean relative, final Vector2f pos2, final Vector2f pos) {
this.listElement.add(new ElementSmoothCurveTo(relative, pos2, pos)); this.listElement.add(new ElementSmoothCurveTo(relative, pos2, pos));
} }
public void stop() { public void stop() {
this.listElement.add(new ElementStop()); this.listElement.add(new ElementStop());
} }
} }

View File

@ -1,8 +1,7 @@
package org.atriasoft.esvg.render; package org.atriasoft.esvg.render;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -11,7 +10,6 @@ import org.slf4j.LoggerFactory;
*/ */
public class Point { public class Point {
static final Logger LOGGER = LoggerFactory.getLogger(Point.class);
public Vector2f delta = Vector2f.ZERO; public Vector2f delta = Vector2f.ZERO;
public float len = 0; public float len = 0;
public Vector2f miterAxe = Vector2f.ZERO; public Vector2f miterAxe = Vector2f.ZERO;
@ -22,35 +20,35 @@ public class Point {
public Vector2f posNext = Vector2f.ZERO; public Vector2f posNext = Vector2f.ZERO;
public Vector2f posPrevious = Vector2f.ZERO; public Vector2f posPrevious = Vector2f.ZERO;
public PointType type; public PointType type;
public Point() { public Point() {
this.pos = Vector2f.ZERO; this.pos = Vector2f.ZERO;
this.type = PointType.join; this.type = PointType.join;
} }
public Point(final Vector2f pos) { public Point(final Vector2f pos) {
this.pos = pos; this.pos = pos;
this.type = PointType.join; this.type = PointType.join;
} }
public Point(final Vector2f pos, final PointType type) { public Point(final Vector2f pos, final PointType type) {
this.pos = pos; this.pos = pos;
this.type = type; this.type = type;
} }
void normalize(final Vector2f nextPoint) { void normalize(final Vector2f nextPoint) {
this.delta = nextPoint.less(this.pos); this.delta = nextPoint.less(this.pos);
this.len = this.delta.length(); this.len = this.delta.length();
} }
void setEndPath() { void setEndPath() {
if (this.type == PointType.interpolation) { if (this.type == PointType.interpolation) {
LOGGER.warn("Request stop path of an interpolate Point"); Log.warning("Request stop path of an interpolate Point");
this.type = PointType.stop; this.type = PointType.stop;
return; return;
} }
if (this.type == PointType.stop) { if (this.type == PointType.stop) {
LOGGER.warn("Request stop path of an STOP Point"); Log.warning("Request stop path of an STOP Point");
return; return;
} }
if (this.type == PointType.start) { if (this.type == PointType.start) {

View File

@ -3,48 +3,46 @@ package org.atriasoft.esvg.render;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.util.Pair;
import org.atriasoft.etk.math.Matrix2x3f; import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PointList { public class PointList {
static final Logger LOGGER = LoggerFactory.getLogger(PointList.class);
public List<List<Point>> data = new ArrayList<>(); public List<List<Point>> data = new ArrayList<>();
public PointList() { public PointList() {
} }
public void addList(final List<Point> list) { public void addList(final List<Point> list) {
this.data.add(list); this.data.add(list);
// TODO : Add a checker of correct list ... // TODO : Add a checker of correct list ...
} }
public void applyMatrix(final Matrix2x3f transformationMatrix) { public void applyMatrix(final Matrix2x3f transformationMatrix) {
for (final List<Point> it : this.data) { for (List<Point> it : this.data) {
for (final Point val : it) { for (Point val : it) {
val.pos = transformationMatrix.multiply(val.pos); val.pos = transformationMatrix.multiply(val.pos);
} }
} }
} }
public void display() { public void display() {
LOGGER.trace(" Display list of points : size=" + this.data.size()); Log.warning(" Display list of points : size=" + this.data.size());
for (final List<Point> it : this.data) { for (List<Point> it : this.data) {
LOGGER.trace(" Find List " + it.size() + " members"); Log.warning(" Find List " + it.size() + " members");
for (int iii = 0; iii < it.size(); ++iii) { for (int iii = 0; iii < it.size(); ++iii) {
final Point elem = it.get(iii); Point elem = it.get(iii);
LOGGER.trace(" [" + iii + "] Find " + elem.type + " " + elem.pos); Log.verbose(" [" + iii + "] Find " + elem.type + " " + elem.pos);
} }
} }
} }
public Pair<Vector2f, Vector2f> getViewPort() { public Pair<Vector2f, Vector2f> getViewPort() {
Pair<Vector2f, Vector2f> out = new Pair<>(Vector2f.MAX_VALUE, Vector2f.MIN_VALUE); Pair<Vector2f, Vector2f> out = new Pair<>(Vector2f.MAX_VALUE, Vector2f.MIN_VALUE);
for (final List<Point> it : this.data) { for (List<Point> it : this.data) {
for (final Point it2 : it) { for (Point it2 : it) {
out = new Pair<>(Vector2f.min(out.first, it2.pos), Vector2f.max(out.second, it2.pos)); out = new Pair<>(Vector2f.min(out.first, it2.pos), Vector2f.max(out.second, it2.pos));
} }
} }

View File

@ -4,15 +4,14 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.CapMode;
import org.atriasoft.esvg.JoinMode;
import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.slf4j.Logger; import org.atriasoft.etk.math.FMath;
import org.slf4j.LoggerFactory; import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.esvg.CapMode;
import org.atriasoft.esvg.JoinMode;
import org.atriasoft.esvg.internal.Log;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -21,20 +20,13 @@ import org.slf4j.LoggerFactory;
*/ */
public class SegmentList { public class SegmentList {
static final Logger LOGGER = LoggerFactory.getLogger(SegmentList.class); static Vector2f getIntersect(final Vector2f point1, final Vector2f vect1, final Vector2f point2, final Vector2f vect2) {
float diviseur = vect1.x() * vect2.y() - vect1.y() * vect2.x();
static Vector2f getIntersect(
final Vector2f point1,
final Vector2f vect1,
final Vector2f point2,
final Vector2f vect2) {
final float diviseur = vect1.x() * vect2.y() - vect1.y() * vect2.x();
if (diviseur != 0.0f) { if (diviseur != 0.0f) {
final float mmm = (vect1.x() * point1.y() - vect1.x() * point2.y() - vect1.y() * point1.x() float mmm = (vect1.x() * point1.y() - vect1.x() * point2.y() - vect1.y() * point1.x() + vect1.y() * point2.x()) / diviseur;
+ vect1.y() * point2.x()) / diviseur;
return point2.add(vect2.multiply(mmm)); return point2.add(vect2.multiply(mmm));
} }
LOGGER.error("Get divider / 0.0f"); Log.error("Get divider / 0.0f");
return point2; return point2;
} }
@ -63,16 +55,16 @@ public class SegmentList {
} }
public void applyMatrix(final Matrix2x3f transformationMatrix) { public void applyMatrix(final Matrix2x3f transformationMatrix) {
for (final Segment it : this.data) { for (Segment it : this.data) {
it.applyMatrix(transformationMatrix); it.applyMatrix(transformationMatrix);
} }
} }
public void clearHorizontals() { public void clearHorizontals() {
// TODO Auto-generated method stub // TODO Auto-generated method stub
final Iterator<Segment> itr = this.data.iterator(); Iterator<Segment> itr = this.data.iterator();
while (itr.hasNext()) { while (itr.hasNext()) {
final Segment seg = itr.next(); Segment seg = itr.next();
if (seg.p0.y() == seg.p1.y()) { if (seg.p0.y() == seg.p1.y()) {
itr.remove(); itr.remove();
} }
@ -80,7 +72,7 @@ public class SegmentList {
} }
public void createSegmentList(final PointList listPoint) { public void createSegmentList(final PointList listPoint) {
for (final List<Point> it : listPoint.data) { for (List<Point> it : listPoint.data) {
// Build Segments // Build Segments
for (int iii = 0, jjj = it.size() - 1; iii < it.size(); jjj = iii++) { for (int iii = 0, jjj = it.size() - 1; iii < it.size(); jjj = iii++) {
addSegment(it.get(jjj), it.get(iii)); addSegment(it.get(jjj), it.get(iii));
@ -88,52 +80,45 @@ public class SegmentList {
} }
} }
public void createSegmentListStroke( public void createSegmentListStroke(final PointList listPoint, final float width, final CapMode cap, final JoinMode join, final float miterLimit) {
final PointList listPoint, for (List<Point> itListPoint : listPoint.data) {
final float width,
final CapMode cap,
final JoinMode join,
final float miterLimit) {
for (final List<Point> itListPoint : listPoint.data) {
// generate for every point all the orthogonal elements // generate for every point all the orthogonal elements
// //
// normal edge * end path // normal edge * end path
// (mitter) * | * * * * * * * * * * * * * * // (mitter) * | * * * * * * * * * * * * * *
// * |<--*----this | * // * |<--*----this | *
// * | * this -->| * // * | * this -->| *
// * * * | * // * * * | *
// * . | . * . . . . . . . . * * // * . | . * . . . . . . . . * *
// * . | . * | * // * . | . * | *
// * A . | . B * | * // * A . | . B * | *
// . * . | * // . * . | *
// . * * . * * * * * * * * * * * * * // . * * . * * * * * * * * * * * * *
// * * // * *
// * * // * *
for (int idPevious = itListPoint.size() - 1, idCurrent = 0, idNext = 1; idCurrent < itListPoint.size(); for (int idPevious = itListPoint.size() - 1, idCurrent = 0, idNext = 1; idCurrent < itListPoint.size(); idPevious = idCurrent++, idNext++) {
idPevious = idCurrent++, idNext++) {
if (idNext == itListPoint.size()) { if (idNext == itListPoint.size()) {
idNext = 0; idNext = 0;
} }
if (itListPoint.get(idCurrent).type == PointType.join if (itListPoint.get(idCurrent).type == PointType.join || itListPoint.get(idCurrent).type == PointType.interpolation) {
|| itListPoint.get(idCurrent).type == PointType.interpolation) {
if (idPevious < 0) { if (idPevious < 0) {
LOGGER.error("an error occure a previous ID is < 0.... "); Log.error("an error occure a previous ID is < 0.... ");
continue; continue;
} }
if (idNext >= itListPoint.size()) { if (idNext >= itListPoint.size()) {
LOGGER.error("an error occure a next ID is >= nbPoint len .... "); Log.error("an error occure a next ID is >= nbPoint len .... ");
continue; continue;
} }
//LOGGER.debug("JOIN : id : prev/curr/next : " + idPevious + "/" + idCurrent + "/" + idNext); //Log.debug("JOIN : id : prev/curr/next : " + idPevious + "/" + idCurrent + "/" + idNext);
//LOGGER.debug("JOIN : val : prev/curr/next : " + itListPoint.get(idPevious).pos + "/" + itListPoint.get(idCurrent).pos + "/" + itListPoint.get(idNext).pos); //Log.debug("JOIN : val : prev/curr/next : " + itListPoint.get(idPevious).pos + "/" + itListPoint.get(idCurrent).pos + "/" + itListPoint.get(idNext).pos);
Vector2f vecA = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos); Vector2f vecA = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos);
//LOGGER.debug("JOIN : vecA : " + vecA); //Log.debug("JOIN : vecA : " + vecA);
vecA = vecA.safeNormalize(); vecA = vecA.safeNormalize();
Vector2f vecB = itListPoint.get(idNext).pos.less(itListPoint.get(idCurrent).pos); Vector2f vecB = itListPoint.get(idNext).pos.less(itListPoint.get(idCurrent).pos);
//LOGGER.debug("JOIN : vecB : " + vecB); //Log.debug("JOIN : vecB : " + vecB);
vecB = vecB.safeNormalize(); vecB = vecB.safeNormalize();
Vector2f vecC = vecA.less(vecB); Vector2f vecC = vecA.less(vecB);
//LOGGER.debug("JOIN : vecC : " + vecC); //Log.debug("JOIN : vecC : " + vecC);
if (vecC.isZero()) { if (vecC.isZero()) {
// special case: 1 line ... // special case: 1 line ...
itListPoint.get(idCurrent).miterAxe = new Vector2f(vecA.y(), vecA.x()); itListPoint.get(idCurrent).miterAxe = new Vector2f(vecA.y(), vecA.x());
@ -149,7 +134,7 @@ public class SegmentList {
vecB = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos); vecB = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos);
vecB = vecB.safeNormalize(); vecB = vecB.safeNormalize();
itListPoint.get(idCurrent).orthoAxePrevious = new Vector2f(vecB.y(), -vecB.x()); itListPoint.get(idCurrent).orthoAxePrevious = new Vector2f(vecB.y(), -vecB.x());
//LOGGER.debug("JOIN : miterAxe " + itListPoint.get(idCurrent).miterAxe); //Log.debug("JOIN : miterAxe " + itListPoint.get(idCurrent).miterAxe);
} else if (itListPoint.get(idCurrent).type == PointType.start) { } else if (itListPoint.get(idCurrent).type == PointType.start) {
itListPoint.get(idCurrent).posNext = itListPoint.get(idNext).pos; itListPoint.get(idCurrent).posNext = itListPoint.get(idNext).pos;
Vector2f vecB = itListPoint.get(idNext).pos.less(itListPoint.get(idCurrent).pos); Vector2f vecB = itListPoint.get(idNext).pos.less(itListPoint.get(idCurrent).pos);
@ -159,7 +144,7 @@ public class SegmentList {
itListPoint.get(idCurrent).orthoAxeNext = itListPoint.get(idCurrent).miterAxe; itListPoint.get(idCurrent).orthoAxeNext = itListPoint.get(idCurrent).miterAxe;
} else if (itListPoint.get(idCurrent).type == PointType.stop) { } else if (itListPoint.get(idCurrent).type == PointType.stop) {
if (idPevious < 0) { if (idPevious < 0) {
LOGGER.error("an error occure a previous ID is < 0.... "); Log.error("an error occure a previous ID is < 0.... ");
continue; continue;
} }
itListPoint.get(idCurrent).posPrevious = itListPoint.get(idPevious).pos; itListPoint.get(idCurrent).posPrevious = itListPoint.get(idPevious).pos;
@ -169,27 +154,25 @@ public class SegmentList {
itListPoint.get(idCurrent).orthoAxePrevious = itListPoint.get(idCurrent).miterAxe; itListPoint.get(idCurrent).orthoAxePrevious = itListPoint.get(idCurrent).miterAxe;
itListPoint.get(idCurrent).orthoAxeNext = itListPoint.get(idCurrent).miterAxe; itListPoint.get(idCurrent).orthoAxeNext = itListPoint.get(idCurrent).miterAxe;
} else { } else {
LOGGER.info("TODO: Unsupported type of point ...."); Log.todo("Unsupported type of point ....");
} }
} }
// create segment list: // create segment list:
boolean haveStartLine = false; boolean haveStartLine = false;
final Dynamic<Vector2f> leftPoint = new Dynamic<>(Vector2f.ZERO); Dynamic<Vector2f> leftPoint = new Dynamic<Vector2f>(Vector2f.ZERO);
final Dynamic<Vector2f> rightPoint = new Dynamic<>(Vector2f.ZERO); Dynamic<Vector2f> rightPoint = new Dynamic<Vector2f>(Vector2f.ZERO);
if (itListPoint.size() > 0) { if (itListPoint.size() > 0) {
if (itListPoint.get(0).type == PointType.join) { if (itListPoint.get(0).type == PointType.join) {
final Point it = itListPoint.get(itListPoint.size() - 1); Point it = itListPoint.get(itListPoint.size() - 1);
// Calculate the perpendicular axis ... // Calculate the perpendicular axis ...
leftPoint.value = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f)); leftPoint.value = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f));
rightPoint.value = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f)); rightPoint.value = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f));
// cyclic path... // cyclic path...
if (it.type == PointType.interpolation) { if (it.type == PointType.interpolation) {
leftPoint.value = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, leftPoint.value = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
it.miterAxe); rightPoint.value = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
rightPoint.value = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious),
it.pos, it.miterAxe);
} else if (it.type == PointType.join) { } else if (it.type == PointType.join) {
// Calculate the perpendicular axis ... // Calculate the perpendicular axis ...
leftPoint.value = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f)); leftPoint.value = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f));
@ -197,14 +180,12 @@ public class SegmentList {
// project on the miter Axis ... // project on the miter Axis ...
switch (join) { switch (join) {
case MITER: { case MITER: {
final Vector2f left = SegmentList.getIntersect(leftPoint.value, Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
it.pos.less(it.posPrevious), it.pos, it.miterAxe); Vector2f right = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
final Vector2f right = SegmentList.getIntersect(rightPoint.value,
it.pos.less(it.posPrevious), it.pos, it.miterAxe);
// Check the miter limit: // Check the miter limit:
final float limitRight = (left.less(it.pos)).length() / width * 2.0f; float limitRight = (left.less(it.pos)).length() / width * 2.0f;
final float limitLeft = (right.less(it.pos)).length() / width * 2.0f; float limitLeft = (right.less(it.pos)).length() / width * 2.0f;
LOGGER.trace(" miter Limit: " + limitRight + " " + limitLeft + " <= " + miterLimit); Log.verbose(" miter Limit: " + limitRight + " " + limitLeft + " <= " + miterLimit);
if (limitRight <= miterLimit && limitLeft <= miterLimit) { if (limitRight <= miterLimit && limitLeft <= miterLimit) {
leftPoint.value = left; leftPoint.value = left;
rightPoint.value = right; rightPoint.value = right;
@ -213,16 +194,14 @@ public class SegmentList {
} }
case ROUND: case ROUND:
case BEVEL: { case BEVEL: {
final Vector2f axePrevious = (it.pos.less(it.posPrevious)).safeNormalize(); Vector2f axePrevious = (it.pos.less(it.posPrevious)).safeNormalize();
final Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize(); Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize();
final float cross = axePrevious.cross(axeNext); float cross = axePrevious.cross(axeNext);
if (cross > 0.0f) { if (cross > 0.0f) {
rightPoint.value = SegmentList.getIntersect(rightPoint.value, rightPoint.value = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
it.pos.less(it.posPrevious), it.pos, it.miterAxe);
leftPoint.value = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f)); leftPoint.value = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f));
} else { } else {
leftPoint.value = SegmentList.getIntersect(leftPoint.value, leftPoint.value = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
it.pos.less(it.posPrevious), it.pos, it.miterAxe);
rightPoint.value = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f)); rightPoint.value = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f));
} }
break; break;
@ -231,112 +210,106 @@ public class SegmentList {
break; break;
} }
} else { } else {
LOGGER.error("Start list point with a join, but last lement is not a join"); Log.error("Start list point with a join, but last lement is not a join");
} }
} }
} }
for (final Point it : itListPoint) { for (Point it : itListPoint) {
switch (it.type) { switch (it.type) {
case single: case single:
// just do nothing .... // just do nothing ....
LOGGER.trace("Find Single " + it.pos); Log.verbose("Find Single " + it.pos);
break; break;
case start: case start:
LOGGER.trace("Find Start " + it.pos); Log.verbose("Find Start " + it.pos);
if (haveStartLine) { if (haveStartLine) {
// close previous : // close previous :
LOGGER.warn(" find a non close path ..."); Log.warning(" find a non close path ...");
addSegment(leftPoint.value, rightPoint.value); addSegment(leftPoint.value, rightPoint.value);
} }
haveStartLine = true; haveStartLine = true;
startStopPoint(leftPoint, rightPoint, it, cap, width, true); startStopPoint(leftPoint, rightPoint, it, cap, width, true);
break; break;
case stop: case stop:
LOGGER.trace("Find Stop " + it.pos); Log.verbose("Find Stop " + it.pos);
if (!haveStartLine) { if (!haveStartLine) {
LOGGER.warn("find close path without start part ..."); Log.warning("find close path without start part ...");
break; break;
} }
haveStartLine = false; haveStartLine = false;
startStopPoint(leftPoint, rightPoint, it, cap, width, false); startStopPoint(leftPoint, rightPoint, it, cap, width, false);
break; break;
case interpolation: { case interpolation: {
LOGGER.trace("Find interpolation " + it.pos); Log.verbose("Find interpolation " + it.pos);
final Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
it.pos, it.miterAxe); Vector2f right = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
final Vector2f right = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious),
it.pos, it.miterAxe);
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint.value, left); addSegment(leftPoint.value, left);
LOGGER.trace(" segment :" + leftPoint + " . " + left); Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint.value); addSegment(right, rightPoint.value);
LOGGER.trace(" segment :" + right + " . " + rightPoint); Log.verbose(" segment :" + right + " . " + rightPoint);
leftPoint.value = left; leftPoint.value = left;
rightPoint.value = right; rightPoint.value = right;
} }
break; break;
case join: case join:
LOGGER.trace("Find join " + it.pos); Log.verbose("Find join " + it.pos);
switch (join) { switch (join) {
case MITER: { case MITER: {
final Vector2f left = SegmentList.getIntersect(leftPoint.value, Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
it.pos.less(it.posPrevious), it.pos, it.miterAxe); Vector2f right = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
final Vector2f right = SegmentList.getIntersect(rightPoint.value,
it.pos.less(it.posPrevious), it.pos, it.miterAxe);
// Check the miter limit: // Check the miter limit:
final float limitRight = left.less(it.pos).length() / width * 2.0f; float limitRight = left.less(it.pos).length() / width * 2.0f;
final float limitLeft = right.less(it.pos).length() / width * 2.0f; float limitLeft = right.less(it.pos).length() / width * 2.0f;
LOGGER.trace(" miter Limit: " + limitRight + " " + limitLeft + " <= " + miterLimit); Log.verbose(" miter Limit: " + limitRight + " " + limitLeft + " <= " + miterLimit);
if (limitRight <= miterLimit && limitLeft <= miterLimit) { if (limitRight <= miterLimit && limitLeft <= miterLimit) {
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint.value, left); addSegment(leftPoint.value, left);
LOGGER.trace(" segment :" + leftPoint + " . " + left); Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint.value); addSegment(right, rightPoint.value);
LOGGER.trace(" segment :" + right + " . " + rightPoint); Log.verbose(" segment :" + right + " . " + rightPoint);
leftPoint.value = left; leftPoint.value = left;
rightPoint.value = right; rightPoint.value = right;
break; break;
} }
LOGGER.trace(" Find miter Limit ... ==> create BEVEL"); Log.verbose(" Find miter Limit ... ==> create BEVEL");
} }
case ROUND: case ROUND:
case BEVEL: { case BEVEL: {
final Vector2f axePrevious = (it.pos.less(it.posPrevious)).safeNormalize(); Vector2f axePrevious = (it.pos.less(it.posPrevious)).safeNormalize();
final Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize(); Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize();
final float cross = axePrevious.cross(axeNext); float cross = axePrevious.cross(axeNext);
if (cross > 0.0f) { if (cross > 0.0f) {
final Vector2f right = SegmentList.getIntersect(rightPoint.value, Vector2f right = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
it.pos.less(it.posPrevious), it.pos, it.miterAxe); Vector2f left1 = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f));
final Vector2f left1 = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f)); Vector2f left2 = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f));
final Vector2f left2 = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f));
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint.value, left1); addSegment(leftPoint.value, left1);
LOGGER.trace(" segment :" + leftPoint + " . " + left1); Log.verbose(" segment :" + leftPoint + " . " + left1);
if (join != JoinMode.ROUND) { if (join != JoinMode.ROUND) {
// Miter and bevel: // Miter and bevel:
addSegment(left1, left2); addSegment(left1, left2);
LOGGER.trace(" segment :" + left1 + " . " + left2); Log.verbose(" segment :" + left1 + " . " + left2);
} else { } else {
createSegmentListStroke(left1, left2, it.pos, width, false); createSegmentListStroke(left1, left2, it.pos, width, false);
} }
addSegment(right, rightPoint.value); addSegment(right, rightPoint.value);
LOGGER.trace(" segment :" + right + " . " + rightPoint); Log.verbose(" segment :" + right + " . " + rightPoint);
leftPoint.value = left2; leftPoint.value = left2;
rightPoint.value = right; rightPoint.value = right;
} else { } else {
final Vector2f left = SegmentList.getIntersect(leftPoint.value, Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
it.pos.less(it.posPrevious), it.pos, it.miterAxe); Vector2f right1 = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f));
final Vector2f right1 = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f)); Vector2f right2 = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f));
final Vector2f right2 = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f));
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint.value, left); addSegment(leftPoint.value, left);
LOGGER.trace(" segment :" + leftPoint + " . " + left); Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right1, rightPoint.value); addSegment(right1, rightPoint.value);
LOGGER.trace(" segment :" + right1 + " . " + rightPoint); Log.verbose(" segment :" + right1 + " . " + rightPoint);
if (join != JoinMode.ROUND) { if (join != JoinMode.ROUND) {
// Miter and bevel: // Miter and bevel:
addSegment(right2, right1); addSegment(right2, right1);
LOGGER.trace(" segment :" + right2 + " . " + right1); Log.verbose(" segment :" + right2 + " . " + right1);
} else { } else {
createSegmentListStroke(right1, right2, it.pos, width, true); createSegmentListStroke(right1, right2, it.pos, width, true);
} }
@ -357,21 +330,15 @@ public class SegmentList {
} }
private void createSegmentListStroke( private void createSegmentListStroke(final Vector2f point1, final Vector2f point2, final Vector2f center, final float width, final boolean isStart) {
final Vector2f point1,
final Vector2f point2,
final Vector2f center,
final float width,
final boolean isStart) {
int nbDot = (int) width; int nbDot = (int) width;
if (nbDot <= 2) { if (nbDot <= 2) {
nbDot = 2; nbDot = 2;
} }
final float angleToDraw = FMath float angleToDraw = FMath.acos((point1.less(center)).safeNormalize().dot((point2.less(center)).safeNormalize()));
.acos((point1.less(center)).safeNormalize().dot((point2.less(center)).safeNormalize())); float baseAngle = angleToDraw / nbDot;
final float baseAngle = angleToDraw / nbDot;
float iii; float iii;
final Vector2f axe = (point1.less(center)).safeNormalize(); Vector2f axe = (point1.less(center)).safeNormalize();
Vector2f ppp1 = point1; Vector2f ppp1 = point1;
@ -383,74 +350,68 @@ public class SegmentList {
} else { } else {
tmpMat = Matrix2x3f.createRotate(iii); tmpMat = Matrix2x3f.createRotate(iii);
} }
final Vector2f axeRotate = tmpMat.multiply(axe); Vector2f axeRotate = tmpMat.multiply(axe);
ppp2 = center.add(axeRotate.multiply(width * 0.5f)); ppp2 = center.add(axeRotate.multiply(width * 0.5f));
if (isStart) { if (isStart) {
addSegment(ppp2, ppp1); addSegment(ppp2, ppp1);
LOGGER.trace(" segment :" + ppp2 + " . " + ppp1); Log.verbose(" segment :" + ppp2 + " . " + ppp1);
} else { } else {
addSegment(ppp1, ppp2); addSegment(ppp1, ppp2);
LOGGER.trace(" segment :" + ppp1 + " . " + ppp2); Log.verbose(" segment :" + ppp1 + " . " + ppp2);
} }
ppp1 = ppp2; ppp1 = ppp2;
} }
if (isStart) { if (isStart) {
addSegment(point2, ppp1); addSegment(point2, ppp1);
LOGGER.trace(" segment :" + point2 + " . " + ppp1); Log.verbose(" segment :" + point2 + " . " + ppp1);
} else { } else {
addSegment(ppp1, point2); addSegment(ppp1, point2);
LOGGER.trace(" segment :" + ppp1 + " . " + point2); Log.verbose(" segment :" + ppp1 + " . " + point2);
} }
} }
public Pair<Vector2f, Vector2f> getViewPort() { public Pair<Vector2f, Vector2f> getViewPort() {
Pair<Vector2f, Vector2f> out = new Pair<>(Vector2f.MAX_VALUE, Vector2f.MIN_VALUE); Pair<Vector2f, Vector2f> out = new Pair<>(Vector2f.MAX_VALUE, Vector2f.MIN_VALUE);
for (final Segment it : this.data) { for (Segment it : this.data) {
out = new Pair<>(Vector2f.min(out.first, it.p0, it.p1), Vector2f.max(out.second, it.p0, it.p1)); out = new Pair<>(Vector2f.min(out.first, it.p0, it.p1), Vector2f.max(out.second, it.p0, it.p1));
} }
return out; return out;
} }
private void startStopPoint( private void startStopPoint(final Dynamic<Vector2f> leftPoint, final Dynamic<Vector2f> rightPoint, final Point point, final CapMode cap, final float width, final boolean isStart) {
final Dynamic<Vector2f> leftPoint,
final Dynamic<Vector2f> rightPoint,
final Point point,
final CapMode cap,
final float width,
final boolean isStart) {
switch (cap) { switch (cap) {
case BUTT: { case BUTT: {
final Vector2f left = point.pos.add(point.miterAxe.multiply(width * 0.5f)); Vector2f left = point.pos.add(point.miterAxe.multiply(width * 0.5f));
final Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f)); Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f));
if (!isStart) { if (!isStart) {
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint.value, left); addSegment(leftPoint.value, left);
LOGGER.trace(" segment :" + leftPoint + " . " + left); Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint.value); addSegment(right, rightPoint.value);
LOGGER.trace(" segment :" + right + " . " + rightPoint); Log.verbose(" segment :" + right + " . " + rightPoint);
} }
leftPoint.value = left; leftPoint.value = left;
rightPoint.value = right; rightPoint.value = right;
} }
if (!isStart) { if (!isStart) {
addSegment(leftPoint.value, rightPoint.value); addSegment(leftPoint.value, rightPoint.value);
LOGGER.trace(" segment :" + leftPoint + " . " + rightPoint); Log.verbose(" segment :" + leftPoint + " . " + rightPoint);
} else { } else {
addSegment(rightPoint.value, leftPoint.value); addSegment(rightPoint.value, leftPoint.value);
LOGGER.trace(" segment :" + rightPoint + " . " + leftPoint); Log.verbose(" segment :" + rightPoint + " . " + leftPoint);
} }
break; break;
case ROUND: { case ROUND: {
if (!isStart) { if (!isStart) {
final Vector2f left = point.pos.add(point.miterAxe.multiply(width * 0.5f)); Vector2f left = point.pos.add(point.miterAxe.multiply(width * 0.5f));
final Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f)); Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f));
if (!isStart) { if (!isStart) {
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint.value, left); addSegment(leftPoint.value, left);
LOGGER.trace(" segment :" + leftPoint + " . " + left); Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint.value); addSegment(right, rightPoint.value);
LOGGER.trace(" segment :" + right + " . " + rightPoint); Log.verbose(" segment :" + right + " . " + rightPoint);
} }
leftPoint.value = left; leftPoint.value = left;
rightPoint.value = right; rightPoint.value = right;
@ -473,30 +434,30 @@ public class SegmentList {
} }
Vector2f left = point.pos.add(point.miterAxe.multiply(width * 0.5f)); Vector2f left = point.pos.add(point.miterAxe.multiply(width * 0.5f));
Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f)); Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f));
final Matrix2x3f tmpMat = Matrix2x3f.createTranslate(nextAxe.safeNormalize().multiply(width * -0.5f)); Matrix2x3f tmpMat = Matrix2x3f.createTranslate(nextAxe.safeNormalize().multiply(width * -0.5f));
left = tmpMat.multiply(left); left = tmpMat.multiply(left);
right = tmpMat.multiply(right); right = tmpMat.multiply(right);
if (!isStart) { if (!isStart) {
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint.value, left); addSegment(leftPoint.value, left);
LOGGER.trace(" segment :" + leftPoint + " . " + left); Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint.value); addSegment(right, rightPoint.value);
LOGGER.trace(" segment :" + right + " . " + rightPoint); Log.verbose(" segment :" + right + " . " + rightPoint);
} }
leftPoint.value = left; leftPoint.value = left;
rightPoint.value = right; rightPoint.value = right;
if (!isStart) { if (!isStart) {
addSegment(leftPoint.value, rightPoint.value); addSegment(leftPoint.value, rightPoint.value);
LOGGER.trace(" segment :" + leftPoint + " . " + rightPoint); Log.verbose(" segment :" + leftPoint + " . " + rightPoint);
} else { } else {
addSegment(rightPoint.value, leftPoint.value); addSegment(rightPoint.value, leftPoint.value);
LOGGER.trace(" segment :" + rightPoint + " . " + leftPoint); Log.verbose(" segment :" + rightPoint + " . " + leftPoint);
} }
LOGGER.trace(" segment :" + leftPoint + " . " + rightPoint); Log.verbose(" segment :" + leftPoint + " . " + rightPoint);
} }
break; break;
default: default:
LOGGER.error(" Undefined CAP TYPE"); Log.error(" Undefined CAP TYPE");
break; break;
} }
} }

View File

@ -4,29 +4,27 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.math.FMath; import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i; import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.etk.util.ArraysTools; import org.atriasoft.etk.util.ArraysTools;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Weight { public class Weight {
static final Logger LOGGER = LoggerFactory.getLogger(Weight.class);
private float[][] data = null; private float[][] data = null;
private Vector2i size; private Vector2i size;
// constructor : // constructor :
public Weight() { public Weight() {
this.size = Vector2i.ZERO; this.size = Vector2i.ZERO;
} }
public Weight(final Vector2i size) { public Weight(final Vector2i size) {
this.size = size; this.size = size;
resize(size); resize(size);
} }
public void append(final int posY, final Scanline data) { public void append(final int posY, final Scanline data) {
if (posY >= 0 && posY < this.size.y()) { if (posY >= 0 && posY < this.size.y()) {
for (int xxx = 0; xxx < this.size.x(); ++xxx) { for (int xxx = 0; xxx < this.size.x(); ++xxx) {
@ -34,29 +32,28 @@ public class Weight {
} }
} }
} }
public void clear(final float fill) { public void clear(final float fill) {
ArraysTools.fill2(this.data, fill); ArraysTools.fill2(this.data, fill);
} }
public void fusion(final Weight redered, final int offsetXXX, final int offsetYYY) { public void fusion(final Weight redered, final int offsetXXX, final int offsetYYY) {
for (int yyy = 0; yyy < redered.getHeight(); yyy++) { for (int yyy = 0; yyy < redered.getHeight(); yyy++) {
for (int xxx = 0; xxx < redered.getWidth(); xxx++) { for (int xxx = 0; xxx < redered.getWidth(); xxx++) {
this.data[offsetYYY + yyy][offsetXXX + xxx] = FMath.avg(0.0f, this.data[offsetYYY + yyy][offsetXXX + xxx] = FMath.avg(0.0f, this.data[offsetYYY + yyy][offsetXXX + xxx] + redered.get(xxx, yyy), 1.0f);
this.data[offsetYYY + yyy][offsetXXX + xxx] + redered.get(xxx, yyy), 1.0f);
} }
} }
} }
public void generate(final Vector2i size, final int subSamplingCount, final SegmentList listSegment) { public void generate(final Vector2i size, final int subSamplingCount, final SegmentList listSegment) {
resize(size); resize(size);
// for each lines: // for each lines:
for (int yyy = 0; yyy < size.y(); ++yyy) { for (int yyy = 0; yyy < size.y(); ++yyy) {
LOGGER.trace("Weighting ... " + yyy + " / " + size.y()); Log.verbose("Weighting ... " + yyy + " / " + size.y());
// Reduce the number of lines in the subsampling parsing: // Reduce the number of lines in the subsampling parsing:
final List<Segment> availlableSegmentPixel = new ArrayList<>(); List<Segment> availlableSegmentPixel = new ArrayList<Segment>();
for (final Segment it : listSegment.data) { for (Segment it : listSegment.data) {
if (it.p0.y() < yyy + 1 && it.p1.y() > (yyy)) { if (it.p0.y() < yyy + 1 && it.p1.y() > (yyy)) {
availlableSegmentPixel.add(it); availlableSegmentPixel.add(it);
} }
@ -64,21 +61,20 @@ public class Weight {
if (availlableSegmentPixel.size() == 0) { if (availlableSegmentPixel.size() == 0) {
continue; continue;
} }
LOGGER.trace(" Find Basic segments " + availlableSegmentPixel.size()); Log.verbose(" Find Basic segments " + availlableSegmentPixel.size());
// This represent the pondaration on the subSampling // This represent the pondaration on the subSampling
final float deltaSize = 1.0f / subSamplingCount; float deltaSize = 1.0f / subSamplingCount;
for (int kkk = 0; kkk < subSamplingCount; ++kkk) { for (int kkk = 0; kkk < subSamplingCount; ++kkk) {
LOGGER.trace(" Scanline ... " + kkk + " / " + subSamplingCount); Log.verbose(" Scanline ... " + kkk + " / " + subSamplingCount);
final Scanline scanline = new Scanline(size.x()); Scanline scanline = new Scanline(size.x());
//find all the segment that cross the middle of the line of the center of the pixel line: //find all the segment that cross the middle of the line of the center of the pixel line:
final float subSamplingCenterPos = yyy + deltaSize * 0.5f + deltaSize * kkk; float subSamplingCenterPos = yyy + deltaSize * 0.5f + deltaSize * kkk;
final List<Segment> availlableSegment = new ArrayList<>(); List<Segment> availlableSegment = new ArrayList<>();
// find in the subList ... // find in the subList ...
for (final Segment it : availlableSegmentPixel) { for (Segment it : availlableSegmentPixel) {
if (it.p0.y() <= subSamplingCenterPos && it.p1.y() > subSamplingCenterPos) { if (it.p0.y() <= subSamplingCenterPos && it.p1.y() > subSamplingCenterPos) {
// check if we not get 2 identical lines: // check if we not get 2 identical lines:
if (availlableSegment.size() > 0 if (availlableSegment.size() > 0 && availlableSegment.get(availlableSegment.size() - 1).p1 == it.p0
&& availlableSegment.get(availlableSegment.size() - 1).p1 == it.p0
&& availlableSegment.get(availlableSegment.size() - 1).direction == it.direction) { && availlableSegment.get(availlableSegment.size() - 1).direction == it.direction) {
// we not add this point in this case to prevent double count of the same point. // we not add this point in this case to prevent double count of the same point.
} else { } else {
@ -86,27 +82,27 @@ public class Weight {
} }
} }
} }
LOGGER.trace(" Availlable Segment " + availlableSegment.size()); Log.verbose(" Availlable Segment " + availlableSegment.size());
if (availlableSegment.size() == 0) { if (availlableSegment.size() == 0) {
continue; continue;
} }
for (final Segment it : availlableSegment) { for (Segment it : availlableSegment) {
LOGGER.trace(" Availlable Segment " + it.p0 + " . " + it.p1 + " dir=" + it.direction); Log.verbose(" Availlable Segment " + it.p0 + " . " + it.p1 + " dir=" + it.direction);
} }
// x position, angle // x position, angle
final List<Pair<Float, Integer>> listPosition = new ArrayList<>(); List<Pair<Float, Integer>> listPosition = new ArrayList<>();
for (final Segment it : availlableSegment) { for (Segment it : availlableSegment) {
final Vector2f delta = it.p0.less(it.p1); Vector2f delta = it.p0.less(it.p1);
// x = coefficent*y+bbb; // x = coefficent*y+bbb;
final float coefficient = delta.x() / delta.y(); float coefficient = delta.x() / delta.y();
final float bbb = it.p0.x() - coefficient * it.p0.y(); float bbb = it.p0.x() - coefficient * it.p0.y();
final float xpos = coefficient * subSamplingCenterPos + bbb; float xpos = coefficient * subSamplingCenterPos + bbb;
listPosition.add(new Pair<>(xpos, it.direction)); listPosition.add(new Pair<Float, Integer>(xpos, it.direction));
} }
LOGGER.trace(" List position " + listPosition.size()); Log.verbose(" List position " + listPosition.size());
// now we order position of the xPosition: // now we order position of the xPosition:
Collections.sort(listPosition, (e1, e2) -> ((int) (e1.first - e2.first))); Collections.sort(listPosition, (e1, e2) -> ((int) (e1.first - e2.first)));
// move through all element in the point: // move through all element in the point:
int lastState = 0; int lastState = 0;
float currentValue = 0.0f; float currentValue = 0.0f;
@ -115,30 +111,30 @@ public class Weight {
// * current pos // * current pos
// * pos ... // * pos ...
// TODO Code the Odd/even and non-zero ... // TODO Code the Odd/even and non-zero ...
for (final Pair<Float, Integer> it : listPosition) { for (Pair<Float, Integer> it : listPosition) {
if (currentPos != it.first.intValue()) { if (currentPos != it.first.intValue()) {
// fill to the new pos -1: // fill to the new pos -1:
final float endValue = FMath.min(1.0f, FMath.abs(lastState)) * deltaSize; float endValue = FMath.min(1.0f, FMath.abs(lastState)) * deltaSize;
for (int iii = currentPos + 1; iii < it.first.intValue(); ++iii) { for (int iii = currentPos + 1; iii < it.first.intValue(); ++iii) {
scanline.set(iii, endValue); scanline.set(iii, endValue);
} }
currentPos = it.first.intValue(); currentPos = it.first.intValue();
currentValue = endValue; currentValue = endValue;
} }
final int oldState = lastState; int oldState = lastState;
lastState += it.second; lastState += it.second;
if (oldState == 0) { if (oldState == 0) {
// nothing to draw before ... // nothing to draw before ...
final float ratio = 1.0f - (it.first - it.first.intValue()); float ratio = 1.0f - (it.first - it.first.intValue());
currentValue += ratio * deltaSize; currentValue += ratio * deltaSize;
} else if (lastState == 0) { } else if (lastState == 0) {
// something new to draw ... // something new to draw ...
final float ratio = 1.0f - (it.first - it.first.intValue()); float ratio = 1.0f - (it.first - it.first.intValue());
currentValue -= ratio * deltaSize; currentValue -= ratio * deltaSize;
} else { } else {
// nothing to do ... // nothing to do ...
} }
if (currentPos == it.first.intValue()) { if (currentPos == it.first.intValue()) {
scanline.set(currentPos, currentValue); scanline.set(currentPos, currentValue);
} }
@ -146,7 +142,7 @@ public class Weight {
// if the counter is not at 0 ==> fill if to the end with full value ... 2.0 // if the counter is not at 0 ==> fill if to the end with full value ... 2.0
if (lastState != 0) { if (lastState != 0) {
// just past the last state to the end of the image ... // just past the last state to the end of the image ...
LOGGER.error("end of Path whith no end ... " + currentPos + " . " + size.x()); Log.error("end of Path whith no end ... " + currentPos + " . " + size.x());
for (int xxx = currentPos; xxx < size.x(); ++xxx) { for (int xxx = currentPos; xxx < size.x(); ++xxx) {
scanline.set(xxx, 100.0f); scanline.set(xxx, 100.0f);
} }
@ -155,50 +151,42 @@ public class Weight {
} }
} }
} }
public float get(final int xxx, final int yyy) { public float get(final int xxx, final int yyy) {
if (this.data == null) { if (this.data == null) {
return 0; return 0;
} }
return this.data[yyy][xxx]; return this.data[yyy][xxx];
} }
public float get(final Vector2i pos) { public float get(final Vector2i pos) {
if (this.data == null) { if (this.data == null) {
return 0; return 0;
} }
return this.data[pos.y()][pos.x()]; return this.data[pos.y()][pos.x()];
} }
public int getHeight() { public int getHeight() {
return this.size.y(); return this.size.y();
} }
public Vector2i getSize() { public Vector2i getSize() {
return this.size; return this.size;
} }
public int getWidth() { public int getWidth() {
return this.size.x(); return this.size.x();
} }
// ----------------------------------------------- // -----------------------------------------------
// -- basic tools : // -- basic tools :
// ----------------------------------------------- // -----------------------------------------------
public void resize(final Vector2i size) { public void resize(final Vector2i size) {
this.size = size; this.size = size;
if (this.size.x() <= 0) {
LOGGER.error("Error in the Weight size : " + this.size);
this.size = this.size.withX(1);
}
if (this.size.y() <= 0) {
LOGGER.error("Error in the Weight size : " + this.size);
this.size = this.size.withY(1);
}
this.data = new float[this.size.y()][this.size.x()]; this.data = new float[this.size.y()][this.size.x()];
clear(0); clear(0);
} }
public void set(final int posY, final Scanline data) { public void set(final int posY, final Scanline data) {
if (posY >= 0 && posY < this.size.y()) { if (posY >= 0 && posY < this.size.y()) {
for (int xxx = 0; xxx < this.size.x(); ++xxx) { for (int xxx = 0; xxx < this.size.x(); ++xxx) {
@ -206,9 +194,9 @@ public class Weight {
} }
} }
} }
public void set(final Vector2i pos, final float newColor) { public void set(final Vector2i pos, final float newColor) {
this.data[pos.y()][pos.x()] = newColor; this.data[pos.y()][pos.x()] = newColor;
} }
} }

View File

@ -1,188 +0,0 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class TestCap {
@Test
public void testTestCapButt() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>\
<polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbutt.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbutt.png"));
}
@Test
public void testTestCapButtDiag1() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>\
<polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag1.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag1.png"));
}
@Test
public void testTestCapButtDiag2() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>\
<polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag2.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag2.png"));
}
@Test
public void testTestCapButtVert() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>\
<polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbuttVert.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbuttVert.png"));
}
@Test
public void testTestCapRound() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>\
<polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapround.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapround.png"));
}
@Test
public void testTestCapRoundDiag1() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>\
<polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag1.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag1.png"));
}
@Test
public void testTestCapRoundDiag2() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>\
<polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag2.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag2.png"));
}
@Test
public void testTestCapRoundVert() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>\
<polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCaproundVert.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCaproundVert.png"));
}
@Test
public void testTestCapSquare() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>\
<polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquare.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquare.png"));
}
@Test
public void testTestCapSquareDiag1() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>\
<polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag1.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag1.png"));
}
@Test
public void testTestCapSquareDiag2() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>\
<polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag2.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag2.png"));
}
@Test
public void testTestCapSquareVert() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>\
<polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquareVert.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquareVert.png"));
}
}

View File

@ -1,51 +0,0 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class TestCircle {
@Test
public void testTestCircleFill() throws RuntimeException {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<circle cx='50' cy='50' r='40' fill='red' />\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCirclefill.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCirclefill.png"));
}
@Test
public void testTestCircleFillandstroke() throws RuntimeException {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<circle cx='50' cy='50' r='40' stroke='green' stroke-width='3' fill='red' />\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCirclefillandstroke.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCirclefillandstroke.png"));
}
@Test
public void testTestCircleStroke() throws RuntimeException {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<circle cx='50' cy='50' r='40' stroke='green' stroke-width='3' />\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCirclestroke.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCirclestroke.png"));
}
}

View File

@ -1,113 +0,0 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.Esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.esvg.EsvgFont;
import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class TestFont {
@Test
public void testFontError1() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='900' width='700'>\
<path d='M296 463q80 0 125 -45t45 -126q0 -130 -73 -217.5t-187 -87.5q-80 0 -125 45.5t-45 127.5q0 126 73 214.5t187 88.5zM218 51q78 0 123.5 68t45.5 166q0 115 -103 115q-75 0 -122 -66.5t-47 -167.5q0 -115 103 -115z'\
stroke='green' stroke-width='3' />\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestFontError1.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestFontError1.png"));
}
@Test
public void testFontError2() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='900' width='700'>\
<path d='M296 463q80 0 125 -45t45 -126q0 -130 -73 -217.5t-187 -87.5q-80 0 -125 45.5t-45 127.5q0 126 73 214.5t187 88.5z'\
stroke='green' stroke-width='3' />\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestFontError2.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestFontError2.png"));
}
@Test
public void testFontError3() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='900' width='700'>\
<path d='M218 51q78 0 123.5 68t45.5 166q0 115 -103 115q-75 0 -122 -66.5t-47 -167.5q0 -115 103 -115z'\
stroke='green' stroke-width='3' />\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestFontError3.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestFontError3.png"));
}
@Test
public void testFontError4() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='900' width='700'>\
<path d='M1011 -78q51 -11 84.5 -50.5t33.5 -93.5q0 -61 -43 -103t-104 -42q-60 0 -102 43q-43 42 -43 102q0 34 16 67q-2 0 -20 -4.5t-36.5 -8t-47 -7.5t-66.5 -6.5t-80 -2.5q-144 0 -248 27.5t-164.5 80.5t-88.5 123t-28 161q0 124 106 240l33 -30q-101 -101 -101 -206
q0 -335 487 -335q304 0 401 123q-39 -10 -68 -10q-95 3 -142 74q-50 -74 -136 -74q-68 0 -120 47t-52 125v92q0 75 -25.5 106t-58.5 31q-49 0 -92 -49t-43 -124q0 -19 3.5 -40.5t13.5 -53t34 -61.5t60 -48l-22 -25q-43 23 -72 58t-41 72.5t-16 63t-4 46.5q0 103 58.5 161.5
t130.5 58.5q24 0 47.5 -8t46.5 -26.5t37 -56t14 -89.5v-87q0 -79 37 -112t81 -33q40 0 69.5 22.5t29.5 57.5v322h83v-275q0 -55 27.5 -84.5t67.5 -29.5q60 0 95.5 52.5t35.5 125.5q0 20 -3 40t-12.5 50t-33 57.5t-57.5 46.5l29 25q57 -44 90.5 -105t33.5 -130
q0 -195 -115 -291zM972 -218q23 0 37.5 15t14.5 37q0 17 -16 32.5t-35 15.5q-30 0 -41.5 -12t-11.5 -36q0 -23 15 -37.5t37 -14.5zM970 -316q41 0 69.5 29t28.5 69q0 38 -19 60q1 -3 1 -13q0 -38 -25 -62.5t-60 -24.5q-33 0 -57.5 22.5t-28.5 55.5q-7 -20 -7 -38
q0 -41 29 -69.5t69 -28.5z'\
stroke='green' stroke-width='3' />\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestFontError4.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestFontError4.png"));
}
@Test
public void testFontprintE25() {
Esvg.init();
final EsvgFont font = EsvgFont.load(new Uri("FONTS", "FreeSherif.svg", "esvg"));
Assertions.assertNotNull(font);
Weight out = font.render('E', 25);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_E25.png"));
out = font.render('e', 25);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_e25.png"));
out = font.render('É', 25);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_Ecute25.png"));
out = font.render('é', 25);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_ecute25.png"));
out = font.render('p', 25);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_p25.png"));
out = font.render('f', 25);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_f25.png"));
}
@Test
public void testFontprintSimpleText() {
Esvg.init();
final EsvgFont font = EsvgFont.load(new Uri("FONTS", "FreeSherif.svg", "esvg"));
Weight out = font.render("Hello, How are you? VA // @ ê É", 100, false);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_Hello.png"));
out = font.render("Hello, How are you? VA // @ ê É", 100, true);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_Hello_withKerning.png"));
}
@Test
public void testFontRead() {
Esvg.init();
final EsvgFont font = EsvgFont.load(new Uri("FONTS", "FreeSherif.svg", "esvg"));
}
}

View File

@ -1,413 +0,0 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class TestGradientLinear {
@Test
public void testTestGradientLinearDiag1() {
//@formatter:off
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='0%' y1='0%' x2='100%' y2='100%'>
<stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
//@formatter:on
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1.png"));
}
@Test
public void testTestGradientLinearDiag1Partiel() {
//@formatter:off
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='40%' y1='40%' x2='70%' y2='70%'>
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
//@formatter:on
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1Partiel.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1Partiel.png"));
}
@Test
public void testTestGradientLinearDiag2() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>
<stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2.png"));
}
@Test
public void testTestGradientLinearDiag2Rotate0() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='0%' y1='50%' x2='100%' y2='50%'>
<stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse transform='rotate (30 50 50)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate0.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate0.png"));
}
@Test
public void testTestGradientLinearDiag2Rotate1() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>
<stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse transform='rotate (45 50 50)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate1.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate1.png"));
}
@Test
public void testTestGradientLinearDiag2Rotate2() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>
<stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse transform='rotate (-45 50 50)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate2.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate2.png"));
}
@Test
public void testTestGradientLinearDiag2scale() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>
<stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse transform='scale (0.5 2.0) translate (10,-25)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri
.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2scale.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2scale.png"));
}
@Test
public void testTestGradientLinearHorizontal() {
//@formatter:off
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad1' x1='0%' y1='0%' x2='100%' y2='0%'>
<stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
//@formatter:on
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri
.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearhorizontal.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearhorizontal.png"));
}
@Test
public void testTestGradientLinearInternalHref() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2Values'>
<stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
<linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%' xlink:href='#grad2Values' />
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearinternalHref.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearinternalHref.png"));
}
@Test
public void testTestGradientLinearUnitBoxspreadNone() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%'>
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadNone.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadNone.png"));
}
@Test
public void testTestGradientLinearUnitBoxspreadPad() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='pad'>
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadPad.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadPad.png"));
}
@Test
public void testTestGradientLinearUnitBoxspreadReflect() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='reflect'>
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadReflect.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadReflect.png"));
}
@Test
public void testTestGradientLinearUnitBoxspreadRepeat() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='repeat'>
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadRepeat.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadRepeat.png"));
}
@Test
public void testTestGradientLinearUnitUserspreadNone() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' gradientUnits='userSpaceOnUse'>
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadNone.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadNone.png"));
}
@Test
public void testTestGradientLinearUnitUserspreadPad() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='pad' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadPad.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadPad.png"));
}
@Test
public void testTestGradientLinearUnitUserspreadReflect() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadReflect.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadReflect.png"));
}
@Test
public void testTestGradientLinearUnitUserspreadRepeate() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadRepeate.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadRepeate.png"));
}
@Test
public void testTestGradientLinearVertical() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<linearGradient id='grad2' x1='0%' y1='0%' x2='0%' y2='100%'>
<stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri
.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearvertical.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearvertical.png"));
}
}

View File

@ -1,388 +0,0 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class TestGradientRadial {
@Test
public void testTestGradientRadialCircle() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50%' cy='50%' r='50%' fx='50%' fy='50%'>
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='50' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialcircle.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialcircle.png"));
}
@Test
public void testTestGradientRadialFull() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50%' cy='50%' r='50%' fx='50%' fy='50%'>
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialfull.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialfull.png"));
}
@Test
public void testTestGradientRadialPartial() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad2' cx='20%' cy='30%' r='30%' fx='50%' fy='50%'>
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri
.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialpartial.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialpartial.png"));
}
@Test
public void testTestGradientRadialUnitBoxspreadNone() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%'>
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadNone.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadNone.png"));
}
@Test
public void testTestGradientRadialUnitBoxspreadPad() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='pad'>
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadPad.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadPad.png"));
}
@Test
public void testTestGradientRadialUnitBoxspreadReflect() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='reflect'>
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadReflect.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadReflect.png"));
}
@Test
public void testTestGradientRadialUnitBoxspreadRepeat() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='repeat'>
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadRepeat.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadRepeat.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadNone() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50%' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadNone.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadNone.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadPad() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='pad' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPad.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPad.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadPadunCenter() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='pad' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPadunCenter.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc,
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPadunCenter.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadReflect() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflect.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflect.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadReflectunCenter() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflectunCenter.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc,
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflectunCenter.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadRepeat() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeat.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeat.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadRepeatout() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50' cy='50' r='24' fx='20' fy='40' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatout.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc,
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatout.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadRepeatunCenter() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc,
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadRepeatunCenter2() {
final String data = """
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<svg height='100' width='100'>
<defs>
<radialGradient id='grad1' cx='50' cy='50' r='24' fx='60' fy='60' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter2.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc,
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter2.png"));
}
}

2
test/.gitignore vendored
View File

@ -1,3 +1 @@
/__pycache__/
/bin/ /bin/

View File

@ -1,127 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="300"
height="300"
viewBox="0 0 79.374998 79.375002"
version="1.1"
id="svg8"
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)"
sodipodi:docname="Unnamed document 2.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="443.11885"
inkscape:cy="483.15179"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:window-width="3838"
inkscape:window-height="2118"
inkscape:window-x="0"
inkscape:window-y="20"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.35px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="52.662182"
y="11.725324"
id="text835"><tspan
sodipodi:role="line"
id="tspan833"
x="52.662182"
y="11.725324"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.35px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583">H<tspan
style="fill:#d38b00;fill-opacity:1"
id="tspan1023">e</tspan>llo</tspan><tspan
sodipodi:role="line"
x="52.662182"
y="19.662823"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:6.35px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
id="tspan847">sq<tspan
style="fill:#8c0000;fill-opacity:1"
id="tspan1029">m</tspan>l</tspan><tspan
sodipodi:role="line"
x="52.662182"
y="27.600323"
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.35px;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
id="tspan849">k<tspan
style="fill:#000063;fill-opacity:1"
id="tspan1031">s</tspan>d</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444444px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583;-inkscape-font-specification:'sans-serif, Normal';font-stretch:normal;font-variant:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;"
x="1.3595439"
y="44.163139"
id="text853"><tspan
sodipodi:role="line"
id="tspan851"
x="1.3595439"
y="44.163139"
style="stroke-width:0.264583;-inkscape-font-specification:'sans-serif, Normal';font-family:sans-serif;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;font-size:5.64444444px;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;">Hello</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444444px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583;-inkscape-font-specification:'sans-serif, Normal';font-stretch:normal;font-variant:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;"
x="1.1807559"
y="55.513321"
id="text857"><tspan
sodipodi:role="line"
id="tspan855"
x="1.1807559"
y="55.513321"
style="stroke-width:0.264583;font-weight:bold;-inkscape-font-specification:'sans-serif, Normal';font-family:sans-serif;font-style:normal;font-stretch:normal;font-variant:normal;font-size:5.64444444px;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal">Hello Bold</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444444px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583;-inkscape-font-specification:'sans-serif, Normal';font-stretch:normal;font-variant:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;"
x="1.196579"
y="65.77121"
id="text861"><tspan
sodipodi:role="line"
id="tspan859"
x="1.196579"
y="65.77121"
style="stroke-width:0.264583;font-style:italic;-inkscape-font-specification:'sans-serif, Normal';font-family:sans-serif;font-weight:normal;font-stretch:normal;font-variant:normal;font-size:5.64444444px;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal">Hello Italic</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444444px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583;-inkscape-font-specification:'sans-serif, Normal';font-stretch:normal;font-variant:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;"
x="1.9766912"
y="76.594482"
id="text865"><tspan
sodipodi:role="line"
id="tspan863"
x="1.9766912"
y="76.594482"
style="stroke-width:0.264583;font-weight:bold;font-style:italic;-inkscape-font-specification:'sans-serif, Normal';font-family:sans-serif;font-stretch:normal;font-variant:normal;font-size:5.64444444px;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal">Hello Bold Italic</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.4 KiB

View File

@ -1,37 +1,36 @@
package test.atriasoft.esvg; package test.atriasoft.esvg;
import org.atriasoft.egami.Image;
import org.atriasoft.egami.ImageFloatRGBA; import org.atriasoft.egami.ImageFloatRGBA;
import org.atriasoft.egami.Image;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.Weight; import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.Color; import org.atriasoft.etk.Color;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.atriasoft.etk.math.Vector2i; import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.pngencoder.PngEncoder; import org.atriasoft.pngencoder.PngEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ConfigTest { public class ConfigTest {
static final Logger LOGGER = LoggerFactory.getLogger(ConfigTest.class);
public static final String BASE_PATH = "./testResult/";//"~/dev/workspace-game/atriasoft/esvg/"; public static final String BASE_PATH = "./testResult/";//"~/dev/workspace-game/atriasoft/esvg/";
public static final boolean VISUAL_DEBUG = true; public static final boolean VISUAL_DEBUG = true;
public static void generateAnImage(final EsvgDocument doc, final Uri uri) { public static void generateAnImage(final EsvgDocument doc, final Uri uri) {
final Image data = doc.renderImageFloatRGBA(null, ConfigTest.VISUAL_DEBUG); Image data = doc.renderImageFloatRGBA(null, ConfigTest.VISUAL_DEBUG);
if (data == null) { if (data == null) {
LOGGER.error("No data generated ..."); Log.critical("No data generated ...");
} }
LOGGER.warn("Save file in " + uri.getPath()); Log.warning("Save file in " + uri.getPath());
final byte[] outElem = new PngEncoder().withBufferedImage(data).withCompressionLevel(9).toBytes(); byte[] outElem = new PngEncoder().withBufferedImage(data).withCompressionLevel(9).toBytes();
LOGGER.warn("outsize = " + outElem.length); Log.warning("outsize = " + outElem.length);
new PngEncoder().withBufferedImage(data).withCompressionLevel(9).toFile(uri.getPath()); new PngEncoder().withBufferedImage(data).withCompressionLevel(9).toFile(uri.getPath());
} }
public static void generateAnImage(final Weight weight, final Uri uri) { public static void generateAnImage(final Weight weight, final Uri uri) {
final ImageFloatRGBA image = new ImageFloatRGBA(weight.getWidth() + 2, weight.getHeight() + 2); ImageFloatRGBA image = new ImageFloatRGBA(weight.getWidth() + 2, weight.getHeight() + 2);
for (int yyy = 0; yyy < weight.getHeight(); yyy++) { for (int yyy = 0; yyy < weight.getHeight(); yyy++) {
for (int xxx = 0; xxx < weight.getWidth(); xxx++) { for (int xxx = 0; xxx < weight.getWidth(); xxx++) {
final float elem = weight.get(new Vector2i(xxx, yyy)); float elem = weight.get(new Vector2i(xxx, yyy));
image.setColorFloat(xxx, yyy, 1.0f, 1.0f, 1.0f, elem); image.setColorFloat(xxx, yyy, 1.0f, 1.0f, 1.0f, elem);
} }
} }
@ -43,11 +42,11 @@ public class ConfigTest {
image.setColor(xxx, 0, Color.ORANGE); image.setColor(xxx, 0, Color.ORANGE);
image.setColor(xxx, weight.getHeight() + 1, Color.ORANGE); image.setColor(xxx, weight.getHeight() + 1, Color.ORANGE);
} }
LOGGER.warn("Save file in " + uri.getPath()); Log.warning("Save file in " + uri.getPath());
final byte[] outElem = new PngEncoder().withBufferedImage(image).withCompressionLevel(9).toBytes(); byte[] outElem = new PngEncoder().withBufferedImage(image).withCompressionLevel(9).toBytes();
LOGGER.warn("outsize = " + outElem.length); Log.warning("outsize = " + outElem.length);
new PngEncoder().withBufferedImage(image).withCompressionLevel(9).toFile(uri.getPath()); new PngEncoder().withBufferedImage(image).withCompressionLevel(9).toFile(uri.getPath());
} }
private ConfigTest() {} private ConfigTest() {}
} }

View File

@ -0,0 +1,139 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Test;
class TestCap {
@Test
public void testTestCapButt() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>"
+ " <polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbutt.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbutt.png"));
}
@Test
public void testTestCapButtDiag1() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>"
+ " <polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag1.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag1.png"));
}
@Test
public void testTestCapButtDiag2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>"
+ " <polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag2.png"));
}
@Test
public void testTestCapButtVert() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>"
+ " <polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbuttVert.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbuttVert.png"));
}
@Test
public void testTestCapRound() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>"
+ " <polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapround.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapround.png"));
}
@Test
public void testTestCapRoundDiag1() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>"
+ " <polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag1.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag1.png"));
}
@Test
public void testTestCapRoundDiag2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>"
+ " <polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag2.png"));
}
@Test
public void testTestCapRoundVert() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>"
+ " <polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCaproundVert.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCaproundVert.png"));
}
@Test
public void testTestCapSquare() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>"
+ " <polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquare.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquare.png"));
}
@Test
public void testTestCapSquareDiag1() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>"
+ " <polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag1.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag1.png"));
}
@Test
public void testTestCapSquareDiag2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>"
+ " <polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag2.png"));
}
@Test
public void testTestCapSquareVert() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>"
+ " <polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquareVert.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquareVert.png"));
}
}

View File

@ -0,0 +1,36 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Test;
class TestCircle {
@Test
public void testTestCircleFill() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <circle cx='50' cy='50' r='40' fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCirclefill.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCirclefill.png"));
}
@Test
public void testTestCircleFillandstroke() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <circle cx='50' cy='50' r='40' stroke='green' stroke-width='3' fill='red' />"
+ "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCirclefillandstroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCirclefillandstroke.png"));
}
@Test
public void testTestCircleStroke() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <circle cx='50' cy='50' r='40' stroke='green' stroke-width='3' />" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCirclestroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCirclestroke.png"));
}
}

View File

@ -2,8 +2,6 @@ package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class TestColor { class TestColor {
@ -13,7 +11,7 @@ class TestColor {
+ " <rect x='12.5' y='12.5' width='75' height='50' stroke='#0F0' stroke-opacity='0.5' stroke-width='3' fill='#F00' fill-opacity='0.5' />" + "</svg>"; + " <rect x='12.5' y='12.5' width='75' height='50' stroke='#0F0' stroke-opacity='0.5' stroke-width='3' fill='#F00' fill-opacity='0.5' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestColorblending.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestColorblending.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestColorblending.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestColorblending.png"));
} }
@ -23,7 +21,7 @@ class TestColor {
+ " <rect x='12.5' y='12.5' width='75' height='50' stroke='#0F0' stroke-opacity='0.5' stroke-width='3' fill='#F00' fill-opacity='0.5' opacity='0.7' />" + "</svg>"; + " <rect x='12.5' y='12.5' width='75' height='50' stroke='#0F0' stroke-opacity='0.5' stroke-width='3' fill='#F00' fill-opacity='0.5' opacity='0.7' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestColorblendingandopacity.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestColorblendingandopacity.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestColorblendingandopacity.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestColorblendingandopacity.png"));
} }
@ -35,7 +33,7 @@ class TestColor {
+ " <rect x='30' y='30' width='20' height='20' stroke='orange' stroke-width='1' fill='violet'/>" + "</svg>"; + " <rect x='30' y='30' width='20' height='20' stroke='orange' stroke-width='1' fill='violet'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestColormultiplelayer.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestColormultiplelayer.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestColormultiplelayer.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestColormultiplelayer.png"));
} }
@ -45,7 +43,7 @@ class TestColor {
+ " <rect x='12.5' y='12.5' width='75' height='50' stroke='#0F0' stroke-width='3' fill='#F00' opacity='0.5' />" + "</svg>"; + " <rect x='12.5' y='12.5' width='75' height='50' stroke='#0F0' stroke-width='3' fill='#F00' opacity='0.5' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestColoropacity.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestColoropacity.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestColoropacity.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestColoropacity.png"));
} }
} }

View File

@ -2,8 +2,6 @@ package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class TestEllipse { class TestEllipse {
@ -13,7 +11,7 @@ class TestEllipse {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <ellipse cx='50' cy='50' rx='80' ry='30' fill='red' />" + "</svg>"; String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <ellipse cx='50' cy='50' rx='80' ry='30' fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestEllipsefill.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestEllipsefill.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestEllipsefill.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestEllipsefill.png"));
} }
@ -23,7 +21,7 @@ class TestEllipse {
+ " <ellipse cx='50' cy='50' rx='80' ry='30' stroke='green' stroke-width='3' fill='red' />" + "</svg>"; + " <ellipse cx='50' cy='50' rx='80' ry='30' stroke='green' stroke-width='3' fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestEllipsefillandstroke.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestEllipsefillandstroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestEllipsefillandstroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestEllipsefillandstroke.png"));
} }
@ -33,7 +31,7 @@ class TestEllipse {
+ "</svg>"; + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestEllipsestroke.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestEllipsestroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestEllipsestroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestEllipsestroke.png"));
} }
} }

View File

@ -0,0 +1,93 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.Esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.esvg.EsvgFont;
import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Test;
class TestFont {
@Test
public void testFontError1() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='900' width='700'>"
+ " <path d='M296 463q80 0 125 -45t45 -126q0 -130 -73 -217.5t-187 -87.5q-80 0 -125 45.5t-45 127.5q0 126 73 214.5t187 88.5zM218 51q78 0 123.5 68t45.5 166q0 115 -103 115q-75 0 -122 -66.5t-47 -167.5q0 -115 103 -115z'"
+ " stroke='green' stroke-width='3' />" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestFontError1.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestFontError1.png"));
}
@Test
public void testFontError2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='900' width='700'>"
+ " <path d='M296 463q80 0 125 -45t45 -126q0 -130 -73 -217.5t-187 -87.5q-80 0 -125 45.5t-45 127.5q0 126 73 214.5t187 88.5z'" + " stroke='green' stroke-width='3' />"
+ "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestFontError2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestFontError2.png"));
}
@Test
public void testFontError3() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='900' width='700'>"
+ " <path d='M218 51q78 0 123.5 68t45.5 166q0 115 -103 115q-75 0 -122 -66.5t-47 -167.5q0 -115 103 -115z'" + " stroke='green' stroke-width='3' />" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestFontError3.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestFontError3.png"));
}
@Test
public void testFontError4() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='900' width='700'>"
+ " <path d='M1011 -78q51 -11 84.5 -50.5t33.5 -93.5q0 -61 -43 -103t-104 -42q-60 0 -102 43q-43 42 -43 102q0 34 16 67q-2 0 -20 -4.5t-36.5 -8t-47 -7.5t-66.5 -6.5t-80 -2.5q-144 0 -248 27.5t-164.5 80.5t-88.5 123t-28 161q0 124 106 240l33 -30q-101 -101 -101 -206\n"
+ "q0 -335 487 -335q304 0 401 123q-39 -10 -68 -10q-95 3 -142 74q-50 -74 -136 -74q-68 0 -120 47t-52 125v92q0 75 -25.5 106t-58.5 31q-49 0 -92 -49t-43 -124q0 -19 3.5 -40.5t13.5 -53t34 -61.5t60 -48l-22 -25q-43 23 -72 58t-41 72.5t-16 63t-4 46.5q0 103 58.5 161.5\n"
+ "t130.5 58.5q24 0 47.5 -8t46.5 -26.5t37 -56t14 -89.5v-87q0 -79 37 -112t81 -33q40 0 69.5 22.5t29.5 57.5v322h83v-275q0 -55 27.5 -84.5t67.5 -29.5q60 0 95.5 52.5t35.5 125.5q0 20 -3 40t-12.5 50t-33 57.5t-57.5 46.5l29 25q57 -44 90.5 -105t33.5 -130\n"
+ "q0 -195 -115 -291zM972 -218q23 0 37.5 15t14.5 37q0 17 -16 32.5t-35 15.5q-30 0 -41.5 -12t-11.5 -36q0 -23 15 -37.5t37 -14.5zM970 -316q41 0 69.5 29t28.5 69q0 38 -19 60q1 -3 1 -13q0 -38 -25 -62.5t-60 -24.5q-33 0 -57.5 22.5t-28.5 55.5q-7 -20 -7 -38\n"
+ "q0 -41 29 -69.5t69 -28.5z'" + " stroke='green' stroke-width='3' />" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestFontError4.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestFontError4.png"));
}
@Test
public void testFontprintE25() {
Esvg.init();
EsvgFont font = EsvgFont.load(new Uri("FONTS", "FreeSherif.svg", "esvg"));
Weight out = font.render('E', 25);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_E25.png"));
out = font.render('e', 25);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_e25.png"));
out = font.render('É', 25);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_Ecute25.png"));
out = font.render('é', 25);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_ecute25.png"));
out = font.render('p', 25);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_p25.png"));
out = font.render('f', 25);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_f25.png"));
}
@Test
public void testFontprintSimpleText() {
Esvg.init();
EsvgFont font = EsvgFont.load(new Uri("FONTS", "FreeSherif.svg", "esvg"));
Weight out = font.render("Hello, How are you? VA // @ ê É", 100, false);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_Hello.png"));
out = font.render("Hello, How are you? VA // @ ê É", 100, true);
ConfigTest.generateAnImage(out, new Uri(ConfigTest.BASE_PATH + "testFontprint_Hello_withKerning.png"));
}
@Test
public void testFontRead() {
Esvg.init();
EsvgFont font = EsvgFont.load(new Uri("FONTS", "FreeSherif.svg", "esvg"));
}
}

View File

@ -0,0 +1,258 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Test;
class TestGradientLinear {
@Test
public void testTestGradientLinearDiag1() {
//@formatter:off
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
+ "<svg height='100' width='100'>\n"
+ " <defs>\n"
+ " <linearGradient id='grad2' x1='0%' y1='0%' x2='100%' y2='100%'>\n"
+ " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n"
+ " </linearGradient>\n"
+ " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n"
+ "</svg>\n";
//@formatter:on
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1.png"));
}
@Test
public void testTestGradientLinearDiag1Partiel() {
//@formatter:off
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
+ "<svg height='100' width='100'>\n"
+ " <defs>\n"
+ " <linearGradient id='grad2' x1='40%' y1='40%' x2='70%' y2='70%'>\n"
+ " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " </linearGradient>\n"
+ " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n"
+ "</svg>\n";
//@formatter:on
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1Partiel.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1Partiel.png"));
}
@Test
public void testTestGradientLinearDiag2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2.png"));
}
@Test
public void testTestGradientLinearDiag2Rotate0() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='0%' y1='50%' x2='100%' y2='50%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n"
+ " <ellipse transform='rotate (30 50 50)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate0.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate0.png"));
}
@Test
public void testTestGradientLinearDiag2Rotate1() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n"
+ " <ellipse transform='rotate (45 50 50)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate1.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate1.png"));
}
@Test
public void testTestGradientLinearDiag2Rotate2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n"
+ " <ellipse transform='rotate (-45 50 50)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate2.png"));
}
@Test
public void testTestGradientLinearDiag2scale() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n"
+ " <ellipse transform='scale (0.5 2.0) translate (10,-25)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2scale.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2scale.png"));
}
@Test
public void testTestGradientLinearHorizontal() {
//@formatter:off
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
+ "<svg height='100' width='100'>\n"
+ " <defs>\n"
+ " <linearGradient id='grad1' x1='0%' y1='0%' x2='100%' y2='0%'>\n"
+ " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n"
+ " </linearGradient>\n"
+ " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
+ "</svg>\n";
//@formatter:on
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearhorizontal.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearhorizontal.png"));
}
@Test
public void testTestGradientLinearInternalHref() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" + " <linearGradient id='grad2Values'>\n"
+ " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n"
+ " </linearGradient>\n" + " <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%' xlink:href='#grad2Values' />\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearinternalHref.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearinternalHref.png"));
}
@Test
public void testTestGradientLinearUnitBoxspreadNone() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%'>\n" + " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadNone.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadNone.png"));
}
@Test
public void testTestGradientLinearUnitBoxspreadPad() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='pad'>\n" + " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadPad.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadPad.png"));
}
@Test
public void testTestGradientLinearUnitBoxspreadReflect() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='reflect'>\n" + " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadReflect.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadReflect.png"));
}
@Test
public void testTestGradientLinearUnitBoxspreadRepeat() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='repeat'>\n" + " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadRepeat.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadRepeat.png"));
}
@Test
public void testTestGradientLinearUnitUserspreadNone() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' gradientUnits='userSpaceOnUse'>\n"
+ " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " </linearGradient>\n" + " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadNone.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadNone.png"));
}
@Test
public void testTestGradientLinearUnitUserspreadPad() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='pad' gradientUnits='userSpaceOnUse' >\n"
+ " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " </linearGradient>\n" + " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadPad.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadPad.png"));
}
@Test
public void testTestGradientLinearUnitUserspreadReflect() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >\n"
+ " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " </linearGradient>\n" + " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadReflect.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadReflect.png"));
}
@Test
public void testTestGradientLinearUnitUserspreadRepeate() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >\n"
+ " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " </linearGradient>\n" + " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadRepeate.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadRepeate.png"));
}
@Test
public void testTestGradientLinearVertical() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <linearGradient id='grad2' x1='0%' y1='0%' x2='0%' y2='100%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearvertical.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearvertical.png"));
}
}

View File

@ -0,0 +1,216 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Test;
class TestGradientRadial {
@Test
public void testTestGradientRadialCircle() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50%' cy='50%' r='50%' fx='50%' fy='50%'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='50' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialcircle.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialcircle.png"));
}
@Test
public void testTestGradientRadialFull() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50%' cy='50%' r='50%' fx='50%' fy='50%'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialfull.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialfull.png"));
}
@Test
public void testTestGradientRadialPartial() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad2' cx='20%' cy='30%' r='30%' fx='50%' fy='50%'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialpartial.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialpartial.png"));
}
@Test
public void testTestGradientRadialUnitBoxspreadNone() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadNone.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadNone.png"));
}
@Test
public void testTestGradientRadialUnitBoxspreadPad() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='pad'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadPad.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadPad.png"));
}
@Test
public void testTestGradientRadialUnitBoxspreadReflect() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='reflect'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadReflect.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadReflect.png"));
}
@Test
public void testTestGradientRadialUnitBoxspreadRepeat() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='repeat'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadRepeat.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadRepeat.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadNone() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50%' gradientUnits='userSpaceOnUse' >\n"
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n"
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadNone.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadNone.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadPad() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='pad' gradientUnits='userSpaceOnUse' >\n"
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n"
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPad.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPad.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadPadunCenter() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='pad' gradientUnits='userSpaceOnUse' >\n"
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n"
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPadunCenter.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPadunCenter.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadReflect() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >\n"
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n"
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflect.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflect.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadReflectunCenter() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >\n"
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n"
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflectunCenter.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflectunCenter.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadRepeat() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >\n"
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n"
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeat.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeat.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadRepeatout() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50' cy='50' r='24' fx='20' fy='40' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >\n"
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n"
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatout.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatout.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadRepeatunCenter() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >\n"
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n"
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter.png"));
}
@Test
public void testTestGradientRadialUnitUserspreadRepeatunCenter2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n"
+ " <radialGradient id='grad1' cx='50' cy='50' r='24' fx='60' fy='60' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >\n"
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n"
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter2.png"));
}
}

View File

@ -2,8 +2,6 @@ package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class TestJoin { class TestJoin {
@ -14,7 +12,7 @@ class TestJoin {
+ " stroke='green' stroke-width='5' fill='orange' stroke-linejoin='bevel'/>" + "</svg>"; + " stroke='green' stroke-width='5' fill='orange' stroke-linejoin='bevel'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelCornerCasePath.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelCornerCasePath.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelCornerCasePath.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelCornerCasePath.png"));
} }
@ -24,7 +22,7 @@ class TestJoin {
+ " <polyline points='80,20 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>"; + " <polyline points='80,20 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft1.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft1.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft1.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft1.png"));
} }
@ -34,7 +32,7 @@ class TestJoin {
+ " <polyline points='80,80 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>"; + " <polyline points='80,80 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft2.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft2.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft2.png"));
} }
@ -44,7 +42,7 @@ class TestJoin {
+ " <polyline points='20,80 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>"; + " <polyline points='20,80 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft3.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft3.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft3.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft3.png"));
} }
@ -54,7 +52,7 @@ class TestJoin {
+ " <polyline points='20,20 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>"; + " <polyline points='20,20 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft4.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft4.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft4.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelLeft4.png"));
} }
@ -64,7 +62,7 @@ class TestJoin {
+ " <polyline points='20,20 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>"; + " <polyline points='20,20 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight1.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight1.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight1.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight1.png"));
} }
@ -74,7 +72,7 @@ class TestJoin {
+ " <polyline points='20,80 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>"; + " <polyline points='20,80 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight2.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight2.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight2.png"));
} }
@ -84,7 +82,7 @@ class TestJoin {
+ " <polyline points='80,80 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>"; + " <polyline points='80,80 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight3.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight3.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight3.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight3.png"));
} }
@ -94,7 +92,7 @@ class TestJoin {
+ " <polyline points='80,20 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>"; + " <polyline points='80,20 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='bevel'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight4.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight4.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight4.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinbevelRight4.png"));
} }
@ -105,7 +103,7 @@ class TestJoin {
+ " stroke='green' stroke-width='5' fill='orange' stroke-linejoin='miter'/>" + "</svg>"; + " stroke='green' stroke-width='5' fill='orange' stroke-linejoin='miter'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterCornerCasePath.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterCornerCasePath.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterCornerCasePath.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterCornerCasePath.png"));
} }
@ -116,7 +114,7 @@ class TestJoin {
+ " stroke='green' stroke-width='5' fill='orange' stroke-linejoin='miter' stroke-miterlimit='0.3'/>" + "</svg>"; + " stroke='green' stroke-width='5' fill='orange' stroke-linejoin='miter' stroke-miterlimit='0.3'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterCornerCasePathLimit.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterCornerCasePathLimit.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterCornerCasePathLimit.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterCornerCasePathLimit.png"));
} }
@ -126,7 +124,7 @@ class TestJoin {
+ " <polyline points='80,20 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>"; + " <polyline points='80,20 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft1.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft1.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft1.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft1.png"));
} }
@ -136,7 +134,7 @@ class TestJoin {
+ " <polyline points='80,80 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>"; + " <polyline points='80,80 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft2.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft2.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft2.png"));
} }
@ -146,7 +144,7 @@ class TestJoin {
+ " <polyline points='20,80 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>"; + " <polyline points='20,80 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft3.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft3.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft3.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft3.png"));
} }
@ -158,7 +156,7 @@ class TestJoin {
+ " <polyline points='20,20 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>"; + " <polyline points='20,20 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft4.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft4.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft4.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLeft4.png"));
} }
@ -168,7 +166,7 @@ class TestJoin {
+ " <polyline points='10,10 25,25 10,40' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>"; + " <polyline points='10,10 25,25 10,40' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit1.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit1.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit1.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit1.png"));
} }
@ -178,7 +176,7 @@ class TestJoin {
+ " <polyline points='10,10 50,25 10,40' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>"; + " <polyline points='10,10 50,25 10,40' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit2.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit2.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit2.png"));
} }
@ -188,7 +186,7 @@ class TestJoin {
+ " <polyline points='10,10 75,25 10,40' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>"; + " <polyline points='10,10 75,25 10,40' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit3.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit3.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit3.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit3.png"));
} }
@ -198,7 +196,7 @@ class TestJoin {
+ " <polyline points='10,10 90,25 10,40' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>"; + " <polyline points='10,10 90,25 10,40' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit4.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit4.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit4.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterLimit4.png"));
} }
@ -208,7 +206,7 @@ class TestJoin {
+ " <polyline points='20,20 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>"; + " <polyline points='20,20 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight1.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight1.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight1.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight1.png"));
} }
@ -218,7 +216,7 @@ class TestJoin {
+ " <polyline points='20,80 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>"; + " <polyline points='20,80 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight2.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight2.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight2.png"));
} }
@ -228,7 +226,7 @@ class TestJoin {
+ " <polyline points='80,80 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>"; + " <polyline points='80,80 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight3.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight3.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight3.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight3.png"));
} }
@ -238,7 +236,7 @@ class TestJoin {
+ " <polyline points='80,20 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>"; + " <polyline points='80,20 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='miter'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight4.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight4.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight4.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinmiterRight4.png"));
} }
@ -251,7 +249,7 @@ class TestJoin {
+ " stroke='green' stroke-width='5' fill='orange' stroke-linejoin='round'/>" + "</svg>"; + " stroke='green' stroke-width='5' fill='orange' stroke-linejoin='round'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundCornerCasePath.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundCornerCasePath.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundCornerCasePath.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundCornerCasePath.png"));
} }
@ -261,7 +259,7 @@ class TestJoin {
+ " <polyline points='80,20 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>"; + " <polyline points='80,20 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft1.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft1.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft1.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft1.png"));
} }
@ -271,7 +269,7 @@ class TestJoin {
+ " <polyline points='80,80 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>"; + " <polyline points='80,80 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft2.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft2.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft2.png"));
} }
@ -281,7 +279,7 @@ class TestJoin {
+ " <polyline points='20,80 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>"; + " <polyline points='20,80 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft3.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft3.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft3.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft3.png"));
} }
@ -291,7 +289,7 @@ class TestJoin {
+ " <polyline points='20,20 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>"; + " <polyline points='20,20 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft4.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft4.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft4.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundLeft4.png"));
} }
@ -301,7 +299,7 @@ class TestJoin {
+ " <polyline points='20,20 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>"; + " <polyline points='20,20 50,50 20,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight1.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight1.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight1.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight1.png"));
} }
@ -311,7 +309,7 @@ class TestJoin {
+ " <polyline points='20,80 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>"; + " <polyline points='20,80 50,50 80,80' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight2.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight2.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight2.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight2.png"));
} }
@ -321,7 +319,7 @@ class TestJoin {
+ " <polyline points='80,80 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>"; + " <polyline points='80,80 50,50 80,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight3.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight3.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight3.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight3.png"));
} }
@ -331,7 +329,7 @@ class TestJoin {
+ " <polyline points='80,20 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>"; + " <polyline points='80,20 50,50 20,20' stroke='green' stroke-width='20' fill='none' stroke-linejoin='round'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight4.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight4.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight4.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestJoinroundRight4.png"));
} }
} }

View File

@ -2,8 +2,6 @@ package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class TestLine { class TestLine {
@ -13,7 +11,7 @@ class TestLine {
+ "</svg>"; + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestLinestroke.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestLinestroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestLinestroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestLinestroke.png"));
} }
} }

View File

@ -2,8 +2,6 @@ package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class TestPath { class TestPath {
@ -15,7 +13,7 @@ class TestPath {
+ "</svg>"; + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPatharc.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPatharc.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPatharc.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPatharc.png"));
} }
@ -24,7 +22,7 @@ class TestPath {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <path d='m 50,50 q -30,1 -20,20 z'" + " fill='red' />" + "</svg>"; String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <path d='m 50,50 q -30,1 -20,20 z'" + " fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathbezierCurveTo.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathbezierCurveTo.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathbezierCurveTo.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathbezierCurveTo.png"));
} }
@ -33,7 +31,7 @@ class TestPath {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <path d='m 50,50 t -20,30 t 30,-20 z'" + " fill='red' />" + "</svg>"; String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <path d='m 50,50 t -20,30 t 30,-20 z'" + " fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathbezierSmoothCurveTo.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathbezierSmoothCurveTo.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathbezierSmoothCurveTo.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathbezierSmoothCurveTo.png"));
} }
@ -42,7 +40,7 @@ class TestPath {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <path d='m 50,50 c -30,0 -30,1 -20,20 z'" + " fill='red' />" + "</svg>"; String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <path d='m 50,50 c -30,0 -30,1 -20,20 z'" + " fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathcurveTo.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathcurveTo.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathcurveTo.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathcurveTo.png"));
} }
@ -54,7 +52,7 @@ class TestPath {
+ " id='path3421'\n" + " inkscape:connector-curvature='0' />\n" + "</svg>"; + " id='path3421'\n" + " inkscape:connector-curvature='0' />\n" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathendpathbordercase.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathendpathbordercase.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathendpathbordercase.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathendpathbordercase.png"));
} }
@ -65,7 +63,7 @@ class TestPath {
+ " fill='red' />" + "</svg>"; + " fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathfill.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathfill.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathfill.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathfill.png"));
} }
@ -76,7 +74,7 @@ class TestPath {
+ " stroke='green' stroke-width='3' fill='red' />" + "</svg>"; + " stroke='green' stroke-width='3' fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathfillandstroke.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathfillandstroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathfillandstroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathfillandstroke.png"));
} }
@ -85,7 +83,7 @@ class TestPath {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <path d='m 50,50 s -30,0 -20,20 z'" + " fill='red' />" + "</svg>"; String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <path d='m 50,50 s -30,0 -20,20 z'" + " fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathsmoothCurveTo.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathsmoothCurveTo.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathsmoothCurveTo.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathsmoothCurveTo.png"));
} }
@ -96,7 +94,7 @@ class TestPath {
+ " stroke='green' stroke-width='3' />" + "</svg>"; + " stroke='green' stroke-width='3' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathstroke.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPathstroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathstroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPathstroke.png"));
} }

View File

@ -2,8 +2,6 @@ package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class TestPolygon { class TestPolygon {
@ -12,7 +10,7 @@ class TestPolygon {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <polygon points='50,10 90,50 10,80' fill='red' />" + "</svg>"; String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <polygon points='50,10 90,50 10,80' fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPolygonfill.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPolygonfill.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPolygonfill.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPolygonfill.png"));
} }
@ -22,7 +20,7 @@ class TestPolygon {
+ " <polygon points='50,10 90,50 10,80' stroke='green' stroke-width='3' fill='red' />" + "</svg>"; + " <polygon points='50,10 90,50 10,80' stroke='green' stroke-width='3' fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPolygonfillandstroke.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPolygonfillandstroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPolygonfillandstroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPolygonfillandstroke.png"));
} }
@ -32,7 +30,7 @@ class TestPolygon {
+ "</svg>"; + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPolygonstroke.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPolygonstroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPolygonstroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPolygonstroke.png"));
} }
} }

View File

@ -2,8 +2,6 @@ package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class TestPolyline { class TestPolyline {
@ -13,7 +11,7 @@ class TestPolyline {
+ "</svg>"; + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPolyLinefill.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPolyLinefill.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPolyLinefill.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPolyLinefill.png"));
} }
@ -23,7 +21,7 @@ class TestPolyline {
+ " <polyline points='20,20 40,25 60,40 80,90 90,50 5,90' stroke='green' stroke-width='3' fill='orange' />" + "</svg>"; + " <polyline points='20,20 40,25 60,40 80,90 90,50 5,90' stroke='green' stroke-width='3' fill='orange' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPolyLinefillandstroke.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPolyLinefillandstroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPolyLinefillandstroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPolyLinefillandstroke.png"));
} }
@ -33,7 +31,7 @@ class TestPolyline {
+ " <polyline points='20,20 40,25 60,40 80,90 90,50 5,90' stroke='green' stroke-width='3' fill='none' />" + "</svg>"; + " <polyline points='20,20 40,25 60,40 80,90 90,50 5,90' stroke='green' stroke-width='3' fill='none' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPolyLinestroke.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestPolyLinestroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPolyLinestroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestPolyLinestroke.png"));
} }
} }

View File

@ -2,8 +2,6 @@ package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class TestRectangle { class TestRectangle {
@ -13,7 +11,7 @@ class TestRectangle {
+ "</svg>"; + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestRectanglecornedfill.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestRectanglecornedfill.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestRectanglecornedfill.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestRectanglecornedfill.png"));
} }
@ -23,7 +21,7 @@ class TestRectangle {
+ " <rect x='12.5' y='12.5' width='75' height='50' rx='20' ry='20' stroke='green' stroke-width='3' fill='red' />" + "</svg>"; + " <rect x='12.5' y='12.5' width='75' height='50' rx='20' ry='20' stroke='green' stroke-width='3' fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestRectanglecornedfillandstroke.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestRectanglecornedfillandstroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestRectanglecornedfillandstroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestRectanglecornedfillandstroke.png"));
} }
@ -33,7 +31,7 @@ class TestRectangle {
+ " <rect x='12.5' y='12.5' width='75' height='50' rx='20' ry='20' stroke='green' stroke-width='3' />" + "</svg>"; + " <rect x='12.5' y='12.5' width='75' height='50' rx='20' ry='20' stroke='green' stroke-width='3' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestRectanglecornedstroke.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestRectanglecornedstroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestRectanglecornedstroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestRectanglecornedstroke.png"));
} }
@ -42,7 +40,7 @@ class TestRectangle {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <rect x='12.5' y='12.5' width='75' height='50' fill='red' />" + "</svg>"; String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <rect x='12.5' y='12.5' width='75' height='50' fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestRectanglefill.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestRectanglefill.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestRectanglefill.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestRectanglefill.png"));
} }
@ -52,7 +50,7 @@ class TestRectangle {
+ " <rect x='12.5' y='12.5' width='75' height='50' stroke='green' stroke-width='3' fill='red' />" + "</svg>"; + " <rect x='12.5' y='12.5' width='75' height='50' stroke='green' stroke-width='3' fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestRectanglefillandstroke.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestRectanglefillandstroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestRectanglefillandstroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestRectanglefillandstroke.png"));
} }
@ -62,7 +60,7 @@ class TestRectangle {
+ " <rect x='12.5' y='12.5' width='75' height='50' stroke='green' stroke-width='3' />" + "</svg>"; + " <rect x='12.5' y='12.5' width='75' height='50' stroke='green' stroke-width='3' />" + "</svg>";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestRectanglestroke.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestRectanglestroke.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestRectanglestroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestRectanglestroke.png"));
} }
} }

View File

@ -3,8 +3,6 @@ package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
class TestStyle { class TestStyle {
public void testTestExternWorddown() { public void testTestExternWorddown() {
@ -118,7 +116,7 @@ class TestStyle {
+ "</svg>\n"; + "</svg>\n";
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestExternworddown.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestExternworddown.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestExternworddown.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestExternworddown.png"));
} }
} }

View File

@ -2,10 +2,8 @@ package test.atriasoft.esvg;
import org.atriasoft.esvg.Esvg; import org.atriasoft.esvg.Esvg;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.atriasoft.etk.Uri;
class TestText { class TestText {
@Test @Test
@ -45,7 +43,7 @@ class TestText {
//@formatter:on //@formatter:on
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestTextFull.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestTextFull.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestTextFull.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestTextFull.png"));
} }
@ -113,7 +111,7 @@ class TestText {
//@formatter:on //@formatter:on
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestTextFull.svg"), data.replace("'", "\""))); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestTextFull.svg"), data.replace("'", "\""));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestTextFull.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestTextFull.png"));
} }
} }

View File