mirror of
https://github.com/octoleo/plantuml.git
synced 2024-11-25 06:17:33 +00:00
refactor: remove unused code
This commit is contained in:
parent
8f5c3379ed
commit
e92dcd400b
2
attic.md
2
attic.md
@ -4,4 +4,6 @@ This document catalogs code that was previously part of PlantUML but has since b
|
|||||||
It serves as a historical reference to ensure we remember and understand past decisions.
|
It serves as a historical reference to ensure we remember and understand past decisions.
|
||||||
|
|
||||||
- [logo language](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/logo)
|
- [logo language](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/logo)
|
||||||
|
- [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)
|
- [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)
|
||||||
|
@ -37,8 +37,6 @@ package net.atmp;
|
|||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Image;
|
|
||||||
import java.awt.geom.AffineTransform;
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -46,22 +44,16 @@ import java.io.OutputStream;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
|
||||||
|
|
||||||
import com.plantuml.api.cheerpj.WasmLog;
|
import com.plantuml.api.cheerpj.WasmLog;
|
||||||
|
|
||||||
import net.sourceforge.plantuml.AnimatedGifEncoder;
|
|
||||||
import net.sourceforge.plantuml.AnnotatedBuilder;
|
import net.sourceforge.plantuml.AnnotatedBuilder;
|
||||||
import net.sourceforge.plantuml.AnnotatedWorker;
|
import net.sourceforge.plantuml.AnnotatedWorker;
|
||||||
import net.sourceforge.plantuml.EmptyImageBuilder;
|
import net.sourceforge.plantuml.EmptyImageBuilder;
|
||||||
import net.sourceforge.plantuml.FileFormat;
|
import net.sourceforge.plantuml.FileFormat;
|
||||||
import net.sourceforge.plantuml.FileFormatOption;
|
import net.sourceforge.plantuml.FileFormatOption;
|
||||||
import net.sourceforge.plantuml.FileUtils;
|
|
||||||
import net.sourceforge.plantuml.OptionFlags;
|
import net.sourceforge.plantuml.OptionFlags;
|
||||||
import net.sourceforge.plantuml.Scale;
|
import net.sourceforge.plantuml.Scale;
|
||||||
import net.sourceforge.plantuml.TitledDiagram;
|
import net.sourceforge.plantuml.TitledDiagram;
|
||||||
import net.sourceforge.plantuml.anim.AffineTransformation;
|
|
||||||
import net.sourceforge.plantuml.anim.Animation;
|
|
||||||
import net.sourceforge.plantuml.api.ImageDataComplex;
|
import net.sourceforge.plantuml.api.ImageDataComplex;
|
||||||
import net.sourceforge.plantuml.api.ImageDataSimple;
|
import net.sourceforge.plantuml.api.ImageDataSimple;
|
||||||
import net.sourceforge.plantuml.braille.UGraphicBraille;
|
import net.sourceforge.plantuml.braille.UGraphicBraille;
|
||||||
@ -87,14 +79,10 @@ import net.sourceforge.plantuml.klimt.drawing.tikz.UGraphicTikz;
|
|||||||
import net.sourceforge.plantuml.klimt.drawing.txt.UGraphicTxt;
|
import net.sourceforge.plantuml.klimt.drawing.txt.UGraphicTxt;
|
||||||
import net.sourceforge.plantuml.klimt.drawing.visio.UGraphicVdx;
|
import net.sourceforge.plantuml.klimt.drawing.visio.UGraphicVdx;
|
||||||
import net.sourceforge.plantuml.klimt.font.StringBounder;
|
import net.sourceforge.plantuml.klimt.font.StringBounder;
|
||||||
import net.sourceforge.plantuml.klimt.geom.MinMax;
|
|
||||||
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
|
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
|
||||||
import net.sourceforge.plantuml.klimt.shape.TextBlock;
|
import net.sourceforge.plantuml.klimt.shape.TextBlock;
|
||||||
import net.sourceforge.plantuml.klimt.shape.UDrawable;
|
import net.sourceforge.plantuml.klimt.shape.UDrawable;
|
||||||
import net.sourceforge.plantuml.klimt.shape.URectangle;
|
import net.sourceforge.plantuml.klimt.shape.URectangle;
|
||||||
import net.sourceforge.plantuml.mjpeg.MJPEGGenerator;
|
|
||||||
import net.sourceforge.plantuml.security.SFile;
|
|
||||||
import net.sourceforge.plantuml.security.SImageIO;
|
|
||||||
import net.sourceforge.plantuml.skin.ColorParam;
|
import net.sourceforge.plantuml.skin.ColorParam;
|
||||||
import net.sourceforge.plantuml.skin.CornerParam;
|
import net.sourceforge.plantuml.skin.CornerParam;
|
||||||
import net.sourceforge.plantuml.skin.LineParam;
|
import net.sourceforge.plantuml.skin.LineParam;
|
||||||
@ -113,9 +101,6 @@ import net.sourceforge.plantuml.url.Url;
|
|||||||
|
|
||||||
public class ImageBuilder {
|
public class ImageBuilder {
|
||||||
|
|
||||||
// ::comment when __CORE__
|
|
||||||
private Animation animation;
|
|
||||||
// ::done
|
|
||||||
private boolean annotations;
|
private boolean annotations;
|
||||||
private HColor backcolor = getDefaultHBackColor();
|
private HColor backcolor = getDefaultHBackColor();
|
||||||
|
|
||||||
@ -223,9 +208,6 @@ public class ImageBuilder {
|
|||||||
public ImageBuilder styled(TitledDiagram diagram) {
|
public ImageBuilder styled(TitledDiagram diagram) {
|
||||||
skinParam = diagram.getSkinParam();
|
skinParam = diagram.getSkinParam();
|
||||||
stringBounder = fileFormatOption.getDefaultStringBounder(skinParam);
|
stringBounder = fileFormatOption.getDefaultStringBounder(skinParam);
|
||||||
// ::comment when __CORE__
|
|
||||||
animation = diagram.getAnimation();
|
|
||||||
// ::done
|
|
||||||
annotations = true;
|
annotations = true;
|
||||||
backcolor = diagram.calculateBackColor();
|
backcolor = diagram.calculateBackColor();
|
||||||
margin = calculateMargin(diagram);
|
margin = calculateMargin(diagram);
|
||||||
@ -246,21 +228,7 @@ public class ImageBuilder {
|
|||||||
udrawable = annotatedWorker.addAdd((TextBlock) udrawable);
|
udrawable = annotatedWorker.addAdd((TextBlock) udrawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ::comment when __CORE__
|
return writeImageInternal(os);
|
||||||
switch (fileFormatOption.getFileFormat()) {
|
|
||||||
case MJPEG:
|
|
||||||
return writeImageMjpeg(os);
|
|
||||||
case ANIMATED_GIF:
|
|
||||||
return writeImageAnimatedGif(os);
|
|
||||||
default:
|
|
||||||
return writeImageInternal(os, animation);
|
|
||||||
// ::done
|
|
||||||
// ::uncomment when __CORE__
|
|
||||||
// return writeImageInternal(os);
|
|
||||||
// ::done
|
|
||||||
// ::comment when __CORE__
|
|
||||||
}
|
|
||||||
// ::done
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] writeByteArray() throws IOException {
|
public byte[] writeByteArray() throws IOException {
|
||||||
@ -270,34 +238,19 @@ public class ImageBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ::revert when __CORE__
|
private ImageData writeImageInternal(OutputStream os) throws IOException {
|
||||||
private ImageData writeImageInternal(OutputStream os, Animation animationArg) throws IOException {
|
|
||||||
// private ImageData writeImageInternal(OutputStream os) throws IOException {
|
|
||||||
// ::done
|
|
||||||
XDimension2D dim = getFinalDimension();
|
XDimension2D dim = getFinalDimension();
|
||||||
double dx = 0;
|
double dx = 0;
|
||||||
double dy = 0;
|
double dy = 0;
|
||||||
// ::comment when __CORE__
|
|
||||||
if (animationArg != null) {
|
|
||||||
final MinMax minmax = animationArg.getMinMax(dim);
|
|
||||||
animationArg.setDimension(dim);
|
|
||||||
dim = minmax.getDimension();
|
|
||||||
dx = -minmax.getMinX();
|
|
||||||
dy = -minmax.getMinY();
|
|
||||||
}
|
|
||||||
// ::done
|
|
||||||
final Scale scale = titledDiagram == null ? null : titledDiagram.getScale();
|
final Scale scale = titledDiagram == null ? null : titledDiagram.getScale();
|
||||||
final double scaleFactor = (scale == null ? 1 : scale.getScale(dim.getWidth(), dim.getHeight())) * getDpi()
|
final double scaleFactor = (scale == null ? 1 : scale.getScale(dim.getWidth(), dim.getHeight())) * getDpi()
|
||||||
/ 96.0;
|
/ 96.0;
|
||||||
if (scaleFactor <= 0)
|
if (scaleFactor <= 0)
|
||||||
throw new IllegalStateException("Bad scaleFactor");
|
throw new IllegalStateException("Bad scaleFactor");
|
||||||
WasmLog.log("...image drawing...");
|
WasmLog.log("...image drawing...");
|
||||||
// ::revert when __CORE__
|
UGraphic ug = createUGraphic(dim, dx, dy, scaleFactor,
|
||||||
UGraphic ug = createUGraphic(dim, animationArg, dx, dy, scaleFactor,
|
|
||||||
titledDiagram == null ? new Pragma() : titledDiagram.getPragma());
|
titledDiagram == null ? new Pragma() : titledDiagram.getPragma());
|
||||||
// UGraphic ug = createUGraphic(dim, dx, dy, scaleFactor,
|
|
||||||
// titledDiagram == null ? new Pragma() : titledDiagram.getPragma());
|
|
||||||
// ::done
|
|
||||||
maybeDrawBorder(ug, dim);
|
maybeDrawBorder(ug, dim);
|
||||||
if (randomPixel)
|
if (randomPixel)
|
||||||
drawRandomPoint(ug);
|
drawRandomPoint(ug);
|
||||||
@ -330,8 +283,8 @@ public class ImageBuilder {
|
|||||||
if (stroke == null)
|
if (stroke == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
final URectangle rectangle = URectangle.build(dim.getWidth() - stroke.getThickness(),
|
final URectangle rectangle = URectangle
|
||||||
dim.getHeight() - stroke.getThickness())
|
.build(dim.getWidth() - stroke.getThickness(), dim.getHeight() - stroke.getThickness())
|
||||||
.rounded(skinParam.getRoundCorner(CornerParam.diagramBorder, null));
|
.rounded(skinParam.getRoundCorner(CornerParam.diagramBorder, null));
|
||||||
|
|
||||||
ug.apply(color == null ? HColors.BLACK : color).apply(stroke).draw(rectangle);
|
ug.apply(color == null ? HColors.BLACK : color).apply(stroke).draw(rectangle);
|
||||||
@ -364,83 +317,13 @@ public class ImageBuilder {
|
|||||||
return ug;
|
return ug;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ::comment when __CORE__
|
private UGraphic createUGraphic(final XDimension2D dim, double dx, double dy, double scaleFactor, Pragma pragma) {
|
||||||
private ImageData writeImageMjpeg(OutputStream os) throws IOException {
|
|
||||||
|
|
||||||
final XDimension2D dim = getFinalDimension();
|
|
||||||
|
|
||||||
final SFile f = new SFile("c:/tmp.avi");
|
|
||||||
|
|
||||||
final int nbframe = 100;
|
|
||||||
|
|
||||||
final MJPEGGenerator m = new MJPEGGenerator(f, getAviImage(null).getWidth(null),
|
|
||||||
getAviImage(null).getHeight(null), 12.0, nbframe);
|
|
||||||
for (int i = 0; i < nbframe; i++) {
|
|
||||||
// AffineTransform at = AffineTransform.getRotateInstance(1.0);
|
|
||||||
AffineTransform at = AffineTransform.getTranslateInstance(dim.getWidth() / 2, dim.getHeight() / 2);
|
|
||||||
at.rotate(90.0 * Math.PI / 180.0 * i / 100);
|
|
||||||
at.translate(-dim.getWidth() / 2, -dim.getHeight() / 2);
|
|
||||||
// final AffineTransform at = AffineTransform.getTranslateInstance(i, 0);
|
|
||||||
// final ImageIcon ii = new ImageIcon(getAviImage(at));
|
|
||||||
// m.addImage(ii.getImage());
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
m.finishAVI();
|
|
||||||
|
|
||||||
FileUtils.copyToStream(f, os);
|
|
||||||
|
|
||||||
return createImageData(dim);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ImageData writeImageAnimatedGif(OutputStream os) throws IOException {
|
|
||||||
|
|
||||||
final XDimension2D dim = getFinalDimension();
|
|
||||||
|
|
||||||
final MinMax minmax = animation.getMinMax(dim);
|
|
||||||
|
|
||||||
final AnimatedGifEncoder e = new AnimatedGifEncoder();
|
|
||||||
// e.setQuality(1);
|
|
||||||
e.setRepeat(0);
|
|
||||||
e.start(os);
|
|
||||||
// e.setDelay(1000); // 1 frame per sec
|
|
||||||
// e.setDelay(100); // 10 frame per sec
|
|
||||||
e.setDelay(60); // 16 frame per sec
|
|
||||||
// e.setDelay(50); // 20 frame per sec
|
|
||||||
|
|
||||||
for (AffineTransformation at : animation.getAll()) {
|
|
||||||
final ImageIcon ii = new ImageIcon(getAviImage(at));
|
|
||||||
e.addFrame((BufferedImage) ii.getImage());
|
|
||||||
}
|
|
||||||
e.finish();
|
|
||||||
return createImageData(dim);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Image getAviImage(AffineTransformation affineTransform) throws IOException {
|
|
||||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
writeImageInternal(baos, Animation.singleton(affineTransform));
|
|
||||||
baos.close();
|
|
||||||
return SImageIO.read(baos.toByteArray());
|
|
||||||
}
|
|
||||||
// ::done
|
|
||||||
|
|
||||||
// ::revert when __CORE__
|
|
||||||
private UGraphic createUGraphic(final XDimension2D dim, Animation animationArg, double dx, double dy,
|
|
||||||
double scaleFactor, Pragma pragma) {
|
|
||||||
// private UGraphic createUGraphic(final XDimension2D dim, double dx, double dy,
|
|
||||||
// double scaleFactor, Pragma pragma) {
|
|
||||||
// ::done
|
|
||||||
final ColorMapper colorMapper = fileFormatOption.getColorMapper();
|
final ColorMapper colorMapper = fileFormatOption.getColorMapper();
|
||||||
switch (fileFormatOption.getFileFormat()) {
|
switch (fileFormatOption.getFileFormat()) {
|
||||||
case PNG:
|
case PNG:
|
||||||
case RAW:
|
case RAW:
|
||||||
// ::comment when __CORE__
|
return createUGraphicPNG(scaleFactor, dim, dx, dy, fileFormatOption.getWatermark(),
|
||||||
return createUGraphicPNG(scaleFactor, dim, animationArg, dx, dy, fileFormatOption.getWatermark(),
|
|
||||||
fileFormatOption.getFileFormat());
|
fileFormatOption.getFileFormat());
|
||||||
// ::done
|
|
||||||
// ::uncomment when __CORE__
|
|
||||||
// return createUGraphicPNG(scaleFactor, dim, dx, dy,
|
|
||||||
// fileFormatOption.getWatermark(), fileFormatOption.getFileFormat());
|
|
||||||
// ::done
|
|
||||||
case SVG:
|
case SVG:
|
||||||
return createUGraphicSVG(scaleFactor, dim, pragma);
|
return createUGraphicSVG(scaleFactor, dim, pragma);
|
||||||
// ::comment when __CORE__
|
// ::comment when __CORE__
|
||||||
@ -492,13 +375,8 @@ public class ImageBuilder {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ::uncomment when __CORE__
|
private UGraphic createUGraphicPNG(double scaleFactor, final XDimension2D dim, double dx, double dy,
|
||||||
// private UGraphic createUGraphicPNG(double scaleFactor, final XDimension2D
|
String watermark, FileFormat format) {
|
||||||
// dim, double dx, double dy, String watermark, FileFormat format) {
|
|
||||||
// ::done
|
|
||||||
// ::comment when __CORE__
|
|
||||||
private UGraphic createUGraphicPNG(double scaleFactor, final XDimension2D dim, Animation affineTransforms,
|
|
||||||
double dx, double dy, String watermark, FileFormat format) {
|
|
||||||
// ::done
|
// ::done
|
||||||
Color pngBackColor = new Color(0, 0, 0, 0);
|
Color pngBackColor = new Color(0, 0, 0, 0);
|
||||||
|
|
||||||
@ -513,15 +391,9 @@ public class ImageBuilder {
|
|||||||
(int) (dim.getHeight() * scaleFactor), pngBackColor, stringBounder);
|
(int) (dim.getHeight() * scaleFactor), pngBackColor, stringBounder);
|
||||||
final Graphics2D graphics2D = builder.getGraphics2D();
|
final Graphics2D graphics2D = builder.getGraphics2D();
|
||||||
|
|
||||||
// ::comment when __CORE__
|
|
||||||
final UGraphicG2d ug = new UGraphicG2d(backcolor, fileFormatOption.getColorMapper(), stringBounder, graphics2D,
|
final UGraphicG2d ug = new UGraphicG2d(backcolor, fileFormatOption.getColorMapper(), stringBounder, graphics2D,
|
||||||
scaleFactor, dx, dy, format, affineTransforms == null ? null : affineTransforms.getFirst());
|
scaleFactor, dx, dy, format);
|
||||||
// ::done
|
|
||||||
// ::uncomment when __CORE__
|
|
||||||
// final UGraphicG2d ug = new UGraphicG2d(backcolor,
|
|
||||||
// fileFormatOption.getColorMapper(), stringBounder, graphics2D,
|
|
||||||
// scaleFactor, dx, dy, format);
|
|
||||||
// ::done
|
|
||||||
ug.setBufferedImage(builder.getBufferedImage());
|
ug.setBufferedImage(builder.getBufferedImage());
|
||||||
final BufferedImage im = ug.getBufferedImage();
|
final BufferedImage im = ug.getBufferedImage();
|
||||||
if (this.backcolor instanceof HColorGradient)
|
if (this.backcolor instanceof HColorGradient)
|
||||||
|
@ -76,8 +76,6 @@ public enum FileFormat {
|
|||||||
SCXML("application/scxml+xml"), //
|
SCXML("application/scxml+xml"), //
|
||||||
GRAPHML("application/graphml+xml"), //
|
GRAPHML("application/graphml+xml"), //
|
||||||
PDF("application/pdf"), //
|
PDF("application/pdf"), //
|
||||||
MJPEG("video/x-msvideo"), //
|
|
||||||
ANIMATED_GIF("image/gif"), //
|
|
||||||
HTML("text/html"), //
|
HTML("text/html"), //
|
||||||
HTML5("text/html"), //
|
HTML5("text/html"), //
|
||||||
VDX("application/vnd.visio.xml"), //
|
VDX("application/vnd.visio.xml"), //
|
||||||
@ -112,15 +110,9 @@ public enum FileFormat {
|
|||||||
if (name().startsWith("XMI"))
|
if (name().startsWith("XMI"))
|
||||||
return ".xmi";
|
return ".xmi";
|
||||||
|
|
||||||
if (this == MJPEG)
|
|
||||||
return ".avi";
|
|
||||||
|
|
||||||
if (this == LATEX || this == LATEX_NO_PREAMBLE)
|
if (this == LATEX || this == LATEX_NO_PREAMBLE)
|
||||||
return ".tex";
|
return ".tex";
|
||||||
|
|
||||||
if (this == ANIMATED_GIF)
|
|
||||||
return ".gif";
|
|
||||||
|
|
||||||
if (this == BRAILLE_PNG)
|
if (this == BRAILLE_PNG)
|
||||||
return ".braille.png";
|
return ".braille.png";
|
||||||
|
|
||||||
|
@ -42,8 +42,6 @@ import java.util.Map;
|
|||||||
import net.atmp.ImageBuilder;
|
import net.atmp.ImageBuilder;
|
||||||
import net.sourceforge.plantuml.abel.DisplayPositioned;
|
import net.sourceforge.plantuml.abel.DisplayPositioned;
|
||||||
import net.sourceforge.plantuml.abel.DisplayPositionned;
|
import net.sourceforge.plantuml.abel.DisplayPositionned;
|
||||||
import net.sourceforge.plantuml.anim.Animation;
|
|
||||||
import net.sourceforge.plantuml.anim.AnimationDecoder;
|
|
||||||
import net.sourceforge.plantuml.api.ApiStable;
|
import net.sourceforge.plantuml.api.ApiStable;
|
||||||
import net.sourceforge.plantuml.command.CommandExecutionResult;
|
import net.sourceforge.plantuml.command.CommandExecutionResult;
|
||||||
import net.sourceforge.plantuml.core.Diagram;
|
import net.sourceforge.plantuml.core.Diagram;
|
||||||
@ -88,10 +86,6 @@ public abstract class TitledDiagram extends AbstractPSystem implements Diagram,
|
|||||||
|
|
||||||
private final SkinParam skinParam;
|
private final SkinParam skinParam;
|
||||||
|
|
||||||
// ::comment when __CORE__
|
|
||||||
private Animation animation;
|
|
||||||
// ::done
|
|
||||||
|
|
||||||
private final Pragma pragma = new Pragma();
|
private final Pragma pragma = new Pragma();
|
||||||
|
|
||||||
public Pragma getPragma() {
|
public Pragma getPragma() {
|
||||||
@ -218,21 +212,6 @@ public abstract class TitledDiagram extends AbstractPSystem implements Diagram,
|
|||||||
return ClockwiseTopRightBottomLeft.same(10);
|
return ClockwiseTopRightBottomLeft.same(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ::comment when __CORE__
|
|
||||||
final public void setAnimation(Iterable<CharSequence> animationData) {
|
|
||||||
// try {
|
|
||||||
final AnimationDecoder animationDecoder = new AnimationDecoder(animationData);
|
|
||||||
this.animation = Animation.create(animationDecoder.decode());
|
|
||||||
// } catch (ScriptException e) {
|
|
||||||
// Logme.error(e);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
final public Animation getAnimation() {
|
|
||||||
return animation;
|
|
||||||
}
|
|
||||||
// ::done
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImageBuilder createImageBuilder(FileFormatOption fileFormatOption) throws IOException {
|
public ImageBuilder createImageBuilder(FileFormatOption fileFormatOption) throws IOException {
|
||||||
return super.createImageBuilder(fileFormatOption).styled(this);
|
return super.createImageBuilder(fileFormatOption).styled(this);
|
||||||
|
@ -38,10 +38,8 @@ package net.sourceforge.plantuml;
|
|||||||
import static net.atmp.ImageBuilder.plainImageBuilder;
|
import static net.atmp.ImageBuilder.plainImageBuilder;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.geom.AffineTransform;
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
@ -74,10 +72,8 @@ import net.sourceforge.plantuml.klimt.shape.TextBlock;
|
|||||||
import net.sourceforge.plantuml.klimt.shape.UDrawable;
|
import net.sourceforge.plantuml.klimt.shape.UDrawable;
|
||||||
import net.sourceforge.plantuml.klimt.shape.UImage;
|
import net.sourceforge.plantuml.klimt.shape.UImage;
|
||||||
import net.sourceforge.plantuml.log.Logme;
|
import net.sourceforge.plantuml.log.Logme;
|
||||||
import net.sourceforge.plantuml.mjpeg.MJPEGGenerator;
|
|
||||||
import net.sourceforge.plantuml.pdf.PdfConverter;
|
import net.sourceforge.plantuml.pdf.PdfConverter;
|
||||||
import net.sourceforge.plantuml.security.SFile;
|
import net.sourceforge.plantuml.security.SFile;
|
||||||
import net.sourceforge.plantuml.security.SImageIO;
|
|
||||||
import net.sourceforge.plantuml.security.SecurityUtils;
|
import net.sourceforge.plantuml.security.SecurityUtils;
|
||||||
import net.sourceforge.plantuml.skin.UmlDiagramType;
|
import net.sourceforge.plantuml.skin.UmlDiagramType;
|
||||||
import net.sourceforge.plantuml.style.NoStyleAvailableException;
|
import net.sourceforge.plantuml.style.NoStyleAvailableException;
|
||||||
@ -258,27 +254,6 @@ public abstract class UmlDiagram extends TitledDiagram implements Diagram, Annot
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ::comment when __CORE__
|
// ::comment when __CORE__
|
||||||
private void exportDiagramInternalMjpeg(OutputStream os) throws IOException {
|
|
||||||
final SFile f = new SFile("c:/test.avi");
|
|
||||||
final int nb = 150;
|
|
||||||
final double framerate = 30;
|
|
||||||
final MJPEGGenerator m = new MJPEGGenerator(f, 640, 480, framerate, nb);
|
|
||||||
|
|
||||||
for (int i = 0; i < nb; i++) {
|
|
||||||
final AffineTransform at = new AffineTransform();
|
|
||||||
final double coef = (nb - 1 - i) * 1.0 / nb;
|
|
||||||
at.setToShear(coef, coef);
|
|
||||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
// exportDiagramTOxxBEREMOVED(baos, null, 0, new
|
|
||||||
// FileFormatOption(FileFormat.PNG, at));
|
|
||||||
baos.close();
|
|
||||||
final BufferedImage im = SImageIO.read(baos.toByteArray());
|
|
||||||
m.addImage(im);
|
|
||||||
}
|
|
||||||
m.finishAVI();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private ImageData exportDiagramInternalPdf(OutputStream os, int index) throws IOException {
|
private ImageData exportDiagramInternalPdf(OutputStream os, int index) throws IOException {
|
||||||
final File svg = FileUtils.createTempFileLegacy("pdf", ".svf");
|
final File svg = FileUtils.createTempFileLegacy("pdf", ".svf");
|
||||||
final File pdfFile = FileUtils.createTempFileLegacy("pdf", ".pdf");
|
final File pdfFile = FileUtils.createTempFileLegacy("pdf", ".pdf");
|
||||||
|
@ -1,157 +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.anim;
|
|
||||||
|
|
||||||
import java.awt.geom.AffineTransform;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import net.sourceforge.plantuml.StringUtils;
|
|
||||||
import net.sourceforge.plantuml.klimt.geom.MinMax;
|
|
||||||
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
|
|
||||||
import net.sourceforge.plantuml.klimt.geom.XPoint2D;
|
|
||||||
|
|
||||||
public class AffineTransformation {
|
|
||||||
// ::remove folder when __HAXE__
|
|
||||||
// ::remove folder when __CORE__
|
|
||||||
|
|
||||||
static private final Pattern rotate = Pattern.compile("rotate\\s+(-?\\d+\\.?\\d*)");
|
|
||||||
static private final Pattern shear = Pattern.compile("shear\\s+(-?\\d+\\.?\\d*)\\s+(-?\\d+\\.?\\d*)");
|
|
||||||
static private final Pattern translate = Pattern.compile("translate\\s+(-?\\d+\\.?\\d*)\\s+(-?\\d+\\.?\\d*)");
|
|
||||||
static private final Pattern scale = Pattern.compile("scale\\s+(-?\\d+\\.?\\d*)\\s+(-?\\d+\\.?\\d*)");
|
|
||||||
static private final Pattern color = Pattern.compile("color\\s+.*");
|
|
||||||
|
|
||||||
private final AffineTransform affineTransform;
|
|
||||||
private XDimension2D dimension;
|
|
||||||
|
|
||||||
private AffineTransformation(AffineTransform affineTransform) {
|
|
||||||
this.affineTransform = Objects.requireNonNull(affineTransform);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AffineTransformation compose(AffineTransformation other) {
|
|
||||||
final AffineTransform tmp = new AffineTransform(this.affineTransform);
|
|
||||||
tmp.concatenate(other.affineTransform);
|
|
||||||
return new AffineTransformation(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AffineTransformation from(AffineTransform affineTransform) {
|
|
||||||
return new AffineTransformation(affineTransform);
|
|
||||||
}
|
|
||||||
|
|
||||||
static AffineTransformation create(String value) {
|
|
||||||
final StringTokenizer st = new StringTokenizer(value, "|");
|
|
||||||
AffineTransformation result = null;
|
|
||||||
while (st.hasMoreTokens()) {
|
|
||||||
final String s = st.nextToken();
|
|
||||||
final AffineTransformation tmp = createSimple(s);
|
|
||||||
if (tmp != null) {
|
|
||||||
if (result == null) {
|
|
||||||
result = tmp;
|
|
||||||
} else {
|
|
||||||
result = result.compose(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AffineTransformation createSimple(String value) {
|
|
||||||
Matcher m = rotate.matcher(StringUtils.trin(value));
|
|
||||||
if (m.find()) {
|
|
||||||
final double angle = Double.parseDouble(m.group(1));
|
|
||||||
return new AffineTransformation(AffineTransform.getRotateInstance(angle * Math.PI / 180.0));
|
|
||||||
}
|
|
||||||
m = shear.matcher(value);
|
|
||||||
if (m.find()) {
|
|
||||||
final double shx = Double.parseDouble(m.group(1));
|
|
||||||
final double shy = Double.parseDouble(m.group(2));
|
|
||||||
return new AffineTransformation(AffineTransform.getShearInstance(shx, shy));
|
|
||||||
}
|
|
||||||
m = translate.matcher(value);
|
|
||||||
if (m.find()) {
|
|
||||||
final double tx = Double.parseDouble(m.group(1));
|
|
||||||
final double ty = Double.parseDouble(m.group(2));
|
|
||||||
return new AffineTransformation(AffineTransform.getTranslateInstance(tx, ty));
|
|
||||||
}
|
|
||||||
m = scale.matcher(value);
|
|
||||||
if (m.find()) {
|
|
||||||
final double scalex = Double.parseDouble(m.group(1));
|
|
||||||
final double scaley = Double.parseDouble(m.group(2));
|
|
||||||
return new AffineTransformation(AffineTransform.getScaleInstance(scalex, scaley));
|
|
||||||
}
|
|
||||||
m = color.matcher(value);
|
|
||||||
if (m.find()) {
|
|
||||||
return new AffineTransformation(new AffineTransform());
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final AffineTransform getAffineTransform() {
|
|
||||||
return getAffineTransform(dimension);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AffineTransform getAffineTransform(XDimension2D dimension) {
|
|
||||||
if (dimension == null) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
final AffineTransform at = AffineTransform.getTranslateInstance(dimension.getWidth() / 2,
|
|
||||||
dimension.getHeight() / 2);
|
|
||||||
at.concatenate(affineTransform);
|
|
||||||
at.translate(-dimension.getWidth() / 2, -dimension.getHeight() / 2);
|
|
||||||
|
|
||||||
return at;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDimension(XDimension2D dim) {
|
|
||||||
this.dimension = dim;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public MinMax getMinMax(XDimension2D rect) {
|
|
||||||
MinMax result = MinMax.getEmpty(false);
|
|
||||||
final AffineTransform tmp = getAffineTransform(rect);
|
|
||||||
|
|
||||||
result = result.addPoint(new XPoint2D(0, 0).transform(tmp));
|
|
||||||
result = result.addPoint(new XPoint2D(0, rect.getHeight()).transform(tmp));
|
|
||||||
result = result.addPoint(new XPoint2D(rect.getWidth(), 0).transform(tmp));
|
|
||||||
result = result.addPoint(new XPoint2D(rect.getWidth(), rect.getHeight()).transform(tmp));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,99 +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.anim;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import net.sourceforge.plantuml.klimt.geom.MinMax;
|
|
||||||
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
|
|
||||||
|
|
||||||
public class Animation {
|
|
||||||
|
|
||||||
private final List<AffineTransformation> all;
|
|
||||||
|
|
||||||
private Animation(List<AffineTransformation> all) {
|
|
||||||
if (all.size() == 0) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
this.all = all;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Animation singleton(AffineTransformation affineTransformation) {
|
|
||||||
if (affineTransformation == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new Animation(Collections.singletonList(affineTransformation));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Animation create(List<String> descriptions) {
|
|
||||||
final List<AffineTransformation> all = new ArrayList<>();
|
|
||||||
for (String s : descriptions) {
|
|
||||||
final AffineTransformation tmp = AffineTransformation.create(s);
|
|
||||||
if (tmp != null) {
|
|
||||||
all.add(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new Animation(all);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<AffineTransformation> getAll() {
|
|
||||||
return Collections.unmodifiableCollection(all);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDimension(XDimension2D dim) {
|
|
||||||
for (AffineTransformation affineTransform : all) {
|
|
||||||
affineTransform.setDimension(dim);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public AffineTransformation getFirst() {
|
|
||||||
return all.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MinMax getMinMax(XDimension2D dim) {
|
|
||||||
MinMax result = MinMax.getEmpty(false);
|
|
||||||
for (AffineTransformation affineTransform : all) {
|
|
||||||
final MinMax m = affineTransform.getMinMax(dim);
|
|
||||||
result = result.addMinMax(m);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,78 +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.anim;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
|
|
||||||
public class AnimationDecoder {
|
|
||||||
|
|
||||||
private final List<String> result = new ArrayList<>();
|
|
||||||
|
|
||||||
public AnimationDecoder(Iterable<CharSequence> data) {
|
|
||||||
|
|
||||||
for (final Iterator<CharSequence> it = data.iterator(); it.hasNext();) {
|
|
||||||
String line = it.next().toString();
|
|
||||||
if (line.matches("^\\s*\\[script\\]\\s*$")) {
|
|
||||||
final StringBuilder scriptText = new StringBuilder();
|
|
||||||
while (true) {
|
|
||||||
line = it.next().toString();
|
|
||||||
if (line.matches("^\\s*\\[/script\\]\\s*$")) {
|
|
||||||
final AnimationScript script = new AnimationScript();
|
|
||||||
final String out = script.eval(scriptText.toString());
|
|
||||||
for (final StringTokenizer st = new StringTokenizer(out, "\n"); st.hasMoreTokens();) {
|
|
||||||
result.add(st.nextToken());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
scriptText.append(line);
|
|
||||||
scriptText.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.add(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> decode() {
|
|
||||||
return Collections.unmodifiableList(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,71 +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.anim;
|
|
||||||
|
|
||||||
public class AnimationScript {
|
|
||||||
|
|
||||||
// private final ScriptEngine engine;
|
|
||||||
|
|
||||||
public AnimationScript() {
|
|
||||||
|
|
||||||
// final ScriptEngineManager manager = new ScriptEngineManager();
|
|
||||||
// engine = manager.getEngineByName("js");
|
|
||||||
|
|
||||||
// ScriptEngineManager manager = new ScriptEngineManager();
|
|
||||||
// List<ScriptEngineFactory> factories = manager.getEngineFactories();
|
|
||||||
// for (ScriptEngineFactory factory : factories) {
|
|
||||||
// System.out.println("Name : " + factory.getEngineName());
|
|
||||||
// System.out.println("Version : " + factory.getEngineVersion());
|
|
||||||
// System.out.println("Language name : " + factory.getLanguageName());
|
|
||||||
// System.out.println("Language version : " + factory.getLanguageVersion());
|
|
||||||
// System.out.println("Extensions : " + factory.getExtensions());
|
|
||||||
// System.out.println("Mime types : " + factory.getMimeTypes());
|
|
||||||
// System.out.println("Names : " + factory.getNames());
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public String eval(String line) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
// final ScriptContext context = engine.getContext();
|
|
||||||
// final StringWriter sw = new StringWriter();
|
|
||||||
// context.setWriter(new PrintWriter(sw));
|
|
||||||
// engine.eval(line, context);
|
|
||||||
// final String result = sw.toString();
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +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.command;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import net.sourceforge.plantuml.UmlDiagram;
|
|
||||||
import net.sourceforge.plantuml.regex.IRegex;
|
|
||||||
import net.sourceforge.plantuml.regex.RegexConcat;
|
|
||||||
import net.sourceforge.plantuml.regex.RegexLeaf;
|
|
||||||
import net.sourceforge.plantuml.regex.RegexResult;
|
|
||||||
import net.sourceforge.plantuml.utils.LineLocation;
|
|
||||||
|
|
||||||
public class CommandAffineTransform extends SingleLineCommand2<UmlDiagram> {
|
|
||||||
|
|
||||||
public static final CommandAffineTransform ME = new CommandAffineTransform();
|
|
||||||
|
|
||||||
private CommandAffineTransform() {
|
|
||||||
super(getRegexConcat());
|
|
||||||
}
|
|
||||||
|
|
||||||
static IRegex getRegexConcat() {
|
|
||||||
return RegexConcat.build(CommandAffineTransform.class.getName(), RegexLeaf.start(), //
|
|
||||||
new RegexLeaf("!transformation"), //
|
|
||||||
RegexLeaf.spaceOneOrMore(), //
|
|
||||||
new RegexLeaf("ANIMATION", "([^{}]*)"), RegexLeaf.end()); //
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected CommandExecutionResult executeArg(UmlDiagram diagram, LineLocation location, RegexResult arg) {
|
|
||||||
final CharSequence value = arg.get("ANIMATION", 0);
|
|
||||||
// ::comment when __CORE__
|
|
||||||
diagram.setAnimation(Collections.singletonList(value));
|
|
||||||
// ::done
|
|
||||||
return CommandExecutionResult.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,60 +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.command;
|
|
||||||
|
|
||||||
import net.sourceforge.plantuml.TitledDiagram;
|
|
||||||
import net.sourceforge.plantuml.utils.BlocLines;
|
|
||||||
|
|
||||||
public class CommandAffineTransformMultiline extends CommandMultilines<TitledDiagram> {
|
|
||||||
|
|
||||||
public static final CommandAffineTransformMultiline ME = new CommandAffineTransformMultiline();
|
|
||||||
|
|
||||||
private CommandAffineTransformMultiline() {
|
|
||||||
super("^!transformation[%s]+\\{[%s]*$");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPatternEnd() {
|
|
||||||
return "^[%s]*!\\}[%s]*$";
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandExecutionResult execute(final TitledDiagram diagram, BlocLines lines) {
|
|
||||||
// lines = lines.subExtract(1, 1);
|
|
||||||
// diagram.setAnimation(lines);
|
|
||||||
return CommandExecutionResult.error("Not yet implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -73,8 +73,6 @@ public final class CommonCommands {
|
|||||||
cmds.add(CommandScaleMaxWidth.ME);
|
cmds.add(CommandScaleMaxWidth.ME);
|
||||||
cmds.add(CommandScaleMaxHeight.ME);
|
cmds.add(CommandScaleMaxHeight.ME);
|
||||||
cmds.add(CommandScaleMaxWidthAndHeight.ME);
|
cmds.add(CommandScaleMaxWidthAndHeight.ME);
|
||||||
cmds.add(CommandAffineTransform.ME);
|
|
||||||
cmds.add(CommandAffineTransformMultiline.ME);
|
|
||||||
final CommandFactorySprite factorySpriteCommand = new CommandFactorySprite();
|
final CommandFactorySprite factorySpriteCommand = new CommandFactorySprite();
|
||||||
cmds.add(factorySpriteCommand.createMultiLine(false));
|
cmds.add(factorySpriteCommand.createMultiLine(false));
|
||||||
cmds.add(factorySpriteCommand.createSingleLine());
|
cmds.add(factorySpriteCommand.createSingleLine());
|
||||||
|
@ -1,829 +0,0 @@
|
|||||||
package net.sourceforge.plantuml.jasic;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Jasic uses the MIT License:
|
|
||||||
|
|
||||||
Copyright (c) 2010 Robert Nystrom
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* This defines a single class that contains an entire interpreter for a language very similar to the original BASIC.
|
|
||||||
* Everything is here (albeit in very simplified form): tokenizing, parsing, and interpretation. The file is organized
|
|
||||||
* in phases, with each appearing roughly in the order that they occur when a program is run. You should be able to read
|
|
||||||
* this top-down to walk through the entire process of loading and running a program.
|
|
||||||
*
|
|
||||||
* Jasic language syntax ---------------------
|
|
||||||
*
|
|
||||||
* Comments start with ' and proceed to the end of the line:
|
|
||||||
*
|
|
||||||
* print "hi there" ' this is a comment
|
|
||||||
*
|
|
||||||
* Numbers and strings are supported. Strings should be in "double quotes", and only positive integers can be parsed
|
|
||||||
* (though numbers are double internally).
|
|
||||||
*
|
|
||||||
* Variables are identified by name which must start with a letter and can contain letters or numbers. Case is
|
|
||||||
* significant for names and keywords.
|
|
||||||
*
|
|
||||||
* Each statement is on its own line. Optionally, a line may have a label before the statement. A label is a name that
|
|
||||||
* ends with a colon:
|
|
||||||
*
|
|
||||||
* foo:
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* The following statements are supported:
|
|
||||||
*
|
|
||||||
* <name> = <expression> Evaluates the expression and assigns the result to the given named variable. All variables are
|
|
||||||
* globally scoped.
|
|
||||||
*
|
|
||||||
* pi = (314159 / 10000)
|
|
||||||
*
|
|
||||||
* print <expression> Evaluates the expression and prints the result.
|
|
||||||
*
|
|
||||||
* print "hello, " + "world"
|
|
||||||
*
|
|
||||||
* input <name> Reads in a line of input from the user and stores it in the variable with the given name.
|
|
||||||
*
|
|
||||||
* input guess
|
|
||||||
*
|
|
||||||
* goto <label> Jumps to the statement after the label with the given name.
|
|
||||||
*
|
|
||||||
* goto loop
|
|
||||||
*
|
|
||||||
* if <expression> then <label> Evaluates the expression. If it evaluates to a non-zero number, then jumps to the
|
|
||||||
* statement after the given label.
|
|
||||||
*
|
|
||||||
* if a < b then dosomething
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* The following expressions are supported:
|
|
||||||
*
|
|
||||||
* <expression> = <expression> Evaluates to 1 if the two expressions are equal, 0 otherwise.
|
|
||||||
*
|
|
||||||
* <expression> + <expression> If the left-hand expression is a number, then adds the two expressions, otherwise
|
|
||||||
* concatenates the two strings.
|
|
||||||
*
|
|
||||||
* <expression> - <expression> <expression> * <expression> <expression> / <expression> <expression> < <expression>
|
|
||||||
* <expression> > <expression> You can figure it out.
|
|
||||||
*
|
|
||||||
* <name> A name in an expression simply returns the value of the variable with that name. If the variable was never
|
|
||||||
* set, it defaults to 0.
|
|
||||||
*
|
|
||||||
* All binary operators have the same precedence. Sorry, I had to cut corners somewhere.
|
|
||||||
*
|
|
||||||
* To keep things simple, I've omitted some stuff or hacked things a bit. When possible, I'll leave a "HACK" note there
|
|
||||||
* explaining what and why. If you make your own interpreter, you'll want to address those.
|
|
||||||
*
|
|
||||||
* @author Bob Nystrom
|
|
||||||
*/
|
|
||||||
public class Jasic {
|
|
||||||
// ::remove folder when __HAXE__
|
|
||||||
// ::remove folder when __CORE__
|
|
||||||
// ::remove folder when __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__
|
|
||||||
|
|
||||||
// Tokenizing (lexing) -----------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function takes a script as a string of characters and chunks it into a
|
|
||||||
* sequence of tokens. Each token is a meaningful unit of program, like a
|
|
||||||
* variable name, a number, a string, or an operator.
|
|
||||||
*/
|
|
||||||
private static List<Token> tokenize(String source) {
|
|
||||||
List<Token> tokens = new ArrayList<>();
|
|
||||||
|
|
||||||
String token = "";
|
|
||||||
TokenizeState state = TokenizeState.DEFAULT;
|
|
||||||
|
|
||||||
// Many tokens are a single character, like operators and ().
|
|
||||||
String charTokens = "\n=+-*/<>()";
|
|
||||||
TokenType[] tokenTypes = { TokenType.LINE, TokenType.EQUALS, TokenType.OPERATOR, TokenType.OPERATOR,
|
|
||||||
TokenType.OPERATOR, TokenType.OPERATOR, TokenType.OPERATOR, TokenType.OPERATOR, TokenType.LEFT_PAREN,
|
|
||||||
TokenType.RIGHT_PAREN };
|
|
||||||
|
|
||||||
// Scan through the code one character at a time, building up the list
|
|
||||||
// of tokens.
|
|
||||||
for (int i = 0; i < source.length(); i++) {
|
|
||||||
char c = source.charAt(i);
|
|
||||||
switch (state) {
|
|
||||||
case DEFAULT:
|
|
||||||
if (charTokens.indexOf(c) != -1) {
|
|
||||||
tokens.add(new Token(Character.toString(c), tokenTypes[charTokens.indexOf(c)]));
|
|
||||||
} else if (Character.isLetter(c)) {
|
|
||||||
token += c;
|
|
||||||
state = TokenizeState.WORD;
|
|
||||||
} else if (Character.isDigit(c)) {
|
|
||||||
token += c;
|
|
||||||
state = TokenizeState.NUMBER;
|
|
||||||
} else if (c == '"') {
|
|
||||||
state = TokenizeState.STRING;
|
|
||||||
} else if (c == '\'') {
|
|
||||||
state = TokenizeState.COMMENT;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WORD:
|
|
||||||
if (Character.isLetterOrDigit(c)) {
|
|
||||||
token += c;
|
|
||||||
} else if (c == ':') {
|
|
||||||
tokens.add(new Token(token, TokenType.LABEL));
|
|
||||||
token = "";
|
|
||||||
state = TokenizeState.DEFAULT;
|
|
||||||
} else {
|
|
||||||
tokens.add(new Token(token, TokenType.WORD));
|
|
||||||
token = "";
|
|
||||||
state = TokenizeState.DEFAULT;
|
|
||||||
i--; // Reprocess this character in the default state.
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NUMBER:
|
|
||||||
// HACK: Negative numbers and floating points aren't supported.
|
|
||||||
// To get a negative number, just do 0 - <your number>.
|
|
||||||
// To get a floating point, divide.
|
|
||||||
if (Character.isDigit(c)) {
|
|
||||||
token += c;
|
|
||||||
} else {
|
|
||||||
tokens.add(new Token(token, TokenType.NUMBER));
|
|
||||||
token = "";
|
|
||||||
state = TokenizeState.DEFAULT;
|
|
||||||
i--; // Reprocess this character in the default state.
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STRING:
|
|
||||||
if (c == '"') {
|
|
||||||
tokens.add(new Token(token, TokenType.STRING));
|
|
||||||
token = "";
|
|
||||||
state = TokenizeState.DEFAULT;
|
|
||||||
} else {
|
|
||||||
token += c;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case COMMENT:
|
|
||||||
if (c == '\n') {
|
|
||||||
state = TokenizeState.DEFAULT;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HACK: Silently ignore any in-progress token when we run out of
|
|
||||||
// characters. This means that, for example, if a script has a string
|
|
||||||
// that's missing the closing ", it will just ditch it.
|
|
||||||
return tokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Token data --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This defines the different kinds of tokens or meaningful chunks of code that
|
|
||||||
* the parser knows how to consume. These let us distinguish, for example,
|
|
||||||
* between a string "foo" and a variable named "foo".
|
|
||||||
*
|
|
||||||
* HACK: A typical tokenizer would actually have unique token types for each
|
|
||||||
* keyword (print, goto, etc.) so that the parser doesn't have to look at the
|
|
||||||
* names, but Jasic is a little more crude.
|
|
||||||
*/
|
|
||||||
private enum TokenType {
|
|
||||||
WORD, NUMBER, STRING, LABEL, LINE, EQUALS, OPERATOR, LEFT_PAREN, RIGHT_PAREN, EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a single meaningful chunk of code. It is created by the tokenizer and
|
|
||||||
* consumed by the parser.
|
|
||||||
*/
|
|
||||||
private static class Token {
|
|
||||||
public Token(String text, TokenType type) {
|
|
||||||
this.text = text;
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String text;
|
|
||||||
public final TokenType type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This defines the different states the tokenizer can be in while it's scanning
|
|
||||||
* through the source code. Tokenizers are state machines, which means the only
|
|
||||||
* data they need to store is where they are in the source code and this one
|
|
||||||
* "state" or mode value.
|
|
||||||
*
|
|
||||||
* One of the main differences between tokenizing and parsing is this
|
|
||||||
* regularity. Because the tokenizer stores only this one state value, it can't
|
|
||||||
* handle nesting (which would require also storing a number to identify how
|
|
||||||
* deeply nested you are). The parser is able to handle that.
|
|
||||||
*/
|
|
||||||
private enum TokenizeState {
|
|
||||||
DEFAULT, WORD, NUMBER, STRING, COMMENT
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parsing -----------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This defines the Jasic parser. The parser takes in a sequence of tokens and
|
|
||||||
* generates an abstract syntax tree. This is the nested data structure that
|
|
||||||
* represents the series of statements, and the expressions (which can nest
|
|
||||||
* arbitrarily deeply) that they evaluate. In technical terms, what we have is a
|
|
||||||
* recursive descent parser, the simplest kind to hand-write.
|
|
||||||
*
|
|
||||||
* As a side-effect, this phase also stores off the line numbers for each label
|
|
||||||
* in the program. It's a bit gross, but it works.
|
|
||||||
*/
|
|
||||||
private class Parser {
|
|
||||||
public Parser(List<Token> tokens) {
|
|
||||||
this.tokens = tokens;
|
|
||||||
position = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The top-level function to start parsing. This will keep consuming tokens and
|
|
||||||
* routing to the other parse functions for the different grammar syntax until
|
|
||||||
* we run out of code to parse.
|
|
||||||
*
|
|
||||||
* @param labels A map of label names to statement indexes. The parser will fill
|
|
||||||
* this in as it scans the code.
|
|
||||||
* @return The list of parsed statements.
|
|
||||||
*/
|
|
||||||
public List<Statement> parse(Map<String, Integer> labels) {
|
|
||||||
List<Statement> statements = new ArrayList<>();
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// Ignore empty lines.
|
|
||||||
while (match(TokenType.LINE))
|
|
||||||
;
|
|
||||||
|
|
||||||
if (match(TokenType.LABEL)) {
|
|
||||||
// Mark the index of the statement after the label.
|
|
||||||
labels.put(last(1).text, statements.size());
|
|
||||||
} else if (match(TokenType.WORD, TokenType.EQUALS)) {
|
|
||||||
String name = last(2).text;
|
|
||||||
Expression value = expression();
|
|
||||||
statements.add(new AssignStatement(name, value));
|
|
||||||
} else if (match("print")) {
|
|
||||||
statements.add(new PrintStatement(expression()));
|
|
||||||
} else if (match("input")) {
|
|
||||||
statements.add(new InputStatement(consume(TokenType.WORD).text));
|
|
||||||
} else if (match("goto")) {
|
|
||||||
statements.add(new GotoStatement(consume(TokenType.WORD).text));
|
|
||||||
} else if (match("if")) {
|
|
||||||
Expression condition = expression();
|
|
||||||
consume("then");
|
|
||||||
String label = consume(TokenType.WORD).text;
|
|
||||||
statements.add(new IfThenStatement(condition, label));
|
|
||||||
} else
|
|
||||||
break; // Unexpected token (likely EOF), so end.
|
|
||||||
}
|
|
||||||
|
|
||||||
return statements;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The following functions each represent one grammatical part of the
|
|
||||||
// language. If this parsed English, these functions would be named like
|
|
||||||
// noun() and verb().
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a single expression. Recursive descent parsers start with the
|
|
||||||
* lowest-precedent term and moves towards higher precedence. For Jasic, binary
|
|
||||||
* operators (+, -, etc.) are the lowest.
|
|
||||||
*
|
|
||||||
* @return The parsed expression.
|
|
||||||
*/
|
|
||||||
private Expression expression() {
|
|
||||||
return operator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a series of binary operator expressions into a single expression. In
|
|
||||||
* Jasic, all operators have the same predecence and associate left-to-right.
|
|
||||||
* That means it will interpret: 1 + 2 * 3 - 4 / 5 like: ((((1 + 2) * 3) - 4) /
|
|
||||||
* 5)
|
|
||||||
*
|
|
||||||
* It works by building the expression tree one at a time. So, given this code:
|
|
||||||
* 1 + 2 * 3, this will:
|
|
||||||
*
|
|
||||||
* 1. Parse (1) as an atomic expression. 2. See the (+) and start a new operator
|
|
||||||
* expression. 3. Parse (2) as an atomic expression. 4. Build a (1 + 2)
|
|
||||||
* expression and replace (1) with it. 5. See the (*) and start a new operator
|
|
||||||
* expression. 6. Parse (3) as an atomic expression. 7. Build a ((1 + 2) * 3)
|
|
||||||
* expression and replace (1 + 2) with it. 8. Return the last expression built.
|
|
||||||
*
|
|
||||||
* @return The parsed expression.
|
|
||||||
*/
|
|
||||||
private Expression operator() {
|
|
||||||
Expression expression = atomic();
|
|
||||||
|
|
||||||
// Keep building operator expressions as long as we have operators.
|
|
||||||
while (match(TokenType.OPERATOR) || match(TokenType.EQUALS)) {
|
|
||||||
char operator = last(1).text.charAt(0);
|
|
||||||
Expression right = atomic();
|
|
||||||
expression = new OperatorExpression(expression, operator, right);
|
|
||||||
}
|
|
||||||
|
|
||||||
return expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses an "atomic" expression. This is the highest level of precedence and
|
|
||||||
* contains single literal tokens like 123 and "foo", as well as parenthesized
|
|
||||||
* expressions.
|
|
||||||
*
|
|
||||||
* @return The parsed expression.
|
|
||||||
*/
|
|
||||||
private Expression atomic() {
|
|
||||||
if (match(TokenType.WORD)) {
|
|
||||||
// A word is a reference to a variable.
|
|
||||||
return new VariableExpression(last(1).text);
|
|
||||||
} else if (match(TokenType.NUMBER)) {
|
|
||||||
return new NumberValue(Double.parseDouble(last(1).text));
|
|
||||||
} else if (match(TokenType.STRING)) {
|
|
||||||
return new StringValue(last(1).text);
|
|
||||||
} else if (match(TokenType.LEFT_PAREN)) {
|
|
||||||
// The contents of a parenthesized expression can be any
|
|
||||||
// expression. This lets us "restart" the precedence cascade
|
|
||||||
// so that you can have a lower precedence expression inside
|
|
||||||
// the parentheses.
|
|
||||||
Expression expression = expression();
|
|
||||||
consume(TokenType.RIGHT_PAREN);
|
|
||||||
return expression;
|
|
||||||
}
|
|
||||||
throw new Error("Couldn't parse :(");
|
|
||||||
}
|
|
||||||
|
|
||||||
// The following functions are the core low-level operations that the
|
|
||||||
// grammar parser is built in terms of. They match and consume tokens in
|
|
||||||
// the token stream.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumes the next two tokens if they are the given type (in order). Consumes
|
|
||||||
* no tokens if either check fais.
|
|
||||||
*
|
|
||||||
* @param type1 Expected type of the next token.
|
|
||||||
* @param type2 Expected type of the subsequent token.
|
|
||||||
* @return True if tokens were consumed.
|
|
||||||
*/
|
|
||||||
private boolean match(TokenType type1, TokenType type2) {
|
|
||||||
if (get(0).type != type1)
|
|
||||||
return false;
|
|
||||||
if (get(1).type != type2)
|
|
||||||
return false;
|
|
||||||
position += 2;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumes the next token if it's the given type.
|
|
||||||
*
|
|
||||||
* @param type Expected type of the next token.
|
|
||||||
* @return True if the token was consumed.
|
|
||||||
*/
|
|
||||||
private boolean match(TokenType type) {
|
|
||||||
if (get(0).type != type)
|
|
||||||
return false;
|
|
||||||
position++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumes the next token if it's a word token with the given name.
|
|
||||||
*
|
|
||||||
* @param name Expected name of the next word token.
|
|
||||||
* @return True if the token was consumed.
|
|
||||||
*/
|
|
||||||
private boolean match(String name) {
|
|
||||||
if (get(0).type != TokenType.WORD)
|
|
||||||
return false;
|
|
||||||
if (!get(0).text.equals(name))
|
|
||||||
return false;
|
|
||||||
position++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumes the next token if it's the given type. If not, throws an exception.
|
|
||||||
* This is for cases where the parser demands a token of a certain type in a
|
|
||||||
* certain position, for example a matching ) after an opening (.
|
|
||||||
*
|
|
||||||
* @param type Expected type of the next token.
|
|
||||||
* @return The consumed token.
|
|
||||||
*/
|
|
||||||
private Token consume(TokenType type) {
|
|
||||||
if (get(0).type != type)
|
|
||||||
throw new Error("Expected " + type + ".");
|
|
||||||
return tokens.get(position++);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumes the next token if it's a word with the given name. If not, throws an
|
|
||||||
* exception.
|
|
||||||
*
|
|
||||||
* @param name Expected name of the next word token.
|
|
||||||
* @return The consumed token.
|
|
||||||
*/
|
|
||||||
private Token consume(String name) {
|
|
||||||
if (!match(name))
|
|
||||||
throw new Error("Expected " + name + ".");
|
|
||||||
return last(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a previously consumed token, indexing backwards. last(1) will be the
|
|
||||||
* token just consumed, last(2) the one before that, etc.
|
|
||||||
*
|
|
||||||
* @param offset How far back in the token stream to look.
|
|
||||||
* @return The consumed token.
|
|
||||||
*/
|
|
||||||
private Token last(int offset) {
|
|
||||||
return tokens.get(position - offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an unconsumed token, indexing forward. get(0) will be the next token to
|
|
||||||
* be consumed, get(1) the one after that, etc.
|
|
||||||
*
|
|
||||||
* @param offset How far forward in the token stream to look.
|
|
||||||
* @return The yet-to-be-consumed token.
|
|
||||||
*/
|
|
||||||
private Token get(int offset) {
|
|
||||||
if (position + offset >= tokens.size()) {
|
|
||||||
return new Token("", TokenType.EOF);
|
|
||||||
}
|
|
||||||
return tokens.get(position + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final List<Token> tokens;
|
|
||||||
private int position;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Abstract syntax tree (AST) ----------------------------------------------
|
|
||||||
|
|
||||||
// These classes define the syntax tree data structures. This is how code is
|
|
||||||
// represented internally in a way that's easy for the interpreter to
|
|
||||||
// understand.
|
|
||||||
//
|
|
||||||
// HACK: Unlike most real compilers or interpreters, the logic to execute
|
|
||||||
// the code is baked directly into these classes. Typically, it would be
|
|
||||||
// separated out so that the AST us just a static data structure.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base interface for a Jasic statement. The different supported statement types
|
|
||||||
* like "print" and "goto" implement this.
|
|
||||||
*/
|
|
||||||
public interface Statement {
|
|
||||||
/**
|
|
||||||
* Statements implement this to actually perform whatever behavior the statement
|
|
||||||
* causes. "print" statements will display text here, "goto" statements will
|
|
||||||
* change the current statement, etc.
|
|
||||||
*/
|
|
||||||
void execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base interface for an expression. An expression is like a statement except
|
|
||||||
* that it also returns a value when executed. Expressions do not appear at the
|
|
||||||
* top level in Jasic programs, but are used in many statements. For example,
|
|
||||||
* the value printed by a "print" statement is an expression. Unlike statements,
|
|
||||||
* expressions can nest.
|
|
||||||
*/
|
|
||||||
public interface Expression {
|
|
||||||
/**
|
|
||||||
* Expression classes implement this to evaluate the expression and return the
|
|
||||||
* value.
|
|
||||||
*
|
|
||||||
* @return The value of the calculated expression.
|
|
||||||
*/
|
|
||||||
Value evaluate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A "print" statement evaluates an expression, converts the result to a string,
|
|
||||||
* and displays it to the user.
|
|
||||||
*/
|
|
||||||
public class PrintStatement implements Statement {
|
|
||||||
public PrintStatement(Expression expression) {
|
|
||||||
this.expression = expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void execute() {
|
|
||||||
System.out.println(expression.evaluate().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Expression expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An "input" statement reads input from the user and stores it in a variable.
|
|
||||||
*/
|
|
||||||
public class InputStatement implements Statement {
|
|
||||||
public InputStatement(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void execute() {
|
|
||||||
try {
|
|
||||||
String input = lineIn.readLine();
|
|
||||||
|
|
||||||
// Store it as a number if possible, otherwise use a string.
|
|
||||||
try {
|
|
||||||
double value = Double.parseDouble(input);
|
|
||||||
variables.put(name, new NumberValue(value));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
variables.put(name, new StringValue(input));
|
|
||||||
}
|
|
||||||
} catch (IOException e1) {
|
|
||||||
// HACK: Just ignore the problem.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An assignment statement evaluates an expression and stores the result in a
|
|
||||||
* variable.
|
|
||||||
*/
|
|
||||||
public class AssignStatement implements Statement {
|
|
||||||
public AssignStatement(String name, Expression value) {
|
|
||||||
this.name = name;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void execute() {
|
|
||||||
variables.put(name, value.evaluate());
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
private final Expression value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A "goto" statement jumps execution to another place in the program.
|
|
||||||
*/
|
|
||||||
public class GotoStatement implements Statement {
|
|
||||||
public GotoStatement(String label) {
|
|
||||||
this.label = label;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void execute() {
|
|
||||||
if (labels.containsKey(label)) {
|
|
||||||
currentStatement = labels.get(label).intValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String label;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An if then statement jumps execution to another place in the program, but
|
|
||||||
* only if an expression evaluates to something other than 0.
|
|
||||||
*/
|
|
||||||
public class IfThenStatement implements Statement {
|
|
||||||
public IfThenStatement(Expression condition, String label) {
|
|
||||||
this.condition = condition;
|
|
||||||
this.label = label;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void execute() {
|
|
||||||
if (labels.containsKey(label)) {
|
|
||||||
double value = condition.evaluate().toNumber();
|
|
||||||
if (value != 0) {
|
|
||||||
currentStatement = labels.get(label).intValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Expression condition;
|
|
||||||
private final String label;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A variable expression evaluates to the current value stored in that variable.
|
|
||||||
*/
|
|
||||||
public class VariableExpression implements Expression {
|
|
||||||
public VariableExpression(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Value evaluate() {
|
|
||||||
if (variables.containsKey(name)) {
|
|
||||||
return variables.get(name);
|
|
||||||
}
|
|
||||||
return new NumberValue(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An operator expression evaluates two expressions and then performs some
|
|
||||||
* arithmetic operation on the results.
|
|
||||||
*/
|
|
||||||
public class OperatorExpression implements Expression {
|
|
||||||
public OperatorExpression(Expression left, char operator, Expression right) {
|
|
||||||
this.left = left;
|
|
||||||
this.operator = operator;
|
|
||||||
this.right = right;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Value evaluate() {
|
|
||||||
Value leftVal = left.evaluate();
|
|
||||||
Value rightVal = right.evaluate();
|
|
||||||
|
|
||||||
switch (operator) {
|
|
||||||
case '=':
|
|
||||||
// Coerce to the left argument's type, then compare.
|
|
||||||
if (leftVal instanceof NumberValue) {
|
|
||||||
return new NumberValue((leftVal.toNumber() == rightVal.toNumber()) ? 1 : 0);
|
|
||||||
} else {
|
|
||||||
return new NumberValue(leftVal.toString().equals(rightVal.toString()) ? 1 : 0);
|
|
||||||
}
|
|
||||||
case '+':
|
|
||||||
// Addition if the left argument is a number, otherwise do
|
|
||||||
// string concatenation.
|
|
||||||
if (leftVal instanceof NumberValue) {
|
|
||||||
return new NumberValue(leftVal.toNumber() + rightVal.toNumber());
|
|
||||||
} else {
|
|
||||||
return new StringValue(leftVal.toString() + rightVal.toString());
|
|
||||||
}
|
|
||||||
case '-':
|
|
||||||
return new NumberValue(leftVal.toNumber() - rightVal.toNumber());
|
|
||||||
case '*':
|
|
||||||
return new NumberValue(leftVal.toNumber() * rightVal.toNumber());
|
|
||||||
case '/':
|
|
||||||
return new NumberValue(leftVal.toNumber() / rightVal.toNumber());
|
|
||||||
case '<':
|
|
||||||
// Coerce to the left argument's type, then compare.
|
|
||||||
if (leftVal instanceof NumberValue) {
|
|
||||||
return new NumberValue((leftVal.toNumber() < rightVal.toNumber()) ? 1 : 0);
|
|
||||||
} else {
|
|
||||||
return new NumberValue((leftVal.toString().compareTo(rightVal.toString()) < 0) ? 1 : 0);
|
|
||||||
}
|
|
||||||
case '>':
|
|
||||||
// Coerce to the left argument's type, then compare.
|
|
||||||
if (leftVal instanceof NumberValue) {
|
|
||||||
return new NumberValue((leftVal.toNumber() > rightVal.toNumber()) ? 1 : 0);
|
|
||||||
} else {
|
|
||||||
return new NumberValue((leftVal.toString().compareTo(rightVal.toString()) > 0) ? 1 : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new Error("Unknown operator.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Expression left;
|
|
||||||
private final char operator;
|
|
||||||
private final Expression right;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value types -------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the base interface for a value. Values are the data that the
|
|
||||||
* interpreter processes. They are what gets stored in variables, printed, and
|
|
||||||
* operated on.
|
|
||||||
*
|
|
||||||
* There is an implementation of this interface for each of the different
|
|
||||||
* primitive types (really just double and string) that Jasic supports. Wrapping
|
|
||||||
* them in a single Value interface lets Jasic be dynamically-typed and convert
|
|
||||||
* between different representations as needed.
|
|
||||||
*
|
|
||||||
* Note that Value extends Expression. This is a bit of a hack, but it lets us
|
|
||||||
* use values (which are typically only ever seen by the interpreter and not the
|
|
||||||
* parser) as both runtime values, and as object representing literals in code.
|
|
||||||
*/
|
|
||||||
public interface Value extends Expression {
|
|
||||||
/**
|
|
||||||
* Value types override this to convert themselves to a string representation.
|
|
||||||
*/
|
|
||||||
String toString();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Value types override this to convert themselves to a numeric representation.
|
|
||||||
*/
|
|
||||||
double toNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A numeric value. Jasic uses doubles internally for all numbers.
|
|
||||||
*/
|
|
||||||
public class NumberValue implements Value {
|
|
||||||
public NumberValue(double value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return Double.toString(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public double toNumber() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Value evaluate() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final double value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A string value.
|
|
||||||
*/
|
|
||||||
public class StringValue implements Value {
|
|
||||||
public StringValue(String value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double toNumber() {
|
|
||||||
return Double.parseDouble(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Value evaluate() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interpreter -------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new Jasic instance. The instance stores the global state of the
|
|
||||||
* interpreter such as the values of all of the variables and the current
|
|
||||||
* statement.
|
|
||||||
*/
|
|
||||||
public Jasic() {
|
|
||||||
variables = new HashMap<String, Value>();
|
|
||||||
labels = new HashMap<String, Integer>();
|
|
||||||
|
|
||||||
InputStreamReader converter = new InputStreamReader(System.in);
|
|
||||||
lineIn = new BufferedReader(converter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is where the magic happens. This runs the code through the parsing
|
|
||||||
* pipeline to generate the AST. Then it executes each statement. It keeps track
|
|
||||||
* of the current line in a member variable that the statement objects have
|
|
||||||
* access to. This lets "goto" and "if then" do flow control by simply setting
|
|
||||||
* the index of the current statement.
|
|
||||||
*
|
|
||||||
* In an interpreter that didn't mix the interpretation logic in with the AST
|
|
||||||
* node classes, this would be doing a lot more work.
|
|
||||||
*
|
|
||||||
* @param source A string containing the source code of a .jas script to
|
|
||||||
* interpret.
|
|
||||||
*/
|
|
||||||
public void interpret(String source) {
|
|
||||||
// Tokenize.
|
|
||||||
List<Token> tokens = tokenize(source);
|
|
||||||
|
|
||||||
// Parse.
|
|
||||||
Parser parser = new Parser(tokens);
|
|
||||||
List<Statement> statements = parser.parse(labels);
|
|
||||||
|
|
||||||
// Interpret until we're done.
|
|
||||||
currentStatement = 0;
|
|
||||||
while (currentStatement < statements.size()) {
|
|
||||||
int thisStatement = currentStatement;
|
|
||||||
currentStatement++;
|
|
||||||
statements.get(thisStatement).execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Map<String, Value> variables;
|
|
||||||
private final Map<String, Integer> labels;
|
|
||||||
|
|
||||||
private final BufferedReader lineIn;
|
|
||||||
|
|
||||||
private int currentStatement;
|
|
||||||
|
|
||||||
}
|
|
@ -37,7 +37,6 @@ package net.sourceforge.plantuml.klimt.drawing.g2d;
|
|||||||
|
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Shape;
|
import java.awt.Shape;
|
||||||
import java.awt.geom.AffineTransform;
|
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -50,7 +49,6 @@ import java.util.Objects;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import net.sourceforge.plantuml.FileFormat;
|
import net.sourceforge.plantuml.FileFormat;
|
||||||
import net.sourceforge.plantuml.anim.AffineTransformation;
|
|
||||||
import net.sourceforge.plantuml.klimt.UAntiAliasing;
|
import net.sourceforge.plantuml.klimt.UAntiAliasing;
|
||||||
import net.sourceforge.plantuml.klimt.UChange;
|
import net.sourceforge.plantuml.klimt.UChange;
|
||||||
import net.sourceforge.plantuml.klimt.UClip;
|
import net.sourceforge.plantuml.klimt.UClip;
|
||||||
@ -88,10 +86,6 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
|
|||||||
private List<Url> urls = new ArrayList<>();
|
private List<Url> urls = new ArrayList<>();
|
||||||
private Set<Url> allUrls = new HashSet<>();
|
private Set<Url> allUrls = new HashSet<>();
|
||||||
|
|
||||||
// ::comment when __CORE__
|
|
||||||
private final boolean hasAffineTransform;
|
|
||||||
// ::done
|
|
||||||
|
|
||||||
public final Set<Url> getAllUrlsEncountered() {
|
public final Set<Url> getAllUrlsEncountered() {
|
||||||
return Collections.unmodifiableSet(allUrls);
|
return Collections.unmodifiableSet(allUrls);
|
||||||
}
|
}
|
||||||
@ -114,9 +108,6 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
|
|||||||
private UGraphicG2d(UGraphicG2d other) {
|
private UGraphicG2d(UGraphicG2d other) {
|
||||||
super(other.getStringBounder());
|
super(other.getStringBounder());
|
||||||
copy(other);
|
copy(other);
|
||||||
// ::comment when __CORE__
|
|
||||||
this.hasAffineTransform = other.hasAffineTransform;
|
|
||||||
// ::done
|
|
||||||
this.dpiFactor = other.dpiFactor;
|
this.dpiFactor = other.dpiFactor;
|
||||||
this.bufferedImage = other.bufferedImage;
|
this.bufferedImage = other.bufferedImage;
|
||||||
this.urls = other.urls;
|
this.urls = other.urls;
|
||||||
@ -128,20 +119,11 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
|
|||||||
|
|
||||||
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
|
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
|
||||||
double dpiFactor, FileFormat format) {
|
double dpiFactor, FileFormat format) {
|
||||||
// ::revert when __CORE__
|
this(defaultBackground, colorMapper, stringBounder, g2d, dpiFactor, 0, 0, format);
|
||||||
this(defaultBackground, colorMapper, stringBounder, g2d, dpiFactor, 0, 0, format, null);
|
|
||||||
// this(defaultBackground, colorMapper, stringBounder, g2d, dpiFactor, 0, 0,
|
|
||||||
// format);
|
|
||||||
// ::done
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ::revert when __CORE__
|
|
||||||
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
|
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
|
||||||
double dpiFactor, double dx, double dy, FileFormat format, AffineTransformation affineTransform) {
|
double dpiFactor, double dx, double dy, FileFormat format) {
|
||||||
// public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper,
|
|
||||||
// StringBounder stringBounder, Graphics2D g2d,
|
|
||||||
// double dpiFactor, double dx, double dy, FileFormat format) {
|
|
||||||
// ::done
|
|
||||||
super(stringBounder);
|
super(stringBounder);
|
||||||
copy(defaultBackground, colorMapper, g2d);
|
copy(defaultBackground, colorMapper, g2d);
|
||||||
this.format = format;
|
this.format = format;
|
||||||
@ -149,21 +131,13 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
|
|||||||
if (dpiFactor != 1.0)
|
if (dpiFactor != 1.0)
|
||||||
g2d.scale(dpiFactor, dpiFactor);
|
g2d.scale(dpiFactor, dpiFactor);
|
||||||
|
|
||||||
// ::comment when __CORE__
|
|
||||||
this.hasAffineTransform = affineTransform != null;
|
|
||||||
if (this.hasAffineTransform) {
|
|
||||||
if (dx != 0 || dy != 0)
|
|
||||||
getGraphicObject().transform(AffineTransform.getTranslateInstance(dx, dy));
|
|
||||||
getGraphicObject().transform(affineTransform.getAffineTransform());
|
|
||||||
}
|
|
||||||
// ::done
|
|
||||||
register(dpiFactor);
|
register(dpiFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(double dpiFactor) {
|
private void register(double dpiFactor) {
|
||||||
registerDriver(URectangle.class, new DriverRectangleG2d(dpiFactor, this));
|
registerDriver(URectangle.class, new DriverRectangleG2d(dpiFactor, this));
|
||||||
// ::comment when __CORE__
|
// ::comment when __CORE__
|
||||||
if (this.hasAffineTransform || dpiFactor != 1.0)
|
if (dpiFactor != 1.0)
|
||||||
registerDriver(UText.class, new DriverTextAsPathG2d(this, getStringBounder()));
|
registerDriver(UText.class, new DriverTextAsPathG2d(this, getStringBounder()));
|
||||||
else
|
else
|
||||||
// ::done
|
// ::done
|
||||||
|
@ -1,493 +0,0 @@
|
|||||||
/*
|
|
||||||
* MJPEGGenerator.java
|
|
||||||
*
|
|
||||||
* Created on April 17, 2006, 11:48 PM
|
|
||||||
*
|
|
||||||
* To change this template, choose Tools | Options and locate the template under
|
|
||||||
* the Source Creation and Management node. Right-click the template and choose
|
|
||||||
* Open. You can then make changes to the template in the Source Editor.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.sourceforge.plantuml.mjpeg;
|
|
||||||
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.Image;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import net.sourceforge.plantuml.security.SFile;
|
|
||||||
import net.sourceforge.plantuml.security.SImageIO;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author monceaux
|
|
||||||
*/
|
|
||||||
public class MJPEGGenerator {
|
|
||||||
// ::remove folder when __HAXE__
|
|
||||||
// ::remove folder when __CORE__
|
|
||||||
/*
|
|
||||||
* Info needed for MJPEG AVI
|
|
||||||
*
|
|
||||||
* - size of file minus "RIFF & 4 byte file size"
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
int width = 0;
|
|
||||||
int height = 0;
|
|
||||||
double framerate = 0;
|
|
||||||
int numFrames = 0;
|
|
||||||
SFile aviFile = null;
|
|
||||||
FileOutputStream aviOutput = null;
|
|
||||||
FileChannel aviChannel = null;
|
|
||||||
|
|
||||||
long riffOffset = 0;
|
|
||||||
long aviMovieOffset = 0;
|
|
||||||
|
|
||||||
AVIIndexList indexlist = null;
|
|
||||||
|
|
||||||
/** Creates a new instance of MJPEGGenerator */
|
|
||||||
public MJPEGGenerator(SFile aviFile, int width, int height, double framerate, int numFrames) throws IOException {
|
|
||||||
this.aviFile = aviFile;
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
this.framerate = framerate;
|
|
||||||
this.numFrames = numFrames;
|
|
||||||
aviOutput = aviFile.createFileOutputStream();
|
|
||||||
aviChannel = aviOutput.getChannel();
|
|
||||||
|
|
||||||
RIFFHeader rh = new RIFFHeader();
|
|
||||||
aviOutput.write(rh.toBytes());
|
|
||||||
aviOutput.write(new AVIMainHeader().toBytes());
|
|
||||||
aviOutput.write(new AVIStreamList().toBytes());
|
|
||||||
aviOutput.write(new AVIStreamHeader().toBytes());
|
|
||||||
aviOutput.write(new AVIStreamFormat().toBytes());
|
|
||||||
aviOutput.write(new AVIJunk().toBytes());
|
|
||||||
aviMovieOffset = aviChannel.position();
|
|
||||||
aviOutput.write(new AVIMovieList().toBytes());
|
|
||||||
indexlist = new AVIIndexList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addImage(Image image) throws IOException {
|
|
||||||
byte[] fcc = new byte[] { '0', '0', 'd', 'b' };
|
|
||||||
byte[] imagedata = writeImageToBytes(image);
|
|
||||||
int useLength = imagedata.length;
|
|
||||||
long position = aviChannel.position();
|
|
||||||
int extra = (useLength + (int) position) % 4;
|
|
||||||
if (extra > 0)
|
|
||||||
useLength = useLength + extra;
|
|
||||||
|
|
||||||
indexlist.addAVIIndex((int) position, useLength);
|
|
||||||
|
|
||||||
aviOutput.write(fcc);
|
|
||||||
aviOutput.write(intBytes(swapInt(useLength)));
|
|
||||||
aviOutput.write(imagedata);
|
|
||||||
if (extra > 0) {
|
|
||||||
for (int i = 0; i < extra; i++)
|
|
||||||
aviOutput.write(0);
|
|
||||||
}
|
|
||||||
imagedata = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void finishAVI() throws IOException {
|
|
||||||
byte[] indexlistBytes = indexlist.toBytes();
|
|
||||||
aviOutput.write(indexlistBytes);
|
|
||||||
aviOutput.close();
|
|
||||||
long size = aviFile.length();
|
|
||||||
RandomAccessFile raf = new RandomAccessFile(aviFile.conv(), "rw");
|
|
||||||
raf.seek(4);
|
|
||||||
raf.write(intBytes(swapInt((int) size - 8)));
|
|
||||||
raf.seek(aviMovieOffset + 4);
|
|
||||||
raf.write(intBytes(swapInt((int) (size - 8 - aviMovieOffset - indexlistBytes.length))));
|
|
||||||
raf.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// public void writeAVI(File file) throws Exception
|
|
||||||
// {
|
|
||||||
// OutputStream os = SecurityUtils.FileOutputStream(file);
|
|
||||||
//
|
|
||||||
// // RIFFHeader
|
|
||||||
// // AVIMainHeader
|
|
||||||
// // AVIStreamList
|
|
||||||
// // AVIStreamHeader
|
|
||||||
// // AVIStreamFormat
|
|
||||||
// // write 00db and image bytes...
|
|
||||||
// }
|
|
||||||
|
|
||||||
public static int swapInt(int v) {
|
|
||||||
return (v >>> 24) | (v << 24) | ((v << 8) & 0x00FF0000) | ((v >> 8) & 0x0000FF00);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static short swapShort(short v) {
|
|
||||||
return (short) ((v >>> 8) | (v << 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] intBytes(int i) {
|
|
||||||
byte[] b = new byte[4];
|
|
||||||
b[0] = (byte) (i >>> 24);
|
|
||||||
b[1] = (byte) ((i >>> 16) & 0x000000FF);
|
|
||||||
b[2] = (byte) ((i >>> 8) & 0x000000FF);
|
|
||||||
b[3] = (byte) (i & 0x000000FF);
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] shortBytes(short i) {
|
|
||||||
byte[] b = new byte[2];
|
|
||||||
b[0] = (byte) (i >>> 8);
|
|
||||||
b[1] = (byte) (i & 0x000000FF);
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class RIFFHeader {
|
|
||||||
public byte[] fcc = new byte[] { 'R', 'I', 'F', 'F' };
|
|
||||||
public int fileSize = 0;
|
|
||||||
public byte[] fcc2 = new byte[] { 'A', 'V', 'I', ' ' };
|
|
||||||
public byte[] fcc3 = new byte[] { 'L', 'I', 'S', 'T' };
|
|
||||||
public int listSize = 200;
|
|
||||||
public byte[] fcc4 = new byte[] { 'h', 'd', 'r', 'l' };
|
|
||||||
|
|
||||||
public RIFFHeader() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toBytes() throws IOException {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
baos.write(fcc);
|
|
||||||
baos.write(intBytes(swapInt(fileSize)));
|
|
||||||
baos.write(fcc2);
|
|
||||||
baos.write(fcc3);
|
|
||||||
baos.write(intBytes(swapInt(listSize)));
|
|
||||||
baos.write(fcc4);
|
|
||||||
baos.close();
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AVIMainHeader {
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* FOURCC fcc; DWORD cb; DWORD dwMicroSecPerFrame; DWORD dwMaxBytesPerSec; DWORD
|
|
||||||
* dwPaddingGranularity; DWORD dwFlags; DWORD dwTotalFrames; DWORD
|
|
||||||
* dwInitialFrames; DWORD dwStreams; DWORD dwSuggestedBufferSize; DWORD dwWidth;
|
|
||||||
* DWORD dwHeight; DWORD dwReserved[4];
|
|
||||||
*/
|
|
||||||
|
|
||||||
public byte[] fcc = new byte[] { 'a', 'v', 'i', 'h' };
|
|
||||||
public int cb = 56;
|
|
||||||
public int dwMicroSecPerFrame = 0; // (1 / frames per sec) * 1,000,000
|
|
||||||
public int dwMaxBytesPerSec = 10000000;
|
|
||||||
public int dwPaddingGranularity = 0;
|
|
||||||
public int dwFlags = 65552;
|
|
||||||
public int dwTotalFrames = 0; // replace with correct value
|
|
||||||
public int dwInitialFrames = 0;
|
|
||||||
public int dwStreams = 1;
|
|
||||||
public int dwSuggestedBufferSize = 0;
|
|
||||||
public int dwWidth = 0; // replace with correct value
|
|
||||||
public int dwHeight = 0; // replace with correct value
|
|
||||||
public int[] dwReserved = new int[4];
|
|
||||||
|
|
||||||
public AVIMainHeader() {
|
|
||||||
dwMicroSecPerFrame = (int) ((1.0 / framerate) * 1000000.0);
|
|
||||||
dwWidth = width;
|
|
||||||
dwHeight = height;
|
|
||||||
dwTotalFrames = numFrames;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toBytes() throws IOException {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
baos.write(fcc);
|
|
||||||
baos.write(intBytes(swapInt(cb)));
|
|
||||||
baos.write(intBytes(swapInt(dwMicroSecPerFrame)));
|
|
||||||
baos.write(intBytes(swapInt(dwMaxBytesPerSec)));
|
|
||||||
baos.write(intBytes(swapInt(dwPaddingGranularity)));
|
|
||||||
baos.write(intBytes(swapInt(dwFlags)));
|
|
||||||
baos.write(intBytes(swapInt(dwTotalFrames)));
|
|
||||||
baos.write(intBytes(swapInt(dwInitialFrames)));
|
|
||||||
baos.write(intBytes(swapInt(dwStreams)));
|
|
||||||
baos.write(intBytes(swapInt(dwSuggestedBufferSize)));
|
|
||||||
baos.write(intBytes(swapInt(dwWidth)));
|
|
||||||
baos.write(intBytes(swapInt(dwHeight)));
|
|
||||||
baos.write(intBytes(swapInt(dwReserved[0])));
|
|
||||||
baos.write(intBytes(swapInt(dwReserved[1])));
|
|
||||||
baos.write(intBytes(swapInt(dwReserved[2])));
|
|
||||||
baos.write(intBytes(swapInt(dwReserved[3])));
|
|
||||||
baos.close();
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AVIStreamList {
|
|
||||||
public byte[] fcc = new byte[] { 'L', 'I', 'S', 'T' };
|
|
||||||
public int size = 124;
|
|
||||||
public byte[] fcc2 = new byte[] { 's', 't', 'r', 'l' };
|
|
||||||
|
|
||||||
public AVIStreamList() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toBytes() throws IOException {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
baos.write(fcc);
|
|
||||||
baos.write(intBytes(swapInt(size)));
|
|
||||||
baos.write(fcc2);
|
|
||||||
baos.close();
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AVIStreamHeader {
|
|
||||||
/*
|
|
||||||
* FOURCC fcc; DWORD cb; FOURCC fccType; FOURCC fccHandler; DWORD dwFlags; WORD
|
|
||||||
* wPriority; WORD wLanguage; DWORD dwInitialFrames; DWORD dwScale; DWORD
|
|
||||||
* dwRate; DWORD dwStart; DWORD dwLength; DWORD dwSuggestedBufferSize; DWORD
|
|
||||||
* dwQuality; DWORD dwSampleSize; struct { short int left; short int top; short
|
|
||||||
* int right; short int bottom; } rcFrame;
|
|
||||||
*/
|
|
||||||
|
|
||||||
public byte[] fcc = new byte[] { 's', 't', 'r', 'h' };
|
|
||||||
public int cb = 64;
|
|
||||||
public byte[] fccType = new byte[] { 'v', 'i', 'd', 's' };
|
|
||||||
public byte[] fccHandler = new byte[] { 'M', 'J', 'P', 'G' };
|
|
||||||
public int dwFlags = 0;
|
|
||||||
public short wPriority = 0;
|
|
||||||
public short wLanguage = 0;
|
|
||||||
public int dwInitialFrames = 0;
|
|
||||||
public int dwScale = 0; // microseconds per frame
|
|
||||||
public int dwRate = 1000000; // dwRate / dwScale = frame rate
|
|
||||||
public int dwStart = 0;
|
|
||||||
public int dwLength = 0; // num frames
|
|
||||||
public int dwSuggestedBufferSize = 0;
|
|
||||||
public int dwQuality = -1;
|
|
||||||
public int dwSampleSize = 0;
|
|
||||||
public int left = 0;
|
|
||||||
public int top = 0;
|
|
||||||
public int right = 0;
|
|
||||||
public int bottom = 0;
|
|
||||||
|
|
||||||
public AVIStreamHeader() {
|
|
||||||
dwScale = (int) ((1.0 / framerate) * 1000000.0);
|
|
||||||
dwLength = numFrames;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toBytes() throws IOException {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
baos.write(fcc);
|
|
||||||
baos.write(intBytes(swapInt(cb)));
|
|
||||||
baos.write(fccType);
|
|
||||||
baos.write(fccHandler);
|
|
||||||
baos.write(intBytes(swapInt(dwFlags)));
|
|
||||||
baos.write(shortBytes(swapShort(wPriority)));
|
|
||||||
baos.write(shortBytes(swapShort(wLanguage)));
|
|
||||||
baos.write(intBytes(swapInt(dwInitialFrames)));
|
|
||||||
baos.write(intBytes(swapInt(dwScale)));
|
|
||||||
baos.write(intBytes(swapInt(dwRate)));
|
|
||||||
baos.write(intBytes(swapInt(dwStart)));
|
|
||||||
baos.write(intBytes(swapInt(dwLength)));
|
|
||||||
baos.write(intBytes(swapInt(dwSuggestedBufferSize)));
|
|
||||||
baos.write(intBytes(swapInt(dwQuality)));
|
|
||||||
baos.write(intBytes(swapInt(dwSampleSize)));
|
|
||||||
baos.write(intBytes(swapInt(left)));
|
|
||||||
baos.write(intBytes(swapInt(top)));
|
|
||||||
baos.write(intBytes(swapInt(right)));
|
|
||||||
baos.write(intBytes(swapInt(bottom)));
|
|
||||||
baos.close();
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AVIStreamFormat {
|
|
||||||
/*
|
|
||||||
* FOURCC fcc; DWORD cb; DWORD biSize; LONG biWidth; LONG biHeight; WORD
|
|
||||||
* biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG
|
|
||||||
* biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant;
|
|
||||||
*/
|
|
||||||
|
|
||||||
public byte[] fcc = new byte[] { 's', 't', 'r', 'f' };
|
|
||||||
public int cb = 40;
|
|
||||||
public int biSize = 40; // same as cb
|
|
||||||
public int biWidth = 0;
|
|
||||||
public int biHeight = 0;
|
|
||||||
public short biPlanes = 1;
|
|
||||||
public short biBitCount = 24;
|
|
||||||
public byte[] biCompression = new byte[] { 'M', 'J', 'P', 'G' };
|
|
||||||
public int biSizeImage = 0; // width x height in pixels
|
|
||||||
public int biXPelsPerMeter = 0;
|
|
||||||
public int biYPelsPerMeter = 0;
|
|
||||||
public int biClrUsed = 0;
|
|
||||||
public int biClrImportant = 0;
|
|
||||||
|
|
||||||
public AVIStreamFormat() {
|
|
||||||
biWidth = width;
|
|
||||||
biHeight = height;
|
|
||||||
biSizeImage = width * height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toBytes() throws IOException {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
baos.write(fcc);
|
|
||||||
baos.write(intBytes(swapInt(cb)));
|
|
||||||
baos.write(intBytes(swapInt(biSize)));
|
|
||||||
baos.write(intBytes(swapInt(biWidth)));
|
|
||||||
baos.write(intBytes(swapInt(biHeight)));
|
|
||||||
baos.write(shortBytes(swapShort(biPlanes)));
|
|
||||||
baos.write(shortBytes(swapShort(biBitCount)));
|
|
||||||
baos.write(biCompression);
|
|
||||||
baos.write(intBytes(swapInt(biSizeImage)));
|
|
||||||
baos.write(intBytes(swapInt(biXPelsPerMeter)));
|
|
||||||
baos.write(intBytes(swapInt(biYPelsPerMeter)));
|
|
||||||
baos.write(intBytes(swapInt(biClrUsed)));
|
|
||||||
baos.write(intBytes(swapInt(biClrImportant)));
|
|
||||||
baos.close();
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AVIMovieList {
|
|
||||||
public byte[] fcc = new byte[] { 'L', 'I', 'S', 'T' };
|
|
||||||
public int listSize = 0;
|
|
||||||
public byte[] fcc2 = new byte[] { 'm', 'o', 'v', 'i' };
|
|
||||||
// 00db size jpg image data ...
|
|
||||||
|
|
||||||
public AVIMovieList() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toBytes() throws IOException {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
baos.write(fcc);
|
|
||||||
baos.write(intBytes(swapInt(listSize)));
|
|
||||||
baos.write(fcc2);
|
|
||||||
baos.close();
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AVIIndexList {
|
|
||||||
public byte[] fcc = new byte[] { 'i', 'd', 'x', '1' };
|
|
||||||
public int cb = 0;
|
|
||||||
public ArrayList ind = new ArrayList();
|
|
||||||
|
|
||||||
public AVIIndexList() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addAVIIndex(AVIIndex ai) {
|
|
||||||
ind.add(ai);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addAVIIndex(int dwOffset, int dwSize) {
|
|
||||||
ind.add(new AVIIndex(dwOffset, dwSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toBytes() throws IOException {
|
|
||||||
cb = 16 * ind.size();
|
|
||||||
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
baos.write(fcc);
|
|
||||||
baos.write(intBytes(swapInt(cb)));
|
|
||||||
for (int i = 0; i < ind.size(); i++) {
|
|
||||||
AVIIndex in = (AVIIndex) ind.get(i);
|
|
||||||
baos.write(in.toBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
baos.close();
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AVIIndex {
|
|
||||||
public byte[] fcc = new byte[] { '0', '0', 'd', 'b' };
|
|
||||||
public int dwFlags = 16;
|
|
||||||
public int dwOffset = 0;
|
|
||||||
public int dwSize = 0;
|
|
||||||
|
|
||||||
public AVIIndex(int dwOffset, int dwSize) {
|
|
||||||
this.dwOffset = dwOffset;
|
|
||||||
this.dwSize = dwSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toBytes() throws IOException {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
baos.write(fcc);
|
|
||||||
baos.write(intBytes(swapInt(dwFlags)));
|
|
||||||
baos.write(intBytes(swapInt(dwOffset)));
|
|
||||||
baos.write(intBytes(swapInt(dwSize)));
|
|
||||||
baos.close();
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AVIJunk {
|
|
||||||
public byte[] fcc = new byte[] { 'J', 'U', 'N', 'K' };
|
|
||||||
public int size = 1808;
|
|
||||||
public byte[] data = new byte[size];
|
|
||||||
|
|
||||||
public AVIJunk() {
|
|
||||||
Arrays.fill(data, (byte) 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toBytes() throws IOException {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
baos.write(fcc);
|
|
||||||
baos.write(intBytes(swapInt(size)));
|
|
||||||
baos.write(data);
|
|
||||||
baos.close();
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] writeImageToBytes(Image image) throws IOException {
|
|
||||||
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
Graphics2D g = bi.createGraphics();
|
|
||||||
g.drawImage(image, 0, 0, width, height, null);
|
|
||||||
SImageIO.write(bi, "jpg", baos);
|
|
||||||
baos.close();
|
|
||||||
bi = null;
|
|
||||||
g = null;
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
// public static void main(String[] args) throws Exception {
|
|
||||||
// double framerate = 12.0;
|
|
||||||
// double transitionDuration = 1; // seconds
|
|
||||||
// double slideDuration = 3; // seconds
|
|
||||||
//
|
|
||||||
// File photoDir = SecurityUtils.file(args[0]);
|
|
||||||
// File[] files = photoDir.listFiles(new FilenameFilter() {
|
|
||||||
// public boolean accept(java.io.File dir, String name) {
|
|
||||||
// if (StringUtils.goLowerCase(name).endsWith("jpg"))
|
|
||||||
// return true;
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// int numFrames = (int) (files.length * framerate * (slideDuration + transitionDuration)
|
|
||||||
// + (transitionDuration * framerate));
|
|
||||||
// MJPEGGenerator m = new MJPEGGenerator(SecurityUtils.file(args[1]), 640, 480, framerate, numFrames);
|
|
||||||
// for (int i = 0; i < files.length; i++) {
|
|
||||||
// System.out.println("processing file " + i);
|
|
||||||
// ImageIcon ii = new ImageIcon(files[i].getCanonicalPath());
|
|
||||||
// m.addImage(ii.getImage());
|
|
||||||
// }
|
|
||||||
// m.finishAVI();
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user