[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.Vector2f;
import org.atriasoft.etk.math.Vector2i;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file
* @author Edouard DUPIN
@ -21,23 +23,24 @@ import org.atriasoft.etk.math.Vector2i;
* @license MPL v2.0 (see license file)
*/
public class Renderer {
private static final Logger LOGGER = LoggerFactory.getLogger(Renderer.class);
private static final boolean DEBUG_MODE = false;
protected ImageFloatRGBA buffer; // for debug
protected EsvgDocument document; // for debug
private int factor = 1;
protected int interpolationRecurtionMax = 10;
protected float interpolationThreshold = 0.25f;
protected int nbSubScanLine = 8;
protected Vector2i size;
private final boolean visualDebug = false;
public Renderer(final Vector2i size, final EsvgDocument document) {
this(size, document, false);
}
public Renderer(final Vector2i size, final EsvgDocument document, final boolean visualDebug) {
this.size = size;
this.document = document;
@ -48,7 +51,7 @@ public class Renderer {
}
setSize(size);
}
void addDebugSegment(final SegmentList listSegment) {
if (!this.visualDebug) {
return;
@ -130,31 +133,31 @@ public class Renderer {
}
}
}
ImageFloatRGBA getData() {
return this.buffer;
}
int getInterpolationRecurtionMax() {
return this.interpolationRecurtionMax;
}
float getInterpolationThreshold() {
return this.interpolationThreshold;
}
public EsvgDocument getMainDocument() {
return this.document;
}
int getNumberSubScanLine() {
return this.nbSubScanLine;
}
Vector2i getSize() {
return this.size;
}
protected Color mergeColor(final Color base, final Color integration) {
/*
if (integration.a() < base.a()) {
@ -178,23 +181,24 @@ public class Renderer {
*/
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) {
final long startTime = System.currentTimeMillis();
if (colorFill != null) {
//colorFill.setViewPort(Pair<Vector2f, Vector2f>(new Vector2f(0,0), Vector2f(sizeX, sizeY)));
colorFill.generate(this.document);
@ -205,14 +209,16 @@ public class Renderer {
}
// all together
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) {
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;
Color intermediateColorStroke = Color.NONE;
if (colorFill != null && valueFill != 0.0f) {
intermediateColorFill = colorFill.getColor(pos);
@ -237,9 +243,9 @@ public class Renderer {
}
}
}
if (Renderer.DEBUG_MODE) {
// display the gradient position:
if (colorFill instanceof final DynamicColorSpecial tmpColor) {
final SegmentList listSegment = new SegmentList();
@ -266,20 +272,22 @@ public class Renderer {
addDebugSegment(listSegment);
}
}
final long stopTime = System.currentTimeMillis();
LOGGER.trace("take time to generate: " + (stopTime - startTime));
}
public void setInterpolationRecurtionMax(final int value) {
this.interpolationRecurtionMax = FMath.avg(1, value, 200);
}
void setInterpolationThreshold(final float value) {
this.interpolationThreshold = FMath.avg(0.0f, value, 20000.0f);
}
void setNumberSubScanLine(final int value) {
this.nbSubScanLine = FMath.avg(1, value, 200);
}
public void setSize(final Vector2i size) {
this.size = size;
if (Renderer.DEBUG_MODE) {
@ -288,5 +296,5 @@ public class Renderer {
this.buffer = new ImageFloatRGBA(this.size.multiply(this.factor));
}
}
}