1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-12-22 10:59:01 +00:00

refactor: remove unused code

This commit is contained in:
Arnaud Roques 2023-10-22 12:15:29 +02:00
parent e92dcd400b
commit f8d87217a7
19 changed files with 12 additions and 1003 deletions

View File

@ -7,3 +7,5 @@ It serves as a historical reference to ensure we remember and understand past de
- [basic language](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/jasic)
- [mjpeg export](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/mjpeg)
- [animation](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/anim)
- [ditherer quantization](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/quantization)
- [syntax suggestion](https://github.com/plantuml/plantuml/blob/v1.2023.12/src/net/sourceforge/plantuml/syntax/SyntaxChecker.java)

View File

@ -240,16 +240,13 @@ public class ImageBuilder {
private ImageData writeImageInternal(OutputStream os) throws IOException {
XDimension2D dim = getFinalDimension();
double dx = 0;
double dy = 0;
final Scale scale = titledDiagram == null ? null : titledDiagram.getScale();
final double scaleFactor = (scale == null ? 1 : scale.getScale(dim.getWidth(), dim.getHeight())) * getDpi()
/ 96.0;
if (scaleFactor <= 0)
throw new IllegalStateException("Bad scaleFactor");
WasmLog.log("...image drawing...");
UGraphic ug = createUGraphic(dim, dx, dy, scaleFactor,
UGraphic ug = createUGraphic(dim, scaleFactor,
titledDiagram == null ? new Pragma() : titledDiagram.getPragma());
maybeDrawBorder(ug, dim);
if (randomPixel)
@ -317,12 +314,12 @@ public class ImageBuilder {
return ug;
}
private UGraphic createUGraphic(final XDimension2D dim, double dx, double dy, double scaleFactor, Pragma pragma) {
private UGraphic createUGraphic(final XDimension2D dim, double scaleFactor, Pragma pragma) {
final ColorMapper colorMapper = fileFormatOption.getColorMapper();
switch (fileFormatOption.getFileFormat()) {
case PNG:
case RAW:
return createUGraphicPNG(scaleFactor, dim, dx, dy, fileFormatOption.getWatermark(),
return createUGraphicPNG(scaleFactor, dim, fileFormatOption.getWatermark(),
fileFormatOption.getFileFormat());
case SVG:
return createUGraphicSVG(scaleFactor, dim, pragma);
@ -375,9 +372,8 @@ public class ImageBuilder {
}
private UGraphic createUGraphicPNG(double scaleFactor, final XDimension2D dim, double dx, double dy,
String watermark, FileFormat format) {
// ::done
private UGraphic createUGraphicPNG(double scaleFactor, final XDimension2D dim, String watermark,
FileFormat format) {
Color pngBackColor = new Color(0, 0, 0, 0);
if (this.backcolor instanceof HColorSimple)
@ -392,7 +388,7 @@ public class ImageBuilder {
final Graphics2D graphics2D = builder.getGraphics2D();
final UGraphicG2d ug = new UGraphicG2d(backcolor, fileFormatOption.getColorMapper(), stringBounder, graphics2D,
scaleFactor, dx, dy, format);
scaleFactor, format);
ug.setBufferedImage(builder.getBufferedImage());
final BufferedImage im = ug.getBufferedImage();

View File

@ -83,7 +83,7 @@ public class OptionFlags {
static public void setMaxPixel(int max) {
}
static public final boolean USE_HECTOR = false;
// static public final boolean USE_HECTOR = false;
static public boolean ADD_NICE_FOR_DOT = false;
// static public final boolean USE_IF_VERTICAL = true;

View File

@ -66,11 +66,11 @@ import net.sourceforge.plantuml.eggs.PSystemColorsFactory;
import net.sourceforge.plantuml.eggs.PSystemEggFactory;
import net.sourceforge.plantuml.eggs.PSystemPathFactory;
import net.sourceforge.plantuml.eggs.PSystemRIPFactory;
import net.sourceforge.plantuml.eggs.PSystemUnsupported;
import net.sourceforge.plantuml.eggs.PSystemWelcomeFactory;
import net.sourceforge.plantuml.emoji.PSystemListEmojiFactory;
import net.sourceforge.plantuml.error.PSystemError;
import net.sourceforge.plantuml.error.PSystemErrorUtils;
import net.sourceforge.plantuml.error.PSystemUnsupported;
import net.sourceforge.plantuml.filesdiagram.FilesDiagramFactory;
import net.sourceforge.plantuml.flowdiagram.FlowDiagramFactory;
import net.sourceforge.plantuml.font.PSystemListFontsFactory;

View File

@ -33,7 +33,7 @@
*
*
*/
package net.sourceforge.plantuml.eggs;
package net.sourceforge.plantuml.error;
import java.io.IOException;
import java.util.ArrayList;

View File

@ -119,11 +119,6 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
double dpiFactor, FileFormat format) {
this(defaultBackground, colorMapper, stringBounder, g2d, dpiFactor, 0, 0, format);
}
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
double dpiFactor, double dx, double dy, FileFormat format) {
super(stringBounder);
copy(defaultBackground, colorMapper, g2d);
this.format = format;

View File

@ -35,23 +35,20 @@
*/
package net.sourceforge.plantuml.png;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.io.OutputStream;
import net.sourceforge.plantuml.klimt.color.ColorMapper;
import net.sourceforge.plantuml.quantization.Quantizer;
import net.sourceforge.plantuml.security.SFile;
import net.sourceforge.plantuml.security.SImageIO;
import net.sourceforge.plantuml.utils.Log;
public class PngIO {
// ::remove folder when __HAXE__
// ::remove folder when __HAXE__
// ::comment when __CORE__
private static final String copyleft = "Generated by https://plantuml.com";
public static boolean USE_QUANTIZATION = false;
public static void write(RenderedImage image, ColorMapper mapper, SFile file, String metadata, int dpi)
throws IOException {
@ -76,9 +73,6 @@ public class PngIO {
String debugData) throws IOException {
// ::comment when __CORE__
if (USE_QUANTIZATION)
image = Quantizer.quantizeNow(mapper, (BufferedImage) image);
if (metadata == null)
// ::done
SImageIO.write(image, "png", os);

View File

@ -1,78 +0,0 @@
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sourceforge.plantuml.quantization;
import java.util.Comparator;
import java.util.WeakHashMap;
/**
* Provides a stable ordering of objects, such that:
*
* <ul>
* <li>compare(a, b) == 0 iff a == b</li>
* <li>sign(compare(a, b)) == -sign(compare(b, a))</li>
* </ul>
*
* <p>
* Similar to Guava's {code Ordering.arbitrary()}.
*/
final class ArbitraryComparator implements Comparator<Object> {
public static final ArbitraryComparator INSTANCE = new ArbitraryComparator();
/**
* If we have no other way to order two objects in a stable manner, we will
* register both in this map and order them according to their associated
* values. The map's values are just integers corresponding to the order in
* which objects were added.
*/
private static final WeakHashMap<Object, Integer> objectIds = new WeakHashMap<>();
private ArbitraryComparator() {
}
@Override
public int compare(Object a, Object b) {
if (a == b)
return 0;
if (a == null)
return -1;
if (b == null)
return 1;
int identityHashCodeDifference = System.identityHashCode(a) - System.identityHashCode(b);
if (identityHashCodeDifference != 0) {
return identityHashCodeDifference;
}
// We have an identityHashCode collision.
return getObjectId(a) - getObjectId(b);
}
/**
* Get the ID of an object, adding it to the ID map if it isn't already
* registered.
*/
private static int getObjectId(Object object) {
synchronized (objectIds) {
Integer id = objectIds.get(object);
if (id == null) {
id = objectIds.size();
objectIds.put(object, id);
}
return id;
}
}
}

View File

@ -1,19 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.Set;
public interface ColorQuantizer {
/**
* Quantize the given set of colors, returning a set no larger than
* {@code maxColors}.
*
* <p>
* The intent is to pick a set of colors which are representative of the
* original color set, but no specific guarantees are made.
*
* @param originalColors the colors in the original image
* @param maxColorCount the maximum number of colors to allow
* @return a quantized collection of colors no larger than {@code maxColors}
*/
public Set<QColor> quantize(Multiset<QColor> originalColors, int maxColorCount);
}

View File

@ -1,16 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.Set;
public interface Ditherer {
// ::remove folder when __HAXE__
/**
* Dither the given image, producing a new image which only contains colors from
* the given color set.
*
* @param image the original, unquantized image
* @param newColors the quantized set of colors to be used in the new image
* @return a new image containing only of colors from {@code newColors}
*/
public QImage dither(QImage image, Set<QColor> newColors);
}

View File

@ -1,53 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.Set;
public final class FloydSteinbergDitherer implements Ditherer {
public static final FloydSteinbergDitherer INSTANCE = new FloydSteinbergDitherer();
private static final ErrorComponent[] ERROR_DISTRIBUTION = { new ErrorComponent(1, 0, 7.0 / 16.0),
new ErrorComponent(-1, 1, 3.0 / 16.0), new ErrorComponent(0, 1, 5.0 / 16.0),
new ErrorComponent(1, 1, 1.0 / 16.0) };
private FloydSteinbergDitherer() {
}
@Override
public QImage dither(QImage image, Set<QColor> newColors) {
final int width = image.getWidth();
final int height = image.getHeight();
QColor[][] colors = new QColor[height][width];
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
colors[y][x] = image.getColor(x, y);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x) {
final QColor originalColor = colors[y][x];
final QColor replacementColor = originalColor.getNearestColor(newColors);
colors[y][x] = replacementColor;
final QColor error = originalColor.minus(replacementColor);
for (ErrorComponent component : ERROR_DISTRIBUTION) {
int siblingX = x + component.deltaX, siblingY = y + component.deltaY;
if (siblingX >= 0 && siblingY >= 0 && siblingX < width && siblingY < height) {
QColor errorComponent = error.scaled(component.errorFraction);
colors[siblingY][siblingX] = colors[siblingY][siblingX].plus(errorComponent);
}
}
}
return QImage.fromColors(colors);
}
private static final class ErrorComponent {
final int deltaX, deltaY;
final double errorFraction;
ErrorComponent(int deltaX, int deltaY, double errorFraction) {
this.deltaX = deltaX;
this.deltaY = deltaY;
this.errorFraction = errorFraction;
}
}
}

View File

@ -1,133 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
public final class HashMultiset<E> extends AbstractCollection<E> implements Multiset<E> {
private final Map<E, Count> elementCounts = new HashMap<>();
private int size;
public HashMultiset() {
}
public HashMultiset(Collection<E> source) {
addAll(source);
}
@Override
public void add(E element, int n) {
Count count = elementCounts.get(element);
if (count != null)
count.value += n;
else
elementCounts.put(element, new Count(n));
size += n;
}
@Override
public boolean add(E element) {
add(element, 1);
return true;
}
@Override
public int remove(Object element, int n) {
Count count = elementCounts.get(element);
if (count == null)
return 0;
if (n < count.value) {
count.value -= n;
size -= n;
return n;
}
elementCounts.remove(element);
size -= count.value;
return count.value;
}
@Override
public boolean remove(Object element) {
return remove(element, 1) > 0;
}
@Override
public Iterator<E> iterator() {
return new HashMultisetIterator();
}
@Override
public int size() {
return size;
}
@Override
public int count(Object element) {
Count countOrNull = elementCounts.get(element);
return countOrNull != null ? countOrNull.value : 0;
}
@Override
public Set<E> getDistinctElements() {
return elementCounts.keySet();
}
private final class HashMultisetIterator implements Iterator<E> {
final private Iterator<Map.Entry<E, Count>> distinctElementIterator;
private E currentElement;
private int currentCount;
private boolean currentElementRemoved;
HashMultisetIterator() {
this.distinctElementIterator = elementCounts.entrySet().iterator();
this.currentCount = 0;
}
@Override
public boolean hasNext() {
return currentCount > 0 || distinctElementIterator.hasNext();
}
@Override
public E next() {
if (hasNext() == false)
throw new NoSuchElementException("iterator has been exhausted");
if (currentCount == 0) {
Map.Entry<E, Count> next = distinctElementIterator.next();
currentElement = next.getKey();
currentCount = next.getValue().value;
}
currentCount--;
currentElementRemoved = false;
return currentElement;
}
@Override
public void remove() {
if (currentElement == null)
throw new IllegalStateException("next() has not been called");
if (currentElementRemoved)
throw new IllegalStateException("remove() already called for current element");
HashMultiset.this.remove(currentElement);
}
}
private static final class Count {
private int value;
Count(int value) {
this.value = value;
}
}
}

View File

@ -1,76 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Uses k-means clustering for color quantization. This tends to yield good
* results, but convergence can be slow. It is not recommended for large images.
*/
public final class KMeansQuantizer implements ColorQuantizer {
public static final KMeansQuantizer INSTANCE = new KMeansQuantizer();
private KMeansQuantizer() {
}
@Override
public Set<QColor> quantize(Multiset<QColor> originalColors, int maxColorCount) {
Map<QColor, Multiset<QColor>> clustersByCentroid = new LinkedHashMap<>();
Set<QColor> centroidsToRecompute = getInitialCentroids(originalColors, maxColorCount);
for (QColor centroid : centroidsToRecompute)
clustersByCentroid.put(centroid, new HashMultiset<QColor>());
for (QColor color : originalColors.getDistinctElements()) {
final int count = originalColors.count(color);
clustersByCentroid.get(color.getNearestColor(centroidsToRecompute)).add(color, count);
}
while (centroidsToRecompute.isEmpty() == false) {
recomputeCentroids(clustersByCentroid, centroidsToRecompute);
centroidsToRecompute.clear();
Set<QColor> allCentroids = clustersByCentroid.keySet();
for (QColor centroid : clustersByCentroid.keySet()) {
Multiset<QColor> cluster = clustersByCentroid.get(centroid);
for (QColor color : new ArrayList<>(cluster.getDistinctElements())) {
QColor newCentroid = color.getNearestColor(allCentroids);
if (newCentroid != centroid) {
final int count = cluster.count(color);
final Multiset<QColor> newCluster = clustersByCentroid.get(newCentroid);
cluster.remove(color, count);
newCluster.add(color, count);
centroidsToRecompute.add(centroid);
centroidsToRecompute.add(newCentroid);
}
}
}
}
return clustersByCentroid.keySet();
}
private static void recomputeCentroids(Map<QColor, Multiset<QColor>> clustersByCentroid,
Set<QColor> centroidsToRecompute) {
for (QColor oldCentroid : centroidsToRecompute) {
final Multiset<QColor> cluster = clustersByCentroid.get(oldCentroid);
final QColor newCentroid = QColor.getCentroid(cluster);
clustersByCentroid.remove(oldCentroid);
clustersByCentroid.put(newCentroid, cluster);
}
}
private static Set<QColor> getInitialCentroids(Multiset<QColor> originalColors, int maxColorCount) {
// We use the Forgy initialization method: choose random colors as initial
// cluster centroids.
final List<QColor> colorList = new ArrayList<>(originalColors.getDistinctElements());
Collections.shuffle(colorList);
return new HashSet<>(colorList.subList(0, maxColorCount));
}
}

View File

@ -1,136 +0,0 @@
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sourceforge.plantuml.quantization;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
* Implements median cut quantization.
*
* <p>
* The algorithm works as follows:
*
* <ul>
* <li>Begin with one cluster containing all the original colors.</li>
* <li>Find the cluster containing the greatest spread along a single color
* component (red, green or blue).</li>
* <li>Find the median of that color component among colors in the cluster.</li>
* <li>Split the cluster into two halves, using that median as a threshold.</li>
* <li>Repeat this process until the desired number of clusters is reached.</li>
* </ul>
*/
public final class MedianCutQuantizer implements ColorQuantizer {
public static final MedianCutQuantizer INSTANCE = new MedianCutQuantizer();
private MedianCutQuantizer() {
}
@Override
public Set<QColor> quantize(Multiset<QColor> originalColors, int maxColorCount) {
TreeSet<Cluster> clusters = new TreeSet<>(new ClusterSpreadComparator());
clusters.add(new Cluster(originalColors));
while (clusters.size() < maxColorCount) {
Cluster clusterWithLargestSpread = clusters.pollFirst();
clusters.addAll(clusterWithLargestSpread.split());
}
Set<QColor> clusterCentroids = new HashSet<>();
for (Cluster cluster : clusters) {
clusterCentroids.add(QColor.getCentroid(cluster.colors));
}
return clusterCentroids;
}
private static final class Cluster {
final Multiset<QColor> colors;
double largestSpread;
int componentWithLargestSpread;
Cluster(Multiset<QColor> colors) {
this.colors = colors;
this.largestSpread = -1;
for (int component = 0; component < 3; ++component) {
double componentSpread = getComponentSpread(component);
if (componentSpread > largestSpread) {
largestSpread = componentSpread;
componentWithLargestSpread = component;
}
}
}
double getComponentSpread(int component) {
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;
for (QColor color : colors) {
min = Math.min(min, color.getComponent(component));
max = Math.max(max, color.getComponent(component));
}
return max - min;
}
Collection<Cluster> split() {
List<QColor> orderedColors = new ArrayList<>(colors);
Collections.sort(orderedColors, new ColorComponentComparator(componentWithLargestSpread));
int medianIndex = orderedColors.size() / 2;
return Arrays.asList(new Cluster(new HashMultiset<>(orderedColors.subList(0, medianIndex))),
new Cluster(new HashMultiset<>(orderedColors.subList(medianIndex, orderedColors.size()))));
}
}
/**
* Orders clusters according to their maximum spread, in descending order.
*/
static final class ClusterSpreadComparator implements Comparator<Cluster> {
@Override
public int compare(Cluster a, Cluster b) {
double spreadDifference = b.largestSpread - a.largestSpread;
if (spreadDifference == 0) {
return ArbitraryComparator.INSTANCE.compare(a, b);
}
return (int) Math.signum(spreadDifference);
}
}
/**
* Orders colors according to the value of one particular component, in
* ascending order.
*/
static final class ColorComponentComparator implements Comparator<QColor> {
final int component;
ColorComponentComparator(int component) {
this.component = component;
}
@Override
public int compare(QColor a, QColor b) {
double componentDifference = a.getComponent(component) - b.getComponent(component);
if (componentDifference == 0) {
return ArbitraryComparator.INSTANCE.compare(a, b);
}
return (int) Math.signum(componentDifference);
}
}
}

View File

@ -1,33 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.Collection;
import java.util.Set;
/**
* A collection which permits duplicates, and provides methods adding/removing
* several counts of an element.
*
* @param <E> the element type
*/
public interface Multiset<E> extends Collection<E> {
/**
* Add n counts of an element.
*
* @param element the element to add
* @param n how many to add
*/
public void add(E element, int n);
/**
* Remove up to n counts of an element.
*
* @param element the element the remove
* @param n how many to remove
* @return the number of elements removed
*/
public int remove(Object element, int n);
public int count(Object element);
public Set<E> getDistinctElements();
}

View File

@ -1,143 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.Collection;
import net.sourceforge.plantuml.klimt.color.ColorMapper;
/**
* An RGB representation of a color, which stores each component as a double in
* the range [0, 1]. Values outside of [0, 1] are permitted though, as this is
* convenient e.g. for representing color deltas.
*/
public final class QColor {
public static final QColor BLACK = new QColor(0, 0, 0);
public static final QColor WHITE = new QColor(1, 1, 1);
public static final QColor RED = new QColor(1, 0, 0);
public static final QColor GREEN = new QColor(0, 1, 0);
public static final QColor BLUE = new QColor(0, 0, 1);
private final double red;
private final double green;
private final double blue;
public QColor(double red, double green, double blue) {
this.red = red;
this.green = green;
this.blue = blue;
}
public static QColor fromArgbInt(ColorMapper mapper, int rgb) {
final double alpha = (rgb >>> 24 & 0xFF) / 255.0;
double red = (rgb >>> 16 & 0xFF) / 255.0;
double green = (rgb >>> 8 & 0xFF) / 255.0;
double blue = (rgb & 0xFF) / 255.0;
if (mapper == ColorMapper.DARK_MODE) {
red = alpha * red;
green = alpha * green;
blue = alpha * blue;
} else {
red = 1 - alpha * (1 - red);
green = 1 - alpha * (1 - green);
blue = 1 - alpha * (1 - blue);
}
return new QColor(red, green, blue);
}
public static QColor fromRgbInt(int rgb) {
final double red = (rgb >>> 16 & 0xFF) / 255.0;
final double green = (rgb >>> 8 & 0xFF) / 255.0;
final double blue = (rgb & 0xFF) / 255.0;
return new QColor(red, green, blue);
}
public static QColor getCentroid(Multiset<QColor> colors) {
QColor sum = QColor.BLACK;
for (QColor color : colors.getDistinctElements()) {
int weight = colors.count(color);
sum = sum.plus(color.scaled(weight));
}
return sum.scaled(1.0 / colors.size());
}
public double getComponent(int index) {
switch (index) {
case 0:
return red;
case 1:
return green;
case 2:
return blue;
default:
throw new IllegalArgumentException("Unexpected component index: " + index);
}
}
public QColor scaled(double s) {
return new QColor(s * red, s * green, s * blue);
}
public QColor plus(QColor that) {
return new QColor(this.red + that.red, this.green + that.green, this.blue + that.blue);
}
public QColor minus(QColor that) {
return new QColor(this.red - that.red, this.green - that.green, this.blue - that.blue);
}
public double getEuclideanDistanceTo(QColor that) {
final QColor d = this.minus(that);
final double sumOfSquares = d.red * d.red + d.green * d.green + d.blue * d.blue;
return Math.sqrt(sumOfSquares);
}
/**
* Find this color's nearest neighbor, based on Euclidean distance, among some
* set of colors.
*/
public QColor getNearestColor(Collection<QColor> colors) {
QColor nearestCentroid = null;
double nearestCentroidDistance = Double.POSITIVE_INFINITY;
for (QColor color : colors) {
final double distance = getEuclideanDistanceTo(color);
if (distance < nearestCentroidDistance) {
nearestCentroid = color;
nearestCentroidDistance = distance;
}
}
return nearestCentroid;
}
public int getRgbInt() {
final int redComponent = (int) (red * 255);
final int greenComponent = (int) (green * 255);
final int blueComponent = (int) (blue * 255);
return redComponent << 16 | greenComponent << 8 | blueComponent;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof QColor))
return false;
final QColor that = (QColor) o;
return this.red == that.red && this.green == that.green && this.blue == that.blue;
}
@Override
public int hashCode() {
int result;
long temp;
temp = Double.doubleToLongBits(red);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(green);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(blue);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public String toString() {
return String.format("Color[%f, %f, %f]", red, green, blue);
}
}

View File

@ -1,92 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.awt.image.BufferedImage;
import net.sourceforge.plantuml.klimt.color.ColorMapper;
/**
* An immutable grid of pixel colors.
*/
public final class QImage {
/**
* The first index corresponds to the row, while the second index corresponds
* the column.
*/
private final QColor[][] colors;
private QImage(QColor[][] colors) {
this.colors = colors;
}
public static QImage fromBufferedImage(ColorMapper mapper, BufferedImage img) {
final int height = img.getHeight();
final int width = img.getWidth();
final QColor[][] colors = new QColor[height][width];
if (img.getType() == BufferedImage.TYPE_INT_ARGB) {
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
colors[y][x] = QColor.fromArgbInt(mapper, img.getRGB(x, y));
} else if (img.getType() == BufferedImage.TYPE_INT_RGB) {
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
colors[y][x] = QColor.fromRgbInt(img.getRGB(x, y));
} else {
throw new IllegalArgumentException();
}
return new QImage(colors);
}
public static QImage fromColors(QColor[][] colors) {
return new QImage(colors);
}
public QColor getColor(int x, int y) {
return colors[y][x];
}
public QColor getColor(int index) {
return colors[index / getWidth()][index % getWidth()];
}
Multiset<QColor> getColors() {
final Multiset<QColor> colorCounts = new HashMultiset<>();
for (int i = 0; i < getNumPixels(); ++i) {
final QColor color = getColor(i);
colorCounts.add(color);
}
return colorCounts;
}
public int getWidth() {
return colors[0].length;
}
public int getHeight() {
return colors.length;
}
public int getNumPixels() {
return getWidth() * getHeight();
}
public BufferedImage toBufferedImage() {
final BufferedImage result = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
for (int i = 0; i < result.getWidth(); i++)
for (int j = 0; j < result.getHeight(); j++)
result.setRGB(i, j, colors[j][i].getRgbInt());
return result;
}
public BufferedImage toBufferedImageKeepTransparency(BufferedImage orig) {
final BufferedImage result = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
for (int i = 0; i < result.getWidth(); i++)
for (int j = 0; j < result.getHeight(); j++) {
if ((orig.getRGB(i, j)) != 0x00000000)
result.setRGB(i, j, colors[j][i].getRgbInt() | 0xFF000000);
}
return result;
}
}

View File

@ -1,38 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Set;
import net.sourceforge.plantuml.klimt.color.ColorMapper;
public final class Quantizer {
// ::remove folder when __CORE__
private static final int MAX_COLOR_COUNT = 256;
private static QImage quantizeNow(QImage image) throws IOException {
Multiset<QColor> originalColors = image.getColors();
Set<QColor> distinctColors = originalColors.getDistinctElements();
if (distinctColors.size() > MAX_COLOR_COUNT) {
// distinctColors = KMeansQuantizer.INSTANCE.quantize(originalColors,
// MAX_COLOR_COUNT);
distinctColors = MedianCutQuantizer.INSTANCE.quantize(originalColors, MAX_COLOR_COUNT);
image = FloydSteinbergDitherer.INSTANCE.dither(image, distinctColors);
}
return image;
}
public static BufferedImage quantizeNow(ColorMapper mapper, BufferedImage orig) throws IOException {
final QImage raw = QImage.fromBufferedImage(mapper, orig);
final QImage result = quantizeNow(raw);
if (orig.getType() == BufferedImage.TYPE_INT_RGB)
return result.toBufferedImage();
else if (orig.getType() == BufferedImage.TYPE_INT_ARGB)
return result.toBufferedImageKeepTransparency(orig);
else
throw new IllegalArgumentException();
}
}

View File

@ -1,161 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, 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.syntax;
import java.util.Collections;
import java.util.List;
import net.sourceforge.plantuml.BlockUml;
import net.sourceforge.plantuml.ErrorUml;
import net.sourceforge.plantuml.OptionFlags;
import net.sourceforge.plantuml.SourceStringReader;
import net.sourceforge.plantuml.UmlDiagram;
import net.sourceforge.plantuml.annotation.DeadCode;
import net.sourceforge.plantuml.core.Diagram;
import net.sourceforge.plantuml.error.PSystemError;
import net.sourceforge.plantuml.preproc.Defines;
import net.sourceforge.plantuml.text.BackSlash;
import net.sourceforge.plantuml.utils.LineLocation;
import net.sourceforge.plantuml.utils.LineLocationImpl;
@DeadCode(comment = "used too much CPU")
public class SyntaxChecker {
// ::remove folder when __HAXE__
// ::remove file when __CORE__
public static SyntaxResult checkSyntax(List<String> source) {
final StringBuilder sb = new StringBuilder();
for (String s : source) {
sb.append(s);
sb.append(BackSlash.NEWLINE);
}
return checkSyntax(sb.toString());
}
public static SyntaxResult checkSyntax(String source) {
OptionFlags.getInstance().setQuiet(true);
final SyntaxResult result = new SyntaxResult();
if (source.startsWith("@startuml\n") == false) {
result.setError(true);
result.setLineLocation(new LineLocationImpl("", null).oneLineRead());
result.addErrorText("No @startuml/@enduml found");
return result;
}
if (source.endsWith("@enduml\n") == false && source.endsWith("@enduml") == false) {
result.setError(true);
result.setLineLocation(lastLineNumber2(source));
result.addErrorText("No @enduml found");
return result;
}
final SourceStringReader sourceStringReader = new SourceStringReader(Defines.createEmpty(), source,
Collections.<String>emptyList());
final List<BlockUml> blocks = sourceStringReader.getBlocks();
if (blocks.size() == 0) {
result.setError(true);
result.setLineLocation(lastLineNumber2(source));
result.addErrorText("No @enduml found");
return result;
}
final Diagram system = blocks.get(0).getDiagram();
result.setCmapData(system.hasUrl());
if (system instanceof UmlDiagram) {
result.setUmlDiagramType(((UmlDiagram) system).getUmlDiagramType());
result.setDescription(system.getDescription().getDescription());
} else if (system instanceof PSystemError) {
result.setError(true);
final PSystemError sys = (PSystemError) system;
result.setLineLocation(sys.getLineLocation());
result.setSystemError(sys);
for (ErrorUml er : sys.getErrorsUml())
result.addErrorText(er.getError());
} else {
result.setDescription(system.getDescription().getDescription());
}
return result;
}
public static SyntaxResult checkSyntaxFair(String source) {
final SyntaxResult result = new SyntaxResult();
final SourceStringReader sourceStringReader = new SourceStringReader(Defines.createEmpty(), source,
Collections.<String>emptyList());
final List<BlockUml> blocks = sourceStringReader.getBlocks();
if (blocks.size() == 0) {
result.setError(true);
result.setLineLocation(lastLineNumber2(source));
result.addErrorText("No @enduml found");
return result;
}
final Diagram system = blocks.get(0).getDiagram();
result.setCmapData(system.hasUrl());
if (system instanceof UmlDiagram) {
result.setUmlDiagramType(((UmlDiagram) system).getUmlDiagramType());
result.setDescription(system.getDescription().getDescription());
} else if (system instanceof PSystemError) {
result.setError(true);
final PSystemError sys = (PSystemError) system;
result.setLineLocation(sys.getLineLocation());
for (ErrorUml er : sys.getErrorsUml()) {
result.addErrorText(er.getError());
}
result.setSystemError(sys);
} else {
result.setDescription(system.getDescription().getDescription());
}
return result;
}
private static int lastLineNumber(String source) {
int result = 0;
for (int i = 0; i < source.length(); i++)
if (source.charAt(i) == '\n')
result++;
return result;
}
private static LineLocation lastLineNumber2(String source) {
LineLocationImpl result = new LineLocationImpl("", null).oneLineRead();
for (int i = 0; i < source.length(); i++)
if (source.charAt(i) == '\n')
result = result.oneLineRead();
return result;
}
}