JAL-629 --structureimage with formatting args.
authorBen Soares <b.soares@dundee.ac.uk>
Mon, 22 May 2023 19:42:02 +0000 (20:42 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Mon, 22 May 2023 19:42:02 +0000 (20:42 +0100)
12 files changed:
src/jalview/appletgui/AlignFrame.java
src/jalview/bin/Commands.java
src/jalview/bin/Jalview.java
src/jalview/bin/argparser/Arg.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/AppJmol.java
src/jalview/gui/ImageExporter.java
src/jalview/gui/StructureChooser.java
src/jalview/gui/StructureViewer.java
src/jalview/util/ImageMaker.java
src/jalview/util/imagemaker/BitmapImageSizing.java [new file with mode: 0644]

index 2a2fc70..0159bc7 100644 (file)
  */
 package jalview.appletgui;
 
+import java.awt.BorderLayout;
+import java.awt.Canvas;
+import java.awt.CheckboxMenuItem;
+import java.awt.Color;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Label;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.Panel;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.jmol.viewer.Viewer;
+
 import jalview.analysis.AlignmentSorter;
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.analysis.TreeBuilder;
@@ -81,45 +120,6 @@ import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.ViewportRanges;
 
-import java.awt.BorderLayout;
-import java.awt.Canvas;
-import java.awt.CheckboxMenuItem;
-import java.awt.Color;
-import java.awt.FlowLayout;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Frame;
-import java.awt.Graphics;
-import java.awt.Label;
-import java.awt.Menu;
-import java.awt.MenuBar;
-import java.awt.MenuItem;
-import java.awt.Panel;
-import java.awt.Rectangle;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.util.Arrays;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-import org.jmol.viewer.Viewer;
-
 public class AlignFrame extends EmbmenuFrame implements ActionListener,
         ItemListener, KeyListener, AlignViewControllerGuiI
 {
index dcdb4c0..2d57bc4 100644 (file)
@@ -14,6 +14,7 @@ import java.util.Locale;
 import java.util.Map;
 
 import jalview.analysis.AlignmentUtils;
+import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.argparser.Arg;
 import jalview.bin.argparser.ArgParser;
 import jalview.bin.argparser.ArgParser.Position;
@@ -26,6 +27,7 @@ import jalview.datamodel.SequenceI;
 import jalview.datamodel.annotations.AlphaFoldAnnotationRowBuilder;
 import jalview.gui.AlignFrame;
 import jalview.gui.AlignmentPanel;
+import jalview.gui.AppJmol;
 import jalview.gui.Desktop;
 import jalview.gui.Preferences;
 import jalview.gui.StructureChooser;
@@ -45,9 +47,13 @@ import jalview.io.IdentifyFile;
 import jalview.io.NewickFile;
 import jalview.structure.StructureImportSettings.TFType;
 import jalview.structure.StructureSelectionManager;
+import jalview.util.FileUtils;
 import jalview.util.HttpUtils;
+import jalview.util.ImageMaker;
+import jalview.util.ImageMaker.TYPE;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.util.imagemaker.BitmapImageSizing;
 
 public class Commands
 {
@@ -73,7 +79,7 @@ public class Commands
     argParser = argparser;
     headless = h;
     desktop = d;
-    afMap = new HashMap<String, AlignFrame>();
+    afMap = new HashMap<>();
     if (argparser != null)
     {
       processArgs(argparser, headless);
@@ -558,12 +564,74 @@ public class Commands
                           || Cache.getDefault("ADD_TEMPFACT_ANN", false));
 
           // TODO use ssFromStructure
-          StructureChooser.openStructureFileForSequence(null, null, ap, seq,
-                  false, structureFilepath, tft, paeFilepath, false,
-                  ssFromStructure, false, viewerType);
+          StructureViewer sv = StructureChooser
+                  .openStructureFileForSequence(null, null, ap, seq, false,
+                          structureFilepath, tft, paeFilepath, false,
+                          ssFromStructure, false, viewerType);
 
-          String structureImage = ArgParser.getValueFromSubValOrArg(avm, av,
-                  Arg.STRUCTUREIMAGE, subVals);
+          if (headless)
+          {
+            sv.setAsync(false);
+          }
+
+          String structureImageFilename = ArgParser.getValueFromSubValOrArg(
+                  avm, av, Arg.STRUCTUREIMAGE, subVals);
+          if (sv != null && structureImageFilename != null)
+          {
+            File structureImageFile = new File(structureImageFilename);
+            String width = ArgParser.getValueFromSubValOrArg(avm, av,
+                    Arg.STRUCTUREIMAGEWIDTH, subVals);
+            String height = ArgParser.getValueFromSubValOrArg(avm, av,
+                    Arg.STRUCTUREIMAGEHEIGHT, subVals);
+            String scale = ArgParser.getValueFromSubValOrArg(avm, av,
+                    Arg.STRUCTUREIMAGESCALE, subVals);
+            String renderer = ArgParser.getValueFromSubValOrArg(avm, av,
+                    Arg.STRUCTUREIMAGETEXTRENDERER, subVals);
+            String typeS = ArgParser.getValueFromSubValOrArg(avm, av,
+                    Arg.STRUCTUREIMAGETYPE, subVals);
+            if (typeS == null || typeS.length() == 0)
+            {
+              typeS = FileUtils.getExtension(structureImageFile);
+            }
+            TYPE imageType;
+            try
+            {
+              imageType = Enum.valueOf(TYPE.class,
+                      typeS.toUpperCase(Locale.ROOT));
+            } catch (IllegalArgumentException e)
+            {
+              Console.warn("Do not know image format '" + typeS
+                      + "', using PNG");
+              imageType = TYPE.PNG;
+            }
+            BitmapImageSizing userBis = ImageMaker
+                    .parseScaleWidthHeightStrings(scale, width, height);
+            switch (sv.getViewerType())
+            {
+            case JMOL:
+              try
+              {
+                Thread.sleep(1000);
+              } catch (InterruptedException e)
+              {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+              }
+              JalviewStructureDisplayI sview = sv
+                      .getJalviewStructureDisplay();
+              if (sview instanceof AppJmol)
+              {
+                AppJmol jmol = (AppJmol) sview;
+                jmol.makePDBImage(structureImageFile, imageType, renderer,
+                        userBis);
+              }
+              break;
+            default:
+              Console.warn("Cannot export image for structure viewer "
+                      + sv.getViewerType() + " yet");
+              break;
+            }
+          }
         }
       }
     }
@@ -638,48 +706,14 @@ public class Commands
           renderer = "text";
         String type = "png"; // default
 
-        float bitmapscale = 0.0f;
-        int bitmapwidth = 0;
-        int bitmapheight = 0;
         String scale = ArgParser.getValueFromSubValOrArg(avm, av, Arg.SCALE,
                 subVal);
-        if (scale != null)
-        {
-          try
-          {
-            bitmapscale = Float.parseFloat(scale);
-          } catch (NumberFormatException e)
-          {
-            Console.warn("Did not understand scale '" + scale
-                    + "', won't be used.");
-          }
-        }
         String width = ArgParser.getValueFromSubValOrArg(avm, av, Arg.WIDTH,
                 subVal);
-        if (width != null)
-        {
-          try
-          {
-            bitmapwidth = Integer.parseInt(width);
-          } catch (NumberFormatException e)
-          {
-            Console.warn("Did not understand width '" + width
-                    + "', won't be used.");
-          }
-        }
         String height = ArgParser.getValueFromSubValOrArg(avm, av,
                 Arg.HEIGHT, subVal);
-        if (height != null)
-        {
-          try
-          {
-            bitmapheight = Integer.parseInt(height);
-          } catch (NumberFormatException e)
-          {
-            Console.warn("Did not understand height '" + height
-                    + "', won't be used.");
-          }
-        }
+        BitmapImageSizing userBis = ImageMaker
+                .parseScaleWidthHeightStrings(scale, width, height);
 
         type = ArgParser.getValueFromSubValOrArg(avm, av, Arg.TYPE, subVal);
         if (type == null && fileName != null)
@@ -708,7 +742,7 @@ public class Commands
 
         case "png":
           Console.debug("Outputting type '" + type + "' to " + fileName);
-          af.createPNG(file, null, bitmapscale, bitmapwidth, bitmapheight);
+          af.createPNG(file, null, userBis);
           break;
 
         case "html":
index 59382fd..2716ce1 100755 (executable)
@@ -1470,6 +1470,7 @@ public class Jalview
     return set;
   }
 
+  /*
   private static void showUsage()
   {
     System.out.println(
@@ -1512,6 +1513,7 @@ public class Jalview
                     + "-jvmmemmax=MAXMEMORY\tOnly available with standalone executable jar or jalview.bin.Launcher. Limit maximum heap size (memory) to MAXMEMORY. MAXMEMORY can be specified in bytes, kilobytes(k), megabytes(m), gigabytes(g) or if you're lucky enough, terabytes(t). This defaults to 32g if total physical memory can be detected, or to 8g if total physical memory cannot be detected. See https://www.jalview.org/help/html/memory.html for more details.\n"
                     + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
   }
+  */
 
   private static void startUsageStats(final Desktop desktop)
   {
index ae01c48..2354cdd 100644 (file)
@@ -128,9 +128,6 @@ public enum Arg
                   + "none,\n" + "jmol,\n" + "chimera,\n" + "chimerax,\n"
                   + "pymol.",
           Opt.STRING, Opt.LINKED, Opt.MULTI),
-  STRUCTUREIMAGE(Type.STRUCTURE,
-          "Export an image of a 3D structure opened in JMOL", Opt.STRING,
-          Opt.LINKED, Opt.MULTI),
   NOTEMPFAC(Type.STRUCTURE,
           "Do not show the temperature factor annotation for the preceding --structure.",
           Opt.UNARY, Opt.LINKED, Opt.ALLOWALL, Opt.SECRET), // keep this secret
@@ -146,11 +143,11 @@ public enum Arg
           Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWALL,
           Opt.REQUIREINPUT, Opt.OUTPUT, Opt.PRIMARY),
   TYPE(Type.IMAGE,
-          "Set the image format for the preceding --image to name. Valid values for name are: svg,\n"
-                  + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
+          "Set the image format for the preceding --image. Valid values are:\n"
+                  + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
           Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
   TEXTRENDERER(Type.IMAGE,
-          "Sets whether text in a vector image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values for name are:\n"
+          "Sets whether text in a vector image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values are:\n"
                   + "text,\n" + "lineart.",
           Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
   SCALE(Type.IMAGE,
@@ -162,6 +159,28 @@ public enum Arg
   HEIGHT(Type.IMAGE,
           "Sets a height for bitmap image format (PNG) with the width maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --scale and --width then the smallest scaling will be used (scale, width and height provide bounds for the image).",
           Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
+  STRUCTUREIMAGE(Type.IMAGE,
+          "Export an image of a 3D structure opened in JMOL", Opt.STRING,
+          Opt.LINKED, Opt.MULTI),
+
+  STRUCTUREIMAGETYPE(Type.IMAGE,
+          "Set the structure image format for the preceding --structureimage. Valid values are:\n"
+                  + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
+          Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
+  STRUCTUREIMAGETEXTRENDERER(Type.IMAGE,
+          "Sets whether text in a vector structure image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values are:\n"
+                  + "text,\n" + "lineart.",
+          Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
+  STRUCTUREIMAGESCALE(Type.IMAGE,
+          "Sets a scaling for bitmap structure image format (PNG). Should be given as a floating point number. If used in conjunction with --structureimagewidth and --structureimageheight then the smallest scaling will be used (structureimagescale, structureimagewidth and structureimageheight provide bounds for the structure image).",
+          Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
+  STRUCTUREIMAGEWIDTH(Type.IMAGE,
+          "Sets a width for bitmap structure image format (PNG) with the height maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --structureimagescale and --structureimageheight then the smallest scaling will be used (structureimagescale, structureimagewidth and structureimageheight provide bounds for the structure image).",
+          Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
+  STRUCTUREIMAGEHEIGHT(Type.IMAGE,
+          "Sets a height for bitmap structure image format (PNG) with the width maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --structureimagescale and --structureimagewidth then the smallest scaling will be used (structureimagescale, structureimagewidth and structureimageheight provide bounds for the structure image).",
+          Opt.STRING, Opt.LINKED, Opt.ALLOWALL),
+
   OUTPUT(Type.OUTPUT,
           "Export the open alignment to file filename. The format name is specified by the subval modifier format=name, a following --format name argument or guessed from the file extension. Valid format names (and file extensions) are:\n"
                   + "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n"
index 71905c1..37eaae7 100644 (file)
@@ -151,6 +151,7 @@ import jalview.util.HttpUtils;
 import jalview.util.ImageMaker.TYPE;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.util.imagemaker.BitmapImageSizing;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.ViewportRanges;
 import jalview.ws.DBRefFetcher;
@@ -1480,14 +1481,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void createPNG(File f)
   {
-    createPNG(f, null, 0.0f, 0, 0);
+    createPNG(f, null, BitmapImageSizing.nullBitmapImageSizing());
   }
 
-  public void createPNG(File f, String renderer, float bitmapscale,
-          int bitmapwidth, int bitmapheight)
+  public void createPNG(File f, String renderer, BitmapImageSizing userBis)
   {
-    alignPanel.makeAlignmentImage(TYPE.PNG, f, renderer, bitmapscale,
-            bitmapwidth, bitmapheight);
+    alignPanel.makeAlignmentImage(TYPE.PNG, f, renderer, userBis);
   }
 
   /**
index a5a1aff..7befa20 100644 (file)
@@ -65,6 +65,7 @@ import jalview.structure.StructureSelectionManager;
 import jalview.util.Comparison;
 import jalview.util.ImageMaker;
 import jalview.util.MessageManager;
+import jalview.util.imagemaker.BitmapImageSizing;
 import jalview.viewmodel.ViewportListenerI;
 import jalview.viewmodel.ViewportRanges;
 
@@ -1175,7 +1176,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
   void makeAlignmentImage(ImageMaker.TYPE type, File file, String renderer)
   {
-    makeAlignmentImage(type, file, renderer, 0.0f, 0, 0);
+    makeAlignmentImage(type, file, renderer,
+            BitmapImageSizing.nullBitmapImageSizing());
   }
 
   /**
@@ -1188,7 +1190,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * @param bitmapscale
    */
   void makeAlignmentImage(ImageMaker.TYPE type, File file, String renderer,
-          float bitmapscale, int bitmapwidth, int bitmapheight)
+          BitmapImageSizing userBis)
   {
     final int borderBottomOffset = 5;
 
@@ -1219,7 +1221,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
     int imageHeight = aDimension.getHeight() + borderBottomOffset;
     String of = MessageManager.getString("label.alignment");
     exporter.doExport(file, this, imageWidth, imageHeight, of, renderer,
-            bitmapscale, bitmapwidth, bitmapheight);
+            userBis);
   }
 
   /**
index 2447a2f..806bfc1 100644 (file)
  */
 package jalview.gui;
 
-import java.util.Locale;
-
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
 import java.io.File;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 import javax.swing.JPanel;
@@ -43,15 +44,16 @@ import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.StructureViewerModel;
 import jalview.datamodel.StructureViewerModel.StructureData;
-import jalview.fts.service.alphafold.AlphafoldRestClient;
 import jalview.gui.ImageExporter.ImageWriterI;
 import jalview.gui.StructureViewer.ViewerType;
 import jalview.structure.StructureCommand;
 import jalview.structures.models.AAStructureBindingModel;
 import jalview.util.BrowserLauncher;
 import jalview.util.ImageMaker;
+import jalview.util.ImageMaker.TYPE;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.util.imagemaker.BitmapImageSizing;
 
 public class AppJmol extends StructureViewerBase
 {
@@ -424,21 +426,48 @@ public class AppJmol extends StructureViewerBase
   @Override
   public void makePDBImage(ImageMaker.TYPE type)
   {
+    makePDBImage(null, type, null,
+            BitmapImageSizing.nullBitmapImageSizing());
+  }
+
+  public void makePDBImage(File file, ImageMaker.TYPE type, String renderer,
+          BitmapImageSizing userBis)
+  {
     int width = getWidth();
     int height = getHeight();
+
+    BitmapImageSizing bis = ImageMaker.getScaleWidthHeight(width, height,
+            userBis);
+    float usescale = bis.scale;
+    int usewidth = bis.width;
+    int useheight = bis.height;
+
     ImageWriterI writer = new ImageWriterI()
     {
       @Override
       public void exportImage(Graphics g) throws Exception
       {
-        jmb.jmolViewer.renderScreenImage(g, width, height);
+        Graphics2D ig2 = (Graphics2D) g;
+        ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                RenderingHints.VALUE_ANTIALIAS_ON);
+        if (type == TYPE.PNG && usescale > 0.0f)
+        {
+          // for a scaled image, this scales down a bigger image to increase
+          // resolution
+
+          ig2.scale(1 / usescale, 1 / usescale);
+        }
+
+        jmb.jmolViewer.antialiased = true;
+        jmb.jmolViewer.requestRepaintAndWait("image export");
+        jmb.jmolViewer.renderScreenImage(ig2, usewidth, useheight);
       }
     };
     String view = MessageManager.getString("action.view")
             .toLowerCase(Locale.ROOT);
     ImageExporter exporter = new ImageExporter(writer,
             getProgressIndicator(), type, getTitle());
-    exporter.doExport(null, this, width, height, view);
+    exporter.doExport(file, this, width, height, view, renderer, userBis);
   }
 
   @Override
index 785d206..1d472f1 100644 (file)
@@ -34,6 +34,7 @@ import jalview.util.ImageMaker;
 import jalview.util.ImageMaker.TYPE;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.util.imagemaker.BitmapImageSizing;
 
 /**
  * A class that marshals steps in exporting a view in image graphics format
@@ -105,12 +106,12 @@ public class ImageExporter
   public void doExport(File file, Component parent, int width, int height,
           String imageSource)
   {
-    doExport(file, parent, width, height, imageSource, null, 0.0f, 0, 0);
+    doExport(file, parent, width, height, imageSource, null,
+            BitmapImageSizing.nullBitmapImageSizing());
   }
 
   public void doExport(File file, Component parent, int width, int height,
-          String imageSource, String renderer, float bitmapscale,
-          int bitmapwidth, int bitmapheight)
+          String imageSource, String renderer, BitmapImageSizing userBis)
   {
     final long messageId = System.currentTimeMillis();
     setStatus(
@@ -166,7 +167,7 @@ public class ImageExporter
       final File chosenFile = file;
       Callable<Void> okAction = () -> {
         exportImage(chosenFile, !textSelected.get(), width, height,
-                messageId, bitmapscale, bitmapwidth, bitmapheight);
+                messageId, userBis);
         return null;
       };
       LineartOptions epsOption = new LineartOptions(TYPE.EPS.getName(),
@@ -193,7 +194,7 @@ public class ImageExporter
        * - just do the export
        */
       exportImage(file, !textSelected.get(), width, height, messageId,
-              bitmapscale, bitmapwidth, bitmapheight);
+              userBis);
     }
   }
 
@@ -209,8 +210,7 @@ public class ImageExporter
    * @param messageId
    */
   protected void exportImage(File chosenFile, boolean asLineart, int width,
-          int height, long messageId, float bitmapscale, int bitmapwidth,
-          int bitmapheight)
+          int height, long messageId, BitmapImageSizing userBis)
   {
     String type = imageType.getName();
     try
@@ -220,7 +220,7 @@ public class ImageExporter
       // "status.exporting_alignment_as_x_file", type),
       // messageId);
       ImageMaker im = new ImageMaker(imageType, width, height, chosenFile,
-              title, asLineart, bitmapscale, bitmapwidth, bitmapheight);
+              title, asLineart, userBis);
       imageWriter.exportImage(im.getGraphics());
       im.writeImage();
       setStatus(
index 35972b0..790873f 100644 (file)
@@ -1736,13 +1736,14 @@ public class StructureChooser extends GStructureChooser
             paeFilename, false, true, doXferSettings, null);
   }
 
-  public static void openStructureFileForSequence(
+  public static StructureViewer openStructureFileForSequence(
           StructureSelectionManager ssm, StructureChooser sc,
           AlignmentPanel ap, SequenceI seq, boolean prompt,
           String sFilename, TFType tft, String paeFilename,
           boolean forceHeadless, boolean showRefAnnotations,
           boolean doXferSettings, ViewerType viewerType)
   {
+    StructureViewer sv = null;
     boolean headless = forceHeadless;
     if (sc == null)
     {
@@ -1751,7 +1752,9 @@ public class StructureChooser extends GStructureChooser
       sc = new StructureChooser(new SequenceI[] { seq }, seq, ap, false);
     }
     if (ssm == null)
+    {
       ssm = ap.getStructureSelectionManager();
+    }
 
     PDBEntry fileEntry = new AssociatePdbFileWithSeq().associatePdbWithSeq(
             sFilename, DataSourceType.FILE, seq, prompt, Desktop.instance,
@@ -1760,15 +1763,19 @@ public class StructureChooser extends GStructureChooser
     // if headless, "false" in the sc constructor above will avoid GUI behaviour
     // in sc.launchStructureViewer()
     if (!headless && !(viewerType == null))
-      sc.launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
+    {
+      sv = sc.launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
               new SequenceI[]
               { seq }, viewerType);
+    }
 
     if (headless)
       sc.mainFrame.dispose();
 
     if (showRefAnnotations)
       showReferenceAnnotationsForSequence(ap.alignFrame, seq);
+
+    return sv;
   }
 
   public static void showReferenceAnnotationsForSequence(AlignFrame af,
index 0c12eb2..6cef665 100644 (file)
@@ -54,6 +54,16 @@ public class StructureViewer
    */
   private boolean superposeAdded = true;
 
+  /**
+   * whether to open structures in their own thread or not
+   */
+  private boolean async = true;
+
+  public void setAsync(boolean b)
+  {
+    async = b;
+  }
+
   public enum ViewerType
   {
     JMOL, CHIMERA, CHIMERAX, PYMOL
@@ -146,7 +156,8 @@ public class StructureViewer
     if (sview != null)
     {
       sview.setAlignAddedStructures(superposeAdded);
-      new Thread(new Runnable()
+
+      Runnable viewRunnable = new Runnable()
       {
         @Override
         public void run()
@@ -165,7 +176,15 @@ public class StructureViewer
 
           sview.updateTitleAndMenus();
         }
-      }).start();
+      };
+      if (async)
+      {
+        new Thread(viewRunnable).start();
+      }
+      else
+      {
+        viewRunnable.run();
+      }
       return sview;
     }
 
@@ -303,6 +322,11 @@ public class StructureViewer
 
   JalviewStructureDisplayI sview = null;
 
+  public JalviewStructureDisplayI getJalviewStructureDisplay()
+  {
+    return sview;
+  }
+
   public JalviewStructureDisplayI viewStructures(PDBEntry pdb,
           SequenceI[] seqsForPdb, AlignmentPanel ap)
   {
index 016feee..3306b0d 100755 (executable)
@@ -34,7 +34,9 @@ import org.jfree.graphics2d.svg.SVGGraphics2D;
 import org.jfree.graphics2d.svg.SVGHints;
 import org.jibble.epsgraphics.EpsGraphics2D;
 
+import jalview.bin.Console;
 import jalview.io.JalviewFileChooser;
+import jalview.util.imagemaker.BitmapImageSizing;
 
 public class ImageMaker
 {
@@ -114,8 +116,8 @@ public class ImageMaker
    * @throws IOException
    */
   public ImageMaker(TYPE imageType, int width, int height, File file,
-          String fileTitle, boolean useLineart, float bitmapscale,
-          int bitmapwidth, int bitmapheight) throws IOException
+          String fileTitle, boolean useLineart, BitmapImageSizing userBis)
+          throws IOException
   {
     this.type = imageType;
 
@@ -129,7 +131,7 @@ public class ImageMaker
       setupEPS(width, height, fileTitle, useLineart);
       break;
     case PNG:
-      setupPNG(width, height, bitmapscale, bitmapwidth, bitmapheight);
+      setupPNG(width, height, userBis);
       break;
     default:
     }
@@ -180,50 +182,26 @@ public class ImageMaker
    * @param height
    * @param scale
    */
-  protected void setupPNG(int width, int height, float scale,
-          int bitmapwidth, int bitmapheight)
+  protected void setupPNG(int width, int height, BitmapImageSizing userBis)
   {
     if (width == 0 || height == 0)
       return;
 
-    float usescale = 0.0f;
-    int usewidth = width;
-    int useheight = height;
+    BitmapImageSizing bis = ImageMaker.getScaleWidthHeight(width, height,
+            userBis);
+    float usescale = bis.scale;
+    int usewidth = bis.width;
+    int useheight = bis.height;
 
-    // use the smallest positive scale (i.e. fit in the box)
-    if (scale > 0.0f)
-    {
-      usescale = scale;
-      usewidth = Math.round(scale * width);
-      useheight = Math.round(scale * height);
-    }
-    if (bitmapwidth > 0)
-    {
-      float wscale = (float) bitmapwidth / width;
-      if (wscale > 0.0f && (usescale == 0.0f || wscale < usescale))
-      {
-        usescale = wscale;
-        usewidth = bitmapwidth;
-        useheight = Math.round(usescale * height);
-      }
-    }
-    if (bitmapheight > 0)
-    {
-      float hscale = (float) bitmapheight / height;
-      if (hscale > 0.0f && (usescale == 0.0f || hscale < usescale))
-      {
-        usescale = hscale;
-        usewidth = Math.round(usescale * width);
-        useheight = bitmapheight;
-      }
-    }
     bi = new BufferedImage(usewidth, useheight, BufferedImage.TYPE_INT_RGB);
     graphics = bi.getGraphics();
     Graphics2D ig2 = (Graphics2D) graphics;
     ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
             RenderingHints.VALUE_ANTIALIAS_ON);
     if (usescale > 0.0f)
+    {
       ig2.scale(usescale, usescale);
+    }
   }
 
   /**
@@ -267,4 +245,120 @@ public class ImageMaker
     pg.setAccurateTextMode(useLineart);
     graphics = pg;
   }
+
+  /**
+   * Takes suggested float scale, int width, int height and create a bounding
+   * box returned as a BitmapImageSizing object with consistent scale, width,
+   * height fields.
+   * 
+   * @param scale
+   * @param bitmapwidth
+   * @param bitmapheight
+   * @return BitmapImageSizing
+   */
+  public static BitmapImageSizing getScaleWidthHeight(int width, int height,
+          float scale, int bitmapwidth, int bitmapheight)
+  {
+    float usescale = 0.0f;
+    int usewidth = width;
+    int useheight = height;
+
+    // use the smallest positive scale (i.e. fit in the box)
+    if (scale > 0.0f)
+    {
+      usescale = scale;
+      usewidth = Math.round(scale * width);
+      useheight = Math.round(scale * height);
+    }
+    if (bitmapwidth > 0)
+    {
+      float wscale = (float) bitmapwidth / width;
+      if (wscale > 0.0f && (usescale == 0.0f || wscale < usescale))
+      {
+        usescale = wscale;
+        usewidth = bitmapwidth;
+        useheight = Math.round(usescale * height);
+      }
+    }
+    if (bitmapheight > 0)
+    {
+      float hscale = (float) bitmapheight / height;
+      if (hscale > 0.0f && (usescale == 0.0f || hscale < usescale))
+      {
+        usescale = hscale;
+        usewidth = Math.round(usescale * width);
+        useheight = bitmapheight;
+      }
+    }
+    return new BitmapImageSizing(usescale, usewidth, useheight);
+  }
+
+  /**
+   * Takes suggested scale, width, height as a BitmapImageSizing object and
+   * create a bounding box returned as a BitmapImageSizing object with
+   * consistent scale, width, height fields.
+   * 
+   * @param bis
+   * @return BitmapImageSizing
+   */
+  public static BitmapImageSizing getScaleWidthHeight(int width, int height,
+          BitmapImageSizing bis)
+  {
+    return ImageMaker.getScaleWidthHeight(width, height, bis.scale,
+            bis.width, bis.height);
+  }
+
+  /**
+   * Takes String versions of suggested float scale, int width, int height and
+   * create a bounding box returned as a BitmapImageSizing object with
+   * consistent scale, width, height fields.
+   * 
+   * @param scaleS
+   * @param widthS
+   * @param heightS
+   * @return BitmapImageSizing
+   */
+  public static BitmapImageSizing parseScaleWidthHeightStrings(
+          String scaleS, String widthS, String heightS)
+  {
+    float scale = 0.0f;
+    int width = 0;
+    int height = 0;
+
+    if (scaleS != null)
+    {
+      try
+      {
+        scale = Float.parseFloat(scaleS);
+      } catch (NumberFormatException e)
+      {
+        Console.warn("Did not understand scale '" + scaleS
+                + "', won't be used.");
+      }
+    }
+    if (widthS != null)
+    {
+      try
+      {
+        width = Integer.parseInt(widthS);
+      } catch (NumberFormatException e)
+      {
+        Console.warn("Did not understand width '" + widthS
+                + "', won't be used.");
+      }
+    }
+    if (heightS != null)
+    {
+      try
+      {
+        height = Integer.parseInt(heightS);
+      } catch (NumberFormatException e)
+      {
+        Console.warn("Did not understand height '" + heightS
+                + "', won't be used.");
+      }
+    }
+
+    return new BitmapImageSizing(scale, width, height);
+  }
 }
diff --git a/src/jalview/util/imagemaker/BitmapImageSizing.java b/src/jalview/util/imagemaker/BitmapImageSizing.java
new file mode 100644 (file)
index 0000000..312b834
--- /dev/null
@@ -0,0 +1,22 @@
+package jalview.util.imagemaker;
+
+public class BitmapImageSizing
+{
+  public final float scale;
+
+  public final int width;
+
+  public final int height;
+
+  public BitmapImageSizing(float scale, int width, int height)
+  {
+    this.scale = scale;
+    this.width = width;
+    this.height = height;
+  }
+
+  public static BitmapImageSizing nullBitmapImageSizing()
+  {
+    return new BitmapImageSizing(0.0f, 0, 0);
+  }
+}