Greetings,

Just in case someone else finds the need for copying the exact zoom and/or
cursor location...

Copy Exact Zoom: Taken predominately from Zoom.setZoom: if
areaselection... with fix(?)

      ImageCanvas fic = fimp.getCanvas();
      ImageCanvas tic = timp.getCanvas();
      Insets insets = fimp.getWindow().getInsets();
      Rectangle srcRect = fic.getSrcRect();
      double mag = fic.getMagnification();
      int cw = (int)(srcRect.width*mag + insets.right+insets.left +
ImageWindow.HGAP*2);
      int ch = (int)(srcRect.height*mag + insets.top+insets.bottom +
ImageWindow.VGAP*2+fimp.getWindow().getSliderHeight());
      tic.setSourceRect(srcRect);
      tic.setMagnification(mag);
      tic.setSize(new Dimension((int)(srcRect.width*mag),
(int)(srcRect.height*mag)));
      timp.getWindow().setSize(cw,ch);

// lacking from the stolen code snippet...
// for the zoom to occur you need to...
      tic.repaint();


Copy the cursor:
Code snippet taken from SyncWindows.drawSyncCursor. Trouble with using it
directly is that it is private and not static.
1) make a Shape (specifically GeneralPath) where the locations are zero
(origin) based.
   public static Shape makeShapeX(int near, int far) {
      GeneralPath path = new GeneralPath();
      path.moveTo(-far, -far); path.lineTo(-near, -near);
      path.moveTo(+far, +far); path.lineTo(+near, +near);
      path.moveTo(-far, +far); path.lineTo(-near, +near);
      path.moveTo(+far, -far); path.lineTo(+near, -near);
      return new GeneralPath(path);
      }
2) Convert to an Roi at the cursor location in image coordinates...
   public static Roi makeCursorRoi(ImageCanvas ic, Point p, Shape shape) {
      Rectangle sr = ic.getSrcRect();
      double mag = ic.getMagnification();
      AffineTransform at = new AffineTransform(1.0/mag,0.0, 0.0,1.0/mag,
sr.x+p.x,sr.y+p.y);
      return new ShapeRoi(at.createTransformedShape(shape));
      }
3) set this ROI as a cursor in the desired window as an overlay...
   public static boolean setCursor(ImagePlus imp, Roi cursor) {
      cursor.setStrokeColor(Color.red);
      cursor.setStrokeWidth(2);
      cursor.setNonScalable(true);
      cursor.setIsCursor(true);
      Overlay o = removeCursor(imp);
      if (o == null) return false;
      o.add(cursor);
      imp.setOverlay(o);
      return true;
      }

Bonus gotchas:
timp.settimp.setDisplayRange(fimp.getDisplayRangeMin(),fimp.getDisplayRangeMax());
// needs following for the display change
timp.updateAndDraw();

>From memory (and docs)... imp.repaintWindow does not update the slice
label if had been changed.

Fred

PS: non-minimal demonstrative code attached.


On Mon, December 8, 2025 11:42 am, Fred Damen wrote:
> Greetings, Kenneth and others,
>
> Thanks for the quick response, although, let me redirect the intent of
> what I am looking for in a response... Some times doing something in Java
> in ImageJ just works if you get the steps just right; lifting code
> snippets from publicly available code is a great way of accomplishing this
> - although this requires finding this code. When writing the code simply
> from reading the documentation sometimes only kinda-sorta works, and you
> spend way to much time trying to get it to work.
>
> For example, some times opening a series of ImagePlus(s) (which includes
> zooming) one of the ImageWindows which exists and is displayed, albeit the
> ImageWindow is a couple of pixels width and the canvas size is something
> like -1,35 (from memory 35 is the height of the title bar). In this
> condition, using ic.zoom100Percent() alone does not resize the window. But
> if, when detected, you set the canvas size to something legit,
> ic.setSize(imp.getWidth(),imp.getHeight()), the ic.zoom100Percent() works
> as expected, n.b., any legit size works. During the debugging, I noticed
> that if I can make said ImageWindow active and use the GUI Image>Zoom>View
> 100% it seems to always zooms to 100%; Why this GUI works and not what is
> supposedly called does not???
>
> So, if someone has code snippets that can replicate the specific geometry
> and zoom conditions, and/ot place something visible (but does not modify /
> function) at a point in said other window, and is willing to share, my
> happiness level will rise significantly.
>
> When I asked for code snippet for scrolling large tables within a Panel,
> something I struggled with, Curtis provided a code snippet that worked
> perfectly, Thanks again Curtis...
>
> Thanks in advance,
>
> Fred
>
> On Mon, December 8, 2025 3:23 am, Kenneth Sloan wrote:
>> The way I do this is:
>>
>> a) define a Class that extends ImageWindow
>> b) define methods such as “SetZoom(…)”, and “SetCursor”
>> c) define methods such as “LinkToWindow(MyImageWindow)
>> d) In the code that creates each such window, use “LinkToWindow” to
>> tell all the windows about each other
>> e) in the MyImageWindow class, catch all of the changes you want to
>> handle, and notify  all of the windows you are linked to.  BEWARE OF
>> LOOPS.
>>
>> If there is a better way to do this kind of thing, I’m all ears - but
>> this has worked for me.
>>
>> Note: I do this for a slightly different reason, but the general idea is
>> to:
>>
>> a) create an extension class
>> b) link the windows
>> c) modify the extension class to accept the links, capture the changes,
>> and communicate them.
>>
>> --
>> Kenneth Sloan
>> [email protected]
>> Vision is the art of seeing what is invisible to others.
>>
>>
>> --
>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
import ij.*;
import ij.process.*;
import ij.gui.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import ij.plugin.*;
import ij.plugin.frame.*;

public class Copy_N_Paste implements PlugIn {

   public void run(String arg) {
      ImagePlus imp = IJ.getImage();
      switch(arg.toLowerCase()) {
         case "": break;
         case "from":          copyFrom(imp);          return;
         case "zoom":          pasteZoom(imp);         return;
         case "czt":           pasteCZT(imp);          return;
         case "displayrange":  pasteDisplayRange(imp); return;
         case "addmenu":       addMenu();              return;
         case "removemenu":    removeMenu();           return;
         default:     IJ.showStatus("Copy_N_Paste: illegal arg '"+arg+"'");
                      return;
         }
      GenericDialog gd = new GenericDialog("Copy_N_Paste");
      gd.addChoice("Which:", new String[]{"Zoom", "CZT", "Display Range", 
"Cursor", "Add Menu", "Remove Menu"}, "");
      gd.addImageChoice("From", imp.getTitle());
      gd.addImageChoice("To:", "");
      gd.showDialog();
      if (gd.wasCanceled()) return;
      String which = gd.getNextChoice();
      ImagePlus fimp = gd.getNextImage();
      ImagePlus timp = gd.getNextImage();
      switch(which) {
         case "Zoom":          copyZoom(fimp, timp);         return;
         case "CZT":           copyCZT(fimp, timp);          return;
         case "Display Range": copyDisplayRange(fimp, timp); return;
         //case "Cursor":        copyCursor(fimp, timp);       return;
         case "Add Menu":      addMenu();                    return;
         case "Remove Menu":   removeMenu();                 return;
         default: IJ.showStatus("Copy_N_Paste: illigal option '"+which+"'");
         }
      }

   public static void copyFrom(ImagePlus fimp) {
      IJ.setProperty("Copy_N_Paste:From",fimp);
      }
   public static boolean pasteZoom(ImagePlus timp) {
      ImagePlus fimp = (ImagePlus)IJ.getProperty("Copy_N_Paste:From");
      if (fimp == null) {
         IJ.error("Copy_N_Paste: From ImagePlus not set.");
         return false;
         }
      return copyZoom(fimp,timp);
      }
   public static boolean copyZoom(ImagePlus fimp, ImagePlus timp) {
      if (fimp == null) return false;
      if (timp == null) return false;
      //fimp.waitTillActivated(fimp);
      //timp.waitTillActivated(fimp);
      ImageCanvas fic = fimp.getCanvas();
      ImageCanvas tic = timp.getCanvas();
      Insets insets = fimp.getWindow().getInsets();
      Rectangle srcRect = fic.getSrcRect();
      double mag = fic.getMagnification();
      int cw = (int)(srcRect.width*mag + insets.right+insets.left + 
ImageWindow.HGAP*2);
      int ch = (int)(srcRect.height*mag + insets.top+insets.bottom + 
ImageWindow.VGAP*2+fimp.getWindow().getSliderHeight()); 
      tic.setSourceRect(srcRect);
      tic.setMagnification(mag);
      tic.setSize(new Dimension((int)(srcRect.width*mag), 
(int)(srcRect.height*mag)));
      timp.getWindow().setSize(cw,ch);

      //timp.getWindow().pack();
      tic.repaint();
      //IJ.wait(100);

      return true;
      }

   public static boolean pasteCZT(ImagePlus timp) {
      ImagePlus fimp = (ImagePlus)IJ.getProperty("Copy_N_Paste:From");
      if (fimp == null) {
         IJ.error("Copy_N_Paste: From ImagePlus not set.");
         return false;
         }
      return copyCZT(fimp,timp);
      }
   public static boolean copyCZT(ImagePlus fimp, ImagePlus timp) {
      if (fimp == null) return false;
      if (timp == null) return false;
      timp.setPosition(fimp.getNChannels()== 1 ? 1 : fimp.getC(),
                       fimp.getNSlices()  == 1 ? 1 : fimp.getZ(),
                       fimp.getNFrames()  == 1 ? 1 : fimp.getT());
      return true;
      }

   public static boolean pasteDisplayRange(ImagePlus timp) {
      ImagePlus fimp = (ImagePlus)IJ.getProperty("Copy_N_Paste:From");
      if (fimp == null) {
         IJ.error("Copy_N_Paste: From ImagePlus not set.");
         return false;
         }
      return copyDisplayRange(fimp,timp);
      }
   public static boolean copyDisplayRange(ImagePlus fimp, ImagePlus timp) {
      if (fimp == null) return false;
      if (timp == null) return false;
      timp.setDisplayRange(fimp.getDisplayRangeMin(),fimp.getDisplayRangeMax());
      //timp.getCanvas().draw();
      //timp.repaintWindow();
      timp.updateAndDraw();
      //timp.updateAndRepaintWindow();
      return true;
      }

   public static Shape makeShape() {
      return makeShapeX();
      }

   public static int defaultNear =  2;
   public static int defaultFar  = 16;
   public static Shape makeShapeX() {
      return makeShapeX(defaultNear, defaultFar);
      }
   public static Shape makeShapeX(int near, int far) {
      GeneralPath path = new GeneralPath();
      path.moveTo(-far, -far); path.lineTo(-near, -near);
      path.moveTo(+far, +far); path.lineTo(+near, +near);
      path.moveTo(-far, +far); path.lineTo(-near, +near);
      path.moveTo(+far, -far); path.lineTo(+near, -near);
      return new GeneralPath(path);
      }
   public static Roi makeCursorRoi(ImageCanvas ic, int x, int y, Shape shape) {
      return makeCursorRoi(ic, new Point(x,y), shape);
      }
   public static Roi makeCursorRoi(ImageCanvas ic, Shape shape) {
      return makeCursorRoi(ic, ic.getCursorLoc(), shape);
      }
   public static Roi makeCursorRoi(ImageCanvas ic, Point p, Shape shape) {
      Rectangle sr = ic.getSrcRect();
      double mag = ic.getMagnification();
      AffineTransform at = new AffineTransform(1.0/mag,0.0, 0.0,1.0/mag, 
sr.x+p.x,sr.y+p.y);
      return new ShapeRoi(at.createTransformedShape(shape));
      }
   public static boolean pasteCursor(ImagePlus timp) {
      ImageCanvas ic = timp.getCanvas();
      Point p = ic.getCursorLoc();
      Roi cursor = makeCursorRoi(ic, p, makeShapeX(defaultNear, defaultFar));
      Overlay o = removeCursor(timp);
      return setCursor(timp, cursor);
      }
   public static boolean copyCursor(Shape shape, ImagePlus fimp, ImagePlus ... 
timp) {
      if (shape == null) return false;
      if (fimp  == null) return false;
      Roi cursor = makeCursorRoi(fimp.getCanvas(), shape);
      for(int i=0; i<timp.length; i++)
         if (timp[i] != null)
            setCursor(timp[i], cursor);
      return true;
      }
   public static boolean copyCursor(ImagePlus fimp, ImagePlus timp) {
      return copyCursor(fimp, timp, makeShapeX(defaultNear, defaultFar));
      }
   public static boolean copyCursor(ImagePlus fimp, ImagePlus timp, int near, 
int far) {
      return copyCursor(fimp, timp, makeShapeX(near, far));
      }
   public static boolean copyCursor(ImagePlus fimp, ImagePlus timp, Shape 
shape) {
      if (fimp == null) return false;
      if (timp == null) return false;
      ImageCanvas ic = fimp.getCanvas();
      if (ic==null || !ic.cursorOverImage()) return false;
      return setCursor(timp, makeCursorRoi(ic, shape));
      }
   public static Overlay removeCursor(ImagePlus imp) {
      if (imp == null) return null;
      Overlay o = imp.getOverlay();
      if (o == null) 
         return new Overlay();
      for(int i=o.size()-1; i>=0; i--)
         if (o.get(i)!=null && o.get(i).isCursor())
            o.remove(i);
      imp.setOverlay(o);
      return o;
      }
   public static boolean setCursor(ImagePlus imp, Roi cursor) {
      cursor.setStrokeColor(Color.red);
      cursor.setStrokeWidth(2);
      cursor.setNonScalable(true);
      cursor.setIsCursor(true);
      Overlay o = removeCursor(imp);
      if (o == null) return false;
      o.add(cursor);
      imp.setOverlay(o);
      return true;
      }

   private static String menuName = "Copy_N_Paste";
   public static void addMenu() {
      removeMenu();
      PopupMenu ppm = Menus.getPopupMenu();
      Menu pm = new Menu(menuName);
      ppm.add(pm);

      MenuItem dmi = new MenuItem("Dialog");
      dmi.addActionListener(new ActionListener() { 
         public void actionPerformed(ActionEvent e) {
            new Copy_N_Paste().run("");
            } 
         });
      pm.add(dmi);

      MenuItem frommi = new MenuItem("Mark From");
      frommi.addActionListener(new ActionListener() { 
         public void actionPerformed(ActionEvent e) {
            ImagePlus imp = WindowManager.getCurrentImage();
            copyFrom(imp);
            } 
         });
      pm.add(frommi);

      pm.addSeparator();

      MenuItem tozmi = new MenuItem("Zoom");
      tozmi.addActionListener(new ActionListener() { 
         public void actionPerformed(ActionEvent e) {
            ImagePlus imp = WindowManager.getCurrentImage();
            pasteZoom(imp);
            } 
         });
      pm.add(tozmi);

      MenuItem todrmi = new MenuItem("Display Range");
      todrmi.addActionListener(new ActionListener() { 
         public void actionPerformed(ActionEvent e) {
            ImagePlus imp = WindowManager.getCurrentImage();
            pasteDisplayRange(imp);
            } 
         });
      pm.add(todrmi);

      MenuItem tocztmi = new MenuItem("CZT");
      tocztmi.addActionListener(new ActionListener() { 
         public void actionPerformed(ActionEvent e) {
            ImagePlus imp = WindowManager.getCurrentImage();
            pasteCZT(imp);
            } 
         });
      pm.add(tocztmi);

      MenuItem tczmi = new MenuItem("TestCursor");
      tczmi.addActionListener(new ActionListener() { 
         public void actionPerformed(ActionEvent e) {
            ImagePlus imp = WindowManager.getCurrentImage();
            pasteCursor(imp);
            } 
         });
      pm.add(tczmi);
      }
   private static boolean removeMenu() {
      PopupMenu ppm = Menus.getPopupMenu();
      int n = ppm.getItemCount();
      for(int i=n-1; i>=0; i--)
         if (ppm.getItem(i).getLabel().equals(menuName)) { 
            ((Menu)ppm.getItem(i)).removeAll();
            ppm.remove(i); 
            return true;
            }
      return false;
      }
}

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html

Reply via email to