Clover icon

Coverage Report

  1. Project Clover database Mon Sep 2 2024 17:57:51 BST
  2. Package jalview.gui

File ImageExporter.java

 

Coverage histogram

../../img/srcFileCovDistChart5.png
43% of files have more coverage

Code metrics

14
47
5
2
253
139
18
0.38
9.4
2.5
3.6

Classes

Class Line # Actions
ImageExporter 54 47 18
0.4696969747%
ImageExporter.ImageWriterI 62 0 0
-1.0 -
 

Contributing tests

This file is covered by 18 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
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.
11    *
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.
16    *
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.
20    */
21    package jalview.gui;
22   
23    import java.awt.Component;
24    import java.awt.Graphics;
25    import java.io.File;
26    import java.util.concurrent.atomic.AtomicBoolean;
27   
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;
39   
40    /**
41    * A class that marshals steps in exporting a view in image graphics format
42    * <ul>
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
45    * necessary</li>
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>
49    * </ul>
50    *
51    * @author gmcarstairs
52    *
53    */
 
54    public class ImageExporter
55    {
56    // todo move interface to jalview.api? or replace with lambda?
57    /**
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.
61    */
 
62    public interface ImageWriterI
63    {
64    void exportImage(Graphics g) throws Exception;
65    }
66   
67    private IProgressIndicator messageBoard;
68   
69    private ImageWriterI imageWriter;
70   
71    TYPE imageType;
72   
73    private String title;
74   
75    /**
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
78    *
79    * @param writer
80    * @param statusBar
81    * @param type
82    * @param fileTitle
83    */
 
84  46 toggle public ImageExporter(ImageWriterI writer, IProgressIndicator statusBar,
85    TYPE type, String fileTitle)
86    {
87  46 this.imageWriter = writer;
88  46 this.messageBoard = statusBar;
89  46 this.imageType = type;
90  46 this.title = fileTitle;
91    }
92   
93    /**
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
97    *
98    * @param file
99    * output file (if null, user is prompted to choose)
100    * @param parent
101    * parent component for any dialogs shown
102    * @param width
103    * @param height
104    * @param imageSource
105    * what the image is of e.g. Tree, Alignment
106    */
 
107  0 toggle public void doExport(File file, Component parent, int width, int height,
108    String imageSource) throws ImageOutputException
109    {
110  0 doExport(file, parent, width, height, imageSource, null,
111    BitmapImageSizing.defaultBitmapImageSizing());
112    }
113   
 
114  46 toggle public void doExport(File file, Component parent, int width, int height,
115    String imageSource, String renderer, BitmapImageSizing userBis)
116    throws ImageOutputException
117    {
118  46 final long messageId = System.currentTimeMillis();
119  46 setStatus(
120    MessageManager.formatMessage(
121    "status.exporting_alignment_as_x_file", imageType),
122    messageId);
123   
124    /*
125    * prompt user for output file if not provided
126    */
127  46 if (file == null && !Jalview.isHeadlessMode())
128    {
129  0 if (Desktop.instance.isInBatchMode())
130    {
131    // defensive error report - we could wait for user input.. I guess ?
132  0 throw (new ImageOutputException(
133    "Need an output file to render to when exporting images in batch mode!"));
134    }
135  0 JalviewFileChooser chooser = imageType.getFileChooser();
136  0 chooser.setFileView(new JalviewFileView());
137  0 MessageManager.formatMessage("label.create_image_of",
138    imageType.getName(), imageSource);
139  0 String title = "Create " + imageType.getName()
140    + " image from alignment";
141  0 chooser.setDialogTitle(title);
142  0 chooser.setToolTipText(MessageManager.getString("action.save"));
143  0 int value = chooser.showSaveDialog(parent);
144  0 if (value != JalviewFileChooser.APPROVE_OPTION)
145    {
146  0 String msg = MessageManager.formatMessage(
147    "status.cancelled_image_export_operation", imageType.name);
148  0 setStatus(msg, messageId);
149  0 return;
150    }
151  0 Cache.setProperty("LAST_DIRECTORY",
152    chooser.getSelectedFile().getParent());
153  0 file = chooser.getSelectedFile();
154    }
155   
156    /*
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
160    */
161  46 String renderStyle = renderer == null
162    ? Cache.getDefault(imageType.getName() + "_RENDERING",
163    LineartOptions.PROMPT_EACH_TIME)
164    : renderer;
165  46 if (Platform.isJS())
166    {
167  0 renderStyle = "Text";
168    }
169  46 AtomicBoolean textSelected = new AtomicBoolean(
170    !StringUtils.equalsIgnoreCase("lineart", renderStyle));
171  46 if ((imageType == TYPE.EPS || imageType == TYPE.SVG) && StringUtils
172    .equalsIgnoreCase(LineartOptions.PROMPT_EACH_TIME, renderStyle)
173    && !Jalview.isHeadlessMode())
174    {
175  0 final File chosenFile = file;
176  0 Runnable okAction = () -> {
177  0 exportImage(chosenFile, !textSelected.get(), width, height,
178    messageId, userBis);
179    };
180  0 LineartOptions epsOption = new LineartOptions(TYPE.EPS.getName(),
181    textSelected);
182  0 epsOption.setResponseAction(1, () -> {
183  0 setStatus(MessageManager.formatMessage(
184    "status.cancelled_image_export_operation",
185    imageType.getName()), messageId);
186    });
187  0 epsOption.setResponseAction(0, okAction);
188  0 epsOption.showDialog();
189    /* no code here - JalviewJS cannot execute it */
190    }
191    else
192    {
193    /*
194    * character rendering not required, or preference already set
195    * or we're in headless mode - just do the export
196    */
197  46 exportImage(file, !textSelected.get(), width, height, messageId,
198    userBis);
199    }
200    }
201   
202    /**
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.
206    *
207    * @param chosenFile
208    * @param asLineart
209    * @param width
210    * @param height
211    * @param messageId
212    */
 
213  46 toggle protected void exportImage(File chosenFile, boolean asLineart, int width,
214    int height, long messageId, BitmapImageSizing userBis)
215    {
216  46 String type = imageType.getName();
217  46 try
218    {
219    // setStatus(
220    // MessageManager.formatMessage(
221    // "status.exporting_alignment_as_x_file", type),
222    // messageId);
223  46 ImageMaker im = new ImageMaker(imageType, width, height, chosenFile,
224    title, asLineart, userBis);
225  46 imageWriter.exportImage(im.getGraphics());
226  46 im.writeImage();
227  46 setStatus(
228    MessageManager.formatMessage("status.export_complete", type),
229    messageId);
230    } catch (Exception e)
231    {
232  0 jalview.bin.Console.error(String.format("Error creating %s file: %s",
233    type, e.toString()), e);
234  0 setStatus(MessageManager.formatMessage("info.error_creating_file",
235    type), messageId);
236    }
237    }
238   
239    /**
240    * Asks the callback to show a status message with given id
241    *
242    * @param msg
243    * @param id
244    */
 
245  92 toggle void setStatus(String msg, long id)
246    {
247  92 if (messageBoard != null && !Jalview.isHeadlessMode())
248    {
249  26 messageBoard.setProgressBar(msg, id);
250    }
251    }
252   
253    }