package ij.plugin;
import ij.*;
import ij.plugin.filter.*;
import ij.process.*;
import ij.gui.*;
import java.awt.*;

/** This plugin implements the Image/Adjust/Canvas Size command.
	It changes the canvas size of an image or stack without resizing the image.
	The border is filled with the current background color.
	@author Jeffrey Kuhn (jkuhn at ccwf.cc.utexas.edu)
*/
public class CanvasResizer implements PlugIn {
	boolean zeroFill = Prefs.get("resizer.zero", false);

	public void run(String arg) {
		int wOld, hOld, wNew, hNew;
		boolean fIsStack = false;

		ImagePlus imp = IJ.getImage();
		wOld = imp.getWidth();
		hOld = imp.getHeight();
		if (!imp.okToDeleteRoi()) return;

		ImageStack stackOld = imp.getStack();
		if ((stackOld != null) && (stackOld.getSize() > 1))
			fIsStack = true;

		String[] sPositions = {
			"Top-Left", "Top-Center", "Top-Right", 
			"Center-Left", "Center", "Center-Right",
			"Bottom-Left", "Bottom-Center", "Bottom-Right"
		};
			
		String strTitle = fIsStack ? "Resize Stack Canvas" : "Resize Image Canvas";
		GenericDialog gd = new GenericDialog(strTitle);
		gd.addNumericField("Width:", wOld, 0, 5, "pixels");
		gd.addNumericField("Height:", hOld, 0, 5, "pixels");
		gd.addChoice("Position:", sPositions, sPositions[4]);
		gd.addCheckbox("Zero Fill", zeroFill);
		gd.showDialog();
		if (gd.wasCanceled())
			return;
			
		wNew = (int)gd.getNextNumber();
		hNew = (int)gd.getNextNumber();
		int iPos = gd.getNextChoiceIndex();
		zeroFill = gd.getNextBoolean();
		Prefs.set("resizer.zero", zeroFill);
		
		int xOff, yOff;
		int xC = (wNew - wOld)/2;	// offset for centered
		int xR = (wNew - wOld);		// offset for right
		int yC = (hNew - hOld)/2;	// offset for centered
		int yB = (hNew - hOld);		// offset for bottom
		
		switch(iPos) {
		case 0:	// TL
			xOff=0;	yOff=0; break;
		case 1:	// TC
			xOff=xC; yOff=0; break;
		case 2:	// TR
			xOff=xR; yOff=0; break;
		case 3: // CL
			xOff=0; yOff=yC; break;
		case 4: // C
			xOff=xC; yOff=yC; break;
		case 5:	// CR
			xOff=xR; yOff=yC; break;
		case 6: // BL
			xOff=0; yOff=yB; break;
		case 7: // BC
			xOff=xC; yOff=yB; break;
		case 8: // BR
			xOff=xR; yOff=yB; break;
		default: // center
			xOff=xC; yOff=yC; break;
		}
		
		if (fIsStack) {
			ImageStack stackNew = expandStack(stackOld, wNew, hNew, xOff, yOff);
			imp.setStack(null, stackNew);
		} else {
			if (!IJ.macroRunning())
				Undo.setup(Undo.COMPOUND_FILTER, imp);
			ImageWindow win = imp.getWindow();
			if (win!=null && (win instanceof PlotWindow))
				((PlotWindow)win).getPlot().setFrozen(true);
			ImageProcessor newIP = expandImage(imp.getProcessor(), wNew, hNew, xOff, yOff);
			imp.setProcessor(null, newIP);
			if (!IJ.macroRunning())
				Undo.setup(Undo.COMPOUND_FILTER_DONE, imp);
		}
		Overlay overlay = imp.getOverlay();
		if (overlay!=null)
			overlay.translate(xOff, yOff);
	}
	
	public ImageStack expandStack(ImageStack stackOld, int wNew, int hNew, int xOff, int yOff) {
		int nFrames = stackOld.getSize();
		ImageProcessor ipOld = stackOld.getProcessor(1);		
		ImageStack stackNew = new ImageStack(wNew, hNew, stackOld.getColorModel());
		ImageProcessor ipNew;
		
		for (int i=1; i<=nFrames; i++) {
			IJ.showProgress((double)i/nFrames);
			ipNew = ipOld.createProcessor(wNew, hNew);
			if (zeroFill)
				ipNew.setValue(0.0);
			else 
				ipNew.setGlobalBackgroundColor();
			ipNew.fill();
			ipNew.insert(stackOld.getProcessor(i), xOff, yOff);
			stackNew.addSlice(stackOld.getSliceLabel(i), ipNew);
		}
		return stackNew;
	}
	
	public ImageProcessor expandImage(ImageProcessor ipOld, int wNew, int hNew, int xOff, int yOff) {
		ImageProcessor ipNew = ipOld.createProcessor(wNew, hNew);
		if (zeroFill)
			ipNew.setValue(0.0);
		else 
			ipNew.setGlobalBackgroundColor();
		ipNew.fill();
		ipNew.insert(ipOld, xOff, yOff);
		return ipNew;
	}

}

