290 public static int TOP = 8;
295 public static int X1 = 18;
296 public static int Y1 = 22;
297 public static int X2 = 26;
298 public static int Y2 = 30;
299 public static int XD = 18;
300 public static int YD = 22;
358 private int polygon = 0, rect = 1, oval = 2, line = 3, freeline = 4, polyline = 5, noRoi = 6,
359 freehand = 7, traced = 8, angle = 9, point = 10;
363 private MemoryStream ins;
377 ins =
new MemoryStream(bytes);
379 this.size = bytes.Length;
383 public static ROI
open(
string path)
395 data = File.ReadAllBytes(path);
397 if (getByte(0) != 73 || getByte(1) != 111)
398 throw new IOException(
"This is not an ImageJ ROI");
400 int type = getByte(
TYPE);
401 int subtype = getShort(
SUBTYPE);
402 int top = getShort(
TOP);
403 int left = getShort(
LEFT);
404 int bottom = getShort(
BOTTOM);
405 int right = getShort(
RIGHT);
406 int width = right - left;
407 int height = bottom - top;
411 int options = getShort(
OPTIONS);
414 int channel = 0, slice = 0, frame = 0;
415 int overlayLabelColor = 0;
416 int overlayFontSize = 0;
418 int imageOpacity = 0;
421 bool drawOffset = subPixelResolution && (options &
DRAW_OFFSET) != 0;
422 bool scaleStrokeWidth =
true;
426 bool subPixelRect = version >= 223 && subPixelResolution && (type == rect || type == oval);
427 double xd = 0.0, yd = 0.0, widthd = 0.0, heightd = 0.0;
432 widthd = getFloat(
WIDTHD);
436 if (hdr2Offset > 0 && hdr2Offset +
IMAGE_SIZE + 4 <= size)
445 group = getByte(hdr2Offset +
GROUP);
448 if (name !=
null && name.EndsWith(
".roi"))
449 name = name.Substring(0, name.Length - 4);
480 roi = ROI.CreateRectangle(
new ZCT(slice - 1, channel - 1, frame - 1), xd, yd, widthd, heightd);
482 roi = ROI.CreateRectangle(
new ZCT(slice - 1, channel - 1, frame - 1), left, top, width, height);
485 throw new NotSupportedException(
"Type rounded rectangle not supported.");
489 roi = ROI.CreateEllipse(
new ZCT(slice - 1, channel - 1, frame - 1), xd, yd, widthd, heightd);
491 roi = ROI.CreateEllipse(
new ZCT(slice - 1, channel - 1, frame - 1), left, top, width, height);
494 float x1 = getFloat(
X1);
495 float y1 = getFloat(
Y1);
496 float x2 = getFloat(
X2);
497 float y2 = getFloat(
Y2);
499 if (subtype ==
ARROW)
501 throw new NotSupportedException(
"Type arrow not supported.");
516 roi = ROI.CreateLine(
new ZCT(slice, channel, frame),
new PointD(x1, y1),
new PointD(x2, y2));
531 if (n == 0 || n < 0)
break;
532 int[] x =
new int[n];
533 int[] y =
new int[n];
537 int base2 = base1 + 2 * n;
539 for (
int i = 0; i < n; i++)
541 xtmp = getShort(base1 + i * 2);
542 if (xtmp < 0) xtmp = 0;
543 ytmp = getShort(base2 + i * 2);
544 if (ytmp < 0) ytmp = 0;
548 if (subPixelResolution)
553 base2 = base1 + 4 * n;
554 for (
int i = 0; i < n; i++)
556 xf[i] = getFloat(base1 + i * 4);
557 yf[i] = getFloat(base2 + i * 4);
563 if (subPixelResolution)
565 roi.AddPoints(xf, yf);
578 roi.type = ROI.Type.Point;
582 roi.type = ROI.Type.Polygon;
583 else if (type == freehand)
585 roi.type = ROI.Type.Freeform;
588 throw new NotSupportedException(
"ROI type not supported.");
603 else if (type == traced)
604 roi.type = ROI.Type.Polyline;
605 else if (type == polyline)
606 roi.type = ROI.Type.Polyline;
607 else if (type == freeline)
608 roi.type = ROI.Type.Polyline;
609 else if (type == angle)
610 roi.type = ROI.Type.Point;
612 roi.type = ROI.Type.Freeform;
613 if (subPixelResolution)
615 roi.AddPoints(xf, yf);
623 throw new IOException(
"Unrecognized ROI type: " + type);
627 roi.roiName = getRoiName();
632 getStrokeWidthAndColor(roi, hdr2Offset, scaleStrokeWidth);
642 if (version >= 218 && subtype ==
TEXT)
644 getTextRoi(roi, version);
645 roi.type = ROI.Type.Label;
666 if (version >= 228 && group > 0)
669 roi.coord.Z = position;
670 if (channel > 0 || slice > 0 || frame > 0)
671 roi.coord =
new ZCT(slice - 1, channel - 1, frame - 1);
676 for (
int i = 0; i < roi.Points.Count; i++)
680 roi.UpdateBoundingBox();
683 if (roi.type == ROI.Type.Polygon || roi.type == ROI.Type.Freeform)
712 void getStrokeWidthAndColor(ROI roi,
int hdr2Offset,
bool scaleStrokeWidth)
718 if (strokeWidthD > 0.0)
719 strokeWidth = strokeWidthD;
721 if (strokeWidth > 0.0)
723 roi.strokeWidth = strokeWidth;
726 if (strokeColor != 0)
728 byte[] bts = BitConverter.GetBytes(strokeColor);
729 Color c =
Color.FromArgb(bts[0], bts[1], bts[2], bts[3]);
735 byte[] bts = BitConverter.GetBytes(strokeColor);
736 Color c =
Color.FromArgb(bts[0], bts[1], bts[2], bts[3]);
772 void getTextRoi(ROI roi,
int version)
776 int size = getInt(hdrSize);
777 int styleAndJustification = getInt(hdrSize + 4);
778 int style = styleAndJustification & 255;
779 int justification = (styleAndJustification >> 8) & 3;
780 bool drawStringMode = (styleAndJustification & 1024) != 0;
781 int nameLength = getInt(hdrSize + 8);
782 int textLength = getInt(hdrSize + 12);
783 char[] name =
new char[nameLength];
784 char[] text =
new char[textLength];
785 for (
int i = 0; i < nameLength; i++)
786 name[i] = (
char)getShort(hdrSize + 16 + i * 2);
787 for (
int i = 0; i < textLength; i++)
788 text[i] = (
char)getShort(hdrSize + 16 + nameLength * 2 + i * 2);
789 double angle = version >= 225 ? getFloat(hdrSize + 16 + nameLength * 2 + textLength * 2) : 0f;
791 string fam =
new string(name);
794 roi.Text =
new string(text);
819 string fileName = name;
825 if (offset == 0 || Length == 0)
827 if (offset + Length * 2 > size)
829 char[] namem =
new char[Length];
830 for (
int i = 0; i < Length; i++)
831 namem[i] = (
char)getShort(offset + i * 2);
832 return new string(namem);
845 if (offset == 0 || Length == 0)
847 if (offset + Length * 2 > size)
849 char[] props =
new char[Length];
850 for (
int i = 0; i < Length; i++)
851 props[i] = (
char)getShort(offset + i * 2);
852 return new string(props);
860 int[] getPointCounters(
int n)
868 if (offset + n * 4 > data.Length)
870 int[] counters =
new int[n];
871 for (
int i = 0; i < n; i++)
872 counters[i] = getInt(offset + i * 4);
884 return data[bas] & 255;
893 int getShort(
int bas)
895 int b0 = data[bas] & 255;
896 int b1 = data[bas + 1] & 255;
897 int n = (short)((b0 << 8) + b1);
908 int getUnsignedShort(
int bas)
910 int b0 = data[bas] & 255;
911 int b1 = data[bas + 1] & 255;
912 return (b0 << 8) + b1;
922 int b0 = data[bas] & 255;
923 int b1 = data[bas + 1] & 255;
924 int b2 = data[bas + 2] & 255;
925 int b3 = data[bas + 3] & 255;
926 return ((b0 << 24) + (b1 << 16) + (b2 << 8) + b3);
935 float getFloat(
int bas)
938 byte[] bytes = BitConverter.GetBytes(getInt(bas));
939 return BitConverter.ToSingle(bytes, 0);
950 if (bytes ==
null || bytes.Length == 0)
957 catch (IOException e)
1059 static int HEADER_SIZE = 64;
1060 static int HEADER2_SIZE = 64;
1061 static int VERSION = 228;
1062 private string path;
1063 private FileStream f;
1064 private int polygon = 0, rect = 1, oval = 2, line = 3, freeline = 4, polyline = 5, noRoi = 6, freehand = 7,
1065 traced = 8, angle = 9, point = 10;
1066 private byte[] data;
1067 private string roiName;
1068 private int roiNameSize;
1069 private string roiProps;
1070 private int roiPropsSize;
1071 private int countersSize;
1072 private int[] counters;
1073 private bool subres =
true;
1088 public static bool save(ROI roi, String path)
1095 catch (IOException e)
1112 f =
new FileStream(path, FileMode.Create);
1144 void write(ROI roi, FileStream f)
1146 RectangleD r =
new RectangleD(roi.BoundingBox.X, roi.BoundingBox.Y, roi.BoundingBox.W, roi.BoundingBox.H);
1150 int type = GetImageJType(roi);
1155 if (roiName !=
null)
1156 roiNameSize = roiName.Length * 2;
1160 roiProps = roi.properties;
1161 if (roiProps !=
null)
1162 roiPropsSize = roiProps.Length * 2;
1190 xf =
null, yf =
null;
1195 n = roi.Points.Count;
1198 GetPointsXY(roi, out x, out y);
1227 data =
new byte[HEADER_SIZE + HEADER2_SIZE + n * 4 + floatSize + roiNameSize + roiPropsSize + countersSize];
1228 data[0] = 73; data[1] = 111; data[2] = 117; data[3] = 116;
1229 putShort(RoiDecoder.VERSION_OFFSET, VERSION);
1230 data[RoiDecoder.TYPE] = (byte)type;
1231 float px, py, pw, ph;
1232 GetXY(roi, out px, out py);
1233 GetWH(roi, out pw, out ph);
1234 putShort(RoiDecoder.TOP, (
int)py);
1235 putShort(RoiDecoder.LEFT, (
int)px);
1236 putShort(RoiDecoder.BOTTOM, (
int)(py + ph));
1237 putShort(RoiDecoder.RIGHT, (
int)(px + pw));
1239 if (subres && (type == rect || type == oval))
1258 if (roi.Points.Count == 4)
1260 putFloat(RoiDecoder.XD, (
float)PointsImage[0].X);
1261 putFloat(RoiDecoder.YD, (
float)PointsImage[0].Y);
1264 putFloat(RoiDecoder.WIDTHD, (
float)PointsImage[1].X - (
float)PointsImage[0].X);
1265 putFloat(RoiDecoder.HEIGHTD, (
float)PointsImage[2].Y - (
float)PointsImage[1].Y);
1266 options |= RoiDecoder.SUB_PIXEL_RESOLUTION;
1267 putShort(RoiDecoder.OPTIONS, options);
1270 if (n > 65535 && type != point)
1272 if (type == polygon || type == freehand || type == traced)
1277 saveShapeRoi(roi, rect, f, options);
1284 if (type == point && n > 65535)
1285 putInt(RoiDecoder.SIZE, n);
1287 putShort(RoiDecoder.N_COORDINATES, n);
1288 putInt(RoiDecoder.POSITION,
roi.coord.Z);
1302 putFloat(RoiDecoder.X1, (
float)PointsImage[0].X);
1303 putFloat(RoiDecoder.Y1, (
float)PointsImage[0].Y);
1304 putFloat(RoiDecoder.X2, (
float)PointsImage[1].X);
1305 putFloat(RoiDecoder.Y2, (
float)PointsImage[1].Y);
1327 putByte(RoiDecoder.POINT_TYPE, 1);
1328 putShort(RoiDecoder.STROKE_WIDTH, (
int)
roi.strokeWidth);
1347 putShort(RoiDecoder.SUBTYPE, RoiDecoder.ELLIPSE);
1350 float fx, fy, fw, fh;
1351 GetXY(roi, out fx, out fy);
1352 GetWH(roi, out fw, out fh);
1353 putFloat(RoiDecoder.X1, fx);
1354 putFloat(RoiDecoder.Y1, fy);
1355 putFloat(RoiDecoder.X2, fw);
1356 putFloat(RoiDecoder.Y2, fh);
1363 saveStrokeWidthAndColor(roi);
1372 if (
roi.type == ROI.Type.Label)
1379 putHeader2(roi, HEADER_SIZE + n * 4 + floatSize);
1384 int base2 = base1 + 2 * n;
1385 for (
int i = 0; i < n; i++)
1387 putShort(base1 + i * 2, (
int)(x[i] - px));
1388 putShort(base2 + i * 2, (
int)(y[i] - py));
1393 base2 = base1 + 4 * n;
1394 for (
int i = 0; i < n; i++)
1396 putFloat(base1 + i * 4, xf[i]);
1397 putFloat(base2 + i * 4, yf[i]);
1403 f.Write(data,0,data.Length);
1409 void saveStrokeWidthAndColor(ROI roi)
1413 putShort(RoiDecoder.STROKE_WIDTH, (
int)
roi.strokeWidth);
1414 Color strokeColor =
roi.strokeColor;
1415 int intColor = (strokeColor.R << 16) | (strokeColor.G << 8) | (strokeColor.B);
1416 putInt(RoiDecoder.STROKE_COLOR, 0);
1418 int intFillColor = (fillColor.R << 16) | (fillColor.G << 8) | (fillColor.B);
1419 putInt(RoiDecoder.FILL_COLOR, 0);
1429 void saveShapeRoi(ROI roi,
int type, FileStream f,
int options)
1435 data =
new byte[HEADER_SIZE + HEADER2_SIZE + roiNameSize + roiPropsSize];
1436 data[0] = 73; data[1] = 111; data[2] = 117; data[3] = 116;
1438 putShort(RoiDecoder.VERSION_OFFSET, VERSION);
1439 data[RoiDecoder.TYPE] = (byte)type;
1442 GetXY(roi, out x, out y);
1443 GetWH(roi, out w, out h);
1444 putShort(RoiDecoder.TOP, (
int)y);
1445 putShort(RoiDecoder.LEFT, (
int)x);
1446 putShort(RoiDecoder.BOTTOM, (
int)(y + h));
1447 putShort(RoiDecoder.RIGHT, (
int)(x + w));
1448 putInt(RoiDecoder.POSITION,
roi.coord.Z);
1452 saveStrokeWidthAndColor(roi);
1465 int hdr2Offset = HEADER_SIZE;
1467 putHeader2(roi, hdr2Offset);
1468 f.Write(data, 0, data.Length);
1493 void saveTextRoi(ROI roi)
1496 string fontName =
roi.family.ToString();
1497 int size = (int)
roi.fontSize;
1498 int drawStringMode = 0;
1500 string text =
roi.roiName;
1502 int angleLength = 4;
1503 int fontNameLength = fontName.Length;
1504 int textLength = text.Length;
1505 int textRoiDataLength = 16 + fontNameLength * 2 + textLength * 2 + angleLength;
1506 byte[] data2 =
new byte[HEADER_SIZE + HEADER2_SIZE + textRoiDataLength + roiNameSize + roiPropsSize];
1507 Array.Copy(data, 0, data2, 0, HEADER_SIZE);
1509 putShort(RoiDecoder.SUBTYPE, RoiDecoder.TEXT);
1510 putInt(HEADER_SIZE, size);
1511 putInt(HEADER_SIZE + 4, style);
1512 putInt(HEADER_SIZE + 8, fontNameLength);
1513 putInt(HEADER_SIZE + 12, textLength);
1514 for (
int i = 0; i < fontNameLength; i++)
1515 putShort(HEADER_SIZE + 16 + i * 2, fontName.ElementAt(i));
1516 for (
int i = 0; i < textLength; i++)
1517 putShort(HEADER_SIZE + 16 + fontNameLength * 2 + i * 2, text.ElementAt(i));
1518 int hdr2Offset = HEADER_SIZE + textRoiDataLength;
1520 putFloat(hdr2Offset - angleLength, angle);
1521 putHeader2(roi, hdr2Offset);
1548 void putHeader2(ROI roi,
int hdr2Offset)
1551 putInt(RoiDecoder.HEADER2_OFFSET, hdr2Offset);
1552 putInt(hdr2Offset + RoiDecoder.C_POSITION,
roi.coord.C + 1);
1553 putInt(hdr2Offset + RoiDecoder.Z_POSITION,
roi.coord.Z + 1);
1554 putInt(hdr2Offset + RoiDecoder.T_POSITION,
roi.coord.T + 1);
1556 Color overlayLabelColor =
roi.strokeColor;
1557 int intColor = (overlayLabelColor.R << 16) | (overlayLabelColor.G << 8) | (overlayLabelColor.B);
1559 putInt(hdr2Offset + RoiDecoder.OVERLAY_LABEL_COLOR, 0);
1562 putShort(hdr2Offset + RoiDecoder.OVERLAY_FONT_SIZE, (
int)
roi.fontSize);
1563 if (roiNameSize > 0)
1564 putName(roi, hdr2Offset);
1565 double strokeWidth =
roi.strokeWidth;
1568 putFloat(hdr2Offset + RoiDecoder.FLOAT_STROKE_WIDTH, (
float)strokeWidth);
1569 if (roiPropsSize > 0)
1570 putProps(roi, hdr2Offset);
1571 if (countersSize > 0)
1572 putPointCounters(roi, hdr2Offset);
1573 putByte(hdr2Offset + RoiDecoder.GROUP,
roi.serie);
1581 void putName(ROI roi,
int hdr2Offset)
1583 int offset = hdr2Offset + HEADER2_SIZE;
1584 int nameLength = roiNameSize / 2;
1585 putInt(hdr2Offset + RoiDecoder.NAME_OFFSET, offset);
1586 putInt(hdr2Offset + RoiDecoder.NAME_LENGTH, nameLength);
1587 for (
int i = 0; i < nameLength; i++)
1588 putShort(offset + i * 2, roiName.ElementAt(i));
1598 void putProps(ROI roi,
int hdr2Offset)
1600 int offset = hdr2Offset + HEADER2_SIZE + roiNameSize;
1601 int roiPropsLength = roiPropsSize / 2;
1602 putInt(hdr2Offset + RoiDecoder.ROI_PROPS_OFFSET, offset);
1603 putInt(hdr2Offset + RoiDecoder.ROI_PROPS_LENGTH, roiPropsLength);
1604 for (
int i = 0; i < roiPropsLength; i++)
1605 putShort(offset + i * 2, roiProps.ElementAt(i));
1612 void putPointCounters(ROI roi,
int hdr2Offset)
1614 int offset = hdr2Offset + HEADER2_SIZE + roiNameSize + roiPropsSize;
1615 putInt(hdr2Offset + RoiDecoder.COUNTERS_OFFSET, offset);
1616 for (
int i = 0; i < countersSize / 4; i++)
1617 putInt(offset + i * 4, counters[i]);
1625 void putByte(
int bas,
int v)
1627 data[bas] = (byte)v;
1634 void putShort(
int bas,
int v)
1638 data[bas] = (byte)rightMove(v, 8);
1639 data[bas + 1] = (byte)v;
1647 void putFloat(
int bas,
float v)
1649 byte[] bytes = BitConverter.GetBytes(v);
1650 int tmp = BitConverter.ToInt32(bytes, 0);
1652 data[bas] = (byte)(tmp >> 24);
1653 data[bas + 1] = (byte)(tmp >> 16);
1654 data[bas + 2] = (byte)(tmp >> 8);
1655 data[bas + 3] = (byte)tmp;
1662 void putInt(
int bas,
int i)
1664 data[bas] = (byte)(i >> 24);
1665 data[bas + 1] = (byte)(i >> 16);
1666 data[bas + 2] = (byte)(i >> 8);
1667 data[bas + 3] = (byte)i;