Example #1
0
/** This plugin implements the Image/Scale command. */
public class Scaler implements PlugIn, TextListener, FocusListener {
  private ImagePlus imp;
  private static String xstr = "0.5";
  private static String ystr = "0.5";
  private String zstr = "1.0";
  private static int newWidth, newHeight;
  private int newDepth;
  private static boolean averageWhenDownsizing = true;
  private static boolean newWindow = true;
  private static int interpolationMethod = ImageProcessor.BILINEAR;
  private String[] methods = ImageProcessor.getInterpolationMethods();
  private static boolean fillWithBackground;
  private static boolean processStack = true;
  private double xscale, yscale, zscale;
  private String title = "Untitled";
  private Vector fields;
  private double bgValue;
  private boolean constainAspectRatio = true;
  private TextField xField, yField, zField, widthField, heightField, depthField;
  private Rectangle r;
  private Object fieldWithFocus;
  private int oldDepth;

  public void run(String arg) {
    imp = IJ.getImage();
    Roi roi = imp.getRoi();
    if (roi != null && !roi.isArea()) imp.deleteRoi(); // ignore any line selection
    ImageProcessor ip = imp.getProcessor();
    if (!showDialog(ip)) return;
    if (newDepth > 0 && newDepth != oldDepth) {
      newWindow = true;
      processStack = true;
    }
    if ((ip.getWidth() > 1 && ip.getHeight() > 1) || newWindow)
      ip.setInterpolationMethod(interpolationMethod);
    else ip.setInterpolationMethod(ImageProcessor.NONE);
    ip.setBackgroundValue(bgValue);
    imp.startTiming();
    try {
      if (newWindow && imp.getStackSize() > 1 && processStack) createNewStack(imp, ip);
      else scale(ip);
    } catch (OutOfMemoryError o) {
      IJ.outOfMemory("Scale");
    }
    IJ.showProgress(1.0);
  }

  void createNewStack(ImagePlus imp, ImageProcessor ip) {
    int nSlices = imp.getStackSize();
    int w = imp.getWidth(), h = imp.getHeight();
    ImagePlus imp2 = imp.createImagePlus();
    Rectangle r = ip.getRoi();
    boolean crop = r.width != imp.getWidth() || r.height != imp.getHeight();
    ImageStack stack1 = imp.getStack();
    ImageStack stack2 = new ImageStack(newWidth, newHeight);
    ImageProcessor ip1, ip2;
    int method = interpolationMethod;
    if (w == 1 || h == 1) method = ImageProcessor.NONE;
    for (int i = 1; i <= nSlices; i++) {
      IJ.showStatus("Scale: " + i + "/" + nSlices);
      ip1 = stack1.getProcessor(i);
      String label = stack1.getSliceLabel(i);
      if (crop) {
        ip1.setRoi(r);
        ip1 = ip1.crop();
      }
      ip1.setInterpolationMethod(method);
      ip2 = ip1.resize(newWidth, newHeight, averageWhenDownsizing);
      if (ip2 != null) stack2.addSlice(label, ip2);
      IJ.showProgress(i, nSlices);
    }
    imp2.setStack(title, stack2);
    Calibration cal = imp2.getCalibration();
    if (cal.scaled()) {
      cal.pixelWidth *= 1.0 / xscale;
      cal.pixelHeight *= 1.0 / yscale;
    }
    IJ.showProgress(1.0);
    int[] dim = imp.getDimensions();
    imp2.setDimensions(dim[2], dim[3], dim[4]);
    if (imp.isComposite()) {
      imp2 = new CompositeImage(imp2, ((CompositeImage) imp).getMode());
      ((CompositeImage) imp2).copyLuts(imp);
    }
    if (imp.isHyperStack()) imp2.setOpenAsHyperStack(true);
    if (newDepth > 0 && newDepth != oldDepth)
      imp2 = (new Resizer()).zScale(imp2, newDepth, interpolationMethod);
    if (imp2 != null) {
      imp2.show();
      imp2.changes = true;
    }
  }

  void scale(ImageProcessor ip) {
    if (newWindow) {
      Rectangle r = ip.getRoi();
      ImagePlus imp2 = imp.createImagePlus();
      imp2.setProcessor(title, ip.resize(newWidth, newHeight, averageWhenDownsizing));
      Calibration cal = imp2.getCalibration();
      if (cal.scaled()) {
        cal.pixelWidth *= 1.0 / xscale;
        cal.pixelHeight *= 1.0 / yscale;
      }
      imp2.show();
      imp.trimProcessor();
      imp2.trimProcessor();
      imp2.changes = true;
    } else {
      if (processStack && imp.getStackSize() > 1) {
        Undo.reset();
        StackProcessor sp = new StackProcessor(imp.getStack(), ip);
        sp.scale(xscale, yscale, bgValue);
      } else {
        ip.snapshot();
        Undo.setup(Undo.FILTER, imp);
        ip.setSnapshotCopyMode(true);
        ip.scale(xscale, yscale);
        ip.setSnapshotCopyMode(false);
      }
      imp.deleteRoi();
      imp.updateAndDraw();
      imp.changes = true;
    }
  }

  boolean showDialog(ImageProcessor ip) {
    String macroOptions = Macro.getOptions();
    if (macroOptions != null) {
      if (macroOptions.indexOf(" interpolate") != -1)
        macroOptions.replaceAll(" interpolate", " interpolation=Bilinear");
      else if (macroOptions.indexOf(" interpolation=") == -1)
        macroOptions = macroOptions + " interpolation=None";
      Macro.setOptions(macroOptions);
    }
    int bitDepth = imp.getBitDepth();
    int stackSize = imp.getStackSize();
    boolean isStack = stackSize > 1;
    oldDepth = stackSize;
    if (isStack) {
      xstr = "1.0";
      ystr = "1.0";
      zstr = "1.0";
    }
    r = ip.getRoi();
    int width = newWidth;
    if (width == 0) width = r.width;
    int height = (int) ((double) width * r.height / r.width);
    xscale = Tools.parseDouble(xstr, 0.0);
    yscale = Tools.parseDouble(ystr, 0.0);
    zscale = 1.0;
    if (xscale != 0.0 && yscale != 0.0) {
      width = (int) (r.width * xscale);
      height = (int) (r.height * yscale);
    } else {
      xstr = "-";
      ystr = "-";
    }
    GenericDialog gd = new GenericDialog("Scale");
    gd.addStringField("X Scale:", xstr);
    gd.addStringField("Y Scale:", ystr);
    if (isStack) gd.addStringField("Z Scale:", zstr);
    gd.setInsets(5, 0, 5);
    gd.addStringField("Width (pixels):", "" + width);
    gd.addStringField("Height (pixels):", "" + height);
    if (isStack) {
      String label = "Depth (images):";
      if (imp.isHyperStack()) {
        int slices = imp.getNSlices();
        int frames = imp.getNFrames();
        if (slices == 1 && frames > 1) {
          label = "Depth (frames):";
          oldDepth = frames;
        } else {
          label = "Depth (slices):";
          oldDepth = slices;
        }
      }
      gd.addStringField(label, "" + oldDepth);
    }
    fields = gd.getStringFields();
    for (int i = 0; i < fields.size(); i++) {
      ((TextField) fields.elementAt(i)).addTextListener(this);
      ((TextField) fields.elementAt(i)).addFocusListener(this);
    }
    xField = (TextField) fields.elementAt(0);
    yField = (TextField) fields.elementAt(1);
    if (isStack) {
      zField = (TextField) fields.elementAt(2);
      widthField = (TextField) fields.elementAt(3);
      heightField = (TextField) fields.elementAt(4);
      depthField = (TextField) fields.elementAt(5);
    } else {
      widthField = (TextField) fields.elementAt(2);
      heightField = (TextField) fields.elementAt(3);
    }
    fieldWithFocus = xField;
    gd.addChoice("Interpolation:", methods, methods[interpolationMethod]);
    if (bitDepth == 8 || bitDepth == 24)
      gd.addCheckbox("Fill with background color", fillWithBackground);
    gd.addCheckbox("Average when downsizing", averageWhenDownsizing);
    boolean hyperstack = imp.isHyperStack() || imp.isComposite();
    if (isStack && !hyperstack) gd.addCheckbox("Process entire stack", processStack);
    gd.addCheckbox("Create new window", newWindow);
    title = WindowManager.getUniqueName(imp.getTitle());
    gd.setInsets(10, 0, 0);
    gd.addStringField("Title:", title, 12);
    gd.showDialog();
    if (gd.wasCanceled()) return false;
    xstr = gd.getNextString();
    ystr = gd.getNextString();
    xscale = Tools.parseDouble(xstr, 0.0);
    yscale = Tools.parseDouble(ystr, 0.0);
    if (isStack) {
      zstr = gd.getNextString();
      zscale = Tools.parseDouble(ystr, 0.0);
    }
    String wstr = gd.getNextString();
    newWidth = (int) Tools.parseDouble(wstr, 0);
    newHeight = (int) Tools.parseDouble(gd.getNextString(), 0);
    if (newHeight != 0 && (wstr.equals("-") || wstr.equals("0")))
      newWidth = (int) (newHeight * (double) r.width / r.height);
    if (newWidth == 0 || newHeight == 0) {
      IJ.error("Scaler", "Width or height is 0");
      return false;
    }
    if (xscale > 0.0 && yscale > 0.0) {
      newWidth = (int) (r.width * xscale);
      newHeight = (int) (r.height * yscale);
    }
    if (isStack) newDepth = (int) Tools.parseDouble(gd.getNextString(), 0);
    interpolationMethod = gd.getNextChoiceIndex();
    if (bitDepth == 8 || bitDepth == 24) fillWithBackground = gd.getNextBoolean();
    averageWhenDownsizing = gd.getNextBoolean();
    if (isStack && !hyperstack) processStack = gd.getNextBoolean();
    if (hyperstack) processStack = true;
    newWindow = gd.getNextBoolean();
    if (xscale == 0.0) {
      xscale = (double) newWidth / r.width;
      yscale = (double) newHeight / r.height;
    }
    title = gd.getNextString();

    if (fillWithBackground) {
      Color bgc = Toolbar.getBackgroundColor();
      if (bitDepth == 8) bgValue = ip.getBestIndex(bgc);
      else if (bitDepth == 24) bgValue = bgc.getRGB();
    } else bgValue = 0.0;
    return true;
  }

  public void textValueChanged(TextEvent e) {
    Object source = e.getSource();
    double newXScale = xscale;
    double newYScale = yscale;
    double newZScale = zscale;
    if (source == xField && fieldWithFocus == xField) {
      String newXText = xField.getText();
      newXScale = Tools.parseDouble(newXText, 0);
      if (newXScale == 0) return;
      if (newXScale != xscale) {
        int newWidth = (int) (newXScale * r.width);
        widthField.setText("" + newWidth);
        if (constainAspectRatio) {
          yField.setText(newXText);
          int newHeight = (int) (newXScale * r.height);
          heightField.setText("" + newHeight);
        }
      }
    } else if (source == yField && fieldWithFocus == yField) {
      String newYText = yField.getText();
      newYScale = Tools.parseDouble(newYText, 0);
      if (newYScale == 0) return;
      if (newYScale != yscale) {
        int newHeight = (int) (newYScale * r.height);
        heightField.setText("" + newHeight);
      }
    } else if (source == zField && fieldWithFocus == zField) {
      String newZText = zField.getText();
      newZScale = Tools.parseDouble(newZText, 0);
      if (newZScale == 0) return;
      if (newZScale != zscale) {
        int nSlices = imp.getStackSize();
        if (imp.isHyperStack()) {
          int slices = imp.getNSlices();
          int frames = imp.getNFrames();
          if (slices == 1 && frames > 1) nSlices = frames;
          else nSlices = slices;
        }
        int newDepth = (int) (newZScale * nSlices);
        depthField.setText("" + newDepth);
      }
    } else if (source == widthField && fieldWithFocus == widthField) {
      int newWidth = (int) Tools.parseDouble(widthField.getText(), 0.0);
      if (newWidth != 0) {
        int newHeight = (int) (newWidth * (double) r.height / r.width);
        heightField.setText("" + newHeight);
        xField.setText("-");
        yField.setText("-");
        newXScale = 0.0;
        newYScale = 0.0;
      }
    } else if (source == depthField && fieldWithFocus == depthField) {
      int newDepth = (int) Tools.parseDouble(depthField.getText(), 0.0);
      if (newDepth != 0) {
        zField.setText("-");
        newZScale = 0.0;
      }
    }
    xscale = newXScale;
    yscale = newYScale;
    zscale = newZScale;
  }

  public void focusGained(FocusEvent e) {
    fieldWithFocus = e.getSource();
    if (fieldWithFocus == widthField) constainAspectRatio = true;
    else if (fieldWithFocus == yField) constainAspectRatio = false;
  }

  public void focusLost(FocusEvent e) {}
}
Example #2
0
/** This plugin implements the Image/Rotate/Arbitrarily command. */
public class Rotator implements ExtendedPlugInFilter, DialogListener {
  private int flags = DOES_ALL | SUPPORTS_MASKING | PARALLELIZE_STACKS;
  private static double angle = 15.0;
  private static boolean fillWithBackground;
  private static boolean enlarge;
  private static int gridLines = 1;
  private ImagePlus imp;
  private int bitDepth;
  private boolean canEnlarge;
  private boolean isEnlarged;
  private GenericDialog gd;
  private PlugInFilterRunner pfr;
  private String[] methods = ImageProcessor.getInterpolationMethods();
  private static int interpolationMethod = ImageProcessor.BILINEAR;

  public int setup(String arg, ImagePlus imp) {
    this.imp = imp;
    if (imp != null) {
      bitDepth = imp.getBitDepth();
      Roi roi = imp.getRoi();
      Rectangle r = roi != null ? roi.getBounds() : null;
      canEnlarge =
          r == null
              || (r.x == 0 && r.y == 0 && r.width == imp.getWidth() && r.height == imp.getHeight());
    }
    return flags;
  }

  public void run(ImageProcessor ip) {
    if (enlarge && gd.wasOKed())
      synchronized (this) {
        if (!isEnlarged) {
          enlargeCanvas();
          isEnlarged = true;
        }
      }
    if (isEnlarged) { // enlarging may have made the ImageProcessor invalid, also for the parallel
                      // threads
      int slice = pfr.getSliceNumber();
      if (imp.getStackSize() == 1) ip = imp.getProcessor();
      else ip = imp.getStack().getProcessor(slice);
    }
    ip.setInterpolationMethod(interpolationMethod);
    if (fillWithBackground) {
      Color bgc = Toolbar.getBackgroundColor();
      if (bitDepth == 8) ip.setBackgroundValue(ip.getBestIndex(bgc));
      else if (bitDepth == 24) ip.setBackgroundValue(bgc.getRGB());
    } else ip.setBackgroundValue(0);
    ip.rotate(angle);
    if (!gd.wasOKed()) drawGridLines(gridLines);
    if (isEnlarged && imp.getStackSize() == 1) {
      imp.changes = true;
      imp.updateAndDraw();
      Undo.setup(Undo.COMPOUND_FILTER_DONE, imp);
    }
  }

  void enlargeCanvas() {
    imp.unlock();
    if (imp.getStackSize() == 1) Undo.setup(Undo.COMPOUND_FILTER, imp);
    IJ.run("Select All");
    IJ.run("Rotate...", "angle=" + angle);
    Roi roi = imp.getRoi();
    Rectangle r = roi.getBounds();
    if (r.width < imp.getWidth()) r.width = imp.getWidth();
    if (r.height < imp.getHeight()) r.height = imp.getHeight();
    IJ.showStatus("Rotate: Enlarging...");
    IJ.run(
        "Canvas Size...",
        "width="
            + r.width
            + " height="
            + r.height
            + " position=Center "
            + (fillWithBackground ? "" : "zero"));
    IJ.showStatus("Rotating...");
  }

  void drawGridLines(int lines) {
    ImageCanvas ic = imp.getCanvas();
    if (ic == null) return;
    if (lines == 0) {
      ic.setDisplayList(null);
      return;
    }
    GeneralPath path = new GeneralPath();
    float width = imp.getWidth();
    float height = imp.getHeight();
    float xinc = width / lines;
    float yinc = height / lines;
    float xstart = xinc / 2f;
    float ystart = yinc / 2f;
    for (int i = 0; i < lines; i++) {
      path.moveTo(xstart + xinc * i, 0f);
      path.lineTo(xstart + xinc * i, height);
      path.moveTo(0f, ystart + yinc * i);
      path.lineTo(width, ystart + yinc * i);
    }
    ic.setDisplayList(path, null, null);
  }

  public int showDialog(ImagePlus imp, String command, PlugInFilterRunner pfr) {
    this.pfr = pfr;
    String macroOptions = Macro.getOptions();
    if (macroOptions != null) {
      if (macroOptions.indexOf(" interpolate") != -1)
        macroOptions.replaceAll(" interpolate", " interpolation=Bilinear");
      else if (macroOptions.indexOf(" interpolation=") == -1)
        macroOptions = macroOptions + " interpolation=None";
      Macro.setOptions(macroOptions);
    }
    gd = new GenericDialog("Rotate", IJ.getInstance());
    gd.addNumericField("Angle (degrees):", angle, (int) angle == angle ? 1 : 2);
    gd.addNumericField("Grid Lines:", gridLines, 0);
    gd.addChoice("Interpolation:", methods, methods[interpolationMethod]);
    if (bitDepth == 8 || bitDepth == 24)
      gd.addCheckbox("Fill with Background Color", fillWithBackground);
    if (canEnlarge) gd.addCheckbox("Enlarge Image to Fit Result", enlarge);
    else enlarge = false;
    gd.addPreviewCheckbox(pfr);
    gd.addDialogListener(this);
    gd.showDialog();
    drawGridLines(0);
    if (gd.wasCanceled()) {
      return DONE;
    }
    if (!enlarge) flags |= KEEP_PREVIEW; // standard filter without enlarge
    else if (imp.getStackSize() == 1) flags |= NO_CHANGES; // undoable as a "compound filter"
    return IJ.setupDialog(imp, flags);
  }

  public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
    angle = gd.getNextNumber();
    // only check for invalid input to "angle", don't care about gridLines
    if (gd.invalidNumber()) {
      if (gd.wasOKed()) IJ.error("Angle is invalid.");
      return false;
    }
    gridLines = (int) gd.getNextNumber();
    interpolationMethod = gd.getNextChoiceIndex();
    if (bitDepth == 8 || bitDepth == 24) fillWithBackground = gd.getNextBoolean();
    if (canEnlarge) enlarge = gd.getNextBoolean();
    return true;
  }

  public void setNPasses(int nPasses) {}
}