From 6e25b30d6081bdd1f23d5eb240587b14948f4d19 Mon Sep 17 00:00:00 2001 From: Arnaud Roques Date: Sat, 19 Nov 2022 15:57:30 +0100 Subject: [PATCH] Improve compression management --- .../plantuml/LineBreakStrategy.java | 6 +- .../plantuml/code/CompressionZip.java | 73 +++++++++++++++++++ .../plantuml/code/CompressionZlib.java | 16 ++-- .../plantuml/code/CompressionZlibAttic.java | 28 ++++--- .../plantuml/code/CompressionZopfliZlib.java | 8 +- .../plantuml/code/TranscoderSmart.java | 16 ++-- .../code/TranscoderSmartProtected.java | 16 ++-- .../command/note/CommandFactoryNote.java | 21 +++++- .../note/CommandFactoryNoteOnEntity.java | 4 +- .../note/CommandFactoryTipOnEntity.java | 42 ++++++++++- ...FactorySequenceNoteOverSeveralCommand.java | 10 ++- .../sourceforge/plantuml/creole/Fission.java | 39 ++++------ .../sourceforge/plantuml/preproc/Stdlib.java | 63 +++++++++++++++- .../plantuml/project/GanttDiagramFactory.java | 27 ++++--- .../plantuml/project/lang/SentenceSimple.java | 8 +- .../plantuml/quantization/QColor.java | 2 - .../plantuml/svek/image/EntityImageNote.java | 8 +- .../plantuml/svek/image/EntityImageTips.java | 6 +- .../sourceforge/plantuml/version/Version.java | 6 +- 19 files changed, 289 insertions(+), 110 deletions(-) create mode 100644 src/net/sourceforge/plantuml/code/CompressionZip.java diff --git a/src/net/sourceforge/plantuml/LineBreakStrategy.java b/src/net/sourceforge/plantuml/LineBreakStrategy.java index 0da285807..55b723359 100644 --- a/src/net/sourceforge/plantuml/LineBreakStrategy.java +++ b/src/net/sourceforge/plantuml/LineBreakStrategy.java @@ -44,7 +44,7 @@ public class LineBreakStrategy { public LineBreakStrategy(String value) { this.value = value; } - + @Override public String toString() { return value; @@ -55,9 +55,9 @@ public class LineBreakStrategy { } public double getMaxWidth() { - if (value != null && value.matches("-?\\d+")) { + if (value != null && value.matches("-?\\d+")) return Double.parseDouble(value); - } + return 0; } diff --git a/src/net/sourceforge/plantuml/code/CompressionZip.java b/src/net/sourceforge/plantuml/code/CompressionZip.java new file mode 100644 index 000000000..7f450d08d --- /dev/null +++ b/src/net/sourceforge/plantuml/code/CompressionZip.java @@ -0,0 +1,73 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2023, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://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.code; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public class CompressionZip implements Compression { + + public byte[] compress(byte[] in) { + throw new UnsupportedOperationException(); + } + + public ByteArray decompress(byte[] input) throws NoPlantumlCompressionException { + try { + try (final ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(input))) { + final ZipEntry ent = zis.getNextEntry(); + final String name = ent.getName(); + final byte[] buffer = new byte[10_000]; + + try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + int len; + while ((len = zis.read(buffer)) > 0) { + baos.write(buffer, 0, len); + if (baos.size() > 200_000) + throw new NoPlantumlCompressionException("Zip error"); + } + return ByteArray.from(baos.toByteArray()); + } + } + } catch (IOException e) { + throw new NoPlantumlCompressionException(e); + } + + } + +} diff --git a/src/net/sourceforge/plantuml/code/CompressionZlib.java b/src/net/sourceforge/plantuml/code/CompressionZlib.java index ad6c8733e..8973afee9 100644 --- a/src/net/sourceforge/plantuml/code/CompressionZlib.java +++ b/src/net/sourceforge/plantuml/code/CompressionZlib.java @@ -47,16 +47,16 @@ public class CompressionZlib implements Compression { private static final int COMPRESSION_LEVEL = 9; public byte[] compress(byte[] in) { - if (USE_ZOPFLI) { + if (USE_ZOPFLI) return new CompressionZopfliZlib().compress(in); - } - if (in.length == 0) { + + if (in.length == 0) return null; - } + int len = in.length * 2; - if (len < 1000) { + if (len < 1000) len = 1000; - } + // Compress the bytes final Deflater compresser = new Deflater(COMPRESSION_LEVEL, true); compresser.setInput(in); @@ -64,9 +64,9 @@ public class CompressionZlib implements Compression { final byte[] output = new byte[len]; final int compressedDataLength = compresser.deflate(output); - if (compresser.finished() == false) { + if (compresser.finished() == false) return null; - } + return copyArray(output, compressedDataLength); } diff --git a/src/net/sourceforge/plantuml/code/CompressionZlibAttic.java b/src/net/sourceforge/plantuml/code/CompressionZlibAttic.java index 59616039a..3f97ec042 100644 --- a/src/net/sourceforge/plantuml/code/CompressionZlibAttic.java +++ b/src/net/sourceforge/plantuml/code/CompressionZlibAttic.java @@ -47,16 +47,16 @@ public class CompressionZlibAttic implements Compression { private static final int COMPRESSION_LEVEL = 9; public byte[] compress(byte[] in) { - if (USE_ZOPFLI) { + if (USE_ZOPFLI) return new CompressionZopfliZlib().compress(in); - } - if (in.length == 0) { + + if (in.length == 0) return null; - } + int len = in.length * 2; - if (len < 1000) { + if (len < 1000) len = 1000; - } + byte[] result = null; result = tryCompress(in, len); return result; @@ -70,9 +70,9 @@ public class CompressionZlibAttic implements Compression { final byte[] output = new byte[len]; final int compressedDataLength = compresser.deflate(output); - if (compresser.finished() == false) { + if (compresser.finished() == false) return null; - } + return copyArray(output, compressedDataLength); } @@ -84,11 +84,9 @@ public class CompressionZlibAttic implements Compression { int len = 100_000; byte[] result = null; result = tryDecompress(in2, len); - if (result == null) { + if (result == null) throw new NoPlantumlCompressionException("Too big?"); - } - return ByteArray.from(result); } catch (IOException e) { // Logme.error(e); @@ -98,18 +96,18 @@ public class CompressionZlibAttic implements Compression { } private byte[] tryDecompress(byte[] in, final int len) throws IOException { - if (len > 200_000) { + if (len > 200_000) throw new IOException("OutOfMemory"); - } + // Decompress the bytes final byte[] tmp = new byte[len]; final Inflater decompresser = new Inflater(true); decompresser.setInput(in); try { final int resultLength = decompresser.inflate(tmp); - if (decompresser.finished() == false) { + if (decompresser.finished() == false) return null; - } + decompresser.end(); final byte[] result = copyArray(tmp, resultLength); diff --git a/src/net/sourceforge/plantuml/code/CompressionZopfliZlib.java b/src/net/sourceforge/plantuml/code/CompressionZopfliZlib.java index 5103a2649..7e6d5ea12 100644 --- a/src/net/sourceforge/plantuml/code/CompressionZopfliZlib.java +++ b/src/net/sourceforge/plantuml/code/CompressionZopfliZlib.java @@ -43,13 +43,13 @@ import net.sourceforge.plantuml.zopfli.Zopfli; public class CompressionZopfliZlib implements Compression { public byte[] compress(byte[] in) { - if (in.length == 0) { + if (in.length == 0) return null; - } + int len = in.length * 2; - if (len < 100) { + if (len < 100) len = 100; - } + final Zopfli compressor = new Zopfli(len); final Options options = new Options(OutputFormat.DEFLATE, BlockSplitting.FIRST, 30); diff --git a/src/net/sourceforge/plantuml/code/TranscoderSmart.java b/src/net/sourceforge/plantuml/code/TranscoderSmart.java index 0f5c43261..0b1190883 100644 --- a/src/net/sourceforge/plantuml/code/TranscoderSmart.java +++ b/src/net/sourceforge/plantuml/code/TranscoderSmart.java @@ -46,20 +46,24 @@ public class TranscoderSmart implements Transcoder { new CompressionZlib()); private final Transcoder hexOnly = TranscoderImpl.utf8(new AsciiEncoderHex(), new ArobaseStringCompressor(), new CompressionNone()); + private final Transcoder zip = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor(), + new CompressionZip()); public String decode(String code) throws NoPlantumlCompressionException { // Work in progress // See https://github.com/plantuml/plantuml/issues/117 - if (code.startsWith("~0")) { + if (code.startsWith("~0")) return zlib.decode(code.substring(2)); - } - if (code.startsWith("~1")) { + + if (code.startsWith("~1")) return oldOne.decode(code.substring(2)); - } - if (code.startsWith("~h")) { + + if (code.startsWith("~h")) return hexOnly.decode(code.substring(2)); - } + + if (code.startsWith("~zip~")) + return zip.decode(code.substring(5)); try { return zlib.decode(code); diff --git a/src/net/sourceforge/plantuml/code/TranscoderSmartProtected.java b/src/net/sourceforge/plantuml/code/TranscoderSmartProtected.java index 0540d5974..57c6aba9c 100644 --- a/src/net/sourceforge/plantuml/code/TranscoderSmartProtected.java +++ b/src/net/sourceforge/plantuml/code/TranscoderSmartProtected.java @@ -46,20 +46,24 @@ public class TranscoderSmartProtected implements Transcoder { new CompressionZlib()); private final Transcoder hexOnly = TranscoderImpl.utf8(new AsciiEncoderHex(), new ArobaseStringCompressor(), new CompressionNone()); + private final Transcoder zip = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor(), + new CompressionZip()); public String decode(String code) throws NoPlantumlCompressionException { // Work in progress // See https://github.com/plantuml/plantuml/issues/117 - if (code.startsWith("~0")) { + if (code.startsWith("~0")) return decodeZlib(code.substring(2)); - } - if (code.startsWith("~1")) { + + if (code.startsWith("~1")) return decodeHuffman(code.substring(2)); - } - if (code.startsWith("~h")) { + + if (code.startsWith("~h")) return hexOnly.decode(code.substring(2)); - } + + if (code.startsWith("~zip~")) + return zip.decode(code.substring(5)); return decodeZlib(code); } diff --git a/src/net/sourceforge/plantuml/command/note/CommandFactoryNote.java b/src/net/sourceforge/plantuml/command/note/CommandFactoryNote.java index 57a67ed93..d53c567ca 100644 --- a/src/net/sourceforge/plantuml/command/note/CommandFactoryNote.java +++ b/src/net/sourceforge/plantuml/command/note/CommandFactoryNote.java @@ -35,6 +35,7 @@ */ package net.sourceforge.plantuml.command.note; +import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.LineLocation; import net.sourceforge.plantuml.baraye.IEntity; import net.sourceforge.plantuml.classdiagram.AbstractEntityDiagram; @@ -54,6 +55,7 @@ import net.sourceforge.plantuml.cucadiagram.Code; import net.sourceforge.plantuml.cucadiagram.Ident; import net.sourceforge.plantuml.cucadiagram.LeafType; import net.sourceforge.plantuml.cucadiagram.Stereotag; +import net.sourceforge.plantuml.cucadiagram.Stereotype; import net.sourceforge.plantuml.graphic.color.ColorParser; import net.sourceforge.plantuml.graphic.color.ColorType; import net.sourceforge.plantuml.ugraphic.color.NoSuchColorException; @@ -70,6 +72,8 @@ public final class CommandFactoryNote implements SingleMultiFactoryCommand{2})?"), // + RegexLeaf.spaceZeroOrMore(), // ColorParser.exp1(), // RegexLeaf.end() // ); @@ -89,6 +93,8 @@ public final class CommandFactoryNote implements SingleMultiFactoryCommand{2})?"), // + RegexLeaf.spaceZeroOrMore(), // ColorParser.exp1(), // RegexLeaf.end() // ); @@ -134,14 +140,21 @@ public final class CommandFactoryNote implements SingleMultiFactoryCommand { @@ -83,6 +88,12 @@ public final class CommandFactoryTipOnEntity implements SingleMultiFactoryComman RegexLeaf.spaceOneOrMore(), // partialPattern, // RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("TAGS1", Stereotag.pattern() + "?"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("STEREO", "(\\<{2}.*\\>{2})?"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("TAGS2", Stereotag.pattern() + "?"), // + RegexLeaf.spaceZeroOrMore(), // ColorParser.exp1(), // RegexLeaf.spaceZeroOrMore(), // new RegexLeaf("URL", "(" + UrlBuilder.getRegexp() + ")?"), // @@ -100,6 +111,12 @@ public final class CommandFactoryTipOnEntity implements SingleMultiFactoryComman RegexLeaf.spaceOneOrMore(), // partialPattern, // RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("TAGS1", Stereotag.pattern() + "?"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("STEREO", "(\\<{2}.*\\>{2})?"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("TAGS2", Stereotag.pattern() + "?"), // + RegexLeaf.spaceZeroOrMore(), // ColorParser.exp1(), // RegexLeaf.spaceZeroOrMore(), // new RegexLeaf("URL", "(" + UrlBuilder.getRegexp() + ")?"), // @@ -107,6 +124,10 @@ public final class CommandFactoryTipOnEntity implements SingleMultiFactoryComman ); } + private static ColorParser color() { + return ColorParser.simpleColor(ColorType.BACK); + } + public Command createSingleLine() { throw new UnsupportedOperationException(); } @@ -165,16 +186,31 @@ public final class CommandFactoryTipOnEntity implements SingleMultiFactoryComman tips = diagram.getOrCreateLeaf(identTip, identTip.toCode(diagram), LeafType.TIPS, null); final LinkType type = new LinkType(LinkDecor.NONE, LinkDecor.NONE).getInvisible(); final Link link; - if (position == Position.RIGHT) { + if (position == Position.RIGHT) link = new Link(diagram.getIEntityFactory(), diagram.getSkinParam().getCurrentStyleBuilder(), cl1, (IEntity) tips, type, LinkArg.noDisplay(1)); - } else { + else link = new Link(diagram.getIEntityFactory(), diagram.getSkinParam().getCurrentStyleBuilder(), (IEntity) tips, cl1, type, LinkArg.noDisplay(1)); - } + diagram.addLink(link); } tips.putTip(member, lines.toDisplay()); + + Colors colors = color().getColor(line0, diagram.getSkinParam().getIHtmlColorSet()); + + final String stereotypeString = line0.get("STEREO", 0); + Stereotype stereotype = null; + if (stereotypeString != null) { + stereotype = Stereotype.build(stereotypeString); + colors = colors.applyStereotypeForNote(stereotype, diagram.getSkinParam(), ColorParam.noteBackground, + ColorParam.noteBorder); + } + if (stereotypeString != null) + tips.setStereotype(stereotype); + + tips.setColors(colors); + return CommandExecutionResult.ok(); } diff --git a/src/net/sourceforge/plantuml/command/note/sequence/FactorySequenceNoteOverSeveralCommand.java b/src/net/sourceforge/plantuml/command/note/sequence/FactorySequenceNoteOverSeveralCommand.java index c4239d52f..b404b8ed4 100644 --- a/src/net/sourceforge/plantuml/command/note/sequence/FactorySequenceNoteOverSeveralCommand.java +++ b/src/net/sourceforge/plantuml/command/note/sequence/FactorySequenceNoteOverSeveralCommand.java @@ -73,7 +73,7 @@ public final class FactorySequenceNoteOverSeveralCommand implements SingleMultiF RegexLeaf.spaceZeroOrMore(), // new RegexLeaf("STYLE", "(note|hnote|rnote)"), // RegexLeaf.spaceZeroOrMore(), // - new RegexLeaf("STEREO", "(\\<{2}.*\\>{2})?"), // + new RegexLeaf("STEREO1", "(\\<{2}.*\\>{2})?"), // RegexLeaf.spaceZeroOrMore(), // new RegexLeaf("over"), // RegexLeaf.spaceOneOrMore(), // @@ -83,6 +83,8 @@ public final class FactorySequenceNoteOverSeveralCommand implements SingleMultiF RegexLeaf.spaceZeroOrMore(), // new RegexLeaf("P2", "([%pLN_.@]+|[%g][^%g]+[%g])"), // RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("STEREO2", "(\\<{2}.*\\>{2})?"), // + RegexLeaf.spaceZeroOrMore(), // color().getRegex(), // RegexLeaf.spaceZeroOrMore(), // new RegexLeaf("URL", "(" + UrlBuilder.getRegexp() + ")?"), RegexLeaf.end() // @@ -96,7 +98,7 @@ public final class FactorySequenceNoteOverSeveralCommand implements SingleMultiF RegexLeaf.spaceZeroOrMore(), // new RegexLeaf("STYLE", "(note|hnote|rnote)"), // RegexLeaf.spaceZeroOrMore(), // - new RegexLeaf("STEREO", "(\\<{2}.*\\>{2})?"), // + new RegexLeaf("STEREO1", "(\\<{2}.*\\>{2})?"), // RegexLeaf.spaceZeroOrMore(), // new RegexLeaf("over"), // RegexLeaf.spaceOneOrMore(), // @@ -106,6 +108,8 @@ public final class FactorySequenceNoteOverSeveralCommand implements SingleMultiF RegexLeaf.spaceZeroOrMore(), // new RegexLeaf("P2", "([%pLN_.@]+|[%g][^%g]+[%g])"), // RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("STEREO2", "(\\<{2}.*\\>{2})?"), // + RegexLeaf.spaceZeroOrMore(), // color().getRegex(), // RegexLeaf.spaceZeroOrMore(), // new RegexLeaf("URL", "(" + UrlBuilder.getRegexp() + ")?"), // @@ -166,7 +170,7 @@ public final class FactorySequenceNoteOverSeveralCommand implements SingleMultiF final Display display = diagram.manageVariable(lines.toDisplay()); final Note note = new Note(p1, p2, display, diagram.getSkinParam().getCurrentStyleBuilder()); Colors colors = color().getColor(line0, diagram.getSkinParam().getIHtmlColorSet()); - final String stereotypeString = line0.get("STEREO", 0); + final String stereotypeString = line0.getLazzy("STEREO", 0); if (stereotypeString != null) { final Stereotype stereotype = Stereotype.build(stereotypeString); colors = colors.applyStereotypeForNote(stereotype, diagram.getSkinParam(), ColorParam.noteBackground, diff --git a/src/net/sourceforge/plantuml/creole/Fission.java b/src/net/sourceforge/plantuml/creole/Fission.java index 067e749c5..1c8874a8c 100644 --- a/src/net/sourceforge/plantuml/creole/Fission.java +++ b/src/net/sourceforge/plantuml/creole/Fission.java @@ -37,7 +37,6 @@ package net.sourceforge.plantuml.creole; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -46,7 +45,6 @@ import net.sourceforge.plantuml.LineBreakStrategy; import net.sourceforge.plantuml.awt.geom.XDimension2D; import net.sourceforge.plantuml.creole.atom.AbstractAtom; import net.sourceforge.plantuml.creole.atom.Atom; -import net.sourceforge.plantuml.creole.legacy.AtomText; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.ugraphic.UGraphic; @@ -62,18 +60,18 @@ public class Fission { public List getSplitted(StringBounder stringBounder) { final double valueMaxWidth = maxWidth.getMaxWidth(); - if (valueMaxWidth == 0) { + if (valueMaxWidth == 0) return Arrays.asList(stripe); - } + final List result = new ArrayList<>(); StripeSimpleInternal current = new StripeSimpleInternal(stripe.getLHeader()); double remainingSpace = valueMaxWidth; - for (Atom atom : noHeader()) { + for (Atom atom : noHeader()) while (true) { final List splitInTwo = atom.splitInTwo(stringBounder, remainingSpace); final Atom part1 = splitInTwo.get(0); final double widthPart1 = part1.calculateDimension(stringBounder).getWidth(); - current.addAtom(part1, widthPart1); + current.addAtom(part1); remainingSpace -= widthPart1; if (remainingSpace <= 0) { result.add(current); @@ -91,25 +89,25 @@ public class Fission { remainingSpace = valueMaxWidth; } } - } - if (remainingSpace < valueMaxWidth) { + + if (remainingSpace < valueMaxWidth) result.add(current); - } + return Collections.unmodifiableList(result); } private List noHeader() { final List atoms = stripe.getAtoms(); - if (stripe.getLHeader() == null) { + if (stripe.getLHeader() == null) return atoms; - } + return atoms.subList(1, atoms.size()); } private static Atom blank(final Atom header) { - if (header == null) { + if (header == null) return null; - } + return new AbstractAtom() { public XDimension2D calculateDimension(StringBounder stringBounder) { @@ -126,31 +124,22 @@ public class Fission { }; } - private Collection getSplitted(StringBounder stringBounder, Atom atom) { - if (atom instanceof AtomText) { - return ((AtomText) atom).getSplitted(stringBounder, maxWidth); - } - return Collections.singleton(atom); - } - static class StripeSimpleInternal implements Stripe { private final List atoms = new ArrayList<>(); - private double totalWidth; private StripeSimpleInternal(Atom header) { - if (header != null) { + if (header != null) this.atoms.add(header); - } + } public List getAtoms() { return Collections.unmodifiableList(atoms); } - private void addAtom(Atom atom, double width) { + private void addAtom(Atom atom) { this.atoms.add(atom); - this.totalWidth += width; } public Atom getLHeader() { diff --git a/src/net/sourceforge/plantuml/preproc/Stdlib.java b/src/net/sourceforge/plantuml/preproc/Stdlib.java index 3627db18a..0227eced5 100644 --- a/src/net/sourceforge/plantuml/preproc/Stdlib.java +++ b/src/net/sourceforge/plantuml/preproc/Stdlib.java @@ -2,8 +2,10 @@ package net.sourceforge.plantuml.preproc; import static java.nio.charset.StandardCharsets.UTF_8; +import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; @@ -22,8 +24,12 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.imageio.ImageIO; + import net.sourceforge.plantuml.Log; import net.sourceforge.plantuml.brotli.BrotliInputStream; +import net.sourceforge.plantuml.code.Base64Coder; +import net.sourceforge.plantuml.creole.atom.AtomImg; import net.sourceforge.plantuml.log.Logme; import net.sourceforge.plantuml.security.SFile; @@ -90,6 +96,14 @@ public class Stdlib { return null; } + private static int read1byte(InputStream is) throws IOException { + return is.read() & 0xFF; + } + + private static int read2bytes(InputStream is) throws IOException { + return (read1byte(is) << 8) + read1byte(is); + } + private String loadResource(String file) throws IOException { final SoftReference cached = cache.get(file.toLowerCase()); if (cached != null) { @@ -110,6 +124,8 @@ public class Stdlib { dataStream.close(); return null; } + InputStream dataImagePngBase64Stream = null; + final List colors = new ArrayList<>(); try { StringBuilder found = null; while (true) { @@ -122,7 +138,7 @@ public class Stdlib { found = new StringBuilder(); while (true) { - final String s = dataStream.readUTF(); + String s = dataStream.readUTF(); if (s.equals(SEPARATOR)) { if (found != null) { final String result = found.toString(); @@ -131,6 +147,24 @@ public class Stdlib { } break; } + + if (s.contains(AtomImg.DATA_IMAGE_PNG_BASE64)) { + if (dataImagePngBase64Stream == null) { + dataImagePngBase64Stream = getDataImagePngBase64(); + final int size = read2bytes(dataImagePngBase64Stream); + for (int i = 0; i < size; i++) { + final int alpha = read1byte(dataImagePngBase64Stream); + final int red = read1byte(dataImagePngBase64Stream); + final int green = read1byte(dataImagePngBase64Stream); + final int blue = read1byte(dataImagePngBase64Stream); + final int rgb = (alpha << 24) + (red << 16) + (green << 8) + blue; + colors.add(rgb); + } + } + final String base64 = readOneImage(dataImagePngBase64Stream, colors); + s = s.replaceFirst(AtomImg.DATA_IMAGE_PNG_BASE64, AtomImg.DATA_IMAGE_PNG_BASE64 + base64); + } + if (found != null) { found.append(s); found.append("\n"); @@ -156,6 +190,27 @@ public class Stdlib { } finally { dataStream.close(); spriteStream.close(); + if (dataImagePngBase64Stream != null) + dataImagePngBase64Stream.close(); + } + + } + + private String readOneImage(InputStream is, List colors) throws IOException { + final int width = is.read(); + final int height = is.read(); + + final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + + for (int y = 0; y < height; y += 1) + for (int x = 0; x < width; x += 1) { + final int rgb = colors.get(read2bytes(is)); + result.setRGB(x, y, rgb); + } + + try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + ImageIO.write(result, "png", baos); + return new String(Base64Coder.encode(baos.toByteArray())); } } @@ -228,7 +283,13 @@ public class Stdlib { final InputStream raw = getInternalInputStream(name, "-dex.repx"); if (raw == null) return null; + return new BrotliInputStream(raw); + } + private InputStream getDataImagePngBase64() throws IOException { + final InputStream raw = getInternalInputStream(name, "-ghx.repx"); + if (raw == null) + return null; return new BrotliInputStream(raw); } diff --git a/src/net/sourceforge/plantuml/project/GanttDiagramFactory.java b/src/net/sourceforge/plantuml/project/GanttDiagramFactory.java index c48ebe4a6..de79dc195 100644 --- a/src/net/sourceforge/plantuml/project/GanttDiagramFactory.java +++ b/src/net/sourceforge/plantuml/project/GanttDiagramFactory.java @@ -134,31 +134,30 @@ public class GanttDiagramFactory extends PSystemCommandFactory { synchronized (cache) { if (cache.size() == 0) { - for (Subject subject : subjects()) { + for (Subject subject : subjects()) for (SentenceSimple sentenceA : subject.getSentences()) { cache.add(NaturalCommand.create(sentenceA)); for (SentenceSimple sentenceB : subject.getSentences()) { - if (sentenceA.getVerbPattern().equals(sentenceB.getVerbPattern()) == false) { + final String signatureA = sentenceA.getSignature(); + final String signatureB = sentenceB.getSignature(); + if (signatureA.equals(signatureB) == false) cache.add(NaturalCommand.create(new SentenceAnd(sentenceA, sentenceB))); - } + } } - } - for (Subject subject : subjects()) { - for (SentenceSimple sentenceA : subject.getSentences()) { - for (SentenceSimple sentenceB : subject.getSentences()) { + for (Subject subject : subjects()) + for (SentenceSimple sentenceA : subject.getSentences()) + for (SentenceSimple sentenceB : subject.getSentences()) for (SentenceSimple sentenceC : subject.getSentences()) { - if (sentenceA.getVerbPattern().equals(sentenceB.getVerbPattern()) == false - && sentenceA.getVerbPattern().equals(sentenceC.getVerbPattern()) == false - && sentenceC.getVerbPattern().equals(sentenceB.getVerbPattern()) == false) { + final String signatureA = sentenceA.getSignature(); + final String signatureB = sentenceB.getSignature(); + final String signatureC = sentenceC.getSignature(); + if (signatureA.equals(signatureB) == false && signatureA.equals(signatureC) == false + && signatureC.equals(signatureB) == false) cache.add( NaturalCommand.create(new SentenceAndAnd(sentenceA, sentenceB, sentenceC))); - } } - } - } - } } } return cache; diff --git a/src/net/sourceforge/plantuml/project/lang/SentenceSimple.java b/src/net/sourceforge/plantuml/project/lang/SentenceSimple.java index 100e171c0..e0094f2be 100644 --- a/src/net/sourceforge/plantuml/project/lang/SentenceSimple.java +++ b/src/net/sourceforge/plantuml/project/lang/SentenceSimple.java @@ -55,6 +55,10 @@ public abstract class SentenceSimple implements Sentence { this.complementii = complement; } + public String getSignature() { + return subjectii.getClass() + "/" + verb.getPattern() + "/" + complementii.getClass(); + } + public final IRegex toRegex() { if (complementii instanceof ComplementEmpty) return new RegexConcat(// @@ -89,10 +93,6 @@ public abstract class SentenceSimple implements Sentence { public abstract CommandExecutionResult execute(GanttDiagram project, Object subject, Object complement); - public final String getVerbPattern() { - return verb.getPattern(); - } - public IRegex getVerbRegex() { return verb; } diff --git a/src/net/sourceforge/plantuml/quantization/QColor.java b/src/net/sourceforge/plantuml/quantization/QColor.java index 196ef221b..a220b0fff 100644 --- a/src/net/sourceforge/plantuml/quantization/QColor.java +++ b/src/net/sourceforge/plantuml/quantization/QColor.java @@ -36,9 +36,7 @@ public final class QColor { 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); diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageNote.java b/src/net/sourceforge/plantuml/svek/image/EntityImageNote.java index fd2aa4943..0a5d0d32d 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageNote.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageNote.java @@ -67,6 +67,7 @@ import net.sourceforge.plantuml.skin.rose.Rose; import net.sourceforge.plantuml.style.PName; import net.sourceforge.plantuml.style.SName; import net.sourceforge.plantuml.style.Style; +import net.sourceforge.plantuml.style.StyleSignature; import net.sourceforge.plantuml.style.StyleSignatureBasic; import net.sourceforge.plantuml.svek.AbstractEntityImage; import net.sourceforge.plantuml.svek.ShapeType; @@ -88,7 +89,7 @@ public class EntityImageNote extends AbstractEntityImage implements Stencil { private final int marginX1 = 6; private final int marginX2 = 15; private final int marginY = 5; - private final boolean withShadow; + private final ISkinParam skinParam; private final Style style; @@ -98,7 +99,6 @@ public class EntityImageNote extends AbstractEntityImage implements Stencil { super(entity, getSkin(getISkinParam(skinParam, entity), entity)); this.skinParam = getISkinParam(skinParam, entity); - this.withShadow = getSkinParam().shadowing(getEntity().getStereotype()); final Display strings = entity.getDisplay(); this.style = getDefaultStyleDefinition(umlDiagramType.getStyleName()) @@ -186,8 +186,8 @@ public class EntityImageNote extends AbstractEntityImage implements Stencil { return new XDimension2D(width, height); } - private StyleSignatureBasic getDefaultStyleDefinition(SName sname) { - return StyleSignatureBasic.of(SName.root, SName.element, sname, SName.note); + private StyleSignature getDefaultStyleDefinition(SName sname) { + return StyleSignatureBasic.of(SName.root, SName.element, sname, SName.note).withTOBECHANGED(getStereo()); } final public void drawU(UGraphic ug) { diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageTips.java b/src/net/sourceforge/plantuml/svek/image/EntityImageTips.java index 1f509dd83..4703d818c 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageTips.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageTips.java @@ -58,6 +58,7 @@ import net.sourceforge.plantuml.skin.rose.Rose; import net.sourceforge.plantuml.style.PName; import net.sourceforge.plantuml.style.SName; import net.sourceforge.plantuml.style.Style; +import net.sourceforge.plantuml.style.StyleSignature; import net.sourceforge.plantuml.style.StyleSignatureBasic; import net.sourceforge.plantuml.svek.AbstractEntityImage; import net.sourceforge.plantuml.svek.Bibliotekon; @@ -70,7 +71,6 @@ import net.sourceforge.plantuml.ugraphic.color.HColor; public class EntityImageTips extends AbstractEntityImage { - final private Rose rose = new Rose(); private final ISkinParam skinParam; private final HColor noteBackgroundColor; @@ -96,8 +96,8 @@ public class EntityImageTips extends AbstractEntityImage { } - private StyleSignatureBasic getDefaultStyleDefinition(SName sname) { - return StyleSignatureBasic.of(SName.root, SName.element, sname, SName.note); + private StyleSignature getDefaultStyleDefinition(SName sname) { + return StyleSignatureBasic.of(SName.root, SName.element, sname, SName.note).withTOBECHANGED(getStereo()); } private Position getPosition() { diff --git a/src/net/sourceforge/plantuml/version/Version.java b/src/net/sourceforge/plantuml/version/Version.java index 80e8ef448..b055be947 100644 --- a/src/net/sourceforge/plantuml/version/Version.java +++ b/src/net/sourceforge/plantuml/version/Version.java @@ -45,7 +45,7 @@ public class Version { private static final int MAJOR_SEPARATOR = 1000000; public static int version() { - return 1202212; + return 1202213; } public static int versionPatched() { @@ -81,7 +81,7 @@ public class Version { } public static int beta() { - final int beta = 8; + final int beta = 0; return beta; } @@ -94,7 +94,7 @@ public class Version { } public static long compileTime() { - return 1666548746412L; + return 1668864137549L; } public static String compileTimeString() {