BioImager  5.0.0
A .NET microscopy imaging application based on Bio library. Supports various microscopes by using imported libraries & GUI automation. Supports XInput game controllers to move stage, take images, run ImageJ macros on images or Bio C# scripts.
Loading...
Searching...
No Matches
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 Bitmap = AForge.Bitmap;
16using Image = System.Drawing.Image;
17using Keys = System.Windows.Forms.Keys;
18using PointF = AForge.PointF;
19using Rectangle = AForge.Rectangle;
20using RectangleD = AForge.RectangleD;
21using RectangleF = AForge.RectangleF;
22using SizeF = AForge.SizeF;
23
24namespace BioImager
25{
26
30 public partial class ImageView : UserControl, IDisposable
31 {
32 GLWindow window;
33 SlideGLArea gl = new SlideGLArea();
34 SlideRenderer slideRenderer;
36 public ImageView(BioImage im, bool OpenWithOpenSlide = true)
37 {
38 string file = im.ID.Replace("\\", "/");
39 InitializeComponent();
40 bool useGpuTiles = im.Resolutions.Count > 1;
41 BioLib.SlideSourceBase.UseGPU = useGpuTiles;
42 OpenSlideGTK.SlideSourceBase.useGPU = useGpuTiles;
43 viewpanel.Paint += Viewpanel_Paint;
44 AttachViewerInput(viewpanel);
45
46 if (im.isPyramidal)
47 {
48 gl.Size = new System.Drawing.Size(800, 600);
49 if (im.openSlideImage != null && OpenWithOpenSlide)
50 {
51 Initialize(im.file, im);
52 }
53 else
54 Initialize(im.file, im);
55 hScrollBar.Visible = true;
56 vScrollBar.Visible = true;
57 }
58 else
59 {
60 hScrollBar.Visible = false;
61 vScrollBar.Visible = false;
62 Tools.selectBoxSize = GetSelectBoxSize();
63 }
64 App.viewer = this;
65 serie = im.series;
66 gl.Dock = DockStyle.Fill;
67 viewpanel.Controls.Add(gl);
68 AttachViewerInput(gl);
69 InitializeOverview();
70 Dock = DockStyle.Fill;
71 AddImage(im);
72 UpdateRenderSurfaceMode();
73 App.viewer = this;
74 if (file == "" || file == null)
75 return;
76 InitGUI();
77 MouseWheel += new System.Windows.Forms.MouseEventHandler(ImageView_MouseWheel);
78 zBar.MouseWheel += new System.Windows.Forms.MouseEventHandler(ZTrackBar_MouseWheel);
79 cBar.MouseWheel += new System.Windows.Forms.MouseEventHandler(CTrackBar_MouseWheel);
80 tBar.MouseWheel += new System.Windows.Forms.MouseEventHandler(TimeTrackBar_MouseWheel);
81 //We set the trackbar event to handled so that it only scrolls one tick not the default multiple.
82 zBar.MouseWheel += (sender, e) => ((HandledMouseEventArgs)e).Handled = true;
83 tBar.MouseWheel += (sender, e) => ((HandledMouseEventArgs)e).Handled = true;
84 cBar.MouseWheel += (sender, e) => ((HandledMouseEventArgs)e).Handled = true;
85 this.SizeChanged += ImageView_SizeChanged;
86 this.KeyDown += ImageView_KeyDown;
87 this.KeyPress += ImageView_KeyPress;
88 this.KeyUp += ImageView_KeyUp;
89 TimeFps = 60;
90 ZFps = 60;
91 CFps = 1;
92 resolutions = im.Resolutions;
93 if (im.isPyramidal)
94 {
95 // Keep the renderer bound to the currently selected pyramidal source.
96 if (im.OpenSlideBase != null)
97 {
98 if (slideRenderer == null)
99 slideRenderer = new SlideRenderer(gl);
100 if (!slideRenderer.IsSource(im.OpenSlideBase))
101 slideRenderer.SetSource(im.OpenSlideBase);
102 }
103 else if (im.SlideBase != null)
104 {
105 if (slideRenderer == null)
106 slideRenderer = new SlideRenderer(gl);
107 if (!slideRenderer.IsSource(im.SlideBase))
108 slideRenderer.SetSource(im.SlideBase);
109 }
110 }
111 InitGL();
112 update = true;
113 InitPreview();
114 GoToImage();
115 UpdateImages();
116 Mode = ViewMode.Filtered;
117 UpdateView();
118
119 }
121 public ImageView()
122 {
123 InitializeComponent();
124 viewpanel.Paint += Viewpanel_Paint;
125 AttachViewerInput(viewpanel);
126 InitGL();
127 AttachViewerInput(gl);
128 InitializeOverview();
129 Dock = DockStyle.Fill;
130 App.viewer = this;
131 InitGUI();
132 //Buf = image.GetBufByCoord(GetCoordinate());
133 MouseWheel += new System.Windows.Forms.MouseEventHandler(ImageView_MouseWheel);
134 zBar.MouseWheel += new System.Windows.Forms.MouseEventHandler(ZTrackBar_MouseWheel);
135 cBar.MouseWheel += new System.Windows.Forms.MouseEventHandler(CTrackBar_MouseWheel);
136 tBar.MouseWheel += new System.Windows.Forms.MouseEventHandler(TimeTrackBar_MouseWheel);
137 this.SizeChanged += ImageView_SizeChanged;
138 //We set the trackbar event to handled so that it only scrolls one tick not the default multiple.
139 zBar.MouseWheel += (sender, e) => ((HandledMouseEventArgs)e).Handled = true;
140 tBar.MouseWheel += (sender, e) => ((HandledMouseEventArgs)e).Handled = true;
141 cBar.MouseWheel += (sender, e) => ((HandledMouseEventArgs)e).Handled = true;
142 TimeFps = 60;
143 ZFps = 60;
144 CFps = 1;
145 update = true;
146 UpdateImages();
147 GoToImage();
148 UpdateView();
149 }
150 protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
151 {
152 const int WM_KEYDOWN = 0x0100;
153 const int WM_KEYUP = 0x0101;
154 const int WM_CHAR = 0x0102;
155
156 switch (msg.Msg)
157 {
158 case WM_KEYDOWN:
159 ImageView_KeyDown(this, new KeyEventArgs(keyData));
160 break;
161
162 case WM_KEYUP:
163 ImageView_KeyUp(this, new KeyEventArgs(keyData));
164 break;
165
166 case WM_CHAR:
167 char ch = (char)msg.WParam;
168 ImageView_KeyPress(this, new System.Windows.Forms.KeyPressEventArgs(ch));
169 break;
170 }
171
172 return base.ProcessCmdKey(ref msg, keyData);
173 }
174
175 private void ImageView_SizeChanged(object? sender, EventArgs e)
176 {
177 if (SelectedImage != null)
178 if (UsesSlideRenderer(SelectedImage))
179 SelectedImage.PyramidalSize = new AForge.Size(gl.Width, gl.Height);
180 if (centerOnNextResize && SelectedImage != null && ViewWidth > 1 && ViewHeight > 1)
181 {
182 centerOnNextResize = false;
184 }
185 UpdateOverviewVisibility();
186 }
187
188 private void InitGL()
189 {
190 var gameWindowSettings = new GameWindowSettings()
191 {
192 UpdateFrequency = 60,
193 };
194 NativeWindowSettings nativeSettings;
195
196 nativeSettings = new NativeWindowSettings()
197 {
198 ClientSize = new Vector2i(600, 400),
199 Location = new Vector2i(0, 0),
200 Title = "OpenGL Context",
201 StartVisible = false, // Window starts hidden
202 API = ContextAPI.OpenGL,
203 Profile = ContextProfile.Core,
204 APIVersion = new Version(3, 3)
205 };
206 window = new GLWindow(gameWindowSettings, nativeSettings);
207 GLFWProvider.SetErrorCallback((error, description) =>
208 {
209 Console.WriteLine($"BioImager GLFW Error {error}: {description}");
210 });
211 }
212
213 private void BringRenderSurfacesToFront()
214 {
215 if (gl.Parent == viewpanel)
216 gl.BringToFront();
217 if (overviewPanel != null && overviewPanel.Parent == viewpanel)
218 overviewPanel.BringToFront();
219 }
220
221 private void AttachViewerInput(Control surface)
222 {
223 surface.MouseDown += pictureBox_MouseDown;
224 surface.MouseMove += rgbPictureBox_MouseMove;
225 surface.MouseUp += pictureBox_MouseUp;
226 surface.MouseDoubleClick += pictureBox_MouseDoubleClick;
227 surface.MouseWheel += ImageView_MouseWheel;
228 surface.MouseEnter += (sender, e) => surface.Focus();
229 }
230
231 ~ImageView()
232 {
233
234 }
235 public struct Layer
236 {
237 public double Resolution
238 {
239 get; set;
240 }
241 public bool Enabled { get; set; }
242 public Layer(double d)
243 {
244 Enabled = true;
245 Resolution = d;
246 }
247 public Layer(double d, bool enabled)
248 {
249 Enabled = enabled;
250 Resolution = d;
251 }
252 }
253
254 public List<Layer> Layers = new List<Layer>();
255 private Layers layersTool = new Layers();
256 private bool IsLayerEnabled(double d)
257 {
258 foreach (Layer item in Layers)
259 {
260 if (d == item.Resolution && item.Enabled)
261 return true;
262 }
263 return false;
264 }
265 List<System.Drawing.Bitmap> Bitmaps = new List<System.Drawing.Bitmap>();
266 List<Resolution> resolutions = new List<Resolution>();
267 public static List<ROI> selectedAnnotations = new List<ROI>();
268 private static int selectedIndex = 0;
270 {
271 get
272 {
273 if (App.viewer != null)
274 {
275 if (App.viewer.Images.Count > 0)
276 return App.viewer.Images[selectedIndex];
277 else
278 return null;
279 }
280 else
281 return null;
282 }
283 set
284 {
285 if (App.viewer != null)
286 {
287 if (App.viewer.Images.Count > 0)
288 App.viewer.Images[selectedIndex] = value;
289 else
290 App.viewer.AddImage(value);
291 }
292 }
293 }
294 public static Bitmap SelectedBuffer
295 {
296 get
297 {
298 int ind = SelectedImage.Coords[SelectedImage.Coordinate.Z, SelectedImage.Coordinate.C, SelectedImage.Coordinate.T];
299 return SelectedImage.Buffers[ind];
300 }
301 }
302 public static PointD mouseDown;
303 public static bool down;
304 public static PointD mouseUp;
305 public static bool up;
306 public static bool Ctrl
307 {
308 get
309 {
310 return Win32.GetKeyState(Keys.LControlKey);
311 }
312 }
313 private bool x1State = false;
314 private bool x2State = false;
315 public static MouseButtons mouseUpButtons;
316 public static MouseButtons mouseDownButtons;
317 private PointD pd;
318 public static bool showBounds = true;
319 public static bool showText = true;
320 public Image Buf = null;
321 public bool init = false;
322 private bool update = false;
323 public List<BioImage> Images = new List<BioImage>();
324 private bool centerOnNextResize;
329 private void Render(System.Drawing.Graphics canvas)
330 {
331 try
332 {
333 DrawOverlay(canvas);
334 System.Drawing.Rectangle rf = new System.Drawing.Rectangle((int)canvas.Clip.GetBounds(canvas).X, (int)canvas.Clip.GetBounds(canvas).Y,
335 (int)canvas.Clip.GetBounds(canvas).Width, (int)canvas.Clip.GetBounds(canvas).Height);
336 // Plugin rendering hook
337 Plugins.Render(this, new PaintEventArgs(canvas, rf));
338 }
339 catch (Exception ex)
340 {
341 Console.WriteLine($"Annotation render error: {ex.Message}");
342 }
343 }
344
345 private void RefreshPyramidalOverlayTexture()
346 {
347 if (SelectedImage == null || !SelectedImage.isPyramidal || gl == null)
348 return;
349 if (gl.Width <= 0 || gl.Height <= 0)
350 return;
351
352 using System.Drawing.Bitmap overlay = new System.Drawing.Bitmap(gl.Width, gl.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
353 using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(overlay))
354 {
355 g.Clear(System.Drawing.Color.Transparent);
356 Render(g);
357 }
358
359 gl.SetOverlayBitmap(overlay);
360 }
361
362 private void BindSlideRendererSource(BioImage image)
363 {
364 if (image == null || !UsesSlideRenderer(image))
365 return;
366
367 if (slideRenderer == null)
368 slideRenderer = new SlideRenderer(gl);
369
370 if (image.OpenSlideBase != null)
371 {
372 if (!slideRenderer.IsSource(image.OpenSlideBase))
373 slideRenderer.SetSource(image.OpenSlideBase);
374 }
375 else if (image.SlideBase != null)
376 {
377 if (!slideRenderer.IsSource(image.SlideBase))
378 slideRenderer.SetSource(image.SlideBase);
379 }
380 }
381
382 private static bool UsesSlideRenderer(BioImage image)
383 {
384 return image != null && (image.isPyramidal || image.SlideBase != null || image.OpenSlideBase != null);
385 }
386
388 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
389 public int SelectedIndex
390 {
391 get;
392 set
393 {
394 if (value >= 0 && value < Images.Count)
395 {
396 App.viewer = this;
397 field = value;
398 selectedIndex = field;
399 InitGUI();
400 if (UsesSlideRenderer(Images[field]))
401 BindSlideRendererSource(Images[field]);
402 }
403 }
404 } = 0;
405 public Tools tools { get { return App.tools; } }
406 public string filepath = "";
407 public int serie = 0;
408 public int minSizeX = 50;
409 public int minSizeY = 20;
410 public bool loopZ = true;
411 public bool loopT = true;
412 public bool loopC = true;
413 private AForge.Rectangle overview;
415 {
416 get { return overview; }
417 }
418 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
419 public bool ShowStage { get; set; }
420 private double pxWmicron = 0.004;
421 private double pxHmicron = 0.004;
422 AForge.SizeF scale = new AForge.SizeF(1, 1);
430 private bool initializingCoordinates;
431 public void SetCoordinate(int z, int c, int t)
432 {
433 if (IsDisposed)
434 return;
435
436 if (InvokeRequired)
437 {
438 BeginInvoke(new MethodInvoker(() => SetCoordinate(z, c, t)));
439 return;
440 }
441
442 if (SelectedImage == null)
443 return;
444
445 int targetZ = Math.Clamp(z, zBar.Minimum, zBar.Maximum);
446 int targetC = Math.Clamp(c, cBar.Minimum, cBar.Maximum);
447 int targetT = Math.Clamp(t, tBar.Minimum, tBar.Maximum);
448
449 initializingCoordinates = true;
450 if (zBar.Value != targetZ)
451 zBar.Value = targetZ;
452 if (cBar.Value != targetC)
453 cBar.Value = targetC;
454 if (tBar.Value != targetT)
455 tBar.Value = targetT;
456 initializingCoordinates = false;
457 SelectedImage.Coordinate = new ZCT(targetZ, targetC, targetT);
458 UpdateView();
459 }
464 {
465 if (SelectedImage != null)
466 return SelectedImage.Coordinate;
467 else
468 return new ZCT();
469 }
475 public void AddImage(BioImage im)
476 {
477 ZCT initialCoordinate = new ZCT(im.Coordinate.Z, im.Coordinate.C, im.Coordinate.T);
478 Images.Add(im);
479 SelectedIndex = Images.Count - 1;
480 centerOnNextResize = true;
481 bool c = false;
482 foreach (var item in Layers)
483 {
484 if (item.Resolution == im.PhysicalSizeX)
485 c = true;
486 }
487 if (!c)
488 Layers.Add(new Layer(im.PhysicalSizeX));
489 if (im.isPyramidal)
490 {
491 hScrollBar.Visible = true;
492 vScrollBar.Visible = true;
493 }
494 else
495 {
496 hScrollBar.Visible = false;
497 vScrollBar.Visible = false;
498 Tools.selectBoxSize = GetSelectBoxSize();
499 }
500 InitGUI();
501 SetCoordinate(initialCoordinate.Z, initialCoordinate.C, initialCoordinate.T);
502 UpdateImages();
503
504 GoToImage(Images.Count - 1);
505 QueueInitialCenterAfterLayout(Images.Count - 1);
506 }
507
508 private void QueueInitialCenterAfterLayout(int imageIndex)
509 {
510 if (!IsHandleCreated)
511 return;
512 BeginInvoke(new System.Action(() =>
513 {
514 if (IsDisposed || !centerOnNextResize || imageIndex >= Images.Count)
515 return;
516 centerOnNextResize = false;
517 GoToImage(imageIndex);
518 }));
519 }
523
524 private static int GetPreviewLevel(BioImage image)
525 {
526 if (image == null || image.Resolutions.Count == 0)
527 return 0;
528
529 int nativeLevelCount = image.PyramidNativeLevelCount > 0
530 ? Math.Min(image.PyramidNativeLevelCount, image.Resolutions.Count)
531 : image.Resolutions.Count;
532 return Math.Max(0, nativeLevelCount - 1);
533 }
535 private bool showControls = true;
537 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
538 public bool ShowControls
539 {
540 get => showControls;
541 set
542 {
543 showControls = value;
544 trackBarPanel.Visible = value;
545 hideControlsToolStripMenuItem1.Text = value ? "Hide Controls" : "Show Controls";
546 showControlsToolStripMenuItem.Text = value ? "Hide Controls" : "Show Controls";
547 PerformLayout();
548 UpdateView();
549 }
550 }
552 private bool showStatus = true;
554 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
555 public bool ShowStatus
556 {
557 get => showStatus;
558 set
559 {
560 showStatus = value;
561 statusPanel.Visible = value;
562 hideControlsToolStripMenuItem.Text = value ? "Hide Status" : "Show Status";
563 PerformLayout();
564 UpdateView();
565 }
566 }
570
571 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
572 public double PxWmicron
573 {
574 get
575 {
576 return pxWmicron;
577 }
578 set
579 {
580 pxWmicron = value;
581 }
582 }
586 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
587 public double PxHmicron
588 {
589 get
590 {
591 return pxHmicron;
592 }
593 set
594 {
595 pxHmicron = value;
596 }
597 }
598 public enum ViewMode
599 {
600 Raw,
601 Filtered,
602 RGBImage,
603 Emission,
604 }
605 private ViewMode viewMode = ViewMode.Filtered;
607 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
609 {
610 get
611 {
612 return viewMode;
613 }
614 set
615 {
616 viewMode = value;
617 //If view mode is changed we update.
618 update = true;
619 UpdateImages();
620 App.tabsView.UpdateViewMode(viewMode);
621 UpdateView();
623 if (viewMode == ViewMode.RGBImage)
624 {
625 cBar.Value = 0;
626 rgbBoxsPanel.BringToFront();
627 cBar.SendToBack();
628 cLabel.SendToBack();
629 BringRenderSurfacesToFront();
630 }
631 else
632 if (viewMode == ViewMode.Filtered)
633 {
634 rgbBoxsPanel.SendToBack();
635 cBar.BringToFront();
636 cLabel.BringToFront();
637 BringRenderSurfacesToFront();
638 }
639 else
640 if (viewMode == ViewMode.Raw)
641 {
642 rgbBoxsPanel.SendToBack();
643 cBar.BringToFront();
644 cLabel.BringToFront();
645 BringRenderSurfacesToFront();
646 }
647 else
648 {
649 cBar.Value = 0;
650 rgbBoxsPanel.BringToFront();
651 cBar.SendToBack();
652 cLabel.SendToBack();
653 BringRenderSurfacesToFront();
654 }
655 }
656 }
658 public string Path
659 {
660 get
661 {
662 return filepath;
663 }
664 }
666 public Channel RChannel
667 {
668 get
669 {
670 return SelectedImage.Channels[SelectedImage.rgbChannels[0]];
671 }
672 }
674 public Channel GChannel
675 {
676 get
677 {
678 return SelectedImage.Channels[SelectedImage.rgbChannels[1]];
679 }
680 }
682 public Channel BChannel
683 {
684 get
685 {
686 return SelectedImage.Channels[SelectedImage.rgbChannels[2]];
687 }
688 }
689 PointD origin = new PointD(0, 0);
690 bool hardwareAcceleration = true;
691 public bool OpenSlide
692 {
693 get { if (SelectedImage.SlideBase == null) return true; else return false; }
694 }
695 public int? MacroResolution { get { return SelectedImage.MacroResolution; } }
696 public int? LabelResolution { get { return SelectedImage.LabelResolution; } }
697 public int ViewWidth
698 {
699 get
700 {
701 if (SelectedImage != null && !SelectedImage.isPyramidal && viewpanel != null && viewpanel.ClientSize.Width > 1)
702 return viewpanel.ClientSize.Width;
703 return gl.Width;
704 }
705 }
706 public int ViewHeight
707 {
708 get
709 {
710 if (SelectedImage != null && !SelectedImage.isPyramidal && viewpanel != null && viewpanel.ClientSize.Height > 1)
711 return viewpanel.ClientSize.Height;
712 return gl.Height;
713 }
714 }
716 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
718 {
719 get { return origin; }
720 set
721 {
722 origin = value;
723 update = true;
724 UpdateView();
725 }
726 }
728 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
730 {
731 get
732 {
733 if (SelectedImage != null)
734 return SelectedImage.PyramidalOrigin;
735 else
736 return new PointD(0, 0);
737 }
738 set
739 {
740 SelectedImage.PyramidalOrigin = value;
741 }
742 }
744 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
745 public double Resolution
746 {
747 get
748 {
749 if (SelectedImage == null)
750 return 1;
751 return SelectedImage.Resolution;
752 }
753 set
754 {
755 SelectedImage.Resolution = value;
756 if (SelectedImage.Type == BioImage.ImageType.well)
757 SelectedImage.Level = (int)value;
758 }
759 }
760
764 public int Level
765 {
766 get
767 {
768 if (SelectedImage != null)
769 return SelectedImage.Level;
770 else
771 return 0;
772 }
773 }
777 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
778 public new AForge.SizeF Scale
779 {
780 get
781 {
782 return scale;
783 }
784 set
785 {
786 scale = value;
787 update = true;
788 UpdateView();
789 Tools.selectBoxSize = GetSelectBoxSize();
790 }
791 }
793 public ContextMenuStrip ViewContextMenu
794 {
795 get
796 {
797 return contextMenuStrip;
798 }
799 }
804 private readonly bool[] rgbEnabled = { true, true, true };
805 private bool initializingRgbSelectors;
806 private BioImage rgbSelectorImage;
807
808 private int[] SelectedRgbChannels(BioImage image) => Enumerable.Range(0, 3)
809 .Select(i => rgbEnabled[i] ? image.rgbChannels[i] : -1).ToArray();
810
811 public void UpdateRGBChannels()
812 {
813 if (SelectedImage == null) return;
814 System.Windows.Forms.ComboBox[] boxes = { channelBoxR, channelBoxG, channelBoxB };
815 for (int i = 0; i < boxes.Length; i++)
816 {
817 rgbEnabled[i] = boxes[i].SelectedIndex > 0;
818 if (rgbEnabled[i]) SelectedImage.rgbChannels[i] = boxes[i].SelectedIndex - 1;
819 }
820 }
821
822 private bool timeEnabled = false;
823 private int zfps;
825 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
826 public int ZFps
827 {
828 get
829 {
830 return zfps;
831 }
832 set
833 {
834 zfps = value;
835 float f = value;
836 zTimer.Interval = (int)Math.Floor(1000 / f);
837 }
838 }
839 private int timefps;
841 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
842 public int TimeFps
843 {
844 get
845 {
846 return timefps;
847 }
848 set
849 {
850 timefps = value;
851 float f = value;
852 timelineTimer.Interval = (int)Math.Floor(1000 / f);
853 }
854 }
855 private int cfps;
857 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
858 public int CFps
859 {
860 get
861 {
862 return cfps;
863 }
864 set
865 {
866 cfps = value;
867 float f = value;
868 cTimer.Interval = (int)Math.Floor(1000 / f);
869 }
870 }
874 public void InitGUI()
875 {
876 if (SelectedImage == null)
877 return;
878 ZCT coordinate = new ZCT(SelectedImage.Coordinate.Z, SelectedImage.Coordinate.C, SelectedImage.Coordinate.T);
879 initializingCoordinates = true;
880 ZarrChannelView.InitializeChannels(SelectedImage);
881 zBar.Maximum = Math.Max(0, SelectedImage.SizeZ - 1);
882 if (!SelectedImage.IsZarrSource && SelectedImage.Buffers.Count > 0 && SelectedImage.Buffers[0].RGBChannelsCount == 3)
883 cBar.Maximum = 0;
884 else
885 cBar.Maximum = Math.Max(0, SelectedImage.SizeC - 1);
886 if (SelectedImage.SizeT > 1)
887 {
888 tBar.Maximum = Math.Max(0, SelectedImage.SizeT - 1);
889 tBar.Enabled = true;
890 timeEnabled = true;
891 }
892 else
893 {
894 tBar.Enabled = false;
895 timeEnabled = false;
896 tBar.Maximum = Math.Max(0, SelectedImage.SizeT - 1);
897 }
898 //rgbPictureBox.Image = image.plane.GetBitmap();
899 //we clear the channel comboboxes incase we have channels from previous loaded image.
900 bool sameImage = ReferenceEquals(rgbSelectorImage, SelectedImage);
901 rgbSelectorImage = SelectedImage;
902 bool[] previousEnabled = (bool[])rgbEnabled.Clone();
903 int[] previousChannels = (int[])SelectedImage.rgbChannels.Clone();
904 initializingRgbSelectors = true;
905 channelBoxR.Items.Clear();
906 channelBoxG.Items.Clear();
907 channelBoxB.Items.Clear();
908
909 channelBoxR.Items.Add("");
910 channelBoxG.Items.Add("");
911 channelBoxB.Items.Add("");
912 foreach (Channel ch in SelectedImage.Channels)
913 {
914 channelBoxR.Items.Add(ch);
915 channelBoxG.Items.Add(ch);
916 channelBoxB.Items.Add(ch);
917 }
918 System.Windows.Forms.ComboBox[] rgbBoxes = { channelBoxR, channelBoxG, channelBoxB };
919 int count = SelectedImage.Channels.Count;
920 for (int i = 0; i < rgbBoxes.Length; i++)
921 rgbBoxes[i].SelectedIndex = count == 0 || (sameImage && !previousEnabled[i]) ? 0 :
922 (sameImage ? Math.Clamp(previousChannels[i], 0, count - 1) : (i < count ? i : 0)) + 1;
923 initializingRgbSelectors = false;
924 zBar.Value = Math.Clamp(coordinate.Z, zBar.Minimum, zBar.Maximum);
925 cBar.Value = Math.Clamp(coordinate.C, cBar.Minimum, cBar.Maximum);
926 tBar.Value = Math.Clamp(coordinate.T, tBar.Minimum, tBar.Maximum);
927 SelectedImage.Coordinate = new ZCT(zBar.Value, cBar.Value, tBar.Value);
928 initializingCoordinates = false;
930
931 init = true;
932 }
937 public void UpdateSelectBoxSize(float size)
938 {
939 ROI.selectBoxSize = size;
940 UpdateToolSelectBoxSize();
941 }
942
943 private const float MinSelectBoxScreenSize = 8f;
944 private const float MinSelectionHitScreenSize = 8f;
945
946 private float GetSelectBoxSize()
947 {
948 return GetSelectBoxSizeForScreenPixels(MinSelectBoxScreenSize);
949 }
950
951 private float GetSelectBoxSizeForScreenPixels(float minScreenSize)
952 {
953 if (SelectedImage != null && SelectedImage.isPyramidal)
954 {
955 float logicalSize = Math.Max(ROI.selectBoxSize, minScreenSize);
956 double resolution = Resolution;
957 if (resolution <= 0 || double.IsNaN(resolution) || double.IsInfinity(resolution))
958 resolution = 1;
959 return (float)(logicalSize * resolution);
960 }
961
962 float zoom = Math.Abs(Scale.Width);
963 if (zoom <= 0 || float.IsNaN(zoom) || float.IsInfinity(zoom))
964 zoom = 1f;
965
966 double pixelSize = Math.Min(PxWmicron, PxHmicron);
967 if (pixelSize <= 0 || double.IsNaN(pixelSize) || double.IsInfinity(pixelSize))
968 pixelSize = 1;
969
970 float screenSize = Math.Max(ROI.selectBoxSize, minScreenSize);
971 return (float)(screenSize / (zoom * pixelSize));
972 }
973
974 private void UpdateToolSelectBoxSize()
975 {
976 Tools.selectBoxSize = GetSelectBoxSize();
977 }
982 public void UpdateOverlay()
983 {
984 UpdateToolSelectBoxSize();
985 if (SelectedImage != null && UsesSlideRenderer(SelectedImage))
986 {
987 RefreshPyramidalOverlayTexture();
988 gl.Invalidate();
989 overviewPanel.Invalidate();
990 }
991 else
992 viewpanel.Invalidate();
993 }
997 public void UpdateStatus()
998 {
999 BioImage image = OverviewSelectedImage;
1000 if (image == null)
1001 return;
1002 string res = image.Type == BioImage.ImageType.well
1003 ? $"Well:{image.Level}"
1004 : image.isPyramidal ? $"Res.:{image.Resolution:G4} Level:{image.Level}" : "";
1005 string pixelFormat = image.Buffers.Count > 0
1006 ? image.Buffers[0].PixelFormat.ToString()
1007 : image.Resolutions.Count > 0
1008 ? image.Resolutions[Math.Clamp(image.Level, 0, image.Resolutions.Count - 1)].PixelFormat.ToString()
1009 : "";
1010 string position = image.isPyramidal
1011 ? $"({image.PyramidalOrigin.X:0.##}, {image.PyramidalOrigin.Y:0.##})"
1012 : $"({-Origin.X:0.##}, {-Origin.Y:0.##})";
1013 string location = $"({image.Volume.Location.X:0.##}, {image.Volume.Location.Y:0.##})";
1014 string plane = $"{zBar.Value + 1}/{zBar.Maximum + 1}";
1015 if (Mode != ViewMode.RGBImage)
1016 plane += $", {cBar.Value + 1}/{cBar.Maximum + 1}";
1017 if (timeEnabled)
1018 plane += $", {tBar.Value + 1}/{tBar.Maximum + 1}";
1019 statusLabel.Text = $"{plane}, {mousePoint}{mouseColor}, {pixelFormat}, Origin: {position}, {location} {res}";
1020 }
1025 public void UpdateView(bool refreshImages = true)
1026 {
1027 UpdateStatus();
1028 update = true;
1029 UpdateToolSelectBoxSize();
1030 if (refreshImages)
1031 UpdateImages();
1032 UpdateRenderSurfaceMode();
1033 UpdateScrollBars();
1034 overviewPanel.Invalidate();
1035 if (SelectedImage != null && UsesSlideRenderer(SelectedImage))
1036 {
1037 RefreshPyramidalOverlayTexture();
1038 gl.Invalidate();
1039 overviewPanel.Invalidate();
1040 }
1041 else
1042 viewpanel.Invalidate();
1043 }
1047 /*
1048 public void RenderFrame()
1049 {
1050 if (!update)
1051 return;
1052 drawing = true;
1053 if (dBitmaps.Count != Images.Count)
1054 UpdateImages();
1055 if (HardwareAcceleration && sk != null)
1056 {
1057 Plugins.Render(this, sk);
1058 sk.BeginDraw();
1059 sk.RenderTarget2D.Clear(new RawColor4(1.0f, 1.0f, 1.0f, 1.0f));
1060 RectangleF rg = ToScreenRect(PointD.MinX, PointD.MinY, PointD.MaxX - PointD.MinX, PointD.MaxY - PointD.MinY);
1061 //dx.RenderTarget2D.Transform = SharpDX.Matrix3x2.Rotation((float)Math.PI);
1062 SharpDX.Direct2D1.SolidColorBrush pen = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(1.0f, 0.0f, 0.0f, 1.0f));
1063 SharpDX.Direct2D1.SolidColorBrush red = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(1.0f, 0.0f, 0.0f, 1.0f));
1064 SharpDX.Direct2D1.SolidColorBrush green = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(0.0f, 1.0f, 0.0f, 1.0f));
1065 SharpDX.Direct2D1.SolidColorBrush mag = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(1.0f, 0.0f, 1.0f, 1.0f));
1066 SharpDX.Direct2D1.SolidColorBrush blue = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(0.0f, 0.0f, 1.0f, 1.0f));
1067 SharpDX.Direct2D1.SolidColorBrush b = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(1.0f, 1.0f, 0.0f, 1.0f));
1068 SharpDX.Direct2D1.SolidColorBrush gray = new SharpDX.Direct2D1.SolidColorBrush(sk.RenderTarget2D, new RawColor4(0.5f, 0.5f, 0.5f, 1.0f));
1069
1070 sk.RenderTarget2D.FillRectangle(ToSKRect(rg.X, rg.Y, rg.Width, rg.Height), gray);
1071 for (int x = 0; x < Images.Count; x++)
1072 {
1073 if (!IsLayerEnabled(Images[x].PhysicalSizeX) && !Images[x].isPyramidal)
1074 continue;
1075 RectangleF r = ToScreenRect(Images[x].Volume.Location.X, Images[x].Volume.Location.Y, Images[x].Volume.Width, Images[x].Volume.Height);
1076 double w = ToViewW(ViewWidth);
1077 double h = ToViewH(ViewHeight);
1078 RectangleF rge = new RectangleF((float)((-Origin.X) - (w / 2)), (float)((-Origin.Y) - (h / 2)), (float)(Math.Abs(w)), (float)(Math.Abs(h)));
1079 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);
1080 //if (rge.IntersectsWith(rec))
1081 sk.RenderTarget2D.DrawBitmap(dBitmaps[x], ToSKRect(r.X, r.Y, r.Width, r.Height), 1.0f, SharpDX.Direct2D1.BitmapInterpolationMode.Linear);
1082 if (x == selectedIndex)
1083 sk.RenderTarget2D.DrawRectangle(ToSKRect(r.X, r.Y, r.Width, r.Height), blue);
1084 }
1085 bool bounds = showBounds;
1086 bool labels = showText;
1087 foreach (BioImage bi in Images)
1088 {
1089 if (!IsLayerEnabled(bi.PhysicalSizeX) && !bi.isPyramidal)
1090 continue;
1091 foreach (ROI an in bi.Annotations)
1092 {
1093 if (an.type == ROI.Type.Polygon || an.type == ROI.Type.Freeform || an.type == ROI.Type.Polyline)
1094 {
1095 if (zBar.Value != an.coord.Z || tBar.Value != an.coord.T)
1096 continue;
1097 }
1098 else if (zBar.Value != an.coord.Z || cBar.Value != an.coord.C || tBar.Value != an.coord.T)
1099 continue;
1100 float w = Math.Abs(Scale.Width);
1101 Font fo = new Font(new FontFamily(an.family), (float)((an.strokeWidth / w) * an.fontSize));
1102 PointF pc = new PointF((float)(an.BoundingBox.X + (an.BoundingBox.W / 2)), (float)(an.BoundingBox.Y + (an.BoundingBox.H / 2)));
1103 float width = (float)an.strokeWidth / w;
1104 if (width <= 0)
1105 width = 1;
1106 sk.RenderTarget2D.StrokeWidth = width;
1107 if (an.Selected)
1108 b.Color = new RawColor4(1.0f, 0.0f, 1.0f, 1.0f);
1109 else
1110 b.Color = new RawColor4((float)an.strokeColor.R / 255f, (float)an.strokeColor.G / 255f, (float)an.strokeColor.B / 255f, 1.0f);
1111 if (an.type == ROI.Type.Point)
1112 {
1113 PointD pf = ToScreenSpace(an.Points[0]);
1114 SharpDX.Direct2D1.Ellipse dot = new SharpDX.Direct2D1.Ellipse(new RawVector2((float)pf.X, (float)pf.Y), 2f, 2f);
1115 sk.RenderTarget2D.FillEllipse(dot, b);
1116 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1117 for (int i = 0; i < rfs.Length; i++)
1118 {
1119 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1120 }
1121 }
1122 else
1123 if (an.type == ROI.Type.Line)
1124 {
1125 PointD pf = ToScreenSpace(an.GetPoint(0));
1126 PointD pf2 = ToScreenSpace(an.GetPoint(1));
1127 sk.RenderTarget2D.DrawLine(new RawVector2((float)pf.X, (float)pf.Y), new RawVector2((float)pf2.X, (float)pf2.Y), b);
1128 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1129 for (int i = 0; i < rfs.Length; i++)
1130 {
1131 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1132 }
1133 }
1134 else
1135 if (an.type == ROI.Type.Rectangle && an.BoundingBox.W > 0 && an.BoundingBox.H > 0)
1136 {
1137 RectangleF rec = ToScreenSpace(an.BoundingBox);
1138 sk.RenderTarget2D.DrawRectangle(ToSKRect(rec.X, rec.Y, rec.Width, rec.Height), red);
1139 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1140 for (int i = 0; i < rfs.Length; i++)
1141 {
1142 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1143 }
1144 }
1145 else
1146 if (an.type == ROI.Type.Ellipse)
1147 {
1148 RectangleF r = ToScreenSpace(an.BoundingBox);
1149 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1150 RawRectangleF rf = ToSKRect(rfs[0].X, rfs[0].Y, rfs[0].Width, rfs[0].Height);
1151 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);
1152 sk.RenderTarget2D.DrawEllipse(e, b);
1153 for (int i = 0; i < rfs.Length; i++)
1154 {
1155 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1156 }
1157 }
1158 else
1159 if (an.type == ROI.Type.Polygon && an.closed)
1160 {
1161 RawVector2 pf;
1162 RawVector2 pf2;
1163 for (int i = 0; i < an.Points.Count - 1; i++)
1164 {
1165 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);
1166 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);
1167 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1168 }
1169 pf = new RawVector2((float)ToScreenSpace(an.GetPoint(0)).X, (float)ToScreenSpace(an.GetPoint(0)).Y);
1170 pf2 = new RawVector2((float)ToScreenSpace(an.GetPoint(an.Points.Count - 1)).X, (float)ToScreenSpace(an.GetPoint(an.Points.Count - 1)).Y);
1171 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1172
1173 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1174 for (int i = 0; i < rfs.Length; i++)
1175 {
1176 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1177 }
1178 }
1179 else
1180 if ((an.type == ROI.Type.Polygon && !an.closed) || an.type == ROI.Type.Polyline)
1181 {
1182 RawVector2 pf;
1183 RawVector2 pf2;
1184 for (int i = 0; i < an.Points.Count - 1; i++)
1185 {
1186 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);
1187 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);
1188 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1189 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1190 }
1191
1192 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1193 for (int i = 0; i < rfs.Length; i++)
1194 {
1195 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1196 }
1197
1198 }
1199 else
1200 if (an.type == ROI.Type.Freeform && an.closed)
1201 {
1202 RawVector2 pf;
1203 RawVector2 pf2;
1204 for (int i = 0; i < an.Points.Count - 1; i++)
1205 {
1206 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);
1207 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);
1208 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1209 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1210 }
1211 pf = new RawVector2((float)ToScreenSpace(an.GetPoint(0)).X, (float)ToScreenSpace(an.GetPoint(0)).Y);
1212 pf2 = new RawVector2((float)ToScreenSpace(an.GetPoint(an.Points.Count - 1)).X, (float)ToScreenSpace(an.GetPoint(an.Points.Count - 1)).Y);
1213 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1214 if (an.Selected)
1215 {
1216 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1217 for (int i = 0; i < rfs.Length; i++)
1218 {
1219 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1220 }
1221 }
1222 }
1223 else
1224 if (an.type == ROI.Type.Freeform && !an.closed)
1225 {
1226 RawVector2 pf;
1227 RawVector2 pf2;
1228 for (int i = 0; i < an.Points.Count - 1; i++)
1229 {
1230 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);
1231 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);
1232 sk.RenderTarget2D.DrawLine(pf, pf2, b);
1233 }
1234 if (an.Selected)
1235 {
1236 RectangleF[] rfs = ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize));
1237 for (int i = 0; i < rfs.Length; i++)
1238 {
1239 sk.RenderTarget2D.DrawRectangle(ToSKRect(rfs[i].X, rfs[i].Y, rfs[i].Width, rfs[i].Height), red);
1240 }
1241 }
1242 }
1243 if (an.type == ROI.Type.Label)
1244 {
1245 using Font labelFont = GetScaledLabelFont(an, (float)w);
1246 System.Drawing.Size textSize = System.Windows.Forms.TextRenderer.MeasureText(an.Text ?? string.Empty, labelFont);
1247 System.Drawing.RectangleF rec = GetLabelScreenRect(an);
1248 float tx = rec.X + ((rec.Width - textSize.Width) / 2f);
1249 float ty = rec.Y + ((rec.Height - textSize.Height) / 2f);
1250 RawRectangleF r = ToSKRect(tx, ty, textSize.Width, textSize.Height);
1251 SharpDX.DirectWrite.TextFormat tex = new SharpDX.DirectWrite.TextFormat(sk.FactoryDWrite, an.family.ToString(), an.fontSize);
1252 sk.RenderTarget2D.DrawText(an.Text ?? string.Empty, tex, r, b);
1253 tex.Dispose();
1254 sk.RenderTarget2D.DrawRectangle(ToSKRect(rec.X, rec.Y, rec.Width, rec.Height), red);
1255 }
1256 if (labels)
1257 {
1258 if (an.Text != null && an.type != ROI.Type.Label)
1259 {
1260 System.Drawing.Size s = TextRenderer.MeasureText(an.Text, new Font(an.family, an.fontSize));
1261 //Lets draw the text of this ROI in the middle of the ROI.
1262 float fw = ((float)an.BoundingBox.X + ((float)an.BoundingBox.W / 2)) - ((float)s.Width / 2);
1263 float fh = ((float)an.BoundingBox.Y + ((float)an.BoundingBox.H / 2)) - ((float)s.Height / 2);
1264 RawRectangleF r = ToSKRect(fw, fh, s.Width, s.Height);
1265 SharpDX.DirectWrite.TextFormat tex = new SharpDX.DirectWrite.TextFormat(sk.FactoryDWrite, an.family.ToString(), an.fontSize);
1266 sk.RenderTarget2D.DrawText(an.Text, tex, r, b);
1267 tex.Dispose();
1268 }
1269 }
1270 if (bounds)
1271 {
1272 if (an.type == ROI.Type.Point)
1273 {
1274 PointD pt = ToScreenSpace(an.Points[0]);
1275 SharpDX.Direct2D1.Ellipse dot = new SharpDX.Direct2D1.Ellipse(new RawVector2((float)pt.X, (float)pt.Y), 2f, 2f);
1276 sk.RenderTarget2D.FillEllipse(dot, green);
1277 }
1278 else if (an.type == ROI.Type.Label)
1279 {
1280 System.Drawing.RectangleF rec = GetLabelScreenRect(an);
1281 sk.RenderTarget2D.DrawRectangle(ToSKRect(rec.X, rec.Y, rec.Width, rec.Height), green);
1282 }
1283 else
1284 {
1285 RectangleF r = ToScreenSpace(an.BoundingBox);
1286 sk.RenderTarget2D.DrawRectangle(ToSKRect(r.X, r.Y, r.Width, r.Height), green);
1287 }
1288 }
1289 if (an.Selected)
1290 {
1291 if (an.type == ROI.Type.Point)
1292 {
1293 PointD pt = ToScreenSpace(an.Points[0]);
1294 SharpDX.Direct2D1.Ellipse dot = new SharpDX.Direct2D1.Ellipse(new RawVector2((float)pt.X, (float)pt.Y), 2f, 2f);
1295 sk.RenderTarget2D.FillEllipse(dot, mag);
1296 continue;
1297 }
1298 else if (an.type == ROI.Type.Label)
1299 {
1300 System.Drawing.RectangleF rec = GetLabelScreenRect(an);
1301 sk.RenderTarget2D.DrawRectangle(ToSKRect(rec.X, rec.Y, rec.Width, rec.Height), mag);
1302 continue;
1303 }
1304
1305 //Lets draw the selected bounding box.
1306 RectangleF r = ToScreenSpace(an.BoundingBox);
1307 sk.RenderTarget2D.DrawRectangle(ToSKRect(r.X, r.Y, r.Width, r.Height), mag);
1308
1309 //Lets draw the selectBoxes.
1310 List<RectangleD> rects = new List<RectangleD>();
1311 RectangleD[] sels = an.GetSelectBoxes(Tools.selectBoxSize);
1312 for (int i = 0; i < an.selectedPoints.Count; i++)
1313 {
1314 if (an.selectedPoints[i] < an.GetPointCount())
1315 {
1316 rects.Add(sels[an.selectedPoints[i]]);
1317 }
1318 }
1319 if (rects.Count > 0)
1320 {
1321 for (int i = 0; i < rects.Count; i++)
1322 {
1323 RectangleF ri = ToScreenSpace(rects[i]);
1324 sk.RenderTarget2D.DrawRectangle(ToSKRect(ri.X, ri.Y, ri.Width, ri.Height), blue);
1325 }
1326 }
1327 rects.Clear();
1328 }
1329
1330 }
1331 }
1332 if (ShowStage)
1333 {
1334 AForge.RectangleD re = Microscope.GetViewRectangle(false);
1335 RectangleF vr = ToScreenRect(re.X, re.Y, re.W, re.H);
1336 RawRectangleF rr = ToSKRect(vr.X, vr.Y, vr.Width, vr.Height);
1337 sk.RenderTarget2D.DrawRectangle(rr, red);
1338 }
1339
1340 if(Tools.currentTool!=null)
1341 if (Tools.currentTool.type == Tools.Tool.Type.rectSel || Tools.currentTool.type == Tools.Tool.Type.rect)// && Modifiers == ModifierType.Button1Mask)
1342 {
1343 var recd = ToScreenRect(Tools.currentTool.Rectangle.X, Tools.currentTool.Rectangle.Y, Tools.currentTool.Rectangle.W, Tools.currentTool.Rectangle.H);
1344 sk.RenderTarget2D.DrawRectangle(ToSKRect((float)recd.X, (float)recd.Y, (float)recd.Width, (float)recd.Height), blue);
1345 }
1346 pen.Dispose();
1347 red.Dispose();
1348 mag.Dispose();
1349 green.Dispose();
1350 blue.Dispose();
1351 gray.Dispose();
1352 b.Dispose();
1353 sk.EndDraw();
1354 }
1355 drawing = false;
1356 }
1357 */
1361 public void UpdateViewLegacy(bool refresh)
1362 {
1363 UpdateStatus();
1364 update = refresh;
1365 if (update)
1366 {
1367 gl.Invalidate();
1368 overviewPanel.Invalidate();
1369 }
1370 }
1371 bool updating = false;
1376 private int zarrRgbRequest;
1377 public async void UpdateImages(bool updatePyramidal = true)
1378 {
1379 if (SelectedImage == null)
1380 return;
1382 UpdateRenderSurfaceMode();
1383 if (UsesSlideRenderer(SelectedImage))
1384 {
1385 InitPreview();
1386 if (!updatePyramidal || gl.Width <= 1 || gl.Height <= 1)
1387 return;
1388 SelectedImage.PyramidalOrigin = PyramidalOrigin;
1389 SelectedImage.PyramidalSize = new AForge.Size(gl.Width, gl.Height);
1390
1391 // Use the new renderer - no more ReadPixels!
1392 BindSlideRendererSource(SelectedImage);
1393 try
1394 {
1395 BioImage? directZarr = null;
1396 int[]? directZarrChannels = null;
1397 if (SelectedImage.IsZarrSource)
1398 {
1399 if (Mode == ViewMode.RGBImage)
1400 {
1401 directZarr = SelectedImage;
1402 directZarrChannels = SelectedRgbChannels(SelectedImage);
1403 }
1404 else if (Mode == ViewMode.Filtered)
1405 {
1406 // Use the same direct, coordinate-aware Zarr reader as
1407 // RGB mode. Repeating the selected channel produces the
1408 // expected grayscale Filtered view and avoids the legacy
1409 // buffered plane path that could remain stuck on Z=0.
1410 int channel = Math.Clamp(GetCoordinate().C, 0,
1411 Math.Max(0, SelectedImage.SizeC - 1));
1412 directZarr = SelectedImage;
1413 directZarrChannels = new[] { channel, channel, channel };
1414 }
1415 }
1416
1417 await slideRenderer.UpdateViewAsync(
1419 gl.Width,
1420 gl.Height,
1421 Resolution,
1422 GetCoordinate(),
1423 directZarr,
1424 Mode == ViewMode.RGBImage ? SelectedRgbChannels(SelectedImage) : directZarrChannels
1425 );
1426 }
1427 catch (Exception ex)
1428 {
1429 System.Diagnostics.Trace.WriteLine($"Could not update slide view: {ex}");
1430 }
1431 RefreshPyramidalOverlayTexture();
1432 UpdateScrollBars();
1433 // Pyramidal images are drawn from tiles, not the full-plane buffers below.
1434 return;
1435 }
1436
1437 if (SelectedImage.IsZarrSource &&
1438 (Mode == ViewMode.RGBImage || Mode == ViewMode.Filtered) &&
1439 Images.Count == 1 && SelectedImage.levels?.Count > 0)
1440 {
1441 var image = SelectedImage;
1442 var requestedMode = Mode;
1443 int request = ++zarrRgbRequest;
1444 int width = image.Buffers[0].SizeX, height = image.Buffers[0].SizeY;
1445 try
1446 {
1447 int[] channels;
1448 if (requestedMode == ViewMode.RGBImage)
1449 {
1450 channels = SelectedRgbChannels(image);
1451 }
1452 else
1453 {
1454 int channel = Math.Clamp(GetCoordinate().C, 0,
1455 Math.Max(0, image.SizeC - 1));
1456 channels = new[] { channel, channel, channel };
1457 }
1458
1459 byte[] rgba = await ZarrChannelView.ReadRgbTileAsync(image, 0, 0, 0, width, height,
1460 GetCoordinate(), channels);
1461 if (request != zarrRgbRequest || SelectedImage != image || Mode != requestedMode)
1462 return;
1463 var frame = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
1464 var data = frame.LockBits(new System.Drawing.Rectangle(0, 0, width, height),
1465 System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
1466 try
1467 {
1468 for (int i = 0; i < rgba.Length; i += 4)
1469 (rgba[i], rgba[i + 2]) = (rgba[i + 2], rgba[i]);
1470 for (int row = 0; row < height; row++)
1471 Marshal.Copy(rgba, row * width * 4, IntPtr.Add(data.Scan0, row * data.Stride), width * 4);
1472 }
1473 finally { frame.UnlockBits(data); }
1474 foreach (var old in Bitmaps) old?.Dispose();
1475 Bitmaps.Clear();
1476 Bitmaps.Add(frame);
1477 update = true;
1478 UpdateRegularOverview();
1479 InvalidateView();
1480 }
1481 catch (Exception ex)
1482 {
1483 System.Diagnostics.Trace.WriteLine($"Could not render Zarr RGB channels: {ex.Message}");
1484 }
1485 return;
1486 }
1487
1488 // AForge's filters copy from unmanaged pixel pointers. Missing or disposed
1489 // buffers have a null pointer, so keep the last frame until pixels are available.
1490 foreach (BioImage image in Images)
1491 {
1492 int index = image.GetFrameIndex(zBar.Value, cBar.Value, tBar.Value);
1493 bool unavailable = index < 0 || index >= image.Buffers.Count;
1494 if (!unavailable)
1495 {
1496 var buffers = Mode == ViewMode.Filtered || Mode == ViewMode.Raw
1497 ? new[] { image.Buffers[index] }
1498 : image.Buffers.AsEnumerable();
1499 unavailable = buffers.Any(buffer =>
1500 buffer == null || buffer.Bytes == null || buffer.Bytes.Length == 0);
1501 }
1502 if (unavailable)
1503 {
1504 System.Diagnostics.Trace.WriteLine($"Image pixels are unavailable: {image.ID}");
1505 return;
1506 }
1507 }
1508 for (int i = 0; i < Bitmaps.Count; i++)
1509 {
1510 Bitmaps[i].Dispose();
1511 Bitmaps[i] = null;
1512 }
1513 Bitmaps.Clear();
1514 if (zBar.Maximum != SelectedImage.SizeZ - 1 || tBar.Maximum != SelectedImage.SizeT - 1)
1515 {
1516 InitGUI();
1517 }
1518
1519 int bi = 0;
1520 foreach (BioImage b in Images)
1521 {
1522 if (b.isPyramidal)
1523 b.PyramidalOrigin = PyramidalOrigin;
1524 b.PyramidalSize = new AForge.Size(gl.Width, gl.Height);
1525 ZCT coords = new ZCT(zBar.Value, cBar.Value, tBar.Value);
1526 Bitmap bitmap = null;
1527
1528 int index = b.Coords[zBar.Value, cBar.Value, tBar.Value];
1529 if (Mode == ViewMode.Filtered)
1530 {
1531 bitmap = b.GetFiltered(coords, b.RChannel.RangeR, b.GChannel.RangeG, b.BChannel.RangeB);
1532 }
1533 else if (Mode == ViewMode.RGBImage)
1534 {
1535 if (b.Buffers[0].RGBChannelsCount == 1)
1536 {
1537 var planes = new Bitmap[3];
1538 for (int color = 0; color < 3; color++)
1539 {
1540 int channel = Math.Clamp(b.rgbChannels[color], 0, b.SizeC - 1);
1541 planes[2 - color] = b.Buffers[b.GetFrameIndex(coords.Z, channel, coords.T)];
1542 }
1543 bitmap = Bitmap.GetRGBBitmap(planes, b.RChannel.RangeR, b.GChannel.RangeG, b.BChannel.RangeB);
1544 }
1545 else
1546 bitmap = b.GetRGBBitmap(coords, b.RChannel.RangeR, b.GChannel.RangeG, b.BChannel.RangeB);
1547 }
1548 else if (Mode == ViewMode.Raw)
1549 {
1550 bitmap = (Bitmap)b.Buffers[index].GetImageRGBA();
1551 }
1552 else
1553 {
1554 bitmap = b.GetEmission(coords, b.RChannel.RangeR, b.GChannel.RangeG, b.BChannel.RangeB);
1555 }
1556 var display = ToSysBitmap(bitmap);
1557 if (Mode == ViewMode.RGBImage)
1558 MaskRgbComponents(display, rgbEnabled);
1559 Bitmaps.Add(display);
1560 bi++;
1561 }
1562 UpdateRegularOverview();
1563 update = true;
1564 InvalidateView();
1565 }
1566
1567 private void UpdateRenderSurfaceMode()
1568 {
1569 if (SelectedImage == null)
1570 {
1571 hScrollBar.Visible = false;
1572 vScrollBar.Visible = false;
1573 PerformLayout();
1574 if (overviewPanel != null)
1575 overviewPanel.Visible = false;
1576 return;
1577 }
1578
1579 if (UsesSlideRenderer(SelectedImage))
1580 {
1581 if (gl.Parent != viewpanel)
1582 viewpanel.Controls.Add(gl);
1583 if (!gl.Visible)
1584 gl.Visible = true;
1585 BringRenderSurfacesToFront();
1586 }
1587 else
1588 {
1589 if (gl.Visible)
1590 gl.Visible = false;
1591 if (gl.Parent == viewpanel)
1592 viewpanel.Controls.Remove(gl);
1593 gl.ClearOverlayBitmap();
1594 }
1595 hScrollBar.Visible = UsesSlideRenderer(SelectedImage);
1596 vScrollBar.Visible = UsesSlideRenderer(SelectedImage);
1597 PerformLayout();
1598 UpdateOverviewVisibility();
1599 }
1600 bool drawing = false;
1601 public void RemoveImage(int i)
1602 {
1603 do
1604 {
1605 System.Threading.Thread.Sleep(50);
1606 Application.DoEvents();
1607 } while (drawing || updating);
1608 Images[i].Dispose();
1609 Images.RemoveAt(i);
1610 UpdateImages();
1611 }
1612 public void RemoveImages()
1613 {
1614 do
1615 {
1616 Thread.Sleep(50);
1617 Application.DoEvents();
1618 } while (drawing || updating);
1619 for (int i = 0; i < Images.Count; i++)
1620 {
1621 Images[i].Dispose();
1622 }
1623 Images.Clear();
1624 UpdateImages();
1625 }
1626 Bitmap bitmap;
1630 public void UpdateImage()
1631 {
1632 UpdateImages();
1633 }
1641 private void channelBoxR_SelectedIndexChanged(object sender, EventArgs e)
1642 {
1643 if (initializingRgbSelectors || SelectedImage == null || channelBoxR.SelectedIndex == -1)
1644 return;
1645 rgbEnabled[0] = channelBoxR.SelectedIndex > 0;
1646 if (rgbEnabled[0]) SelectedImage.rgbChannels[0] = channelBoxR.SelectedIndex - 1;
1647 update = true;
1648 UpdateView();
1649 }
1657 private void channelBoxG_SelectedIndexChanged(object sender, EventArgs e)
1658 {
1659 if (initializingRgbSelectors || SelectedImage == null || channelBoxG.SelectedIndex == -1)
1660 return;
1661 rgbEnabled[1] = channelBoxG.SelectedIndex > 0;
1662 if (rgbEnabled[1]) SelectedImage.rgbChannels[1] = channelBoxG.SelectedIndex - 1;
1663 update = true;
1664 UpdateView();
1665 }
1673 private void channelBoxB_SelectedIndexChanged(object sender, EventArgs e)
1674 {
1675 if (initializingRgbSelectors || SelectedImage == null || channelBoxB.SelectedIndex == -1)
1676 return;
1677 rgbEnabled[2] = channelBoxB.SelectedIndex > 0;
1678 if (rgbEnabled[2]) SelectedImage.rgbChannels[2] = channelBoxB.SelectedIndex - 1;
1679 update = true;
1680 UpdateView();
1681 }
1689 private void showControlsToolStripMenuItem_Click(object sender, EventArgs e)
1690 {
1692 }
1697 private void playZToolStripMenuItem_Click(object sender, EventArgs e)
1698 {
1699 if (playZToolStripMenuItem.Checked)
1700 {
1701 //We stop
1702 playZToolStripMenuItem.Checked = false;
1703 stopZToolStripMenuItem.Checked = true;
1704 zTimer.Stop();
1705 }
1706 else
1707 {
1708 //We start
1709 playZToolStripMenuItem.Checked = true;
1710 stopZToolStripMenuItem.Checked = false;
1711 zTimer.Start();
1712 }
1713 }
1718 private void stopZToolStripMenuItem_Click(object sender, EventArgs e)
1719 {
1720 if (stopZToolStripMenuItem.Checked)
1721 {
1722 //We start
1723 playZToolStripMenuItem.Checked = true;
1724 stopZToolStripMenuItem.Checked = false;
1725 zTimer.Start();
1726
1727 }
1728 else
1729 {
1730 //We stop
1731 playZToolStripMenuItem.Checked = false;
1732 stopZToolStripMenuItem.Checked = true;
1733 zTimer.Stop();
1734 }
1735 }
1740 private void playTimeToolStripMenu_Click(object sender, EventArgs e)
1741 {
1742 if (playTimeToolStripMenu.Checked)
1743 {
1744 //We stop
1745 playTimeToolStripMenu.Checked = false;
1746 stopTimeToolStripMenu.Checked = true;
1747 timelineTimer.Stop();
1748 }
1749 else
1750 {
1751 //We start
1752 playTimeToolStripMenu.Checked = true;
1753 stopTimeToolStripMenu.Checked = false;
1754 timelineTimer.Start();
1755 }
1756 }
1762 private void stopTimeToolStripMenu_Click(object sender, EventArgs e)
1763 {
1764 playTimeToolStripMenu.Checked = false;
1765 stopTimeToolStripMenu.Checked = true;
1766 timelineTimer.Stop();
1767 }
1772 private void playCToolStripMenuItem_Click(object sender, EventArgs e)
1773 {
1774 if (playCToolStripMenuItem.Checked)
1775 {
1776 //We stop
1777 playCToolStripMenuItem.Checked = false;
1778 stopCToolStripMenuItem.Checked = true;
1779 cTimer.Stop();
1780 }
1781 else
1782 {
1783 //We start
1784 playCToolStripMenuItem.Checked = true;
1785 stopCToolStripMenuItem.Checked = false;
1786 cTimer.Start();
1787 }
1788 }
1794 private void stopCToolStripMenuItem_Click(object sender, EventArgs e)
1795 {
1796 stopCToolStripMenuItem.Checked = false;
1797 playCToolStripMenuItem.Checked = true;
1798 cTimer.Stop();
1799 }
1800 private string mousePoint = "";
1801 private string mouseColor = "";
1808 private void playSpeedToolStripMenuItem_Click(object sender, EventArgs e)
1809 {
1810 PlaySpeed sp = null;
1811 if (Mode == ViewMode.RGBImage)
1812 sp = new PlaySpeed(timeEnabled, false, ZFps, TimeFps, CFps);
1813 else
1814 sp = new PlaySpeed(timeEnabled, true, ZFps, TimeFps, CFps);
1815 if (sp.ShowDialog() != DialogResult.OK)
1816 return;
1817 zTimer.Interval = sp.TimePlayspeed;
1818 cTimer.Interval = sp.CPlayspeed;
1819 timelineTimer.Interval = sp.TimePlayspeed;
1820 }
1827 private void playSpeedToolStripMenuItem1_Click(object sender, EventArgs e)
1828 {
1829 PlaySpeed sp = null;
1830 if (Mode == ViewMode.RGBImage)
1831 sp = new PlaySpeed(timeEnabled, false, ZFps, TimeFps, CFps);
1832 else
1833 sp = new PlaySpeed(timeEnabled, true, ZFps, TimeFps, CFps);
1834 if (sp.ShowDialog() != DialogResult.OK)
1835 return;
1836 zTimer.Interval = sp.TimePlayspeed;
1837 cTimer.Interval = sp.CPlayspeed;
1838 timelineTimer.Interval = sp.TimePlayspeed;
1839 }
1847 private void CPlaySpeedToolStripMenuItem_Click(object sender, EventArgs e)
1848 {
1849 PlaySpeed sp = null;
1850 if (Mode == ViewMode.RGBImage)
1851 sp = new PlaySpeed(timeEnabled, false, ZFps, TimeFps, CFps);
1852 else
1853 sp = new PlaySpeed(timeEnabled, true, ZFps, TimeFps, CFps);
1854 if (sp.ShowDialog() != DialogResult.OK)
1855 return;
1856 zTimer.Interval = sp.TimePlayspeed;
1857 cTimer.Interval = sp.CPlayspeed;
1858 timelineTimer.Interval = sp.TimePlayspeed;
1859 }
1879 public void GetRange()
1880 {
1881 RangeTool t;
1882 if (Mode == ViewMode.Filtered)
1883 t = new RangeTool(timeEnabled, true, zBar.Minimum, zBar.Maximum, tBar.Minimum, tBar.Maximum, cBar.Minimum, cBar.Maximum);
1884 else
1885 t = new RangeTool(timeEnabled, false, zBar.Minimum, zBar.Maximum, tBar.Minimum, tBar.Maximum, cBar.Minimum, cBar.Maximum);
1886 if (t.ShowDialog() != DialogResult.OK)
1887 return;
1888 zBar.Minimum = t.ZMin;
1889 zBar.Maximum = t.ZMax;
1890 tBar.Minimum = t.TimeMin;
1891 tBar.Maximum = t.TimeMax;
1892 cBar.Minimum = t.CMin;
1893 cBar.Maximum = t.CMax;
1894 }
1895 private void setValueRangeToolStripMenuItem_Click(object sender, EventArgs e)
1896 {
1897 GetRange();
1898 }
1899 private void setValueRangeToolStripMenuItem1_Click(object sender, EventArgs e)
1900 {
1901 GetRange();
1902 }
1903 private void setCValueRangeToolStripMenuItem_Click(object sender, EventArgs e)
1904 {
1905 GetRange();
1906 }
1911 private void ImageView_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
1912 {
1913 if (e is HandledMouseEventArgs handled && handled.Handled)
1914 return;
1915 var source = sender as System.Windows.Forms.Control ?? this;
1916 System.Drawing.Point cursor = source.Parent == viewpanel
1917 ? new System.Drawing.Point(source.Left + e.X, source.Top + e.Y)
1918 : viewpanel.PointToClient(source.PointToScreen(e.Location));
1919 if (e.Delta == 0 || !viewpanel.ClientRectangle.Contains(cursor) || Images.Count == 0)
1920 return;
1921
1922 App.viewer = this;
1923 Plugins.ScrollEvent(sender, e);
1924 if (e is HandledMouseEventArgs wheel)
1925 {
1926 if (wheel.Handled)
1927 return;
1928 // Prevent a canvas event from bubbling up and zooming a second time.
1929 wheel.Handled = true;
1930 }
1931
1932 const double minZoom = 0.000001;
1933 const double maxZoom = 1000000;
1934 double factor = Math.Pow(1.2, e.Delta / 120.0);
1935 PointD anchor = ImageToViewSpace(cursor.X, cursor.Y);
1936 if (SelectedImage.isPyramidal)
1937 {
1938 // Resolution is world units per screen pixel, so zooming in reduces it.
1939 Resolution = Math.Clamp(Resolution / factor, minZoom, maxZoom);
1940 PyramidalOrigin = new PointD(anchor.X - cursor.X * Resolution,
1941 anchor.Y - cursor.Y * Resolution);
1942 Tools.selectBoxSize = (float)(ROI.selectBoxSize * Resolution);
1943 UpdateImages();
1944 }
1945 else
1946 {
1947 // Clamp the common factor to preserve the X/Y scale ratio.
1948 factor = Math.Clamp(factor,
1949 minZoom / Math.Min(Scale.Width, Scale.Height),
1950 maxZoom / Math.Max(Scale.Width, Scale.Height));
1951 Scale = new SizeF((float)(Scale.Width * factor), (float)(Scale.Height * factor));
1952 PointD shifted = ImageToViewSpace(cursor.X, cursor.Y);
1953 Origin = new PointD(Origin.X + shifted.X - anchor.X, Origin.Y + shifted.Y - anchor.Y);
1954 }
1955 UpdateView();
1956 }
1957
1958 private void ZoomPyramidalAt(System.Drawing.Point mouseLocation, double zoomFactor)
1959 {
1960 if (SelectedImage == null || !SelectedImage.isPyramidal)
1961 return;
1962
1963 double oldResolution = Resolution;
1964 double oldOriginX = PyramidalOrigin.X;
1965 double oldOriginY = PyramidalOrigin.Y;
1966 double newResolution = oldResolution * zoomFactor;
1967 if (newResolution <= 0 || Math.Abs(newResolution - oldResolution) < double.Epsilon)
1968 return;
1969
1970 // PyramidalOrigin is stored in world units. Convert the cursor anchor
1971 // into the same space before changing resolution.
1972 double worldX = oldOriginX + (mouseLocation.X * oldResolution);
1973 double worldY = oldOriginY + (mouseLocation.Y * oldResolution);
1974
1975 SelectedImage.Resolution = newResolution;
1976
1977 var schema = SelectedImage.OpenSlideBase != null
1978 ? (BruTile.ITileSchema)SelectedImage.OpenSlideBase.Schema
1979 : SelectedImage.SlideBase.Schema;
1980
1981 double newOriginX = worldX - (mouseLocation.X * Resolution);
1982 double newOriginY = worldY - (mouseLocation.Y * Resolution);
1983
1984 double maxX = schema != null ? schema.Extent.MaxX : newOriginX;
1985 double maxY = schema != null ? -schema.Extent.MinY : newOriginY;
1986
1987 PyramidalOrigin = new PointD(
1988 Math.Max(0, Math.Min(newOriginX, maxX)),
1989 Math.Max(0, Math.Min(newOriginY, maxY)));
1990
1991 UpdateView();
1992 }
1993
1999 private void ZTrackBar_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
2000 {
2001 if (e.Delta > 0)
2002 {
2003 if (zBar.Value + 1 <= zBar.Maximum)
2004 zBar.Value += 1;
2005 }
2006 else
2007 {
2008 if (zBar.Value - 1 >= zBar.Minimum)
2009 zBar.Value -= 1;
2010 }
2011
2012 }
2020 private void TimeTrackBar_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
2021 {
2022 if (!timeEnabled)
2023 return;
2024 if (e.Delta > 0)
2025 {
2026 if (tBar.Value + 1 <= tBar.Maximum)
2027 tBar.Value += 1;
2028 }
2029 else
2030 {
2031 if (tBar.Value - 1 >= tBar.Minimum)
2032 tBar.Value -= 1;
2033 }
2034 }
2040 private void CTrackBar_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
2041 {
2042 if (e.Delta > 0)
2043 {
2044 if (cBar.Value + 1 <= cBar.Maximum)
2045 cBar.Value += 1;
2046 }
2047 else
2048 {
2049 if (cBar.Value - 1 >= cBar.Minimum)
2050 cBar.Value -= 1;
2051 }
2052 }
2053
2060 private void cTimer_Tick(object sender, EventArgs e)
2061 {
2062 if (playCToolStripMenuItem.Checked)
2063 {
2064 if (cBar.Maximum >= cBar.Value + 1)
2065 cBar.Value++;
2066 else
2067 {
2068 if (loopC)
2069 cBar.Value = cBar.Minimum;
2070 }
2071 }
2072 }
2079 private void zTimer_Tick(object sender, EventArgs e)
2080 {
2081 if (playZToolStripMenuItem.Checked)
2082 {
2083 if (zBar.Maximum >= zBar.Value + 1)
2084 zBar.Value++;
2085 else
2086 {
2087 if (loopZ)
2088 zBar.Value = zBar.Minimum;
2089 }
2090 }
2091 }
2099 private void timer_Tick(object sender, EventArgs e)
2100 {
2101 if (playTimeToolStripMenu.Checked)
2102 {
2103 if (tBar.Maximum >= tBar.Value + 1)
2104 tBar.Value++;
2105 else
2106 {
2107 if (loopT)
2108 tBar.Value = tBar.Minimum;
2109 }
2110 }
2111 }
2119 private void zBar_ValueChanged(object sender, EventArgs e)
2120 {
2121 if (initializingCoordinates || SelectedImage == null)
2122 return;
2123 SelectedImage.Coordinate = new ZCT(zBar.Value, SelectedImage.Coordinate.C, SelectedImage.Coordinate.T);
2124 update = true;
2125 UpdateView();
2126 }
2133 private void timeBar_ValueChanged(object sender, EventArgs e)
2134 {
2135 if (initializingCoordinates || SelectedImage == null)
2136 return;
2137 SelectedImage.Coordinate = new ZCT(SelectedImage.Coordinate.Z, SelectedImage.Coordinate.C, tBar.Value);
2138 update = true;
2139 UpdateView();
2140 }
2148 private void cBar_ValueChanged(object sender, EventArgs e)
2149 {
2150 if (initializingCoordinates || SelectedImage == null)
2151 return;
2152 SelectedImage.Coordinate = new ZCT(SelectedImage.Coordinate.Z, cBar.Value, SelectedImage.Coordinate.T);
2153 update = true;
2154 UpdateView();
2155 }
2156
2157 private void loopTimeToolStripMenuItem_Click(object sender, EventArgs e)
2158 {
2159 loopT = loopTimeToolStripMenuItem.Checked;
2160 }
2161 private void loopZToolStripMenuItem_Click(object sender, EventArgs e)
2162 {
2163 loopZ = loopZToolStripMenuItem.Checked;
2164 }
2165 private void loopCToolStripMenuItem_Click(object sender, EventArgs e)
2166 {
2167 loopC = loopCToolStripMenuItem.Checked;
2168 }
2169
2170 public bool showRROIs = true;
2171 public bool showGROIs = true;
2172 public bool showBROIs = true;
2173
2174 private List<ROI> annotationsR = new List<ROI>();
2175 public List<ROI> AnnotationsR
2176 {
2177 get
2178 {
2179 if (SelectedImage == null)
2180 return new List<ROI>();
2181 return SelectedImage.Annotations.Where(an =>
2182 an != null &&
2183 an.coord.Z == SelectedImage.Coordinate.Z &&
2184 an.coord.T == SelectedImage.Coordinate.T &&
2185 (an.type == ROI.Type.Polygon || an.type == ROI.Type.Freeform || an.type == ROI.Type.Polyline || an.coord.C == RChannel.Index)).ToList();
2186 }
2187 }
2188 private List<ROI> annotationsG = new List<ROI>();
2189 public List<ROI> AnnotationsG
2190 {
2191 get
2192 {
2193 if (SelectedImage == null)
2194 return new List<ROI>();
2195 return SelectedImage.Annotations.Where(an =>
2196 an != null &&
2197 an.coord.Z == SelectedImage.Coordinate.Z &&
2198 an.coord.T == SelectedImage.Coordinate.T &&
2199 (an.type == ROI.Type.Polygon || an.type == ROI.Type.Freeform || an.type == ROI.Type.Polyline || an.coord.C == GChannel.Index)).ToList();
2200 }
2201 }
2202 private List<ROI> annotationsB = new List<ROI>();
2203 public List<ROI> AnnotationsB
2204 {
2205 get
2206 {
2207 if (SelectedImage == null)
2208 return new List<ROI>();
2209 return SelectedImage.Annotations.Where(an =>
2210 an != null &&
2211 an.coord.Z == SelectedImage.Coordinate.Z &&
2212 an.coord.T == SelectedImage.Coordinate.T &&
2213 (an.type == ROI.Type.Polygon || an.type == ROI.Type.Freeform || an.type == ROI.Type.Polyline || an.coord.C == BChannel.Index)).ToList();
2214 }
2215 }
2216 public List<ROI> AnnotationsRGB
2217 {
2218 get
2219 {
2220 if (SelectedImage == null)
2221 return null;
2222 List<ROI> ans = new List<ROI>();
2223 if (Mode == ViewMode.RGBImage)
2224 {
2225 if (showRROIs)
2226 ans.AddRange(AnnotationsR);
2227 if (showGROIs)
2228 ans.AddRange(AnnotationsG);
2229 if (showBROIs)
2230 ans.AddRange(AnnotationsB);
2231 }
2232 else
2233 {
2234 ans.AddRange(SelectedImage.Annotations.Where(an =>
2235 an != null &&
2236 an.coord.Z == SelectedImage.Coordinate.Z &&
2237 an.coord.T == SelectedImage.Coordinate.T &&
2238 (an.type == ROI.Type.Polygon || an.type == ROI.Type.Freeform || an.type == ROI.Type.Polyline || an.coord.C == SelectedImage.Coordinate.C)));
2239 }
2240 return ans;
2241 }
2242 }
2243 private System.Drawing.Point ToPoint(AForge.Point p)
2244 {
2245 return new System.Drawing.Point((int)p.X, (int)p.Y);
2246 }
2247 private System.Drawing.PointF ToPointF(PointD p)
2248 {
2249 return new System.Drawing.PointF((float)p.X, (float)p.Y);
2250 }
2256 private void DrawOverlay(System.Drawing.Graphics g)
2257 {
2258 if (SelectedImage == null)
2259 return;
2260 System.Drawing.Pen pen = null;
2261 System.Drawing.Pen red = null;
2262 System.Drawing.Pen green = null;
2263 System.Drawing.Pen mag = null;
2264 System.Drawing.Pen blue = null;
2265 Brush b = null;
2266 bool bounds = showBounds;
2267 bool labels = showText;
2268 ZCT cor = GetCoordinate();
2269 foreach (BioImage bi in Images)
2270 {
2271 if (!IsLayerEnabled(bi.PhysicalSizeX) && !bi.isPyramidal)
2272 continue;
2273 foreach (ROI an in bi.Annotations)
2274 {
2275 if (an.type == ROI.Type.Polygon || an.type == ROI.Type.Freeform || an.type == ROI.Type.Polyline)
2276 {
2277 if (zBar.Value != an.coord.Z || tBar.Value != an.coord.T)
2278 continue;
2279 }
2280 else if (Mode == ViewMode.RGBImage)
2281 {
2282 if (!showRROIs && an.coord.C == 0)
2283 continue;
2284 if (!showGROIs && an.coord.C == 1)
2285 continue;
2286 if (!showBROIs && an.coord.C == 2)
2287 continue;
2288 }
2289 else if (zBar.Value != an.coord.Z || cBar.Value != an.coord.C || tBar.Value != an.coord.T)
2290 continue;
2291 float w = Math.Abs(Scale.Width);
2292 pen = new System.Drawing.Pen(new SolidBrush(System.Drawing.Color.FromArgb(an.strokeColor.R, an.strokeColor.G, an.strokeColor.B)), (float)an.strokeWidth / w);
2293 red = new System.Drawing.Pen(Brushes.Red, (float)an.strokeWidth / w);
2294 mag = new System.Drawing.Pen(Brushes.Magenta, (float)an.strokeWidth / w);
2295 green = new System.Drawing.Pen(Brushes.Green, (float)an.strokeWidth / w);
2296 blue = new System.Drawing.Pen(Brushes.Blue, (float)an.strokeWidth / w);
2297 Font fo = new Font(an.family, (float)(an.strokeWidth / w) * an.fontSize);
2298 if (an.Selected)
2299 {
2300 b = new SolidBrush(System.Drawing.Color.Magenta);
2301 }
2302 else
2303 b = new SolidBrush(System.Drawing.Color.FromArgb(an.strokeColor.R, an.strokeColor.G, an.strokeColor.B));
2304 PointF pc = new PointF((float)(an.BoundingBox.X + (an.BoundingBox.W / 2)), (float)(an.BoundingBox.Y + (an.BoundingBox.H / 2)));
2305 float width = (float)ToViewSizeW(ROI.selectBoxSize / w);
2306 if (SelectedImage.isPyramidal)
2307 {
2308 width = (float)(ROI.selectBoxSize * Resolution);
2309 }
2310 if (an.type == ROI.Type.Point)
2311 {
2312 PointD pt = ToScreenSpace(an.Points[0]);
2313 g.FillEllipse(b, (float)pt.X - 2f, (float)pt.Y - 2f, 4f, 4f);
2314 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2315 {
2316 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2317 }
2318 }
2319 else
2320 if (an.type == ROI.Type.Line)
2321 {
2322 g.DrawLine(pen, ToPointF(ToScreenSpace(an.Points[0])), ToPointF(ToScreenSpace(an.GetPoint(1))));
2323 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2324 {
2325 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2326 }
2327 }
2328 else
2329 if (an.type == ROI.Type.Rectangle && an.BoundingBox.W > 0 && an.BoundingBox.H > 0)
2330 {
2331 RectangleD rec = ToScreenSpace(an.BoundingBox);
2332 g.DrawRectangle(pen, new System.Drawing.RectangleF((float)rec.X, (float)rec.Y, (float)rec.W, (float)rec.H));
2333 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2334 {
2335 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2336 }
2337 }
2338 else
2339 if (an.type == ROI.Type.Ellipse)
2340 {
2341 RectangleD rec = ToScreenSpace(an.BoundingBox);
2342 g.DrawEllipse(pen, (float)rec.X, (float)rec.Y, (float)rec.W, (float)rec.H);
2343 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2344 {
2345 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2346 }
2347 }
2348 else
2349 if (an.type == ROI.Type.Polygon && an.closed)
2350 {
2351 if (an.Points.Count > 1)
2352 {
2353 System.Drawing.PointF[] pts = new System.Drawing.PointF[an.Points.Count];
2354 for (int i = 0; i < an.Points.Count; i++)
2355 {
2356 var p = ToScreenSpace(an.Points[i].X, an.Points[i].Y);
2357 pts[i] = new System.Drawing.PointF((float)p.X, (float)p.Y);
2358 }
2359 g.DrawLines(pen, pts);
2360 g.DrawLine(pen, pts[pts.Length - 1], pts[0]);
2361 }
2362 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2363 {
2364 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2365 }
2366 }
2367 else
2368 if (an.type == ROI.Type.Polygon && !an.closed)
2369 {
2370 if (an.Points.Count > 1)
2371 {
2372 System.Drawing.PointF[] pts = new System.Drawing.PointF[an.Points.Count];
2373 for (int i = 0; i < an.Points.Count; i++)
2374 {
2375 var p = ToScreenSpace(an.Points[i].X, an.Points[i].Y);
2376 pts[i] = new System.Drawing.PointF((float)p.X, (float)p.Y);
2377 }
2378 g.DrawLines(pen, pts);
2379 }
2380 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2381 {
2382 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2383 }
2384 }
2385 else
2386 if (an.type == ROI.Type.Polyline)
2387 {
2388 if (an.Points.Count > 1)
2389 {
2390 System.Drawing.PointF[] pts = new System.Drawing.PointF[an.Points.Count];
2391 for (int i = 0; i < an.Points.Count; i++)
2392 {
2393 var p = ToScreenSpace(an.Points[i].X, an.Points[i].Y);
2394 pts[i] = new System.Drawing.PointF((float)p.X, (float)p.Y);
2395 }
2396 g.DrawLines(pen, pts);
2397 }
2398 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2399 {
2400 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2401 }
2402 }
2403
2404 else
2405 if (an.type == ROI.Type.Freeform && an.closed)
2406 {
2407 if (an.Points.Count > 1)
2408 {
2409 System.Drawing.PointF[] pts = new System.Drawing.PointF[an.Points.Count];
2410 for (int i = 0; i < an.Points.Count; i++)
2411 {
2412 var p = ToScreenSpace(an.Points[i].X, an.Points[i].Y);
2413 pts[i] = new System.Drawing.PointF((float)p.X, (float)p.Y);
2414 }
2415 g.DrawLines(pen, pts);
2416 g.DrawLine(pen, pts[pts.Length - 1], pts[0]);
2417 }
2418 if (an.Selected)
2419 {
2420 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2421 {
2422 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2423 }
2424 }
2425 }
2426 else
2427 if (an.type == ROI.Type.Freeform && !an.closed)
2428 {
2429 if (an.Points.Count > 1)
2430 {
2431 System.Drawing.PointF[] pts = new System.Drawing.PointF[an.Points.Count];
2432 for (int i = 0; i < an.Points.Count; i++)
2433 {
2434 var p = ToScreenSpace(an.Points[i].X, an.Points[i].Y);
2435 pts[i] = new System.Drawing.PointF((float)p.X, (float)p.Y);
2436 }
2437 g.DrawLines(pen, pts);
2438 }
2439 if (an.Selected)
2440 {
2441 foreach (var item in ToScreenSpace(an.GetSelectBoxes(Tools.selectBoxSize)))
2442 {
2443 g.DrawRectangle(red, new System.Drawing.RectangleF((float)item.X, (float)item.Y, (float)item.W, (float)item.H));
2444 }
2445 }
2446 }
2447 if (an.type == ROI.Type.Label)
2448 {
2449 System.Drawing.RectangleF rec = GetLabelScreenRect(an);
2450 using Font labelFont = GetScaledLabelFont(an, w);
2451 System.Drawing.Size textSize = System.Windows.Forms.TextRenderer.MeasureText(an.Text ?? string.Empty, labelFont);
2452 float tx = rec.X + ((rec.Width - textSize.Width) / 2f);
2453 float ty = rec.Y + ((rec.Height - textSize.Height) / 2f);
2454 g.DrawString(an.Text ?? string.Empty, labelFont, b, tx, ty);
2455 g.DrawRectangle(red, rec.X, rec.Y, rec.Width, rec.Height);
2456 }
2457 if (labels)
2458 {
2459 if (an.type == ROI.Type.Label)
2460 continue;
2461 System.Drawing.SizeF s = System.Windows.Forms.TextRenderer.MeasureText(an.Text, new Font(an.family, an.fontSize));
2462 //Lets draw the text of this ROI in the middle of the RO
2463 float fw = ((float)an.BoundingBox.X + ((float)an.BoundingBox.W / 2)) - ((float)s.Width / 2);
2464 float fh = ((float)an.BoundingBox.Y + ((float)an.BoundingBox.H / 2)) - ((float)s.Height / 2);
2465 var v = ToScreenSpace(new PointF(fw, fh));
2466 g.DrawString(an.Text, fo, b, v.X, v.Y);
2467 }
2468 if (bounds)
2469 {
2470 if (an.type == ROI.Type.Point)
2471 {
2472 var pv = ToScreenSpace(an.Points[0]);
2473 g.FillEllipse(Brushes.Green, (float)pv.X - 2f, (float)pv.Y - 2f, 4f, 4f);
2474 }
2475 else if (an.type == ROI.Type.Label)
2476 {
2477 System.Drawing.RectangleF rec = GetLabelScreenRect(an);
2478 g.DrawRectangle(green, rec.X, rec.Y, rec.Width, rec.Height);
2479 }
2480 else
2481 {
2482 var rb = ToScreenSpace(an.BoundingBox);
2483 g.DrawRectangles(green, new System.Drawing.RectangleF[1] { new System.Drawing.RectangleF((float)rb.X, (float)rb.Y, (float)rb.W, (float)rb.H) });
2484 }
2485 }
2486 if (an.Selected)
2487 {
2488 if (an.type == ROI.Type.Point)
2489 {
2490 var pv = ToScreenSpace(an.Points[0]);
2491 g.FillEllipse(Brushes.Magenta, (float)pv.X - 2f, (float)pv.Y - 2f, 4f, 4f);
2492 continue;
2493 }
2494 else if (an.type == ROI.Type.Label)
2495 {
2496 System.Drawing.RectangleF rec = GetLabelScreenRect(an);
2497 g.DrawRectangle(mag, rec.X, rec.Y, rec.Width, rec.Height);
2498 continue;
2499 }
2500
2501 //Lets draw the bounding box.
2502 var rb = ToScreenSpace(an.BoundingBox);
2503 g.DrawRectangles(mag, new System.Drawing.RectangleF[1] { new System.Drawing.RectangleF((float)rb.X, (float)rb.Y, (float)rb.W, (float)rb.H) });
2504 //Lets draw the selectBoxes.
2505 List<RectangleD> rects = new List<RectangleD>();
2506 RectangleD[] sels = an.GetSelectBoxes(Tools.selectBoxSize);
2507 for (int i = 0; i < an.selectedPoints.Count; i++)
2508 {
2509 if (an.selectedPoints[i] < an.GetPointCount())
2510 {
2511 rects.Add(sels[an.selectedPoints[i]]);
2512 }
2513 }
2514 for (int i = 0; i < rects.Count; i++)
2515 {
2516 var va = ToScreenSpace(rects.ToArray());
2517 g.DrawRectangle(blue, new System.Drawing.RectangleF((float)va[0].X, (float)va[0].Y, (float)va[0].W, (float)va[0].H));
2518 }
2519
2520 rects.Clear();
2521 //Lets draw the text of this ROI in the middle of the ROI
2522 if (an.type == ROI.Type.Label)
2523 continue;
2524 System.Drawing.Size s = System.Windows.Forms.TextRenderer.MeasureText(an.Text, new Font(an.family, an.fontSize));
2525 float fw = ((float)an.BoundingBox.X + ((float)an.BoundingBox.W / 2)) - ((float)s.Width / 2);
2526 float fh = ((float)an.BoundingBox.Y + ((float)an.BoundingBox.H / 2)) - ((float)s.Height / 2);
2527 var vv = ToScreenSpace(new PointF(fw, fh));
2528 g.DrawString(an.Text, fo, b, vv.X, vv.Y);
2529 }
2530 if (Tools.currentTool != null && Tools.currentTool.type == Tools.Tool.Type.rectSel)
2531 {
2532 RectangleD sel = Tools.currentTool.Rectangle;
2533 if (sel.W != 0 || sel.H != 0)
2534 {
2535 double x = Math.Min(sel.X, sel.X + sel.W);
2536 double y = Math.Min(sel.Y, sel.Y + sel.H);
2537 double selW = Math.Abs(sel.W);
2538 double selH = Math.Abs(sel.H);
2539 RectangleD normalized = new RectangleD(x, y, selW, selH);
2540 RectangleD rec = ToScreenSpace(normalized);
2541 g.DrawRectangle(blue, new System.Drawing.RectangleF((float)rec.X, (float)rec.Y, (float)rec.W, (float)rec.H));
2542 }
2543 }
2544 pen.Dispose();
2545 red.Dispose();
2546 mag.Dispose();
2547 green.Dispose();
2548 blue.Dispose();
2549 b.Dispose();
2550 }
2551 }
2552 }
2557 AForge.SizeF dSize = new AForge.SizeF(1, 1);
2562 public void DrawView(System.Drawing.Graphics g)
2563 {
2564 try
2565 {
2566 drawing = true;
2567 if (SelectedImage == null)
2568 return;
2569 if (UsesSlideRenderer(SelectedImage))
2570 {
2571 UpdateImages();
2572 return;
2573 }
2574 g.TranslateTransform(ViewWidth / 2, ViewHeight / 2);
2575 if (Scale.Width == 0 || float.IsInfinity(Scale.Width))
2576 Scale = new SizeF(1, 1);
2577 g.ScaleTransform(Scale.Width, Scale.Height);
2578 if (Bitmaps.Count == 0)
2579 return;
2580 System.Drawing.RectangleF[] rf = new System.Drawing.RectangleF[1];
2581 System.Drawing.Pen blue = new System.Drawing.Pen(Brushes.Blue, 1 / Scale.Width);
2582 int i = 0;
2583 foreach (BioImage im in Images)
2584 {
2585 if (!IsLayerEnabled(im.PhysicalSizeX) && !im.isPyramidal)
2586 continue;
2587 RectangleD r = ToScreenRect(im.Volume.Location.X, im.Volume.Location.Y, im.Volume.Width, im.Volume.Height);
2588 double w = ToViewW(ViewWidth);
2589 double h = ToViewH(ViewHeight);
2590 RectangleF rg = new RectangleF((float)((-Origin.X) - (w / 2)), (float)((-Origin.Y) - (h / 2)), (float)(w), (float)(h));
2591 RectangleF rec = new RectangleF((float)im.Volume.Location.X, (float)im.Volume.Location.Y, (float)im.Volume.Width, (float)im.Volume.Height);
2592 if (SelectedImage.isPyramidal)
2593 {
2594 var tr = g.Transform;
2595 g.ResetTransform();
2596 g.DrawImage(Bitmaps[i], 0, 0);
2597 g.Transform = tr;
2598 }
2599 else
2600 if (rg.IntersectsWith(rec))
2601 {
2602 g.DrawImage(Bitmaps[i], (float)r.X, (float)r.Y, (float)r.W, (float)r.H);
2603 }
2604 if (i == SelectedIndex && !SelectedImage.isPyramidal)
2605 {
2606 rf[0] = new System.Drawing.RectangleF((float)r.X, (float)r.Y, (float)r.W, (float)r.H);
2607 g.DrawRectangles(blue, rf);
2608 }
2609 i++;
2610 }
2611 if (ShowStage)
2612 {
2614 RectangleF[] rfs = new RectangleF[1] { new RectangleF((float)d.X, (float)d.Y, (float)d.W, (float)d.H) };
2615 var v = ToScreenSpace(rfs);
2616 System.Drawing.Pen red = new System.Drawing.Pen(Brushes.Red, 1 / Scale.Width);
2617 g.DrawRectangle(red, v[0].X, v[0].Y, v[0].Width, v[0].Height);
2618 }
2619 blue.Dispose();
2620 update = false;
2621 drawing = false;
2622 }
2623 catch (Exception e)
2624 {
2625 Console.WriteLine(e.Message);
2626 }
2627 }
2632 private void pictureBox_Paint(object sender, PaintEventArgs e)
2633 {
2634 update = true;
2635 //
2636 BringRenderSurfacesToFront();
2637 //Render(gl.CreateGraphics());
2638 DrawView(gl.CreateGraphics());
2639 Plugins.Paint(sender, e);
2640 }
2641
2642 private void Viewpanel_Paint(object sender, PaintEventArgs e)
2643 {
2644 if (SelectedImage == null)
2645 return;
2646 if (UsesSlideRenderer(SelectedImage))
2647 {
2648 return;
2649 }
2650 DrawView(e.Graphics);
2651 DrawOverlay(e.Graphics);
2652 Render(e.Graphics);
2653 }
2654
2658 public double GetScale()
2659 {
2660 return GetSelectionBoxHitSize();
2661 }
2662
2664 {
2665 return GetSelectBoxSizeForScreenPixels(MinSelectionHitScreenSize);
2666 }
2667 private System.Drawing.Bitmap ToSysBitmap(Bitmap bm)
2668 {
2669 if (bm == null)
2670 return null;
2671 if (bm.PixelFormat == AForge.PixelFormat.Format16bppGrayScale)
2672 {
2673 var grayResult = new System.Drawing.Bitmap(
2674 bm.Width,
2675 bm.Height,
2676 System.Drawing.Imaging.PixelFormat.Format24bppRgb);
2677 int min = int.MaxValue;
2678 int max = int.MinValue;
2679 for (int y = 0; y < bm.Height; y++)
2680 {
2681 for (int x = 0; x < bm.Width; x++)
2682 {
2683 int value = (int)bm.GetValue(x, y, 0);
2684 if (value < min)
2685 min = value;
2686 if (value > max)
2687 max = value;
2688 }
2689 }
2690 if (max <= min)
2691 max = min + 1;
2692
2693 var grayRect = new System.Drawing.Rectangle(0, 0, bm.Width, bm.Height);
2694 var grayData = grayResult.LockBits(grayRect, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
2695 try
2696 {
2697 int dstStride = Math.Abs(grayData.Stride);
2698 unsafe
2699 {
2700 for (int y = 0; y < bm.Height; y++)
2701 {
2702 byte* dstRow = (byte*)grayData.Scan0 + (y * dstStride);
2703 for (int x = 0; x < bm.Width; x++)
2704 {
2705 byte value = (byte)(((int)bm.GetValue(x, y, 0) - min) * 255 / (max - min));
2706 int offset = x * 3;
2707 dstRow[offset] = value;
2708 dstRow[offset + 1] = value;
2709 dstRow[offset + 2] = value;
2710 }
2711 }
2712 }
2713 }
2714 finally
2715 {
2716 grayResult.UnlockBits(grayData);
2717 }
2718
2719 return grayResult;
2720 }
2721
2722 var rgba = bm.GetImageRGBA();
2723 var result = new System.Drawing.Bitmap(
2724 bm.Width,
2725 bm.Height,
2726 System.Drawing.Imaging.PixelFormat.Format32bppArgb);
2727
2728 var rect = new System.Drawing.Rectangle(0, 0, bm.Width, bm.Height);
2729 var data = result.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
2730 try
2731 {
2732 int bytes = bm.Width * bm.Height * 4;
2733 byte[] buffer = new byte[bytes];
2734 Marshal.Copy(rgba.Data, buffer, 0, bytes);
2735 Marshal.Copy(buffer, 0, data.Scan0, bytes);
2736 }
2737 finally
2738 {
2739 result.UnlockBits(data);
2740 }
2741
2742 return result;
2743 }
2744
2745 PointD mouseD = new PointD(0, 0);
2746 PointD prevMove = new PointD();
2747 private PointD GetStatusPoint(PointD p)
2748 {
2749 if (SelectedImage != null && SelectedImage.isPyramidal && Resolution != 0)
2750 return new PointD(p.X / Resolution, p.Y / Resolution);
2751 return p;
2752 }
2753 private void UpdateMouseStatus(PointD p)
2754 {
2755 if (SelectedImage == null)
2756 return;
2757
2758 PointD displayPoint = GetStatusPoint(p);
2759 PointD samplePoint = SelectedImage.isPyramidal
2760 ? new PointD((p.X / Resolution) - PyramidalOrigin.X, (p.Y / Resolution) - PyramidalOrigin.Y)
2761 : p;
2762
2763 mousePoint = "(" + (int)displayPoint.X + ", " + (int)displayPoint.Y + ")";
2764 mouseColor = "";
2765
2766 AForge.Point s = SelectedImage.isPyramidal
2767 ? new AForge.Point(
2768 Math.Max(1, SelectedImage.Resolutions[Math.Clamp(SelectedImage.Level, 0, SelectedImage.Resolutions.Count - 1)].SizeX),
2769 Math.Max(1, SelectedImage.Resolutions[Math.Clamp(SelectedImage.Level, 0, SelectedImage.Resolutions.Count - 1)].SizeY))
2770 : new AForge.Point(SelectedImage.SizeX, SelectedImage.SizeY);
2771 if (samplePoint.X < 0 || samplePoint.Y < 0 || samplePoint.X >= s.X || samplePoint.Y >= s.Y)
2772 return;
2773
2774 int zc = SelectedImage.Coordinate.Z;
2775 int cc = SelectedImage.Coordinate.C;
2776 int tc = SelectedImage.Coordinate.T;
2777 if (SelectedImage.isPyramidal &&
2778 SelectedImage.Resolutions.Count > 0 &&
2779 SelectedImage.Resolutions[Math.Clamp(SelectedImage.Level, 0, SelectedImage.Resolutions.Count - 1)].PixelFormat == AForge.PixelFormat.Format16bppGrayScale)
2780 {
2781 try
2782 {
2783 int frameIndex = SelectedImage.GetFrameIndex(zc, cc, tc);
2784 int level = Math.Clamp(SelectedImage.Level, 0, SelectedImage.Resolutions.Count - 1);
2785 int sx = (int)Math.Floor(samplePoint.X);
2786 int sy = (int)Math.Floor(samplePoint.Y);
2787 byte[] raw = SelectedImage.GetTileBytesRaw(frameIndex, level, sx, sy, 1, 1, SelectedImage.Coordinate)
2788 .GetAwaiter()
2789 .GetResult();
2790 if (raw != null && raw.Length >= 2)
2791 {
2792 ushort value = (ushort)(raw[0] | (raw[1] << 8));
2793 mouseColor = ", " + value;
2794 return;
2795 }
2796 }
2797 catch
2798 {
2799 // Fall back to the generic buffer-backed path below.
2800 }
2801 }
2802 if (SelectedImage.isPyramidal)
2803 {
2804 try
2805 {
2806 int frameIndex = SelectedImage.GetFrameIndex(zc, cc, tc);
2807 int level = Math.Clamp(SelectedImage.Level, 0, SelectedImage.Resolutions.Count - 1);
2808 int sx = (int)Math.Floor(samplePoint.X);
2809 int sy = (int)Math.Floor(samplePoint.Y);
2810 using Bitmap rawTile = SelectedImage.GetTile(frameIndex, level, sx, sy, 1, 1, SelectedImage.Coordinate, true)
2811 .GetAwaiter()
2812 .GetResult();
2813 if (rawTile != null)
2814 {
2815 switch (rawTile.PixelFormat)
2816 {
2817 case AForge.PixelFormat.Format8bppIndexed:
2818 mouseColor = ", " + (int)rawTile.GetValue(0, 0, 0);
2819 return;
2820 case AForge.PixelFormat.Format16bppGrayScale:
2821 mouseColor = ", " + (int)rawTile.GetValue(0, 0, 0);
2822 return;
2823 case AForge.PixelFormat.Format24bppRgb:
2824 case AForge.PixelFormat.Format32bppArgb:
2825 case AForge.PixelFormat.Format32bppRgb:
2826 case AForge.PixelFormat.Format32bppPArgb:
2827 {
2828 int b = (int)rawTile.GetValue(0, 0, 0);
2829 int g = (int)rawTile.GetValue(0, 0, 1);
2830 int r = (int)rawTile.GetValue(0, 0, 2);
2831 mouseColor = ", " + r + "," + g + "," + b;
2832 return;
2833 }
2834 case AForge.PixelFormat.Format48bppRgb:
2835 {
2836 int b = (int)rawTile.GetValue(0, 0, 0);
2837 int g = (int)rawTile.GetValue(0, 0, 1);
2838 int r = (int)rawTile.GetValue(0, 0, 2);
2839 mouseColor = ", " + r + "," + g + "," + b;
2840 return;
2841 }
2842 }
2843 }
2844 }
2845 catch
2846 {
2847 // Fall back to the generic buffer-backed path below.
2848 }
2849 }
2850 if (SelectedImage.isRGB)
2851 {
2852 int r = (int)SelectedImage.GetValueRGB(zc, RChannel.Index, tc, (int)samplePoint.X, (int)samplePoint.Y, 0);
2853 int g = (int)SelectedImage.GetValueRGB(zc, GChannel.Index, tc, (int)samplePoint.X, (int)samplePoint.Y, 1);
2854 int b = (int)SelectedImage.GetValueRGB(zc, BChannel.Index, tc, (int)samplePoint.X, (int)samplePoint.Y, 2);
2855 mouseColor = ", " + r + "," + g + "," + b;
2856 }
2857 else
2858 {
2859 int r = (int)SelectedImage.GetValueRGB(zc, 0, tc, (int)samplePoint.X, (int)samplePoint.Y, 0);
2860 mouseColor = ", " + r;
2861 }
2862 }
2870 private void rgbPictureBox_MouseMove(object sender, MouseEventArgs e)
2871 {
2872 App.viewer = this;
2873 PointD p = ImageToViewSpace(e.Location.X, e.Location.Y);
2874 tools.ToolMove(p, e.Button);
2875 mouseMove = p;
2876 MouseMoveInt = new PointD(e.X, e.Y);
2877 if (SelectedImage == null)
2878 return;
2879 UpdateMouseStatus(p);
2880 if (e.Button == MouseButtons.XButton1 && !x1State && !Ctrl && Mode != ViewMode.RGBImage)
2881 {
2882 if (cBar.Value < cBar.Maximum)
2883 cBar.Value++;
2884 x1State = true;
2885 }
2886 else if (e.Button == MouseButtons.XButton1 && !x1State && Ctrl)
2887 {
2888 if (tBar.Value < tBar.Maximum)
2889 tBar.Value++;
2890 x1State = true;
2891 }
2892 if (e.Button != MouseButtons.XButton1)
2893 x1State = false;
2894
2895 if (e.Button == MouseButtons.XButton2 && !x2State && !Ctrl && Mode != ViewMode.RGBImage)
2896 {
2897 if (cBar.Value > cBar.Minimum)
2898 cBar.Value--;
2899 x2State = true;
2900 }
2901 else if (e.Button == MouseButtons.XButton2 && !x2State && Ctrl)
2902 {
2903 if (tBar.Value > tBar.Minimum)
2904 tBar.Value--;
2905 x2State = true;
2906 }
2907 if (e.Button != MouseButtons.XButton2)
2908 x2State = false;
2909
2910 if (Tools.currentTool.type == Tools.Tool.Type.move && e.Button == MouseButtons.Left)
2911 {
2912 foreach (ROI an in selectedAnnotations)
2913 {
2914 if (an.selectedPoints.Count > 0 && an.selectedPoints.Count < an.GetPointCount())
2915 {
2916 if (an.type == ROI.Type.Rectangle || an.type == ROI.Type.Ellipse)
2917 {
2918 RectangleD d = an.BoundingBox;
2919 if (an.selectedPoints[0] == 0)
2920 {
2921 double dw = d.X - p.X;
2922 double dh = d.Y - p.Y;
2923 d.X = p.X;
2924 d.Y = p.Y;
2925 d.W += dw;
2926 d.H += dh;
2927 }
2928 else
2929 if (an.selectedPoints[0] == 1)
2930 {
2931 double dw = p.X - (d.W + d.X);
2932 double dh = d.Y - p.Y;
2933 d.W += dw;
2934 d.H += dh;
2935 d.Y -= dh;
2936 }
2937 else
2938 if (an.selectedPoints[0] == 2)
2939 {
2940 double dw = d.X - p.X;
2941 double dh = p.Y - (d.Y + d.H);
2942 d.W += dw;
2943 d.H += dh;
2944 d.X -= dw;
2945 }
2946 else
2947 if (an.selectedPoints[0] == 3)
2948 {
2949 double dw = d.X - p.X;
2950 double dh = d.Y - p.Y;
2951 d.W = p.X - an.X;
2952 d.H = p.Y - an.Y;
2953 }
2954 an.BoundingBox = d;
2955 an.Validate();
2956 }
2957 else
2958 {
2959 PointD pod = new PointD(p.X - pd.X, p.Y - pd.Y);
2960 for (int i = 0; i < an.selectedPoints.Count; i++)
2961 {
2962 PointD poid = an.GetPoint(an.selectedPoints[i]);
2963 an.UpdatePoint(new PointD(poid.X + pod.X, poid.Y + pod.Y), an.selectedPoints[i]);
2964 }
2965 an.UpdateBoundingBox();
2966 }
2967 }
2968 else
2969 {
2970 PointD pod = new PointD(p.X - pd.X, p.Y - pd.Y);
2971 for (int i = 0; i < an.GetPointCount(); i++)
2972 {
2973 PointD poid = an.Points[i];
2974 an.UpdatePoint(new PointD(poid.X + pod.X, poid.Y + pod.Y), i);
2975 }
2976 an.UpdateBoundingBox();
2977 }
2978 }
2979 UpdateOverlay();
2980 }
2981
2982 if (Tools.currentTool != null)
2983 if (Tools.currentTool.type == Tools.Tool.Type.pencil && e.Button == MouseButtons.Left)
2984 {
2985 PointD pencilIp = SelectedImage.ToImageSpace(p);
2986 Tools.Tool tool = Tools.currentTool;
2987 Graphics.Graphics g = Graphics.Graphics.FromImage(SelectedBuffer);
2988 Graphics.Pen pen = new Graphics.Pen(Tools.DrawColor, (int)Tools.StrokeWidth, ImageView.SelectedImage.bitsPerPixel);
2989 g.FillEllipse(new Rectangle((int)pencilIp.X, (int)pencilIp.Y, (int)Tools.StrokeWidth, (int)Tools.StrokeWidth), pen.color);
2990 UpdateImage();
2991 }
2992
2993 UpdateStatus();
2994 prevMove = p;
2995 pd = p;
2996 }
3003 private void pictureBox_MouseUp(object sender, MouseEventArgs e)
3004 {
3005 PointD p = ImageToViewSpace(e.Location.X, e.Location.Y);
3006 mouseUpButtons = e.Button;
3007 mouseDownButtons = MouseButtons.None;
3008 MouseUpInt = new PointD(e.X, e.Y);
3009 mouseUp = p;
3010 down = false;
3011 up = true;
3012 if (SelectedImage == null)
3013 return;
3014 App.viewer = this;
3015 tools.ToolUp(p, e.Button);
3016 }
3023 private void pictureBox_MouseDown(object sender, MouseEventArgs e)
3024 {
3025 App.viewer = this;
3026 MouseDownInt = new PointD(e.X, e.Y);
3027 mouseDownButtons = e.Button;
3028 mouseUpButtons = MouseButtons.None;
3029 PointD p = ImageToViewSpace(e.Location.X, e.Location.Y);
3030 pd = new PointD(p.X, p.Y);
3031 mouseDown = pd;
3032 mouseD = new PointD(e.Location.X, e.Location.Y);
3033 down = true;
3034 up = false;
3035 if (SelectedImage == null)
3036 return;
3037 tools.BringToFront();
3038 int ind = 0;
3039 foreach (BioImage b in Images)
3040 {
3041 RectangleD r = new RectangleD(b.Volume.Location.X, b.Volume.Location.Y, b.Volume.Width, b.Volume.Height);
3042 if (r.IntersectsWith(p))
3043 {
3044 b.selected = true;
3045 SelectedIndex = ind;
3046 }
3047 else
3048 b.selected = false;
3049 ind++;
3050 }
3051 if (!Ctrl && e.Button == MouseButtons.Left && Tools.currentTool.type != Tools.Tool.Type.rectSel)
3052 {
3053 foreach (ROI item in selectedAnnotations)
3054 {
3055 if (item.Selected)
3056 item.selectedPoints.Clear();
3057 }
3058 selectedAnnotations.Clear();
3059 }
3060
3061 if (Tools.currentTool.type == Tools.Tool.Type.move && e.Button == MouseButtons.Left)
3062 {
3063 float width = (float)GetSelectionBoxHitSize();
3064 float height = (float)GetSelectionBoxHitSize();
3065 foreach (BioImage bi in Images)
3066 {
3067 foreach (ROI an in bi.Annotations)
3068 {
3069 if (an.GetSelectBound(width, height).IntersectsWith(new RectangleD(p.X, p.Y, 1, 1)))
3070 {
3071 selectedAnnotations.Add(an);
3072 an.Selected = true;
3073 RectangleD[] sels = an.GetSelectBoxes(Tools.selectBoxSize);
3074 double hitSize = GetSelectionBoxHitSize();
3075 RectangleD r = new RectangleD(p.X - hitSize / 2, p.Y - hitSize / 2, hitSize, hitSize);
3076 for (int i = 0; i < sels.Length; i++)
3077 {
3078 if (sels[i].IntersectsWith(r))
3079 {
3080 an.selectedPoints.Add(i);
3081 }
3082 }
3083 }
3084 else
3085 if (!Ctrl)
3086 an.Selected = false;
3087 }
3088 }
3089 UpdateOverlay();
3090 }
3091
3092 if (e.Button == MouseButtons.Left)
3093 {
3094 UpdateMouseStatus(p);
3095 }
3096 UpdateStatus();
3097 tools.ToolDown(mouseDown, e.Button);
3098 }
3106 private void pictureBox_MouseDoubleClick(object sender, MouseEventArgs e)
3107 {
3108 if (SelectedImage == null)
3109 return;
3110 App.viewer = this;
3111 PointD p = ToViewSpace(e.Location.X, e.Location.Y);
3112 tools.ToolDown(p, e.Button);
3113 if (e.Button != MouseButtons.XButton1 && e.Button != MouseButtons.XButton2)
3114 Origin = new PointD(-p.X, -p.Y);
3115 }
3122 private void deleteROIToolStripMenuItem_Click(object sender, EventArgs e)
3123 {
3124 if (SelectedImage == null)
3125 return;
3126 foreach (ROI item in AnnotationsRGB)
3127 {
3128 if (item.Selected && (item.selectedPoints.Count == 0 || item.selectedPoints.Count == item.GetPointCount() || item.type == ROI.Type.Ellipse || item.type == ROI.Type.Rectangle))
3129 {
3130 SelectedImage.Annotations.Remove(item);
3131 }
3132 else
3133 {
3134 if ((item.type == ROI.Type.Polygon || item.type == ROI.Type.Freeform || item.type == ROI.Type.Polyline) && item.selectedPoints.Count > 0)
3135 {
3136 item.RemovePoints(item.selectedPoints.ToArray());
3137
3138 }
3139 item.selectedPoints.Clear();
3140 }
3141 }
3142 UpdateOverlay();
3143 }
3150 private void setTextSelectionToolStripMenuItem_Click(object sender, EventArgs e)
3151 {
3152 if (SelectedImage == null)
3153 return;
3154 foreach (ROI item in AnnotationsRGB)
3155 {
3156 if (item.Selected)
3157 {
3158 TextInput input = new TextInput(item.Text);
3159 if (input.ShowDialog() != DialogResult.OK)
3160 return;
3161 item.Text = input.TextValue;
3162 item.family = input.font.FontFamily.Name;
3163 item.fontSize = input.font.Size;
3164 item.strokeColor = AForge.Color.FromArgb(input.color.R, input.color.G, input.color.B);
3165 UpdateOverlay();
3166 }
3167 }
3168 }
3169
3174 private void copyViewToClipboardToolStripMenuItem_Click(object sender, EventArgs e)
3175 {
3176 System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(ViewWidth, ViewHeight);
3177 using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
3178 {
3179 DrawView(g);
3180 DrawOverlay(g);
3181 }
3182 System.Windows.Forms.Clipboard.SetImage(bmp);
3183 }
3184 List<ROI> copys = new List<ROI>();
3185
3187 public void CopySelection()
3188 {
3189 copys.Clear();
3190 string s = "";
3191 foreach (ROI item in AnnotationsRGB)
3192 {
3193 if (item.Selected)
3194 {
3195 copys.Add(item);
3196 s += BioImage.ROIToString(item);
3197 }
3198 }
3199 System.Windows.Forms.Clipboard.SetText(s);
3200 }
3203 public void PasteSelection()
3204 {
3205 string[] sts = System.Windows.Forms.Clipboard.GetText().Split(BioImage.NewLine);
3206 foreach (string line in sts)
3207 {
3208 if (line.Length > 8)
3209 {
3210 ROI an = BioImage.StringToROI(line);
3211 //We set the coordinates of the ROI's we are pasting
3212 an.coord = GetCoordinate();
3213 SelectedImage.Annotations.Add(an);
3214 }
3215 }
3216 UpdateOverlay();
3217 }
3222 private void copyROIToolStripMenuItem_Click(object sender, EventArgs e)
3223 {
3224 CopySelection();
3225 }
3226
3232 private void pasteROIToolStripMenuItem_Click(object sender, EventArgs e)
3233 {
3235 }
3236
3241 private void hideControlsToolStripMenuItem_Click(object sender, EventArgs e)
3242 {
3243 if (ShowControls)
3244 ShowControls = false;
3245 else
3246 ShowControls = true;
3247 }
3248
3253 private void showControlToolStripMenuItem_Click(object sender, EventArgs e)
3254 {
3255 if (ShowControls)
3256 ShowControls = false;
3257 else
3258 ShowControls = true;
3259 }
3260
3265 private void HideStatusMenuItem_Click(object sender, EventArgs e)
3266 {
3268 }
3273 private void rGBToolStripMenuItem_Click(object sender, EventArgs e)
3274 {
3275 Mode = ViewMode.RGBImage;
3276 }
3277
3282 private void filteredToolStripMenuItem_Click(object sender, EventArgs e)
3283 {
3284 Mode = ViewMode.Filtered;
3285 }
3286
3291 private void rawToolStripMenuItem_Click(object sender, EventArgs e)
3292 {
3293 Mode = ViewMode.Raw;
3294 }
3301 public PointD ImageToViewSpace(double x, double y)
3302 {
3303 if (SelectedImage == null)
3304 return ToViewSpace(x, y);
3305 if (SelectedImage.isPyramidal)
3306 {
3307 return new PointD(PyramidalOrigin.X + (x * Resolution), PyramidalOrigin.Y + (y * Resolution));
3308 }
3309 else
3310 return ToViewSpace(x, y);
3311 }
3318 {
3319 PointD d = ToViewSpace(p.X, p.Y);
3320 return new PointF((float)d.X, (float)d.Y);
3321 }
3328 {
3329 return ToViewSpace(p.X, p.Y); ;
3330 }
3337 public PointD ToViewSpace(double x, double y)
3338 {
3339 if (SelectedImage != null)
3340 if (SelectedImage.isPyramidal)
3341 {
3342 return new PointD((x - PyramidalOrigin.X) / Resolution, (y - PyramidalOrigin.Y) / Resolution);
3343 }
3344 double dx, dy;
3345 dx = (ToViewSizeW(x - (ViewWidth / 2)) / Scale.Width) - Origin.X;
3346 dy = (ToViewSizeH(y - (ViewHeight / 2)) / Scale.Height) - Origin.Y;
3347 return new PointD(dx, dy);
3348 }
3354 private double ToViewSizeW(double d)
3355 {
3356 if (SelectedImage != null)
3357 if (SelectedImage.isPyramidal)
3358 {
3359 return d / Resolution;
3360 }
3361 double x = (double)(d / PxWmicron);
3362 return x;
3363 }
3369 public double ToViewSizeH(double d)
3370 {
3371 if (SelectedImage != null)
3372 if (SelectedImage.isPyramidal)
3373 {
3374 return d / Resolution;
3375 }
3376 double y = (double)(d / PxHmicron);
3377 return y;
3378 }
3384 public double ToViewW(double d)
3385 {
3386 double x = (double)(d / PxWmicron) / scale.Width;
3387 return x;
3388 }
3394 public double ToViewH(double d)
3395 {
3396 double y = (double)(d / PxHmicron) / scale.Height;
3397 return y;
3398 }
3405 public PointD ToScreenSpace(double x, double y)
3406 {
3407 if (SelectedImage != null && SelectedImage.isPyramidal)
3408 {
3409 return new PointD((x - PyramidalOrigin.X) / Resolution, (y - PyramidalOrigin.Y) / Resolution);
3410 }
3411 double fx = ToScreenScaleW(Origin.X + x);
3412 double fy = ToScreenScaleH(Origin.Y + y);
3413 return new PointD(fx, fy);
3414 }
3421 {
3422 return ToScreenSpace(p.X, p.Y);
3423 }
3430 {
3431 PointD pd = ToScreenSpace(p.X, p.Y);
3432 return new PointF((float)pd.X, (float)pd.Y);
3433 }
3440 {
3441 PointF[] pf = new PointF[p.Length];
3442 for (int i = 0; i < p.Length; i++)
3443 {
3444 pf[i] = ToScreenSpace(p[i]);
3445 }
3446 return pf;
3447 }
3448 private Font GetLabelFont(ROI an)
3449 {
3450 string family = string.IsNullOrWhiteSpace(an?.family) ? SystemFonts.DefaultFont.FontFamily.Name : an.family;
3451 float size = an != null && an.fontSize > 0 ? an.fontSize : SystemFonts.DefaultFont.Size;
3452 try
3453 {
3454 return new Font(family, size);
3455 }
3456 catch
3457 {
3458 return new Font(SystemFonts.DefaultFont.FontFamily, SystemFonts.DefaultFont.Size);
3459 }
3460 }
3461 private Font GetScaledLabelFont(ROI an, float zoomScale)
3462 {
3463 string family = string.IsNullOrWhiteSpace(an?.family) ? SystemFonts.DefaultFont.FontFamily.Name : an.family;
3464 float baseSize = an != null && an.fontSize > 0 ? an.fontSize : SystemFonts.DefaultFont.Size;
3465 float scale = Math.Max(0.0001f, zoomScale);
3466 try
3467 {
3468 return new Font(family, baseSize / scale);
3469 }
3470 catch
3471 {
3472 return new Font(SystemFonts.DefaultFont.FontFamily, SystemFonts.DefaultFont.Size / scale);
3473 }
3474 }
3475 private System.Drawing.RectangleF GetLabelScreenRect(ROI an)
3476 {
3477 if (an == null)
3478 return System.Drawing.RectangleF.Empty;
3479 AForge.RectangleD rect = ToScreenSpace(an.BoundingBox);
3480 return new System.Drawing.RectangleF((float)rect.X, (float)rect.Y, (float)rect.W, (float)rect.H);
3481 }
3487 public PointF ToScreenSpace(Point3D p)
3488 {
3489 PointD pd = ToScreenSpace(p.X, p.Y);
3490 return new PointF((float)pd.X, (float)pd.Y);
3491 }
3497 public float ToScreenScaleW(double x)
3498 {
3499 return (float)(x * PxWmicron);
3500 }
3506 public float ToScreenScaleH(double y)
3507 {
3508 return (float)(y * PxHmicron);
3509 }
3516 {
3517 float x = ToScreenScaleW((float)p.X);
3518 float y = ToScreenScaleH((float)p.Y);
3519 return new PointF(x, y);
3520 }
3529 public RectangleD ToScreenRect(double x, double y, double w, double h)
3530 {
3531 if (SelectedImage == null)
3532 {
3533 PointD pf;
3534 pf = ToScreenSpace(x, y);
3535 return new RectangleD(pf.X, pf.Y, ToScreenScaleW(w), ToScreenScaleH(h));
3536 }
3537 if (SelectedImage.isPyramidal)
3538 {
3539 PointD d = ToScreenSpace(x, y);
3540 double dw = ToViewSizeW(w);
3541 double dh = ToViewSizeH(h);
3542 return new RectangleD(d.X, d.Y, dw, dh);
3543 }
3544 else
3545 {
3546 PointD pf = ToScreenSpace(x, y);
3547 return new RectangleD(pf.X, pf.Y, ToScreenScaleW(w), ToScreenScaleH(h));
3548 }
3549 }
3559 public SKRect ToSKRect(double x, double y, double w, double h)
3560 {
3561 double xd = gl.Width / 2;
3562 double yd = gl.Height / 2;
3563 return new SKRect((float)(xd - x), (float)(yd - y), (float)(xd - (x + w)), (float)(yd - (y + h)));
3564 }
3571 {
3572 return ToScreenRect(p.X, p.Y, p.W, p.H);
3573 }
3580 {
3581 return ToScreenRect(p.X, p.Y, p.Width, p.Height);
3582 }
3589 {
3590 RectangleD[] rs = new RectangleD[p.Length];
3591 for (int i = 0; i < p.Length; i++)
3592 {
3593 rs[i] = ToScreenSpace(p[i]);
3594 }
3595 return rs;
3596 }
3603 {
3604 RectangleF[] rs = new RectangleF[p.Length];
3605 for (int i = 0; i < p.Length; i++)
3606 {
3607 rs[i] = ToScreenSpace(p[i]).ToRectangleF();
3608 }
3609 return rs;
3610 }
3617 {
3618 PointF[] rs = new PointF[p.Length];
3619 for (int i = 0; i < p.Length; i++)
3620 {
3621 PointD pd = ToScreenSpace(p[i]);
3622 rs[i] = new PointF((float)pd.X, (float)pd.Y);
3623 }
3624 return rs;
3625 }
3631 public float ToScreenW(double x)
3632 {
3633 return (float)(x * PxWmicron);
3634 }
3640 public float ToScreenH(double y)
3641 {
3642 return (float)(y * PxHmicron);
3643 }
3651 public void ImageView_KeyDown(object sender, KeyEventArgs e)
3652 {
3653 double moveAmount = 5 * Scale.Width;
3654 Plugins.KeyDownEvent(sender, e);
3655 if (e.KeyCode == Keys.C && e.Control)
3656 {
3657 CopySelection();
3658 return;
3659 }
3660 if (e.KeyCode == Keys.V && e.Control)
3661 {
3663 return;
3664 }
3665 if (e.KeyCode == Keys.Subtract || e.KeyCode == Keys.NumPad7)
3666 {
3667 if (SelectedImage.isPyramidal)
3668 ZoomPyramidalAt(new System.Drawing.Point(ViewWidth / 2, ViewHeight / 2), 0.9);
3669 else
3670 Scale = new SizeF(Scale.Width - 0.1f, Scale.Height - 0.1f);
3671 if (!SelectedImage.isPyramidal)
3672 UpdateView();
3673 }
3674 if (e.KeyCode == Keys.Add || e.KeyCode == Keys.NumPad9)
3675 {
3676 if (SelectedImage.isPyramidal)
3677 ZoomPyramidalAt(new System.Drawing.Point(ViewWidth / 2, ViewHeight / 2), 1.1);
3678 else
3679 Scale = new SizeF(Scale.Width + 0.1f, Scale.Height + 0.1f);
3680 if (!SelectedImage.isPyramidal)
3681 UpdateView();
3682 }
3683 if (e.KeyCode == Keys.W || e.KeyCode == Keys.NumPad8)
3684 {
3685 if (SelectedImage.isPyramidal)
3686 PyramidalOrigin = new PointD(PyramidalOrigin.X, PyramidalOrigin.Y - moveAmount);
3687 else
3688 Origin = new PointD(Origin.X, Origin.Y + moveAmount);
3689 UpdateView();
3690 }
3691 if (e.KeyCode == Keys.S || e.KeyCode == Keys.NumPad2)
3692 {
3693 if (SelectedImage.isPyramidal)
3694 PyramidalOrigin = new PointD(PyramidalOrigin.X, PyramidalOrigin.Y + moveAmount);
3695 else
3696 Origin = new PointD(Origin.X, Origin.Y - moveAmount);
3697 UpdateView();
3698 }
3699 if (e.KeyCode == Keys.A || e.KeyCode == Keys.NumPad4)
3700 {
3701 if (SelectedImage.isPyramidal)
3702 PyramidalOrigin = new PointD(PyramidalOrigin.X - moveAmount, PyramidalOrigin.Y);
3703 else
3704 Origin = new PointD(Origin.X + moveAmount, Origin.Y);
3705 UpdateView();
3706 }
3707 if (e.KeyCode == Keys.D || e.KeyCode == Keys.NumPad6)
3708 {
3709 if (SelectedImage.isPyramidal)
3710 PyramidalOrigin = new PointD(PyramidalOrigin.X + moveAmount, PyramidalOrigin.Y);
3711 else
3712 Origin = new PointD(Origin.X - moveAmount, Origin.Y);
3713 UpdateView();
3714 }
3715 }
3716 private void ImageView_KeyUp(object sender, KeyEventArgs e)
3717 {
3718 Plugins.KeyUpEvent(sender, e);
3719 }
3720 private void ImageView_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
3721 {
3722 Plugins.KeyPressEvent(sender, e);
3723 }
3728 public void GoToImage()
3729 {
3731 }
3732 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
3734 {
3735 get { return new PointD(PyramidalOrigin.X * Resolution, PyramidalOrigin.Y * Resolution); }
3736 set { PyramidalOrigin = new PointD(value.X / Resolution, value.Y / Resolution); }
3737 }
3738 PointD mouseDownInt = new PointD(0, 0);
3739 PointD mouseUpInt = new PointD(0, 0);
3740 PointD mouseMoveInt = new PointD(0, 0);
3741 PointD mouseMove = new PointD(0, 0);
3742 /* A property that returns the value of the mouseDownInt variable. */
3743 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
3745 {
3746 get { return mouseDownInt; }
3747 set { mouseDownInt = value; }
3748 }
3749 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
3751 {
3752 get { return mouseUpInt; }
3753 set { mouseUpInt = value; }
3754 }
3755 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
3757 {
3758 get { return mouseMoveInt; }
3759 set { mouseMoveInt = value; }
3760 }
3761
3762 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
3763 public bool ShowMasks { get; set; } = true;
3764
3770 public void GoToImage(int i)
3771 {
3772 if (i < 0 || Images.Count <= i)
3773 return;
3774 App.viewer = this;
3775 if (SelectedIndex != i)
3776 SelectedIndex = i;
3777 BioImage image = Images[i];
3778 int viewportWidth = GetEffectiveViewWidth();
3779 int viewportHeight = GetEffectiveViewHeight();
3780 if (UsesSlideRenderer(image))
3781 {
3782 CenterPyramidalImage(image, viewportWidth, viewportHeight);
3783 UpdateView();
3784 return;
3785 }
3786
3787 double dx = image.Volume.Width / 2;
3788 double dy = image.Volume.Height / 2;
3789 origin = new PointD(-(image.Volume.Location.X + dx), -(image.Volume.Location.Y + dy));
3790 double screenWidth = Math.Abs(ToScreenScaleW(image.Volume.Width));
3791 double screenHeight = Math.Abs(ToScreenScaleH(image.Volume.Height));
3792 double wx = screenWidth > 0 ? viewportWidth / screenWidth : 1;
3793 double wy = screenHeight > 0 ? viewportHeight / screenHeight : 1;
3794 double fitScale = Math.Min(wx, wy);
3795 if (fitScale <= 0 || double.IsNaN(fitScale) || double.IsInfinity(fitScale))
3796 fitScale = 1;
3797 scale = new SizeF((float)fitScale, (float)fitScale);
3798 update = true;
3799 UpdateView();
3800 }
3801
3802 private int GetEffectiveViewWidth()
3803 {
3804 int width = ViewWidth;
3805 if (width <= 1)
3806 width = viewpanel?.ClientSize.Width ?? Width;
3807 if (width <= 1)
3808 width = Width;
3809 return Math.Max(1, width);
3810 }
3811
3812 private int GetEffectiveViewHeight()
3813 {
3814 int height = ViewHeight;
3815 if (height <= 1)
3816 height = viewpanel?.ClientSize.Height ?? Height;
3817 if (height <= 1)
3818 height = Height;
3819 return Math.Max(1, height);
3820 }
3821
3822 private void CenterPyramidalImage(BioImage image, int viewportWidth, int viewportHeight)
3823 {
3824 if (!TryGetPyramidalWorldBounds(image, out double minX, out double minY, out double maxX, out double maxY))
3825 return;
3826
3827 double worldWidth = maxX - minX;
3828 double worldHeight = maxY - minY;
3829 if (worldWidth <= 0 || worldHeight <= 0)
3830 return;
3831
3832 double fitResolution = Math.Max(worldWidth / viewportWidth, worldHeight / viewportHeight) * 1.02;
3833 if (fitResolution <= 0 || double.IsNaN(fitResolution) || double.IsInfinity(fitResolution))
3834 fitResolution = image.Resolution > 0 ? image.Resolution : 1;
3835
3836 image.Resolution = fitResolution;
3837 double viewportWorldWidth = viewportWidth * fitResolution;
3838 double viewportWorldHeight = viewportHeight * fitResolution;
3839 double centerX = minX + (worldWidth / 2);
3840 double centerY = minY + (worldHeight / 2);
3841
3842 image.PyramidalOrigin = new PointD(
3843 centerX - (viewportWorldWidth / 2),
3844 -(centerY + (viewportWorldHeight / 2)));
3845 }
3846
3847 private void CenterPyramidalOrigin(BioImage image, int viewportWidth, int viewportHeight)
3848 {
3849 if (viewportWidth <= 1 || viewportHeight <= 1)
3850 return;
3851 if (!TryGetPyramidalWorldBounds(image, out double minX, out double minY, out double maxX, out double maxY))
3852 return;
3853
3854 double worldWidth = maxX - minX;
3855 double worldHeight = maxY - minY;
3856 if (worldWidth <= 0 || worldHeight <= 0)
3857 return;
3858
3859 double visibleWidth = viewportWidth * Math.Max(image.Resolution, 1e-9);
3860 double visibleHeight = viewportHeight * Math.Max(image.Resolution, 1e-9);
3861 double centerX = minX + (worldWidth / 2.0);
3862 double centerY = minY + (worldHeight / 2.0);
3863
3864 image.PyramidalOrigin = new PointD(
3865 centerX - (visibleWidth / 2.0),
3866 -(centerY + (visibleHeight / 2.0)));
3867 }
3868
3869 private bool TryGetPyramidalWorldBounds(BioImage image, out double minX, out double minY, out double maxX, out double maxY)
3870 {
3871 minX = minY = maxX = maxY = 0;
3872 BruTile.ITileSchema schema = null;
3873 if (image.OpenSlideBase != null)
3874 schema = image.OpenSlideBase.Schema;
3875 else if (image.SlideBase != null)
3876 schema = image.SlideBase.Schema;
3877
3878 if (schema != null)
3879 {
3880 minX = schema.Extent.MinX;
3881 minY = schema.Extent.MinY;
3882 maxX = schema.Extent.MaxX;
3883 maxY = schema.Extent.MaxY;
3884 return maxX > minX && maxY > minY;
3885 }
3886
3887 if (image.Resolutions.Count == 0)
3888 return false;
3889
3890 double unitsPerPixel = image.GetUnitPerPixel(0);
3891 if (unitsPerPixel <= 0 || double.IsNaN(unitsPerPixel) || double.IsInfinity(unitsPerPixel))
3892 unitsPerPixel = 1;
3893
3894 minX = 0;
3895 maxX = image.Resolutions[0].SizeX * unitsPerPixel;
3896 maxY = 0;
3897 minY = -(image.Resolutions[0].SizeY * unitsPerPixel);
3898 return maxX > minX && maxY > minY;
3899 }
3900
3905 private void goToImageToolStripMenuItem_Click(object sender, EventArgs e)
3906 {
3907 GoToImage();
3908 }
3914 private void goToToolStripMenuItem1_Click(object sender, EventArgs e)
3915 {
3916 Origin = new PointD(mouseDown.X, mouseDown.Y);
3917 }
3923 private void goToImageToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
3924 {
3925 ToolStripMenuItem item = (ToolStripMenuItem)sender;
3926 item.DropDownItems.Clear();
3927 for (int i = 0; i < Images.Count; i++)
3928 {
3929 BioImage im = Images[i];
3930 ToolStripMenuItem it = new ToolStripMenuItem();
3931 it.Text = $"{i}: {im.filename}";
3932 it.Tag = i;
3933 item.DropDownItems.Add(it);
3934 }
3935 }
3943 private void goToImageToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
3944 {
3945 if (e.ClickedItem.Tag is int index && index >= 0 && index < Images.Count)
3946 {
3947 GoToImage(index);
3948 return;
3949 }
3950 }
3951 public new void Dispose()
3952 {
3953 foreach (var bitmap in Bitmaps)
3954 bitmap?.Dispose();
3955 Bitmaps.Clear();
3956 base.Dispose();
3957 }
3958
3964 private void goToToolStripMenuItem_Click_1(object sender, EventArgs e)
3965 {
3967 }
3968
3973 private void drawToolStripMenuItem_Click(object sender, EventArgs e)
3974 {
3975 Graphics.Graphics g = Graphics.Graphics.FromImage(SelectedBuffer);
3976 foreach (ROI item in AnnotationsRGB)
3977 {
3978 Graphics.Pen p = new Graphics.Pen(Tools.DrawColor, (int)Tools.StrokeWidth, SelectedBuffer.BitsPerPixel);
3979 g.pen = p;
3980 if (item.Selected)
3981 {
3982 if (item.type == ROI.Type.Point)
3983 {
3984 PointD pt = SelectedImage.ToImageSpace(item.Points[0]);
3985 g.FillEllipse(new RectangleF((float)pt.X - 2f, (float)pt.Y - 2f, 4f, 4f), p.color);
3986 }
3987 else
3988 if (item.type == ROI.Type.Line)
3989 {
3990 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));
3991 }
3992 else
3993 if (item.type == ROI.Type.Rectangle)
3994 {
3995 g.DrawRectangle(SelectedImage.ToImageSpace(item.BoundingBox));
3996 }
3997 else
3998 if (item.type == ROI.Type.Ellipse)
3999 {
4000 g.DrawEllipse(SelectedImage.ToImageSpace(item.BoundingBox));
4001 }
4002 else
4003 if (item.type == ROI.Type.Freeform || item.type == ROI.Type.Polygon || item.type == ROI.Type.Polyline)
4004 {
4005 if (item.closed)
4006 {
4007 for (int i = 0; i < item.GetPointCount() - 1; i++)
4008 {
4009 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));
4010 }
4011 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));
4012
4013 }
4014 else
4015 {
4016 for (int i = 0; i < item.GetPointCount() - 1; i++)
4017 {
4018 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));
4019 }
4020 }
4021 }
4022 }
4023 }
4024 update = true;
4025 UpdateImage();
4026 }
4027
4032 private void fillToolStripMenuItem_Click(object sender, EventArgs e)
4033 {
4034 Graphics.Graphics g = Graphics.Graphics.FromImage(SelectedBuffer);
4035 foreach (ROI item in AnnotationsRGB)
4036 {
4037 Graphics.Pen p = new Graphics.Pen(Tools.DrawColor, (int)Tools.StrokeWidth, SelectedBuffer.BitsPerPixel);
4038 if (item.Selected)
4039 {
4040 if (item.type == ROI.Type.Point)
4041 {
4042 PointD pt = SelectedImage.ToImageSpace(item.Points[0]);
4043 g.FillEllipse(new RectangleF((float)pt.X - 2f, (float)pt.Y - 2f, 4f, 4f), p.color);
4044 }
4045 else
4046 if (item.type == ROI.Type.Line)
4047 {
4048 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));
4049 }
4050 else
4051 if (item.type == ROI.Type.Rectangle)
4052 {
4053 g.FillRectangle(SelectedImage.ToImageSpace(item.BoundingBox), p.color);
4054 }
4055 else
4056 if (item.type == ROI.Type.Ellipse)
4057 {
4058 g.FillEllipse(SelectedImage.ToImageSpace(item.BoundingBox), p.color);
4059 }
4060 else
4061 if (item.type == ROI.Type.Freeform || item.type == ROI.Type.Polygon || item.type == ROI.Type.Polyline)
4062 {
4063 g.FillPolygon(SelectedImage.ToImageSpace(item.GetPointsF()), SelectedImage.ToImageSpace(item.BoundingBox), p.color);
4064 }
4065 }
4066 }
4067 update = true;
4068 UpdateImage();
4069 }
4070
4071 public void GoToStage()
4072 {
4074 double dx = d.W / 2;
4075 double dy = d.H / 2;
4076 Origin = new PointD(-(d.X + dx), -(d.Y + dy));
4077 double wx, wy;
4078 wx = Math.Abs(ViewWidth / ToScreenScaleW(d.W));
4079 wy = Math.Abs(ViewHeight / ToScreenScaleH(d.H));
4080 scale.Width = (float)wy;
4081 scale.Height = (float)wy;
4082 update = true;
4083 UpdateView();
4084 }
4088 public void MoveStageToImage()
4089 {
4090 if (SelectedImage == null)
4091 return;
4092 Microscope.Stage.SetPosition(SelectedImage.Volume.Location.X, SelectedImage.Volume.Location.Y);
4093 update = true;
4094 UpdateView();
4095 }
4099 public void MoveStageToImage(int i)
4100 {
4101 update = true;
4102 Microscope.Stage.SetPosition(Images[i].Volume.Location.X, Images[i].Volume.Location.Y);
4103 UpdateView();
4104 }
4110 private void goToStageToolStripMenuItem_Click(object sender, EventArgs e)
4111 {
4112 update = true;
4113 GoToStage();
4114 }
4121 private void moveStageToImageToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
4122 {
4123 int i = 0;
4124 foreach (var item in Images)
4125 {
4126 if (item.ID.Contains(e.ClickedItem.Text))
4127 {
4129 return;
4130 }
4131 i++;
4132 }
4133 }
4134
4139 private void moveStageToImageToolStripMenuItem_Click(object sender, EventArgs e)
4140 {
4142 }
4143 private void layersToolStripMenuItem_Click(object sender, EventArgs e)
4144 {
4145 if (layersTool == null)
4146 layersTool = new Layers();
4147 layersTool.Show();
4148 }
4153 private void pictureBox_SizeChanged(object sender, EventArgs e)
4154 {
4155 if (ViewWidth < 2 || ViewHeight < 2) return;
4156 if (SelectedImage.isPyramidal)
4157 {
4158 if (SelectedImage.isPyramidal)
4159 UpdateImages();
4160 }
4161 }
4162 private void contextMenuStrip_Opening(object sender, CancelEventArgs e)
4163 {
4164 App.viewer = this;
4165 if (App.tabsView != null)
4166 Function.Initialize();
4167 }
4168 private void hideOverviewToolStripMenuItem_Click(object sender, EventArgs e)
4169 {
4170 if (hideOverViewToolStripMenuItem.Text == "Hide Overview")
4171 {
4172 ShowOverview = false;
4173 hideOverViewToolStripMenuItem.Text = "Show Overview";
4174 }
4175 else
4176 {
4177 ShowOverview = true;
4178 hideOverViewToolStripMenuItem.Text = "Hide Overview";
4179 }
4180 UpdateOverviewVisibility();
4181 }
4182 private void removeImageToolStripMenuItem_Click(object sender, EventArgs e)
4183 {
4185 }
4186
4187 private void removeImagesToolStripMenuItem_Click(object sender, EventArgs e)
4188 {
4189 RemoveImages();
4190 }
4191 #region OpenSlide
4192 private OpenSlideBase _openSlideBase;
4193 private SlideBase _slideBase;
4194
4198 private void Initialize(string file, BioImage bm)
4199 {
4200 if (bm.Type != BioImage.ImageType.pyramidal)
4201 return;
4202 if (bm.OpenSlideBase == null)
4203 {
4204 _slideBase = bm.SlideBase;
4205 slideRenderer = new SlideRenderer(gl);
4206 slideRenderer.SetSource(_slideBase);
4207 }
4208 else
4209 {
4210 _openSlideBase = bm.OpenSlideBase;
4211 slideRenderer = new SlideRenderer(gl);
4212 slideRenderer.SetSource(_openSlideBase);
4213 }
4214 }
4215
4216 #endregion
4217
4218 private sealed class BufferedViewPanel : Panel
4219 {
4220 public BufferedViewPanel()
4221 {
4222 SetStyle(ControlStyles.UserPaint |
4223 ControlStyles.AllPaintingInWmPaint |
4224 ControlStyles.OptimizedDoubleBuffer |
4225 ControlStyles.ResizeRedraw, true);
4226 }
4227 }
4228
4229 }
4230}
AForge.Bitmap Bitmap
AForge.RectangleD RectangleD
AForge.RectangleF RectangleF
AForge.Rectangle Rectangle
AForge.PointF PointF
System.Drawing.SizeF SizeF
System.Drawing.Image Image
Definition ImageView.cs:16
System.Windows.Forms.Keys Keys
Definition ImageView.cs:17
System.Windows.Forms.Application Application
Definition ImageView.cs:14
AForge.PointD PointD
System.Drawing.Graphics Graphics
Definition OMERO.cs:14
BioLib.BioImage BioImage
Definition TabsView.cs:15
AForge.ZCT ZCT
Definition TabsView.cs:17
static Tools tools
Definition App.cs:21
static TabsView tabsView
Definition App.cs:16
static ChannelsTool channelsTool
Definition App.cs:15
static ImageView viewer
Definition App.cs:23
static bool down
Definition ImageView.cs:303
PointD PyramidalOriginTransformed
List< BioImage > Images
Definition ImageView.cs:323
float ToScreenScaleH(double y)
new AForge.SizeF Scale
Scale when opening image stacks.
Definition ImageView.cs:779
List< ROI > AnnotationsRGB
PointD ImageToViewSpace(double x, double y)
static bool showText
Definition ImageView.cs:319
List< ROI > AnnotationsG
bool ShowControls
Setting the visibility of the trackBarPanel. *‍/.
Definition ImageView.cs:539
Channel RChannel
A property that returns the R channel of the selected image. *‍/.
Definition ImageView.cs:667
float ToScreenH(double y)
static bool Ctrl
Definition ImageView.cs:307
PointD Origin
A property of the class PointD. *‍/.
Definition ImageView.cs:718
void DrawView(System.Drawing.Graphics g)
Draws the viewport when Hardware Acceleration is off.
PointF[] ToScreenSpace(PointD[] p)
PointF ToScreenScale(PointD p)
List< ROI > AnnotationsR
PointD PyramidalOrigin
Setting the value of the pyramidalOrigin variable. *‍/.
Definition ImageView.cs:730
void SetCoordinate(int z, int c, int t)
Definition ImageView.cs:431
void UpdateView(bool refreshImages=true)
void RemoveImage(int i)
PointD ToScreenSpace(double x, double y)
float ToScreenW(double x)
PointD ToViewSpace(PointD p)
RectangleD[] ToScreenSpace(RectangleD[] p)
ImageView(BioImage im, bool OpenWithOpenSlide=true)
Initializing the image viewer. *‍/.
Definition ImageView.cs:36
List< ROI > AnnotationsB
SKRect ToSKRect(double x, double y, double w, double h)
ViewMode Mode
Setting the view mode of the application. *‍/.
Definition ImageView.cs:609
double PxHmicron
Only used when opening stacks.
Definition ImageView.cs:588
PointF[] ToScreenSpace(PointF[] p)
int TimeFps
Setting the interval of the timer to the value of the timefps variable. *‍/.
Definition ImageView.cs:843
int CFps
Setting the interval of the timer to the inverse of the fps. *‍/.
Definition ImageView.cs:859
PointF ToViewSpace(PointF p)
PointF ToScreenSpace(PointF p)
RectangleD ToScreenSpace(RectangleD p)
double ToViewW(double d)
void UpdateSelectBoxSize(float size)
Definition ImageView.cs:937
void CopySelection()
It takes the selected ROIs and copies them to the clipboard.
void GoToImage(int i)
Channel GChannel
A property that returns the G channel of the image. *‍/.
Definition ImageView.cs:675
bool ShowStatus
Setting the value of the property ShowStatus. *‍/.
Definition ImageView.cs:556
static bool showBounds
Definition ImageView.cs:318
static List< ROI > selectedAnnotations
Definition ImageView.cs:267
ImageView()
Initializing the ImageView class. *‍/.
Definition ImageView.cs:121
override bool ProcessCmdKey(ref Message msg, Keys keyData)
Definition ImageView.cs:150
Channel BChannel
Getting the B channel of the image. *‍/.
Definition ImageView.cs:683
string Path
A property that returns the filepath. *‍/.
Definition ImageView.cs:659
int ZFps
Setting the interval of the timer to the value of the fps. *‍/.
Definition ImageView.cs:827
double PxWmicron
Only used when opening stacks.
Definition ImageView.cs:573
void ImageView_KeyDown(object sender, KeyEventArgs e)
void UpdateViewLegacy(bool refresh)
RectangleF[] ToScreenSpace(RectangleF[] p)
float ToScreenScaleW(double x)
RectangleD ToScreenRect(double x, double y, double w, double h)
static PointD mouseDown
Definition ImageView.cs:302
int SelectedIndex
A property that is used to set the selected index of the image. *‍/.
Definition ImageView.cs:390
static BioImage SelectedImage
Definition ImageView.cs:270
RectangleD ToScreenSpace(RectangleF p)
static PointD mouseUp
Definition ImageView.cs:304
static Bitmap SelectedBuffer
Definition ImageView.cs:295
int Level
Current level when viewing whole-slide and pyramidal images.
Definition ImageView.cs:765
PointD ToViewSpace(double x, double y)
void AddImage(BioImage im)
Definition ImageView.cs:475
static MouseButtons mouseUpButtons
Definition ImageView.cs:315
double GetSelectionBoxHitSize()
PointF ToScreenSpace(Point3D p)
List< Layer > Layers
Definition ImageView.cs:254
static MouseButtons mouseDownButtons
Definition ImageView.cs:316
void MoveStageToImage(int i)
PointD ToScreenSpace(PointD p)
double ToViewH(double d)
async void UpdateImages(bool updatePyramidal=true)
ContextMenuStrip ViewContextMenu
A property that returns a ContextMenuStrip object. *‍/.
Definition ImageView.cs:794
double Resolution
A property of the class ImageViewer. It is a getter and setter for the resolution of the image.
Definition ImageView.cs:746
double ToViewSizeH(double d)
static RectangleD GetViewRectangle(bool update)
static Stage Stage
static void KeyDownEvent(object o, KeyEventArgs e)
Definition Plugin.cs:71
static void Paint(object o, PaintEventArgs e)
Definition Plugin.cs:92
static void KeyUpEvent(object o, KeyEventArgs e)
Definition Plugin.cs:64
static void Render(object o, PaintEventArgs e)
Definition Plugin.cs:99
void SetPosition(double px, double py)
Definition Microscope.cs:69
void UpdateViewMode(ImageView.ViewMode v)
Definition TabsView.cs:715
void ToolMove(PointD e, MouseButtons buts)
Definition Tools.cs:585
void ToolUp(PointD e, MouseButtons buts)
Definition Tools.cs:431
void ToolDown(PointD e, MouseButtons buts)
Definition Tools.cs:259
static bool GetKeyState(System.Windows.Forms.Keys vKey)
Definition Win32.cs:24
Layer(double d, bool enabled)
Definition ImageView.cs:247