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.StringUtils;
38 import jalview.util.imagemaker.BitmapImageSizing;
41 * A class that marshals steps in exporting a view in image graphics format
43 * <li>prompts the user for the output file, if not already specified</li>
44 * <li>prompts the user for Text or Lineart character rendering, if
46 * <li>instantiates an ImageMaker to create the appropriate Graphics output
47 * context for the image format</li>
48 * <li>invokes a callback to do the work of writing to the graphics</li>
54 public class ImageExporter
56 // todo move interface to jalview.api? or replace with lambda?
58 * An interface for the callback that can be run to write the image on to the
59 * graphics object. The callback should throw any exceptions arising so they
60 * can be reported by this class.
62 public interface ImageWriterI
64 void exportImage(Graphics g) throws Exception;
67 private IProgressIndicator messageBoard;
69 private ImageWriterI imageWriter;
76 * Constructor given a callback handler to write graphics data, an (optional)
77 * target for status messages, image type and (optional) title for output file
84 public ImageExporter(ImageWriterI writer, IProgressIndicator statusBar,
85 TYPE type, String fileTitle)
87 this.imageWriter = writer;
88 this.messageBoard = statusBar;
89 this.imageType = type;
90 this.title = fileTitle;
94 * Prompts the user for output file and Text/Lineart options as required,
95 * configures a Graphics context for output, and makes a callback to the
96 * client code to perform the image output
99 * output file (if null, user is prompted to choose)
101 * parent component for any dialogs shown
105 * what the image is of e.g. Tree, Alignment
107 public void doExport(File file, Component parent, int width, int height,
108 String imageSource) throws ImageOutputException
110 doExport(file, parent, width, height, imageSource, null,
111 BitmapImageSizing.defaultBitmapImageSizing());
114 public void doExport(File file, Component parent, int width, int height,
115 String imageSource, String renderer, BitmapImageSizing userBis)
116 throws ImageOutputException
118 final long messageId = System.currentTimeMillis();
120 MessageManager.formatMessage(
121 "status.exporting_alignment_as_x_file", imageType),
125 * prompt user for output file if not provided
127 if (file == null && !Jalview.isHeadlessMode())
129 if (Desktop.instance.isInBatchMode())
131 // defensive error report - we could wait for user input.. I guess ?
132 throw (new ImageOutputException(
133 "Need an output file to render to when exporting images in batch mode!"));
135 JalviewFileChooser chooser = imageType.getFileChooser();
136 chooser.setFileView(new JalviewFileView());
137 MessageManager.formatMessage("label.create_image_of",
138 imageType.getName(), imageSource);
139 String title = "Create " + imageType.getName()
140 + " image from alignment";
141 chooser.setDialogTitle(title);
142 chooser.setToolTipText(MessageManager.getString("action.save"));
143 int value = chooser.showSaveDialog(parent);
144 if (value != JalviewFileChooser.APPROVE_OPTION)
146 String msg = MessageManager.formatMessage(
147 "status.cancelled_image_export_operation", imageType.name);
148 setStatus(msg, messageId);
151 Cache.setProperty("LAST_DIRECTORY",
152 chooser.getSelectedFile().getParent());
153 file = chooser.getSelectedFile();
157 * Prompt for Text or Lineart (EPS/SVG) unless a preference is already set
158 * for this as EPS_RENDERING / SVG_RENDERING
159 * Always set to Text for JalviewJS as Lineart (glyph fonts) not available
161 String renderStyle = renderer == null
162 ? Cache.getDefault(imageType.getName() + "_RENDERING",
163 LineartOptions.PROMPT_EACH_TIME)
167 renderStyle = "Text";
169 AtomicBoolean textSelected = new AtomicBoolean(
170 !StringUtils.equalsIgnoreCase("lineart", renderStyle));
171 if ((imageType == TYPE.EPS || imageType == TYPE.SVG) && StringUtils
172 .equalsIgnoreCase(LineartOptions.PROMPT_EACH_TIME, renderStyle)
173 && !Jalview.isHeadlessMode())
175 final File chosenFile = file;
176 Runnable okAction = () -> {
177 exportImage(chosenFile, !textSelected.get(), width, height,
180 LineartOptions epsOption = new LineartOptions(TYPE.EPS.getName(),
182 epsOption.setResponseAction(1, () -> {
183 setStatus(MessageManager.formatMessage(
184 "status.cancelled_image_export_operation",
185 imageType.getName()), messageId);
187 epsOption.setResponseAction(0, okAction);
188 epsOption.showDialog();
189 /* no code here - JalviewJS cannot execute it */
194 * character rendering not required, or preference already set
195 * or we're in headless mode - just do the export
197 exportImage(file, !textSelected.get(), width, height, messageId,
203 * Constructs a suitable graphics context and passes it to the callback
204 * handler for the image to be written. Shows status messages for export in
205 * progress, complete, or failed as appropriate.
213 protected void exportImage(File chosenFile, boolean asLineart, int width,
214 int height, long messageId, BitmapImageSizing userBis)
216 String type = imageType.getName();
220 // MessageManager.formatMessage(
221 // "status.exporting_alignment_as_x_file", type),
223 ImageMaker im = new ImageMaker(imageType, width, height, chosenFile,
224 title, asLineart, userBis);
225 imageWriter.exportImage(im.getGraphics());
228 MessageManager.formatMessage("status.export_complete", type),
230 } catch (Exception e)
232 jalview.bin.Console.error(String.format("Error creating %s file: %s",
233 type, e.toString()), e);
234 setStatus(MessageManager.formatMessage("info.error_creating_file",
240 * Asks the callback to show a status message with given id
245 void setStatus(String msg, long id)
247 if (messageBoard != null && !Jalview.isHeadlessMode())
249 messageBoard.setProgressBar(msg, id);