diff --git a/src/main/java/de/neemann/digital/draw/elements/VisualElement.java b/src/main/java/de/neemann/digital/draw/elements/VisualElement.java index eee32f6c2..f9cc5932a 100644 --- a/src/main/java/de/neemann/digital/draw/elements/VisualElement.java +++ b/src/main/java/de/neemann/digital/draw/elements/VisualElement.java @@ -204,14 +204,14 @@ public class VisualElement implements Drawable, Movable, AttributeListener { public GraphicMinMax getMinMax(boolean includeText) { if (includeText) { if (minMaxText == null) { - GraphicMinMax mm = new GraphicMinMax(true); + GraphicMinMax mm = new GraphicMinMax(true, null); drawShape(mm, null); minMaxText = mm; } return minMaxText; } else { if (minMax == null) { - GraphicMinMax mm = new GraphicMinMax(false); + GraphicMinMax mm = new GraphicMinMax(false, null); drawShape(mm, null); minMax = mm; } diff --git a/src/main/java/de/neemann/digital/draw/gif/GifExporter.java b/src/main/java/de/neemann/digital/draw/gif/GifExporter.java index c33bae11f..a877902dd 100644 --- a/src/main/java/de/neemann/digital/draw/gif/GifExporter.java +++ b/src/main/java/de/neemann/digital/draw/gif/GifExporter.java @@ -128,7 +128,8 @@ public class GifExporter extends JDialog implements ModelStateObserver, ModelMod } private BufferedImage createBufferedImage() throws IOException { - GraphicsImage gri = GraphicsImage.create(null, minMax.getMin(), minMax.getMax(), "gif", 1); + GraphicsImage gri = new GraphicsImage(null, "gif", 1); + gri.setBoundingBox(minMax.getMin(), minMax.getMax()); BufferedImage bi = gri.getBufferedImage(); Graphics gr = bi.getGraphics(); gr.setColor(Color.WHITE); diff --git a/src/main/java/de/neemann/digital/draw/graphics/Export.java b/src/main/java/de/neemann/digital/draw/graphics/Export.java index 93ee7ab09..334590ada 100644 --- a/src/main/java/de/neemann/digital/draw/graphics/Export.java +++ b/src/main/java/de/neemann/digital/draw/graphics/Export.java @@ -36,10 +36,13 @@ public class Export { * @throws IOException IOException */ public void export(OutputStream out) throws IOException { - GraphicMinMax minMax = new GraphicMinMax(); + Graphic gr = factory.create(out); + + GraphicMinMax minMax = new GraphicMinMax(gr); circuit.drawTo(minMax); - Graphic gr = factory.create(out, minMax.getMin(), minMax.getMax()); + gr.setBoundingBox(minMax.getMin(), minMax.getMax()); + try { GraphicLineCollector glc = new GraphicLineCollector(); diff --git a/src/main/java/de/neemann/digital/draw/graphics/ExportFactory.java b/src/main/java/de/neemann/digital/draw/graphics/ExportFactory.java index 83e5b6e60..060cbcca7 100644 --- a/src/main/java/de/neemann/digital/draw/graphics/ExportFactory.java +++ b/src/main/java/de/neemann/digital/draw/graphics/ExportFactory.java @@ -13,10 +13,8 @@ public interface ExportFactory { * Creates a {@link Graphic} instance * * @param out the stream to write the graphic to - * @param min upper right corner of the circuit - * @param max lower left corner of the circuit * @return the {@link Graphic} instance to use * @throws IOException IOException */ - Graphic create(OutputStream out, Vector min, Vector max) throws IOException; + Graphic create(OutputStream out) throws IOException; } diff --git a/src/main/java/de/neemann/digital/draw/graphics/Graphic.java b/src/main/java/de/neemann/digital/draw/graphics/Graphic.java index 085b27caf..dd9b7d59b 100644 --- a/src/main/java/de/neemann/digital/draw/graphics/Graphic.java +++ b/src/main/java/de/neemann/digital/draw/graphics/Graphic.java @@ -9,6 +9,19 @@ package de.neemann.digital.draw.graphics; */ public interface Graphic { + /** + * Sets the bounding box of the future usage of this instance + * Instances that create a file will use this bounding box th write a header. + * So this method needs to be called before a draw-Method is called. + * + * @param min upper left corner + * @param max lower right corner + * @return this for chained calls + */ + default Graphic setBoundingBox(Vector min, Vector max) { + return this; + } + /** * Draws a line * diff --git a/src/main/java/de/neemann/digital/draw/graphics/GraphicMinMax.java b/src/main/java/de/neemann/digital/draw/graphics/GraphicMinMax.java index 25d639e43..829dd8595 100644 --- a/src/main/java/de/neemann/digital/draw/graphics/GraphicMinMax.java +++ b/src/main/java/de/neemann/digital/draw/graphics/GraphicMinMax.java @@ -15,6 +15,7 @@ import static de.neemann.digital.core.element.ElementAttributes.cleanLabel; public class GraphicMinMax implements Graphic { private final boolean includeText; + private final Graphic parent; private Vector min; private Vector max; @@ -22,16 +23,27 @@ public class GraphicMinMax implements Graphic { * Creates a new instance */ public GraphicMinMax() { - this(true); + this(true, null); + } + + /** + * Creates a new instance + * + * @param parent oly used to provide the flags + */ + public GraphicMinMax(Graphic parent) { + this(true, parent); } /** * Creates a new instance * * @param includeText true if text is included in measurement + * @param parent oly used to provide the flags */ - public GraphicMinMax(boolean includeText) { + public GraphicMinMax(boolean includeText, Graphic parent) { this.includeText = includeText; + this.parent = parent; } @Override @@ -135,4 +147,12 @@ public class GraphicMinMax implements Graphic { public Vector getMax() { return max; } + + @Override + public boolean isFlagSet(String name) { + if (parent == null) + return false; + else + return parent.isFlagSet(name); + } } diff --git a/src/main/java/de/neemann/digital/draw/graphics/GraphicSVG.java b/src/main/java/de/neemann/digital/draw/graphics/GraphicSVG.java index eca7c7fe9..f827b8b5e 100644 --- a/src/main/java/de/neemann/digital/draw/graphics/GraphicSVG.java +++ b/src/main/java/de/neemann/digital/draw/graphics/GraphicSVG.java @@ -3,6 +3,8 @@ package de.neemann.digital.draw.graphics; import java.io.*; import java.util.Date; +import static java.lang.System.out; + /** * Used to create a SVG representation of the circuit. * Don't use this implementation directly. Use {@link GraphicSVGIndex} to create plain SVG or @@ -12,65 +14,74 @@ import java.util.Date; */ public class GraphicSVG implements Graphic, Closeable { private static final int DEF_SCALE = 15; - private final BufferedWriter w; + private final OutputStream out; + private final File source; + private final int svgScale; + private BufferedWriter w; /** * Creates a new instance. * * @param out the stream - * @param min upper left corner - * @param max lower right corner * @throws IOException IOException */ - public GraphicSVG(OutputStream out, Vector min, Vector max) throws IOException { - this(out, min, max, null, DEF_SCALE); + public GraphicSVG(OutputStream out) throws IOException { + this(out, null, DEF_SCALE); } /** * Creates a new instance. * * @param file the file - * @param min upper left corner - * @param max lower right corner * @param source source file, only used to create a comment in the SVG file * @param svgScale the scaling * @throws IOException IOException */ - public GraphicSVG(File file, Vector min, Vector max, File source, int svgScale) throws IOException { - this(new FileOutputStream(file), min, max, source, svgScale); + public GraphicSVG(File file, File source, int svgScale) throws IOException { + this(new FileOutputStream(file), source, svgScale); } /** * Creates a new instance. * * @param out the stream to write the file to - * @param min upper left corner - * @param max lower right corner * @param source source file, only used to create a comment in the SVG file * @param svgScale the scaling * @throws IOException IOException */ - public GraphicSVG(OutputStream out, Vector min, Vector max, File source, int svgScale) throws IOException { - w = new BufferedWriter(new OutputStreamWriter(out, "utf-8")); - w.write("\n" - + "\n"); - w.write("\n"); - if (source != null) { - w.write("\n"); + public GraphicSVG(OutputStream out, File source, int svgScale) throws IOException { + this.out = out; + this.source = source; + this.svgScale = svgScale; + } + + @Override + public Graphic setBoundingBox(Vector min, Vector max) { + try { + w = new BufferedWriter(new OutputStreamWriter(out, "utf-8")); + w.write("\n" + + "\n"); + w.write("\n"); + if (source != null) { + w.write("\n"); + } + w.write("\n" + + "\n"); + w.write("\n"); + return this; + } catch (IOException e) { + throw new RuntimeException(e); } - w.write("\n" - + "\n"); - w.write("\n"); } @Override diff --git a/src/main/java/de/neemann/digital/draw/graphics/GraphicSVGIndex.java b/src/main/java/de/neemann/digital/draw/graphics/GraphicSVGIndex.java index 2cf4984aa..6f62468ac 100644 --- a/src/main/java/de/neemann/digital/draw/graphics/GraphicSVGIndex.java +++ b/src/main/java/de/neemann/digital/draw/graphics/GraphicSVGIndex.java @@ -18,26 +18,22 @@ public class GraphicSVGIndex extends GraphicSVG { * Creates new instance * * @param out the file - * @param min upper left corner - * @param max lower right corner * @throws IOException IOException */ - public GraphicSVGIndex(OutputStream out, Vector min, Vector max) throws IOException { - super(out, min, max); + public GraphicSVGIndex(OutputStream out) throws IOException { + super(out); } /** * Creates new instance * * @param out the output stream to use - * @param min upper left corner - * @param max lower right corner * @param source source file, only used to create a comment in the SVG file * @param svgScale the scaling * @throws IOException IOException */ - public GraphicSVGIndex(OutputStream out, Vector min, Vector max, File source, int svgScale) throws IOException { - super(out, min, max, source, svgScale); + public GraphicSVGIndex(OutputStream out, File source, int svgScale) throws IOException { + super(out, source, svgScale); } @Override diff --git a/src/main/java/de/neemann/digital/draw/graphics/GraphicSVGLaTeX.java b/src/main/java/de/neemann/digital/draw/graphics/GraphicSVGLaTeX.java index ac0f8e3ba..962700872 100644 --- a/src/main/java/de/neemann/digital/draw/graphics/GraphicSVGLaTeX.java +++ b/src/main/java/de/neemann/digital/draw/graphics/GraphicSVGLaTeX.java @@ -22,26 +22,22 @@ public class GraphicSVGLaTeX extends GraphicSVG { * Creates new instance * * @param out the file - * @param min upper left corner - * @param max lower right corner * @throws IOException IOException */ - public GraphicSVGLaTeX(OutputStream out, Vector min, Vector max) throws IOException { - super(out, min, max); + public GraphicSVGLaTeX(OutputStream out) throws IOException { + super(out); } /** * Creates new instance * * @param out the output stream to use - * @param min upper left corner - * @param max lower right corner * @param source source file, only used to create a comment in the SVG file * @param svgScale the scaling * @throws IOException IOException */ - public GraphicSVGLaTeX(OutputStream out, Vector min, Vector max, File source, int svgScale) throws IOException { - super(out, min, max, source, svgScale); + public GraphicSVGLaTeX(OutputStream out, File source, int svgScale) throws IOException { + super(out, source, svgScale); } @Override diff --git a/src/main/java/de/neemann/digital/draw/graphics/GraphicSwing.java b/src/main/java/de/neemann/digital/draw/graphics/GraphicSwing.java index 0e9e1aa76..a3875fa8e 100644 --- a/src/main/java/de/neemann/digital/draw/graphics/GraphicSwing.java +++ b/src/main/java/de/neemann/digital/draw/graphics/GraphicSwing.java @@ -14,10 +14,10 @@ import static de.neemann.digital.core.element.ElementAttributes.cleanLabel; */ public class GraphicSwing implements Graphic { - private final Graphics2D gr; private final int minFontSize; private int pixelSize; private Style lastStyle; + private Graphics2D gr; /** * Creates a new instance @@ -38,7 +38,17 @@ public class GraphicSwing implements Graphic { this.gr = gr; this.pixelSize = pixelSize; this.minFontSize = pixelSize * 3; - gr.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + if (gr != null) + gr.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + } + + /** + * Set the graphics instance to use + * + * @param gr the Graphics2D to draw to + */ + protected void setGraphics2D(Graphics2D gr) { + this.gr = gr; } @Override diff --git a/src/main/java/de/neemann/digital/draw/graphics/GraphicsImage.java b/src/main/java/de/neemann/digital/draw/graphics/GraphicsImage.java index 7b0b2345c..3f00b75a1 100644 --- a/src/main/java/de/neemann/digital/draw/graphics/GraphicsImage.java +++ b/src/main/java/de/neemann/digital/draw/graphics/GraphicsImage.java @@ -14,20 +14,29 @@ import java.io.OutputStream; */ public final class GraphicsImage extends GraphicSwing implements Closeable { + private final OutputStream out; + private final String format; + private final float scale; + private BufferedImage bi; + /** - * Creates a new instance of this class + * Creates a new instance * - * @param out the OutputStream to write the image to - * @param min upper left corner - * @param max lower right corner + * @param out the output stream * @param format the format to write - * @param scale the scaling of the created image - * @return the {@link Graphic} instance + * @param scale the scaling */ - public static GraphicsImage create(OutputStream out, Vector min, Vector max, String format, float scale) { + public GraphicsImage(OutputStream out, String format, float scale) { + super(null); + this.out = out; + this.format = format; + this.scale = scale; + } + + @Override + public Graphic setBoundingBox(Vector min, Vector max) { int thickness = Style.MAXLINETHICK; - BufferedImage bi - = new BufferedImage( + bi = new BufferedImage( Math.round((max.x - min.x + thickness * 2) * scale), Math.round((max.y - min.y + thickness * 2) * scale), BufferedImage.TYPE_INT_ARGB); @@ -42,19 +51,8 @@ public final class GraphicsImage extends GraphicSwing implements Closeable { gr.scale(scale, scale); gr.translate(thickness - min.x, thickness - min.y); - - return new GraphicsImage(out, gr, bi, format); - } - - private final OutputStream out; - private final BufferedImage bi; - private final String format; - - private GraphicsImage(OutputStream out, Graphics2D gr, BufferedImage bi, String format) { - super(gr); - this.out = out; - this.bi = bi; - this.format = format; + setGraphics2D(gr); + return this; } @Override diff --git a/src/main/java/de/neemann/digital/gui/Main.java b/src/main/java/de/neemann/digital/gui/Main.java index c5a655b56..43f035efb 100644 --- a/src/main/java/de/neemann/digital/gui/Main.java +++ b/src/main/java/de/neemann/digital/gui/Main.java @@ -477,8 +477,8 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS JMenu export = new JMenu(Lang.get("menu_export")); export.add(new ExportAction(Lang.get("menu_exportSVG"), "svg", GraphicSVGIndex::new)); export.add(new ExportAction(Lang.get("menu_exportSVGLaTex"), "svg", GraphicSVGLaTeX::new)); - export.add(new ExportAction(Lang.get("menu_exportPNGSmall"), "png", (out, min, max) -> GraphicsImage.create(out, min, max, "PNG", 1))); - export.add(new ExportAction(Lang.get("menu_exportPNGLarge"), "png", (out, min, max) -> GraphicsImage.create(out, min, max, "PNG", 2))); + export.add(new ExportAction(Lang.get("menu_exportPNGSmall"), "png", (out) -> new GraphicsImage(out, "PNG", 1))); + export.add(new ExportAction(Lang.get("menu_exportPNGLarge"), "png", (out) -> new GraphicsImage(out, "PNG", 2))); if (enableExperimental()) export.add(new ExportGifAction(Lang.get("menu_exportAnimatedGIF"))); diff --git a/src/test/java/de/neemann/digital/docu/DocuTest.java b/src/test/java/de/neemann/digital/docu/DocuTest.java index f4324251a..169c90bfc 100644 --- a/src/test/java/de/neemann/digital/docu/DocuTest.java +++ b/src/test/java/de/neemann/digital/docu/DocuTest.java @@ -116,10 +116,11 @@ public class DocuTest extends TestCase { } private void writeSVG(File imageFile, VisualElement ve) throws IOException { - GraphicMinMax minMax = new GraphicMinMax(true); - ve.drawTo(minMax, null); try (FileOutputStream out = new FileOutputStream(imageFile)) { - try (GraphicSVG svg = new GraphicSVG(out, minMax.getMin(), minMax.getMax(), null, 20)) { + try (GraphicSVG svg = new GraphicSVG(out, null, 20)) { + GraphicMinMax minMax = new GraphicMinMax(true, svg); + ve.drawTo(minMax, null); + svg.setBoundingBox(minMax.getMin(), minMax.getMax()); ve.drawTo(svg, null); } } diff --git a/src/test/java/de/neemann/digital/draw/graphics/GraphicSVGIndexTest.java b/src/test/java/de/neemann/digital/draw/graphics/GraphicSVGIndexTest.java index 2f06aaf8c..3aa0d5b4f 100644 --- a/src/test/java/de/neemann/digital/draw/graphics/GraphicSVGIndexTest.java +++ b/src/test/java/de/neemann/digital/draw/graphics/GraphicSVGIndexTest.java @@ -7,7 +7,8 @@ import junit.framework.TestCase; */ public class GraphicSVGIndexTest extends TestCase { public void testFormatText() throws Exception { - GraphicSVGIndex gs = new GraphicSVGIndex(System.out, new Vector(0, 0), new Vector(30, 30), null, 30); + GraphicSVGIndex gs = new GraphicSVGIndex(System.out, null, 30); + gs.setBoundingBox(new Vector(0, 0), new Vector(30, 30)); assertEquals("Z0", gs.formatText("Z_0", 0)); assertEquals("<a>", gs.formatText("", 0)); diff --git a/src/test/java/de/neemann/digital/draw/graphics/GraphicSVGLaTeXTest.java b/src/test/java/de/neemann/digital/draw/graphics/GraphicSVGLaTeXTest.java index 68c66ddd1..1dcf19fc5 100644 --- a/src/test/java/de/neemann/digital/draw/graphics/GraphicSVGLaTeXTest.java +++ b/src/test/java/de/neemann/digital/draw/graphics/GraphicSVGLaTeXTest.java @@ -7,7 +7,8 @@ import junit.framework.TestCase; */ public class GraphicSVGLaTeXTest extends TestCase { public void testFormatText() throws Exception { - GraphicSVGLaTeX gs = new GraphicSVGLaTeX(System.out, new Vector(0, 0), new Vector(30, 30), null, 30); + GraphicSVGLaTeX gs = new GraphicSVGLaTeX(System.out, null, 30); + gs.setBoundingBox(new Vector(0, 0), new Vector(30, 30)); assertEquals("$Z_{0}$", gs.formatText("Z_0", Style.NORMAL.getFontSize())); assertEquals("\\&", gs.formatText("&", Style.NORMAL.getFontSize())); diff --git a/src/test/java/de/neemann/digital/draw/graphics/GraphicSVGTest.java b/src/test/java/de/neemann/digital/draw/graphics/GraphicSVGTest.java index 4c5f2ab9d..5821a3760 100644 --- a/src/test/java/de/neemann/digital/draw/graphics/GraphicSVGTest.java +++ b/src/test/java/de/neemann/digital/draw/graphics/GraphicSVGTest.java @@ -7,7 +7,8 @@ import junit.framework.TestCase; */ public class GraphicSVGTest extends TestCase { public void testFormatText() throws Exception { - GraphicSVG gs = new GraphicSVG(System.out, new Vector(0, 0), new Vector(30, 30), null, 30); + GraphicSVG gs = new GraphicSVG(System.out, null, 30); + gs.setBoundingBox(new Vector(0, 0), new Vector(30, 30)); assertEquals("Z0", gs.formatText("Z0", 0)); assertEquals("<a>", gs.formatText("", 0)); diff --git a/src/test/java/de/neemann/digital/integration/TestData.java b/src/test/java/de/neemann/digital/integration/TestData.java index 29308d644..53eeca47b 100644 --- a/src/test/java/de/neemann/digital/integration/TestData.java +++ b/src/test/java/de/neemann/digital/integration/TestData.java @@ -1,6 +1,7 @@ package de.neemann.digital.integration; import de.neemann.digital.draw.graphics.Export; +import de.neemann.digital.draw.graphics.GraphicTransform; import de.neemann.digital.draw.graphics.GraphicsImage; import de.neemann.digital.gui.components.data.DataSample; import de.neemann.digital.gui.components.data.DataSet; @@ -45,7 +46,7 @@ public class TestData extends TestCase { // try to write data to graphics instance ByteArrayOutputStream baos = new ByteArrayOutputStream(); new Export(toBreakRunner.getCircuit(), - (out, min, max) -> GraphicsImage.create(out, min, max, "PNG", 1)) + (out) -> new GraphicsImage(out, "PNG", 1)) .export(baos); assertTrue(baos.size() > 15000); diff --git a/src/test/java/de/neemann/digital/integration/TestExport.java b/src/test/java/de/neemann/digital/integration/TestExport.java index 61ed438a9..540719039 100644 --- a/src/test/java/de/neemann/digital/integration/TestExport.java +++ b/src/test/java/de/neemann/digital/integration/TestExport.java @@ -28,7 +28,7 @@ public class TestExport extends TestCase { public void testSVGExport() throws NodeException, PinException, IOException, ElementNotFoundException { ByteArrayOutputStream baos = export("../../main/dig/processor/Processor.dig", - (out, min, max) -> new GraphicSVGIndex(out, min, max, null, 15)); + (out) -> new GraphicSVGIndex(out, null, 15)); assertTrue(baos.size() > 20000); } @@ -36,7 +36,7 @@ public class TestExport extends TestCase { public void testSVGExportLaTeX() throws NodeException, PinException, IOException, ElementNotFoundException { ByteArrayOutputStream baos = export("../../main/dig/processor/Processor.dig", - (out, min, max) -> new GraphicSVGLaTeX(out, min, max, null, 15)); + (out) -> new GraphicSVGLaTeX(out, null, 15)); assertTrue(baos.size() > 15000); } @@ -44,7 +44,7 @@ public class TestExport extends TestCase { public void testPNGExport() throws NodeException, PinException, IOException, ElementNotFoundException { ByteArrayOutputStream baos = export("../../main/dig/processor/Processor.dig", - (out, min, max) -> GraphicsImage.create(out, min, max, "PNG", 1)); + (out) -> new GraphicsImage(out, "PNG", 1)); assertTrue(baos.size() > 45000); } diff --git a/src/test/java/de/neemann/digital/integration/TestShapes.java b/src/test/java/de/neemann/digital/integration/TestShapes.java index ce0a01659..14b0cc79e 100644 --- a/src/test/java/de/neemann/digital/integration/TestShapes.java +++ b/src/test/java/de/neemann/digital/integration/TestShapes.java @@ -39,7 +39,7 @@ public class TestShapes extends TestCase { // try to write circuit to graphics instance ByteArrayOutputStream baos = new ByteArrayOutputStream(); new Export(circuit, - (out, min, max) -> GraphicsImage.create(out, min, max, "PNG", 1)) + (out) -> new GraphicsImage(out, "PNG", 1)) .export(baos); assertTrue(baos.size() > 30000);