RasterPaints.java
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2025, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*/
package net.sourceforge.plantuml.klimt.drawing.raster;
import net.sourceforge.plantuml.klimt.UParam;
import net.sourceforge.plantuml.klimt.UStroke;
import net.sourceforge.plantuml.klimt.awt.XColor;
import net.sourceforge.plantuml.klimt.color.ColorMapper;
import net.sourceforge.plantuml.klimt.color.HColor;
import net.sourceforge.plantuml.klimt.color.HColorGradient;
import net.sourceforge.plantuml.klimt.color.HColorLinearGradient;
/**
* Paints and strokes of the raster drivers, as the Java2D drivers set them
* (see {@code DriverRectangleG2d} and {@code DriverLineG2d}).
*/
final class RasterPaints {
private RasterPaints() {
}
static int argb(HColor color, ColorMapper mapper) {
return color.toColor(mapper).getRGB();
}
static boolean isGradient(HColor color) {
return color instanceof HColorGradient || color instanceof HColorLinearGradient;
}
/**
* As {@code DriverLineG2d.manageStroke}.
*/
static void setStroke(UStroke stroke, RasterCanvas canvas) {
if (stroke.getDashVisible() == 0)
canvas.setStroke(stroke.getThickness(), 0, 0);
else
canvas.setStroke(stroke.getThickness(), stroke.getDashVisible(), stroke.getDashSpace());
}
/**
* As {@code DriverRectangleG2d.drawBorder}.
*/
static void drawBorder(UParam param, HColor color, ColorMapper mapper, double width, double height,
RasterPath shape, RasterCanvas canvas, double x, double y) {
if (color.isTransparent())
return;
if (isGradient(color))
setGradient(canvas, x, y, mapper, width, height, color);
else
canvas.setColor(argb(color, mapper));
setStroke(param.getStroke(), canvas);
canvas.stroke(shape);
}
/**
* As {@code DriverRectangleG2d.getPaintGradient}, quirks included (the
* vertical and horizontal policies use (y + height) / 2 and (x + width) / 2).
*/
static void setGradient(RasterCanvas canvas, double x, double y, ColorMapper mapper, double width, double height,
HColor back) {
if (back instanceof HColorLinearGradient) {
setLinearGradient(canvas, (HColorLinearGradient) back, mapper, x, y, width, height);
return;
}
final HColorGradient gr = (HColorGradient) back;
final char policy = gr.getPolicy();
final int color1 = argb(gr.getColor1(), mapper);
final int color2 = argb(gr.getColor2(), mapper);
// java.awt.GradientPaint uses float coordinates
final double x1;
final double y1;
final double x2;
final double y2;
if (policy == '|') {
x1 = (float) x;
y1 = (float) (y + height) / 2;
x2 = (float) (x + width);
y2 = (float) (y + height) / 2;
} else if (policy == '\\') {
x1 = (float) x;
y1 = (float) (y + height);
x2 = (float) (x + width);
y2 = (float) y;
} else if (policy == '-') {
x1 = (float) (x + width) / 2;
y1 = (float) y;
x2 = (float) (x + width) / 2;
y2 = (float) (y + height);
} else {
x1 = (float) x;
y1 = (float) y;
x2 = (float) (x + width);
y2 = (float) (y + height);
}
canvas.setLinearGradient(x1, y1, x2, y2, new double[] { 0, 1 }, new int[] { color1, color2 },
RasterCanvas.SPREAD_PAD);
}
private static void setLinearGradient(RasterCanvas canvas, HColorLinearGradient gr, ColorMapper mapper, double x,
double y, double width, double height) {
final int size = gr.getStops().size();
final double[] offsets = new double[size];
final int[] colors = new int[size];
int i = 0;
for (HColorLinearGradient.Stop stop : gr.getStops()) {
offsets[i] = (float) stop.getOffset();
final XColor base = stop.getColor().toColor(mapper);
int alpha = (int) Math.round(base.getAlpha() * stop.getOpacity());
if (alpha < 0)
alpha = 0;
if (alpha > 255)
alpha = 255;
colors[i] = new XColor(base.getRed(), base.getGreen(), base.getBlue(), alpha).getRGB();
i++;
}
final double x1;
final double y1;
final double x2;
final double y2;
if (gr.isUserSpaceOnUse()) {
x1 = (float) gr.getX1();
y1 = (float) gr.getY1();
x2 = (float) gr.getX2();
y2 = (float) gr.getY2();
} else {
x1 = (float) (x + gr.getX1() * width);
y1 = (float) (y + gr.getY1() * height);
x2 = (float) (x + gr.getX2() * width);
y2 = (float) (y + gr.getY2() * height);
}
final int spread;
switch (gr.getSpreadMethod()) {
case REFLECT:
spread = RasterCanvas.SPREAD_REFLECT;
break;
case REPEAT:
spread = RasterCanvas.SPREAD_REPEAT;
break;
case PAD:
default:
spread = RasterCanvas.SPREAD_PAD;
break;
}
canvas.setLinearGradient(x1, y1, x2, y2, offsets, colors, spread);
}
}