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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
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 {
public static final String GRID = "|GRID|";
private int flags = DOES_ALL|SUPPORTS_MASKING;
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;
private Overlay overlay;
private boolean done;
public int setup(String arg, ImagePlus imp) {
this.imp = imp;
if (imp!=null) {
bitDepth = imp.getBitDepth();
Roi roi = imp.getRoi();
if (roi!=null && roi.isLine())
roi = null;
overlay = imp.getOverlay();
if (roi!=null && overlay!=null && Macro.getOptions()==null) {
String msg = "This image has an overlay so the\nselection will be removed.";
if (!IJ.showMessageWithCancel("Rotator", msg))
return DONE;
imp.deleteRoi();
}
Rectangle r = roi!=null?roi.getBounds():null;
canEnlarge = r==null || (r.x==0&&r.y==0&&r.width==imp.getWidth()&&r.height==imp.getHeight());
if (imp.getDisplayMode()==IJ.COMPOSITE) { // setup Undo for composite color stacks
Undo.setup(Undo.TRANSFORM, imp);
flags = flags | NO_UNDO_RESET;
}
Undo.saveOverlay(imp);
if (overlay==null)
overlay = new Overlay();
}
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)
ip.setBackgroundColor(Toolbar.getBackgroundColor());
else
ip.setBackgroundValue(0);
ip.rotate(angle);
if (!gd.wasOKed())
drawGridLines(gridLines);
if (overlay!=null && !imp.getHideOverlay()) {
Overlay overlay2 = overlay.rotate(angle, ip.getWidth()/2, ip.getHeight()/2);
if (overlay2!=null && overlay2.size()>0)
imp.setOverlay(overlay2);
}
if (isEnlarged && imp.getStackSize()==1) {
imp.changes = true;
imp.updateAndDraw();
Undo.setup(Undo.COMPOUND_FILTER_DONE, imp);
}
if (done) { // remove grid
Overlay ovly = imp.getOverlay();
if (ovly!=null) {
ovly.remove(GRID);
if (ovly.size()==0) imp.setOverlay(null);
}
}
}
void enlargeCanvas() {
imp.unlock();
IJ.run(imp, "Select All", "");
IJ.run(imp, "Rotate...", "angle="+angle);
Roi roi = imp.getRoi();
imp.deleteRoi();
Rectangle2D.Double fb = roi.getFloatBounds();
Rectangle r = new Rectangle((int)Math.round(fb.x),(int)Math.round(fb.y),(int)Math.round(fb.width),(int)Math.round(fb.height));
if (r.width<imp.getWidth()) r.width = imp.getWidth();
if (r.height<imp.getHeight()) r.height = imp.getHeight();
IJ.showStatus("Rotate: Enlarging...");
if (imp.getStackSize()==1)
Undo.setup(Undo.COMPOUND_FILTER, imp);
IJ.run(imp, "Canvas Size...", "width="+r.width+" height="+r.height+" position=Center "+(fillWithBackground?"":"zero"));
IJ.showStatus("Rotating...");
}
void drawGridLines(int lines) {
if (overlay==null)
return;
overlay.remove(GRID);
if (lines==0)
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);
}
Roi roi = new ShapeRoi(path);
roi.setName(GRID);
roi.setStrokeWidth(0);
overlay.add(roi);
}
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 = macroOptions.replaceAll(" interpolate", " interpolation=Bilinear");
else if (macroOptions.indexOf(" interpolation=")==-1)
macroOptions = macroOptions+" interpolation=None";
Macro.setOptions(macroOptions);
}
gd = new GenericDialog("Rotate");
gd.addSlider("Angle:", -90, 90, angle, 0.1);
gd.addNumericField("Grid lines:", gridLines, 0);
gd.addChoice("Interpolation:", methods, methods[interpolationMethod]);
gd.addCheckbox("Fill with background color", fillWithBackground);
if (canEnlarge)
gd.addCheckbox("Enlarge image", enlarge);
else
enlarge = false;
gd.addPreviewCheckbox(pfr);
gd.addDialogListener(this);
gd.showDialog();
if (gd.wasCanceled()) {
if (overlay.size()>0) {
overlay.remove(GRID);
imp.setOverlay(overlay);
}
return DONE;
}
Overlay ovly = imp.getOverlay();
if (ovly!=null) {
ovly.remove(GRID);
if (ovly.size()==0) imp.setOverlay(null);
}
if (enlarge)
flags |= NO_CHANGES; // undoable as a "compound filter"
else if (imp.getStackSize()==1)
flags |= KEEP_PREVIEW; // standard filter without enlarge
done = true;
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();
fillWithBackground = gd.getNextBoolean();
if (canEnlarge)
enlarge = gd.getNextBoolean();
return true;
}
/** Returns the current angle. */
public static double getAngle() {
return angle;
}
public void setNPasses(int nPasses) {
}
}
|