package ij.plugin;
import java.awt.*;
import ij.*;
import ij.process.*;
import ij.gui.*;
public class RGBStackConverter implements PlugIn, DialogListener {
private int channels1, slices1, frames1;
private int slices2, frames2;
private int width, height;
private double imageSize;
private static boolean staticKeep = true;
private boolean keep;
private ImagePlus image;
public void run(String arg) {
ImagePlus imp = image;
if (imp==null)
imp = IJ.getImage();
if (!IJ.isMacro()) keep = staticKeep;
CompositeImage cimg = imp.isComposite()?(CompositeImage)imp:null;
int size = imp.getStackSize();
if ((size<2||size>3) && cimg==null) {
IJ.error("A 2 or 3 image stack, or a HyperStack, required");
return;
}
int type = imp.getType();
if (cimg==null && !(type==ImagePlus.GRAY8 || type==ImagePlus.GRAY16)) {
IJ.error("8-bit or 16-bit grayscale stack required");
return;
}
if (!imp.lock())
return;
Undo.reset();
String title = imp.getTitle()+" (RGB)";
if (cimg!=null)
compositeToRGB(cimg, title);
else if (type==ImagePlus.GRAY16) {
sixteenBitsToRGB(imp);
} else {
ImagePlus imp2 = imp.createImagePlus();
imp2.setStack(title, imp.getStack());
ImageConverter ic = new ImageConverter(imp2);
ic.convertRGBStackToRGB();
imp2.show();
}
imp.unlock();
}
public static void convertToRGB(ImagePlus imp) {
if (!imp.isComposite())
throw new IllegalArgumentException("Multi-channel image required");
RGBStackConverter converter = new RGBStackConverter();
ImageWindow win = imp.getWindow();
Point location = null;
if (win!=null) {
location = win.getLocation();
imp.hide();
}
converter.image = imp;
converter.run("");
if (win!=null) {
ImageWindow.setNextLocation(location);
imp.show();
}
}
void compositeToRGB(CompositeImage imp, String title) {
int channels = imp.getNChannels();
int slices = imp.getNSlices();
int frames = imp.getNFrames();
int images = channels*slices*frames;
if (channels==images) {
compositeImageToRGB(imp, title);
return;
}
width = imp.getWidth();
height = imp.getHeight();
imageSize = width*height*4.0/(1024.0*1024.0);
channels1 = imp.getNChannels();
slices1 = slices2 = imp.getNSlices();
frames1 = frames2 = imp.getNFrames();
int c1 = imp.getChannel();
int z1 = imp.getSlice();
int t2 = imp.getFrame();
if (image!=null) {
slices2 = slices1;
frames2 = frames1;
keep = false;
} else {
if (!showDialog())
return;
}
String title2 = keep?WindowManager.getUniqueName(imp.getTitle()):imp.getTitle();
ImagePlus imp2 = imp.createHyperStack(title2, 1, slices2, frames2, 24);
convertHyperstack(imp, imp2);
if (imp.getWindow()==null && !keep) {
imp.setImage(imp2);
imp.setOverlay(imp2.getOverlay());
return;
}
imp2.setOpenAsHyperStack(slices2>1||frames2>1);
Object info = imp.getProperty("Info");
if (info!=null) imp2.setProperty("Info", info);
imp2.setProperties(imp.getPropertiesAsArray());
imp2.show();
if (!keep) {
imp.changes = false;
imp.close();
}
if (imp2.getWindow()!=null)
IJ.selectWindow(imp2.getID());
}
public void convertHyperstack(ImagePlus imp, ImagePlus imp2) {
int slices = imp2.getNSlices();
int frames = imp2.getNFrames();
int c1 = imp.getChannel();
int z1 = imp.getSlice();
int t1 = imp.getFrame();
int i = 1;
int c = 1;
ImageStack stack = imp.getStack();
ImageStack stack2 = imp2.getStack();
imp.setPositionWithoutUpdate(c1, 1, 1);
ImageProcessor ip = imp.getProcessor();
double min = ip.getMin();
double max = ip.getMax();
boolean hsbStack = imp.getProp("HSB_Stack")!=null;
for (int z=1; z<=slices; z++) {
if (slices==1) z = z1;
for (int t=1; t<=frames; t++) {
if (frames==1) t = t1;
imp.setPositionWithoutUpdate(c1, z, t);
boolean isHSB = hsbStack && imp.getNChannels()==3;
int n2 = imp2.getStackIndex(c1, z, t);
if (isHSB) {
ImagePlus hsbImp = new Duplicator().run(imp, 1, 3, z, z, t, t);
ImageConverter ic = new ImageConverter(hsbImp);
ic.convertHSBToRGB();
stack2.setPixels(hsbImp.getProcessor().getPixels(), n2);
} else {
Image img = imp.getImage();
stack2.setPixels((new ColorProcessor(img)).getPixels(), n2);
}
}
}
imp.setPosition(c1, z1, t1);
imp2.resetStack();
imp2.setPosition(1, 1, 1);
Overlay overlay = imp.getOverlay();
if (overlay!=null) {
int firstC = c1, lastC = c1, firstZ = z1, lastZ = z1, firstT = t1, lastT = t1;
if (imp.isComposite() && ((CompositeImage)imp).getMode()==IJ.COMPOSITE) {
firstC = 1;
lastC = imp.getNChannels();
}
if (slices2>1) {firstZ = 1; lastZ = slices2;}
if (frames2>1) {firstT = 1; lastT = frames2;}
Overlay overlay2 = overlay.duplicate();
if (slices2>1 && frames2>1)
overlay2.crop(firstC, lastC, firstZ, lastZ, firstT, lastT); else
overlay2.crop(c1, c1, firstZ, lastZ, firstT, lastT); imp2.setOverlay(overlay2);
}
}
void compositeImageToRGB(CompositeImage imp, String title) {
if (imp.getMode()==IJ.COMPOSITE) {
ImagePlus imp2 = imp.createImagePlus();
imp.updateImage();
imp2.setProcessor(title, new ColorProcessor(imp.getImage()));
Overlay overlay = imp.getOverlay();
Overlay overlay2 = null;
if (overlay!=null) {
overlay2 = overlay.duplicate();
overlay2.crop(1, imp.getNChannels());
imp2.setOverlay(overlay2);
}
if (image!=null && imp.getWindow()==null) {
imp.setImage(imp2);
imp.setOverlay(overlay2);
} else
imp2.show();
return;
}
ImageStack stack = new ImageStack(imp.getWidth(), imp.getHeight());
int c = imp.getChannel();
int n = imp.getNChannels();
for (int i=1; i<=n; i++) {
imp.setPositionWithoutUpdate(i, 1, 1);
stack.addSlice(null, new ColorProcessor(imp.getImage()));
}
imp.setPosition(c, 1, 1);
ImagePlus imp2 = imp.createImagePlus();
imp2.setStack(title, stack);
Object info = imp.getProperty("Info");
if (info!=null) imp2.setProperty("Info", info);
imp2.setProperties(imp.getPropertiesAsArray());
Overlay overlay = imp.getOverlay();
Overlay overlay2 = null;
if (overlay!=null) {
overlay2 = overlay.duplicate();
overlay2.crop(1, imp.getNChannels());
imp2.setOverlay(overlay2);
}
if (image!=null && imp.getWindow()==null) {
imp.setImage(imp2);
imp.setOverlay(overlay2);
} else {
imp2.show();
imp2.setSlice(c);
}
}
void sixteenBitsToRGB(ImagePlus imp) {
Roi roi = imp.getRoi();
int width, height;
Rectangle r;
if (roi!=null) {
r = roi.getBounds();
width = r.width;
height = r.height;
} else
r = new Rectangle(0,0,imp.getWidth(),imp.getHeight());
ImageProcessor ip;
ImageStack stack1 = imp.getStack();
ImageStack stack2 = new ImageStack(r.width, r.height);
for (int i=1; i<=stack1.getSize(); i++) {
ip = stack1.getProcessor(i);
ip.setRoi(r);
ImageProcessor ip2 = ip.crop();
ip2 = ip2.convertToByte(true);
stack2.addSlice(null, ip2);
}
ImagePlus imp2 = imp.createImagePlus();
imp2.setStack(imp.getTitle()+" (RGB)", stack2);
ImageConverter ic = new ImageConverter(imp2);
ic.convertRGBStackToRGB();
imp2.show();
}
boolean showDialog() {
GenericDialog gd = new GenericDialog("Convert to RGB");
gd.setInsets(10, 20, 5);
gd.addMessage("Create RGB image with:");
gd.setInsets(0, 35, 0);
if (slices1!=1) gd.addCheckbox("Slices ("+slices1+")", true);
gd.setInsets(0, 35, 0);
if (frames1!=1) gd.addCheckbox("Frames ("+frames1+")", true);
gd.setInsets(5, 20, 0);
gd.addMessage(getNewDimensions()+" ");
gd.setInsets(15, 20, 0);
gd.addCheckbox("Keep source", keep);
gd.addDialogListener(this);
gd.showDialog();
if (gd.wasCanceled())
return false;
else
return true;
}
public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
if (IJ.isMacOSX()) IJ.wait(100);
if (slices1!=1) slices2 = gd.getNextBoolean()?slices1:1;
if (frames1!=1) frames2 = gd.getNextBoolean()?frames1:1;
keep = gd.getNextBoolean();
if (!IJ.isMacro()) staticKeep = keep;
((Label)gd.getMessage()).setText(getNewDimensions());
return true;
}
String getNewDimensions() {
String s1 = slices2>1?"x"+slices2:"";
String s2 = frames2>1?"x"+frames2:"";
String s = width+"x"+height+s1+s2;
s += " ("+(int)Math.round(imageSize*slices2*frames2)+"MB)";
return(s);
}
}