2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import java.awt.Component;
24 import java.awt.Graphics;
26 import java.util.concurrent.atomic.AtomicBoolean;
28 import jalview.bin.Cache;
29 import jalview.bin.Jalview;
30 import jalview.io.JalviewFileChooser;
31 import jalview.io.JalviewFileView;
32 import jalview.io.exceptions.ImageOutputException;
33 import jalview.util.ImageMaker;
34 import jalview.util.ImageMaker.TYPE;
35 import jalview.util.MessageManager;
36 import jalview.util.Platform;
37 import jalview.util.imagemaker.BitmapImageSizing;
40 * A class that marshals steps in exporting a view in image graphics format
42 * <li>prompts the user for the output file, if not already specified</li>
43 * <li>prompts the user for Text or Lineart character rendering, if
45 * <li>instantiates an ImageMaker to create the appropriate Graphics output
46 * context for the image format</li>
47 * <li>invokes a callback to do the work of writing to the graphics</li>
53 public class ImageExporter
55 // todo move interface to jalview.api? or replace with lambda?
57 * An interface for the callback that can be run to write the image on to the
58 * graphics object. The callback should throw any exceptions arising so they
59 * can be reported by this class.
61 public interface ImageWriterI
63 void exportImage(Graphics g) throws Exception;
66 private IProgressIndicator messageBoard;
68 private ImageWriterI imageWriter;
75 * Constructor given a callback handler to write graphics data, an (optional)
76 * target for status messages, image type and (optional) title for output file
83 public ImageExporter(ImageWriterI writer, IProgressIndicator statusBar,
84 TYPE type, String fileTitle)
86 this.imageWriter = writer;
87 this.messageBoard = statusBar;
88 this.imageType = type;
89 this.title = fileTitle;
93 * Prompts the user for output file and Text/Lineart options as required,
94 * configures a Graphics context for output, and makes a callback to the
95 * client code to perform the image output
98 * output file (if null, user is prompted to choose)
100 * parent component for any dialogs shown
104 * what the image is of e.g. Tree, Alignment
106 public void doExport(File file, Component parent, int width, int height,
107 String imageSource) throws ImageOutputException
109 doExport(file, parent, width, height, imageSource, null,
110 BitmapImageSizing.nullBitmapImageSizing());
113 public void doExport(File file, Component parent, int width, int height,
114 String imageSource, String renderer, BitmapImageSizing userBis) throws ImageOutputException
116 final long messageId = System.currentTimeMillis();
118 MessageManager.formatMessage(
119 "status.exporting_alignment_as_x_file", imageType),
123 * prompt user for output file if not provided
125 if (file == null && !Jalview.isHeadlessMode())
127 if (Desktop.instance.isInBatchMode())
129 // defensive error report - we could wait for user input.. I guess ?
130 throw(new ImageOutputException("Need an output file to render to when exporting images in batch mode!"));
132 JalviewFileChooser chooser = imageType.getFileChooser();
133 chooser.setFileView(new JalviewFileView());
134 MessageManager.formatMessage("label.create_image_of",
135 imageType.getName(), imageSource);
136 String title = "Create " + imageType.getName()
137 + " image from alignment";
138 chooser.setDialogTitle(title);
139 chooser.setToolTipText(MessageManager.getString("action.save"));
140 int value = chooser.showSaveDialog(parent);
141 if (value != JalviewFileChooser.APPROVE_OPTION)
143 String msg = MessageManager.formatMessage(
144 "status.cancelled_image_export_operation", imageType.name);
145 setStatus(msg, messageId);
148 Cache.setProperty("LAST_DIRECTORY",
149 chooser.getSelectedFile().getParent());
150 file = chooser.getSelectedFile();
154 * Prompt for Text or Lineart (EPS/SVG) unless a preference is already set
155 * for this as EPS_RENDERING / SVG_RENDERING
156 * Always set to Text for JalviewJS as Lineart (glyph fonts) not available
158 String renderStyle = renderer == null
159 ? Cache.getDefault(imageType.getName() + "_RENDERING",
160 LineartOptions.PROMPT_EACH_TIME)
164 renderStyle = "Text";
166 AtomicBoolean textSelected = new AtomicBoolean(
167 !"Lineart".equals(renderStyle));
168 if ((imageType == TYPE.EPS || imageType == TYPE.SVG)
169 && LineartOptions.PROMPT_EACH_TIME.equals(renderStyle)
170 && !Jalview.isHeadlessMode())
172 final File chosenFile = file;
173 Runnable okAction = () -> {
174 exportImage(chosenFile, !textSelected.get(), width, height,
177 LineartOptions epsOption = new LineartOptions(TYPE.EPS.getName(),
179 epsOption.setResponseAction(1, () -> {
180 setStatus(MessageManager.formatMessage(
181 "status.cancelled_image_export_operation",
182 imageType.getName()), messageId);
184 epsOption.setResponseAction(0, okAction);
185 epsOption.showDialog();
186 /* no code here - JalviewJS cannot execute it */
191 * character rendering not required, or preference already set
192 * - just do the export
194 exportImage(file, !textSelected.get(), width, height, messageId,
200 * Constructs a suitable graphics context and passes it to the callback
201 * handler for the image to be written. Shows status messages for export in
202 * progress, complete, or failed as appropriate.
210 protected void exportImage(File chosenFile, boolean asLineart, int width,
211 int height, long messageId, BitmapImageSizing userBis)
213 String type = imageType.getName();
217 // MessageManager.formatMessage(
218 // "status.exporting_alignment_as_x_file", type),
220 ImageMaker im = new ImageMaker(imageType, width, height, chosenFile,
221 title, asLineart, userBis);
222 imageWriter.exportImage(im.getGraphics());
225 MessageManager.formatMessage("status.export_complete", type),
227 } catch (Exception e)
229 jalview.bin.Console.error(String.format("Error creating %s file: %s", type,
231 setStatus(MessageManager.formatMessage("info.error_creating_file",
237 * Asks the callback to show a status message with given id
242 void setStatus(String msg, long id)
244 if (messageBoard != null && !Jalview.isHeadlessMode())
246 messageBoard.setProgressBar(msg, id);