gt: 		if (xscale>0.0 && yscale>0.0) {
context: package ij.plugin;
  import ij.*;
  import ij.gui.*;
  import ij.process.*;
  import ij.measure.*;
  import ij.util.Tools;
  import java.awt.*;
  import java.awt.event.*;
  import java.util.*;
  
  /** 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 boolean doZScaling;
      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;
  		doZScaling = newDepth>0 && newDepth!=oldDepth;
  		if (doZScaling) {
  			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 {
  				Overlay overlay = imp.getOverlay();
  				if (imp.getHideOverlay())
  					overlay = null;
  				if (overlay!=null && overlay.size()!=1)
  					overlay = null;
  				if (overlay!=null)
  					overlay = overlay.duplicate();
  				scale(ip, overlay);
  			}
  		}
  		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;
  		}
  		Overlay overlay = imp.getOverlay();
  		if (imp.getHideOverlay())
  			overlay = null;
  		if (overlay!=null) {
  			overlay = overlay.duplicate();
  			Overlay overlay2 = new Overlay();
  			for (int i=0; i<overlay.size(); i++) {
  				Roi roi = overlay.get(i);
  				Rectangle bounds = roi.getBounds();
  				if (roi instanceof ImageRoi && bounds.x==0 && bounds.y==0) {
  					ImageRoi iroi = (ImageRoi)roi;
  					ImageProcessor processor = iroi.getProcessor();
  					processor.setInterpolationMethod(method);
  					processor = processor.resize(newWidth, newHeight, averageWhenDownsizing);
  					iroi.setProcessor(processor);
  					overlay2.add(iroi);
  				}
  			}
  			if (overlay2.size()>0)
  				imp2.setOverlay(overlay2);
  		}
  		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 (doZScaling) {
  			Resizer resizer = new Resizer();
  			resizer.setAverageWhenDownsizing(averageWhenDownsizing);
  			imp2 = resizer.zScale(imp2, newDepth, interpolationMethod);
  		}
  		if (imp2!=null) {
  			imp2.show();
  			imp2.changes = true;
  		}
  	}
  
  	private void scale(ImageProcessor ip, Overlay overlay) {
  		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;
  			}
  			if (overlay!=null) {
  				Roi roi = overlay.get(0);
  				Rectangle bounds = roi.getBounds();
  				if (roi instanceof ImageRoi && bounds.x==0 && bounds.y==0) {
  					ImageRoi iroi = (ImageRoi)roi;
  					ImageProcessor processor = iroi.getProcessor();
  					processor.setInterpolationMethod(interpolationMethod);
  					processor =processor.resize(newWidth, newHeight, averageWhenDownsizing);
  					iroi.setProcessor(processor);
  					imp2.setOverlay(new Overlay(iroi));
  				}
  			}
  			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(zstr, 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;
  		}
  