1 package org.simantics.diagram.export;
3 import java.awt.Graphics2D;
5 import java.awt.RenderingHints;
6 import java.awt.geom.AffineTransform;
7 import java.awt.geom.Rectangle2D;
8 import java.awt.image.BufferedImage;
11 import javax.imageio.ImageIO;
13 import org.simantics.g2d.canvas.ICanvasContext;
14 import org.simantics.g2d.diagram.DiagramHints;
15 import org.simantics.g2d.diagram.DiagramUtils;
16 import org.simantics.g2d.diagram.IDiagram;
17 import org.simantics.g2d.participant.TransformUtil;
18 import org.simantics.scenegraph.g2d.G2DRenderingHints;
19 import org.simantics.scenegraph.utils.QualityHints;
20 import org.simantics.utils.page.MarginUtils;
22 public class ImageBuilder {
31 * @param file File to write the image (optional)
32 * @param dpi Dots Per Inch
33 * @param size Image size in pixels
34 * @param margin percentage of image width for margins. 0.05 is 5%.
36 public ImageBuilder(File file, Double dpi, Point size, double margin) {
40 this.margin = Math.max(margin,0.0);
45 * @param canvasContext
46 * the canvas context to paint
48 * <code>true</code> to actually write the resulting Image to the file.
50 public BufferedImage paint(ICanvasContext canvasContext) throws Exception {
53 BufferedImage image = null;
55 IDiagram diagram = canvasContext.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM);
56 Rectangle2D diagramRect = DiagramUtils.getContentRect(diagram);
58 if (diagramRect == null)
59 diagramRect = new Rectangle2D.Double(0, 0, 100, 100);
61 // add margins to content.
62 double off = Math.max(diagramRect.getWidth(), diagramRect.getHeight()) * margin*0.5;
63 diagramRect = new Rectangle2D.Double(diagramRect.getX() - off, diagramRect.getY() - off, diagramRect.getWidth() + off * 2.0, diagramRect.getHeight() + off * 2.0);
65 // Make sure the transformation is reset.
66 AffineTransform tr = new AffineTransform();
68 Rectangle2D controlArea;
70 double mmToInch = 1.0 / 25.0;
71 controlArea = new Rectangle2D.Double(0, 0, diagramRect.getWidth() * mmToInch * dpi, diagramRect.getHeight() * mmToInch * dpi);
74 controlArea = new Rectangle2D.Double(0, 0, size.getX(), size.getY());
77 canvasContext.getSingleItem(TransformUtil.class).fitArea(controlArea, diagramRect, MarginUtils.NO_MARGINS);
79 int width = (int) controlArea.getWidth();
80 int height = (int) controlArea.getHeight();
81 long sizeBytes = width*height*3;
82 long free = Runtime.getRuntime().freeMemory();
83 if (sizeBytes >= free) { // TODO: should we estimate memory required for rendering?
85 free = Runtime.getRuntime().freeMemory();
88 if (sizeBytes >= free) {
89 throw new Exception("There is not enough available memory to create the image; required " + sizeBytes + ", available " + free);
92 image = new BufferedImage(width, height , BufferedImage.TYPE_3BYTE_BGR);
93 g2 = (Graphics2D) image.getGraphics();
95 QualityHints.HIGH_QUALITY_HINTS.setQuality(g2);
96 g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
100 g2.setClip(new Rectangle2D.Double(0, 0, controlArea.getWidth(), controlArea.getHeight()));
102 g2.setRenderingHint(G2DRenderingHints.KEY_CONTROL_BOUNDS, new Rectangle2D.Double(0, 0, controlArea.getWidth(), controlArea.getHeight()));
104 if (canvasContext.isLocked())
105 throw new IllegalStateException("cannot render image, canvas context is locked: " + canvasContext);
107 canvasContext.getSceneGraph().render(g2);
110 String name = file.getName();
111 name = name.substring(name.lastIndexOf(".") + 1);
112 ImageIO.write(image, name, file);