package ij.plugin; import ij.*; import ij.process.*; import ij.gui.*; import java.awt.*; /** This plugin implements the Image/Stacks/Combine command. It combines two stacks (w1xh1xd1 and w2xh2xd2) to create a new w1+w2 x max(h1,h2) x max(d1,d2) stack. For example, a 256x256x40 and a 256x256x30 stack would be combined into one 512x256x40 stack. If "Vertical" is checked, create a new max(w1+w2) x (h1+h2) x max(d1,d2) stack. Unused areas in the combined stack are filled with the background color. */ public class StackCombiner implements PlugIn { ImagePlus imp1; ImagePlus imp2; static boolean vertical; public void run(String arg) { if (!showDialog()) return; if (imp1.getType()!=imp2.getType() || imp1.isHyperStack() || imp2.isHyperStack()) {error(); return;} ImageStack stack1 = imp1.getStack(); ImageStack stack2 = imp2.getStack(); ImageStack stack3 = vertical?combineVertically(stack1, stack2):combineHorizontally(stack1, stack2); imp1.changes = false; imp1.close(); imp2.changes = false; imp2.close(); new ImagePlus("Combined Stacks", stack3).show(); } public ImageStack combineHorizontally(ImageStack stack1, ImageStack stack2) { int d1 = stack1.getSize(); int d2 = stack2.getSize(); int d3 = Math.max(d1, d2); int w1 = stack1.getWidth(); int h1 = stack1.getHeight(); int w2 = stack2.getWidth(); int h2 = stack2.getHeight(); int w3 = w1 + w2; int h3 = Math.max(h1, h2); ImageStack stack3 = new ImageStack(w3, h3, stack1.getColorModel()); ImageProcessor ip = stack1.getProcessor(1); ImageProcessor ip1, ip2, ip3; Color background = Toolbar.getBackgroundColor(); for (int i=1; i<=d3; i++) { IJ.showProgress((double)i/d3); ip3 = ip.createProcessor(w3, h3); if (h1!=h2) { ip3.setColor(background); ip3.fill(); } if (i<=d1) { ip3.insert(stack1.getProcessor(1),0,0); if (stack2!=stack1) stack1.deleteSlice(1); } if (i<=d2) { ip3.insert(stack2.getProcessor(1),w1,0); stack2.deleteSlice(1); } stack3.addSlice(null, ip3); } return stack3; } public ImageStack combineVertically(ImageStack stack1, ImageStack stack2) { int d1 = stack1.getSize(); int d2 = stack2.getSize(); int d3 = Math.max(d1, d2); int w1 = stack1.getWidth(); int h1 = stack1.getHeight(); int w2 = stack2.getWidth(); int h2 = stack2.getHeight(); int w3 = Math.max(w1, w2); int h3 = h1 + h2; ImageStack stack3 = new ImageStack(w3, h3, stack1.getColorModel()); ImageProcessor ip = stack1.getProcessor(1); ImageProcessor ip1, ip2, ip3; Color background = Toolbar.getBackgroundColor(); for (int i=1; i<=d3; i++) { IJ.showProgress((double)i/d3); ip3 = ip.createProcessor(w3, h3); if (w1!=w2) { ip3.setColor(background); ip3.fill(); } if (i<=d1) { ip3.insert(stack1.getProcessor(1),0,0); if (stack2!=stack1) stack1.deleteSlice(1); } if (i<=d2) { ip3.insert(stack2.getProcessor(1),0,h1); stack2.deleteSlice(1); } stack3.addSlice(null, ip3); } return stack3; } boolean showDialog() { int[] wList = WindowManager.getIDList(); if (wList==null || wList.length<2) { error(); return false; } String[] titles = new String[wList.length]; for (int i=0; i<wList.length; i++) { ImagePlus imp = WindowManager.getImage(wList[i]); titles[i] = imp!=null?imp.getTitle():""; } GenericDialog gd = new GenericDialog("Combiner"); gd.addChoice("Stack1:", titles, titles[0]); gd.addChoice("Stack2:", titles, titles[1]); gd.addCheckbox("Combine vertically", false); gd.addHelp(IJ.URL+"/docs/menus/image.html#combine"); gd.showDialog(); if (gd.wasCanceled()) return false; int[] index = new int[3]; int index1 = gd.getNextChoiceIndex(); int index2 = gd.getNextChoiceIndex(); imp1 = WindowManager.getImage(wList[index1]); imp2 = WindowManager.getImage(wList[index2]); vertical = gd.getNextBoolean(); return true; } void error() { IJ.showMessage("StackCombiner", "This command requires two stacks\n" +"that are the same data type."); } }