BioCore  5.0.0
A Windows .NET microscopy library and application for viewing, editing, and annotating images.
Loading...
Searching...
No Matches
ImageView.cs
Go to the documentation of this file.
1using AForge;
2using AForge.Imaging.Filters;
3using BioLib;
4using CSScripting;
5using Gtk;
6using OpenSlideGTK;
7using OpenTK.Mathematics;
8using OpenTK.Windowing.Common;
9using OpenTK.Windowing.Desktop;
10using OpenTK.Windowing.GraphicsLibraryFramework;
11using SkiaSharp;
12using System.ComponentModel;
13using System.Runtime.InteropServices;
14using Application = System.Windows.Forms.Application;
15using Image = System.Drawing.Image;
16using Keys = System.Windows.Forms.Keys;
17using RectangleD = AForge.RectangleD;
18using SizeF = AForge.SizeF;
19
20namespace BioCore
21{
22
26 public partial class ImageView : UserControl, IDisposable
27 {
28 GLWindow window;
29 SlideGLArea gl = new SlideGLArea();
30 SlideRenderer slideRenderer;
32 public ImageView(BioImage im, bool OpenWithOpenSlide = true)
33 {
34 string file = im.ID.Replace("\\", "/");
35 InitializeComponent();
36 InitializeViewport();
37
38 if (im.isPyramidal)
39 {
40 gl.Size = new System.Drawing.Size(800, 600);
41 if (im.openSlideImage != null && OpenWithOpenSlide)
42 {
43 openSlide = true;
44 Initialize(im.file, im);
45 }
46 else
47 Initialize(im.file, im);
48 hScrollBar.Visible = true;
49 vScrollBar.Visible = true;
50 }
51 else
52 {
53 hScrollBar.Visible = false;
54 vScrollBar.Visible = false;
55 gl.Width += 18;
56 gl.Height += 18;
57 Tools.selectBoxSize = ROI.selectBoxSize;
58 }
59 App.viewer = this;
60 if (im.SlideBase != null && im.isPyramidal && OpenSlide)
61 openSlide = true;
62 serie = im.series;
63 Dock = DockStyle.Fill;
64 AddImage(im);
65 App.viewer = this;
66 if (file == "" || file == null)
67 return;
68 InitGUI();
69 // Preserve a loader-selected initial plane (for example the middle
70 // slice of an NGFF scene). SetCoordinate is asynchronous and raced
71 // construction here, so initialise the controls synchronously.
72 zBar.Value = Math.Clamp(im.Coordinate.Z, zBar.Minimum, zBar.Maximum);
73 cBar.Value = Math.Clamp(im.Coordinate.C, cBar.Minimum, cBar.Maximum);
74 tBar.Value = Math.Clamp(im.Coordinate.T, tBar.Minimum, tBar.Maximum);
75 gl.Paint += Gl_Paint;
76 MouseWheel += new System.Windows.Forms.MouseEventHandler(ImageView_MouseWheel);
77 zBar.MouseWheel += new System.Windows.Forms.MouseEventHandler(ZTrackBar_MouseWheel);
78 cBar.MouseWheel += new System.Windows.Forms.MouseEventHandler(CTrackBar_MouseWheel);
79 tBar.MouseWheel += new System.Windows.Forms.MouseEventHandler(TimeTrackBar_MouseWheel);
80 //We set the trackbar event to handled so that it only scrolls one tick not the default multiple.
81 zBar.MouseWheel += (sender, e) => ((HandledMouseEventArgs)e).Handled = true;
82 tBar.MouseWheel += (sender, e) => ((HandledMouseEventArgs)e).Handled = true;
83 cBar.MouseWheel += (sender, e) => ((HandledMouseEventArgs)e).Handled = true;
84 this.SizeChanged += ImageView_SizeChanged;
85 this.KeyDown += ImageView_KeyDown;
86 this.KeyPress += ImageView_KeyPress;
87 this.KeyUp += ImageView_KeyUp;
88 TimeFps = 60;
89 ZFps = 60;
90 CFps = 1;
91 resolutions = im.Resolutions;
92 if (im.isPyramidal)
93 {
94 // Set the source based on image type
95 if (im.OpenSlideBase != null)
96 {
97 slideRenderer.SetSource(im.OpenSlideBase);
98 }
99 else if (im.SlideBase != null)
100 {
101 slideRenderer.SetSource(im.SlideBase);
102 }
103 }
104 InitGL();
105 update = true;
106 InitPreview();
107 GoToImage();
108 UpdateImages();
109 Mode = ViewMode.Filtered;
110 UpdateView();
111 Initialize(im.ID, im);
112 }
114 public ImageView()
115 {
116 InitializeComponent();
117 InitializeViewport();
118 InitGL();
119 Dock = DockStyle.Fill;
120 App.viewer = this;
121 SetCoordinate(0, 0, 0);
122 InitGUI();
123 gl.Paint += Gl_Paint;
124 //Buf = image.GetBufByCoord(GetCoordinate());
125 MouseWheel += new System.Windows.Forms.MouseEventHandler(ImageView_MouseWheel);
126 zBar.MouseWheel += new System.Windows.Forms.MouseEventHandler(ZTrackBar_MouseWheel);
127 cBar.MouseWheel += new System.Windows.Forms.MouseEventHandler(CTrackBar_MouseWheel);
128 tBar.MouseWheel += new System.Windows.Forms.MouseEventHandler(TimeTrackBar_MouseWheel);
129 this.SizeChanged += ImageView_SizeChanged;
130 //We set the trackbar event to handled so that it only scrolls one tick not the default multiple.
131 zBar.MouseWheel += (sender, e) => ((HandledMouseEventArgs)e).Handled = true;
132 tBar.MouseWheel += (sender, e) => ((HandledMouseEventArgs)e).Handled = true;
133 cBar.MouseWheel += (sender, e) => ((HandledMouseEventArgs)e).Handled = true;
134 TimeFps = 60;
135 ZFps = 60;
136 CFps = 1;
137 update = true;
138 UpdateImages();
139 GoToImage();
140 UpdateView();
141 }
142
143 private void InitializeViewport()
144 {
145 gl.Dock = DockStyle.Fill;
146 gl.Visible = false;
147 gl.ContextMenuStrip = contextMenuStrip;
148 viewport.ContextMenuStrip = contextMenuStrip;
149 contextMenuStrip.Opening += contextMenuStrip_Opening;
150 viewport.Controls.Add(gl);
151 viewpanel.BringToFront();
152 InitializeOverview();
153 // Both rendering surfaces must forward gestures to the same viewer handlers.
154 foreach (System.Windows.Forms.Control surface in new System.Windows.Forms.Control[] { viewpanel, gl })
155 {
156 surface.MouseDown += pictureBox_MouseDown;
157 surface.MouseMove += rgbPictureBox_MouseMove;
158 surface.MouseUp += pictureBox_MouseUp;
159 surface.MouseWheel += ImageView_MouseWheel;
160 }
161 }
162
163 private void UpdateImageSurface()
164 {
165 bool pyramidal = Images.Count > SelectedIndex && Images[SelectedIndex].isPyramidal;
166 gl.Visible = pyramidal;
167 viewpanel.Visible = !pyramidal;
168 if (pyramidal)
169 gl.BringToFront();
170 else
171 viewpanel.BringToFront();
172 UpdateOverviewVisibility();
173 }
174
175 private void InvalidateView()
176 {
177 UpdateOverviewVisibility();
178 overviewPanel.Invalidate();
179 UpdateScrollBars();
180 if (Images.Count > SelectedIndex && Images[SelectedIndex].isPyramidal)
181 gl.Invalidate();
182 else
183 viewpanel.Invalidate();
184 }
185
186 protected override void OnLayout(LayoutEventArgs e)
187 {
188 base.OnLayout(e);
189 if (viewport == null || statusPanel == null || trackBarPanel == null ||
190 hScrollBar == null || vScrollBar == null)
191 return;
192
193 int top = statusPanel.Visible ? statusPanel.Bottom : 0;
194 int bottom = trackBarPanel.Visible ? trackBarPanel.Top : ClientSize.Height;
195 int width = Math.Max(0, ClientSize.Width - (vScrollBar.Visible ? vScrollBar.Width : 0));
196 int height = Math.Max(0, bottom - top - (hScrollBar.Visible ? hScrollBar.Height : 0));
197
198 // Hidden scrollbars must not leave unused strips around the image surface.
199 viewport.Bounds = new System.Drawing.Rectangle(0, top, width, height);
200 hScrollBar.SetBounds(0, top + height, width, hScrollBar.Height);
201 vScrollBar.SetBounds(width, top, vScrollBar.Width, height);
202 UpdateScrollBars();
203 }
204
205 protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
206 {
207 const int WM_KEYDOWN = 0x0100;
208 const int WM_KEYUP = 0x0101;
209 const int WM_CHAR = 0x0102;
210
211 switch (msg.Msg)
212 {
213 case WM_KEYDOWN:
214 ImageView_KeyDown(this, new KeyEventArgs(keyData));
215 break;
216
217 case WM_KEYUP:
218 ImageView_KeyUp(this, new KeyEventArgs(keyData));
219 break;
220
221 case WM_CHAR:
222 char ch = (char)msg.WParam;
223 ImageView_KeyPress(this, new System.Windows.Forms.KeyPressEventArgs(ch));
224 break;
225 }
226
227 return base.ProcessCmdKey(ref msg, keyData);
228 }
229
230 private void ImageView_SizeChanged(object? sender, EventArgs e)
231 {
232 if (SelectedImage != null)
233 if (SelectedImage.isPyramidal)
234 SelectedImage.PyramidalSize = new AForge.Size(gl.Width, gl.Height);
235 }
236
237 private void InitGL()
238 {
239 var gameWindowSettings = new GameWindowSettings()
240 {
241 UpdateFrequency = 60,
242 };
243 NativeWindowSettings nativeSettings;
244
245 nativeSettings = new NativeWindowSettings()
246 {
247 ClientSize = new Vector2i(Width, Height),
248 Location = new Vector2i(0, 0),
249 Title = "OpenGL Context",
250 StartVisible = false, // Window starts hidden
251 API = ContextAPI.OpenGL,
252 Profile = ContextProfile.Core,
253 APIVersion = new Version(3, 3)
254 };
255 window = new GLWindow(gameWindowSettings, nativeSettings);
256 GLFWProvider.SetErrorCallback((error, description) =>
257 {
258 Console.WriteLine($"BioImager GLFW Error {error}: {description}");
259 });
260 }
261
262 private void Gl_Paint(object? sender, PaintEventArgs e)
263 {
264 //Render(((SlideGLArea)sender).CreateGraphics());
265 }
266
267 ~ImageView()
268 {
269
270 }
271 public struct Layer
272 {
273 public double Resolution
274 {
275 get; set;
276 }
277 public bool Enabled { get; set; }
278 public Layer(double d)
279 {
280 Enabled = true;
281 Resolution = d;
282 }
283 public Layer(double d, bool enabled)
284 {
285 Enabled = enabled;
286 Resolution = d;
287 }
288 }
289
290 public List<Layer> Layers = new List<Layer>();
291 private Layers layersTool = new Layers();
292 private bool IsLayerEnabled(double d)
293 {
294 foreach (Layer item in Layers)
295 {
296 if (d == item.Resolution && item.Enabled)
297 return true;
298 }
299 return false;
300 }
301 List<System.Drawing.Bitmap> Bitmaps = new List<System.Drawing.Bitmap>();
302 List<Resolution> resolutions = new List<Resolution>();
303 public static List<ROI> selectedAnnotations = new List<ROI>();
304 private static int selectedIndex = 0;
305 public static BioImage SelectedImage
306 {
307 get
308 {
309 if (App.viewer != null)
310 {
311 if (App.viewer.Images.Count > 0)
312 return App.viewer.Images[selectedIndex];
313 else
314 return null;
315 }
316 else
317 return null;
318 }
319 set
320 {
321 if (App.viewer.Images.Count > 0)
322 App.viewer.Images[selectedIndex] = value;
323 else
324 App.viewer.Images.Add(value);
325 }
326 }
327 public static Bitmap SelectedBuffer
328 {
329 get
330 {
331 int ind = SelectedImage.Coords[SelectedImage.Coordinate.Z, SelectedImage.Coordinate.C, SelectedImage.Coordinate.T];
332 return SelectedImage.Buffers[ind];
333 }
334 }
335 public static PointD mouseDown;
336 public static bool down;
337 public static PointD mouseUp;
338 public static bool up;
339 public static bool Ctrl
340 {
341 get
342 {
343 return Win32.GetKeyState(Keys.LControlKey);
344 }
345 }
346 private bool x1State = false;
347 private bool x2State = false;
348 public static MouseButtons mouseUpButtons;
349 public static MouseButtons mouseDownButtons;
350 private PointD pd;
351 public static bool showBounds = true;
352 public static bool showText = true;
353 public Image Buf = null;
354 public bool init = false;
355 private bool update = false;
356 private bool updateOverlay = false;
357 private List<BioImage> imgs = new List<BioImage>();
358 public List<BioImage> Images
359 {
360 get
361 {
362 return imgs;
363 }
364 }
365 public System.Drawing.Bitmap overviewImage = null;
370 private void Render(System.Drawing.Graphics canvas)
371 {
372 try
373 {
374 if (Images.Count == 0)
375 return;
376 // Draw annotations (ROIs) - keep existing annotation drawing code
377 int i = 0;
378 foreach (BioImage im in Images)
379 {
380 List<ROI> rois = new List<ROI>();
381 rois.AddRange(im.Annotations);
382 int ri = 0;
383 ZCT co = GetCoordinate();
384 canvas.TranslateTransform((float)gl.Width / 2f, (float)gl.Height / 2f);
385 RectangleD rp = ToScreenSpace(new RectangleD(im.StageSizeX * im.PhysicalSizeX, im.StageSizeX * im.PhysicalSizeY, im.SizeX * im.PhysicalSizeX, im.SizeY * im.PhysicalSizeY));
386 UpdateImages();
387 if (!im.isPyramidal)
388 canvas.DrawImage(Bitmaps[i], new System.Drawing.PointF((float)rp.X, (float)rp.Y));
389 i++;
390 }
391 System.Drawing.Rectangle rf = new System.Drawing.Rectangle((int)canvas.Clip.GetBounds(canvas).X, (int)canvas.Clip.GetBounds(canvas).Y,
392 (int)canvas.Clip.GetBounds(canvas).Width, (int)canvas.Clip.GetBounds(canvas).Height);
393
394 // Plugin rendering hook
395 Plugins.Render(this, new PaintEventArgs(canvas, rf));
396 }
397 catch (Exception ex)
398 {
399 Console.WriteLine($"Annotation render error: {ex.Message}");
400 }
401 }
402
404 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
405 public int SelectedIndex
406 {
407 get;
408 set
409 {
410 if (value >= 0 && Images.Count > 0)
411 {
412 field = value;
413 selectedIndex = field;
414 InitGUI();
415 }
416 }
417 } = 0;
418 public Tools tools { get { return App.tools; } }
419 public string filepath = "";
420 public int serie = 0;
421 public int minSizeX = 50;
422 public int minSizeY = 20;
423 public bool loopZ = true;
424 public bool loopT = true;
425 public bool loopC = true;
426 private AForge.Rectangle overview;
427 public Rectangle OverView
428 {
429 get { return overview; }
430 }
431 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
432 public bool ShowStage { get; set; }
433 private double pxWmicron = 0.004;
434 private double pxHmicron = 0.004;
435 AForge.SizeF scale = new AForge.SizeF(1, 1);
443 public void SetCoordinate(int z, int c, int t)
444 {
445 System.Threading.Tasks.Task.Run(() =>
446 {
447 try
448 {
449 App.viewer.Invoke((MethodInvoker)delegate
450 {
451 if (SelectedImage == null)
452 return;
453 if (z >= SelectedImage.SizeZ)
454 zBar.Value = zBar.Maximum;
455 if (c >= SelectedImage.SizeC)
456 cBar.Value = cBar.Maximum;
457 if (t >= SelectedImage.SizeT)
458 tBar.Value = tBar.Maximum;
459 zBar.Value = z;
460 cBar.Value = c;
461 tBar.Value = t;
462 });
463 }
464 catch (Exception e)
465 {
466 Console.WriteLine(e.Message);
467 }
468
469 });
470 }
474 public ZCT GetCoordinate()
475 {
476 if (SelectedImage == null)
477 return new ZCT();
478 return SelectedImage.Coordinate;
479 }
485 public void AddImage(BioImage im)
486 {
487 ZarrChannelView.InitializeChannels(im);
488 if (Images.Contains(im))
489 return;
490 else
491 Images.Add(im);
492 SelectedIndex = Images.Count - 1;
493 bool c = false;
494 foreach (var item in Layers)
495 {
496 if (item.Resolution == im.PhysicalSizeX)
497 c = true;
498 }
499 if (!c)
500 Layers.Add(new Layer(im.PhysicalSizeX));
501 if (im.isPyramidal)
502 {
503 hScrollBar.Visible = true;
504 vScrollBar.Visible = true;
505 InitPreview();
506 }
507 else
508 {
509 hScrollBar.Visible = false;
510 vScrollBar.Visible = false;
511 gl.Width += 18;
512 gl.Height += 18;
513 Tools.selectBoxSize = ROI.selectBoxSize;
514 }
515 Initialize(im.ID, im);
516 InitGUI();
517 UpdateImages();
518 GoToImage(Images.Count - 1);
519 }
521 private bool showControls = true;
523 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
524 public bool ShowControls
525 {
526 get { return trackBarPanel.Visible; }
527 set
528 {
529 showControls = value;
530 if (!value)
531 {
532 trackBarPanel.Hide();
533 if (ShowStatus)
534 {
535 gl.Top = 25;
536 gl.Height += 75;
537 }
538 else
539 {
540 gl.Top = 0;
541 gl.Height += 75;
542 }
543 hideControlsToolStripMenuItem1.Text = "Show Controls";
544 }
545 else
546 {
547 trackBarPanel.Show();
548 if (ShowStatus)
549 {
550 gl.Top = 25;
551 gl.Height -= 75;
552 }
553 else
554 {
555 gl.Top = 0;
556 gl.Height += 75;
557 }
558
559 //panel.Anchor = AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Left;
560 hideControlsToolStripMenuItem1.Text = "Hide Controls";
561 }
562 UpdateView();
563 }
564 }
566 private bool showStatus = true;
568 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
569 public bool ShowStatus
570 {
571 get { return showStatus; }
572 set
573 {
574 showStatus = true;
575 if (!value)
576 {
577 statusPanel.Hide();
578 gl.Top = 0;
579 gl.Height += 25;
580 showControlsToolStripMenuItem.Visible = true;
581 hideControlsToolStripMenuItem.Text = "Show Status";
582 }
583 else
584 {
585 statusPanel.Show();
586 statusPanel.Visible = value;
587 gl.Top = 25;
588 showControlsToolStripMenuItem.Visible = false;
589 hideControlsToolStripMenuItem.Text = "Hide Status";
590 }
591 }
592 }
596
597 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
598 public double PxWmicron
599 {
600 get
601 {
602 return pxWmicron;
603 }
604 set
605 {
606 pxWmicron = value;
607 }
608 }
612 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
613 public double PxHmicron
614 {
615 get
616 {
617 return pxHmicron;
618 }
619 set
620 {
621 pxHmicron = value;
622 }
623 }
624 public enum ViewMode
625 {
626 Raw,
627 Filtered,
628 RGBImage,
629 Emission,
630 }
631 private ViewMode viewMode = ViewMode.Filtered;
633 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
635 {
636 get
637 {
638 return viewMode;
639 }
640 set
641 {
642 if (Mode == value)
643 return;
644 viewMode = value;
645 //If view mode is changed we update.
646 update = true;
647 UpdateImages();
648 App.tabsView.UpdateViewMode(viewMode);
649 UpdateView();
651 if (viewMode == ViewMode.RGBImage)
652 {
653 cBar.Value = 0;
654 rgbBoxsPanel.BringToFront();
655 cBar.SendToBack();
656 cLabel.SendToBack();
657 gl.BringToFront();
658 }
659 else
660 if (viewMode == ViewMode.Filtered)
661 {
662 rgbBoxsPanel.SendToBack();
663 cBar.BringToFront();
664 cLabel.BringToFront();
665 gl.BringToFront();
666 }
667 else
668 if (viewMode == ViewMode.Raw)
669 {
670 rgbBoxsPanel.SendToBack();
671 cBar.BringToFront();
672 cLabel.BringToFront();
673 gl.BringToFront();
674 }
675 else
676 {
677 cBar.Value = 0;
678 rgbBoxsPanel.BringToFront();
679 cBar.SendToBack();
680 cLabel.SendToBack();
681 gl.BringToFront();
682 }
683 }
684 }
686 public string Path
687 {
688 get
689 {
690 return filepath;
691 }
692 }
694 public Channel RChannel
695 {
696 get
697 {
698 return SelectedImage.Channels[SelectedImage.rgbChannels[0]];
699 }
700 }
702 public Channel GChannel
703 {
704 get
705 {
706 return SelectedImage.Channels[SelectedImage.rgbChannels[1]];
707 }
708 }
710 public Channel BChannel
711 {
712 get
713 {
714 return SelectedImage.Channels[SelectedImage.rgbChannels[2]];
715 }
716 }
717 PointD origin = new PointD(0, 0);
718 bool hardwareAcceleration = true;
719 bool openSlide = false;
720 public bool OpenSlide
721 {
722 get { return openSlide; }
723 }
724 public int? MacroResolution { get { return SelectedImage.MacroResolution; } }
725 public int? LabelResolution { get { return SelectedImage.LabelResolution; } }
726 public int ViewWidth
727 {
728 get
729 {
730 return viewport.ClientSize.Width;
731 }
732 }
733 public int ViewHeight
734 {
735 get
736 {
737 return viewport.ClientSize.Height;
738 }
739 }
741 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
742 public PointD Origin
743 {
744 get { return origin; }
745 set
746 {
747 origin = value;
748 update = true;
749 UpdateView();
750 }
751 }
753 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
754 public PointD PyramidalOrigin
755 {
756 get
757 {
758 if (SelectedImage == null)
759 return new PointD(0, 0);
760 return SelectedImage.PyramidalOrigin;
761 }
762 set
763 {
764 SelectedImage.PyramidalOrigin = value;
765 }
766 }
768 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
769 public double Resolution
770 {
771 get
772 {
773 if (SelectedImage == null)
774 return 1;
775 return SelectedImage.Resolution;
776 }
777 set
778 {
779 double dp = Resolution / value;
780 SelectedImage.PyramidalOrigin = new PointD((dp * PyramidalOrigin.X), (dp * PyramidalOrigin.Y));
781 SelectedImage.Resolution = value;
782 if (SelectedImage.Type == BioImage.ImageType.well)
783 SelectedImage.Level = (int)value;
784 updatePyr = true;
785 }
786 }
790 public int Level
791 {
792 get
793 {
794 if (SelectedImage != null)
795 return SelectedImage.Level;
796 else
797 return 0;
798 }
799 }
803 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
804 public new AForge.SizeF Scale
805 {
806 get
807 {
808 return scale;
809 }
810 set
811 {
812 scale = value;
813 update = true;
814 UpdateView();
815 if (SelectedImage != null)
816 if (SelectedImage.isPyramidal)
817 {
818 Tools.selectBoxSize = (float)(ROI.selectBoxSize * Resolution);
819 }
820 else
821 Tools.selectBoxSize = ROI.selectBoxSize;
822 }
823 }
825 public ContextMenuStrip ViewContextMenu
826 {
827 get
828 {
829 return contextMenuStrip;
830 }
831 }
836 private readonly bool[] rgbEnabled = { true, true, true };
837 private bool initializingRgbSelectors;
838 private BioImage rgbSelectorImage;
839
840 private int[] SelectedRgbChannels(BioImage image) => Enumerable.Range(0, 3)
841 .Select(i => rgbEnabled[i] ? image.rgbChannels[i] : -1).ToArray();
842
843 public void UpdateRGBChannels()
844 {
845 if (SelectedImage == null) return;
846 System.Windows.Forms.ComboBox[] boxes = { channelBoxR, channelBoxG, channelBoxB };
847 for (int i = 0; i < boxes.Length; i++)
848 {
849 rgbEnabled[i] = boxes[i].SelectedIndex > 0;
850 if (rgbEnabled[i]) SelectedImage.rgbChannels[i] = boxes[i].SelectedIndex - 1;
851 }
852 }
853 private bool timeEnabled = false;
854 private int zfps;
856 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
857 public int ZFps
858 {
859 get
860 {
861 return zfps;
862 }
863 set
864 {
865 zfps = value;
866 float f = value;
867 zTimer.Interval = (int)Math.Floor(1000 / f);
868 }
869 }
870 private int timefps;
872 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
873 public int TimeFps
874 {
875 get
876 {
877 return timefps;
878 }
879 set
880 {
881 timefps = value;
882 float f = value;
883 timelineTimer.Interval = (int)Math.Floor(1000 / f);
884 }
885 }
886 private int cfps;
888 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
889 public int CFps
890 {
891 get
892 {
893 return cfps;
894 }
895 set
896 {
897 cfps = value;
898 float f = value;
899 cTimer.Interval = (int)Math.Floor(1000 / f);
900 }
901 }
905 public void InitGUI()
906 {
907 if (SelectedImage == null)
908 return;
909 zBar.Maximum = SelectedImage.SizeZ - 1;
910 if (!SelectedImage.IsZarrSource && SelectedImage.Buffers[0].RGBChannelsCount == 3)
911 cBar.Maximum = 0;
912 else
913 cBar.Maximum = SelectedImage.SizeC - 1;
914 if (SelectedImage.SizeT > 1)
915 {
916 tBar.Maximum = SelectedImage.SizeT - 1;
917 timeEnabled = true;
918 }
919 else
920 {
921 tBar.Enabled = false;
922 timeEnabled = false;
923 tBar.Maximum = SelectedImage.SizeT - 1;
924 }
925 //rgbPictureBox.Image = image.plane.GetBitmap();
926 //we clear the channel comboboxes incase we have channels from previous loaded image.
927 bool sameImage = ReferenceEquals(rgbSelectorImage, SelectedImage);
928 rgbSelectorImage = SelectedImage;
929 bool[] previousEnabled = (bool[])rgbEnabled.Clone();
930 int[] previousChannels = (int[])SelectedImage.rgbChannels.Clone();
931 initializingRgbSelectors = true;
932 channelBoxR.Items.Clear();
933 channelBoxG.Items.Clear();
934 channelBoxB.Items.Clear();
935
936 channelBoxR.Items.Add("");
937 channelBoxG.Items.Add("");
938 channelBoxB.Items.Add("");
939 foreach (Channel ch in SelectedImage.Channels)
940 {
941 channelBoxR.Items.Add(ch);
942 channelBoxG.Items.Add(ch);
943 channelBoxB.Items.Add(ch);
944 }
945 System.Windows.Forms.ComboBox[] rgbBoxes = { channelBoxR, channelBoxG, channelBoxB };
946 int count = SelectedImage.Channels.Count;
947 for (int i = 0; i < rgbBoxes.Length; i++)
948 rgbBoxes[i].SelectedIndex = count == 0 || (sameImage && !previousEnabled[i]) ? 0 :
949 (sameImage ? Math.Clamp(previousChannels[i], 0, count - 1) : (i < count ? i : 0)) + 1;
950 initializingRgbSelectors = false;
952
953 init = true;
954 }
959 public void UpdateSelectBoxSize(float size)
960 {
961 ROI.selectBoxSize = size;
962 }
967 public void UpdateOverlay()
968 {
969 updateOverlay = true;
970 InvalidateView();
971 }
975 public void UpdateStatus()
976 {
977 if (SelectedImage == null)
978 return;
979 string res = "";
980 if (SelectedImage.Type == BioImage.ImageType.well)
981 res = "Well:" + SelectedImage.Level;
982 else if (SelectedImage.Type == BioImage.ImageType.pyramidal)
983 {
984 res = $"Res.:{Resolution:G4} Level:{Level}";
985 }
986 string origin = $"({-Origin.X:0.##}, {-Origin.Y:0.##})";
987 string location = $"({SelectedImage.Volume.Location.X:0.##}, {SelectedImage.Volume.Location.Y:0.##})";
988 if (Mode == ViewMode.RGBImage)
989 {
990 if (timeEnabled)
991 {
992 statusLabel.Text = (zBar.Value + 1) + "/" + (zBar.Maximum + 1) + ", " + (tBar.Value + 1) + "/" + (tBar.Maximum + 1) + ", " +
993 mousePoint + mouseColor + ", " + SelectedImage.Buffers[0].PixelFormat.ToString() + ", " + origin + ", " + location + " " + res;
994 }
995 else
996 {
997 statusLabel.Text = (zBar.Value + 1) + "/" + (cBar.Maximum + 1) + ", " + mousePoint + mouseColor + ", " + SelectedImage.Buffers[0].PixelFormat.ToString()
998 + ", " + origin + ", " + location + " " + res;
999 }
1000
1001 }
1002 else
1003 {
1004 if (timeEnabled)
1005 {
1006 statusLabel.Text = (zBar.Value + 1) + "/" + (zBar.Maximum + 1) + ", " + (cBar.Value + 1) + "/" + (cBar.Maximum + 1) + ", " + (tBar.Value + 1) + "/" + (tBar.Maximum + 1) + ", " +
1007 mousePoint + mouseColor + ", " + SelectedImage.Buffers[0].PixelFormat.ToString() + ", " + origin + ", " + location + " " + res;
1008 }
1009 else
1010 {
1011 statusLabel.Text = (zBar.Value + 1) + "/" + (zBar.Maximum + 1) + ", " + (cBar.Value + 1) + "/" + (cBar.Maximum + 1) + ", " + mousePoint + mouseColor + ", " +
1012 SelectedImage.Buffers[0].PixelFormat.ToString() + ", " + origin + ", " + location + " " + res;
1013 }
1014 }
1015 }
1020 public void UpdateView()
1021 {
1022 UpdateImageSurface();
1023 if(SelectedImage!=null)
1024 if (SelectedImage.isPyramidal)
1025 {
1026 // Set the source based on image type
1027 if (SelectedImage.OpenSlideBase != null)
1028 {
1029 slideRenderer.SetSource(SelectedImage.OpenSlideBase);
1030 }
1031 else if (SelectedImage.SlideBase != null)
1032 {
1033 slideRenderer.SetSource(SelectedImage.SlideBase);
1034 }
1035 }
1036 UpdateStatus();
1037 update = true;
1038 UpdateImages();
1039 InvalidateView();
1040 }
1044 /*
1045 public void RenderFrame()
1046 {
1047 if (!update)
1048 return;
1049 drawing = true;
1050 if (dBitmaps.Count != Images.Count)
1051 UpdateImages();
1052 if (HardwareAcceleration && sk != null)
1053 {
1054 Plugins.Render(this, sk);
1055 sk.BeginDraw();
1056 sk.RenderTarget2D.Clear(new RawColor4(1.0f, 1.0f, 1.0f, 1.0f));
1057 RectangleF rg = ToScreenRect(PointD.MinX, PointD.MinY, PointD.MaxX - PointD.MinX, PointD.MaxY - PointD.MinY);
1058 //dx.RenderTarget2D.Transform = SharpDX.Matrix3x2.Rotation((float)Math.PI);
1059 SharpDX.Direct2D1.SolidColorBrush pen = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(1.0f, 0.0f, 0.0f, 1.0f));
1060 SharpDX.Direct2D1.SolidColorBrush red = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(1.0f, 0.0f, 0.0f, 1.0f));
1061 SharpDX.Direct2D1.SolidColorBrush green = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(0.0f, 1.0f, 0.0f, 1.0f));
1062 SharpDX.Direct2D1.SolidColorBrush mag = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(1.0f, 0.0f, 1.0f, 1.0f));
1063 SharpDX.Direct2D1.SolidColorBrush blue = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(0.0f, 0.0f, 1.0f, 1.0f));
1064 SharpDX.Direct2D1.SolidColorBrush b = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(1.0f, 1.0f, 0.0f, 1.0f));
1065 SharpDX.Direct2D1.SolidColorBrush gray = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(0.5f, 0.5f, 0.5f, 1.0f));
1066
1067 sk.RenderTarget2D.FillRectangle(ToSKRect(rg.X, rg.Y, rg.Width, rg.Height), gray);
1068 for (int x = 0; x < Images.Count; x++)
1069 {
1070 if (!IsLayerEnabled(Images[x].PhysicalSizeX) && !Images[x].isPyramidal)
1071 continue;
1072 RectangleF r = ToScreenRect(Images[x].Volume.Location.X, Images[x].Volume.Location.Y, Images[x].Volume.Width, Images[x].Volume.Height);
1073 double w = ToViewW(ViewWidth);
1074 double h = ToViewH(ViewHeight);
1075 RectangleF rge = new RectangleF((float)((-Origin.X) - (w / 2)), (float)((-Origin.Y) - (h / 2)), (float)(Math.Abs(w)), (float)(Math.Abs(h)));
1076 RectangleF rec = new RectangleF((float)Images[x].Volume.Location.X, (float)Images[x].Volume.Location.Y, (float)Images[x].Volume.Width, (float)Images[x].Volume.Height);
1077 //if (rge.IntersectsWith(rec))
1078 sk.RenderTarget2D.DrawBitmap(dBitmaps[x], ToSKRect(r.X, r.Y, r.Width, r.Height), 1.0f, SharpDX.Direct2D1.BitmapInterpolationMode.Linear);
1079 if (x == selectedIndex)
1080 sk.RenderTarget2D.DrawRectangle(ToSKRect(r.X, r.Y, r.Width, r.Height), blue);
1081 }
1082 bool bounds = showBounds;
1083 bool labels = showText;
1084 foreach (BioImage bi in Images)
1085 {
1086 if (!IsLayerEnabled(bi.PhysicalSizeX) && !bi.isPyramidal)
1087 continue;
1088 foreach (ROI an in bi.Annotations)
1089 {
1090 if (zBar.Value != an.coord.Z || cBar.Value != an.coord.C || tBar.Value != an.coord.T)
1091 continue;
1092 float w = Math.Abs(Scale.Width);
1093 Font fo = new Font(new FontFamily(an.family), (float)((an.strokeWidth / w) * an.fontSize));
1094 PointF pc = new PointF((float)(an.BoundingBox.X + (an.BoundingBox.W / 2)), (float)(an.BoundingBox.Y + (an.BoundingBox.H / 2)));
1095 float width = 1;
1096 sk.RenderTarget2D.StrokeWidth = width;
1097 if (an.type == ROI.Type.Point)
1098 {
1099 PointF pf = ToScreenSpace(new PointF((float)an.Points[0].X + 1, (float)an.Points[0].Y + 1));
1100 sk.RenderTarget2D.DrawLine(new RawVector2((float)an.Points[0].X, (float)an.Points[0].Y), new RawVector2(pf.X, pf.Y), b);
1101 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1102 for (int i = 0; i < rfs.Length; i++)
1103 {
1104 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1105 }
1106 }
1107 else
1108 if (an.type == ROI.Type.Line)
1109 {
1110 PointD pf = ToScreenSpace(an.GetPoint(0));
1111 PointD pf2 = ToScreenSpace(an.GetPoint(1));
1112 sk.RenderTarget2D.DrawLine(new RawVector2((float)pf.X, (float)pf.Y), new RawVector2((float)pf2.X, (float)pf2.Y), b);
1113 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1114 for (int i = 0; i < rfs.Length; i++)
1115 {
1116 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1117 }
1118 }
1119 else
1120 if (an.type == ROI.Type.Rectangle && an.BoundingBox.W > 0 && an.BoundingBox.H > 0)
1121 {
1122 RectangleF rec = ToScreenSpace(an.BoundingBox);
1123 sk.RenderTarget2D.DrawRectangle(ToSKRect(rec.X, rec.Y, rec.Width, rec.Height), red);
1124 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1125 for (int i = 0; i < rfs.Length; i++)
1126 {
1127 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1128 }
1129 }
1130 else
1131 if (an.type == ROI.Type.Ellipse)
1132 {
1133 RectangleF r = ToScreenSpace(an.BoundingBox);
1134 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1135 RawRectangleF rf = ToSKRect(rfs[0].X, rfs[0].Y, rfs[0].Width, rfs[0].Height);
1136 SharpDX.Direct2D1.Ellipse e = new SharpDX.Direct2D1.Ellipse(new RawVector2(rf.Left + (Math.Abs(r.Width) / 2) - (rfs[0].Width / 2), rf.Top + (Math.Abs(r.Height) / 2) - (rfs[0].Height / 2)), -r.Width / 2, -r.Height / 2);
1137 sk.RenderTarget2D.DrawEllipse(e, b);
1138 for (int i = 0; i < rfs.Length; i++)
1139 {
1140 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1141 }
1142 }
1143 else
1144 if (an.type == ROI.Type.Polygon && an.closed)
1145 {
1146 RawVector2 pf;
1147 RawVector2 pf2;
1148 for (int i = 0; i < an.Points.Count - 1; i++)
1149 {
1150 pf = new RawVector2((float)ToScreenSpace(an.GetPoint(i).X, an.GetPoint(i).Y).X, (float)ToScreenSpace(an.GetPoint(i).X, an.GetPoint(i).Y).Y);
1151 pf2 = new RawVector2((float)ToScreenSpace(an.GetPoint(i + 1).X, an.GetPoint(i + 1).Y).X, (float)ToScreenSpace(an.GetPoint(i + 1).X, an.GetPoint(i + 1).Y).Y);
1152 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1153 }
1154 pf = new RawVector2((float)ToScreenSpace(an.GetPoint(0)).X, (float)ToScreenSpace(an.GetPoint(0)).Y);
1155 pf2 = new RawVector2((float)ToScreenSpace(an.GetPoint(an.Points.Count - 1)).X, (float)ToScreenSpace(an.GetPoint(an.Points.Count - 1)).Y);
1156 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1157
1158 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1159 for (int i = 0; i < rfs.Length; i++)
1160 {
1161 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1162 }
1163 }
1164 else
1165 if (an.type == ROI.Type.Polygon && !an.closed || an.type == ROI.Type.Polyline)
1166 {
1167 RawVector2 pf;
1168 RawVector2 pf2;
1169 for (int i = 0; i < an.Points.Count - 1; i++)
1170 {
1171 pf = new RawVector2((float)ToScreenSpace(an.GetPoint(i).X, an.GetPoint(i).Y).X, (float)ToScreenSpace(an.GetPoint(i).X, an.GetPoint(i).Y).Y);
1172 pf2 = new RawVector2((float)ToScreenSpace(an.GetPoint(i + 1).X, an.GetPoint(i + 1).Y).X, (float)ToScreenSpace(an.GetPoint(i + 1).X, an.GetPoint(i + 1).Y).Y);
1173 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1174 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1175 }
1176
1177 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1178 for (int i = 0; i < rfs.Length; i++)
1179 {
1180 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1181 }
1182
1183 }
1184 else
1185 if (an.type == ROI.Type.Freeform && an.closed)
1186 {
1187 RawVector2 pf;
1188 RawVector2 pf2;
1189 for (int i = 0; i < an.Points.Count - 1; i++)
1190 {
1191 pf = new RawVector2((float)ToScreenSpace(an.GetPoint(i).X, an.GetPoint(i).Y).X, (float)ToScreenSpace(an.GetPoint(i).X, an.GetPoint(i).Y).Y);
1192 pf2 = new RawVector2((float)ToScreenSpace(an.GetPoint(i + 1).X, an.GetPoint(i + 1).Y).X, (float)ToScreenSpace(an.GetPoint(i + 1).X, an.GetPoint(i + 1).Y).Y);
1193 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1194 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1195 }
1196 pf = new RawVector2((float)ToScreenSpace(an.GetPoint(0)).X, (float)ToScreenSpace(an.GetPoint(0)).Y);
1197 pf2 = new RawVector2((float)ToScreenSpace(an.GetPoint(an.Points.Count - 1)).X, (float)ToScreenSpace(an.GetPoint(an.Points.Count - 1)).Y);
1198 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1199 }
1200 if (an.type == ROI.Type.Label)
1201 {
1202 RectangleF rec = ToScreenSpace(an.BoundingBox);
1203 RawRectangleF r = ToSKRect(rec.X, rec.Y, rec.Width, rec.Height);
1204 SharpDX.DirectWrite.TextFormat tex = new SharpDX.DirectWrite.TextFormat(sk.FactoryDWrite, an.family.ToString(), an.fontSize);
1205 sk.RenderTarget2D.DrawText(an.Text, tex, r, b);
1206 tex.Dispose();
1207 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1208 for (int i = 0; i < rfs.Length; i++)
1209 {
1210 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1211 }
1212 }
1213 if (labels)
1214 {
1215 if (an.Text != null)
1216 {
1217 System.Drawing.Size s = TextRenderer.MeasureText(an.Text, new Font(an.family, an.fontSize));
1218 //Lets draw the text of this ROI in the middle of the ROI.
1219 float fw = ((float)an.BoundingBox.X + ((float)an.BoundingBox.W / 2)) - ((float)s.Width / 2);
1220 float fh = ((float)an.BoundingBox.Y + ((float)an.BoundingBox.H / 2)) - ((float)s.Height / 2);
1221 RawRectangleF r = ToSKRect(fw, fh, s.Width, s.Height);
1222 SharpDX.DirectWrite.TextFormat tex = new SharpDX.DirectWrite.TextFormat(sk.FactoryDWrite, an.family.ToString(), an.fontSize);
1223 sk.RenderTarget2D.DrawText(an.Text, tex, r, b);
1224 tex.Dispose();
1225 }
1226 }
1227 if (bounds)
1228 {
1229 RectangleF r = ToScreenSpace(an.BoundingBox);
1230 sk.RenderTarget2D.DrawRectangle(ToSKRect(r.X, r.Y, r.Width, r.Height), green);
1231 }
1232 if (an.Selected)
1233 {
1234 //Lets draw the selected bounding box.
1235 RectangleF r = ToScreenSpace(an.BoundingBox);
1236 sk.RenderTarget2D.DrawRectangle(ToSKRect(r.X, r.Y, r.Width, r.Height), mag);
1237
1238 //Lets draw the selectBoxes.
1239 List<RectangleD> rects = new List<RectangleD>();
1240 RectangleD[] sels = an.GetSelectBoxes(Tools.selectBoxSize);
1241 for (int i = 0; i < an.selectedPoints.Count; i++)
1242 {
1243 if (an.selectedPoints[i] < an.GetPointCount())
1244 {
1245 rects.Add(sels[an.selectedPoints[i]]);
1246 }
1247 }
1248 if (rects.Count > 0)
1249 {
1250 for (int i = 0; i < rects.Count; i++)
1251 {
1252 RectangleF ri = ToScreenSpace(rects[i]);
1253 sk.RenderTarget2D.DrawRectangle(ToSKRect(ri.X, ri.Y, ri.Width, ri.Height), blue);
1254 }
1255 }
1256 rects.Clear();
1257 }
1258
1259 }
1260 }
1261 if (ShowStage)
1262 {
1263 AForge.RectangleD re = Microscope.GetViewRectangle(false);
1264 RectangleF vr = ToScreenRect(re.X, re.Y, re.W, re.H);
1265 RawRectangleF rr = ToSKRect(vr.X, vr.Y, vr.Width, vr.Height);
1266 sk.RenderTarget2D.DrawRectangle(rr, red);
1267 }
1268
1269 if(Tools.currentTool!=null)
1270 if (Tools.currentTool.type == Tools.Tool.Type.rectSel)// && Modifiers == ModifierType.Button1Mask)
1271 {
1272 var recd = ToScreenRect(Tools.currentTool.Rectangle.X, Tools.currentTool.Rectangle.Y, Tools.currentTool.Rectangle.W, Tools.currentTool.Rectangle.H);
1273 sk.RenderTarget2D.DrawRectangle(ToSKRect((float)recd.X, (float)recd.Y, (float)recd.Width, (float)recd.Height), blue);
1274 }
1275 pen.Dispose();
1276 red.Dispose();
1277 mag.Dispose();
1278 green.Dispose();
1279 blue.Dispose();
1280 gray.Dispose();
1281 b.Dispose();
1282 sk.EndDraw();
1283 }
1284 drawing = false;
1285 }
1286 */
1290 public void UpdateView(bool refresh)
1291 {
1292 UpdateStatus();
1293 update = refresh;
1294 if (update)
1295 {
1296 InvalidateView();
1297 }
1298 }
1299 bool updating = false;
1304 private int zarrRgbRequest;
1305 public async void UpdateImages(bool updatePyramidal = true)
1306 {
1307 if (SelectedImage == null)
1308 return;
1310 UpdateImageSurface();
1311 if (SelectedImage.isPyramidal)
1312 {
1313 InitPreview();
1314 if (!updatePyramidal || gl.Width <= 1 || gl.Height <= 1)
1315 return;
1316 updatePyr = true;
1317 SelectedImage.PyramidalOrigin = PyramidalOrigin;
1318 SelectedImage.PyramidalSize = new AForge.Size(gl.Width, gl.Height);
1319
1320 // Use the new renderer - no more ReadPixels!
1321 if (slideRenderer == null)
1322 {
1323 slideRenderer = new SlideRenderer(gl);
1324 }
1325 try
1326 {
1327 BioImage? directZarr = null;
1328 int[]? directZarrChannels = null;
1329 if (SelectedImage.IsZarrSource)
1330 {
1331 if (Mode == ViewMode.RGBImage)
1332 {
1333 directZarr = SelectedImage;
1334 directZarrChannels = SelectedRgbChannels(SelectedImage);
1335 }
1336 else if (Mode == ViewMode.Filtered)
1337 {
1338 // Use the same direct, coordinate-aware Zarr reader as
1339 // RGB mode. Repeating the selected channel produces the
1340 // expected grayscale Filtered view and avoids the legacy
1341 // buffered plane path that could remain stuck on Z=0.
1342 int channel = Math.Clamp(GetCoordinate().C, 0,
1343 Math.Max(0, SelectedImage.SizeC - 1));
1344 directZarr = SelectedImage;
1345 directZarrChannels = new[] { channel, channel, channel };
1346 }
1347 }
1348
1349 await slideRenderer.UpdateViewAsync(
1351 gl.Width,
1352 gl.Height,
1353 Resolution,
1354 GetCoordinate(),
1355 directZarr,
1356 directZarrChannels
1357 );
1358 }
1359 catch (Exception ex)
1360 {
1361 System.Diagnostics.Trace.WriteLine($"Could not update slide view: {ex}");
1362 }
1363 // Pyramidal images are drawn from tiles, not the full-plane buffers below.
1364 return;
1365 }
1366
1367 if (SelectedImage.IsZarrSource &&
1368 (Mode == ViewMode.RGBImage || Mode == ViewMode.Filtered) &&
1369 Images.Count == 1 && SelectedImage.levels?.Count > 0)
1370 {
1371 var image = SelectedImage;
1372 var requestedMode = Mode;
1373 int request = ++zarrRgbRequest;
1374 int width = image.Buffers[0].SizeX, height = image.Buffers[0].SizeY;
1375 try
1376 {
1377 int[] channels;
1378 if (requestedMode == ViewMode.RGBImage)
1379 {
1380 channels = SelectedRgbChannels(image);
1381 }
1382 else
1383 {
1384 int channel = Math.Clamp(GetCoordinate().C, 0,
1385 Math.Max(0, image.SizeC - 1));
1386 channels = new[] { channel, channel, channel };
1387 }
1388
1389 byte[] rgba = await ZarrChannelView.ReadRgbTileAsync(image, 0, 0, 0, width, height,
1390 GetCoordinate(), channels);
1391 if (request != zarrRgbRequest || SelectedImage != image || Mode != requestedMode)
1392 return;
1393 var frame = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
1394 var data = frame.LockBits(new System.Drawing.Rectangle(0, 0, width, height),
1395 System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
1396 try
1397 {
1398 for (int i = 0; i < rgba.Length; i += 4)
1399 (rgba[i], rgba[i + 2]) = (rgba[i + 2], rgba[i]);
1400 for (int row = 0; row < height; row++)
1401 Marshal.Copy(rgba, row * width * 4, IntPtr.Add(data.Scan0, row * data.Stride), width * 4);
1402 }
1403 finally { frame.UnlockBits(data); }
1404 foreach (var old in Bitmaps) old?.Dispose();
1405 Bitmaps.Clear();
1406 Bitmaps.Add(frame);
1407 update = true;
1408 InvalidateView();
1409 }
1410 catch (Exception ex)
1411 {
1412 System.Diagnostics.Trace.WriteLine($"Could not render Zarr RGB channels: {ex.Message}");
1413 }
1414 return;
1415 }
1416
1417 // AForge's filters copy from unmanaged pixel pointers. Missing or disposed
1418 // buffers have a null pointer, so keep the last frame until pixels are available.
1419 foreach (BioImage image in Images)
1420 {
1421 int index = image.GetFrameIndex(zBar.Value, cBar.Value, tBar.Value);
1422 bool unavailable = index < 0 || index >= image.Buffers.Count;
1423 if (!unavailable)
1424 {
1425 var buffers = Mode == ViewMode.Filtered || Mode == ViewMode.Raw
1426 ? new[] { image.Buffers[index] }
1427 : image.Buffers.AsEnumerable();
1428 unavailable = buffers.Any(buffer =>
1429 buffer == null || buffer.Bytes == null || buffer.Bytes.Length == 0);
1430 }
1431 if (unavailable)
1432 {
1433 System.Diagnostics.Trace.WriteLine($"Image pixels are unavailable: {image.ID}");
1434 return;
1435 }
1436 }
1437 for (int i = 0; i < Bitmaps.Count; i++)
1438 {
1439 Bitmaps[i].Dispose();
1440 Bitmaps[i] = null;
1441 }
1442 Bitmaps.Clear();
1443 if (zBar.Maximum != SelectedImage.SizeZ - 1 || tBar.Maximum != SelectedImage.SizeT - 1)
1444 {
1445 InitGUI();
1446 }
1447
1448 int bi = 0;
1449 foreach (BioImage b in Images)
1450 {
1451 if (b.isPyramidal)
1452 updatePyr = true;
1453 b.PyramidalOrigin = PyramidalOrigin;
1454 b.PyramidalSize = new AForge.Size(gl.Width, gl.Height);
1455 ZCT coords = new ZCT(zBar.Value, cBar.Value, tBar.Value);
1456 Bitmap bitmap = null;
1457
1458 int index = b.Coords[zBar.Value, cBar.Value, tBar.Value];
1459 if (Mode == ViewMode.Filtered)
1460 {
1461 bitmap = b.GetFiltered(coords, b.RChannel.RangeR, b.GChannel.RangeG, b.BChannel.RangeB);
1462 }
1463 else if (Mode == ViewMode.RGBImage)
1464 {
1465 if (b.Buffers[0].RGBChannelsCount == 1)
1466 {
1467 var planes = new Bitmap[3];
1468 for (int color = 0; color < 3; color++)
1469 {
1470 int channel = Math.Clamp(b.rgbChannels[color], 0, b.SizeC - 1);
1471 planes[2 - color] = b.Buffers[b.GetFrameIndex(coords.Z, channel, coords.T)];
1472 }
1473 bitmap = Bitmap.GetRGBBitmap(planes, b.RChannel.RangeR, b.GChannel.RangeG, b.BChannel.RangeB);
1474 }
1475 else
1476 bitmap = b.GetRGBBitmap(coords, b.RChannel.RangeR, b.GChannel.RangeG, b.BChannel.RangeB);
1477 }
1478 else if (Mode == ViewMode.Raw)
1479 {
1480 bitmap = (Bitmap)b.Buffers[index].GetImageRGBA();
1481 }
1482 else
1483 {
1484 bitmap = b.GetEmission(coords, b.RChannel.RangeR, b.GChannel.RangeG, b.BChannel.RangeB);
1485 }
1486 var display = ToSysBitmap(bitmap);
1487 if (Mode == ViewMode.RGBImage)
1488 MaskRgbComponents(display, rgbEnabled);
1489 Bitmaps.Add(display);
1490 bi++;
1491 }
1492 UpdateRegularOverview();
1493 update = true;
1494 InvalidateView();
1495 }
1496 bool drawing = false;
1497 public void RemoveImage(int i)
1498 {
1499 do
1500 {
1501 System.Threading.Thread.Sleep(50);
1502 Application.DoEvents();
1503 } while (drawing || updating);
1504 Images[i].Dispose();
1505 Images.RemoveAt(i);
1506 UpdateImages();
1507 }
1508 public void RemoveImages()
1509 {
1510 do
1511 {
1512 Thread.Sleep(50);
1513 Application.DoEvents();
1514 } while (drawing || updating);
1515 for (int i = 0; i < Images.Count; i++)
1516 {
1517 Images[i].Dispose();
1518 }
1519 Images.Clear();
1520 UpdateImages();
1521 }
1522 Bitmap bitmap;
1526 public void UpdateImage()
1527 {
1528 UpdateImages();
1529 }
1537 private void channelBoxR_SelectedIndexChanged(object sender, EventArgs e)
1538 {
1539 if (initializingRgbSelectors || SelectedImage == null || channelBoxR.SelectedIndex == -1)
1540 return;
1541 rgbEnabled[0] = channelBoxR.SelectedIndex > 0;
1542 if (rgbEnabled[0]) SelectedImage.rgbChannels[0] = channelBoxR.SelectedIndex - 1;
1543 update = true;
1544 UpdateView();
1545 }
1553 private void channelBoxG_SelectedIndexChanged(object sender, EventArgs e)
1554 {
1555 if (initializingRgbSelectors || SelectedImage == null || channelBoxG.SelectedIndex == -1)
1556 return;
1557 rgbEnabled[1] = channelBoxG.SelectedIndex > 0;
1558 if (rgbEnabled[1]) SelectedImage.rgbChannels[1] = channelBoxG.SelectedIndex - 1;
1559 update = true;
1560 UpdateView();
1561 }
1569 private void channelBoxB_SelectedIndexChanged(object sender, EventArgs e)
1570 {
1571 if (initializingRgbSelectors || SelectedImage == null || channelBoxB.SelectedIndex == -1)
1572 return;
1573 rgbEnabled[2] = channelBoxB.SelectedIndex > 0;
1574 if (rgbEnabled[2]) SelectedImage.rgbChannels[2] = channelBoxB.SelectedIndex - 1;
1575 update = true;
1576 UpdateView();
1577 }
1585 private void showControlsToolStripMenuItem_Click(object sender, EventArgs e)
1586 {
1587 if (trackBarPanel.Visible)
1588 {
1589 trackBarPanel.Hide();
1590 trackBarPanel.Height = 0;
1591 Application.DoEvents();
1592 gl.Height += 75;
1593 showControlsToolStripMenuItem.Text = "Show Controls";
1594 gl.Dock = DockStyle.Fill;
1595 }
1596 else
1597 {
1598 trackBarPanel.Show();
1599 gl.Height -= 75;
1600 Application.DoEvents();
1601 trackBarPanel.Height = 75;
1602 showControlsToolStripMenuItem.Text = "Hide Controls";
1603 gl.Dock = DockStyle.Fill;
1604 }
1605
1606 }
1611 private void playZToolStripMenuItem_Click(object sender, EventArgs e)
1612 {
1613 if (playZToolStripMenuItem.Checked)
1614 {
1615 //We stop
1616 playZToolStripMenuItem.Checked = false;
1617 stopZToolStripMenuItem.Checked = true;
1618 zTimer.Stop();
1619 }
1620 else
1621 {
1622 //We start
1623 playZToolStripMenuItem.Checked = true;
1624 stopZToolStripMenuItem.Checked = false;
1625 zTimer.Start();
1626 }
1627 }
1632 private void stopZToolStripMenuItem_Click(object sender, EventArgs e)
1633 {
1634 if (stopZToolStripMenuItem.Checked)
1635 {
1636 //We start
1637 playZToolStripMenuItem.Checked = true;
1638 stopZToolStripMenuItem.Checked = false;
1639 zTimer.Start();
1640
1641 }
1642 else
1643 {
1644 //We stop
1645 playZToolStripMenuItem.Checked = false;
1646 stopZToolStripMenuItem.Checked = true;
1647 zTimer.Stop();
1648 }
1649 }
1654 private void playTimeToolStripMenu_Click(object sender, EventArgs e)
1655 {
1656 if (playTimeToolStripMenu.Checked)
1657 {
1658 //We stop
1659 playTimeToolStripMenu.Checked = false;
1660 stopTimeToolStripMenu.Checked = true;
1661 timelineTimer.Stop();
1662 }
1663 else
1664 {
1665 //We start
1666 playTimeToolStripMenu.Checked = true;
1667 stopTimeToolStripMenu.Checked = false;
1668 timelineTimer.Start();
1669 }
1670 }
1676 private void stopTimeToolStripMenu_Click(object sender, EventArgs e)
1677 {
1678 playTimeToolStripMenu.Checked = false;
1679 stopTimeToolStripMenu.Checked = true;
1680 timelineTimer.Stop();
1681 }
1686 private void playCToolStripMenuItem_Click(object sender, EventArgs e)
1687 {
1688 if (playCToolStripMenuItem.Checked)
1689 {
1690 //We stop
1691 playCToolStripMenuItem.Checked = false;
1692 stopCToolStripMenuItem.Checked = true;
1693 cTimer.Stop();
1694 }
1695 else
1696 {
1697 //We start
1698 playCToolStripMenuItem.Checked = true;
1699 stopCToolStripMenuItem.Checked = false;
1700 cTimer.Start();
1701 }
1702 }
1708 private void stopCToolStripMenuItem_Click(object sender, EventArgs e)
1709 {
1710 stopCToolStripMenuItem.Checked = false;
1711 playCToolStripMenuItem.Checked = true;
1712 cTimer.Stop();
1713 }
1714 private string mousePoint = "";
1715 private string mouseColor = "";
1722 private void playSpeedToolStripMenuItem_Click(object sender, EventArgs e)
1723 {
1724 PlaySpeed sp = null;
1725 if (Mode == ViewMode.RGBImage)
1726 sp = new PlaySpeed(timeEnabled, false, ZFps, TimeFps, CFps);
1727 else
1728 sp = new PlaySpeed(timeEnabled, true, ZFps, TimeFps, CFps);
1729 if (sp.ShowDialog() != DialogResult.OK)
1730 return;
1731 zTimer.Interval = sp.TimePlayspeed;
1732 cTimer.Interval = sp.CPlayspeed;
1733 timelineTimer.Interval = sp.TimePlayspeed;
1734 }
1741 private void playSpeedToolStripMenuItem1_Click(object sender, EventArgs e)
1742 {
1743 PlaySpeed sp = null;
1744 if (Mode == ViewMode.RGBImage)
1745 sp = new PlaySpeed(timeEnabled, false, ZFps, TimeFps, CFps);
1746 else
1747 sp = new PlaySpeed(timeEnabled, true, ZFps, TimeFps, CFps);
1748 if (sp.ShowDialog() != DialogResult.OK)
1749 return;
1750 zTimer.Interval = sp.TimePlayspeed;
1751 cTimer.Interval = sp.CPlayspeed;
1752 timelineTimer.Interval = sp.TimePlayspeed;
1753 }
1761 private void CPlaySpeedToolStripMenuItem_Click(object sender, EventArgs e)
1762 {
1763 PlaySpeed sp = null;
1764 if (Mode == ViewMode.RGBImage)
1765 sp = new PlaySpeed(timeEnabled, false, ZFps, TimeFps, CFps);
1766 else
1767 sp = new PlaySpeed(timeEnabled, true, ZFps, TimeFps, CFps);
1768 if (sp.ShowDialog() != DialogResult.OK)
1769 return;
1770 zTimer.Interval = sp.TimePlayspeed;
1771 cTimer.Interval = sp.CPlayspeed;
1772 timelineTimer.Interval = sp.TimePlayspeed;
1773 }
1793 public void GetRange()
1794 {
1795 RangeTool t;
1796 if (Mode == ViewMode.Filtered)
1797 t = new RangeTool(timeEnabled, true, zBar.Minimum, zBar.Maximum, tBar.Minimum, tBar.Maximum, cBar.Minimum, cBar.Maximum);
1798 else
1799 t = new RangeTool(timeEnabled, false, zBar.Minimum, zBar.Maximum, tBar.Minimum, tBar.Maximum, cBar.Minimum, cBar.Maximum);
1800 if (t.ShowDialog() != DialogResult.OK)
1801 return;
1802 zBar.Minimum = t.ZMin;
1803 zBar.Maximum = t.ZMax;
1804 tBar.Minimum = t.TimeMin;
1805 tBar.Maximum = t.TimeMax;
1806 cBar.Minimum = t.CMin;
1807 cBar.Maximum = t.CMax;
1808 }
1809 private void setValueRangeToolStripMenuItem_Click(object sender, EventArgs e)
1810 {
1811 GetRange();
1812 }
1813 private void setValueRangeToolStripMenuItem1_Click(object sender, EventArgs e)
1814 {
1815 GetRange();
1816 }
1817 private void setCValueRangeToolStripMenuItem_Click(object sender, EventArgs e)
1818 {
1819 GetRange();
1820 }
1825 private void ImageView_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
1826 {
1827 if (e is HandledMouseEventArgs handled && handled.Handled)
1828 return;
1829 var source = sender as System.Windows.Forms.Control ?? this;
1830 System.Drawing.Point cursor = source.Parent == viewport
1831 ? new System.Drawing.Point(source.Left + e.X, source.Top + e.Y)
1832 : viewport.PointToClient(source.PointToScreen(e.Location));
1833 if (e.Delta == 0 || !viewport.ClientRectangle.Contains(cursor) || Images.Count == 0)
1834 return;
1835
1836 App.viewer = this;
1837 Plugins.ScrollEvent(sender, e);
1838 if (e is HandledMouseEventArgs wheel)
1839 {
1840 if (wheel.Handled)
1841 return;
1842 // Prevent a canvas event from bubbling up and zooming a second time.
1843 wheel.Handled = true;
1844 }
1845
1846 const double minZoom = 0.000001;
1847 const double maxZoom = 1000000;
1848 double factor = Math.Pow(1.2, e.Delta / 120.0);
1849 PointD anchor = ImageToViewSpace(cursor.X, cursor.Y);
1850 if (SelectedImage.isPyramidal)
1851 {
1852 // Resolution is world units per screen pixel, so zooming in reduces it.
1853 Resolution = Math.Clamp(Resolution / factor, minZoom, maxZoom);
1854 PyramidalOrigin = new PointD(anchor.X / Resolution - cursor.X,
1855 anchor.Y / Resolution - cursor.Y);
1856 Tools.selectBoxSize = (float)(ROI.selectBoxSize * Resolution);
1857 UpdateImages();
1858 }
1859 else
1860 {
1861 // Clamp the common factor to preserve the X/Y scale ratio.
1862 factor = Math.Clamp(factor,
1863 minZoom / Math.Min(Scale.Width, Scale.Height),
1864 maxZoom / Math.Max(Scale.Width, Scale.Height));
1865 Scale = new SizeF((float)(Scale.Width * factor), (float)(Scale.Height * factor));
1866 PointD shifted = ImageToViewSpace(cursor.X, cursor.Y);
1867 Origin = new PointD(Origin.X + shifted.X - anchor.X, Origin.Y + shifted.Y - anchor.Y);
1868 }
1869 UpdateView();
1870 }
1876 private void ZTrackBar_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
1877 {
1878 if (e.Delta > 0)
1879 {
1880 if (zBar.Value + 1 <= zBar.Maximum)
1881 zBar.Value += 1;
1882 }
1883 else
1884 {
1885 if (zBar.Value - 1 >= zBar.Minimum)
1886 zBar.Value -= 1;
1887 }
1888
1889 }
1897 private void TimeTrackBar_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
1898 {
1899 if (!timeEnabled)
1900 return;
1901 if (e.Delta > 0)
1902 {
1903 if (tBar.Value + 1 <= tBar.Maximum)
1904 tBar.Value += 1;
1905 }
1906 else
1907 {
1908 if (tBar.Value - 1 >= tBar.Minimum)
1909 tBar.Value -= 1;
1910 }
1911 }
1917 private void CTrackBar_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
1918 {
1919 if (e.Delta > 0)
1920 {
1921 if (cBar.Value + 1 <= cBar.Maximum)
1922 cBar.Value += 1;
1923 }
1924 else
1925 {
1926 if (cBar.Value - 1 >= cBar.Minimum)
1927 cBar.Value -= 1;
1928 }
1929 }
1930
1937 private void cTimer_Tick(object sender, EventArgs e)
1938 {
1939 if (playCToolStripMenuItem.Checked)
1940 {
1941 if (cBar.Maximum >= cBar.Value + 1)
1942 cBar.Value++;
1943 else
1944 {
1945 if (loopC)
1946 cBar.Value = cBar.Minimum;
1947 }
1948 }
1949 }
1956 private void zTimer_Tick(object sender, EventArgs e)
1957 {
1958 if (playZToolStripMenuItem.Checked)
1959 {
1960 if (zBar.Maximum >= zBar.Value + 1)
1961 zBar.Value++;
1962 else
1963 {
1964 if (loopZ)
1965 zBar.Value = zBar.Minimum;
1966 }
1967 }
1968 }
1976 private void timer_Tick(object sender, EventArgs e)
1977 {
1978 if (playTimeToolStripMenu.Checked)
1979 {
1980 if (tBar.Maximum >= tBar.Value + 1)
1981 tBar.Value++;
1982 else
1983 {
1984 if (loopT)
1985 tBar.Value = tBar.Minimum;
1986 }
1987 }
1988 }
1996 private void zBar_ValueChanged(object sender, EventArgs e)
1997 {
1998 if (SelectedImage == null)
1999 return;
2000 SelectedImage.Coordinate = new ZCT(zBar.Value, SelectedImage.Coordinate.C, SelectedImage.Coordinate.T);
2001 update = true;
2002 UpdateImage();
2003 UpdateView();
2004 }
2011 private void timeBar_ValueChanged(object sender, EventArgs e)
2012 {
2013 if (SelectedImage == null)
2014 return;
2015 SelectedImage.Coordinate = new ZCT(SelectedImage.Coordinate.Z, SelectedImage.Coordinate.C, tBar.Value);
2016 update = true;
2017 UpdateImage();
2018 UpdateView();
2019 }
2027 private void cBar_ValueChanged(object sender, EventArgs e)
2028 {
2029 if (SelectedImage == null)
2030 return;
2031 SelectedImage.Coordinate = new ZCT(SelectedImage.Coordinate.Z, cBar.Value, SelectedImage.Coordinate.T);
2032 update = true;
2033 UpdateImage();
2034 UpdateView();
2035 }
2036
2037 private void loopTimeToolStripMenuItem_Click(object sender, EventArgs e)
2038 {
2039 loopT = loopTimeToolStripMenuItem.Checked;
2040 }
2041 private void loopZToolStripMenuItem_Click(object sender, EventArgs e)
2042 {
2043 loopZ = loopZToolStripMenuItem.Checked;
2044 }
2045 private void loopCToolStripMenuItem_Click(object sender, EventArgs e)
2046 {
2047 loopC = loopCToolStripMenuItem.Checked;
2048 }
2049
2050 public bool showRROIs = true;
2051 public bool showGROIs = true;
2052 public bool showBROIs = true;
2053
2054 private List<ROI> annotationsR = new List<ROI>();
2055 public List<ROI> AnnotationsR
2056 {
2057 get
2058 {
2059 return SelectedImage.GetAnnotations(SelectedImage.Coordinate.Z, SelectedImage.RChannel.Index, SelectedImage.Coordinate.T);
2060 }
2061 }
2062 private List<ROI> annotationsG = new List<ROI>();
2063 public List<ROI> AnnotationsG
2064 {
2065 get
2066 {
2067 return SelectedImage.GetAnnotations(SelectedImage.Coordinate.Z, SelectedImage.GChannel.Index, SelectedImage.Coordinate.T);
2068 }
2069 }
2070 private List<ROI> annotationsB = new List<ROI>();
2071 public List<ROI> AnnotationsB
2072 {
2073 get
2074 {
2075 return SelectedImage.GetAnnotations(SelectedImage.Coordinate.Z, SelectedImage.BChannel.Index, SelectedImage.Coordinate.T);
2076 }
2077 }
2078 public List<ROI> AnnotationsRGB
2079 {
2080 get
2081 {
2082 if (SelectedImage == null)
2083 return null;
2084 List<ROI> ans = new List<ROI>();
2085 if (Mode == ViewMode.RGBImage)
2086 {
2087 if (showRROIs && rgbEnabled[0])
2088 ans.AddRange(AnnotationsR);
2089 if (showGROIs && rgbEnabled[1])
2090 ans.AddRange(AnnotationsG);
2091 if (showBROIs && rgbEnabled[2])
2092 ans.AddRange(AnnotationsB);
2093 }
2094 else
2095 {
2096 ans.AddRange(SelectedImage.GetAnnotations(SelectedImage.Coordinate));
2097 }
2098 return ans;
2099 }
2100 }
2101 private System.Drawing.Point ToPoint(AForge.Point p)
2102 {
2103 return new System.Drawing.Point((int)p.X, (int)p.Y);
2104 }
2105 private System.Drawing.PointF ToPointF(PointD p)
2106 {
2107 return new System.Drawing.PointF((float)p.X, (float)p.Y);
2108 }
2114 private void DrawOverlay(System.Drawing.Graphics g)
2115 {
2116 if (SelectedImage == null)
2117 return;
2118 if (!updateOverlay)
2119 return;
2120 System.Drawing.Pen pen = null;
2121 System.Drawing.Pen red = null;
2122 System.Drawing.Pen green = null;
2123 System.Drawing.Pen mag = null;
2124 System.Drawing.Pen blue = null;
2125 Brush b = null;
2126 bool bounds = showBounds;
2127 bool labels = showText;
2128 ZCT cor = GetCoordinate();
2129 foreach (BioImage bi in Images)
2130 {
2131 if (!IsLayerEnabled(bi.PhysicalSizeX))
2132 continue;
2133 foreach (ROI an in bi.Annotations)
2134 {
2135 if (Mode == ViewMode.RGBImage)
2136 {
2137 if (!showRROIs && an.coord.C == 0)
2138 continue;
2139 if (!showGROIs && an.coord.C == 1)
2140 continue;
2141 if (!showBROIs && an.coord.C == 2)
2142 continue;
2143 }
2144 else if (zBar.Value != an.coord.Z || cBar.Value != an.coord.C || tBar.Value != an.coord.T)
2145 continue;
2146 float w = Math.Abs(Scale.Width);
2147 pen = new System.Drawing.Pen(new SolidBrush(System.Drawing.Color.FromArgb(an.strokeColor.R, an.strokeColor.G, an.strokeColor.B)), (float)an.strokeWidth / w);
2148 red = new System.Drawing.Pen(Brushes.Red, (float)an.strokeWidth / w);
2149 mag = new System.Drawing.Pen(Brushes.Magenta, (float)an.strokeWidth / w);
2150 green = new System.Drawing.Pen(Brushes.Green, (float)an.strokeWidth / w);
2151 blue = new System.Drawing.Pen(Brushes.Blue, (float)an.strokeWidth / w);
2152 Font fo = new Font(an.family, (float)(an.strokeWidth / w) * an.fontSize);
2153 if (an.Selected)
2154 {
2155 b = new SolidBrush(System.Drawing.Color.Magenta);
2156 }
2157 else
2158 b = new SolidBrush(System.Drawing.Color.FromArgb(an.strokeColor.R, an.strokeColor.G, an.strokeColor.B));
2159 PointF pc = new PointF((float)(an.BoundingBox.X + (an.BoundingBox.W / 2)), (float)(an.BoundingBox.Y + (an.BoundingBox.H / 2)));
2160 float width = (float)ToViewSizeW(ROI.selectBoxSize / w);
2161 if (SelectedImage.isPyramidal)
2162 {
2163 width = (float)(ROI.selectBoxSize * Resolution);
2164 }
2165 if (an.type == ROI.Type.Point)
2166 {
2167 g.DrawLine(pen, ToPointF(ToScreenSpace(an.Points[0])), ToPointF(ToScreenSpace(an.Points[0].X + 1, an.Points[0].Y + 1)));
2168 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2169 {
2170 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2171 }
2172 }
2173 else
2174 if (an.type == ROI.Type.Line)
2175 {
2176 g.DrawLine(pen, ToPointF(ToScreenSpace(an.Points[0])), ToPointF(ToScreenSpace(an.GetPoint(1))));
2177 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2178 {
2179 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2180 }
2181 }
2182 else
2183 if (an.type == ROI.Type.Rectangle && an.BoundingBox.W > 0 && an.BoundingBox.H > 0)
2184 {
2185 g.DrawRectangle(pen, new System.Drawing.RectangleF((float)an.BoundingBox.X, (float)an.BoundingBox.Y, (float)an.W, (float)an.H));
2186 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2187 {
2188 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2189 }
2190 }
2191 else
2192 if (an.type == ROI.Type.Ellipse)
2193 {
2194 RectangleD rec = ToScreenSpace(an.BoundingBox);
2195 g.DrawEllipse(pen, (float)rec.X, (float)rec.Y, (float)rec.W, (float)rec.H);
2196 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2197 {
2198 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2199 }
2200 }
2201 else
2202 if (an.type == ROI.Type.Polygon && an.closed)
2203 {
2204 if (an.Points.Count > 1)
2205 {
2206 System.Drawing.Point[] pts = new System.Drawing.Point[an.Points.Count];
2207 for (int i = 0; i < an.Points.Count; i++)
2208 {
2209 var p = ToScreenSpace(an.Points[i].X, an.Points[i].Y);
2210 pts[i] = new System.Drawing.Point((int)p.X, (int)p.Y);
2211 }
2212 g.DrawLines(pen, pts);
2213 }
2214 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2215 {
2216 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2217 }
2218 }
2219 else
2220 if (an.type == ROI.Type.Polygon && !an.closed)
2221 {
2222 if (an.Points.Count > 1)
2223 {
2224 System.Drawing.Point[] pts = new System.Drawing.Point[an.Points.Count - 1];
2225 for (int i = 0; i < an.Points.Count - 1; i++)
2226 {
2227 var p = ToScreenSpace(an.Points[i].X, an.Points[i].Y);
2228 pts[i] = new System.Drawing.Point((int)p.X, (int)p.Y);
2229 }
2230 g.DrawLines(pen, pts);
2231 }
2232 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2233 {
2234 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2235 }
2236 }
2237 else
2238 if (an.type == ROI.Type.Polyline)
2239 {
2240 if (an.Points.Count > 1)
2241 {
2242 System.Drawing.Point[] pts = new System.Drawing.Point[an.Points.Count - 1];
2243 for (int i = 0; i < an.Points.Count - 1; i++)
2244 {
2245 var p = ToScreenSpace(an.Points[i].X, an.Points[i].Y);
2246 pts[i] = new System.Drawing.Point((int)p.X, (int)p.Y);
2247 }
2248 g.DrawLines(pen, pts);
2249 }
2250 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2251 {
2252 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2253 }
2254 }
2255
2256 else
2257 if (an.type == ROI.Type.Freeform && an.closed)
2258 {
2259 if (an.Points.Count > 1)
2260 {
2261 System.Drawing.Point[] pts = new System.Drawing.Point[an.Points.Count];
2262 for (int i = 0; i < an.Points.Count; i++)
2263 {
2264 var p = ToScreenSpace(an.Points[i].X, an.Points[i].Y);
2265 pts[i] = new System.Drawing.Point((int)p.X, (int)p.Y);
2266 }
2267 g.DrawLines(pen, pts);
2268 }
2269 }
2270 else
2271 if (an.type == ROI.Type.Freeform && !an.closed)
2272 {
2273 if (an.Points.Count > 1)
2274 {
2275 System.Drawing.Point[] pts = new System.Drawing.Point[an.Points.Count - 1];
2276 for (int i = 0; i < an.Points.Count - 1; i++)
2277 {
2278 var p = ToScreenSpace(an.Points[i].X, an.Points[i].Y);
2279 pts[i] = new System.Drawing.Point((int)p.X, (int)p.Y);
2280 }
2281 g.DrawLines(pen, pts);
2282 }
2283 }
2284 if (an.type == ROI.Type.Label)
2285 {
2286 var v = ToScreenSpace(an.Points[0]);
2287 g.DrawString(an.Text, fo, b, (float)v.X, (float)v.Y);
2288 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2289 {
2290 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2291 }
2292 }
2293 if (labels)
2294 {
2295 System.Drawing.SizeF s = System.Windows.Forms.TextRenderer.MeasureText(an.Text, new Font(an.family, an.fontSize));
2296 //Lets draw the text of this ROI in the middle of the RO
2297 float fw = ((float)an.BoundingBox.X + ((float)an.BoundingBox.W / 2)) - ((float)s.Width / 2);
2298 float fh = ((float)an.BoundingBox.Y + ((float)an.BoundingBox.H / 2)) - ((float)s.Height / 2);
2299 var v = ToScreenSpace(new PointF(fw, fh));
2300 g.DrawString(an.Text, fo, b, v.X, v.Y);
2301 }
2302 if (bounds)
2303 {
2304 var v = ToScreenSpace(an.BoundingBox);
2305 g.DrawRectangles(green, new System.Drawing.RectangleF[1] { new System.Drawing.RectangleF((float)v.X, (float)v.Y, (float)v.W, (float)v.H) });
2306 }
2307 if (an.Selected)
2308 {
2309 //Lets draw the bounding box.
2310 var v = ToScreenSpace(an.BoundingBox);
2311 g.DrawRectangles(mag, new System.Drawing.RectangleF[1] { new System.Drawing.RectangleF((float)v.X, (float)v.Y, (float)v.W, (float)v.H) });
2312 //Lets draw the selectBoxes.
2313 List<RectangleD> rects = new List<RectangleD>();
2314 RectangleD[] sels = an.GetSelectBoxes(Tools.selectBoxSize);
2315 for (int i = 0; i < an.selectedPoints.Count; i++)
2316 {
2317 if (an.selectedPoints[i] < an.GetPointCount())
2318 {
2319 rects.Add(sels[an.selectedPoints[i]]);
2320 }
2321 }
2322 for (int i = 0; i < rects.Count; i++)
2323 {
2324 var va = ToScreenSpace(rects.ToArray());
2325 g.DrawRectangle(blue, new System.Drawing.RectangleF((float)va[0].X, (float)va[0].Y, (float)va[0].W, (float)va[0].H));
2326 }
2327
2328 rects.Clear();
2329 //Lets draw the text of this ROI in the middle of the ROI
2330 System.Drawing.Size s = System.Windows.Forms.TextRenderer.MeasureText(an.Text, new Font(an.family, an.fontSize));
2331 float fw = ((float)an.BoundingBox.X + ((float)an.BoundingBox.W / 2)) - ((float)s.Width / 2);
2332 float fh = ((float)an.BoundingBox.Y + ((float)an.BoundingBox.H / 2)) - ((float)s.Height / 2);
2333 var vv = ToScreenSpace(new PointF(fw, fh));
2334 g.DrawString(an.Text, fo, b, vv.X, vv.Y);
2335 }
2336 pen.Dispose();
2337 red.Dispose();
2338 mag.Dispose();
2339 green.Dispose();
2340 blue.Dispose();
2341 b.Dispose();
2342 }
2343 }
2344 }
2349 bool updatePyr = false;
2354 public void DrawView(System.Drawing.Graphics g)
2355 {
2356 try
2357 {
2358 drawing = true;
2359 if (SelectedImage == null)
2360 return;
2361 if (SelectedImage.isPyramidal)
2362 {
2363 UpdateImages(true);
2364 updatePyr = false;
2365 return;
2366 }
2367 g.TranslateTransform(ViewWidth / 2, ViewHeight / 2);
2368 if (Scale.Width == 0 || float.IsInfinity(Scale.Width))
2369 Scale = new SizeF(1, 1);
2370 g.ScaleTransform(Scale.Width, Scale.Height);
2371 if (Bitmaps.Count == 0)
2372 return;
2373 System.Drawing.RectangleF[] rf = new System.Drawing.RectangleF[1];
2374 using System.Drawing.Pen blue = new System.Drawing.Pen(Brushes.Blue, 1 / Scale.Width);
2375 for (int i = 0; i < Images.Count && i < Bitmaps.Count; i++)
2376 {
2377 BioImage im = Images[i];
2378 if (!IsLayerEnabled(im.PhysicalSizeX) && !im.isPyramidal)
2379 continue;
2380 RectangleD r = ToScreenRect(im.Volume.Location.X, im.Volume.Location.Y, im.Volume.Width, im.Volume.Height);
2381 double w = ToViewW(ViewWidth);
2382 double h = ToViewH(ViewHeight);
2383 RectangleF rg = new RectangleF((float)((-Origin.X) - (w / 2)), (float)((-Origin.Y) - (h / 2)), (float)(w), (float)(h));
2384 RectangleF rec = new RectangleF((float)im.Volume.Location.X, (float)im.Volume.Location.Y, (float)im.Volume.Width, (float)im.Volume.Height);
2385 if (SelectedImage.isPyramidal)
2386 {
2387 var tr = g.Transform;
2388 g.ResetTransform();
2389 g.DrawImage(Bitmaps[i], 0, 0);
2390 g.Transform = tr;
2391 }
2392 else
2393 if (rg.IntersectsWith(rec))
2394 {
2395 g.DrawImage(Bitmaps[i], (float)r.X, (float)r.Y, (float)r.W, (float)r.H);
2396 }
2397 if (i == SelectedIndex && !SelectedImage.isPyramidal)
2398 {
2399 rf[0] = new System.Drawing.RectangleF((float)r.X, (float)r.Y, (float)r.W, (float)r.H);
2400 g.DrawRectangles(blue, rf);
2401 }
2402 }
2403 update = false;
2404 }
2405 catch (Exception e)
2406 {
2407 Console.WriteLine(e.Message);
2408 }
2409 finally
2410 {
2411 drawing = false;
2412 }
2413 }
2414 private double scaleorig = 0;
2419 private void pictureBox_Paint(object sender, PaintEventArgs e)
2420 {
2421 var state = e.Graphics.Save();
2422 try
2423 {
2424 DrawView(e.Graphics);
2425 updateOverlay = true;
2426 DrawOverlay(e.Graphics);
2427 }
2428 finally
2429 {
2430 e.Graphics.Restore(state);
2431 }
2432 Plugins.Render(this, e);
2433 Plugins.Paint(sender, e);
2434 }
2438 public double GetScale()
2439 {
2440 return ToViewSizeW(ROI.selectBoxSize / Scale.Width);
2441 }
2442 private System.Drawing.Bitmap ToSysBitmap(Bitmap bm)
2443 {
2444 // Own the display pixels: a Bitmap constructed over AForge's temporary
2445 // managed buffer would retain an unpinned pointer after this method returns.
2446 using Bitmap rgba = bm.GetImageRGBA();
2447 var result = new System.Drawing.Bitmap(rgba.Width, rgba.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
2448 var data = result.LockBits(new System.Drawing.Rectangle(0, 0, result.Width, result.Height),
2449 System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
2450 try
2451 {
2452 int rowBytes = rgba.Width * 4;
2453 for (int y = 0; y < rgba.Height; y++)
2454 Marshal.Copy(rgba.Bytes, y * rgba.Stride, IntPtr.Add(data.Scan0, y * data.Stride), rowBytes);
2455 }
2456 finally
2457 {
2458 result.UnlockBits(data);
2459 }
2460 return result;
2461 }
2462 PointD mouseD = new PointD(0, 0);
2463 PointD prevMove = new PointD();
2471 private void rgbPictureBox_MouseMove(object sender, MouseEventArgs e)
2472 {
2473 PointD p = ImageToViewSpace(e.Location.X, e.Location.Y);
2474 tools.ToolMove(p, e.Button);
2475 mouseMove = p;
2476 MouseMoveInt = new PointD(e.X, e.Y);
2477 if (SelectedImage == null)
2478 return;
2479 if (SelectedImage != null)
2480 {
2481 PointD ip = SelectedImage.ToImageSpace(p);
2482 mousePoint = $"({p.X:0.##}, {p.Y:0.##})";
2483 }
2484 if (e.Button == MouseButtons.XButton1 && !x1State && !Ctrl && Mode != ViewMode.RGBImage)
2485 {
2486 if (cBar.Value < cBar.Maximum)
2487 cBar.Value++;
2488 x1State = true;
2489 }
2490 else if (e.Button == MouseButtons.XButton1 && !x1State && Ctrl)
2491 {
2492 if (tBar.Value < tBar.Maximum)
2493 tBar.Value++;
2494 x1State = true;
2495 }
2496 if (e.Button != MouseButtons.XButton1)
2497 x1State = false;
2498
2499 if (e.Button == MouseButtons.XButton2 && !x2State && !Ctrl && Mode != ViewMode.RGBImage)
2500 {
2501 if (cBar.Value > cBar.Minimum)
2502 cBar.Value--;
2503 x2State = true;
2504 }
2505 else if (e.Button == MouseButtons.XButton2 && !x2State && Ctrl)
2506 {
2507 if (tBar.Value > tBar.Minimum)
2508 tBar.Value--;
2509 x2State = true;
2510 }
2511 if (e.Button != MouseButtons.XButton2)
2512 x2State = false;
2513
2514 if (Tools.currentTool.type == Tools.Tool.Type.move && e.Button == MouseButtons.Left)
2515 {
2516 foreach (ROI an in selectedAnnotations)
2517 {
2518 if (an.selectedPoints.Count > 0 && an.selectedPoints.Count < an.GetPointCount())
2519 {
2520 if (an.type == ROI.Type.Rectangle || an.type == ROI.Type.Ellipse)
2521 {
2522 RectangleD d = an.BoundingBox;
2523 if (an.selectedPoints[0] == 0)
2524 {
2525 double dw = d.X - p.X;
2526 double dh = d.Y - p.Y;
2527 d.X = p.X;
2528 d.Y = p.Y;
2529 d.W += dw;
2530 d.H += dh;
2531 }
2532 else
2533 if (an.selectedPoints[0] == 1)
2534 {
2535 double dw = p.X - (d.W + d.X);
2536 double dh = d.Y - p.Y;
2537 d.W += dw;
2538 d.H += dh;
2539 d.Y -= dh;
2540 }
2541 else
2542 if (an.selectedPoints[0] == 2)
2543 {
2544 double dw = d.X - p.X;
2545 double dh = p.Y - (d.Y + d.H);
2546 d.W += dw;
2547 d.H += dh;
2548 d.X -= dw;
2549 }
2550 else
2551 if (an.selectedPoints[0] == 3)
2552 {
2553 double dw = d.X - p.X;
2554 double dh = d.Y - p.Y;
2555 d.W = p.X - an.X;
2556 d.H = p.Y - an.Y;
2557 }
2558 an.BoundingBox = d;
2559 }
2560 else
2561 {
2562 PointD pod = new PointD(p.X - pd.X, p.Y - pd.Y);
2563 for (int i = 0; i < an.selectedPoints.Count; i++)
2564 {
2565 PointD poid = an.GetPoint(an.selectedPoints[i]);
2566 an.UpdatePoint(new PointD(poid.X + pod.X, poid.Y + pod.Y), an.selectedPoints[i]);
2567 }
2568 }
2569 }
2570 else
2571 {
2572 PointD pod = new PointD(p.X - pd.X, p.Y - pd.Y);
2573 for (int i = 0; i < an.GetPointCount(); i++)
2574 {
2575 PointD poid = an.Points[i];
2576 an.UpdatePoint(new PointD(poid.X + pod.X, poid.Y + pod.Y), i);
2577 }
2578 }
2579 }
2580 UpdateOverlay();
2581 }
2582
2583 if (Tools.currentTool != null)
2584 if (Tools.currentTool.type == Tools.Tool.Type.pencil && e.Button == MouseButtons.Left)
2585 {
2586 PointD ip = SelectedImage.ToImageSpace(p);
2587 Tools.Tool tool = Tools.currentTool;
2588 Graphics g = Graphics.FromImage(SelectedBuffer);
2589 Pen pen = new Pen(Tools.DrawColor, (int)Tools.StrokeWidth, ImageView.SelectedImage.bitsPerPixel);
2590 g.FillEllipse(new Rectangle((int)ip.X, (int)ip.Y, (int)Tools.StrokeWidth, (int)Tools.StrokeWidth), pen.color);
2591 UpdateImage();
2592 }
2593
2594
2595 UpdateStatus();
2596 prevMove = p;
2597 pd = p;
2598 }
2605 private void pictureBox_MouseUp(object sender, MouseEventArgs e)
2606 {
2607 PointD p = ImageToViewSpace(e.Location.X, e.Location.Y);
2608 mouseUpButtons = e.Button;
2609 mouseDownButtons = MouseButtons.None;
2610 MouseUpInt = new PointD(e.X, e.Y);
2611 mouseUp = p;
2612 down = false;
2613 up = true;
2614 if (SelectedImage == null)
2615 return;
2616 App.viewer = this;
2617 tools.ToolUp(p, e.Button);
2618 }
2625 private void pictureBox_MouseDown(object sender, MouseEventArgs e)
2626 {
2627 App.viewer = this;
2628 MouseDownInt = new PointD(e.X, e.Y);
2629 mouseDownButtons = e.Button;
2630 mouseUpButtons = MouseButtons.None;
2631 PointD p = ImageToViewSpace(e.Location.X, e.Location.Y);
2632 pd = new PointD(p.X, p.Y);
2633 mouseDown = pd;
2634 mouseD = new PointD(e.Location.X, e.Location.Y);
2635 down = true;
2636 up = false;
2637 PointD ip;
2638 if (SelectedImage == null)
2639 return;
2640 // Middle drag always starts a pan, including over the overview. Keep
2641 // focus on the canvas instead of activating the floating tools window.
2642 if (e.Button == MouseButtons.Middle)
2643 {
2644 tools.ToolDown(mouseDown, e.Button);
2645 return;
2646 }
2647 ip = SelectedImage.ToImageSpace(p);
2648 tools.BringToFront();
2649 int ind = 0;
2650 foreach (BioImage b in Images)
2651 {
2652 RectangleD r = new RectangleD(b.Volume.Location.X, b.Volume.Location.Y, b.Volume.Width, b.Volume.Height);
2653 if (r.IntersectsWith(p))
2654 {
2655 b.selected = true;
2656 SelectedIndex = ind;
2657 }
2658 else
2659 b.selected = false;
2660 ind++;
2661 }
2662 if (!Ctrl && e.Button == MouseButtons.Left && Tools.currentTool.type != Tools.Tool.Type.rectSel)
2663 {
2664 foreach (ROI item in selectedAnnotations)
2665 {
2666 if (item.Selected)
2667 item.selectedPoints.Clear();
2668 }
2669 selectedAnnotations.Clear();
2670 }
2671
2672 if (Tools.currentTool.type == Tools.Tool.Type.move && e.Button == MouseButtons.Left)
2673 {
2674 float width = (float)ToViewSizeW(ROI.selectBoxSize / Scale.Width);
2675 float height = (float)ToViewSizeH(ROI.selectBoxSize / Scale.Height);
2676 if (openSlide)
2677 {
2678 width = Tools.selectBoxSize;
2679 height = Tools.selectBoxSize;
2680 }
2681 foreach (BioImage bi in Images)
2682 {
2683 foreach (ROI an in bi.Annotations)
2684 {
2685 if (an.GetSelectBound(width, height).IntersectsWith(new RectangleD(p.X, p.Y, 1, 1)))
2686 {
2687 selectedAnnotations.Add(an);
2688 an.Selected = true;
2689 RectangleD[] sels = an.GetSelectBoxes(Tools.selectBoxSize);
2690 RectangleD r = new RectangleD(p.X, p.Y, sels[0].W, sels[0].H);
2691 for (int i = 0; i < sels.Length; i++)
2692 {
2693 if (sels[i].IntersectsWith(r))
2694 {
2695 an.selectedPoints.Add(i);
2696 }
2697 }
2698 }
2699 else
2700 if (!Ctrl)
2701 an.Selected = false;
2702 }
2703 }
2704 UpdateOverlay();
2705 }
2706
2707 if (e.Button == MouseButtons.Left)
2708 {
2709 AForge.Point s = new AForge.Point(SelectedImage.SizeX, SelectedImage.SizeY);
2710 if ((ip.X < s.X && ip.Y < s.Y) || (ip.X >= 0 && ip.Y >= 0))
2711 {
2712 int zc = SelectedImage.Coordinate.Z;
2713 int cc = SelectedImage.Coordinate.C;
2714 int tc = SelectedImage.Coordinate.T;
2715 if (SelectedImage.isPyramidal)
2716 {
2717 if (SelectedImage.isRGB)
2718 {
2719 int r = (int)SelectedImage.GetValueRGB(zc, RChannel.Index, tc, e.X, e.Y, 0);
2720 int g = (int)SelectedImage.GetValueRGB(zc, GChannel.Index, tc, e.X, e.Y, 1);
2721 int b = (int)SelectedImage.GetValueRGB(zc, BChannel.Index, tc, e.X, e.Y, 2);
2722 mouseColor = ", " + r + "," + g + "," + b;
2723 }
2724 else
2725 {
2726 int r = (int)SelectedImage.GetValueRGB(zc, 0, tc, e.X, e.Y, 0);
2727 mouseColor = ", " + r;
2728 }
2729 }
2730 else
2731 {
2732 if (SelectedImage.isRGB)
2733 {
2734 int r = (int)SelectedImage.GetValueRGB(zc, RChannel.Index, tc, (int)ip.X, (int)ip.Y, 0);
2735 int g = (int)SelectedImage.GetValueRGB(zc, GChannel.Index, tc, (int)ip.X, (int)ip.Y, 1);
2736 int b = (int)SelectedImage.GetValueRGB(zc, BChannel.Index, tc, (int)ip.X, (int)ip.Y, 2);
2737 mouseColor = ", " + r + "," + g + "," + b;
2738 }
2739 else
2740 {
2741 int r = (int)SelectedImage.GetValueRGB(zc, 0, tc, (int)ip.X, (int)ip.Y, 0);
2742 mouseColor = ", " + r;
2743 }
2744 }
2745 }
2746 }
2747 UpdateStatus();
2748 tools.ToolDown(mouseDown, e.Button);
2749 }
2757 private void pictureBox_MouseDoubleClick(object sender, MouseEventArgs e)
2758 {
2759 if (SelectedImage == null)
2760 return;
2761 App.viewer = this;
2762 PointD p = ToViewSpace(e.Location.X, e.Location.Y);
2763 tools.ToolDown(p, e.Button);
2764 if (e.Button != MouseButtons.XButton1 && e.Button != MouseButtons.XButton2)
2765 Origin = new PointD(-p.X, -p.Y);
2766 }
2773 private void deleteROIToolStripMenuItem_Click(object sender, EventArgs e)
2774 {
2775 if (SelectedImage == null)
2776 return;
2777 foreach (ROI item in AnnotationsRGB)
2778 {
2779 if (item.Selected && (item.selectedPoints.Count == 0 || item.selectedPoints.Count == item.GetPointCount() || item.type == ROI.Type.Ellipse || item.type == ROI.Type.Rectangle))
2780 {
2781 SelectedImage.Annotations.Remove(item);
2782 }
2783 else
2784 {
2785 if ((item.type == ROI.Type.Polygon || item.type == ROI.Type.Freeform || item.type == ROI.Type.Polyline) && item.selectedPoints.Count > 0)
2786 {
2787 item.RemovePoints(item.selectedPoints.ToArray());
2788
2789 }
2790 item.selectedPoints.Clear();
2791 }
2792 }
2793 UpdateOverlay();
2794 }
2801 private void setTextSelectionToolStripMenuItem_Click(object sender, EventArgs e)
2802 {
2803 if (SelectedImage == null)
2804 return;
2805 foreach (ROI item in AnnotationsRGB)
2806 {
2807 if (item.Selected)
2808 {
2809 TextInput input = new TextInput(item.Text);
2810 if (input.ShowDialog() != DialogResult.OK)
2811 return;
2812 item.Text = input.TextValue;
2813 item.family = input.font.FontFamily.Name;
2814 item.fontSize = input.font.Size;
2815 item.strokeColor = AForge.Color.FromArgb(input.color.R, input.color.G, input.color.B);
2816 UpdateOverlay();
2817 }
2818 }
2819 }
2820
2825 private void copyViewToClipboardToolStripMenuItem_Click(object sender, EventArgs e)
2826 {
2827 System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(ViewWidth, ViewHeight);
2828 using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
2829 {
2830 DrawView(g);
2831 DrawOverlay(g);
2832 }
2833 System.Windows.Forms.Clipboard.SetImage(bmp);
2834 }
2835 List<ROI> copys = new List<ROI>();
2836
2838 public void CopySelection()
2839 {
2840 copys.Clear();
2841 string s = "";
2842 foreach (ROI item in AnnotationsRGB)
2843 {
2844 if (item.Selected)
2845 {
2846 copys.Add(item);
2847 s += BioImage.ROIToString(item);
2848 }
2849 }
2850 System.Windows.Forms.Clipboard.SetText(s);
2851 }
2854 public void PasteSelection()
2855 {
2856 string[] sts = System.Windows.Forms.Clipboard.GetText().Split(BioImage.NewLine);
2857 foreach (string line in sts)
2858 {
2859 if (line.Length > 8)
2860 {
2861 ROI an = BioImage.StringToROI(line);
2862 //We set the coordinates of the ROI's we are pasting
2863 an.coord = GetCoordinate();
2864 SelectedImage.Annotations.Add(an);
2865 }
2866 }
2867 UpdateOverlay();
2868 }
2873 private void copyROIToolStripMenuItem_Click(object sender, EventArgs e)
2874 {
2875 CopySelection();
2876 }
2877
2883 private void pasteROIToolStripMenuItem_Click(object sender, EventArgs e)
2884 {
2886 }
2887
2892 private void hideControlsToolStripMenuItem_Click(object sender, EventArgs e)
2893 {
2894 if (ShowControls)
2895 ShowControls = false;
2896 else
2897 ShowControls = true;
2898 }
2899
2904 private void showControlToolStripMenuItem_Click(object sender, EventArgs e)
2905 {
2906 if (ShowControls)
2907 ShowControls = false;
2908 else
2909 ShowControls = true;
2910 }
2911
2916 private void HideStatusMenuItem_Click(object sender, EventArgs e)
2917 {
2918 ShowStatus = false;
2919 }
2924 private void rGBToolStripMenuItem_Click(object sender, EventArgs e)
2925 {
2926 Mode = ViewMode.RGBImage;
2927 }
2928
2933 private void filteredToolStripMenuItem_Click(object sender, EventArgs e)
2934 {
2935 Mode = ViewMode.Filtered;
2936 }
2937
2942 private void rawToolStripMenuItem_Click(object sender, EventArgs e)
2943 {
2944 Mode = ViewMode.Raw;
2945 }
2952 public PointD ImageToViewSpace(double x, double y)
2953 {
2954 if (SelectedImage == null)
2955 return ToViewSpace(x, y);
2956 if (SelectedImage.isPyramidal)
2957 {
2958 return new PointD((PyramidalOrigin.X + x) * Resolution, (PyramidalOrigin.Y + y) * Resolution);
2959 }
2960 else
2961 return ToViewSpace(x, y);
2962 }
2968 public PointF ToViewSpace(PointF p)
2969 {
2970 PointD d = ToViewSpace(p.X, p.Y);
2971 return new PointF((float)d.X, (float)d.Y);
2972 }
2978 public PointD ToViewSpace(PointD p)
2979 {
2980 return ToViewSpace(p.X, p.Y); ;
2981 }
2988 public PointD ToViewSpace(double x, double y)
2989 {
2990 if (SelectedImage != null)
2991 if (SelectedImage.isPyramidal)
2992 {
2993 double ddx = x / Resolution;
2994 double ddy = y / Resolution;
2995 return new PointD(ddx, ddy);
2996 }
2997 double dx, dy;
2998 dx = (ToViewSizeW(x - (ViewWidth / 2)) / Scale.Width) - Origin.X;
2999 dy = (ToViewSizeH(y - (ViewHeight / 2)) / Scale.Height) - Origin.Y;
3000 return new PointD(dx, dy);
3001 }
3007 private double ToViewSizeW(double d)
3008 {
3009 if (SelectedImage != null)
3010 if (SelectedImage.isPyramidal)
3011 {
3012 return d / Resolution;
3013 }
3014 double x = (double)(d / PxWmicron);
3015 return x;
3016 }
3022 public double ToViewSizeH(double d)
3023 {
3024 if (SelectedImage != null)
3025 if (SelectedImage.isPyramidal)
3026 {
3027 return d / Resolution;
3028 }
3029 double y = (double)(d / PxHmicron);
3030 return y;
3031 }
3037 public double ToViewW(double d)
3038 {
3039 double x = (double)(d / PxWmicron) / scale.Width;
3040 return x;
3041 }
3047 public double ToViewH(double d)
3048 {
3049 double y = (double)(d / PxHmicron) / scale.Height;
3050 return y;
3051 }
3058 public PointD ToScreenSpace(double x, double y)
3059 {
3060 double fx = ToScreenScaleW(Origin.X + x);
3061 double fy = ToScreenScaleH(Origin.Y + y);
3062 return new PointD(fx, fy);
3063 }
3069 public PointD ToScreenSpace(PointD p)
3070 {
3071 return ToScreenSpace(p.X, p.Y);
3072 }
3078 public PointF ToScreenSpace(PointF p)
3079 {
3080 PointD pd = ToScreenSpace(p.X, p.Y);
3081 return new PointF((float)pd.X, (float)pd.Y);
3082 }
3088 public PointF[] ToScreenSpace(PointF[] p)
3089 {
3090 PointF[] pf = new PointF[p.Length];
3091 for (int i = 0; i < p.Length; i++)
3092 {
3093 pf[i] = ToScreenSpace(p[i]);
3094 }
3095 return pf;
3096 }
3102 public PointF ToScreenSpace(Point3D p)
3103 {
3104 PointD pd = ToScreenSpace(p.X, p.Y);
3105 return new PointF((float)pd.X, (float)pd.Y);
3106 }
3112 public float ToScreenScaleW(double x)
3113 {
3114 return (float)(x * PxWmicron);
3115 }
3121 public float ToScreenScaleH(double y)
3122 {
3123 return (float)(y * PxHmicron);
3124 }
3130 public PointF ToScreenScale(PointD p)
3131 {
3132 float x = ToScreenScaleW((float)p.X);
3133 float y = ToScreenScaleH((float)p.Y);
3134 return new PointF(x, y);
3135 }
3144 public RectangleD ToScreenRect(double x, double y, double w, double h)
3145 {
3146 if (SelectedImage == null)
3147 {
3148 PointD pf;
3149 pf = ToScreenSpace(x, y);
3150 return new RectangleD(pf.X, pf.Y, ToScreenScaleW(w), ToScreenScaleH(h));
3151 }
3152 if (SelectedImage.isPyramidal)
3153 {
3154 PointD d = ToViewSpace(x, y);
3155 double dw = ToViewSizeW(w);
3156 double dh = ToViewSizeH(h);
3157 return new RectangleD((d.X - PyramidalOrigin.X), (d.Y - PyramidalOrigin.Y), dw, dh);
3158 }
3159 else
3160 {
3161 PointD pf = ToScreenSpace(x, y);
3162 return new RectangleD(pf.X, pf.Y, ToScreenScaleW(w), ToScreenScaleH(h));
3163 }
3164 }
3174 public SKRect ToSKRect(double x, double y, double w, double h)
3175 {
3176 double xd = gl.Width / 2;
3177 double yd = gl.Height / 2;
3178 return new SKRect((float)(xd - x), (float)(yd - y), (float)(xd - (x + w)), (float)(yd - (y + h)));
3179 }
3186 {
3187 return ToScreenRect(p.X, p.Y, p.W, p.H);
3188 }
3194 public RectangleD ToScreenSpace(RectangleF p)
3195 {
3196 return ToScreenRect(p.X, p.Y, p.Width, p.Height);
3197 }
3204 {
3205 RectangleD[] rs = new RectangleD[p.Length];
3206 for (int i = 0; i < p.Length; i++)
3207 {
3208 rs[i] = ToScreenSpace(p[i]);
3209 }
3210 return rs;
3211 }
3217 public RectangleF[] ToScreenSpace(RectangleF[] p)
3218 {
3219 RectangleF[] rs = new RectangleF[p.Length];
3220 for (int i = 0; i < p.Length; i++)
3221 {
3222 rs[i] = ToScreenSpace(p[i]).ToRectangleF();
3223 }
3224 return rs;
3225 }
3231 public PointF[] ToScreenSpace(PointD[] p)
3232 {
3233 PointF[] rs = new PointF[p.Length];
3234 for (int i = 0; i < p.Length; i++)
3235 {
3236 PointD pd = ToScreenSpace(p[i]);
3237 rs[i] = new PointF((float)pd.X, (float)pd.Y);
3238 }
3239 return rs;
3240 }
3246 public float ToScreenW(double x)
3247 {
3248 return (float)(x * PxWmicron);
3249 }
3255 public float ToScreenH(double y)
3256 {
3257 return (float)(y * PxHmicron);
3258 }
3266 public void ImageView_KeyDown(object sender, KeyEventArgs e)
3267 {
3268 double moveAmount = 5 * Scale.Width;
3269 Plugins.KeyDownEvent(sender, e);
3270 if (e.KeyCode == Keys.C && e.Control)
3271 {
3272 CopySelection();
3273 return;
3274 }
3275 if (e.KeyCode == Keys.V && e.Control)
3276 {
3278 return;
3279 }
3280 if (e.KeyCode == Keys.Subtract || e.KeyCode == Keys.NumPad7)
3281 {
3282 if (SelectedImage.isPyramidal)
3283 Resolution *= 0.9f;
3284 else
3285 Scale = new SizeF(Scale.Width - 0.1f, Scale.Height - 0.1f);
3286 UpdateView();
3287 }
3288 if (e.KeyCode == Keys.Add || e.KeyCode == Keys.NumPad9)
3289 {
3290 if (SelectedImage.isPyramidal)
3291 Resolution *= 1.1f;
3292 else
3293 Scale = new SizeF(Scale.Width + 0.1f, Scale.Height + 0.1f);
3294 UpdateView();
3295 }
3296 if (e.KeyCode == Keys.W || e.KeyCode == Keys.NumPad8)
3297 {
3298 if (SelectedImage.isPyramidal)
3299 PyramidalOrigin = new PointD(PyramidalOrigin.X, PyramidalOrigin.Y - moveAmount);
3300 else
3301 Origin = new PointD(Origin.X, Origin.Y + moveAmount);
3302 UpdateView();
3303 }
3304 if (e.KeyCode == Keys.S || e.KeyCode == Keys.NumPad2)
3305 {
3306 if (SelectedImage.isPyramidal)
3307 PyramidalOrigin = new PointD(PyramidalOrigin.X, PyramidalOrigin.Y + moveAmount);
3308 else
3309 Origin = new PointD(Origin.X, Origin.Y - moveAmount);
3310 UpdateView();
3311 }
3312 if (e.KeyCode == Keys.A || e.KeyCode == Keys.NumPad4)
3313 {
3314 if (SelectedImage.isPyramidal)
3315 PyramidalOrigin = new PointD(PyramidalOrigin.X - moveAmount, PyramidalOrigin.Y);
3316 else
3317 Origin = new PointD(Origin.X + moveAmount, Origin.Y);
3318 UpdateView();
3319 }
3320 if (e.KeyCode == Keys.D || e.KeyCode == Keys.NumPad6)
3321 {
3322 if (SelectedImage.isPyramidal)
3323 PyramidalOrigin = new PointD(PyramidalOrigin.X + moveAmount, PyramidalOrigin.Y);
3324 else
3325 Origin = new PointD(Origin.X - moveAmount, Origin.Y);
3326 UpdateView();
3327 }
3328 }
3329 public void ImageView_KeyUp(object sender, KeyEventArgs e)
3330 {
3331 Plugins.KeyUpEvent(sender, e);
3332 }
3333 public void ImageView_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
3334 {
3335 Plugins.KeyPressEvent(sender, e);
3336 }
3341 public void GoToImage()
3342 {
3344 }
3345 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
3347 {
3348 get { return new PointD(PyramidalOrigin.X * Resolution, PyramidalOrigin.Y * Resolution); }
3349 set { PyramidalOrigin = new PointD(value.X / Resolution, value.Y / Resolution); }
3350 }
3351 PointD mouseDownInt = new PointD(0, 0);
3352 PointD mouseUpInt = new PointD(0, 0);
3353 PointD mouseMoveInt = new PointD(0, 0);
3354 PointD mouseMove = new PointD(0, 0);
3355 /* A property that returns the value of the mouseDownInt variable. */
3356 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
3357 public PointD MouseDownInt
3358 {
3359 get { return mouseDownInt; }
3360 set { mouseDownInt = value; }
3361 }
3362 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
3363 public PointD MouseUpInt
3364 {
3365 get { return mouseUpInt; }
3366 set { mouseUpInt = value; }
3367 }
3368 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
3369 public PointD MouseMoveInt
3370 {
3371 get { return mouseMoveInt; }
3372 set { mouseMoveInt = value; }
3373 }
3374
3375 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
3376 public bool ShowMasks { get; set; } = true;
3377
3383 public void GoToImage(int i)
3384 {
3385 if (i < 0 || Images.Count <= i || ViewWidth <= 0 || ViewHeight <= 0)
3386 return;
3387 App.viewer = this;
3388 if (SelectedIndex != i)
3389 SelectedIndex = i;
3390 else
3391 selectedIndex = i;
3392 BioImage image = Images[i];
3393 if (image.isPyramidal)
3394 {
3395 // The schema extent uses the same world coordinates as the slide
3396 // renderer. BioImage.Volume may only describe its initial Zarr tile.
3397 RectangleD bounds = OverviewWorldBounds(image);
3398 if (bounds.W <= 0 || bounds.H <= 0 || !double.IsFinite(bounds.W) || !double.IsFinite(bounds.H))
3399 return;
3400 double fit = Math.Max(bounds.W / ViewWidth, bounds.H / ViewHeight);
3401 if (!double.IsFinite(fit) || fit <= 0)
3402 return;
3403 Resolution = fit;
3404 PyramidalOrigin = new PointD((bounds.X + bounds.W / 2) / fit - ViewWidth / 2.0,
3405 (bounds.Y + bounds.H / 2) / fit - ViewHeight / 2.0);
3406 UpdateView();
3407 return;
3408 }
3409 double dx = image.Volume.Width / 2;
3410 double dy = image.Volume.Height / 2;
3411 Origin = new PointD(-(image.Volume.Location.X + dx), -(image.Volume.Location.Y + dy));
3412 double wx, wy;
3413 wx = ViewWidth / ToScreenScaleW(image.Volume.Width);
3414 wy = ViewHeight / ToScreenScaleH(image.Volume.Height);
3415 double fitScale = Math.Min(wx, wy);
3416 if (double.IsFinite(fitScale) && fitScale > 0)
3417 Scale = new SizeF((float)fitScale, (float)fitScale);
3418 UpdateView();
3419 }
3420
3425 private void goToImageToolStripMenuItem_Click(object sender, EventArgs e)
3426 {
3427 GoToImage();
3428 }
3434 private void goToToolStripMenuItem1_Click(object sender, EventArgs e)
3435 {
3436 Origin = new PointD(mouseDown.X, mouseDown.Y);
3437 }
3443 private void goToImageToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
3444 {
3445 ToolStripMenuItem item = (ToolStripMenuItem)sender;
3446 item.DropDownItems.Clear();
3447 foreach (BioImage im in Images)
3448 {
3449 ToolStripMenuItem it = new ToolStripMenuItem();
3450 it.Text = im.filename;
3451 item.DropDownItems.Add(it);
3452 }
3453 }
3461 private void goToImageToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
3462 {
3463 int i = 0;
3464 foreach (var item in Images)
3465 {
3466 if (item.filename == e.ClickedItem.Text)
3467 {
3468 GoToImage(i);
3469 return;
3470 }
3471 i++;
3472 }
3473 }
3474 public new void Dispose()
3475 {
3476 for (int i = 0; i < Bitmaps.Count; i++)
3477 {
3478 if (Bitmaps[i] != null)
3479 Bitmaps[i].Dispose();
3480 }
3481 for (int i = 0; i < Bitmaps.Count; i++)
3482 {
3483 if (Bitmaps[i] != null)
3484 Bitmaps[i].Dispose();
3485 }
3486 }
3487
3493 private void goToToolStripMenuItem_Click_1(object sender, EventArgs e)
3494 {
3496 }
3497
3502 private void drawToolStripMenuItem_Click(object sender, EventArgs e)
3503 {
3504 Graphics g = Graphics.FromImage(SelectedBuffer);
3505 foreach (ROI item in AnnotationsRGB)
3506 {
3507 Pen p = new Pen(Tools.DrawColor, (int)Tools.StrokeWidth, SelectedBuffer.BitsPerPixel);
3508 g.pen = p;
3509 if (item.Selected)
3510 {
3511 if (item.type == ROI.Type.Line)
3512 {
3513 g.DrawLine(new PointF((float)SelectedImage.ToImageSpace(item.GetPoint(0)).X, (float)SelectedImage.ToImageSpace(item.GetPoint(0)).Y), new PointF((float)SelectedImage.ToImageSpace(item.GetPoint(1)).X, (float)SelectedImage.ToImageSpace(item.GetPoint(1)).Y));
3514 }
3515 else
3516 if (item.type == ROI.Type.Rectangle)
3517 {
3518 g.DrawRectangle(SelectedImage.ToImageSpace(item.BoundingBox));
3519 }
3520 else
3521 if (item.type == ROI.Type.Ellipse)
3522 {
3523 g.DrawEllipse(SelectedImage.ToImageSpace(item.BoundingBox));
3524 }
3525 else
3526 if (item.type == ROI.Type.Freeform || item.type == ROI.Type.Polygon || item.type == ROI.Type.Polyline)
3527 {
3528 if (item.closed)
3529 {
3530 for (int i = 0; i < item.GetPointCount() - 1; i++)
3531 {
3532 g.DrawLine(new PointF((float)SelectedImage.ToImageSpace(item.GetPoint(i)).X, (float)SelectedImage.ToImageSpace(item.GetPoint(i)).Y), new PointF((float)SelectedImage.ToImageSpace(item.GetPoint(i + 1)).X, (float)SelectedImage.ToImageSpace(item.GetPoint(i + 1)).Y));
3533 }
3534 g.DrawLine(new PointF((float)SelectedImage.ToImageSpace(item.GetPoint(0)).X, (float)SelectedImage.ToImageSpace(item.GetPoint(0)).Y), new PointF((float)SelectedImage.ToImageSpace(item.GetPoint(item.GetPointCount() - 1)).X, (float)SelectedImage.ToImageSpace(item.GetPoint(item.GetPointCount() - 1)).Y));
3535
3536 }
3537 else
3538 {
3539 for (int i = 0; i < item.GetPointCount() - 1; i++)
3540 {
3541 g.DrawLine(new PointF((float)SelectedImage.ToImageSpace(item.GetPoint(i)).X, (float)SelectedImage.ToImageSpace(item.GetPoint(i)).Y), new PointF((float)SelectedImage.ToImageSpace(item.GetPoint(i + 1)).X, (float)SelectedImage.ToImageSpace(item.GetPoint(i + 1)).Y));
3542 }
3543 }
3544 }
3545 }
3546 }
3547 update = true;
3548 UpdateImage();
3549 }
3550
3555 private void fillToolStripMenuItem_Click(object sender, EventArgs e)
3556 {
3557 Graphics g = Graphics.FromImage(SelectedBuffer);
3558 foreach (ROI item in AnnotationsRGB)
3559 {
3560 Pen p = new Pen(Tools.DrawColor, (int)Tools.StrokeWidth, SelectedBuffer.BitsPerPixel);
3561 if (item.Selected)
3562 {
3563 if (item.type == ROI.Type.Line)
3564 {
3565 g.DrawLine(new PointF((float)SelectedImage.ToImageSpace(item.GetPoint(0)).X, (float)SelectedImage.ToImageSpace(item.GetPoint(0)).Y), new PointF((float)SelectedImage.ToImageSpace(item.GetPoint(1)).X, (float)SelectedImage.ToImageSpace(item.GetPoint(1)).Y));
3566 }
3567 else
3568 if (item.type == ROI.Type.Rectangle)
3569 {
3570 g.FillRectangle(SelectedImage.ToImageSpace(item.BoundingBox), p.color);
3571 }
3572 else
3573 if (item.type == ROI.Type.Ellipse)
3574 {
3575 g.FillEllipse(SelectedImage.ToImageSpace(item.BoundingBox), p.color);
3576 }
3577 else
3578 if (item.type == ROI.Type.Freeform || item.type == ROI.Type.Polygon || item.type == ROI.Type.Polyline)
3579 {
3580 g.FillPolygon(SelectedImage.ToImageSpace(item.GetPointsF()), SelectedImage.ToImageSpace(item.BoundingBox), p.color);
3581 }
3582 }
3583 }
3584 update = true;
3585 UpdateImage();
3586 }
3587
3591 public void MoveStageToImage()
3592 {
3593 if (SelectedImage == null)
3594 return;
3595 Microscope.Stage.SetPosition(SelectedImage.Volume.Location.X, SelectedImage.Volume.Location.Y);
3596 update = true;
3597 UpdateView();
3598 }
3602 public void MoveStageToImage(int i)
3603 {
3604 update = true;
3605 Microscope.Stage.SetPosition(Images[i].Volume.Location.X, Images[i].Volume.Location.Y);
3606 UpdateView();
3607 }
3608
3615 private void moveStageToImageToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
3616 {
3617 int i = 0;
3618 foreach (var item in Images)
3619 {
3620 if (item.ID.Contains(e.ClickedItem.Text))
3621 {
3623 return;
3624 }
3625 i++;
3626 }
3627 }
3628
3633 private void moveStageToImageToolStripMenuItem_Click(object sender, EventArgs e)
3634 {
3636 }
3637 private void layersToolStripMenuItem_Click(object sender, EventArgs e)
3638 {
3639 if (layersTool == null)
3640 layersTool = new Layers();
3641 layersTool.Show();
3642 }
3647 private void pictureBox_SizeChanged(object sender, EventArgs e)
3648 {
3649 if (ViewWidth < 2 || ViewHeight < 2) return;
3650 if (SelectedImage.isPyramidal)
3651 {
3652 if (SelectedImage.isPyramidal)
3653 UpdateImages();
3654 }
3655 }
3656 private void contextMenuStrip_Opening(object sender, CancelEventArgs e)
3657 {
3658 App.viewer = this;
3659 if (App.tabsView != null)
3660 Function.Initialize();
3661 }
3662 private void hideOverviewToolStripMenuItem_Click(object sender, EventArgs e)
3663 {
3664 if (hideOverViewToolStripMenuItem.Text == "Hide Overview")
3665 {
3666 ShowOverview = false;
3667 hideOverViewToolStripMenuItem.Text = "Show Overview";
3668 }
3669 else
3670 {
3671 ShowOverview = true;
3672 hideOverViewToolStripMenuItem.Text = "Hide Overview";
3673 }
3674 }
3675 private void removeImageToolStripMenuItem_Click(object sender, EventArgs e)
3676 {
3678 }
3679
3680 private void removeImagesToolStripMenuItem_Click(object sender, EventArgs e)
3681 {
3682 RemoveImages();
3683 }
3684 #region OpenSlide
3685 private OpenSlideBase _openSlideBase;
3686 private SlideBase _slideBase;
3687
3691 private void Initialize(string file, BioImage bm)
3692 {
3693 if (bm.Resolutions.Count == 1)
3694 return;
3695 if (bm.OpenSlideBase == null)
3696 {
3697 _slideBase = bm.SlideBase;
3698 slideRenderer = new SlideRenderer(gl);
3699 slideRenderer.SetSource(_slideBase);
3700 }
3701 else
3702 {
3703 _openSlideBase = bm.OpenSlideBase;
3704 slideRenderer = new SlideRenderer(gl);
3705 slideRenderer.SetSource(_openSlideBase);
3706 }
3707 }
3708
3709 #endregion
3710
3711 private void viewpanel_Paint(object sender, PaintEventArgs e)
3712 {
3713 pictureBox_Paint(sender, e);
3714 }
3715
3716 private void hideAllToolStripMenuItem_Click(object sender, EventArgs e)
3717 {
3718 ShowStage = false;
3719 ShowOverview = false;
3720 ShowStatus = false;
3721 ShowControls = false;
3722 }
3723
3724 private void showAllToolStripMenuItem_Click(object sender, EventArgs e)
3725 {
3726 ShowStage = true;
3727 ShowOverview = true;
3728 ShowStatus = true;
3729 ShowControls = true;
3730 }
3731 }
3732}
System.Drawing.Pen Pen
System.Drawing.Image Image
Definition ImageView.cs:15
AForge.RectangleD RectangleD
Definition ImageView.cs:17
AForge.SizeF SizeF
Definition ImageView.cs:18
System.Windows.Forms.Keys Keys
Definition ImageView.cs:16
System.Windows.Forms.Application Application
Definition ImageView.cs:14
System.Drawing.Graphics Graphics
Definition OMERO.cs:14
static ChannelsTool channelsTool
Definition App.cs:9
static ImageView viewer
Definition App.cs:16
static TabsView tabsView
Definition App.cs:10
static Tools tools
Definition App.cs:14
List< ROI > AnnotationsG
void MoveStageToImage()
new void Dispose()
List< ROI > AnnotationsR
int CFps
Setting the interval of the timer to the inverse of the fps. *‍/.
Definition ImageView.cs:890
bool ShowControls
Setting the visibility of the trackBarPanel. *‍/.
Definition ImageView.cs:525
double ToViewW(double d)
RectangleD ToScreenRect(double x, double y, double w, double h)
System.Drawing.Bitmap overviewImage
Definition ImageView.cs:365
static bool showBounds
Definition ImageView.cs:351
RectangleD[] ToScreenSpace(RectangleD[] p)
PointD ToViewSpace(PointD p)
PointF ToScreenSpace(PointF p)
void UpdateRGBChannels()
Definition ImageView.cs:843
float ToScreenScaleW(double x)
override bool ProcessCmdKey(ref Message msg, Keys keyData)
Definition ImageView.cs:205
void ImageView_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
static PointD mouseDown
Definition ImageView.cs:335
RectangleD ToScreenSpace(RectangleD p)
static bool up
Definition ImageView.cs:338
new AForge.SizeF Scale
Scale when opening image stacks.
Definition ImageView.cs:805
Channel GChannel
A property that returns the G channel of the image. *‍/.
Definition ImageView.cs:703
string Path
A property that returns the filepath. *‍/.
Definition ImageView.cs:687
bool ShowStatus
Setting the value of the property ShowStatus. *‍/.
Definition ImageView.cs:570
void ImageView_KeyUp(object sender, KeyEventArgs e)
PointD ToScreenSpace(PointD p)
PointD PyramidalOrigin
Setting the value of the pyramidalOrigin variable. *‍/.
Definition ImageView.cs:755
List< Layer > Layers
Definition ImageView.cs:290
void AddImage(BioImage im)
Definition ImageView.cs:485
List< BioImage > Images
Definition ImageView.cs:359
double PxWmicron
Only used when opening stacks.
Definition ImageView.cs:599
void MoveStageToImage(int i)
int ZFps
Setting the interval of the timer to the value of the fps. *‍/.
Definition ImageView.cs:858
RectangleF[] ToScreenSpace(RectangleF[] p)
PointF[] ToScreenSpace(PointF[] p)
static BioImage SelectedImage
Definition ImageView.cs:306
Channel RChannel
A property that returns the R channel of the selected image. *‍/.
Definition ImageView.cs:695
Rectangle OverView
Definition ImageView.cs:428
static Bitmap SelectedBuffer
Definition ImageView.cs:328
void SetCoordinate(int z, int c, int t)
Definition ImageView.cs:443
override void OnLayout(LayoutEventArgs e)
Definition ImageView.cs:186
PointF ToScreenScale(PointD p)
void UpdateSelectBoxSize(float size)
Definition ImageView.cs:959
int Level
Current level when viewing whole-slide and pyramidal images.
Definition ImageView.cs:791
void ImageView_KeyDown(object sender, KeyEventArgs e)
static List< ROI > selectedAnnotations
Definition ImageView.cs:303
static bool down
Definition ImageView.cs:336
double ToViewSizeH(double d)
float ToScreenH(double y)
void UpdateView(bool refresh)
double Resolution
A property of the class ImageViewer. It is a getter and setter for the resolution of the image.
Definition ImageView.cs:770
PointD PyramidalOriginTransformed
PointD ToScreenSpace(double x, double y)
ImageView(BioImage im, bool OpenWithOpenSlide=true)
Initializing the image viewer. *‍/.
Definition ImageView.cs:32
PointF ToViewSpace(PointF p)
void CopySelection()
It takes the selected ROIs and copies them to the clipboard.
ContextMenuStrip ViewContextMenu
A property that returns a ContextMenuStrip object. *‍/.
Definition ImageView.cs:826
PointF ToScreenSpace(Point3D p)
PointD Origin
A property of the class PointD. *‍/.
Definition ImageView.cs:743
PointF[] ToScreenSpace(PointD[] p)
List< ROI > AnnotationsB
ViewMode Mode
Setting the view mode of the application. *‍/.
Definition ImageView.cs:635
void DrawView(System.Drawing.Graphics g)
Draws the viewport when Hardware Acceleration is off.
List< ROI > AnnotationsRGB
int TimeFps
Setting the interval of the timer to the value of the timefps variable. *‍/.
Definition ImageView.cs:874
SKRect ToSKRect(double x, double y, double w, double h)
double ToViewH(double d)
Channel BChannel
Getting the B channel of the image. *‍/.
Definition ImageView.cs:711
static bool Ctrl
Definition ImageView.cs:340
static MouseButtons mouseUpButtons
Definition ImageView.cs:348
ImageView()
Initializing the ImageView class. *‍/.
Definition ImageView.cs:114
static bool showText
Definition ImageView.cs:352
RectangleD ToScreenSpace(RectangleF p)
void RemoveImage(int i)
float ToScreenScaleH(double y)
void GoToImage(int i)
async void UpdateImages(bool updatePyramidal=true)
double PxHmicron
Only used when opening stacks.
Definition ImageView.cs:614
static PointD mouseUp
Definition ImageView.cs:337
PointD ToViewSpace(double x, double y)
int SelectedIndex
A property that is used to set the selected index of the image. *‍/.
Definition ImageView.cs:406
float ToScreenW(double x)
PointD ImageToViewSpace(double x, double y)
static MouseButtons mouseDownButtons
Definition ImageView.cs:349
static Stage Stage
static void Render(object o, PaintEventArgs e)
Definition Plugin.cs:100
static void KeyPressEvent(object o, KeyPressEventArgs e)
Definition Plugin.cs:79
static void KeyDownEvent(object o, KeyEventArgs e)
Definition Plugin.cs:72
static void KeyUpEvent(object o, KeyEventArgs e)
Definition Plugin.cs:65
void SetPosition(double px, double py)
Definition Microscope.cs:50
void UpdateViewMode(ImageView.ViewMode v)
Definition TabsView.cs:650
void ToolDown(PointD e, MouseButtons buts)
Definition Tools.cs:241
void ToolUp(PointD e, MouseButtons buts)
Definition Tools.cs:382
void ToolMove(PointD e, MouseButtons buts)
Definition Tools.cs:535
static bool GetKeyState(System.Windows.Forms.Keys vKey)
Definition Win32.cs:20
Layer(double d, bool enabled)
Definition ImageView.cs:283