Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
ImageMaker | 41 | 94 | 42 | ||
ImageMaker.TYPE | 65 | 7 | 4 |
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.util; | |
22 | ||
23 | import java.awt.Graphics; | |
24 | import java.awt.Graphics2D; | |
25 | import java.awt.RenderingHints; | |
26 | import java.awt.image.BufferedImage; | |
27 | import java.io.File; | |
28 | import java.io.FileOutputStream; | |
29 | import java.io.IOException; | |
30 | ||
31 | import javax.imageio.ImageIO; | |
32 | ||
33 | import org.jfree.graphics2d.svg.SVGGraphics2D; | |
34 | import org.jfree.graphics2d.svg.SVGHints; | |
35 | import org.jibble.epsgraphics.EpsGraphics2D; | |
36 | ||
37 | import jalview.bin.Console; | |
38 | import jalview.io.JalviewFileChooser; | |
39 | import jalview.util.imagemaker.BitmapImageSizing; | |
40 | ||
41 | public class ImageMaker | |
42 | { | |
43 | public static final String SVG_DESCRIPTION = "Scalable Vector Graphics"; | |
44 | ||
45 | public static final String SVG_EXTENSION = "svg"; | |
46 | ||
47 | public static final String EPS_DESCRIPTION = "Encapsulated Postscript"; | |
48 | ||
49 | public static final String EPS_EXTENSION = "eps"; | |
50 | ||
51 | public static final String PNG_EXTENSION = "png"; | |
52 | ||
53 | public static final String PNG_DESCRIPTION = "Portable network graphics"; | |
54 | ||
55 | EpsGraphics2D pg; | |
56 | ||
57 | Graphics graphics; | |
58 | ||
59 | FileOutputStream out; | |
60 | ||
61 | BufferedImage bi; | |
62 | ||
63 | TYPE type; | |
64 | ||
65 | public enum TYPE | |
66 | { | |
67 | EPS("EPS", MessageManager.getString("label.eps_file"), EPS_EXTENSION, | |
68 | EPS_DESCRIPTION), | |
69 | PNG("PNG", MessageManager.getString("label.png_image"), PNG_EXTENSION, | |
70 | PNG_DESCRIPTION), | |
71 | SVG("SVG", "SVG", SVG_EXTENSION, SVG_DESCRIPTION); | |
72 | ||
73 | public final String name; | |
74 | ||
75 | public final String label; | |
76 | ||
77 | public final String extension; | |
78 | ||
79 | public final String description; | |
80 | ||
81 | 54 | TYPE(String name, String label, String ext, String desc) |
82 | { | |
83 | 54 | this.name = name; |
84 | 54 | this.label = label; |
85 | 54 | this.extension = ext; |
86 | 54 | this.description = desc; |
87 | } | |
88 | ||
89 | 86 | public String getName() |
90 | { | |
91 | 86 | return name; |
92 | } | |
93 | ||
94 | 0 | public JalviewFileChooser getFileChooser() |
95 | { | |
96 | 0 | return new JalviewFileChooser(extension, description); |
97 | } | |
98 | ||
99 | 0 | public String getLabel() |
100 | { | |
101 | 0 | return label; |
102 | } | |
103 | ||
104 | } | |
105 | ||
106 | /** | |
107 | * Constructor configures the graphics context ready for writing to | |
108 | * | |
109 | * @param imageType | |
110 | * @param width | |
111 | * @param height | |
112 | * @param file | |
113 | * @param fileTitle | |
114 | * @param useLineart | |
115 | * @param bitmapscale | |
116 | * @throws IOException | |
117 | */ | |
118 | 46 | public ImageMaker(TYPE imageType, int width, int height, File file, |
119 | String fileTitle, boolean useLineart, BitmapImageSizing userBis) | |
120 | throws IOException | |
121 | { | |
122 | 46 | this.type = imageType; |
123 | ||
124 | 46 | out = new FileOutputStream(file); |
125 | 46 | switch (imageType) |
126 | { | |
127 | 2 | case SVG: |
128 | 2 | setupSVG(width, height, useLineart); |
129 | 2 | break; |
130 | 10 | case EPS: |
131 | 10 | setupEPS(width, height, fileTitle, useLineart); |
132 | 10 | break; |
133 | 34 | case PNG: |
134 | 34 | setupPNG(width, height, userBis); |
135 | 34 | break; |
136 | 0 | default: |
137 | } | |
138 | } | |
139 | ||
140 | 48 | public Graphics getGraphics() |
141 | { | |
142 | 48 | return graphics; |
143 | } | |
144 | ||
145 | /** | |
146 | * For SVG or PNG, writes the generated graphics data to the file output | |
147 | * stream. For EPS, flushes the output graphics (which is written to file as | |
148 | * it is generated). | |
149 | */ | |
150 | 46 | public void writeImage() |
151 | { | |
152 | 46 | try |
153 | { | |
154 | 46 | switch (type) |
155 | { | |
156 | 10 | case EPS: |
157 | 10 | pg.flush(); |
158 | 10 | pg.close(); |
159 | 10 | break; |
160 | 2 | case SVG: |
161 | 2 | String svgData = ((SVGGraphics2D) getGraphics()).getSVGDocument(); |
162 | 2 | out.write(svgData.getBytes()); |
163 | 2 | out.flush(); |
164 | 2 | out.close(); |
165 | 2 | break; |
166 | 34 | case PNG: |
167 | 34 | ImageIO.write(bi, PNG_EXTENSION, out); |
168 | 34 | out.flush(); |
169 | 34 | out.close(); |
170 | 34 | break; |
171 | } | |
172 | } catch (Exception ex) | |
173 | { | |
174 | 0 | ex.printStackTrace(); |
175 | } | |
176 | } | |
177 | ||
178 | /** | |
179 | * Sets up a graphics object for the PNG image to be written on | |
180 | * | |
181 | * @param width | |
182 | * @param height | |
183 | * @param scale | |
184 | */ | |
185 | 34 | protected void setupPNG(int width, int height, BitmapImageSizing userBis) |
186 | { | |
187 | 34 | if (width == 0 || height == 0) |
188 | 0 | return; |
189 | ||
190 | 34 | BitmapImageSizing bis = ImageMaker.getScaleWidthHeight(width, height, |
191 | userBis); | |
192 | 34 | float usescale = bis.scale(); |
193 | 34 | int usewidth = bis.width(); |
194 | 34 | int useheight = bis.height(); |
195 | ||
196 | 34 | bi = new BufferedImage(usewidth, useheight, BufferedImage.TYPE_INT_RGB); |
197 | 34 | graphics = bi.getGraphics(); |
198 | 34 | Graphics2D ig2 = (Graphics2D) graphics; |
199 | 34 | ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, |
200 | RenderingHints.VALUE_ANTIALIAS_ON); | |
201 | 34 | if (usescale > 0.0f) |
202 | { | |
203 | 4 | ig2.scale(usescale, usescale); |
204 | } | |
205 | } | |
206 | ||
207 | /** | |
208 | * A helper method to configure the SVG output graphics, with choice of Text | |
209 | * or Lineart character rendering | |
210 | * | |
211 | * @param width | |
212 | * @param height | |
213 | * @param useLineart | |
214 | * true for Lineart character rendering, false for Text | |
215 | */ | |
216 | 2 | protected void setupSVG(int width, int height, boolean useLineart) |
217 | { | |
218 | 2 | SVGGraphics2D g2 = new SVGGraphics2D(width, height); |
219 | 2 | if (useLineart) |
220 | { | |
221 | 0 | g2.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE, |
222 | SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR); | |
223 | } | |
224 | 2 | graphics = g2; |
225 | } | |
226 | ||
227 | /** | |
228 | * A helper method that sets up the EPS graphics output with user choice of | |
229 | * Text or Lineart character rendering | |
230 | * | |
231 | * @param width | |
232 | * @param height | |
233 | * @param title | |
234 | * @param useLineart | |
235 | * true for Lineart character rendering, false for Text | |
236 | * @throws IOException | |
237 | */ | |
238 | 10 | protected void setupEPS(int width, int height, String title, |
239 | boolean useLineart) throws IOException | |
240 | { | |
241 | 10 | pg = new EpsGraphics2D(title, out, 0, 0, width, height); |
242 | 10 | Graphics2D ig2 = pg; |
243 | 10 | ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, |
244 | RenderingHints.VALUE_ANTIALIAS_ON); | |
245 | 10 | pg.setAccurateTextMode(useLineart); |
246 | 10 | graphics = pg; |
247 | } | |
248 | ||
249 | /** | |
250 | * Takes initial width and height, and suggested float scale, int width, int | |
251 | * height and create a bounding box returned as a BitmapImageSizing object | |
252 | * with consistent scale, width, height fields. | |
253 | * | |
254 | * @param width | |
255 | * The unscaled image width | |
256 | * @param height | |
257 | * The unscaled image height | |
258 | * @param scale | |
259 | * The suggested scaling | |
260 | * @param bitmapwidth | |
261 | * The suggested width | |
262 | * @param bitmapheight | |
263 | * The suggested height | |
264 | * @return BitmapImageSizing A consistent scale,width and height for the final | |
265 | * image | |
266 | */ | |
267 | 44 | public static BitmapImageSizing getScaleWidthHeight(int width, int height, |
268 | float scale, int bitmapwidth, int bitmapheight) | |
269 | { | |
270 | 44 | float usescale = 0.0f; |
271 | 44 | int usewidth = width; |
272 | 44 | int useheight = height; |
273 | ||
274 | 44 | if ((width == 0 && bitmapwidth > 0) |
275 | || (height == 0 && bitmapheight > 0)) | |
276 | { | |
277 | // original image is zero sized! Avoid dividing by zero! | |
278 | 0 | return BitmapImageSizing.nullBitmapImageSizing(); |
279 | } | |
280 | ||
281 | // use the smallest positive scale (i.e. fit in the box) | |
282 | 44 | if (scale > 0.0f) |
283 | { | |
284 | 8 | usescale = scale; |
285 | 8 | usewidth = Math.round(scale * width); |
286 | 8 | useheight = Math.round(scale * height); |
287 | } | |
288 | 44 | if (bitmapwidth > 0) |
289 | { | |
290 | 0 | float wscale = (float) bitmapwidth / width; |
291 | 0 | if (wscale > 0.0f && (usescale == 0.0f || wscale < usescale)) |
292 | { | |
293 | 0 | usescale = wscale; |
294 | 0 | usewidth = bitmapwidth; |
295 | 0 | useheight = Math.round(usescale * height); |
296 | } | |
297 | } | |
298 | 44 | if (bitmapheight > 0) |
299 | { | |
300 | 0 | float hscale = (float) bitmapheight / height; |
301 | 0 | if (hscale > 0.0f && (usescale == 0.0f || hscale < usescale)) |
302 | { | |
303 | 0 | usescale = hscale; |
304 | 0 | usewidth = Math.round(usescale * width); |
305 | 0 | useheight = bitmapheight; |
306 | } | |
307 | } | |
308 | 44 | return new BitmapImageSizing(usescale, usewidth, useheight, false); |
309 | } | |
310 | ||
311 | /** | |
312 | * Takes suggested scale, width, height as a BitmapImageSizing object and | |
313 | * create a bounding box returned as a BitmapImageSizing object with | |
314 | * consistent scale, width, height fields. | |
315 | * | |
316 | * @param bis | |
317 | * @return BitmapImageSizing | |
318 | */ | |
319 | 44 | public static BitmapImageSizing getScaleWidthHeight(int width, int height, |
320 | BitmapImageSizing bis) | |
321 | { | |
322 | 44 | return ImageMaker.getScaleWidthHeight(width, height, bis.scale(), |
323 | bis.width(), bis.height()); | |
324 | } | |
325 | ||
326 | /** | |
327 | * Takes String versions of suggested float scale, int width, int height and | |
328 | * create a bounding box returned as a BitmapImageSizing object with | |
329 | * consistent scale, width, height fields. | |
330 | * | |
331 | * @param scaleS | |
332 | * @param widthS | |
333 | * @param heightS | |
334 | * @return BitmapImageSizing | |
335 | */ | |
336 | 48 | public static BitmapImageSizing parseScaleWidthHeightStrings( |
337 | String scaleS, String widthS, String heightS) | |
338 | { | |
339 | 48 | if (scaleS == null && widthS == null && heightS == null) |
340 | { | |
341 | // if all items are null (i.e. not provided) we use the dynamic | |
342 | // preferences set BIS | |
343 | 38 | return BitmapImageSizing.defaultBitmapImageSizing(); |
344 | } | |
345 | ||
346 | 10 | float scale = 0.0f; |
347 | 10 | int width = 0; |
348 | 10 | int height = 0; |
349 | ||
350 | 10 | if (scaleS != null) |
351 | { | |
352 | 8 | try |
353 | { | |
354 | 8 | scale = Float.parseFloat(scaleS); |
355 | } catch (NumberFormatException e) | |
356 | { | |
357 | 0 | Console.warn("Did not understand scale '" + scaleS |
358 | + "', won't be used."); | |
359 | } | |
360 | } | |
361 | 10 | if (widthS != null) |
362 | { | |
363 | 3 | try |
364 | { | |
365 | 3 | width = Integer.parseInt(widthS); |
366 | } catch (NumberFormatException e) | |
367 | { | |
368 | 0 | Console.warn("Did not understand width '" + widthS |
369 | + "', won't be used."); | |
370 | } | |
371 | } | |
372 | 10 | if (heightS != null) |
373 | { | |
374 | 3 | try |
375 | { | |
376 | 3 | height = Integer.parseInt(heightS); |
377 | } catch (NumberFormatException e) | |
378 | { | |
379 | 0 | Console.warn("Did not understand height '" + heightS |
380 | + "', won't be used."); | |
381 | } | |
382 | } | |
383 | ||
384 | 10 | return new BitmapImageSizing(scale, width, height, false); |
385 | } | |
386 | } |