diff --git a/src/main/org/atriasoft/esvg/Base.java b/src/main/org/atriasoft/esvg/Base.java index 6c12123..86ec343 100644 --- a/src/main/org/atriasoft/esvg/Base.java +++ b/src/main/org/atriasoft/esvg/Base.java @@ -238,7 +238,7 @@ public class Base { } else { if (content.length() != 0) { this.paint.stroke = parseColor(content); - LOGGER.error("Parse color : " + this.paint.stroke); + //LOGGER.trace("Parse color : " + this.paint.stroke); } content = element.getAttribute("stroke-width", ""); if (content.length() != 0) { @@ -332,9 +332,9 @@ public class Base { if (inputString.length() == 0) { return; } - LOGGER.trace("indexOf transform : '" + inputString + "'"); + //LOGGER.trace("indexOf transform : '" + inputString + "'"); inputString = inputString.replace(',', ' '); - LOGGER.trace("indexOf transform : '" + inputString + "'"); + //LOGGER.trace("indexOf transform : '" + inputString + "'"); // need to indexOf elements in order ... String data = Base.extractTransformData(inputString, "matrix"); if (data.length() != 0) { @@ -352,7 +352,7 @@ public class Base { if (elements != null) { this.transformMatrix = this.transformMatrix .multiply(Matrix2x3f.createTranslate(new Vector2f(elements[0], elements[1]))); - LOGGER.trace("Translate : " + elements[0] + ", " + elements[1]); + //LOGGER.trace("Translate : " + elements[0] + ", " + elements[1]); } else { final float elem = Float.parseFloat(data); this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createTranslate(new Vector2f(elem, 0))); @@ -364,7 +364,7 @@ public class Base { if (elements != null) { this.transformMatrix = this.transformMatrix .multiply(Matrix2x3f.createScale(new Vector2f(elements[0], elements[1]))); - LOGGER.trace("Translate : " + elements[0] + ", " + elements[1]); + //LOGGER.trace("Translate : " + elements[0] + ", " + elements[1]); } else { final float elem = Float.parseFloat(data); this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createScale(elem)); diff --git a/src/main/org/atriasoft/esvg/EsvgDocument.java b/src/main/org/atriasoft/esvg/EsvgDocument.java index 05af93b..388ac92 100644 --- a/src/main/org/atriasoft/esvg/EsvgDocument.java +++ b/src/main/org/atriasoft/esvg/EsvgDocument.java @@ -27,6 +27,7 @@ public class EsvgDocument extends Base { private String title = ""; //!< sub-element list private Uri uri = null; //!< reference elements ... private String version = "0.0"; + private static final boolean envDisplayRefs = "true".equals(System.getenv("ESQG_DISPLAY_REFS")); public EsvgDocument() { @@ -380,7 +381,7 @@ public class EsvgDocument extends Base { } else { this.size = Vector2f.clipInt(this.size); } - if (!isReference) { + if (envDisplayRefs && !isReference) { displayDebug(); } return true; diff --git a/src/main/org/atriasoft/esvg/Renderer.java b/src/main/org/atriasoft/esvg/Renderer.java index ee459de..cc7a978 100644 --- a/src/main/org/atriasoft/esvg/Renderer.java +++ b/src/main/org/atriasoft/esvg/Renderer.java @@ -53,32 +53,33 @@ public class Renderer { if (!this.visualDebug) { return; } - Vector2i dynamicSize = this.size.multiply(this.factor); + final Vector2i dynamicSize = this.size.multiply(this.factor); // for each lines: for (int yyy = 0; yyy < dynamicSize.y(); ++yyy) { // Reduce the number of lines in the subsampling parsing: - List availlableSegmentPixel = new ArrayList<>(); - for (Segment it : listSegment.data) { + final List availlableSegmentPixel = new ArrayList<>(); + for (final Segment it : listSegment.data) { if (it.p0.y() * this.factor <= yyy + 1 && it.p1.y() * this.factor >= (yyy)) { availlableSegmentPixel.add(it); } } //find all the segment that cross the middle of the line of the center of the pixel line: - float subSamplingCenterPos = yyy + 0.5f; - List availlableSegment = new ArrayList<>(); + final float subSamplingCenterPos = yyy + 0.5f; + final List availlableSegment = new ArrayList<>(); // find in the subList ... - for (Segment it : availlableSegmentPixel) { - if (it.p0.y() * this.factor <= subSamplingCenterPos && it.p1.y() * this.factor >= subSamplingCenterPos) { + for (final Segment it : availlableSegmentPixel) { + if (it.p0.y() * this.factor <= subSamplingCenterPos + && it.p1.y() * this.factor >= subSamplingCenterPos) { availlableSegment.add(it); } } // x position, angle - for (Segment it : availlableSegment) { - Vector2f delta = it.p0.multiply(this.factor).less(it.p1.multiply(this.factor)); + for (final Segment it : availlableSegment) { + final Vector2f delta = it.p0.multiply(this.factor).less(it.p1.multiply(this.factor)); // x = coefficent*y+bbb; - float coefficient = delta.x() / delta.y(); - float bbb = it.p0.x() * this.factor - coefficient * it.p0.y() * this.factor; - float xpos = coefficient * subSamplingCenterPos + bbb; + final float coefficient = delta.x() / delta.y(); + final float bbb = it.p0.x() * this.factor - coefficient * it.p0.y() * this.factor; + final float xpos = coefficient * subSamplingCenterPos + bbb; if (xpos >= 0 && xpos < dynamicSize.x() && yyy >= 0 && yyy < dynamicSize.y()) { if (it.direction == 1.0f) { this.buffer.setColor((int) xpos, yyy, Color.BLUE); @@ -91,32 +92,34 @@ public class Renderer { // for each colomn: for (int xxx = 0; xxx < dynamicSize.x(); ++xxx) { // Reduce the number of lines in the subsampling parsing: - List availlableSegmentPixel = new ArrayList<>(); - for (Segment it : listSegment.data) { - 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))) { + final List availlableSegmentPixel = new ArrayList<>(); + for (final Segment it : listSegment.data) { + 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))) { availlableSegmentPixel.add(it); } } //find all the segment that cross the middle of the line of the center of the pixel line: - float subSamplingCenterPos = xxx + 0.5f; - List availlableSegment = new ArrayList<>(); + final float subSamplingCenterPos = xxx + 0.5f; + final List availlableSegment = new ArrayList<>(); // find in the subList ... - for (Segment it : availlableSegmentPixel) { + for (final Segment it : availlableSegmentPixel) { if ((it.p0.x() * this.factor <= subSamplingCenterPos && it.p1.x() * this.factor >= subSamplingCenterPos) - || (it.p0.x() * this.factor >= subSamplingCenterPos && it.p1.x() * this.factor <= subSamplingCenterPos)) { + || (it.p0.x() * this.factor >= subSamplingCenterPos + && it.p1.x() * this.factor <= subSamplingCenterPos)) { availlableSegment.add(it); } } // x position, angle - for (Segment it : availlableSegment) { - Vector2f delta = it.p0.multiply(this.factor).less(it.p1.multiply(this.factor)); + for (final Segment it : availlableSegment) { + final Vector2f delta = it.p0.multiply(this.factor).less(it.p1.multiply(this.factor)); // x = coefficent*y+bbb; if (delta.x() == 0) { continue; } - float coefficient = delta.y() / delta.x(); - float bbb = it.p0.y() * this.factor - coefficient * it.p0.x() * this.factor; - float ypos = coefficient * subSamplingCenterPos + bbb; + final float coefficient = delta.y() / delta.x(); + final float bbb = it.p0.y() * this.factor - coefficient * it.p0.x() * this.factor; + final float ypos = coefficient * subSamplingCenterPos + bbb; if (ypos >= 0 && ypos < dynamicSize.y() && xxx >= 0 && xxx < dynamicSize.y()) { if (it.direction == 1.0f) { this.buffer.setColor(xxx, (int) ypos, Color.BLUE); @@ -160,6 +163,7 @@ public class Renderer { base = result; } */ + /* 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 b = (integration.a() * integration.b() + base.a() * (1.0f - integration.a()) * base.b()); @@ -171,9 +175,26 @@ public class Renderer { b *= reverse; } 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(final Weight weightFill, final DynamicColor colorFill, final Weight weightStroke, final DynamicColor colorStroke, final float opacity) { + public void print( + final Weight weightFill, + final DynamicColor colorFill, + final Weight weightStroke, + final DynamicColor colorStroke, + final float opacity) { if (colorFill != null) { //colorFill.setViewPort(Pair(new Vector2f(0,0), Vector2f(sizeX, sizeY))); colorFill.generate(this.document); @@ -186,9 +207,9 @@ public class Renderer { for (int yyy = 0; yyy < this.size.y(); ++yyy) { for (int xxx = 0; xxx < this.size.x(); ++xxx) { - Vector2i pos = new Vector2i(xxx, yyy); - float valueFill = weightFill.get(pos); - float valueStroke = weightStroke.get(pos); + final Vector2i pos = new Vector2i(xxx, yyy); + final float valueFill = weightFill.get(pos); + final float valueStroke = weightStroke.get(pos); // calculate merge of stroke and fill value: Color intermediateColorFill = Color.NONE; @@ -206,8 +227,8 @@ public class Renderer { if (Renderer.DEBUG_MODE) { for (int deltaY = 0; deltaY < this.factor; deltaY++) { for (int deltaX = 0; deltaX < this.factor; deltaX++) { - int idx = xxx * this.factor + deltaX; - int idy = yyy * this.factor + deltaY; + final int idx = xxx * this.factor + deltaX; + final int idy = yyy * this.factor + deltaY; this.buffer.mergeColor(idx, idy, intermediateColor); } } @@ -220,13 +241,19 @@ public class Renderer { if (Renderer.DEBUG_MODE) { // display the gradient position: - if (colorFill instanceof DynamicColorSpecial tmpColor) { - SegmentList listSegment = new SegmentList(); + if (colorFill instanceof final DynamicColorSpecial tmpColor) { + final SegmentList listSegment = new SegmentList(); // Display bounding box - listSegment.addSegment(new Point(tmpColor.viewPort.first), 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(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.addSegment(new Point(tmpColor.viewPort.first), + 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(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); // display the gradient axis listSegment.addSegment(new Point(tmpColor.pos1), new Point(tmpColor.pos2), false); diff --git a/src/main/org/atriasoft/esvg/render/PathModel.java b/src/main/org/atriasoft/esvg/render/PathModel.java index ae4b7e3..8f0d7a6 100644 --- a/src/main/org/atriasoft/esvg/render/PathModel.java +++ b/src/main/org/atriasoft/esvg/render/PathModel.java @@ -20,7 +20,7 @@ import org.slf4j.LoggerFactory; public class PathModel { static final Logger LOGGER = LoggerFactory.getLogger(PathModel.class); - + private static void interpolateCubicBezier( final List listPoint, final int recurtionMax, @@ -37,11 +37,11 @@ public class PathModel { final Vector2f pos12 = pos1.add(pos2).multiply(0.5f); final Vector2f pos23 = pos2.add(pos3).multiply(0.5f); final Vector2f pos34 = pos3.add(pos4).multiply(0.5f); - + final Vector2f delta = pos4.less(pos1); final 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())); - + if ((distance2 + distance3) * (distance2 + distance3) < threshold * delta.length2()) { listPoint.add(new Point(pos4, type)); return; @@ -49,13 +49,13 @@ public class PathModel { final Vector2f pos123 = pos12.add(pos23).multiply(0.5f); final Vector2f pos234 = pos23.add(pos34).multiply(0.5f); final Vector2f pos1234 = pos123.add(pos234).multiply(0.5f); - + PathModel.interpolateCubicBezier(listPoint, recurtionMax, threshold, pos1, pos12, pos123, pos1234, level + 1, PointType.interpolation); PathModel.interpolateCubicBezier(listPoint, recurtionMax, threshold, pos1234, pos234, pos34, pos4, level + 1, type); } - + /** * add indentation of the string input. * @param data String where the indentation is done. @@ -68,55 +68,55 @@ public class PathModel { } return data.toString(); } - + private static float vectorAngle(Vector2f uuu, Vector2f vvv) { uuu = uuu.safeNormalize(); vvv = vvv.safeNormalize(); return (float) Math.atan2(uuu.cross(vvv), uuu.dot(vvv)); } - + SegmentList debugInformation; - + public List listElement = new ArrayList<>(); - + public PathModel() { - + } - + public void bezierCurveTo(final boolean relative, final Vector2f pos1, final Vector2f pos) { this.listElement.add(new ElementBezierCurveTo(relative, pos1, pos)); } - + public void bezierSmoothCurveTo(final boolean relative, final Vector2f pos) { this.listElement.add(new ElementBezierSmoothCurveTo(relative, pos)); } - + public void clear() { this.listElement.clear(); } - + public void close() { close(false); } - + public void close(final boolean relative) { this.listElement.add(new ElementClose(relative)); } - + public void curveTo(final boolean relative, final Vector2f pos1, final Vector2f pos2, final Vector2f pos) { this.listElement.add(new ElementCurveTo(relative, pos1, pos2, pos)); } - + public void display(final int spacing) { - LOGGER.warn(PathModel.spacingDist(spacing) + "Path"); + //LOGGER.trace(PathModel.spacingDist(spacing) + "Path"); for (final Element it : this.listElement) { if (it == null) { continue; } - LOGGER.warn(PathModel.spacingDist(spacing + 1) + it); + //LOGGER.trace(PathModel.spacingDist(spacing + 1) + it); } } - + public Weight drawFill( final Vector2i size, final Matrix2x3f basicTrans, @@ -133,7 +133,7 @@ public class PathModel { weight.generate(size, config.numberOfScanline(), listSegment); return weight; } - + public Weight drawStroke( final Vector2i size, final Matrix2x3f basicTrans, @@ -151,7 +151,7 @@ public class PathModel { weight.generate(size, config.numberOfScanline(), listSegment); return weight; } - + public void ellipticTo( final boolean relative, final Vector2f radius, @@ -161,15 +161,15 @@ public class PathModel { final Vector2f pos) { this.listElement.add(new ElementElliptic(relative, radius, angle, largeArcFlag, sweepFlag, pos)); } - + public PointList generateListPoints(final int level) { return generateListPoints(level, 10); } - + public PointList generateListPoints(final int level, final int recurtionMax) { return generateListPoints(level, recurtionMax, 0.25f); } - + public PointList generateListPoints(final int level, final int recurtionMax, final float threshold) { LOGGER.trace(PathModel.spacingDist(level) + "Generate List Points ... from a path"); final PointList out = new PointList(); @@ -361,7 +361,7 @@ public class PathModel { + tmpIt.largeArcFlag); LOGGER.info("TODO:" + PathModel.spacingDist(level + 1) + " this.sweepFlag=" + tmpIt.sweepFlag); - + final Vector2f lastPosStore = lastPosition; if (!it.getRelative()) { lastPosition = Vector2f.ZERO; @@ -369,7 +369,7 @@ public class PathModel { final Vector2f pos = lastPosition.add(it.getPos()); final float rotationX = tmpIt.angle * ((float) Math.PI / 180.0f); Vector2f radius = tmpIt.getPos1(); - + //this.debugInformation.addSegment(lastPosStore, pos); Vector2f delta = lastPosStore.less(pos); float ddd = delta.length(); @@ -442,7 +442,7 @@ public class PathModel { // Split arc into max 90 degree segments. // 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; - + final float hda = (deltaTheta / ndivs) * 0.5f; float kappa = (float) Math.abs(4.0f / 3.0f * (1.0f - Math.cos(hda)) / Math.sin(hda)); if (deltaTheta < 0.0f) { @@ -494,29 +494,29 @@ public class PathModel { out.display(); return out; } - + public void lineTo(final boolean relative, final Vector2f pos) { this.listElement.add(new ElementLineTo(relative, pos)); } - + public void lineToH(final boolean relative, final float posX) { this.listElement.add(new ElementLineToH(relative, posX)); } - + public void lineToV(final boolean relative, final float posY) { this.listElement.add(new ElementLineToV(relative, posY)); } - + public void moveTo(final boolean relative, final Vector2f pos) { this.listElement.add(new ElementMoveTo(relative, pos)); } - + public void smoothCurveTo(final boolean relative, final Vector2f pos2, final Vector2f pos) { this.listElement.add(new ElementSmoothCurveTo(relative, pos2, pos)); } - + public void stop() { this.listElement.add(new ElementStop()); } - + }