package jalview.io; import jalview.api.AlignExportSettingI; import jalview.api.FeatureRenderer; import jalview.datamodel.AlignmentExportData; import jalview.datamodel.SequenceI; import jalview.gui.AlignViewport; import jalview.gui.AlignmentPanel; import jalview.gui.HTMLOptions; import jalview.math.AlignmentDimension; import jalview.util.MessageManager; import java.awt.Color; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.io.File; import java.io.FileOutputStream; import org.jfree.graphics2d.svg.SVGGraphics2D; import org.jfree.graphics2d.svg.SVGHints; public class HtmlSvgOutput { AlignViewport av; FeatureRenderer fr; AlignmentPanel ap; public HtmlSvgOutput(File file, AlignmentPanel ap) { this.av = ap.av; this.ap = ap; fr = ap.cloneFeatureRenderer(); generateHtmlSvgOutput(file); } public void generateHtmlSvgOutput(File file) { try { if (file == null) { JalviewFileChooser chooser = getHTMLChooser(); chooser.setFileView(new jalview.io.JalviewFileView()); chooser.setDialogTitle(ap.alignFrame.getTitle()); chooser.setToolTipText(MessageManager.getString("action.save")); int value = chooser.showSaveDialog(ap.alignFrame); if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION) { jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser .getSelectedFile().getParent()); file = chooser.getSelectedFile(); } } AlignmentDimension aDimension = ap.getAlignmentDimension(); SVGGraphics2D g1 = new SVGGraphics2D(aDimension.getWidth(), aDimension.getHeight()); SVGGraphics2D g2 = new SVGGraphics2D(aDimension.getWidth(), aDimension.getHeight()); String renderStyle = jalview.bin.Cache.getDefault("HTML_RENDERING", "Prompt each time"); // If we need to prompt, and if the GUI is visible then // Prompt for rendering style if (renderStyle.equalsIgnoreCase("Prompt each time") && !(System.getProperty("java.awt.headless") != null && System .getProperty("java.awt.headless").equals("true"))) { HTMLOptions svgOption = new HTMLOptions(); renderStyle = svgOption.getValue(); if (renderStyle == null || svgOption.cancelled) { return; } } if (renderStyle.equalsIgnoreCase("lineart")) { g1.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE, SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR); g2.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE, SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR); } printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0, g1, g2); String titleSvgData = g1.getSVGDocument(); String alignSvgData = g2.getSVGDocument(); String jsonData = null; boolean isEmbbedBioJSON = Boolean.valueOf(jalview.bin.Cache .getDefault("EXPORT_EMBBED_BIOJSON", "true")); if (isEmbbedBioJSON) { AlignExportSettingI exportSettings = new AlignExportSettingI(){ @Override public boolean isExportHiddenSequences() { return true; } @Override public boolean isExportHiddenColumns() { return true; } @Override public boolean isExportAnnotations() { return true; } @Override public boolean isExportFeatures() { return true; } @Override public boolean isExportGroups() { return true; } @Override public boolean isCancelled() { return false; } }; AlignmentExportData exportData = jalview.gui.AlignFrame .getAlignmentForExport(JSONFile.FILE_DESC, av, exportSettings); jsonData = new FormatAdapter(ap, exportData.getSettings()) .formatSequences(JSONFile.FILE_DESC, exportData .getAlignment(), exportData.getOmitHidden(), exportData.getStartEndPostions(), av.getColumnSelection()); } String htmlData = getHtml(titleSvgData, alignSvgData, jsonData); FileOutputStream out = new FileOutputStream(file); out.write(htmlData.getBytes()); out.flush(); out.close(); if (!(System.getProperty("java.awt.headless") != null && System .getProperty("java.awt.headless").equals("true"))) { jalview.util.BrowserLauncher.openURL("file:///" + file); } } catch (Exception e) { e.printStackTrace(); } } static JalviewFileChooser getHTMLChooser() { return new jalview.io.JalviewFileChooser( jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[] { "html" }, new String[] { "Hypertext Markup Language" }, "Hypertext Markup Language"); } public int printUnwrapped(int pwidth, int pheight, int pi, Graphics... pg) throws PrinterException { int idWidth = ap.getVisibleIdWidth(false); FontMetrics fm = ap.getFontMetrics(av.getFont()); int scaleHeight = av.getCharHeight() + fm.getDescent(); pg[0].setColor(Color.white); pg[0].fillRect(0, 0, pwidth, pheight); pg[0].setFont(av.getFont()); // ////////////////////////////////// // / How many sequences and residues can we fit on a printable page? int totalRes = (pwidth - idWidth) / av.getCharWidth(); int totalSeq = (pheight - scaleHeight) / av.getCharHeight() - 1; int pagesWide = (av.getAlignment().getWidth() / totalRes) + 1; // /////////////////////////// // / Only print these sequences and residues on this page int startRes; // /////////////////////////// // / Only print these sequences and residues on this page int endRes; // /////////////////////////// // / Only print these sequences and residues on this page int startSeq; // /////////////////////////// // / Only print these sequences and residues on this page int endSeq; startRes = (pi % pagesWide) * totalRes; endRes = (startRes + totalRes) - 1; if (endRes > (av.getAlignment().getWidth() - 1)) { endRes = av.getAlignment().getWidth() - 1; } startSeq = (pi / pagesWide) * totalSeq; endSeq = startSeq + totalSeq; if (endSeq > av.getAlignment().getHeight()) { endSeq = av.getAlignment().getHeight(); } int pagesHigh = ((av.getAlignment().getHeight() / totalSeq) + 1) * pheight; if (av.isShowAnnotation()) { pagesHigh += ap.getAnnotationPanel().adjustPanelHeight() + 3; } pagesHigh /= pheight; if (pi >= (pagesWide * pagesHigh)) { return Printable.NO_SUCH_PAGE; } // draw Scale pg[1].translate(0, 0); ap.getScalePanel().drawScale(pg[1], startRes, endRes, pwidth - idWidth, scaleHeight); pg[1].translate(-idWidth, scaleHeight); // ////////////// // Draw the ids Color currentColor = null; Color currentTextColor = null; pg[0].translate(0, scaleHeight); pg[0].setFont(ap.getIdPanel().getIdCanvas().getIdfont()); SequenceI seq; for (int i = startSeq; i < endSeq; i++) { seq = av.getAlignment().getSequenceAt(i); if ((av.getSelectionGroup() != null) && av.getSelectionGroup().getSequences(null).contains(seq)) { currentColor = Color.gray; currentTextColor = Color.black; } else { currentColor = av.getSequenceColour(seq); currentTextColor = Color.black; } pg[0].setColor(currentColor); pg[0].fillRect(0, (i - startSeq) * av.getCharHeight(), idWidth, av.getCharHeight()); pg[0].setColor(currentTextColor); int xPos = 0; if (av.isRightAlignIds()) { fm = pg[0].getFontMetrics(); xPos = idWidth - fm.stringWidth(seq.getDisplayId(av.getShowJVSuffix())) - 4; } pg[0].drawString( seq.getDisplayId(av.getShowJVSuffix()), xPos, (((i - startSeq) * av.getCharHeight()) + av.getCharHeight()) - (av.getCharHeight() / 5)); } pg[0].setFont(av.getFont()); pg[0].translate(idWidth, 0); // draw main sequence panel pg[1].translate(idWidth, 0); ap.getSeqPanel().seqCanvas.drawPanel(pg[1], startRes, endRes, startSeq, endSeq, 0); if (av.isShowAnnotation() && (endSeq == av.getAlignment().getHeight())) { // draw annotation label - need to offset for current scroll position int offset = -ap.getAlabels().getScrollOffset(); pg[0].translate(0, offset); pg[0].translate(-idWidth - 3, (endSeq - startSeq) * av.getCharHeight() + 3); ap.getAlabels().drawComponent(pg[0], idWidth); pg[0].translate(idWidth + 3, 0); pg[0].translate(0, -offset); // draw annotation - need to offset for current scroll position pg[1].translate(0, offset); pg[1].translate(-idWidth - 3, (endSeq - startSeq) * av.getCharHeight() + 3); pg[1].translate(idWidth + 3, 0); ap.getAnnotationPanel().renderer.drawComponent( ap.getAnnotationPanel(), av, pg[1], -1, startRes, endRes + 1); pg[1].translate(0, -offset); } return Printable.PAGE_EXISTS; } private String getHtml(String titleSvg, String alignmentSvg, String jsonData) { StringBuilder htmlSvg = new StringBuilder(); htmlSvg.append("\n"); if (jsonData != null) { htmlSvg.append(""); htmlSvg.append(""); } htmlSvg.append("\n"); htmlSvg.append("