Skip to content

Commit 9b91548

Browse files
committed
2026.01.24 (1.54s13; Images to Stack)
1 parent 484e05e commit 9b91548

File tree

9 files changed

+103
-39
lines changed

9 files changed

+103
-39
lines changed

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.54s";
82-
public static final String BUILD = "11";
82+
public static final String BUILD = "13";
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/VirtualStack.java

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ public class VirtualStack extends ImageStack {
2020
private int delay;
2121
private Properties properties;
2222
private boolean generateData;
23-
private int[] indexes; // used to translate non-CZT hyperstack slice numbers
23+
private int[] indexes; // used to translate non-CZT hyperstack slice numbers (0-based)
24+
private boolean translating; // translation indexes was actually used, then also translate labels&names
2425

2526

2627
/** Default constructor. */
@@ -80,17 +81,27 @@ public void addSlice(String fileName) {
8081
if (fileName.startsWith("."))
8182
return;
8283
if (names==null)
83-
throw new IllegalArgumentException("VirtualStack(w,h,cm,path) constructor not used");
84+
throw new IllegalArgumentException("VirtualStack(w,h,cm,path) constructor not used");
85+
if (indexes != null)
86+
throw new IllegalArgumentException("Virtual hyperstack with non-czt order cannot be modified");
8487
nSlices++;
85-
if (nSlices==names.length) {
86-
String[] tmp = new String[nSlices*2];
87-
System.arraycopy(names, 0, tmp, 0, nSlices);
88+
expandArrays(nSlices);
89+
names[nSlices-1] = fileName;
90+
}
91+
92+
/** Expands the 'names' and 'labels' arrays if existing and smaller than minSize.
93+
* This should be called each time the stack is enlarged */
94+
protected void expandArrays(int minSize) {
95+
if (names != null && names.length < minSize) {
96+
String[] tmp = new String[minSize*2];
97+
System.arraycopy(names, 0, tmp, 0, names.length);
8898
names = tmp;
89-
tmp = new String[nSlices*2];
90-
System.arraycopy(labels, 0, tmp, 0, nSlices);
99+
}
100+
if (labels != null && labels.length < minSize) {
101+
String[] tmp = new String[minSize*2];
102+
System.arraycopy(labels, 0, tmp, 0, labels.length);
91103
labels = tmp;
92104
}
93-
names[nSlices-1] = fileName;
94105
}
95106

96107
/** Does nothing. */
@@ -101,7 +112,7 @@ public void addSlice(String sliceLabel, Object pixels) {
101112
public void addSlice(String sliceLabel, ImageProcessor ip) {
102113
}
103114

104-
/** Does noting. */
115+
/** Does nothing. */
105116
public void addSlice(String sliceLabel, ImageProcessor ip, int n) {
106117
}
107118

@@ -111,9 +122,16 @@ public void deleteSlice(int n) {
111122
return;
112123
if (n<1 || n>nSlices)
113124
throw new IllegalArgumentException("Argument out of range: "+n);
125+
if (names==null)
126+
throw new IllegalArgumentException("VirtualStack(w,h,cm,path) constructor not used");
127+
if (translating)
128+
throw new IllegalArgumentException("Virtual hyperstack with non-czt order cannot be modified");
114129
for (int i=n; i<nSlices; i++)
115130
names[i-1] = names[i];
116131
names[nSlices-1] = null;
132+
if (labels != null)
133+
for (int i=n; i<nSlices; i++)
134+
labels[i-1] = labels[i];
117135
nSlices--;
118136
}
119137

@@ -147,7 +165,7 @@ public void setPixels(Object pixels, int n) {
147165
* {@link <a href="https://wsr.imagej.net/plugins/Test_Virtual_Stack2.java#gemsiv">Example</a>}
148166
*/
149167
public ImageProcessor getProcessor(int n) {
150-
if (path==null) { //Help>Examples?JavaScript>Terabyte VirtualStack
168+
if (path==null) { //Help>Examples>JavaScript>Terabyte VirtualStack
151169
ImageProcessor ip = null;
152170
int w=getWidth(), h=getHeight();
153171
switch (bitDepth) {
@@ -194,11 +212,11 @@ public ImageProcessor getProcessor(int n) {
194212
String info = (String)imp.getProperty("Info");
195213
if (info!=null) {
196214
if (FolderOpener.useInfo(info))
197-
labels[n-1] = info;
215+
setSliceLabel(info, n);
198216
} else {
199217
String sliceLabel = imp.getStack().getSliceLabel(1);
200218
if (FolderOpener.useInfo(sliceLabel))
201-
labels[n-1] = "Label: "+sliceLabel;
219+
setSliceLabel("Label: "+sliceLabel, n);
202220
}
203221
depthThisImage = imp.getBitDepth();
204222
ip = imp.getProcessor();
@@ -230,7 +248,8 @@ public ImageProcessor getProcessor(int n) {
230248
ip.setSliceNumber(n);
231249
return ip;
232250
}
233-
251+
252+
/** Draw label for Help>Examples>JavaScript>Terabyte VirtualStack */
234253
private void label(ImageProcessor ip, String msg, Color color) {
235254
int size = getHeight()/20;
236255
if (size<9) size=9;
@@ -257,9 +276,13 @@ public int getSize() {
257276

258277
/** Returns the label of the Nth image. */
259278
public String getSliceLabel(int n) {
279+
if (translating)
280+
n = translate(n);
260281
if (labels==null)
261282
return null;
262-
String label = labels[n-1];
283+
String label = (n<=labels.length) ? labels[n-1] : null; //subclass may have grown stack without adding labels
284+
if (names == null)
285+
return label;
263286
if (label==null)
264287
return names[n-1];
265288
else {
@@ -275,11 +298,26 @@ public Object[] getImageArray() {
275298
return null;
276299
}
277300

278-
/** Does nothing. */
301+
/** Sets the label of the specified slice, where {@literal 1<=n<=nSlices}. */
279302
public void setSliceLabel(String label, int n) {
303+
if (n <= 0 || n > getSize())
304+
throw new IllegalArgumentException(outOfRange+n);
305+
if (translating)
306+
n = translate(n);
307+
if (labels == null)
308+
labels = new String[getSize()];
309+
expandArrays(nSlices);
310+
labels[n-1] = label;
311+
}
312+
313+
/** Sets the array of slice labels. The array size must be the stack size or larger */
314+
protected void setSliceLabels(String[] labels) {
315+
if (labels != null && labels.length < getSize())
316+
throw new IllegalArgumentException("Labels array too short: "+labels.length);
317+
this.labels = labels;
280318
}
281319

282-
/** Always return true. */
320+
/** Always returns true. */
283321
public boolean isVirtual() {
284322
return true;
285323
}
@@ -327,14 +365,15 @@ public Properties getProperties() {
327365
return properties;
328366
}
329367

330-
/** Sets the table that translates slice numbers of hyperstacks not in default CZT order. */
368+
/** Sets the (0-based) table that translates slice numbers of hyperstacks not in default CZT order. */
331369
public void setIndexes(int[] indexes) {
332370
this.indexes = indexes;
333371
}
334372

335373
/** Translates slice numbers of hyperstacks not in default CZT order. */
336374
public int translate(int n) {
337375
int n2 = (indexes!=null&&indexes.length==getSize()) ? indexes[n-1]+1 : n;
376+
if (indexes != null) translating = true;
338377
//IJ.log("translate: "+n+" "+n2+" "+getSize()+" "+(indexes!=null?indexes.length:null));
339378
return n2;
340379
}
@@ -346,7 +385,8 @@ public void reduce(int factor) {
346385
nSlices = nSlices/factor;
347386
for (int i=0; i<nSlices; i++) {
348387
names[i] = names[i*factor];
349-
labels[i] = labels[i*factor];
388+
if (labels != null)
389+
labels[i] = labels[i*factor];
350390
}
351391
ImagePlus imp = WindowManager.getCurrentImage();
352392
if (imp!=null) {

ij/gui/NonBlockingGenericDialog.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ public synchronized void showDialog() {
2323
super.showDialog();
2424
if (isMacro())
2525
return;
26-
if (!IJ.macroRunning()) { // add to Window menu on event dispatch thread
26+
if (EventQueue.isDispatchThread())
27+
throw new RuntimeException("To avoid a deadlock, NonBlockingGenericDialog must not be called from the Event Queue");
28+
if (!IJ.macroRunning()) { // add to Window menu on event dispatch thread
2729
final NonBlockingGenericDialog thisDialog = this;
2830
EventQueue.invokeLater(new Runnable() {
2931
public void run() {

ij/gui/WaitForUserDialog.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ public WaitForUserDialog(String text) {
7070

7171
public void show() {
7272
super.show();
73+
if (EventQueue.isDispatchThread())
74+
throw new RuntimeException("To avoid a deadlock, WaitForUserDialog must not be called from the Event Queue");
7375
synchronized(this) { //wait for OK
7476
try {wait();}
7577
catch(InterruptedException e) {return;}

ij/macro/Functions.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8189,7 +8189,7 @@ private Variable doRoiManager() {
81898189
return null;
81908190
} else if (name.equals("setGroup")) {
81918191
int group = (int)getArg();
8192-
if (group<0 || group>255)
8192+
if (group<0 || group>Roi.MAX_ROI_GROUP)
81938193
interp.error("Group out of range");
81948194
rm.setGroup(group);
81958195
return null;

ij/plugin/FileInfoVirtualStack.java

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ else if (fi.fileType==FileInfo.GRAY10_UNSIGNED)
112112
}
113113
}
114114
nImages = info.length;
115+
if (info[0].sliceLabels!=null && info[0].sliceLabels.length==nImages)
116+
setSliceLabels(info[0].sliceLabels);
115117
FileOpener fo = new FileOpener(info[0]);
116118
ImagePlus imp = fo.openImage();
117119
if (nImages==1 && fi.fileType==FileInfo.RGB48)
@@ -189,6 +191,8 @@ public void deleteSlice(int n) {
189191
for (int i=n; i<nImages; i++)
190192
info[i-1] = info[i];
191193
info[nImages-1] = null;
194+
for (int i=n; i<nImages; i++)
195+
setSliceLabel(getSliceLabel(i+1), i);
192196
nImages--;
193197
}
194198

@@ -244,16 +248,6 @@ public int getSize() {
244248
return nImages;
245249
}
246250

247-
/** Returns the label of the Nth image. */
248-
public String getSliceLabel(int n) {
249-
if (n<1 || n>nImages)
250-
throw new IllegalArgumentException("Argument out of range: "+n);
251-
if (info[0].sliceLabels==null || info[0].sliceLabels.length!=nImages)
252-
return null;
253-
else
254-
return info[0].sliceLabels[n-1];
255-
}
256-
257251
public int getWidth() {
258252
return info[0].width;
259253
}
@@ -264,15 +258,16 @@ public int getHeight() {
264258

265259
/** Adds an image to this stack. */
266260
public synchronized void addImage(FileInfo fileInfo) {
267-
nImages++;
268261
if (info==null)
269262
info = new FileInfo[250];
270-
if (nImages==info.length) {
271-
FileInfo[] tmp = new FileInfo[nImages*2];
272-
System.arraycopy(info, 0, tmp, 0, nImages);
263+
if (info.length <= nImages) {
264+
FileInfo[] tmp = new FileInfo[nImages*2+1];
265+
System.arraycopy(info, 0, tmp, 0, info.length);
273266
info = tmp;
274267
}
275-
info[nImages-1] = fileInfo;
268+
269+
info[nImages] = fileInfo;
270+
nImages++;
276271
}
277272

278273
@Override

ij/plugin/HyperStackConverter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
223223
autoCbxIndex = -1;
224224
}
225225
double sizeProduct = 1;
226+
gd.getNextChoiceIndex(); //ensure macro recording of 'ordering' choice
226227
for (int i=0; i<MAX_DIMENSIONS; i++) {
227228
double num = gd.getNextNumber();
228229
if (i==autoCbxIndex) continue;
@@ -232,6 +233,9 @@ public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
232233
}
233234
sizeProduct *= num;
234235
}
236+
gd.getNextChoiceIndex(); //ensure macro recording of 'mode' choice
237+
if (rgb)
238+
gd.getNextBoolean(); //ensure macro recording of 'splitRGB' checkbox
235239
if (autoCbxIndex >= 0) { //calculate the 'auto' dimension
236240
double autoValue = stackSize/sizeProduct;
237241
boolean autoOk = (autoValue == (int)autoValue);

ij/plugin/ImagesToStack.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ private ImagePlus convert(ImagePlus[] images, int count) {
199199
}
200200
ip2.insert(ip, xoff, yoff);
201201
ip = ip2;
202+
Overlay overlay2 = images[i].getOverlay();
203+
if (overlay2!=null) {
204+
overlay2.translate(xoff, yoff);
205+
for (int j=0; j<overlay2.size(); j++) {
206+
Roi roi = overlay2.get(j);
207+
roi.setPosition(i+1);
208+
overlay.add((Roi)roi.clone());
209+
}
210+
}
202211
break;
203212
case SCALE_SMALL: case SCALE_LARGE:
204213
ip.setInterpolationMethod((bicubic?ImageProcessor.BICUBIC:ImageProcessor.BILINEAR));

release-notes.html

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
</head>
66
<body>
77

8-
<li> <u>1.54s11 21 December 2025</u>
8+
<li> <u>1.54s13 24 January 2026</u>
99
<ul>
10-
<li> Thanks to Curtis Rueden, increased the maximum ROI group
11-
number from 255 to 65535.
10+
<li> Thanks to Joris Van Meenen, the <i>Images to Stack</i> command
11+
retains all overlays when not all image are the same
12+
size.
13+
<li> Thanks to Laurent Thomas and Curtis Rueden, increased the maximum
14+
ROI group number from 255 to 65535.
1215
<li> Thanks to Bram van den Broek, macro error messages longer
1316
than 90 characters are displayed on multiple lines and the full
1417
message is displayed in the Debug window.
@@ -19,6 +22,15 @@
1922
<li> Thanks to Jerome Mutterer, fixed regression that caused
2023
"Show All" in the ROI Manager to not work as expected with
2124
composite images.
25+
<li> Thanks to Michael Schmid, fixed an incorrect slice label order bug
26+
and a recording bug with the
27+
<i>Image&gt;Hyperstack&gt;Stack to Hyperstack</i>
28+
command.
29+
<li> Thanks to Michael Schmid, fixed bug with
30+
ImageStack.setSliceLabel(string,int) not working with
31+
FileInfoVirtualStacks.
32+
<li> Thanks to Michael Schmid, fixed bug where TIFF Virtual Stacks
33+
lost their slice labels when a slice was deleted.
2234
</ul>
2335

2436
<li> <u>1.54r 25 September 2025</u>

0 commit comments

Comments
 (0)