BioImager  5.0.0
A .NET microscopy imaging application based on Bio library. Supports various microscopes by using imported libraries & GUI automation. Supports XInput game controllers to move stage, take images, run ImageJ macros on images or Bio C# scripts.
Loading...
Searching...
No Matches
ImageJ.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.Threading.Tasks;
6using System.Diagnostics;
7using System.IO;
8using CSScripting;
9using AForge;
10using Color = AForge.Color;
11using Rectangle = AForge.Rectangle;
12using PointF = AForge.PointF;
13using RectangleD = AForge.RectangleD;
14using BioLib;
15namespace BioImager
16{
17 public class ImageJ
18 {
19 public static class Macro
20 {
21 public class Command
22 {
23 public string Name { get; set; }
24 public string Arguments { get; set; }
25 public string Description { get; set; }
26 public Command(string name, string args, string description)
27 {
28 Name = name;
29 Arguments = args;
30 Description = description;
31 }
32 public override string ToString()
33 {
34 return Name.ToString();
35 }
36 }
37 public class Function
38 {
39 public string Name { get; set; }
40 public string Arguments { get; set; }
41 public string Description { get; set; }
42 public Function(string name, string args, string description)
43 {
44 Name = name;
45 Arguments = args;
46 Description = description;
47 }
48 public override string ToString()
49 {
50 return Name.ToString();
51 }
52 }
53 public static Dictionary<string, Command> Commands = new Dictionary<string, Command>();
54 public static Dictionary<string, List<Function>> Functions = new Dictionary<string, List<Function>>();
55 internal static void Initialize()
56 {
57 string[] sts = File.ReadAllLines(Path.GetDirectoryName(Environment.ProcessPath) + "/macro-functions.txt");
58 foreach (string s in sts)
59 {
60 string com = "";
61 string args = "";
62 string doc = "";
63 bool indoc = false, inargs = false;
64 if (!s.StartsWith('#'))
65 {
66 for (int i = 0; i < s.Length; i++)
67 {
68 if (!inargs)
69 {
70 if (s[i] != '(')
71 com += s[i];
72 else
73 inargs = true;
74 if (s[i] == ' ')
75 {
76 inargs = true;
77 indoc = true;
78 }
79 }
80 else
81 if (!indoc)
82 if (s[i] != ')')
83 args += s[i];
84 else
85 indoc = true;
86 else
87 doc += s[i];
88 }
89 if (!Functions.ContainsKey(com))
90 Functions.Add(com, new List<Function>() { new Function(com, args, doc) });
91 else
92 Functions[com].Add(new Function(com, args, doc));
93 }
94 }
95 string[] cs = File.ReadAllLines(Path.GetDirectoryName(Environment.ProcessPath) + "/macro-commands.csv");
96 foreach (string s in cs)
97 {
98 string[] v = s.Split(',');
99 Commands.Add(v[0], new Command(v[0], v[1], ""));
100 }
101 }
102 }
103 public static List<Macro.Command> Macros = new List<Macro.Command>();
104 public static List<Process> processes = new List<Process>();
105 public static string ImageJPath = Properties.Settings.Default.ImageJPath;
106 private static Random rng = new Random();
107 static bool init = false;
108 public static bool Initialized { get { return init; } private set { } }
115 public static void RunMacro(string file, string param)
116 {
117 if(!Initialized)
118 {
119 Initialize();
120 }
121 file.Replace("/", "\\");
122 Process pr = new Process();
123 pr.StartInfo.FileName = ImageJPath;
124 pr.StartInfo.Arguments = "-macro " + file + " " + param;
125
126 pr.Start();
127 processes.Add(pr);
128 Recorder.AddLine("ImageJ.RunMacro(" + file + "," + '"' + param + '"' + ");");
129 }
137 public static void RunString(string con, string param, bool headless)
138 {
139 if (!Initialized)
140 {
141 Initialize();
142 }
143 Process pr = new Process();
144 pr.StartInfo.FileName = ImageJPath;
145 pr.StartInfo.CreateNoWindow = true;
146 string te = rng.Next(0, 9999999).ToString();
147 string p = Environment.CurrentDirectory + "\\" + te + ".txt";
148 p.Replace("/", "\\");
149 File.WriteAllText(p,con);
150 if(headless)
151 pr.StartInfo.Arguments = "--headless -macro " + p + " " + param;
152 else
153 pr.StartInfo.Arguments = "-macro " + p + " " + param;
154 pr.Start();
155 File.Delete(Path.GetDirectoryName(ImageJPath) + "/done.txt");
156 processes.Add(pr);
157 do
158 {
159 if (File.Exists(Path.GetDirectoryName(ImageJPath) + "/done.txt"))
160 {
161 do
162 {
163 try
164 {
165 File.Delete(Path.GetDirectoryName(ImageJPath) + "/done.txt");
166 }
167 catch (Exception)
168 {
169
170 }
171 } while (File.Exists(Path.GetDirectoryName(ImageJPath) + "/done.txt"));
172 pr.Kill();
173 break;
174 }
175 } while (!pr.HasExited);
176 File.Delete(p);
177 }
189 public static async void RunOnImage(string con, bool headless, bool onTab, bool bioformats, bool newTab)
190 {
191 if (!Initialized)
192 {
193 Initialize();
194 }
195 string filename = "";
196 string dir = Path.GetDirectoryName(ImageView.SelectedImage.file);
197
198 if (ImageView.SelectedImage.ID.EndsWith(".ome.tif"))
199 {
200 filename = Path.GetFileNameWithoutExtension(ImageView.SelectedImage.ID);
201 filename = filename.Remove(filename.Length - 4, 4);
202 }
203 else
204 filename = Path.GetFileNameWithoutExtension(ImageView.SelectedImage.ID);
205 string file = dir + "\\" + filename + "-temp" + ".ome.tif";
206 file = file.Replace("\\", "/");
207 string st =
208 "run(\"Bio-Formats Importer\", \"open=\" + getArgument + \" autoscale color_mode=Default open_all_series display_rois rois_import=[ROI manager] view=Hyperstack stack_order=XYCZT\"); " + con +
209 "run(\"Bio-Formats Exporter\", \"save=" + file + " export compression=Uncompressed\"); " +
210 "dir = getDir(\"startup\"); " +
211 "File.saveString(\"done\", dir + \"/done.txt\");";
212 if(bioformats)
213 st =
214 "open(getArgument); " + con +
215 "run(\"Bio-Formats Exporter\", \"save=" + file + " export compression=Uncompressed\"); " +
216 "dir = getDir(\"startup\"); " +
217 "File.saveString(\"done\", dir + \"/done.txt\");";
218 //We save the image as a temp image as otherwise imagej won't export due to file access error.
219 RunString(st, ImageView.SelectedImage.file, headless);
220
221 if (!File.Exists(file))
222 return;
223
224 string ffile = dir + "/" + filename + ".ome.tif";
225 File.Delete(ffile);
226 File.Copy(file, ffile);
227 File.Delete(file);
228 if (ImageView.SelectedImage.Filename != filename + ".ome.tif" || ImageView.SelectedImage.Filename != filename + ".tif")
229 {
230 if (ImageView.SelectedImage.filename.EndsWith(".tif"))
231 BioImage.OpenFile(ffile, newTab);
232 else
233 BioImage.OpenFile(ffile, true);
234 }
235 else
236 {
237 App.viewer.Images[App.viewer.SelectedIndex] = await BioImage.OpenFile(ffile);
238 }
241 Recorder.AddLine("RunOnImage(\"" + con + "\"," + headless + "," + onTab + "," + newTab + ");");
242 }
243
247 public static bool Initialize()
248 {
249 if (!SetImageJPath())
250 return false;
251 Macro.Initialize();
252 string[] ds = Directory.GetFiles(Path.GetDirectoryName(ImageJPath) + "/macros");
253 foreach (string s in ds)
254 {
255 if (s.EndsWith(".ijm") || s.EndsWith(".txt"))
256 Macros.Add(new Macro.Command(Path.GetFileName(s), "", ""));
257 }
258 return true;
259 }
263 public static bool SetImageJPath()
264 {
265 if (Properties.Settings.Default.ImageJPath == "")
266 {
267 MessageBox.Show("ImageJ path not set. Set the ImageJ executable location.");
268 OpenFileDialog file = new OpenFileDialog();
269 file.Title = "Set the ImageJ executable location.";
270 if (file.ShowDialog() != DialogResult.OK)
271 return false;
272 Properties.Settings.Default.ImageJPath = file.FileName;
273 Properties.Settings.Default.Save();
274 ImageJPath = file.FileName;
275 init = true;
276 file.Dispose();
277 return true;
278 }
279 else
280 return true;
281 }
282
283 /* It reads a binary file and returns a ROI object */
284 public class RoiDecoder
285 {
286 #region Params
287 // offsets
288 public static int VERSION_OFFSET = 4;
289 public static int TYPE = 6;
290 public static int TOP = 8;
291 public static int LEFT = 10;
292 public static int BOTTOM = 12;
293 public static int RIGHT = 14;
294 public static int N_COORDINATES = 16;
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;
301 public static int WIDTHD = 26;
302 public static int HEIGHTD = 30;
303 public static int SIZE = 18;
304 public static int STROKE_WIDTH = 34;
305 public static int SHAPE_ROI_SIZE = 36;
306 public static int STROKE_COLOR = 40;
307 public static int FILL_COLOR = 44;
308 public static int SUBTYPE = 48;
309 public static int OPTIONS = 50;
310 public static int ARROW_STYLE = 52;
311 public static int FLOAT_PARAM = 52; //ellipse ratio or rotated rect width
312 public static int POINT_TYPE = 52;
313 public static int ARROW_HEAD_SIZE = 53;
314 public static int ROUNDED_RECT_ARC_SIZE = 54;
315 public static int POSITION = 56;
316 public static int HEADER2_OFFSET = 60;
317 public static int COORDINATES = 64;
318 // header2 offsets
319 public static int C_POSITION = 4;
320 public static int Z_POSITION = 8;
321 public static int T_POSITION = 12;
322 public static int NAME_OFFSET = 16;
323 public static int NAME_LENGTH = 20;
324 public static int OVERLAY_LABEL_COLOR = 24;
325 public static int OVERLAY_FONT_SIZE = 28; //short
326 public static int GROUP = 30; //byte
327 public static int IMAGE_OPACITY = 31; //byte
328 public static int IMAGE_SIZE = 32; //int
329 public static int FLOAT_STROKE_WIDTH = 36; //float
330 public static int ROI_PROPS_OFFSET = 40;
331 public static int ROI_PROPS_LENGTH = 44;
332 public static int COUNTERS_OFFSET = 48;
333
334 // subtypes
335 public static int TEXT = 1;
336 public static int ARROW = 2;
337 public static int ELLIPSE = 3;
338 public static int IMAGE = 4;
339 public static int ROTATED_RECT = 5;
340
341 // options
342 public static int SPLINE_FIT = 1;
343 public static int DOUBLE_HEADED = 2;
344 public static int OUTLINE = 4;
345 public static int OVERLAY_LABELS = 8;
346 public static int OVERLAY_NAMES = 16;
347 public static int OVERLAY_BACKGROUNDS = 32;
348 public static int OVERLAY_BOLD = 64;
349 public static int SUB_PIXEL_RESOLUTION = 128;
350 public static int DRAW_OFFSET = 256;
351 public static int ZERO_TRANSPARENT = 512;
352 public static int SHOW_LABELS = 1024;
353 public static int SCALE_LABELS = 2048;
354 public static int PROMPT_BEFORE_DELETING = 4096; //points
355 public static int SCALE_STROKE_WIDTH = 8192;
356
357 // types
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;
360
361 private byte[] data;
362 private string path;
363 private MemoryStream ins;
364 private string name;
365 private int size;
366 #endregion
367
369 public RoiDecoder(string path)
370 {
371 this.path = path;
372 }
373
375 public RoiDecoder(byte[] bytes, string name)
376 {
377 ins = new MemoryStream(bytes);
378 this.name = name;
379 this.size = bytes.Length;
380 }
381
383 public static ROI open(string path)
384 {
385 ROI roi = null;
386 RoiDecoder rd = new RoiDecoder(path);
387 roi = rd.getRoi();
388 return roi;
389 }
390
392 public ROI getRoi()
393 {
394 ROI roi = new ROI();
395 data = File.ReadAllBytes(path);
396 size = data.Length;
397 if (getByte(0) != 73 || getByte(1) != 111) //"Iout"
398 throw new IOException("This is not an ImageJ ROI");
399 int version = getShort(VERSION_OFFSET);
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;
408 int n = getUnsignedShort(N_COORDINATES);
409 if (n == 0)
410 n = getInt(SIZE);
411 int options = getShort(OPTIONS);
412 int position = getInt(POSITION);
413 int hdr2Offset = getInt(HEADER2_OFFSET);
414 int channel = 0, slice = 0, frame = 0;
415 int overlayLabelColor = 0;
416 int overlayFontSize = 0;
417 int group = 0;
418 int imageOpacity = 0;
419 int imageSize = 0;
420 bool subPixelResolution = (options & SUB_PIXEL_RESOLUTION) != 0 && version >= 222;
421 bool drawOffset = subPixelResolution && (options & DRAW_OFFSET) != 0;
422 bool scaleStrokeWidth = true;
423 if (version >= 228)
424 scaleStrokeWidth = (options & SCALE_STROKE_WIDTH) != 0;
425
426 bool subPixelRect = version >= 223 && subPixelResolution && (type == rect || type == oval);
427 double xd = 0.0, yd = 0.0, widthd = 0.0, heightd = 0.0;
428 if (subPixelRect)
429 {
430 xd = getFloat(XD);
431 yd = getFloat(YD);
432 widthd = getFloat(WIDTHD);
433 heightd = getFloat(HEIGHTD);
434 }
435
436 if (hdr2Offset > 0 && hdr2Offset + IMAGE_SIZE + 4 <= size)
437 {
438 channel = getInt(hdr2Offset + C_POSITION);
439 slice = getInt(hdr2Offset + Z_POSITION);
440 frame = getInt(hdr2Offset + T_POSITION);
441 overlayLabelColor = getInt(hdr2Offset + OVERLAY_LABEL_COLOR);
442 overlayFontSize = getShort(hdr2Offset + OVERLAY_FONT_SIZE);
443 imageOpacity = getByte(hdr2Offset + IMAGE_OPACITY);
444 imageSize = getInt(hdr2Offset + IMAGE_SIZE);
445 group = getByte(hdr2Offset + GROUP);
446 }
447
448 if (name != null && name.EndsWith(".roi"))
449 name = name.Substring(0, name.Length - 4);
450 bool isComposite = getInt(SHAPE_ROI_SIZE) > 0;
451
452
453 /*
454 if (isComposite)
455 {
456 roi = getShapeRoi();
457 if (version >= 218)
458 getStrokeWidthAndColor(roi, hdr2Offset, scaleStrokeWidth);
459 roi.coord.Z = position;
460 if (channel > 0 || slice > 0 || frame > 0)
461 {
462 roi.coord.C = channel; roi.coord.Z = slice; roi.coord.T = frame;
463 }
464 decodeOverlayOptions(roi, version, options, overlayLabelColor, overlayFontSize);
465 if (version >= 224)
466 {
467 string props = getRoiProps();
468 if (props != null)
469 roi.properties = props;
470 }
471 if (version >= 228 && group > 0)
472 roi.serie = group;
473 return roi;
474 }
475 */
476 switch (type)
477 {
478 case 1: //BoundingBox
479 if (subPixelRect)
480 roi = ROI.CreateRectangle(new ZCT(slice - 1, channel - 1, frame - 1), xd, yd, widthd, heightd);
481 else
482 roi = ROI.CreateRectangle(new ZCT(slice - 1, channel - 1, frame - 1), left, top, width, height);
483 int arcSize = getShort(ROUNDED_RECT_ARC_SIZE);
484 if (arcSize > 0)
485 throw new NotSupportedException("Type rounded rectangle not supported.");
486 break;
487 case 2: //Ellipse
488 if (subPixelRect)
489 roi = ROI.CreateEllipse(new ZCT(slice - 1, channel - 1, frame - 1), xd, yd, widthd, heightd);
490 else
491 roi = ROI.CreateEllipse(new ZCT(slice - 1, channel - 1, frame - 1), left, top, width, height);
492 break;
493 case 3: //Line
494 float x1 = getFloat(X1);
495 float y1 = getFloat(Y1);
496 float x2 = getFloat(X2);
497 float y2 = getFloat(Y2);
498
499 if (subtype == ARROW)
500 {
501 throw new NotSupportedException("Type arrow not supported.");
502 /*
503 roi = new Arrow(x1, y1, x2, y2);
504 ((Arrow)roi).setDoubleHeaded((options & DOUBLE_HEADED) != 0);
505 ((Arrow)roi).setOutline((options & OUTLINE) != 0);
506 int style = getByte(ARROW_STYLE);
507 if (style >= Arrow.FILLED && style <= Arrow.BAR)
508 ((Arrow)roi).setStyle(style);
509 int headSize = getByte(ARROW_HEAD_SIZE);
510 if (headSize >= 0 && style <= 30)
511 ((Arrow)roi).setHeadSize(headSize);
512 */
513 }
514 else
515 {
516 roi = ROI.CreateLine(new ZCT(slice, channel, frame), new PointD(x1, y1), new PointD(x2, y2));
517 //roi.setDrawOffset(drawOffset);
518 }
519
520 break;
521 case 0:
522 case 5:
523 case 6:
524 case 7:
525 case 8:
526 case 9:
527 case 10:
528 //IJ.log("type: "+type);
529 //IJ.log("n: "+n);
530 //ij.IJ.log("rect: "+left+","+top+" "+width+" "+height);
531 if (n == 0 || n < 0) break;
532 int[] x = new int[n];
533 int[] y = new int[n];
534 float[] xf = null;
535 float[] yf = null;
536 int base1 = COORDINATES;
537 int base2 = base1 + 2 * n;
538 int xtmp, ytmp;
539 for (int i = 0; i < n; i++)
540 {
541 xtmp = getShort(base1 + i * 2);
542 if (xtmp < 0) xtmp = 0;
543 ytmp = getShort(base2 + i * 2);
544 if (ytmp < 0) ytmp = 0;
545 x[i] = left + xtmp;
546 y[i] = top + ytmp;
547 }
548 if (subPixelResolution)
549 {
550 xf = new float[n];
551 yf = new float[n];
552 base1 = COORDINATES + 4 * n;
553 base2 = base1 + 4 * n;
554 for (int i = 0; i < n; i++)
555 {
556 xf[i] = getFloat(base1 + i * 4);
557 yf[i] = getFloat(base2 + i * 4);
558 }
559 }
560 if (type == point)
561 {
562 //TODO implement non subpizel ROI
563 if (subPixelResolution)
564 {
565 roi.AddPoints(xf, yf);
566 }
567 else
568 roi.AddPoints(x, y);
569 if (version >= 226)
570 {
571 //((PointRoi)roi).setPointType(getByte(POINT_TYPE));
572 roi.strokeWidth = getShort(STROKE_WIDTH);
573 }
574 //if ((options & SHOW_LABELS) != 0 && !ij.Prefs.noPointLabels)
575 // ((PointRoi)roi).setShowLabels(true);
576 //if ((options & PROMPT_BEFORE_DELETING) != 0)
577 // ((PointRoi)roi).promptBeforeDeleting(true);
578 roi.type = ROI.Type.Point;
579 break;
580 }
581 if (type == polygon)
582 roi.type = ROI.Type.Polygon;
583 else if (type == freehand)
584 {
585 roi.type = ROI.Type.Freeform;
586 if (subtype == ELLIPSE || subtype == ROTATED_RECT)
587 {
588 throw new NotSupportedException("ROI type not supported.");
589 /*
590 double ex1 = getFloat(X1);
591 double ey1 = getFloat(Y1);
592 double ex2 = getFloat(X2);
593 double ey2 = getFloat(Y2);
594 double param = getFloat(FLOAT_PARAM);
595 if (subtype == ROTATED_RECT)
596 roi = new RotatedRectRoi(ex1, ey1, ex2, ey2, param);
597 else
598 roi = new EllipseRoi(ex1, ey1, ex2, ey2, param);
599 break;
600 */
601 }
602 }
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;
611 else
612 roi.type = ROI.Type.Freeform;
613 if (subPixelResolution)
614 {
615 roi.AddPoints(xf, yf);
616 //roi = new PolygonRoi(xf, yf, n, roiType);
617 //roi.setDrawOffset(drawOffset);
618 }
619 else
620 roi.AddPoints(x, y);
621 break;
622 default:
623 throw new IOException("Unrecognized ROI type: " + type);
624 }
625 if (roi == null)
626 return null;
627 roi.roiName = getRoiName();
628
629 // read stroke width, stroke color and fill color (1.43i or later)
630 if (version >= 218)
631 {
632 getStrokeWidthAndColor(roi, hdr2Offset, scaleStrokeWidth);
633 /*
634 if (type == point)
635 roi.setStrokeWidth(0);
636 bool splineFit = (options & SPLINE_FIT) != 0;
637 if (splineFit && roi instanceof PolygonRoi)
638 ((PolygonRoi)roi).fitSpline();
639 */
640 }
641
642 if (version >= 218 && subtype == TEXT)
643 {
644 getTextRoi(roi, version);
645 roi.type = ROI.Type.Label;
646 }
647 /*
648 if (version >= 221 && subtype == IMAGE)
649 roi = getImageRoi(roi, imageOpacity, imageSize, options);
650
651 if (version >= 224)
652 {
653 string props = getRoiProps();
654 if (props != null)
655 roi.setProperties(props);
656 }
657
658 if (version >= 227)
659 {
660 int[] counters = getPointCounters(n);
661 if (counters != null && (roi instanceof PointRoi))
662 ((PointRoi)roi).setCounters(counters);
663 }
664 */
665 // set group (1.52t or later)
666 if (version >= 228 && group > 0)
667 roi.serie = group;
668
669 roi.coord.Z = position;
670 if (channel > 0 || slice > 0 || frame > 0)
671 roi.coord = new ZCT(slice - 1, channel - 1, frame - 1); //-1 because our ROI coordinates are 0 based
672 //decodeOverlayOptions(roi, version, options, overlayLabelColor, overlayFontSize);
673
674 //We convert pixel to subpixel
675
676 for (int i = 0; i < roi.Points.Count; i++)
677 {
678 PointD pd = ImageView.SelectedImage.ToStageSpace(roi.Points[i]);
679 roi.Points[i] = pd;
680 roi.UpdateBoundingBox();
681 }
682
683 if (roi.type == ROI.Type.Polygon || roi.type == ROI.Type.Freeform)
684 roi.closed = true;
685 return roi;
686 }
687 /*
688 void decodeOverlayOptions(ROI roi, int version, int options, int color, int fontSize)
689 {
690
691 Overlay proto = new Overlay();
692 proto.drawLabels((options & OVERLAY_LABELS) != 0);
693 proto.drawNames((options & OVERLAY_NAMES) != 0);
694 proto.drawBackgrounds((options & OVERLAY_BACKGROUNDS) != 0);
695 if (version >= 220 && color != 0)
696 proto.setLabelColor(new Color(color));
697 bool bold = (options & OVERLAY_BOLD) != 0;
698 bool scalable = (options & SCALE_LABELS) != 0;
699 if (fontSize > 0 || bold || scalable)
700 {
701 proto.setLabelFont(new Font("SansSerif", bold ? Font.BOLD : Font.PLAIN, fontSize), scalable);
702 }
703 roi.setPrototypeOverlay(proto);
704
705 }
706 */
712 void getStrokeWidthAndColor(ROI roi, int hdr2Offset, bool scaleStrokeWidth)
713 {
714 double strokeWidth = getShort(STROKE_WIDTH);
715 if (hdr2Offset > 0)
716 {
717 double strokeWidthD = getFloat(hdr2Offset + FLOAT_STROKE_WIDTH);
718 if (strokeWidthD > 0.0)
719 strokeWidth = strokeWidthD;
720 }
721 if (strokeWidth > 0.0)
722 {
723 roi.strokeWidth = strokeWidth;
724 }
725 int strokeColor = getInt(STROKE_COLOR);
726 if (strokeColor != 0)
727 {
728 byte[] bts = BitConverter.GetBytes(strokeColor);
729 Color c = Color.FromArgb(bts[0], bts[1], bts[2], bts[3]);
730 roi.strokeColor = c;
731 }
732 int fillColor = getInt(FILL_COLOR);
733 if (fillColor != 0)
734 {
735 byte[] bts = BitConverter.GetBytes(strokeColor);
736 Color c = Color.FromArgb(bts[0], bts[1], bts[2], bts[3]);
737 roi.fillColor = c;
738 }
739 }
740 /*
741 public ROI getShapeRoi()
742 {
743 int type = getByte(TYPE);
744 if (type!=rect)
745 throw new NotSupportedException("Invalid composite ROI type");
746 int top = getShort(TOP);
747 int left = getShort(LEFT);
748 int bottom = getShort(BOTTOM);
749 int right = getShort(RIGHT);
750 int width = right - left;
751 int height = bottom - top;
752 int n = getInt(SHAPE_ROI_SIZE);
753
754 ROI roi = new ROI();
755 float[] shapeArray = new float[n];
756 int bas = COORDINATES;
757 for (int i = 0; i < n; i++)
758 {
759 shapeArray[i] = getFloat(bas);
760 bas += 4;
761 }
762 roi = new ShapeRoi(shapeArray);
763 roi.setName(getRoiName());
764 return roi;
765 }
766 */
772 void getTextRoi(ROI roi, int version)
773 {
774 Rectangle r = roi.BoundingBox.ToRectangleInt();
775 int hdrSize = 64;
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;
790 //Font font = new Font(new string(name), style, size);
791 string fam = new string(name);
792 roi.family = fam;
793 roi.fontSize = size;
794 roi.Text = new string(text);
795 /*
796 if (roi.subPixel)
797 {
798 RectangleD fb = roi.BoundingBox;
799 roi2 = new TextRoi(fb.getX(), fb.getY(), fb.getWidth(), fb.getHeight(), new string(text), font);
800 }
801 else
802 roi2 = new TextRoi(r.x, r.y, r.width, r.height, new string(text), font);
803
804 roi.strokeColor
805 roi2.setFillColor(roi.getFillColor());
806 roi2.setName(getRoiName());
807 roi2.setJustification(justification);
808 roi2.setDrawStringMode(drawStringMode);
809 roi2.setAngle(angle);
810 return roi2;
811 */
812 }
813
817 string getRoiName()
818 {
819 string fileName = name;
820 int hdr2Offset = getInt(HEADER2_OFFSET);
821 if (hdr2Offset == 0)
822 return fileName;
823 int offset = getInt(hdr2Offset + NAME_OFFSET);
824 int Length = getInt(hdr2Offset + NAME_LENGTH);
825 if (offset == 0 || Length == 0)
826 return fileName;
827 if (offset + Length * 2 > size)
828 return fileName;
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);
833 }
834
838 string getRoiProps()
839 {
840 int hdr2Offset = getInt(HEADER2_OFFSET);
841 if (hdr2Offset == 0)
842 return null;
843 int offset = getInt(hdr2Offset + ROI_PROPS_OFFSET);
844 int Length = getInt(hdr2Offset + ROI_PROPS_LENGTH);
845 if (offset == 0 || Length == 0)
846 return null;
847 if (offset + Length * 2 > size)
848 return null;
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);
853 }
854
860 int[] getPointCounters(int n)
861 {
862 int hdr2Offset = getInt(HEADER2_OFFSET);
863 if (hdr2Offset == 0)
864 return null;
865 int offset = getInt(hdr2Offset + COUNTERS_OFFSET);
866 if (offset == 0)
867 return null;
868 if (offset + n * 4 > data.Length)
869 return null;
870 int[] counters = new int[n];
871 for (int i = 0; i < n; i++)
872 counters[i] = getInt(offset + i * 4);
873 return counters;
874 }
875
876
882 int getByte(int bas)
883 {
884 return data[bas] & 255;
885 }
886
893 int getShort(int bas)
894 {
895 int b0 = data[bas] & 255;
896 int b1 = data[bas + 1] & 255;
897 int n = (short)((b0 << 8) + b1);
898 if (n < -5000)
899 n = (b0 << 8) + b1; // assume n>32767 and unsigned
900 return n;
901 }
902
908 int getUnsignedShort(int bas)
909 {
910 int b0 = data[bas] & 255;
911 int b1 = data[bas + 1] & 255;
912 return (b0 << 8) + b1;
913 }
914
920 int getInt(int bas)
921 {
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);
927 }
928
935 float getFloat(int bas)
936 {
937 //return BitConverter.ToSingle(getInt(bas));
938 byte[] bytes = BitConverter.GetBytes(getInt(bas));
939 return BitConverter.ToSingle(bytes, 0);
940 }
941
947 public static ROI openFromByteArray(byte[] bytes)
948 {
949 ROI roi = null;
950 if (bytes == null || bytes.Length == 0)
951 return roi;
952 try
953 {
954 RoiDecoder decoder = new RoiDecoder(bytes, null);
955 roi = decoder.getRoi();
956 }
957 catch (IOException e)
958 {
959 return null;
960 }
961 return roi;
962 }
963
964 }
965
971 static int GetImageJType(ROI roi)
972 {
973 //private int polygon = 0, rect = 1, oval = 2, line = 3, freeline = 4, polyline = 5, noRoi = 6, freehand = 7,
974 // traced = 8, angle = 9, point = 10;
975 switch (roi.type)
976 {
977 case ROI.Type.Rectangle:
978 return 1;
979 case ROI.Type.Point:
980 return 10;
981 case ROI.Type.Line:
982 return 3;
983 case ROI.Type.Polygon:
984 return 0;
985 case ROI.Type.Polyline:
986 return 5;
987 case ROI.Type.Freeform:
988 return 7;
989 case ROI.Type.Ellipse:
990 return 2;
991 case ROI.Type.Label:
992 default:
993 return 0;
994 }
995 }
996
1002 static void GetPointsXY(ROI roi, out int[] xp, out int[] yp)
1003 {
1004 int[] x = new int[roi.Points.Count];
1005 int[] y = new int[roi.Points.Count];
1006 for (int i = 0; i < roi.Points.Count; i++)
1007 {
1008 PointD pd = ImageView.SelectedImage.ToImageSpace(roi.Points[i]);
1009 x[i] = (int)pd.X;
1010 y[i] = (int)pd.Y;
1011 }
1012 xp = x;
1013 yp = y;
1014
1015 }
1016
1022 static void GetXY(ROI roi, out float x, out float y)
1023 {
1024 PointD pd = ImageView.SelectedImage.ToImageSpace(new PointD(roi.X, roi.Y));
1025 x = (float)pd.X;
1026 y = (float)pd.Y;
1027 }
1033 static void GetWH(ROI roi, out float w, out float h)
1034 {
1035 w = (float)ImageView.SelectedImage.ToImageSizeX(roi.W);
1036 h = (float)ImageView.SelectedImage.ToImageSizeY(roi.H);
1037 }
1045 static int rightMove(int value, int pos)
1046 {
1047 if (pos != 0)
1048 {
1049 int mask = 0x7fffffff;
1050 value >>= 1;
1051 value &= mask;
1052 value >>= pos - 1;
1053 }
1054 return value;
1055 }
1056 /* It takes a ROI object and writes it to a file */
1057 public class RoiEncoder
1058 {
1059 static int HEADER_SIZE = 64;
1060 static int HEADER2_SIZE = 64;
1061 static int VERSION = 228; // v1.52t (roi groups, scale stroke width)
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;
1074
1076 public RoiEncoder(String path)
1077 {
1078 this.path = path;
1079 }
1080
1082 public RoiEncoder(FileStream f)
1083 {
1084 this.f = f;
1085 }
1086
1088 public static bool save(ROI roi, String path)
1089 {
1090 RoiEncoder re = new RoiEncoder(path);
1091 try
1092 {
1093 re.write(roi);
1094 }
1095 catch (IOException e)
1096 {
1097 return false;
1098 }
1099 return true;
1100 }
1101
1103 public void write(ROI roi)
1104 {
1105 if (f != null)
1106 {
1107 write(roi, f);
1108
1109 }
1110 else
1111 {
1112 f = new FileStream(path, FileMode.Create);
1113 write(roi, f);
1114 f.Close();
1115 }
1116 }
1117
1144 void write(ROI roi, FileStream f)
1145 {
1146 RectangleD r = new RectangleD(roi.BoundingBox.X, roi.BoundingBox.Y, roi.BoundingBox.W, roi.BoundingBox.H);
1147 //if (r.width > 60000 || r.height > 60000 || r.x > 60000 || r.y > 60000)
1148 // roi.enableSubPixelResolution();
1149 //int roiType = GetImageJType(roi);
1150 int type = GetImageJType(roi);
1151 int options = 0;
1152 //if (roi.getScaleStrokeWidth())
1153 // options |= RoiDecoder.SCALE_STROKE_WIDTH;
1154 roiName = roi.Text;
1155 if (roiName != null)
1156 roiNameSize = roiName.Length * 2;
1157 else
1158 roiNameSize = 0;
1159
1160 roiProps = roi.properties;
1161 if (roiProps != null)
1162 roiPropsSize = roiProps.Length * 2;
1163 else
1164 roiPropsSize = 0;
1165 /*
1166 switch (roiType) {
1167 case Roi.POLYGON: type = polygon; break;
1168 case Roi.FREEROI: type = freehand; break;
1169 case Roi.TRACED_ROI: type = traced; break;
1170 case Roi.OVAL: type = oval; break;
1171 case Roi.LINE: type = line; break;
1172 case Roi.POLYLINE: type = polyline; break;
1173 case Roi.FREELINE: type = freeline; break;
1174 case Roi.ANGLE: type = angle; break;
1175 case Roi.COMPOSITE: type = rect; break; // shape array size (36-39) will be >0 to indicate composite type
1176 case Roi.POINT: type = point; break;
1177 default: type = rect; break;
1178 }
1179 */
1180 /*
1181 if (roiType == Roi.COMPOSITE) {
1182 saveShapeRoi(roi, type, f, options);
1183 return;
1184 }
1185 */
1186 int n = 0;
1187 int[]
1188 x = null, y = null;
1189 float[]
1190 xf = null, yf = null;
1191 int floatSize = 0;
1192 //if (roi instanceof PolygonRoi) {
1193 //PolygonRoi proi = (PolygonRoi)roi;
1194 //Polygon p = proi.getNonSplineCoordinates();
1195 n = roi.Points.Count; //p.npoints;
1196 //x = p.xpoints;
1197 //y = p.ypoints;
1198 GetPointsXY(roi, out x, out y);
1199 if (subres)
1200 {
1201 /*
1202 if (proi.isSplineFit())
1203 fp = proi.getNonSplineFloatPolygon();
1204 else
1205 fp = roi.getFloatPolygon();
1206 if (n == fp.npoints)
1207 {
1208 options |= RoiDecoder.SUB_PIXEL_RESOLUTION;
1209 if (roi.getDrawOffset())
1210 options |= RoiDecoder.DRAW_OFFSET;
1211 xf = fp.xpoints;
1212 yf = fp.ypoints;
1213 floatSize = n * 8;
1214 }
1215 */
1216 }
1217
1218
1219 countersSize = 0;
1220 /*
1221 if (roi instanceof PointRoi) {
1222 counters = ((PointRoi)roi).getCounters();
1223 if (counters != null && counters.length >= n)
1224 countersSize = n * 4;
1225 }
1226 */
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; // "Iout"
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));
1238 var PointsImage = ImageView.SelectedImage.ToImageSpace(roi.Points);
1239 if (subres && (type == rect || type == oval))
1240 {
1241 //FloatPolygon p = null;
1242 /*
1243 if (roi instanceof OvalRoi)
1244 p = ((OvalRoi)roi).getFloatPolygon4();
1245 else
1246 {
1247 int d = roi.getCornerDiameter();
1248 if (d > 0)
1249 {
1250 roi.setCornerDiameter(0);
1251 p = roi.getFloatPolygon();
1252 roi.setCornerDiameter(d);
1253 }
1254 else
1255 p = roi.getFloatPolygon();
1256 }
1257 */
1258 if (roi.Points.Count == 4)
1259 {
1260 putFloat(RoiDecoder.XD, (float)PointsImage[0].X);
1261 putFloat(RoiDecoder.YD, (float)PointsImage[0].Y);
1262 //putFloat(RoiDecoder.WIDTHD, p.xpoints[1] - roi.Points[0]);
1263 //putFloat(RoiDecoder.HEIGHTD, p.ypoints[2] - p.ypoints[1]);
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);
1268 }
1269 }
1270 if (n > 65535 && type != point)
1271 {
1272 if (type == polygon || type == freehand || type == traced)
1273 {
1274 //String name = roi.Text;
1275 //roi = new ShapeRoi(roi);
1276 //if (name != null) roi.setName(name);
1277 saveShapeRoi(roi, rect, f, options);
1278 return;
1279 }
1280 //ij.IJ.beep();
1281 //ij.IJ.log("Non-polygonal selections with more than 65k points cannot be saved.");
1282 n = 65535;
1283 }
1284 if (type == point && n > 65535)
1285 putInt(RoiDecoder.SIZE, n);
1286 else
1287 putShort(RoiDecoder.N_COORDINATES, n);
1288 putInt(RoiDecoder.POSITION, roi.coord.Z);
1289
1290 /*
1291 if (type == rect)
1292 {
1293 int arcSize = roi.getCornerDiameter();
1294 if (arcSize > 0)
1295 putShort(RoiDecoder.ROUNDED_RECT_ARC_SIZE, arcSize);
1296 }
1297 */
1298
1299 if (type == line) //(roi instanceof Line)
1300 {
1301 //Line line = (Line)roi;
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);
1306 /*
1307 if (roi instanceof Arrow) {
1308 putShort(RoiDecoder.SUBTYPE, RoiDecoder.ARROW);
1309 if (((Arrow)roi).getDoubleHeaded())
1310 options |= RoiDecoder.DOUBLE_HEADED;
1311 if (((Arrow)roi).getOutline())
1312 options |= RoiDecoder.OUTLINE;
1313 putShort(RoiDecoder.OPTIONS, options);
1314 putByte(RoiDecoder.ARROW_STYLE, ((Arrow)roi).getStyle());
1315 putByte(RoiDecoder.ARROW_HEAD_SIZE, (int)((Arrow)roi).getHeadSize());
1316 } else
1317 {
1318 if (roi.getDrawOffset())
1319 options |= RoiDecoder.SUB_PIXEL_RESOLUTION + RoiDecoder.DRAW_OFFSET;
1320 }
1321 */
1322 }
1323
1324 if (type == point)
1325 {
1326 //PointRoi point = (PointRoi)roi;
1327 putByte(RoiDecoder.POINT_TYPE, 1);//point.getPointType());
1328 putShort(RoiDecoder.STROKE_WIDTH, (int)roi.strokeWidth);
1329 /*
1330 if (point.getShowLabels())
1331 options |= RoiDecoder.SHOW_LABELS;
1332 if (point.promptBeforeDeleting())
1333 options |= RoiDecoder.PROMPT_BEFORE_DELETING;
1334 */
1335 }
1336
1337 if (type == oval)
1338 {
1339 /*
1340 double[] p = null;
1341 if (roi instanceof RotatedRectRoi) {
1342 putShort(RoiDecoder.SUBTYPE, RoiDecoder.ROTATED_RECT);
1343 p = ((RotatedRectRoi)roi).getParams();
1344 } else
1345 {
1346 */
1347 putShort(RoiDecoder.SUBTYPE, RoiDecoder.ELLIPSE);
1348 //p = ((EllipseRoi)roi).getParams();
1349 //}
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);
1357 //putFloat(RoiDecoder.FLOAT_PARAM, (float)p[4]);
1358 }
1359
1360 // save stroke width, stroke color and fill color (1.43i or later)
1361 if (VERSION >= 218)
1362 {
1363 saveStrokeWidthAndColor(roi);
1364 /*
1365 if ((roi instanceof PolygonRoi) && ((PolygonRoi)roi).isSplineFit()) {
1366 options |= RoiDecoder.SPLINE_FIT;
1367 putShort(RoiDecoder.OPTIONS, options);
1368 }
1369 */
1370 }
1371
1372 if (roi.type == ROI.Type.Label)//(n == 0 && roi instanceof TextRoi)
1373 saveTextRoi(roi);
1374 /*
1375 else if (n == 0 && roi instanceof ImageRoi)
1376 options = saveImageRoi((ImageRoi)roi, options);
1377 */
1378 //else
1379 putHeader2(roi, HEADER_SIZE + n * 4 + floatSize);
1380
1381 if (n > 0)
1382 {
1383 int base1 = 64;
1384 int base2 = base1 + 2 * n;
1385 for (int i = 0; i < n; i++)
1386 {
1387 putShort(base1 + i * 2, (int)(x[i] - px));
1388 putShort(base2 + i * 2, (int)(y[i] - py));
1389 }
1390 if (xf != null)
1391 {
1392 base1 = 64 + 4 * n;
1393 base2 = base1 + 4 * n;
1394 for (int i = 0; i < n; i++)
1395 {
1396 putFloat(base1 + i * 4, xf[i]);
1397 putFloat(base2 + i * 4, yf[i]);
1398 }
1399 }
1400 }
1401
1402 //saveOverlayOptions(roi, options);
1403 f.Write(data,0,data.Length);
1404 }
1405
1409 void saveStrokeWidthAndColor(ROI roi)
1410 {
1411 //BasicStroke stroke = roi.getStroke();
1412 //if (stroke != null)
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);
1417 Color fillColor = roi.fillColor;
1418 int intFillColor = (fillColor.R << 16) | (fillColor.G << 8) | (fillColor.B);
1419 putInt(RoiDecoder.FILL_COLOR, 0);
1420 }
1421
1429 void saveShapeRoi(ROI roi, int type, FileStream f, int options)
1430 {
1431 //float[] shapeArray = ((ShapeRoi)roi).getShapeAsArray();
1432 //if (shapeArray == null) return;
1433 //BufferedOutputStream bout = new BufferedOutputStream(f);
1434
1435 data = new byte[HEADER_SIZE + HEADER2_SIZE + roiNameSize + roiPropsSize];//shapeArray.length * 4 + roiNameSize + roiPropsSize];
1436 data[0] = 73; data[1] = 111; data[2] = 117; data[3] = 116; // "Iout"
1437
1438 putShort(RoiDecoder.VERSION_OFFSET, VERSION);
1439 data[RoiDecoder.TYPE] = (byte)type;
1440
1441 float x, y, w, h;
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);
1450 //putInt(36, shapeArray.Length); // non-zero segment count indicate composite type
1451 if (VERSION >= 218)
1452 saveStrokeWidthAndColor(roi);
1453 //saveOverlayOptions(roi, options);
1454
1455 // handle the actual data: data are stored segment-wise, i.e.,
1456 // the type of the segment followed by 0-6 control point coordinates.
1457 /*
1458 int bas = 64;
1459 for (int i = 0; i < shapeArray.Length; i++)
1460 {
1461 putFloat(bas, shapeArray[i]);
1462 bas += 4;
1463 }
1464 */
1465 int hdr2Offset = HEADER_SIZE;// + shapeArray.Length * 4;
1466 //ij.IJ.log("saveShapeRoi: "+HEADER_SIZE+" "+shapeArray.length);
1467 putHeader2(roi, hdr2Offset);
1468 f.Write(data, 0, data.Length);
1469 f.Flush();
1470 }
1471
1472 /*
1473 void saveOverlayOptions(ROI roi, int options)
1474 {
1475 Overlay proto = roi.getPrototypeOverlay();
1476 if (proto.getDrawLabels())
1477 options |= RoiDecoder.OVERLAY_LABELS;
1478 if (proto.getDrawNames())
1479 options |= RoiDecoder.OVERLAY_NAMES;
1480 if (proto.getDrawBackgrounds())
1481 options |= RoiDecoder.OVERLAY_BACKGROUNDS;
1482 Font font = proto.getLabelFont();
1483 if (font != null && font.getStyle() == Font.BOLD)
1484 options |= RoiDecoder.OVERLAY_BOLD;
1485 if (proto.scalableLabels())
1486 options |= RoiDecoder.SCALE_LABELS;
1487 putShort(RoiDecoder.OPTIONS, options);
1488 }
1489 */
1493 void saveTextRoi(ROI roi)
1494 {
1495 //Font font = roi.getCurrentFont();
1496 string fontName = roi.family.ToString();
1497 int size = (int)roi.fontSize;
1498 int drawStringMode = 0; //roi.getDrawStringMode() ? 1024 : 0;
1499 int style = 0;//font.getStyle() + roi.getJustification() * 256 + drawStringMode;
1500 string text = roi.roiName;
1501 float angle = 0;
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);
1508 data = data2;
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;
1519 //ij.IJ.log("saveTextRoi: "+HEADER_SIZE+" "+textRoiDataLength+" "+fontNameLength+" "+textLength);
1520 putFloat(hdr2Offset - angleLength, angle);
1521 putHeader2(roi, hdr2Offset);
1522 }
1523 /*
1524 private int saveImageRoi(ROI roi, int options)
1525 {
1526 byte[] bytes = roi.getSerializedImage();
1527 int imageSize = bytes.length;
1528 byte[] data2 = new byte[HEADER_SIZE + HEADER2_SIZE + imageSize + roiNameSize + roiPropsSize];
1529 System.arraycopy(data, 0, data2, 0, HEADER_SIZE);
1530 data = data2;
1531 putShort(RoiDecoder.SUBTYPE, RoiDecoder.IMAGE);
1532 for (int i = 0; i < imageSize; i++)
1533 putByte(HEADER_SIZE + i, bytes[i] & 255);
1534 int hdr2Offset = HEADER_SIZE + imageSize;
1535 double opacity = roi.getOpacity();
1536 putByte(hdr2Offset + RoiDecoder.IMAGE_OPACITY, (int)(opacity * 255.0));
1537 putInt(hdr2Offset + RoiDecoder.IMAGE_SIZE, imageSize);
1538 if (roi.getZeroTransparent())
1539 options |= RoiDecoder.ZERO_TRANSPARENT;
1540 putHeader2(roi, hdr2Offset);
1541 return options;
1542 }
1543 */
1548 void putHeader2(ROI roi, int hdr2Offset)
1549 {
1550 //ij.IJ.log("putHeader2: "+hdr2Offset+" "+roiNameSize+" "+roiName);
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);
1555 //Overlay proto = roi.getPrototypeOverlay();
1556 Color overlayLabelColor = roi.strokeColor; //proto.getLabelColor();
1557 int intColor = (overlayLabelColor.R << 16) | (overlayLabelColor.G << 8) | (overlayLabelColor.B);
1558 //if (overlayLabelColor != null)
1559 putInt(hdr2Offset + RoiDecoder.OVERLAY_LABEL_COLOR, 0);
1560 //Font font = proto.getLabelFont();
1561 //if (font != null)
1562 putShort(hdr2Offset + RoiDecoder.OVERLAY_FONT_SIZE, (int)roi.fontSize);
1563 if (roiNameSize > 0)
1564 putName(roi, hdr2Offset);
1565 double strokeWidth = roi.strokeWidth;
1566 //if (roi.getStroke() == null)
1567 // strokeWidth = 0.0;
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);//roi.getGroup());
1574 }
1575
1581 void putName(ROI roi, int hdr2Offset)
1582 {
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));
1589 }
1590
1598 void putProps(ROI roi, int hdr2Offset)
1599 {
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));
1606 }
1607
1612 void putPointCounters(ROI roi, int hdr2Offset)
1613 {
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]);
1618 countersSize = 0;
1619 }
1620
1625 void putByte(int bas, int v)
1626 {
1627 data[bas] = (byte)v;
1628 }
1629
1634 void putShort(int bas, int v)
1635 {
1636 //data[bas] = (byte)(v >>> 8);
1637 //data[bas] = (byte)UnsignedRightShift(v, 8);
1638 data[bas] = (byte)rightMove(v, 8);
1639 data[bas + 1] = (byte)v;
1640 }
1641
1647 void putFloat(int bas, float v)
1648 {
1649 byte[] bytes = BitConverter.GetBytes(v);
1650 int tmp = BitConverter.ToInt32(bytes, 0);
1651 //int tmp = BitConverter.SingleToInt32Bits(v);//Float.floatToIntBits(v);
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;
1656 }
1657
1662 void putInt(int bas, int i)
1663 {
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;
1668 }
1669 }
1670
1671 }
1672}
AForge.RectangleD RectangleD
AForge.Color Color
AForge.Rectangle Rectangle
AForge.PointF PointF
AForge.PointD PointD
BioLib.BioImage BioImage
Definition TabsView.cs:15
AForge.ZCT ZCT
Definition TabsView.cs:17
static ImageView viewer
Definition App.cs:23
Command(string name, string args, string description)
Definition ImageJ.cs:26
override string ToString()
Definition ImageJ.cs:32
override string ToString()
Definition ImageJ.cs:48
Function(string name, string args, string description)
Definition ImageJ.cs:42
static Dictionary< string, List< Function > > Functions
Definition ImageJ.cs:54
static Dictionary< string, Command > Commands
Definition ImageJ.cs:53
RoiDecoder(string path)
Definition ImageJ.cs:369
static int ZERO_TRANSPARENT
Definition ImageJ.cs:351
static int OVERLAY_LABEL_COLOR
Definition ImageJ.cs:324
static int PROMPT_BEFORE_DELETING
Definition ImageJ.cs:354
static int SUB_PIXEL_RESOLUTION
Definition ImageJ.cs:349
static int OVERLAY_FONT_SIZE
Definition ImageJ.cs:325
static ROI openFromByteArray(byte[] bytes)
Definition ImageJ.cs:947
static int ROUNDED_RECT_ARC_SIZE
Definition ImageJ.cs:314
static int SCALE_STROKE_WIDTH
Definition ImageJ.cs:355
static int ROI_PROPS_OFFSET
Definition ImageJ.cs:330
RoiDecoder(byte[] bytes, string name)
Definition ImageJ.cs:375
static ROI open(string path)
Definition ImageJ.cs:383
static int OVERLAY_BACKGROUNDS
Definition ImageJ.cs:347
static int ROI_PROPS_LENGTH
Definition ImageJ.cs:331
static int FLOAT_STROKE_WIDTH
Definition ImageJ.cs:329
RoiEncoder(FileStream f)
Definition ImageJ.cs:1082
static bool save(ROI roi, String path)
Definition ImageJ.cs:1088
static List< Process > processes
Definition ImageJ.cs:104
static bool SetImageJPath()
Definition ImageJ.cs:263
static void RunMacro(string file, string param)
Definition ImageJ.cs:115
static void RunString(string con, string param, bool headless)
Definition ImageJ.cs:137
static List< Macro.Command > Macros
Definition ImageJ.cs:103
static bool Initialized
Definition ImageJ.cs:108
static async void RunOnImage(string con, bool headless, bool onTab, bool bioformats, bool newTab)
Definition ImageJ.cs:189
static string ImageJPath
Definition ImageJ.cs:105
static bool Initialize()
Definition ImageJ.cs:247
ImageView control for image stacks, pyramidal and whole-slide-images.
List< BioImage > Images
Definition ImageView.cs:323
void UpdateView(bool refreshImages=true)
int SelectedIndex
A property that is used to set the selected index of the image. *‍/.
Definition ImageView.cs:390
static BioImage SelectedImage
Definition ImageView.cs:270
static void AddLine(string s)
Definition Recorder.cs:16