From ec04c7dd1b19e5d9cf4923f2d27f21278928d311 Mon Sep 17 00:00:00 2001 From: Laurent Thomas Date: Sat, 13 Dec 2025 22:30:34 +0100 Subject: [PATCH 1/4] increase max roi group to Integer.MAX_VALUE --- ij/gui/Roi.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ij/gui/Roi.java b/ij/gui/Roi.java index 4d5e7601..87959e80 100644 --- a/ij/gui/Roi.java +++ b/ij/gui/Roi.java @@ -55,6 +55,7 @@ public class Roi extends Object implements Cloneable, java.io.Serializable, Iter public static final int FERET_ARRAYSIZE = 16; // Size of array with Feret values public static final int FERET_ARRAY_POINTOFFSET = 8; // Where point coordinates start in Feret array private static final String NAMES_KEY = "group.names"; + private static final String MAX_ROI_GROUP = Integer.MAX_VALUE; static final int NO_MODS=0, ADD_TO_ROI=1, SUBTRACT_FROM_ROI=2; // modification states @@ -1807,7 +1808,7 @@ public static int getDefaultGroup() { * @see #getGroupColor */ public static void setDefaultGroup(int group) { - if (group<0 || group>255) + if (group<0 || group>MAX_ROI_GROUP) throw new IllegalArgumentException("Invalid group: "+group); defaultGroup = group; groupColor = getGroupColor(group); @@ -1820,7 +1821,7 @@ public int getGroup() { /** Returns the group name associtated with the specified group. */ public static String getGroupName(int groupNumber) { - if (groupNumber<1 || groupNumber>255) + if (groupNumber<1 || groupNumber>MAX_ROI_GROUP) return null; if (groupNames==null && groupNamesString==null) return null; @@ -1835,7 +1836,7 @@ public static String getGroupName(int groupNumber) { } public static synchronized void setGroupName(int groupNumber, String name) { - if (groupNumber<1 || groupNumber>255) + if (groupNumber<1 || groupNumber>MAX_ROI_GROUP) return; if (groupNamesString==null && groupNames==null) groupNames = new String[groupNumber]; @@ -1884,7 +1885,7 @@ public static void setGroupNames(String names) { /** Sets the group of this Roi, and updates stroke color accordingly. */ public void setGroup(int group) { - if (group<0 || group>255) + if (group<0 || group>MAX_ROI_GROUP) throw new IllegalArgumentException("Invalid group: "+group); if (group>0) setStrokeColor(getGroupColor(group)); From dafece8f82c195afb34d9f1eff55ea47453aeb0f Mon Sep 17 00:00:00 2001 From: Laurent Thomas Date: Sun, 14 Dec 2025 16:11:15 +0100 Subject: [PATCH 2/4] fix type and reduce max roi group with safe margin --- ij/gui/Roi.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ij/gui/Roi.java b/ij/gui/Roi.java index 87959e80..d8771c8b 100644 --- a/ij/gui/Roi.java +++ b/ij/gui/Roi.java @@ -55,7 +55,7 @@ public class Roi extends Object implements Cloneable, java.io.Serializable, Iter public static final int FERET_ARRAYSIZE = 16; // Size of array with Feret values public static final int FERET_ARRAY_POINTOFFSET = 8; // Where point coordinates start in Feret array private static final String NAMES_KEY = "group.names"; - private static final String MAX_ROI_GROUP = Integer.MAX_VALUE; + private static final int MAX_ROI_GROUP = Integer.MAX_VALUE - 10; // limit the size of the array for the group name static final int NO_MODS=0, ADD_TO_ROI=1, SUBTRACT_FROM_ROI=2; // modification states From 1f7033fc1f69263a82505c178f77508f7e024d64 Mon Sep 17 00:00:00 2001 From: Curtis Rueden Date: Wed, 17 Dec 2025 16:09:20 -0600 Subject: [PATCH 3/4] Extend ROI group format to support uint16 (0-65535) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increments ROI format version to 229 and uses header2 offset 52 for groups > 255. Maintains backwards compatibility by using byte 30 as marker (value 0 indicates extended group at offset 52). Groups <= 255 continue to use byte 30 for compatibility with older readers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- ij/io/RoiDecoder.java | 7 ++++++- ij/io/RoiEncoder.java | 10 ++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/ij/io/RoiDecoder.java b/ij/io/RoiDecoder.java index 2d989f00..9efc822c 100644 --- a/ij/io/RoiDecoder.java +++ b/ij/io/RoiDecoder.java @@ -89,6 +89,7 @@ public class RoiDecoder { public static final int ROI_PROPS_OFFSET = 40; public static final int ROI_PROPS_LENGTH = 44; public static final int COUNTERS_OFFSET = 48; + public static final int GROUP_EXTENDED = 52; //short (uint16) for groups > 255 // subtypes public static final int TEXT = 1; @@ -207,7 +208,11 @@ public Roi getRoi() throws IOException { overlayFontSize = getShort(hdr2Offset+OVERLAY_FONT_SIZE); imageOpacity = getByte(hdr2Offset+IMAGE_OPACITY); imageSize = getInt(hdr2Offset+IMAGE_SIZE); - group = getByte(hdr2Offset+GROUP); + int groupByte = getByte(hdr2Offset+GROUP); + if (version>=229 && groupByte==0 && hdr2Offset+GROUP_EXTENDED+2<=size) + group = getUnsignedShort(hdr2Offset+GROUP_EXTENDED); + else + group = groupByte; } if (name!=null && name.endsWith(".roi")) diff --git a/ij/io/RoiEncoder.java b/ij/io/RoiEncoder.java index 745ba119..9bf1e156 100644 --- a/ij/io/RoiEncoder.java +++ b/ij/io/RoiEncoder.java @@ -15,7 +15,7 @@ public class RoiEncoder { static final int HEADER_SIZE = 64; static final int HEADER2_SIZE = 64; - static final int VERSION = 228; // v1.52t (roi groups, scale stroke width) + static final int VERSION = 229; // v1.52u (extended roi groups via uint16) private String path; private OutputStream f; private final int polygon=0, rect=1, oval=2, line=3, freeline=4, polyline=5, noRoi=6, freehand=7, @@ -423,7 +423,13 @@ void putHeader2(Roi roi, int hdr2Offset) { putProps(roi, hdr2Offset); if (countersSize>0) putPointCounters(roi, hdr2Offset); - putByte(hdr2Offset+RoiDecoder.GROUP, roi.getGroup()); + int group = roi.getGroup(); + if (group > 255) { + putByte(hdr2Offset+RoiDecoder.GROUP, 0); // marker for extended group + putShort(hdr2Offset+RoiDecoder.GROUP_EXTENDED, group); + } else { + putByte(hdr2Offset+RoiDecoder.GROUP, group); + } } void putName(Roi roi, int hdr2Offset) { From 563ca868d4a2b1cbd32e6b6de7afc24dfd7482a1 Mon Sep 17 00:00:00 2001 From: Curtis Rueden Date: Wed, 17 Dec 2025 16:13:55 -0600 Subject: [PATCH 4/4] Limit the group index bound to uint16 max value --- ij/gui/Roi.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ij/gui/Roi.java b/ij/gui/Roi.java index d8771c8b..61d5c470 100644 --- a/ij/gui/Roi.java +++ b/ij/gui/Roi.java @@ -55,7 +55,7 @@ public class Roi extends Object implements Cloneable, java.io.Serializable, Iter public static final int FERET_ARRAYSIZE = 16; // Size of array with Feret values public static final int FERET_ARRAY_POINTOFFSET = 8; // Where point coordinates start in Feret array private static final String NAMES_KEY = "group.names"; - private static final int MAX_ROI_GROUP = Integer.MAX_VALUE - 10; // limit the size of the array for the group name + private static final int MAX_ROI_GROUP = 65535; // limit to uint16 max value static final int NO_MODS=0, ADD_TO_ROI=1, SUBTRACT_FROM_ROI=2; // modification states