Skip to content

Commit 8360e9a

Browse files
committed
2025.08.21 (1.54q19; Multi-point selections)
1 parent 5f3faaf commit 8360e9a

File tree

10 files changed

+102
-136
lines changed

10 files changed

+102
-136
lines changed

ij/IJ.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,9 +1349,7 @@ public static void makePoint(int x, int y) {
13491349
ImagePlus img = getImage();
13501350
Roi roi = img.getRoi();
13511351
if (shiftKeyDown() && roi!=null && roi.getType()==Roi.POINT) {
1352-
Polygon p = roi.getPolygon();
1353-
p.addPoint(x, y);
1354-
img.setRoi(new PointRoi(p.xpoints, p.ypoints, p.npoints));
1352+
((PointRoi)roi).addUserPoint(null, x, y);
13551353
IJ.setKeyUp(KeyEvent.VK_SHIFT);
13561354
} else if (altKeyDown() && roi!=null && roi.getType()==Roi.POINT) {
13571355
((PolygonRoi)roi).deleteHandle(x, y);
@@ -1365,9 +1363,7 @@ public static void makePoint(double x, double y) {
13651363
ImagePlus img = getImage();
13661364
Roi roi = img.getRoi();
13671365
if (shiftKeyDown() && roi!=null && roi.getType()==Roi.POINT) {
1368-
Polygon p = roi.getPolygon();
1369-
p.addPoint((int)Math.round(x), (int)Math.round(y));
1370-
img.setRoi(new PointRoi(p.xpoints, p.ypoints, p.npoints));
1366+
((PointRoi)roi).addUserPoint(null, x, y);
13711367
IJ.setKeyUp(KeyEvent.VK_SHIFT);
13721368
} else if (altKeyDown() && roi!=null && roi.getType()==Roi.POINT) {
13731369
((PolygonRoi)roi).deleteHandle(x, y);

ij/ImageJ.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public class ImageJ extends Frame implements ActionListener,
7979

8080
/** Plugins should call IJ.getVersion() or IJ.getFullVersion() to get the version string. */
8181
public static final String VERSION = "1.54q";
82-
public static final String BUILD = "14";
82+
public static final String BUILD = "19";
8383
public static Color backgroundColor = new Color(237,237,237);
8484
/** SansSerif, 12-point, plain font. */
8585
public static final Font SansSerif12 = new Font("SansSerif", Font.PLAIN, 12);

ij/gui/HistogramPlot.java

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ public void draw(ImagePlus imp, int bins, double histMin, double histMax, int yM
6969
stats = imp.getStatistics(AREA+MEAN+MODE+MIN_MAX+(limitToThreshold?LIMIT:0), bins, histMin, histMax);
7070
draw(imp, stats);
7171
}
72-
72+
73+
/** For RGB images in mode 'RGB' = R+G+B, i.e., the sum of the red + green + blue histograms,
74+
* we create an image of the three color channels next to each other */
7375
private ImageStatistics RGBHistogram(ImagePlus imp, int bins, double histMin, double histMax) {
7476
ImageProcessor ip = (ColorProcessor)imp.getProcessor();
7577
ip = ip.crop();
@@ -203,8 +205,15 @@ int scaleDown(ImageProcessor ip, double threshold) {
203205
}
204206

205207
void drawPlot(long maxCount, ImageProcessor ip) {
208+
if (frame == null)
209+
frame = getDefaultFrame();
210+
drawPlot(histogram, maxCount, ip, frame, frameColor);
211+
}
212+
213+
/** Draws the histogram with linear scaling and the frame.
214+
* Also used by HistogramWindow */
215+
static void drawPlot(long[] histogram, long maxCount, ImageProcessor ip, Rectangle frame, Color frameColor) {
206216
if (maxCount==0) maxCount = 1;
207-
frame = new Rectangle(XMARGIN, YMARGIN, HIST_WIDTH, HIST_HEIGHT);
208217
if (histogram.length==256) {
209218
double scale2 = HIST_WIDTH/256.0;
210219
int barWidth = 1;
@@ -243,9 +252,17 @@ void drawPlot(long maxCount, ImageProcessor ip) {
243252
}
244253

245254
void drawLogPlot (long maxCount, ImageProcessor ip) {
246-
frame = new Rectangle(XMARGIN, YMARGIN, HIST_WIDTH, HIST_HEIGHT);
255+
if (frame == null)
256+
frame = getDefaultFrame();
257+
drawLogPlot(histogram, maxCount, ip, frame);
258+
}
259+
260+
/** Draws the logarithm of histogram values in gray. To be called before the regular plot,
261+
* which is then in the foreground.
262+
* Also used by HistogramWindow */
263+
static void drawLogPlot(long[] histogram, long maxCount, ImageProcessor ip, Rectangle frame) {
247264
ip.drawRect(frame.x-1, frame.y, frame.width+2, frame.height+1);
248-
double max = Math.log(maxCount);
265+
double max = Math.log(maxCount + 0.5);
249266
ip.setColor(Color.gray);
250267
if (histogram.length==256) {
251268
double scale2 = HIST_WIDTH/256.0;
@@ -254,7 +271,7 @@ void drawLogPlot (long maxCount, ImageProcessor ip) {
254271
if (SCALE>2) barWidth=3;
255272
for (int i=0; i < 256; i++) {
256273
int x =(int)(i*scale2);
257-
int y = histogram[i]==0?0:(int)(HIST_HEIGHT*Math.log(histogram[i])/max);
274+
int y = histogram[i]==0?0:(int)Math.max(HIST_HEIGHT*Math.log(histogram[i]+0.5)/max, 1);
258275
if (y>HIST_HEIGHT) y = HIST_HEIGHT;
259276
for (int j = 0; j<barWidth; j++)
260277
ip.drawLine(x+j+XMARGIN, YMARGIN+HIST_HEIGHT, x+j+XMARGIN, YMARGIN+HIST_HEIGHT-y);
@@ -263,7 +280,7 @@ void drawLogPlot (long maxCount, ImageProcessor ip) {
263280
int index, y;
264281
for (int i = 0; i<HIST_WIDTH; i++) {
265282
index = (int)(i*(double)histogram.length/HIST_WIDTH);
266-
y = histogram[index]==0?0:(int)(HIST_HEIGHT*Math.log(histogram[index])/max);
283+
y = histogram[index]==0?0:(int)Math.max(HIST_HEIGHT*Math.log(histogram[index]+0.5)/max, 1);
267284
if (y>HIST_HEIGHT) y = HIST_HEIGHT;
268285
ip.drawLine(i+XMARGIN, YMARGIN+HIST_HEIGHT, i+XMARGIN, YMARGIN+HIST_HEIGHT-y);
269286
}
@@ -272,7 +289,7 @@ void drawLogPlot (long maxCount, ImageProcessor ip) {
272289
for (int i=0; i<histogram.length; i++) {
273290
long value = histogram[i];
274291
if (value>0L) {
275-
int y = (int)(HIST_HEIGHT*Math.log(value)/max);
292+
int y = (int)Math.max(HIST_HEIGHT*Math.log(value+0.5)/max, 1);
276293
if (y>HIST_HEIGHT) y = HIST_HEIGHT;
277294
int x = (int)(i*xscale)+XMARGIN;
278295
ip.drawLine(x, YMARGIN+HIST_HEIGHT, x, YMARGIN+HIST_HEIGHT-y);
@@ -281,7 +298,7 @@ void drawLogPlot (long maxCount, ImageProcessor ip) {
281298
}
282299
ip.setColor(Color.black);
283300
}
284-
301+
285302
void drawText(ImageProcessor ip, int x, int y) {
286303
ip.setFont(font);
287304
ip.setAntialiasedText(true);
@@ -340,7 +357,13 @@ void drawText(ImageProcessor ip, int x, int y) {
340357
ip.drawString("Bin Width: " + d2s(binWidth), col2, row4);
341358
}
342359
}
343-
360+
361+
/** Returns the default frame size. This is the size of the plot area excluding the
362+
* line around. */
363+
static Rectangle getDefaultFrame() {
364+
return new Rectangle(XMARGIN, YMARGIN, HIST_WIDTH, HIST_HEIGHT);
365+
}
366+
344367
private String d2s(double d) {
345368
if ((int)d==d)
346369
return IJ.d2s(d, 0);
@@ -368,6 +391,8 @@ public double[] getXValues() {
368391

369392
@Override
370393
public void show() {
394+
if (frame == null)
395+
frame = getDefaultFrame();
371396
HistogramWindow hw = new HistogramWindow(this, WindowManager.getImage(srcImageID));
372397
try {
373398
ResultsTable rt = hw.getResultsTable();

ij/gui/HistogramWindow.java

Lines changed: 9 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ public void showHistogram(ImagePlus srcImp, ImageStatistics stats) {
186186
ip.resetRoi();
187187
ip.fill();
188188
ImageProcessor srcIP = srcImp.getProcessor();
189+
if (frame == null)
190+
frame = HistogramPlot.getDefaultFrame();
189191
drawHistogram(srcImp, ip, fixedRange, stats.histMin, stats.histMax);
190192
imp.updateAndDraw();
191193
}
@@ -250,6 +252,8 @@ protected void drawHistogram(ImageProcessor ip, boolean fixedRange) {
250252
}
251253

252254
void drawHistogram(ImagePlus imp, ImageProcessor ip, boolean fixedRange, double xMin, double xMax) {
255+
if (frame == null)
256+
frame = HistogramPlot.getDefaultFrame();
253257
int x, y;
254258
long maxCount2 = 0;
255259
int mode2 = 0;
@@ -269,8 +273,8 @@ void drawHistogram(ImagePlus imp, ImageProcessor ip, boolean fixedRange, double
269273
if ((newMaxCount>(maxCount2 * 2)) && (maxCount2 != 0))
270274
newMaxCount = (int)(maxCount2 * 1.5);
271275
if (logScale || IJ.shiftKeyDown() && !liveMode())
272-
drawLogPlot(yMax>0?yMax:newMaxCount, ip);
273-
drawPlot(yMax>0?yMax:newMaxCount, ip);
276+
HistogramPlot.drawLogPlot(histogram, yMax>0?yMax:newMaxCount, ip, frame);
277+
HistogramPlot.drawPlot(histogram, yMax>0?yMax:newMaxCount, ip, frame, Color.BLACK);
274278
histogram[stats.mode] = saveModalCount;
275279
x = XMARGIN + 1;
276280
y = YMARGIN + HIST_HEIGHT + 2;
@@ -339,84 +343,6 @@ int scaleDown(ImageProcessor ip, double threshold) {
339343
else
340344
return 0;
341345
}
342-
343-
void drawPlot(long maxCount, ImageProcessor ip) {
344-
if (maxCount==0) maxCount = 1;
345-
frame = new Rectangle(XMARGIN, YMARGIN, HIST_WIDTH, HIST_HEIGHT);
346-
ip.drawRect(frame.x-1, frame.y, frame.width+2, frame.height+1);
347-
if (histogram.length==256) {
348-
double scale2 = HIST_WIDTH/256.0;
349-
int barWidth = 1;
350-
if (SCALE>1) barWidth=2;
351-
if (SCALE>2) barWidth=3;
352-
for (int i = 0; i < 256; i++) {
353-
int x =(int)(i*scale2);
354-
int y = (int)(((double)HIST_HEIGHT*(double)histogram[i])/maxCount);
355-
if (y>HIST_HEIGHT) y = HIST_HEIGHT;
356-
for (int j = 0; j<barWidth; j++)
357-
ip.drawLine(x+j+XMARGIN, YMARGIN+HIST_HEIGHT, x+j+XMARGIN, YMARGIN+HIST_HEIGHT-y);
358-
}
359-
} else if (histogram.length<=HIST_WIDTH) {
360-
int index, y;
361-
for (int i=0; i<HIST_WIDTH; i++) {
362-
index = (int)(i*(double)histogram.length/HIST_WIDTH);
363-
y = (int)(((double)HIST_HEIGHT*(double)histogram[index])/maxCount);
364-
if (y>HIST_HEIGHT) y = HIST_HEIGHT;
365-
ip.drawLine(i+XMARGIN, YMARGIN+HIST_HEIGHT, i+XMARGIN, YMARGIN+HIST_HEIGHT-y);
366-
}
367-
} else {
368-
double xscale = (double)HIST_WIDTH/histogram.length;
369-
for (int i=0; i<histogram.length; i++) {
370-
long value = histogram[i];
371-
if (value>0L) {
372-
int y = (int)(((double)HIST_HEIGHT*(double)value)/maxCount);
373-
if (y>HIST_HEIGHT) y = HIST_HEIGHT;
374-
int x = (int)(i*xscale)+XMARGIN;
375-
ip.drawLine(x, YMARGIN+HIST_HEIGHT, x, YMARGIN+HIST_HEIGHT-y);
376-
}
377-
}
378-
}
379-
}
380-
381-
void drawLogPlot (long maxCount, ImageProcessor ip) {
382-
frame = new Rectangle(XMARGIN, YMARGIN, HIST_WIDTH, HIST_HEIGHT);
383-
ip.drawRect(frame.x-1, frame.y, frame.width+2, frame.height+1);
384-
double max = Math.log(maxCount);
385-
ip.setColor(Color.gray);
386-
if (histogram.length==256) {
387-
double scale2 = HIST_WIDTH/256.0;
388-
int barWidth = 1;
389-
if (SCALE>1) barWidth=2;
390-
if (SCALE>2) barWidth=3;
391-
for (int i=0; i < 256; i++) {
392-
int x =(int)(i*scale2);
393-
int y = histogram[i]==0?0:(int)(HIST_HEIGHT*Math.log(histogram[i])/max);
394-
if (y>HIST_HEIGHT) y = HIST_HEIGHT;
395-
for (int j = 0; j<barWidth; j++)
396-
ip.drawLine(x+j+XMARGIN, YMARGIN+HIST_HEIGHT, x+j+XMARGIN, YMARGIN+HIST_HEIGHT-y);
397-
}
398-
} else if (histogram.length<=HIST_WIDTH) {
399-
int index, y;
400-
for (int i = 0; i<HIST_WIDTH; i++) {
401-
index = (int)(i*(double)histogram.length/HIST_WIDTH);
402-
y = histogram[index]==0?0:(int)(HIST_HEIGHT*Math.log(histogram[index])/max);
403-
if (y>HIST_HEIGHT) y = HIST_HEIGHT;
404-
ip.drawLine(i+XMARGIN, YMARGIN+HIST_HEIGHT, i+XMARGIN, YMARGIN+HIST_HEIGHT-y);
405-
}
406-
} else {
407-
double xscale = (double)HIST_WIDTH/histogram.length;
408-
for (int i=0; i<histogram.length; i++) {
409-
long value = histogram[i];
410-
if (value>0L) {
411-
int y = (int)(HIST_HEIGHT*Math.log(value)/max);
412-
if (y>HIST_HEIGHT) y = HIST_HEIGHT;
413-
int x = (int)(i*xscale)+XMARGIN;
414-
ip.drawLine(x, YMARGIN+HIST_HEIGHT, x, YMARGIN+HIST_HEIGHT-y);
415-
}
416-
}
417-
}
418-
ip.setColor(Color.black);
419-
}
420346

421347
void drawText(ImageProcessor ip, int x, int y, boolean fixedRange) {
422348
ip.setFont(font);
@@ -555,11 +481,9 @@ void replot() {
555481
ip.resetRoi();
556482
ip.setColor(Color.black);
557483
ip.setLineWidth(1);
558-
if (logScale) {
559-
drawLogPlot(yMax>0?yMax:newMaxCount, ip);
560-
drawPlot(yMax>0?yMax:newMaxCount, ip);
561-
} else
562-
drawPlot(yMax>0?yMax:newMaxCount, ip);
484+
if (logScale)
485+
HistogramPlot.drawLogPlot(histogram, yMax>0?yMax:newMaxCount, ip, frame);
486+
HistogramPlot.drawPlot(histogram, yMax>0?yMax:newMaxCount, ip, frame, Color.BLACK);
563487
this.imp.updateAndDraw();
564488
}
565489

ij/gui/PointRoi.java

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -143,15 +143,21 @@ public PointRoi(int sx, int sy, ImagePlus imp) {
143143
setCounter(Toolbar.getMultiPointMode()?defaultCounter:0);
144144
incrementCounter(imp);
145145
enlargeArrays(50);
146-
if (IJ.recording()) {
147-
String add = Prefs.pointAddToOverlay?" add":"";
148-
String options = sizes[convertSizeToIndex(size)]+" "+Colors.colorToString(getColor())+" "+types[type]+add;
149-
options = options.toLowerCase();
150-
if (Recorder.scriptMode())
151-
Recorder.recordCall("imp.setRoi(new PointRoi("+x+","+y+",\""+options+"\"));");
152-
else
153-
Recorder.record("makePoint", x, y, options);
154-
}
146+
record(x, y, false);
147+
}
148+
149+
private void record(int xx, int yy, boolean addingPoint) {
150+
if (!IJ.recording())
151+
return;
152+
String add = Prefs.pointAddToOverlay?" add":"";
153+
String options = sizes[convertSizeToIndex(size)]+" "+Colors.colorToString(getColor())+" "+types[type]+add;
154+
options = options.toLowerCase();
155+
if (addingPoint)
156+
options = "add";
157+
if (Recorder.scriptMode())
158+
Recorder.recordCall("imp.setRoi(new PointRoi("+xx+","+yy+",\""+options+"\"));");
159+
else
160+
Recorder.record("makePoint", xx, yy, options);
155161
}
156162

157163
public void setOptions(String options) {
@@ -213,7 +219,6 @@ public void draw(Graphics g) {
213219
double scale = size>=XXL?2:1.5;
214220
fontSize += scale*convertSizeToIndex(size);
215221
fontSize = (int)Math.round(fontSize);
216-
//IJ.log("fontSize: "+fontSize+" "+scale);
217222
font = new Font("SansSerif", Font.PLAIN, fontSize);
218223
g.setFont(font);
219224
if (fontSize>9)
@@ -226,9 +231,7 @@ public void draw(Graphics g) {
226231
slice = 0; // In RoiManager's "show all" mode and not "associate with slice", draw point irrespective of currently selected slice
227232
if (Prefs.showAllPoints)
228233
slice = 0; // "Show on all slices" in Point tool options
229-
//IJ.log("draw: "+positions+" "+imp.getCurrentSlice());
230234
for (int i=0; i<nPoints; i++) {
231-
//IJ.log(i+" "+slice+" "+(positions!=null?positions[i]:-1)+" "+getPosition());
232235
if (slice==0 || (positions!=null&&(slice==positions[i]||positions[i]==0)))
233236
drawPoint(g, xp2[i], yp2[i], i+1);
234237
}
@@ -351,6 +354,7 @@ public void addPoint(ImagePlus imp, double ox, double oy) {
351354
public void addUserPoint(ImagePlus imp, double ox, double oy) {
352355
addPoint(imp, ox, oy);
353356
nMarkers++;
357+
record((int)Math.round(ox),(int)Math.round(oy), true);
354358
}
355359

356360
private void addPoint2(ImagePlus imp, double ox, double oy) {
@@ -399,7 +403,6 @@ protected void deletePoint(int index) {
399403
}
400404

401405
private synchronized void incrementCounter(ImagePlus imp) {
402-
//IJ.log("incrementCounter: "+nPoints+" "+counter+" "+(counters!=null?""+counters.length:"null"));
403406
counts[counter]++;
404407
boolean isStack = imp!=null && imp.getStackSize()>1;
405408
if (counter!=0 || isStack || counters!=null) {
@@ -679,7 +682,6 @@ public void setCounters(int[] counters) {
679682
for (int i=0; i<n; i++) {
680683
int counter = counters[i]&0xff;
681684
int position = counters[i]>>8;
682-
//IJ.log(i+" cnt="+counter+" slice="+position);
683685
this.counters[i] = (short)counter;
684686
this.positions[i] = position;
685687
if (counter<counts.length && counter>nCounters-1)
@@ -736,7 +738,8 @@ public void setPosition(int n) {
736738
* if there are different stack positions for different points.
737739
*/
738740
public int getPosition() {
739-
if (positions==null || nPoints<1 || !positionSet)
741+
//if (positions==null || nPoints<1 || !positionSet)
742+
if (positions==null || nPoints<1)
740743
return 0;
741744
else {
742745
int position = positions[0];
@@ -1031,9 +1034,9 @@ public boolean addToOverlay() {
10311034

10321035
public String toString() {
10331036
if (nPoints>1)
1034-
return ("Roi[Points, count="+nPoints+", pos="+getPositionAsString()+"]");
1037+
return ("Roi[Points, count="+nPoints+", pos="+getPositionAsString()+", size="+size+"]");
10351038
else
1036-
return ("Roi[Point, x="+x+", y="+y+", pos="+getPositionAsString()+"]");
1039+
return ("Roi[Point, x="+x+", y="+y+", pos="+getPositionAsString()+", size="+size+"]");
10371040
}
10381041

10391042
/** @deprecated */

ij/macro/Functions.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5858,8 +5858,16 @@ void makePoint() {
58585858
IJ.makePoint((int)x, (int)y);
58595859
else
58605860
IJ.makePoint(x, y);
5861-
} else
5862-
getImage().setRoi(new PointRoi(x, y, options));
5861+
} else {
5862+
if (options!=null && options.equals("add")) { //add point to multi-point selection
5863+
IJ.setKeyDown(KeyEvent.VK_SHIFT);
5864+
if ((int)x==x && (int)y==y)
5865+
IJ.makePoint((int)x, (int)y);
5866+
else
5867+
IJ.makePoint(x, y);
5868+
} else
5869+
getImage().setRoi(new PointRoi(x, y, options));
5870+
}
58635871
resetImage();
58645872
shiftKeyDown = altKeyDown = false;
58655873
}

ij/plugin/AVI_Reader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ private void readAVI(String path) throws Exception, IOException {
619619
long pos = raFile.getFilePointer();
620620
//IJ.log("at 0x"+Long.toHexString(pos)+" filesize=0x"+Long.toHexString(fileSize));
621621
// extended AVI: try to find further 'RIFF' chunks, where we expect AVIX tags
622-
while (pos>0 && pos<fileSize && (frameNumber<lastFrameToRead+1))
622+
while (pos>0 && pos<fileSize && (frameNumber<=lastFrameToRead))
623623
pos = findFourccAndRead(FOURCC_RIFF, false, fileSize, false);
624624
return;
625625
}

0 commit comments

Comments
 (0)