[DEV] some updates

This commit is contained in:
Edouard DUPIN 2025-08-10 00:50:06 +02:00
parent cba9f75a77
commit b46878696f
2 changed files with 34 additions and 303 deletions

View File

@ -1,277 +0,0 @@
package org.atriasoft.esvg;
import org.atriasoft.egami.ImageByte;
import org.atriasoft.egami.ToolImage;
import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.etk.Color;
import org.atriasoft.etk.Configs;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Graphic context is used to manage dynamic
* @author heero
*
*/
public class GraphicContext {
static final Logger LOGGER = LoggerFactory.getLogger(GraphicContext.class);
private EsvgDocument document = new EsvgDocument();
PaintState paintState;
private PathModel path = null;
private Vector2i size = Vector2i.VALUE_32;
public GraphicContext() {
clear();
}
public Vector2i calculateTextSize(final String data) {
return FontCache.getFont(Configs.getConfigFonts().getName(), false, false)
.calculateTextSize(Configs.getConfigFonts().getSize(), data);
}
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 int getTextHeight() {
return getTextHeight(Configs.getConfigFonts().getSize());
}
public int getTextSize() {
return Configs.getConfigFonts().getSize();
}
public int getTextHeight(final float height) {
return FontCache.getFont(Configs.getConfigFonts().getName(), false, false)
.calculateFontRealHeight((int) height);
}
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) {
LOGGER.error("Empty path... Need call pathStart() before");
return;
}
this.path.lineTo(false, pos);
}
public void pathLineTo(final Vector2f pos) {
if (this.path == null) {
LOGGER.error("Empty path... Need call pathStart() before");
return;
}
this.path.lineTo(true, pos);
}
public void pathMove(final Vector2f pos) {
if (this.path == null) {
LOGGER.error("Empty path... Need call pathStart() before");
return;
}
this.path.moveTo(false, pos);
}
public void pathMoveTo(final Vector2f pos) {
if (this.path == null) {
LOGGER.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) {
LOGGER.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) {
LOGGER.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) {
LOGGER.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) {
LOGGER.error("Path not empty ... Need call pathStart() before");
pathStop();
}
this.document.addElement(new Rectangle(position, width, this.paintState.clone()));
}
public ImageByte render() {
return ToolImage.convertImageByte(this.document.renderImageFloatRGBA(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, Configs.getConfigFonts().getName(), height, data, this.paintState.clone()));
}
public void text(final Vector2f position, final String data) {
text(position, Configs.getConfigFonts().getSize(), data);
}
}

View File

@ -14,6 +14,8 @@ 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
@ -21,23 +23,24 @@ import org.atriasoft.etk.math.Vector2i;
* @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;
@ -48,7 +51,7 @@ 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;
@ -130,31 +133,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()) {
@ -178,23 +181,24 @@ public class Renderer {
*/ */
final float a1 = integration.a(); // alpha over final float a1 = integration.a(); // alpha over
final float a0 = base.a(); // alpha under final float a0 = base.a(); // alpha under
final float a = a1 + a0 * (1 - a1); final float a = a1 + a0 * (1 - a1);
final float aCalc = a != 0 ? 1 / a : 1; final float aCalc = a != 0 ? 1 / a : 1;
final float r = (integration.r() * a1 + base.r() * a0 * (1 - a1)) * aCalc; 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 g = (integration.g() * a1 + base.g() * a0 * (1 - a1)) * aCalc;
final float b = (integration.b() * a1 + base.b() * a0 * (1 - a1)) * aCalc; final float b = (integration.b() * a1 + base.b() * a0 * (1 - a1)) * aCalc;
return new Color(r, g, b, a); return new Color(r, g, b, a);
} }
public void print( public void print(
final Weight weightFill, final Weight weightFill,
final DynamicColor colorFill, final DynamicColor colorFill,
final Weight weightStroke, final Weight weightStroke,
final DynamicColor colorStroke, final DynamicColor colorStroke,
final float opacity) { 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);
@ -205,14 +209,16 @@ 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); final Vector2i pos = new Vector2i(xxx, yyy);
final float valueFill = weightFill.get(pos); final float valueFill = weightFill.get(pos);
final float valueStroke = weightStroke.get(pos); final 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);
@ -237,9 +243,9 @@ 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 final DynamicColorSpecial tmpColor) {
final SegmentList listSegment = new SegmentList(); final SegmentList listSegment = new SegmentList();
@ -266,20 +272,22 @@ 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) {
@ -288,5 +296,5 @@ public class Renderer {
this.buffer = new ImageFloatRGBA(this.size.multiply(this.factor)); this.buffer = new ImageFloatRGBA(this.size.multiply(this.factor));
} }
} }
} }