1 /* PrintACT.java 2 * 3 * 4 * Copyright(C) 2004 Genome Research Limited 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or(at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 * 20 */ 21 22 package uk.ac.sanger.artemis.components; 23 24 import java.awt.*; 25 import java.awt.event.ActionEvent; 26 import java.awt.event.ActionListener; 27 import java.awt.event.KeyEvent; 28 import java.awt.image.BufferedImage; 29 import java.awt.image.RenderedImage; 30 import java.awt.print.PageFormat; 31 import java.awt.print.Printable; 32 import java.awt.print.PrinterException; 33 import java.awt.print.PrinterJob; 34 import java.io.File; 35 import java.io.FileNotFoundException; 36 import java.io.FileOutputStream; 37 import java.io.IOException; 38 import java.io.OutputStreamWriter; 39 import java.io.UnsupportedEncodingException; 40 import java.io.Writer; 41 42 import javax.swing.Box; 43 import javax.swing.JCheckBox; 44 import javax.swing.JCheckBoxMenuItem; 45 import javax.swing.JComboBox; 46 import javax.swing.JFileChooser; 47 import javax.swing.JFrame; 48 import javax.swing.JLabel; 49 import javax.swing.JMenu; 50 import javax.swing.JMenuBar; 51 import javax.swing.JMenuItem; 52 import javax.swing.JOptionPane; 53 import javax.swing.JPanel; 54 import javax.swing.JScrollPane; 55 import javax.swing.JSeparator; 56 import javax.swing.KeyStroke; 57 58 import org.apache.batik.dom.GenericDOMImplementation; 59 import org.apache.batik.svggen.SVGGeneratorContext; 60 import org.apache.batik.svggen.SVGGraphics2D; 61 import org.apache.batik.svggen.SVGGraphics2DIOException; 62 import org.w3c.dom.DOMImplementation; 63 import org.w3c.dom.Document; 64 65 import uk.ac.sanger.artemis.Options; 66 import uk.ac.sanger.artemis.editor.ScrollPanel; 67 68 /** 69 * Use to print images from ACT 70 */ 71 public class PrintACT extends ScrollPanel implements Printable 72 { 73 private static final long serialVersionUID = 1L; 74 /** act display to create image from */ 75 private MultiComparator mc; 76 private JCheckBox drawLabels = new JCheckBox("Show labels on alignment"); 77 PrintACT(MultiComparator mc)78 public PrintACT(MultiComparator mc) 79 { 80 this.mc = mc; 81 } 82 83 paintComponent(Graphics g)84 public void paintComponent(Graphics g) 85 { 86 // let UI delegate paint first (incl. background filling) 87 super.paintComponent(g); 88 Graphics2D g2d = (Graphics2D)g.create(); 89 90 for(int i = 0; i < mc.getFeatureDisplayArray().length; ++i) 91 { 92 if(!(i == mc.getEntryGroupArray().length - 1 && 93 mc.getEntryGroupArray().length == 2)) 94 { 95 Component c[] = mc.getBasePlotGroupArray()[i].getComponents(); 96 for(int j=0; j<c.length; j++) 97 { 98 if(c[j] instanceof BasePlot && c[j].isVisible()) 99 { 100 ((BasePlot)c[j]).paintComponent(g2d); 101 g2d.translate(0,((BasePlot)c[j]).getHeight()); 102 } 103 } 104 105 if(mc.getBamPanelArray()[i].isVisible()) 106 { 107 mc.getBamPanelArray()[i].paintComponents(g2d); 108 g2d.translate(0,mc.getBamPanelArray()[i].getHeight()); 109 } 110 111 if(mc.getVcfPanelArray()[i].isVisible()) 112 { 113 mc.getVcfPanelArray()[i].paintComponents(g2d); 114 g2d.translate(0,mc.getVcfPanelArray()[i].getHeight()); 115 } 116 } 117 118 mc.getFeatureDisplayArray()[i].paintComponent(g2d); 119 g2d.translate(0,mc.getFeatureDisplayArray()[i].getHeight()); 120 121 if(i == mc.getEntryGroupArray().length - 1 && 122 mc.getEntryGroupArray().length == 2) 123 { 124 Component c[] = mc.getBasePlotGroupArray()[i].getComponents(); 125 for(int j=0; j<c.length; j++) 126 { 127 if(c[j] instanceof BasePlot && c[j].isVisible()) 128 { 129 ((BasePlot)c[j]).paintComponent(g2d); 130 g2d.translate(0,((BasePlot)c[j]).getHeight()); 131 } 132 } 133 134 if(mc.getBamPanelArray()[i].isVisible()) 135 { 136 mc.getBamPanelArray()[i].paintComponents(g2d); 137 g2d.translate(0,mc.getBamPanelArray()[i].getHeight()); 138 } 139 140 if(mc.getVcfPanelArray()[i].isVisible()) 141 { 142 mc.getVcfPanelArray()[i].paintComponents(g2d); 143 g2d.translate(0,mc.getVcfPanelArray()[i].getHeight()); 144 } 145 } 146 147 if(i < mc.getAlignmentViewerArray().length) 148 { 149 mc.getAlignmentViewerArray()[i].paintComponentForPrint(g2d,drawLabels.isSelected()); 150 g2d.translate(0,mc.getAlignmentViewerArray()[i].getHeight()); 151 } 152 } 153 154 } 155 156 /** 157 * 158 * Display a print preview page 159 * 160 */ printPreview()161 protected void printPreview() 162 { 163 int width = 999999; 164 int height = 0; 165 for(int i = 0; i < mc.getFeatureDisplayArray().length; ++i) 166 { 167 if(!(i == mc.getEntryGroupArray().length - 1 && 168 mc.getEntryGroupArray().length == 2)) 169 { 170 Component c[] = mc.getBasePlotGroupArray()[i].getComponents(); 171 for(int j=0; j<c.length; j++) 172 if(c[j] instanceof BasePlot && c[j].isVisible()) 173 { 174 height += ((BasePlot)c[j]).getHeight(); 175 if(((BasePlot)c[j]).getSize().width < width && 176 ((BasePlot)c[j]).getSize().width > 0) 177 width = ((BasePlot)c[j]).getSize().width; 178 } 179 } 180 181 if(mc.getBamPanelArray()[i].isVisible()) 182 height += mc.getBamPanelArray()[i].getHeight(); 183 184 if(mc.getVcfPanelArray()[i].isVisible()) 185 height += mc.getVcfPanelArray()[i].getHeight(); 186 187 height += mc.getFeatureDisplayArray()[i].getHeight(); 188 if(mc.getFeatureDisplayArray()[i].getWidth() < width) 189 width = mc.getFeatureDisplayArray()[i].getWidth(); 190 191 if(i == mc.getEntryGroupArray().length - 1 && 192 mc.getEntryGroupArray().length == 2) 193 { 194 Component c[] = mc.getBasePlotGroupArray()[i].getComponents(); 195 for(int j=0; j<c.length; j++) 196 if(c[j] instanceof BasePlot && c[j].isVisible()) 197 { 198 height += ((BasePlot)c[j]).getHeight(); 199 if(((BasePlot)c[j]).getSize().width < width && 200 ((BasePlot)c[j]).getSize().width > 0) 201 width = ((BasePlot)c[j]).getSize().width; 202 } 203 } 204 205 if(i < mc.getAlignmentViewerArray().length) 206 { 207 height += mc.getAlignmentViewerArray()[i].getHeight(); 208 if(mc.getAlignmentViewerArray()[i].getWidth() < width) 209 width = mc.getAlignmentViewerArray()[i].getWidth(); 210 } 211 } 212 213 final JFrame f = new JFrame("Print Preview"); 214 JPanel jpane = (JPanel)f.getContentPane(); 215 JScrollPane scrollPane = new JScrollPane(this); 216 jpane.setLayout(new BorderLayout()); 217 jpane.add(scrollPane,BorderLayout.CENTER); 218 219 final Dimension dScreen = f.getToolkit().getScreenSize(); 220 Dimension d = new Dimension((int)(dScreen.getWidth()*3/4), 221 (int)(dScreen.getHeight()/2)); 222 f.setSize(d); 223 224 setPreferredSize(new Dimension(width,height)); 225 226 JMenuBar menuBar = new JMenuBar(); 227 JMenu filemenu = new JMenu("File"); 228 menuBar.add(filemenu); 229 230 // print png/jpeg 231 JMenuItem printImage = new JMenuItem("Save As Image Files (png/jpeg)..."); 232 printImage.addActionListener(new ActionListener() 233 { 234 public void actionPerformed(ActionEvent e) 235 { 236 print(); 237 } 238 }); 239 filemenu.add(printImage); 240 241 // print PostScript 242 JMenuItem printPS = new JMenuItem("Print..."); 243 printPS.addActionListener(new ActionListener() 244 { 245 public void actionPerformed(ActionEvent e) 246 { 247 doPrintActions(); 248 } 249 }); 250 filemenu.add(printPS); 251 252 // close 253 filemenu.add(new JSeparator()); 254 JMenuItem menuClose = new JMenuItem("Close"); 255 menuClose.setAccelerator(KeyStroke.getKeyStroke( 256 KeyEvent.VK_E, ActionEvent.CTRL_MASK)); 257 258 filemenu.add(menuClose); 259 menuClose.addActionListener(new ActionListener() 260 { 261 public void actionPerformed(ActionEvent e) 262 { 263 f.dispose(); 264 } 265 }); 266 267 JMenu optionsmenu = new JMenu("Options"); 268 menuBar.add(optionsmenu); 269 270 // draw labels 271 JCheckBoxMenuItem showLabels = new JCheckBoxMenuItem("Display Labels", 272 drawLabels.isSelected()); 273 showLabels.addActionListener(new ActionListener() 274 { 275 public void actionPerformed(ActionEvent e) 276 { 277 drawLabels.setSelected(!drawLabels.isSelected()); 278 repaint(); 279 } 280 }); 281 optionsmenu.add(showLabels); 282 283 f.setJMenuBar(menuBar); 284 f.setVisible(true); 285 } 286 287 /** 288 * Print to a jpeg or png file 289 */ print()290 public void print() 291 { 292 // file chooser 293 final StickyFileChooser fc = new StickyFileChooser(); 294 File fselect = new File(fc.getCurrentDirectory()+ 295 System.getProperty("file.separator")+ 296 "act.png"); 297 fc.setSelectedFile(fselect); 298 299 // file name prefix 300 Box YBox = Box.createVerticalBox(); 301 JLabel labFormat = new JLabel("Select Format:"); 302 Font font = labFormat.getFont(); 303 labFormat.setFont(font.deriveFont(Font.BOLD)); 304 YBox.add(labFormat); 305 306 Box bacross = Box.createHorizontalBox(); 307 final JComboBox formatSelect = new JComboBox(PrintArtemis.getImageFormats()); 308 formatSelect.setSelectedItem("png"); 309 formatSelect.addActionListener(new ActionListener() 310 { 311 public void actionPerformed(ActionEvent arg0) 312 { 313 String selected; 314 if(fc.getSelectedFile() != null) 315 { 316 selected = fc.getSelectedFile().getAbsolutePath(); 317 String fmts[] = PrintArtemis.getImageFormats(); 318 for(int i=0; i<fmts.length; i++) 319 selected = selected.replaceAll("."+fmts[i]+"$", ""); 320 } 321 else 322 selected = "act"; 323 324 fc.setSelectedFile(new File(selected+"."+ 325 formatSelect.getSelectedItem())); 326 } 327 }); 328 formatSelect.setSelectedItem("png"); 329 330 Dimension d = formatSelect.getPreferredSize(); 331 formatSelect.setMaximumSize(d); 332 bacross.add(Box.createHorizontalGlue()); 333 bacross.add(formatSelect); 334 YBox.add(bacross); 335 336 bacross = Box.createHorizontalBox(); 337 bacross.add(Box.createHorizontalGlue()); 338 bacross.add(drawLabels); 339 YBox.add(bacross); 340 341 // file prefix & format options 342 fc.setAccessory(YBox); 343 int n = fc.showSaveDialog(null); 344 if(n == JFileChooser.CANCEL_OPTION) 345 return; 346 347 // remove file extension 348 String fsave = fc.getSelectedFile().getAbsolutePath().toLowerCase(); 349 if(fsave.endsWith(".svg")) 350 { 351 createSVG(fc.getSelectedFile()); 352 return; 353 } 354 355 if(fsave.endsWith(".png") || 356 fsave.endsWith(".jpg") || 357 fsave.endsWith(".jpeg") ) 358 { 359 int ind = fsave.lastIndexOf("."); 360 fsave = fc.getSelectedFile().getAbsolutePath(); 361 fsave = fsave.substring(0,ind); 362 } 363 else 364 fsave = fc.getSelectedFile().getAbsolutePath(); 365 366 // image type 367 String ftype = (String)formatSelect.getSelectedItem(); 368 try 369 { 370 RenderedImage rendImage = createImage(); 371 writeImageToFile(rendImage, new File(fsave+"."+ftype), 372 ftype); 373 } 374 catch(NoClassDefFoundError ex) 375 { 376 JOptionPane.showMessageDialog(this, 377 "This option requires Java 1.8 or higher."); 378 } 379 } 380 createSVG(final File fout)381 private void createSVG(final File fout) 382 { 383 final DOMImplementation domImpl = 384 GenericDOMImplementation.getDOMImplementation(); 385 final Document doc = domImpl.createDocument( 386 "http://www.w3.org/2000/svg", "svg", null); 387 388 SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(doc); 389 ctx.setComment("Generated by ACT with Batik SVG Generator"); 390 final SVGGraphics2D svgG = new SVGGraphics2D(ctx, true); 391 svgG.setFont(Options.getOptions().getFont()); 392 svgG.setSVGCanvasSize( getImageSize() ); 393 paintComponent(svgG); 394 395 try 396 { 397 final Writer out = new OutputStreamWriter( 398 new FileOutputStream(fout), "UTF-8"); 399 svgG.stream(out, true); 400 } 401 catch (UnsupportedEncodingException e) 402 { 403 e.printStackTrace(); 404 } 405 catch (SVGGraphics2DIOException e) 406 { 407 e.printStackTrace(); 408 } 409 catch (FileNotFoundException e) 410 { 411 e.printStackTrace(); 412 } 413 414 return; 415 } 416 417 /** 418 * Returns a generated image 419 * @param pageIndex page number 420 * @return image 421 */ createImage()422 private RenderedImage createImage() 423 { 424 Dimension d = getImageSize(); 425 426 // Create a buffered image in which to draw 427 BufferedImage bufferedImage = new BufferedImage( 428 d.width,d.height, 429 BufferedImage.TYPE_INT_RGB); 430 // Create a graphics contents on the buffered image 431 Graphics2D g2d = bufferedImage.createGraphics(); 432 paintComponent(g2d); 433 434 return bufferedImage; 435 } 436 437 /** 438 * Get the size of the image 439 * @return 440 */ getImageSize()441 private Dimension getImageSize() 442 { 443 int width = 999999; 444 int height = 0; 445 for(int i = 0; i < mc.getFeatureDisplayArray().length; ++i) 446 { 447 if(!(i == mc.getEntryGroupArray().length - 1 && 448 mc.getEntryGroupArray().length == 2)) 449 { 450 Component c[] = mc.getBasePlotGroupArray()[i].getComponents(); 451 for(int j=0; j<c.length; j++) 452 if(c[j] instanceof BasePlot) 453 { 454 height += ((BasePlot)c[j]).getHeight(); 455 if(((BasePlot)c[j]).getSize().width < width && 456 ((BasePlot)c[j]).getSize().width > 0) 457 width = ((BasePlot)c[j]).getSize().width; 458 } 459 } 460 461 if(mc.getBamPanelArray()[i].isVisible()) 462 height += mc.getBamPanelArray()[i].getHeight(); 463 464 if(mc.getVcfPanelArray()[i].isVisible()) 465 height += mc.getVcfPanelArray()[i].getHeight(); 466 467 height += mc.getFeatureDisplayArray()[i].getHeight(); 468 if(mc.getFeatureDisplayArray()[i].getWidth() < width) 469 width = mc.getFeatureDisplayArray()[i].getWidth(); 470 471 if(i == mc.getEntryGroupArray().length - 1 && 472 mc.getEntryGroupArray().length == 2) 473 { 474 Component c[] = mc.getBasePlotGroupArray()[i].getComponents(); 475 for(int j=0; j<c.length; j++) 476 if(c[j] instanceof BasePlot) 477 { 478 height += ((BasePlot)c[j]).getHeight(); 479 if(((BasePlot)c[j]).getSize().width < width && 480 ((BasePlot)c[j]).getSize().width > 0) 481 width = ((BasePlot)c[j]).getSize().width; 482 } 483 } 484 485 if(i < mc.getAlignmentViewerArray().length) 486 { 487 height += mc.getAlignmentViewerArray()[i].getHeight(); 488 if(mc.getAlignmentViewerArray()[i].getWidth() < width) 489 width = mc.getAlignmentViewerArray()[i].getWidth(); 490 } 491 } 492 return new Dimension(width, height); 493 } 494 495 /** 496 * 497 * Write out the image 498 * @param image image 499 * @param file file to write image to 500 * @param type type of image 501 * 502 */ writeImageToFile(RenderedImage image, File file, String type)503 private void writeImageToFile(RenderedImage image, 504 File file, String type) 505 { 506 try 507 { 508 javax.imageio.ImageIO.write(image,type,file); 509 } 510 catch ( IOException e ) 511 { 512 System.out.println("Java 1.8+ is required"); 513 e.printStackTrace(); 514 } 515 } 516 doPrintActions()517 protected void doPrintActions() 518 { 519 final PrinterJob pj=PrinterJob.getPrinterJob(); 520 pj.setPrintable(PrintACT.this); 521 pj.printDialog(); 522 try 523 { 524 pj.print(); 525 } 526 catch (Exception PrintException) {} 527 } 528 529 /** 530 * 531 * The method @print@ must be implemented for @Printable@ interface. 532 * Parameters are supplied by system. 533 * 534 */ print(Graphics g, PageFormat pf, int pageIndex)535 public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException 536 { 537 Graphics2D g2 = (Graphics2D) g; 538 539 // RepaintManager.currentManager(this).setDoubleBufferingEnabled(false); 540 Dimension d = getImageSize(); //get size of document 541 double panelWidth = d.width; //width in pixels 542 double panelHeight = d.height; //height in pixels 543 544 double pageHeight = pf.getImageableHeight(); //height of printer page 545 double pageWidth = pf.getImageableWidth(); //width of printer page 546 double scale = pageWidth/panelWidth; 547 int totalNumPages = (int)Math.ceil(scale * panelHeight / pageHeight); 548 // Make sure not print empty pages 549 if(pageIndex >= totalNumPages) 550 return Printable.NO_SUCH_PAGE; 551 552 // Shift Graphic to line up with beginning of print-imageable region 553 g2.translate(pf.getImageableX(), pf.getImageableY()); 554 // Shift Graphic to line up with beginning of next page to print 555 g2.translate(0f, -pageIndex*pageHeight); 556 // Scale the page so the width fits... 557 g2.scale(scale, scale); 558 paintComponent(g2); 559 return Printable.PAGE_EXISTS; 560 } 561 562 } 563