1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
package ij.plugin.filter;
import ij.*;
import ij.gui.*;
import ij.process.*;
import java.awt.*;
import java.awt.geom.*;
/** 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");
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) {
}
}
|