/* GeoGebra - Dynamic Mathematics for Everyone http://www.geogebra.org This file is part of GeoGebra. This program 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. */ package org.geogebra.desktop.export; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.text.NumberFormat; import java.util.Locale; import javax.imageio.ImageIO; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingUtilities; import org.freehep.graphics2d.VectorGraphics; import org.freehep.graphicsio.AbstractVectorGraphicsIO; import org.freehep.graphicsio.FontConstants; import org.freehep.graphicsio.emf.EMFGraphics2D; import org.freehep.graphicsio.emf.EMFPlusGraphics2D; import org.freehep.graphicsio.pdf.PDFGraphics2D; import org.freehep.graphicsio.svg.SVGGraphics2D; import org.freehep.util.UserProperties; import org.geogebra.common.GeoGebraConstants; import org.geogebra.common.awt.GGraphics2D; import org.geogebra.common.euclidian.EuclidianView; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.main.App.ExportType; import org.geogebra.common.util.FileExtensions; import org.geogebra.common.util.StringUtil; import org.geogebra.common.util.debug.Log; import org.geogebra.common.util.lang.Unicode; import org.geogebra.desktop.awt.GGraphics2DD; import org.geogebra.desktop.euclidian.EuclidianViewD; import org.geogebra.desktop.euclidianND.EuclidianViewInterfaceD; import org.geogebra.desktop.export.epsgraphics.ColorMode; import org.geogebra.desktop.export.epsgraphics.EpsGraphics; import org.geogebra.desktop.export.epsgraphics.EpsGraphicsD; import org.geogebra.desktop.gui.util.FileTransferable; import org.geogebra.desktop.main.AppD; import org.geogebra.desktop.main.FontManagerD; import org.geogebra.desktop.main.GeoGebraPreferencesD; import org.geogebra.desktop.main.LocalizationD; import org.geogebra.desktop.util.UtilD; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; /** * @author Markus Hohenwarter */ public class GraphicExportDialog extends JDialog implements KeyListener { // #4979 private static final int EXTRA_MARGIN = 4; private static final long serialVersionUID = 1L; private static final String CREATOR = "GeoGebra / FreeHEP Graphics2D Driver"; private final AppD app; @SuppressWarnings("rawtypes") private JComboBox cbFormat; /** * Combobox for DPI */ @SuppressWarnings("rawtypes") JComboBox cbDPI; private JLabel sizeLabel; private JButton cancelButton; private double exportScale; private int pixelWidth, pixelHeight; private double cmWidth, cmHeight; private final NumberFormat sizeLabelFormat; /** convert text to shapes (eps, pdf, svg) */ boolean textAsShapes = true; /** true for transparent images (png) */ boolean transparent = true; /** set true if Braille font installed */ boolean braille = false; /** whether EMF+ is used or EMF */ boolean EMFPlus = true; private enum Format { PNG, PDF, EPS, SVG, EMF } private EuclidianViewD specifiedEuclidianView; /** print scale or pixel size settings */ PrintScalePanel psp; private LocalizationD loc; /** * Creates a dialog for exporting an image of the active EuclidianView * * @param app * application */ public GraphicExportDialog(AppD app) { this(app, null); } /** * Creates a dialog for exporting an image of the EuclidianView given as a * parameter. * * @param app * application * @param specifiedEuclidianView * EV */ public GraphicExportDialog(AppD app, EuclidianViewD specifiedEuclidianView) { super(app.getFrame(), false); this.app = app; this.loc = app.getLocalization(); this.specifiedEuclidianView = specifiedEuclidianView; sizeLabelFormat = NumberFormat.getInstance(Locale.ENGLISH); sizeLabelFormat.setGroupingUsed(false); sizeLabelFormat.setMaximumFractionDigits(2); checkBrailleFont(); initGUI(); } private Font brailleFont = null; /** * check if a Braille font is installed */ private void checkBrailleFont() { final String preferredBrailleFont = "IDV ComputerBraille (ANSI)"; GraphicsEnvironment e = GraphicsEnvironment .getLocalGraphicsEnvironment(); Font[] fonts = e.getAllFonts(); // Get the fonts // check preferred font first for (Font f : fonts) { if (f.getFontName().equals(preferredBrailleFont)) { Log.debug("found Braille font: " + f.getFontName()); brailleFont = f; braille = true; return; } } // preferred font not found, check for any that contain "braille" for (Font f : fonts) { if (StringUtil.toLowerCase(f.getFontName()) .indexOf("braille") > -1) { Log.debug("found Braille font: " + f.getFontName()); brailleFont = f; braille = true; return; } } } private EuclidianViewInterfaceD getEuclidianView() { if (specifiedEuclidianView != null) { return specifiedEuclidianView; } return (EuclidianViewInterfaceD) app.getActiveEuclidianView(); } @Override public void setVisible(boolean flag) { if (flag) { loadPreferences(); super.setVisible(true); } else { savePreferences(); super.setVisible(false); } } @SuppressWarnings({ "unchecked", "rawtypes" }) private void initGUI() { setResizable(false); setTitle(loc.getMenu("ExportAsPicture")); JPanel cp = new JPanel(new BorderLayout(5, 5)); cp.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); getContentPane().add(cp); // format list JPanel formatPanel = new JPanel(new FlowLayout(5)); String[] formats; if (((EuclidianView) getEuclidianView()).isEuclidianView3D()) { formats = new String[] { loc.getMenu("png") + " (" + FileExtensions.PNG + ")" }; } else { formats = new String[] { loc.getMenu("png") + " (" + FileExtensions.PNG + ")", loc.getMenu("pdf") + " (" + FileExtensions.PDF + ")", loc.getMenu("eps") + " (" + FileExtensions.EPS + ")", loc.getMenu("svg") + " (" + FileExtensions.SVG + ")", loc.getMenu("emf") + " (" + FileExtensions.EMF + ")" }; } cbFormat = new JComboBox(formats); formatPanel.add(new JLabel(loc.getMenu("Format") + ":")); formatPanel.add(cbFormat); cp.add(formatPanel, BorderLayout.NORTH); // panel with fields to enter // scale of image, dpi and // width and height of picture final JPanel p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); // scale EuclidianView ev = (EuclidianView) getEuclidianView(); psp = new PrintScalePanel(app, ev); psp.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateSizeLabel(); } }); p.add(psp); // dpi combo box final JPanel dpiPanel = new JPanel(new FlowLayout(5)); String[] dpiStr = { "72", "96", "150", "300", "600" }; cbDPI = new JComboBox(dpiStr); cbDPI.setSelectedItem("300"); final JLabel resolutionInDPILabel = new JLabel( loc.getMenu("ResolutionInDPI") + ":"); final JCheckBox cbTransparent = new JCheckBox( loc.getMenu("Transparent"), transparent); final JCheckBox cbBraille = new JCheckBox(loc.getMenu("Braille"), braille); final JCheckBox cbEMFPlus = new JCheckBox(loc.getMenu("EMFPlus"), EMFPlus); final JCheckBox textAsShapesCB = new JCheckBox( loc.getMenu("ExportTextAsShapes"), textAsShapes); // make sure panel is wide enough if (selectedFormat() == Format.PNG) { dpiPanel.add(resolutionInDPILabel); dpiPanel.add(cbDPI); if (brailleFont != null) { // GGB-766 dpiPanel.add(cbBraille); } dpiPanel.add(cbTransparent); } else if (selectedFormat() == Format.SVG) { dpiPanel.add(cbTransparent); } else if (selectedFormat() == Format.EMF) { dpiPanel.add(cbEMFPlus); } else { dpiPanel.add(textAsShapesCB); } p.add(dpiPanel); cbDPI.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { updateSizeLabel(); } }); cbTransparent.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { transparent = cbTransparent.isSelected(); } }); cbBraille.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { braille = cbBraille.isSelected(); } }); cbEMFPlus.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { EMFPlus = cbEMFPlus.isSelected(); } }); textAsShapesCB.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { textAsShapes = textAsShapesCB.isSelected(); } }); cbFormat.addActionListener(new ActionListener() { @Override @SuppressFBWarnings({ "SF_SWITCH_FALLTHROUGH", "missing break is deliberate" }) public void actionPerformed(ActionEvent arg0) { textAsShapesCB.setEnabled(true); switch (selectedFormat()) { case SVG: dpiPanel.remove(resolutionInDPILabel); dpiPanel.remove(cbDPI); dpiPanel.remove(cbEMFPlus); dpiPanel.add(cbTransparent); dpiPanel.add(textAsShapesCB); psp.enableAbsoluteSize(true); break; case EPS: textAsShapesCB.setEnabled(false); // fall through case PDF: dpiPanel.remove(resolutionInDPILabel); dpiPanel.remove(cbDPI); dpiPanel.remove(cbEMFPlus); dpiPanel.remove(cbTransparent); dpiPanel.remove(cbBraille); dpiPanel.add(textAsShapesCB); textAsShapesCB.setSelected(true); psp.enableAbsoluteSize(false); break; case EMF: dpiPanel.add(cbEMFPlus); dpiPanel.remove(resolutionInDPILabel); dpiPanel.remove(cbDPI); dpiPanel.remove(cbTransparent); dpiPanel.remove(textAsShapesCB); dpiPanel.remove(cbBraille); psp.enableAbsoluteSize(false); break; default: // PNG dpiPanel.add(resolutionInDPILabel); dpiPanel.add(cbDPI); dpiPanel.remove(cbEMFPlus); dpiPanel.add(cbTransparent); if (braille) { // GGB-766 dpiPanel.add(cbBraille); } dpiPanel.remove(textAsShapesCB); cbDPI.setSelectedItem("300"); cbDPI.setEnabled(true); psp.enableAbsoluteSize(true); break; } updateSizeLabel(); SwingUtilities.updateComponentTreeUI(p); } }); // width and height of picture JPanel sizePanel = new JPanel(new FlowLayout(5)); sizePanel.add(new JLabel(loc.getMenu("Size") + ":")); sizeLabel = new JLabel(); sizePanel.add(sizeLabel); p.add(sizePanel); cp.add(p, BorderLayout.CENTER); // Cancel and Export Button cancelButton = new JButton(loc.getMenu("Cancel")); cancelButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setVisible(false); } }); JButton exportButton = new JButton(loc.getMenu("Save")); exportButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Thread runner = new Thread() { @Override public void run() { setVisible(false); doExport(false); } }; runner.start(); } }); JButton exportClipboardButton = new JButton(loc.getMenu("Clipboard")); exportClipboardButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Thread runner = new Thread() { @Override public void run() { setVisible(false); doExport(true); } }; runner.start(); } }); JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); buttonPanel.add(exportButton); /* * This is done via copying a file to the clipboard. This is not * supported on Mac. * Toolkit.getDefaultToolkit().getSystemClipboard().setContents * (geogebra.gui.util.ImageSelection, null) would be OK (via * AppD.simpleExportToClipboard(EuclidianView)), but this code here * wants to use * Toolkit.getDefaultToolkit().getSystemClipboard().setContents * (FileTransferable, null) via sendToClipboard(File). So we simply not * show the "Clipboard" button here on Mac. */ if (!app.isMacOS()) { buttonPanel.add(exportClipboardButton); } buttonPanel.add(cancelButton); cp.add(buttonPanel, BorderLayout.SOUTH); UtilD.addKeyListenerToAll(this, this); updateSizeLabel(); setPreferredSize(new Dimension( getPreferredSize().width + app.getFontSize() * EXTRA_MARGIN, getPreferredSize().height + app.getFontSize() * EXTRA_MARGIN)); centerOnScreen(); } /** * Creates the picture of the correct format * * @param toClipboard * whether output is a file or clipboard */ void doExport(boolean toClipboard) { Format index = selectedFormat(); switch (index) { case PNG: FontManagerD fm = app.getFontManager(); int fontSize = fm.getFontSize(); File pngDestination = toClipboard ? getTmpPNG() : getPNGdestination(); if (pngDestination != null) { if (braille) { // GGB-766 fm.updateDefaultFonts(fontSize, brailleFont.getFontName(), brailleFont.getFontName()); getEuclidianView().updateFonts(); } exportPNGSilent(pngDestination, toClipboard, transparent, getDPI(), exportScale, app, getEuclidianView(), braille ? ExportType.PNG_BRAILLE : ExportType.PNG); if (braille) { // GGB-766 fm.updateDefaultFonts(fontSize, "SansSerif", "Serif"); getEuclidianView().updateFonts(); } } break; case EPS: // EPS exportEPS(toClipboard); break; case EMF: // EMF exportEMF(toClipboard, EMFPlus); break; case PDF: // PDF exportPDF(toClipboard); break; case SVG: // SVG exportSVG(toClipboard); break; } } private int getDPI() { if (selectedFormat() == Format.EPS || selectedFormat() == Format.SVG) { return 72; } return Integer.parseInt((String) cbDPI.getSelectedItem()); } /** * Select a dpi item in the * * @param dpi * must be one of 72,96,150,300,600 */ public void setDPI(String dpi) { cbDPI.setSelectedItem(dpi); } private void loadPreferences() { try { // format Format formatID = Format.PNG; String format = GeoGebraPreferencesD.getPref().loadPreference( GeoGebraPreferencesD.EXPORT_PIC_FORMAT, "png"); if ("eps".equals(format)) { formatID = Format.EPS; } else if ("svg".equals(format)) { formatID = Format.SVG; } if (formatID.ordinal() < cbFormat.getItemCount()) { cbFormat.setSelectedIndex(formatID.ordinal()); } // dpi if (cbDPI.isEnabled()) { String strDPI = GeoGebraPreferencesD.getPref().loadPreference( GeoGebraPreferencesD.EXPORT_PIC_DPI, "300"); for (int i = 0; i < cbDPI.getItemCount(); i++) { String dpi = cbDPI.getItemAt(i).toString(); if (dpi.equals(strDPI)) { cbDPI.setSelectedIndex(i); } } } /* * // scale in cm double scale = * Double.parseDouble(GeoGebraPreferences.loadPreference( * GeoGebraPreferences.EXPORT_PIC_SCALE, "1")); * app.getEuclidianView().setPrintingScale(scale); */ updateSizeLabel(); } catch (Exception e) { e.printStackTrace(); } } private void savePreferences() { // dpi GeoGebraPreferencesD.getPref().savePreference( GeoGebraPreferencesD.EXPORT_PIC_DPI, cbDPI.getSelectedItem().toString()); // format String format; switch (selectedFormat()) { case EPS: format = "eps"; break; case SVG: format = "svg"; break; default: format = "png"; } GeoGebraPreferencesD.getPref() .savePreference(GeoGebraPreferencesD.EXPORT_PIC_FORMAT, format); /* * // scale in cm * GeoGebraPreferences.savePreference(GeoGebraPreferences. * EXPORT_PIC_SCALE, * Double.toString(app.getEuclidianView().getPrintingScale())); */ } /** * Update the pixel size */ void updateSizeLabel() { EuclidianView ev = (EuclidianView) getEuclidianView(); double printingScale = ev.getPrintingScale(); // takes dpi into account (note: eps has 72dpi) StringBuilder sb = new StringBuilder(); switch (psp.getMode()) { case SIZEINPX: pixelWidth = psp.getPixelWidth(); pixelHeight = psp.getPixelHeight(); cmWidth = (pixelWidth * 2.54) / getDPI(); cmHeight = (pixelHeight * 2.54) / getDPI(); exportScale = pixelWidth / ((double) ev.getExportWidth()); break; case FIXED_SIZE: // what the user typed in the "100 screen pixels = x cm" textfield double screenPixels = Kernel.checkDecimalFraction( 100 * ev.getPrintingScale() / ev.getXscale()); // double screenPixelsY = 100 * ev.getPrintingScale() / // ev.getYscale(); cmWidth = ev.getExportWidth() / 100.0 * screenPixels; // not screenPixelsY // eg http://forum.geogebra.org/viewtopic.php?f=8&t=38682 cmHeight = ev.getExportHeight() / 100.0 * screenPixels; pixelWidth = (int) (cmWidth / 2.54 * getDPI()); pixelHeight = (int) (cmHeight / 2.54 * getDPI()); exportScale = pixelWidth / ((double) ev.getExportWidth()); break; case SIZEINCM: exportScale = (printingScale * getDPI()) / 2.54 / ev.getXscale(); // cm size cmWidth = printingScale * (ev.getExportWidth() / ev.getXscale()); // getXscale() is not a typo, see #2894 // #4185 changed back to getYscale() // * ev.getYscale() / ev.getXscale() added for when x:y ratio is not // 1:1 // http://forum.geogebra.org/viewtopic.php?f=8&t=38682 cmHeight = printingScale * (ev.getExportHeight() / ev.getYscale()) * ev.getYscale() / ev.getXscale(); pixelWidth = (int) Math.floor(ev.getExportWidth() * exportScale); pixelHeight = (int) Math.floor(ev.getExportHeight() * exportScale); break; } sb.append(sizeLabelFormat.format(cmWidth)); sb.append(" cm "); sb.append(Unicode.MULTIPLY); sb.append(' '); sb.append(sizeLabelFormat.format(cmHeight)); sb.append(" cm"); Format index = selectedFormat(); if (index == Format.PNG || index == Format.SVG) { // pixel size sb.append(", "); sb.append(pixelWidth); sb.append(' '); sb.append(Unicode.MULTIPLY); sb.append(' '); sb.append(pixelHeight); sb.append(" pixels"); sb.append(Unicode.Superscript_2); } sizeLabel.setText(sb.toString()); } /** * @return curently selected format */ Format selectedFormat() { return Format.values()[cbFormat.getSelectedIndex()]; } private void centerOnScreen() { // center on screen pack(); setLocationRelativeTo(app.getMainComponent()); } /** * Shows save dialog and exports drawing as eps. */ final private boolean exportEPS(final boolean exportToClipboard) { final EuclidianView ev = (EuclidianView) getEuclidianView(); StringBuilder epsOutput = new StringBuilder(); exportEPS(app, (EuclidianViewD) ev, epsOutput, textAsShapes, pixelWidth, pixelHeight, exportScale); File file; if (exportToClipboard) { String tempDir = UtilD.getTempDir(); file = new File(tempDir + "geogebra.eps"); } else { file = app.getGuiManager().showSaveDialog(FileExtensions.EPS, null, loc.getMenu("eps") + " " + loc.getMenu("Files"), true, false); if (file == null) { return false; } } UtilD.writeStringToFile(epsOutput.toString(), file); if (exportToClipboard) { // note this *doesn't* copy as text // so ctrl-V in notepad won't show anything sendToClipboard(file); } return true; } /** * Exports drawing as emf */ final private boolean exportEMF(boolean exportToClipboard, boolean useEMFplus) { File file; if (exportToClipboard) { String tempDir = UtilD.getTempDir(); file = new File(tempDir + "geogebra.emf"); } else { file = app.getGuiManager().showSaveDialog(FileExtensions.EMF, null, loc.getMenu("emf") + " " + loc.getMenu("Files"), true, false); } if (file == null) { return false; } try { exportEMF(app, (EuclidianViewD) getEuclidianView(), file, useEMFplus, pixelWidth, pixelHeight, exportScale); if (exportToClipboard) { sendToClipboard(file); } return true; } catch (Exception ex) { app.showError("SaveFileFailed"); Log.debug(ex.toString()); return false; } catch (Error ex) { app.showError("SaveFileFailed"); Log.debug(ex.toString()); return false; } } /** * Exports drawing as pdf */ final private boolean exportPDF(boolean exportToClipboard) { File file; String tempDir = UtilD.getTempDir(); if (exportToClipboard) { file = new File(tempDir + "geogebra.pdf"); } else { file = app.getGuiManager().showSaveDialog(FileExtensions.PDF, null, loc.getMenu("pdf") + " " + loc.getMenu("Files"), true, false); } if (file == null) { return false; } try { exportPDF(app, (EuclidianViewD) getEuclidianView(), file, textAsShapes, pixelWidth, pixelHeight, exportScale); if (exportToClipboard) { sendToClipboard(file); } return true; } catch (Exception ex) { ex.printStackTrace(); app.showError("SaveFileFailed"); return false; } catch (Error ex) { ex.printStackTrace(); app.showError("SaveFileFailed"); return false; } } /** * Exports drawing as SVG */ final private boolean exportSVG(boolean exportToClipboard) { EuclidianView ev = (EuclidianView) getEuclidianView(); File file; String tempDir = UtilD.getTempDir(); if (exportToClipboard) { file = new File(tempDir + "geogebra.svg"); } else { file = app.getGuiManager().showSaveDialog(FileExtensions.SVG, null, loc.getMenu("svg") + " " + loc.getMenu("Files"), true, false); } if (file == null) { return false; } try { exportSVG(app, (EuclidianViewD) ev, file, textAsShapes, pixelWidth, pixelHeight, cmWidth, cmHeight, exportScale, transparent); if (exportToClipboard) { // note this *doesn't* copy as text // so ctrl-V in notepad won't show anything sendToClipboard(file); } return true; } catch (Exception ex) { ex.printStackTrace(); app.showError("SaveFileFailed"); Log.debug(ex.toString()); return false; } catch (Error ex) { app.showError("SaveFileFailed"); Log.debug(ex.toString()); return false; } finally { ev.restoreOldCoordSystem(); } } /** * Exports drawing as png with given resolution in dpi * * @param exportToClipboard * whether to use clipboard or not * @return whether succesful */ final public static boolean exportPNGClipboard(boolean transparent0, int dpi, double exportScale0, AppD app, EuclidianViewInterfaceD ev) { File file = getTmpPNG(); return exportPNGSilent(file, true, transparent0, dpi, exportScale0, app, ev, ExportType.PNG); } private static File getTmpPNG() { String tempDir = UtilD.getTempDir(); return new File(tempDir + "geogebra.png"); } private File getPNGdestination() { return app.getGuiManager().showSaveDialog(FileExtensions.PNG, null, loc.getMenu("png") + " " + loc.getMenu("Files"), true, false); } private static boolean exportPNGSilent(File file, boolean exportToClipboard, boolean transparent0, int dpi, double exportScale0, AppD app, EuclidianViewInterfaceD ev, ExportType exportType) { if (file == null) { return false; } try { // draw graphics view into image // EuclidianViewInterfaceD ev = getEuclidianView(); exportPNG(ev, file, transparent0, dpi, exportScale0, exportToClipboard, exportType); return true; } catch (Exception ex) { app.showError("SaveFileFailed"); Log.debug(ex.toString()); return false; } catch (Error ex) { app.showError("SaveFileFailed"); Log.debug(ex.toString()); return false; } } @Override public void keyPressed(KeyEvent e) { int code = e.getKeyCode(); if (code == KeyEvent.VK_ESCAPE) { setVisible(false); } } @Override public void keyReleased(KeyEvent e) { // } @Override public void keyTyped(KeyEvent e) { // } public static void sendToClipboard(File file) { FileTransferable ft = new FileTransferable(file); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ft, null); } /** * * @param app * application * @param ev * view * @param file * target file * @param textAsShapes * whether to convert text to curves * @param pixelWidth * width in pixels * @param pixelHeight * height in pixels * @param cmWidth * width in cm * @param cmHeight * height in cm * @param exportScale * scale units / cm * @param transparent0 * transparent? */ public static void exportSVG(AppD app, EuclidianViewD ev, File file, boolean textAsShapes, int pixelWidth, int pixelHeight, double cmWidth, double cmHeight, double exportScale, boolean transparent0) { UserProperties props = (UserProperties) SVGGraphics2D .getDefaultProperties(); props.setProperty(SVGGraphics2D.EMBED_FONTS, !textAsShapes); props.setProperty(AbstractVectorGraphicsIO.TEXT_AS_SHAPES, textAsShapes); SVGGraphics2D.setDefaultProperties(props); // added SVGExtensions to support grouped objects in layers SVGExtensions g; try { g = new SVGExtensions(file, new Dimension((int) (pixelWidth / exportScale), (int) (pixelHeight / exportScale)), cmWidth, cmHeight); g.setCreator(CREATOR); // make sure LaTeX exported at hi res app.setExporting(ExportType.SVG, exportScale); g.startExport(); // export scale = 1 (change for SVG export in cm) // and avoid lots of these in the file // <g // transform="matrix(.56693, 0.0000, 0.0000, .56693, 0.0000, // 0.0000)"> GGraphics2D expGraphics = new GGraphics2DD(g); ev.exportPaintPre(expGraphics, 1, transparent0); g.startGroup("misc"); ev.drawActionObjects(expGraphics); g.endGroup("misc"); for (int layer = 0; layer <= app.getMaxLayerUsed(); layer++) // draw // only // layers // we // need { g.startGroup("layer" + layer); // ev.drawLayers[layer].drawAll(new GGraphics2DD(g)); g.drawAll(ev.drawLayers[layer], new GGraphics2DD(g)); g.endGroup("layer" + layer); } g.endExport(); expGraphics.resetClip(); } catch (IOException e) { e.printStackTrace(); } finally { app.setExporting(ExportType.NONE, 1); } } /** * * @param app * application * @param ev * view * @param file * target file * @param useEMFplus * whether to use EMF+ * @param pixelWidth * width in pixels * @param pixelHeight * height in pixels * @param exportScale * scale units / cm */ public static void exportEMF(AppD app, EuclidianViewD ev, File file, boolean useEMFplus, int pixelWidth, int pixelHeight, double exportScale) { VectorGraphics g; try { if (useEMFplus) { g = new EMFPlusGraphics2D(file, new Dimension(pixelWidth, pixelHeight)); } else { g = new EMFGraphics2D(file, new Dimension(pixelWidth, pixelHeight)); } g.setCreator(CREATOR); // fix problem with aspect ratio in eg MS Word // https://community.oracle.com/thread/1264130 g.setDeviceIndependent(true); g.startExport(); ev.exportPaint(g, exportScale, ExportType.EMF); g.endExport(); } catch (FileNotFoundException e) { e.printStackTrace(); } } /** * * @param app * application * @param ev * view * @param file * target file * @param textAsShapes * whether to convert text to curves * @param pixelWidth * width in pixels * @param pixelHeight * height in pixels * @param exportScale * scale units / cm */ public static void exportPDF(AppD app, EuclidianViewD ev, File file, boolean textAsShapes, int pixelWidth, int pixelHeight, double exportScale) { ImageIO.scanForPlugins(); // export text as shapes or plaintext // shapes: better representation // text: smaller file size, but some unicode symbols don't export eg // Upsilon UserProperties props = (UserProperties) PDFGraphics2D .getDefaultProperties(); // #TRAC-5292 props.setProperty(PDFGraphics2D.EMBED_FONTS, !textAsShapes); props.setProperty(PDFGraphics2D.EMBED_FONTS_AS, FontConstants.EMBED_FONTS_TYPE1); props.setProperty(AbstractVectorGraphicsIO.TEXT_AS_SHAPES, textAsShapes); PDFGraphics2D.setDefaultProperties(props); VectorGraphics g; try { double printingScale = ev.getPrintingScale(); // TODO: why do we need this to make correct size in cm? double factor = ev.getXscale() * 2.54 / 72; // Dimension size = new Dimension( // (int)(ev.getExportWidth() * printingScale / factor), // (int)(ev.getExportHeight() * printingScale / factor)); Dimension size = new Dimension( (int) (ev.getExportWidth() * printingScale / factor), (int) (ev.getExportHeight() * printingScale / factor)); g = new PDFGraphics2D(file, size); g.setCreator(CREATOR); // g. // // PDFRedundanceTracker tracker = new PDFRedundanceTracker(pdf); // Font font = new Font("Impact", Font.PLAIN, 1000); // FontRenderContext context = new FontRenderContext(null, true, // true); // FontEmbedder fe = PDFFontEmbedderType1.create(context, pdf, // "MyFont", tracker); // fe.includeFont(font, Lookup.getInstance().getTable("PDFLatin"), // "F1"); ((PDFGraphics2D) g).setPageSize(size); g.startExport(); ev.exportPaint(g, printingScale / factor, textAsShapes ? ExportType.PDF_TEXTASSHAPES : ExportType.PDF_EMBEDFONTS); g.endExport(); } catch (FileNotFoundException e) { e.printStackTrace(); } } /** * * @param app * application * @param ev * view * @param file * target file * @param textAsShapes * whether to convert text to curves * @param pixelWidth * width in pixels * @param pixelHeight * height in pixels * @param exportScale * scale units / cm */ public static void exportEPS(AppD app, EuclidianViewD ev, StringBuilder epsOutput, boolean textAsShapes, int pixelWidth, int pixelHeight, double exportScale) { EpsGraphics g; g = new EpsGraphicsD( GeoGebraConstants.APPLICATION_NAME + ", " + GeoGebraConstants.GEOGEBRA_WEBSITE, epsOutput, 0, 0, pixelWidth, pixelHeight, ColorMode.COLOR_RGB, ev.getBackgroundCommon()); // draw to epsGraphics2D ev.exportPaint(g, exportScale, false, ExportType.EPS); } /** * * @param ev * view * @param file * target file * @param transparent * whether result should be transparent * @param dpi * dpi * @param exportScale * scale units / cm * @param exportToClipboard * says if exports to clipboard * */ public static void exportPNG(EuclidianViewInterfaceD ev, File file, boolean transparent, int dpi, double exportScale, boolean exportToClipboard, ExportType exportType) { ev.exportImagePNG(exportScale, transparent, dpi, file, exportToClipboard, exportType); } public static void export(String extension, EuclidianViewInterfaceD ev, File file, boolean transparent, int dpi, double exportScale, boolean textAsShapes, boolean useEMFplus, int pixelWidth, int pixelHeight, AppD app) { if ("png".equals(extension)) { // can be 3D View GraphicExportDialog.exportPNG(ev, file, transparent, dpi, exportScale, false, ExportType.PNG); } else if ("eps".equals(extension)) { StringBuilder sb = new StringBuilder(); GraphicExportDialog.exportEPS(app, (EuclidianViewD) ev, sb, textAsShapes, pixelWidth, pixelHeight, exportScale); UtilD.writeStringToFile(sb.toString(), file); } else if ("pdf".equals(extension)) { GraphicExportDialog.exportPDF(app, (EuclidianViewD) ev, file, textAsShapes, pixelWidth, pixelHeight, exportScale); } else if ("emf".equals(extension)) { GraphicExportDialog.exportEMF(app, (EuclidianViewD) ev, file, useEMFplus, pixelWidth, pixelHeight, exportScale); } else if ("svg".equals(extension)) { GraphicExportDialog.exportSVG(app, (EuclidianViewD) ev, file, textAsShapes, pixelWidth, pixelHeight, -1, -1, exportScale, transparent); } } }