From f8d87217a7b06623247238686ae4104f0c87a360 Mon Sep 17 00:00:00 2001 From: Arnaud Roques Date: Sun, 22 Oct 2023 12:15:29 +0200 Subject: [PATCH] refactor: remove unused code --- attic.md | 2 + src/net/atmp/ImageBuilder.java | 16 +- src/net/sourceforge/plantuml/OptionFlags.java | 2 +- .../sourceforge/plantuml/PSystemBuilder.java | 2 +- .../{eggs => error}/PSystemUnsupported.java | 2 +- .../klimt/drawing/g2d/UGraphicG2d.java | 5 - src/net/sourceforge/plantuml/png/PngIO.java | 8 +- .../quantization/ArbitraryComparator.java | 78 --------- .../plantuml/quantization/ColorQuantizer.java | 19 --- .../plantuml/quantization/Ditherer.java | 16 -- .../quantization/FloydSteinbergDitherer.java | 53 ------ .../plantuml/quantization/HashMultiset.java | 133 --------------- .../quantization/KMeansQuantizer.java | 76 --------- .../quantization/MedianCutQuantizer.java | 136 --------------- .../plantuml/quantization/Multiset.java | 33 ---- .../plantuml/quantization/QColor.java | 143 ---------------- .../plantuml/quantization/QImage.java | 92 ---------- .../plantuml/quantization/Quantizer.java | 38 ----- .../plantuml/syntax/SyntaxChecker.java | 161 ------------------ 19 files changed, 12 insertions(+), 1003 deletions(-) rename src/net/sourceforge/plantuml/{eggs => error}/PSystemUnsupported.java (98%) delete mode 100644 src/net/sourceforge/plantuml/quantization/ArbitraryComparator.java delete mode 100644 src/net/sourceforge/plantuml/quantization/ColorQuantizer.java delete mode 100644 src/net/sourceforge/plantuml/quantization/Ditherer.java delete mode 100644 src/net/sourceforge/plantuml/quantization/FloydSteinbergDitherer.java delete mode 100644 src/net/sourceforge/plantuml/quantization/HashMultiset.java delete mode 100644 src/net/sourceforge/plantuml/quantization/KMeansQuantizer.java delete mode 100644 src/net/sourceforge/plantuml/quantization/MedianCutQuantizer.java delete mode 100644 src/net/sourceforge/plantuml/quantization/Multiset.java delete mode 100644 src/net/sourceforge/plantuml/quantization/QColor.java delete mode 100644 src/net/sourceforge/plantuml/quantization/QImage.java delete mode 100644 src/net/sourceforge/plantuml/quantization/Quantizer.java delete mode 100644 src/net/sourceforge/plantuml/syntax/SyntaxChecker.java diff --git a/attic.md b/attic.md index 839058eb3..6db8f86a0 100644 --- a/attic.md +++ b/attic.md @@ -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) diff --git a/src/net/atmp/ImageBuilder.java b/src/net/atmp/ImageBuilder.java index 6534f2221..078a00562 100644 --- a/src/net/atmp/ImageBuilder.java +++ b/src/net/atmp/ImageBuilder.java @@ -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(); diff --git a/src/net/sourceforge/plantuml/OptionFlags.java b/src/net/sourceforge/plantuml/OptionFlags.java index 6c2bf5bac..bd0e912f4 100644 --- a/src/net/sourceforge/plantuml/OptionFlags.java +++ b/src/net/sourceforge/plantuml/OptionFlags.java @@ -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; diff --git a/src/net/sourceforge/plantuml/PSystemBuilder.java b/src/net/sourceforge/plantuml/PSystemBuilder.java index 06c7af62d..e1e2a3e7b 100644 --- a/src/net/sourceforge/plantuml/PSystemBuilder.java +++ b/src/net/sourceforge/plantuml/PSystemBuilder.java @@ -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; diff --git a/src/net/sourceforge/plantuml/eggs/PSystemUnsupported.java b/src/net/sourceforge/plantuml/error/PSystemUnsupported.java similarity index 98% rename from src/net/sourceforge/plantuml/eggs/PSystemUnsupported.java rename to src/net/sourceforge/plantuml/error/PSystemUnsupported.java index 0b7223c04..a75a587ac 100644 --- a/src/net/sourceforge/plantuml/eggs/PSystemUnsupported.java +++ b/src/net/sourceforge/plantuml/error/PSystemUnsupported.java @@ -33,7 +33,7 @@ * * */ -package net.sourceforge.plantuml.eggs; +package net.sourceforge.plantuml.error; import java.io.IOException; import java.util.ArrayList; diff --git a/src/net/sourceforge/plantuml/klimt/drawing/g2d/UGraphicG2d.java b/src/net/sourceforge/plantuml/klimt/drawing/g2d/UGraphicG2d.java index a2aefdd3b..948e63fe9 100644 --- a/src/net/sourceforge/plantuml/klimt/drawing/g2d/UGraphicG2d.java +++ b/src/net/sourceforge/plantuml/klimt/drawing/g2d/UGraphicG2d.java @@ -119,11 +119,6 @@ public class UGraphicG2d extends AbstractUGraphic 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; diff --git a/src/net/sourceforge/plantuml/png/PngIO.java b/src/net/sourceforge/plantuml/png/PngIO.java index 68448753b..c3136d72f 100644 --- a/src/net/sourceforge/plantuml/png/PngIO.java +++ b/src/net/sourceforge/plantuml/png/PngIO.java @@ -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); diff --git a/src/net/sourceforge/plantuml/quantization/ArbitraryComparator.java b/src/net/sourceforge/plantuml/quantization/ArbitraryComparator.java deleted file mode 100644 index b7105c3d4..000000000 --- a/src/net/sourceforge/plantuml/quantization/ArbitraryComparator.java +++ /dev/null @@ -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: - * - * - * - *

- * Similar to Guava's {code Ordering.arbitrary()}. - */ -final class ArbitraryComparator implements Comparator { - 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 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; - } - } -} diff --git a/src/net/sourceforge/plantuml/quantization/ColorQuantizer.java b/src/net/sourceforge/plantuml/quantization/ColorQuantizer.java deleted file mode 100644 index 79fb426e4..000000000 --- a/src/net/sourceforge/plantuml/quantization/ColorQuantizer.java +++ /dev/null @@ -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}. - * - *

- * 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 quantize(Multiset originalColors, int maxColorCount); -} diff --git a/src/net/sourceforge/plantuml/quantization/Ditherer.java b/src/net/sourceforge/plantuml/quantization/Ditherer.java deleted file mode 100644 index 29048412b..000000000 --- a/src/net/sourceforge/plantuml/quantization/Ditherer.java +++ /dev/null @@ -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 newColors); -} diff --git a/src/net/sourceforge/plantuml/quantization/FloydSteinbergDitherer.java b/src/net/sourceforge/plantuml/quantization/FloydSteinbergDitherer.java deleted file mode 100644 index 4d9bae246..000000000 --- a/src/net/sourceforge/plantuml/quantization/FloydSteinbergDitherer.java +++ /dev/null @@ -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 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; - } - } -} diff --git a/src/net/sourceforge/plantuml/quantization/HashMultiset.java b/src/net/sourceforge/plantuml/quantization/HashMultiset.java deleted file mode 100644 index 9c6547aa6..000000000 --- a/src/net/sourceforge/plantuml/quantization/HashMultiset.java +++ /dev/null @@ -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 extends AbstractCollection implements Multiset { - private final Map elementCounts = new HashMap<>(); - private int size; - - public HashMultiset() { - } - - public HashMultiset(Collection 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 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 getDistinctElements() { - return elementCounts.keySet(); - } - - private final class HashMultisetIterator implements Iterator { - final private Iterator> 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 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; - } - } -} diff --git a/src/net/sourceforge/plantuml/quantization/KMeansQuantizer.java b/src/net/sourceforge/plantuml/quantization/KMeansQuantizer.java deleted file mode 100644 index 4997dc19c..000000000 --- a/src/net/sourceforge/plantuml/quantization/KMeansQuantizer.java +++ /dev/null @@ -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 quantize(Multiset originalColors, int maxColorCount) { - Map> clustersByCentroid = new LinkedHashMap<>(); - Set centroidsToRecompute = getInitialCentroids(originalColors, maxColorCount); - for (QColor centroid : centroidsToRecompute) - clustersByCentroid.put(centroid, new HashMultiset()); - - 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 allCentroids = clustersByCentroid.keySet(); - for (QColor centroid : clustersByCentroid.keySet()) { - Multiset 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 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> clustersByCentroid, - Set centroidsToRecompute) { - for (QColor oldCentroid : centroidsToRecompute) { - final Multiset cluster = clustersByCentroid.get(oldCentroid); - final QColor newCentroid = QColor.getCentroid(cluster); - clustersByCentroid.remove(oldCentroid); - clustersByCentroid.put(newCentroid, cluster); - } - } - - private static Set getInitialCentroids(Multiset originalColors, int maxColorCount) { - // We use the Forgy initialization method: choose random colors as initial - // cluster centroids. - final List colorList = new ArrayList<>(originalColors.getDistinctElements()); - Collections.shuffle(colorList); - return new HashSet<>(colorList.subList(0, maxColorCount)); - } -} diff --git a/src/net/sourceforge/plantuml/quantization/MedianCutQuantizer.java b/src/net/sourceforge/plantuml/quantization/MedianCutQuantizer.java deleted file mode 100644 index 95a0f2678..000000000 --- a/src/net/sourceforge/plantuml/quantization/MedianCutQuantizer.java +++ /dev/null @@ -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. - * - *

- * The algorithm works as follows: - * - *

    - *
  • Begin with one cluster containing all the original colors.
  • - *
  • Find the cluster containing the greatest spread along a single color - * component (red, green or blue).
  • - *
  • Find the median of that color component among colors in the cluster.
  • - *
  • Split the cluster into two halves, using that median as a threshold.
  • - *
  • Repeat this process until the desired number of clusters is reached.
  • - *
- */ -public final class MedianCutQuantizer implements ColorQuantizer { - public static final MedianCutQuantizer INSTANCE = new MedianCutQuantizer(); - - private MedianCutQuantizer() { - } - - @Override - public Set quantize(Multiset originalColors, int maxColorCount) { - TreeSet clusters = new TreeSet<>(new ClusterSpreadComparator()); - clusters.add(new Cluster(originalColors)); - - while (clusters.size() < maxColorCount) { - Cluster clusterWithLargestSpread = clusters.pollFirst(); - clusters.addAll(clusterWithLargestSpread.split()); - } - - Set clusterCentroids = new HashSet<>(); - for (Cluster cluster : clusters) { - clusterCentroids.add(QColor.getCentroid(cluster.colors)); - } - return clusterCentroids; - } - - private static final class Cluster { - final Multiset colors; - double largestSpread; - int componentWithLargestSpread; - - Cluster(Multiset 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 split() { - List 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 { - @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 { - 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); - } - } -} diff --git a/src/net/sourceforge/plantuml/quantization/Multiset.java b/src/net/sourceforge/plantuml/quantization/Multiset.java deleted file mode 100644 index 469340216..000000000 --- a/src/net/sourceforge/plantuml/quantization/Multiset.java +++ /dev/null @@ -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 the element type - */ -public interface Multiset extends Collection { - /** - * 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 getDistinctElements(); -} diff --git a/src/net/sourceforge/plantuml/quantization/QColor.java b/src/net/sourceforge/plantuml/quantization/QColor.java deleted file mode 100644 index ec23fc7c7..000000000 --- a/src/net/sourceforge/plantuml/quantization/QColor.java +++ /dev/null @@ -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 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 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); - } -} diff --git a/src/net/sourceforge/plantuml/quantization/QImage.java b/src/net/sourceforge/plantuml/quantization/QImage.java deleted file mode 100644 index 2876f6aaa..000000000 --- a/src/net/sourceforge/plantuml/quantization/QImage.java +++ /dev/null @@ -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 getColors() { - final Multiset 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; - } - -} diff --git a/src/net/sourceforge/plantuml/quantization/Quantizer.java b/src/net/sourceforge/plantuml/quantization/Quantizer.java deleted file mode 100644 index 83d3cda66..000000000 --- a/src/net/sourceforge/plantuml/quantization/Quantizer.java +++ /dev/null @@ -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 originalColors = image.getColors(); - Set 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(); - - } -} diff --git a/src/net/sourceforge/plantuml/syntax/SyntaxChecker.java b/src/net/sourceforge/plantuml/syntax/SyntaxChecker.java deleted file mode 100644 index ef1eaca31..000000000 --- a/src/net/sourceforge/plantuml/syntax/SyntaxChecker.java +++ /dev/null @@ -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 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.emptyList()); - - final List 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.emptyList()); - - final List 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; - } -}