1 /*
2  * Copyright (C) 2008  Genome Research Limited
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  *
18  *  @author: Tim Carver
19  */
20 
21 package uk.ac.sanger.artemis.circular;
22 
23 import java.awt.BorderLayout;
24 import java.awt.Color;
25 import java.awt.Dimension;
26 import java.awt.Font;
27 import java.awt.Graphics;
28 import java.awt.Graphics2D;
29 import java.awt.print.PageFormat;
30 import java.awt.print.Paper;
31 import java.awt.print.PrinterJob;
32 import java.awt.event.ActionEvent;
33 import java.awt.event.ActionListener;
34 import java.awt.event.KeyEvent;
35 import java.awt.image.BufferedImage;
36 import java.awt.image.RenderedImage;
37 import java.io.File;
38 import java.io.FileNotFoundException;
39 import java.io.FileOutputStream;
40 import java.io.IOException;
41 import java.io.OutputStreamWriter;
42 import java.io.UnsupportedEncodingException;
43 import java.io.Writer;
44 
45 import javax.swing.BorderFactory;
46 import javax.swing.Box;
47 import javax.swing.JComboBox;
48 import javax.swing.JFileChooser;
49 import javax.swing.JFrame;
50 import javax.swing.JLabel;
51 import javax.swing.JMenu;
52 import javax.swing.JMenuBar;
53 import javax.swing.JMenuItem;
54 import javax.swing.JOptionPane;
55 import javax.swing.JPanel;
56 import javax.swing.JScrollPane;
57 import javax.swing.JSeparator;
58 import javax.swing.JTextField;
59 import javax.swing.KeyStroke;
60 import javax.swing.border.Border;
61 
62 import org.apache.batik.dom.GenericDOMImplementation;
63 import org.apache.batik.svggen.SVGGeneratorContext;
64 import org.apache.batik.svggen.SVGGraphics2D;
65 import org.apache.batik.svggen.SVGGraphics2DIOException;
66 import org.w3c.dom.DOMImplementation;
67 import org.w3c.dom.Document;
68 
69 import uk.ac.sanger.artemis.Options;
70 import uk.ac.sanger.artemis.components.PrintArtemis;
71 import uk.ac.sanger.artemis.components.StickyFileChooser;
72 
73 
74 
75 
76 /**
77 *
78 * Print png/jpeg image and print preview.
79 * The imageio package is used here to create jpeg and png images of the
80 * DNA diagram.
81 *
82 */
83 public class PrintDNAImage extends ScrollPanel
84 {
85   private static final long serialVersionUID = 1L;
86 
87   /** page format */
88   private PageFormat format = null;
89 
90   /** alignment sequence panel */
91   private DNADraw dna;
92   /** status field for print preview */
93   private JTextField statusField = new JTextField("");
94   /** type (jpeg/png) */
95   private String type;
96 
97   /**
98   *
99   * @param dna   dna panel
100   *
101   */
PrintDNAImage(DNADraw dna)102   public PrintDNAImage(DNADraw dna)
103   {
104     super();
105     this.dna = dna;
106 
107     setBackground(Color.white);
108   }
109 
110 
111   /**
112   *
113   * Override this method to draw the sequences
114   * @return Graphics g
115   *
116   */
paintComponent(Graphics g)117   public void paintComponent(Graphics g)
118   {
119 // let UI delegate paint first (incl. background filling)
120     super.paintComponent(g);
121     Graphics2D g2d = (Graphics2D) g.create();
122     dna.drawAll(g2d,true);
123   }
124 
125   /**
126   *
127   * Get a default page format
128   * @return     page format
129   *
130   */
getFormatDialog()131   protected PageFormat getFormatDialog()
132   {
133     PrinterJob printerJob = PrinterJob.getPrinterJob();
134     format = new PageFormat();
135     format = printerJob.pageDialog(format);
136     return format;
137   }
138 
139 
140   /**
141   *
142   *  Returns a generated image
143   *  @param pageIndex   page number
144   *  @return            image
145   *
146   */
createDNAImage(int pageIndex)147   private RenderedImage createDNAImage(int pageIndex)
148   {
149     int width  = (int)format.getWidth();
150     int height = (int)format.getHeight();
151     // Create a buffered image in which to draw
152     BufferedImage bufferedImage = new BufferedImage(
153                                   width,height,
154                                   BufferedImage.TYPE_INT_RGB);
155 
156     // Create a graphics contents on the buffered image
157     Graphics2D g2d = bufferedImage.createGraphics();
158     g2d.setColor(Color.white);
159     g2d.fillRect(0,0,width,height);
160     // Draw graphics
161     dna.drawAll(g2d,true);
162 
163     return bufferedImage;
164   }
165 
166 
167   /**
168   *
169   * Display a print preview page
170   *
171   */
printPreview()172   protected void printPreview()
173   {
174     Border loweredbevel = BorderFactory.createLoweredBevelBorder();
175     Border raisedbevel = BorderFactory.createRaisedBevelBorder();
176     Border compound = BorderFactory.createCompoundBorder(raisedbevel,loweredbevel);
177     statusField.setBorder(compound);
178     statusField.setEditable(false);
179 
180     if(format == null)
181       format = getFormatDialog();
182 
183     statusField.setText("DNA map");
184     final JFrame f = new JFrame("Print Preview");
185     JPanel jpane = (JPanel)f.getContentPane();
186     JScrollPane scrollPane = new JScrollPane(this);
187     jpane.setLayout(new BorderLayout());
188     jpane.add(scrollPane,BorderLayout.CENTER);
189     jpane.add(statusField,BorderLayout.SOUTH);
190 
191     Dimension d = new Dimension((int)format.getWidth(),
192                                 (int)format.getHeight());
193     setPreferredSize(d);
194     f.setSize(d);
195 
196     JMenuBar menuBar = new JMenuBar();
197     JMenu filemenu = new JMenu("File");
198     menuBar.add(filemenu);
199 
200 // print postscript
201     JMenu printMenu = new JMenu("Print");
202     filemenu.add(printMenu);
203 
204     JMenuItem print = new JMenuItem("Print Postscript...");
205     print.addActionListener(new ActionListener()
206     {
207       public void actionPerformed(ActionEvent e)
208       {
209         dna.doPrintActions();
210       }
211     });
212     printMenu.add(print);
213 
214 // print png/jpeg
215     JMenuItem printImage = new JMenuItem("Print png/jpeg Image...");
216     printImage.addActionListener(new ActionListener()
217     {
218       public void actionPerformed(ActionEvent e)
219       {
220         printAsSinglePage();
221       }
222     });
223     printMenu.add(printImage);
224 
225 // close
226     filemenu.add(new JSeparator());
227     JMenuItem menuClose = new JMenuItem("Close");
228     menuClose.setAccelerator(KeyStroke.getKeyStroke(
229               KeyEvent.VK_E, ActionEvent.CTRL_MASK));
230 
231     filemenu.add(menuClose);
232     menuClose.addActionListener(new ActionListener()
233     {
234       public void actionPerformed(ActionEvent e)
235       {
236         f.dispose();
237       }
238     });
239 
240     f.setJMenuBar(menuBar);
241     f.setVisible(true);
242   }
243 
244   /**
245   * Provide some options for the image created
246   */
showOptions()247   private File showOptions()
248   {
249     final StickyFileChooser fc = new StickyFileChooser();
250     File fselect = new File(fc.getCurrentDirectory()+
251         System.getProperty("file.separator")+
252         "dnaplotter.png");
253     fc.setSelectedFile(fselect);
254 
255 // file name prefix
256     Box bdown = Box.createVerticalBox();
257     bdown.add(Box.createVerticalGlue());
258 
259     JLabel labFormat = new JLabel("Select Format:");
260     Font font = labFormat.getFont();
261     labFormat.setFont(font.deriveFont(Font.BOLD));
262 
263     bdown.add(labFormat);
264 
265     Box bacross = Box.createHorizontalBox();
266     final JComboBox formatSelect = new JComboBox(PrintArtemis.getImageFormats());
267     formatSelect.setSelectedItem("png");
268     formatSelect.addActionListener(new ActionListener()
269     {
270       public void actionPerformed(ActionEvent arg0)
271       {
272         String selected;
273         if(fc.getSelectedFile() != null)
274         {
275           selected = fc.getSelectedFile().getAbsolutePath();
276           String fmts[] = PrintArtemis.getImageFormats();
277           for(int i=0; i<fmts.length; i++)
278             selected = selected.replaceAll("."+fmts[i]+"$", "");
279         }
280         else
281           selected = "dnaplotter";
282 
283         fc.setSelectedFile(new File(selected+"."+
284                formatSelect.getSelectedItem()));
285       }
286     });
287 
288     Dimension d = formatSelect.getPreferredSize();
289     formatSelect.setMaximumSize(d);
290     bacross.add(Box.createHorizontalGlue());
291     bacross.add(formatSelect);
292     bdown.add(bacross);
293 
294 // file prefix & format options
295     fc.setAccessory(bdown);
296     int n = fc.showSaveDialog(null);
297     if(n == JFileChooser.CANCEL_OPTION)
298       return null;
299 
300     type = (String)formatSelect.getSelectedItem();
301     return fc.getSelectedFile();
302   }
303 
304 
305   /**
306   *
307   * Write out the image
308   * @param image        image
309   * @param file         file to write image to
310   * @param type         type of image
311   *
312   */
writeImageToFile(RenderedImage image, File file, String type)313   private void writeImageToFile(RenderedImage image,
314                                File file, String type)
315   {
316     try
317     {
318       javax.imageio.ImageIO.write(image,type,file);
319     }
320     catch (IOException e)
321     {
322       System.out.println("Java 1.8+ is required");
323     }
324   }
325 
326   /**
327   * Print to one jpeg or png file
328   */
printAsSinglePage()329   public void printAsSinglePage()
330   {
331     //PrinterJob printerJob = PrinterJob.getPrinterJob();
332     format = new PageFormat();
333 
334     File file = showOptions();
335     if(file == null)
336       return;
337 
338     Dimension d = dna.getSize();
339     double imageWidth  = d.getWidth();
340     double imageHeight = d.getHeight();
341 
342     if(type.equals("svg"))
343     {
344       createSVG(file, d);
345       return;
346     }
347 
348     Paper paper  = format.getPaper();
349     paper.setSize(imageWidth,imageHeight);
350     paper.setImageableArea(0,0,
351                            imageWidth,imageHeight+imageHeight);
352     format.setPaper(paper);
353 
354     try
355     {
356       RenderedImage rendImage = createDNAImage(0);
357       writeImageToFile(rendImage,file,type);
358     }
359     catch(NoClassDefFoundError ex)
360     {
361       JOptionPane.showMessageDialog(this,
362             "This option requires Java 1.8 or higher.");
363     }
364   }
365 
createSVG(final File fout, Dimension d)366   private void createSVG(final File fout, Dimension d)
367   {
368     final DOMImplementation domImpl =
369         GenericDOMImplementation.getDOMImplementation();
370     final Document doc = domImpl.createDocument(
371         "http://www.w3.org/2000/svg", "svg", null);
372 
373     SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(doc);
374     ctx.setComment("Generated by DNAPlotter with Batik SVG Generator");
375     final SVGGraphics2D svgG = new SVGGraphics2D(ctx, true);
376     svgG.setFont(Options.getOptions().getFont());
377     svgG.setSVGCanvasSize(d);
378     paintComponent(svgG);
379 
380     try
381     {
382       final Writer out = new OutputStreamWriter(
383           new FileOutputStream(fout), "UTF-8");
384       svgG.stream(out, true);
385     }
386     catch (UnsupportedEncodingException e)
387     {
388       e.printStackTrace();
389     }
390     catch (SVGGraphics2DIOException e)
391     {
392       e.printStackTrace();
393     }
394     catch (FileNotFoundException e)
395     {
396       e.printStackTrace();
397     }
398 
399     return;
400   }
401 
402 }
403 
404 
405