74 PointD pyramidalOrigin,
79 BioImage? rgbZarr =
null,
80 int[]? rgbSelection =
null)
82 if (_openSlideBase ==
null && _slideBase ==
null)
84 if (viewportWidth <= 1 && viewportHeight <= 1)
86 var schema = _useOpenSlide ? _openSlideBase.Schema : _slideBase.Schema;
88 int level = TileUtil.GetLevel(schema.Resolutions, resolution);
89 var levelRes = schema.Resolutions[level];
90 double levelUnitsPerPixel = levelRes.UnitsPerPixel;
92 int[]? requestedRgbSelection = rgbSelection?.ToArray();
93 if (rgbZarr !=
null && requestedRgbSelection ==
null)
94 requestedRgbSelection =
new[] { 0, 1, 2 };
95 bool contentChanged = !_hasContentKey
96 || coordinate.Z != _contentZ
97 || coordinate.C != _contentC
98 || coordinate.T != _contentT
99 || !ReferenceEquals(rgbZarr, _contentRgbZarr)
100 || !SelectionsEqual(requestedRgbSelection, _contentRgbSelection);
105 int renderVersion = ++_renderVersion;
106 if (contentChanged || level != _currentLevel)
108 _glArea.ClearTextureCache();
109 _uploadedTiles.Clear();
110 _currentLevel = level;
113 _hasContentKey =
true;
114 _contentZ = coordinate.Z;
115 _contentC = coordinate.C;
116 _contentT = coordinate.T;
117 _contentRgbZarr = rgbZarr;
118 _contentRgbSelection = requestedRgbSelection;
121 double minX = pyramidalOrigin.X * resolution;
122 double minY = -pyramidalOrigin.Y * resolution;
123 double width = viewportWidth * resolution;
124 double height = viewportHeight * resolution;
125 var worldExtent =
new Extent(minX, minY - height, minX + width, minY);
128 var tileInfos = schema.GetTileInfos(worldExtent, level).ToList();
130 if (tileInfos.Count == 0)
132 var pixelExtent = OpenSlideGTK.ExtentEx.WorldToPixelInvertedY(worldExtent, resolution);
133 tileInfos = schema.GetTileInfos(pixelExtent, level).ToList();
136 int[]? rgbChannels = requestedRgbSelection;
140 if (rgbZarr ==
null && !_useOpenSlide)
141 await _slideBase.FetchTilesAsync(tileInfos.ToList(), level, coordinate, pyramidalOrigin,
new AForge.Size(viewportWidth, viewportHeight));
142 if (renderVersion != _renderVersion)
145 var renderInfos =
new List<TileRenderInfo>();
146 foreach (var tileInfo
in tileInfos)
148 if (!_glArea.HasTileTexture(tileInfo.Index))
153 int tileWidth = schema.GetTileWidth(level);
154 int tileHeight = schema.GetTileHeight(level);
155 int tilePixelWidth = (int)Math.Round(tileInfo.Extent.Width / levelUnitsPerPixel);
156 int tilePixelHeight = (int)Math.Round(tileInfo.Extent.Height / levelUnitsPerPixel);
157 tileData = await ZarrChannelView.ReadRgbTileAsync(rgbZarr, level,
158 tileInfo.Index.Col * tileWidth, tileInfo.Index.Row * tileHeight,
159 tilePixelWidth, tilePixelHeight, coordinate, rgbChannels!);
161 else if (_useOpenSlide)
162 tileData = await _openSlideBase.GetTileAsync(tileInfo);
164 tileData = await _slideBase.GetTileAsync(tileInfo, coordinate);
165 if (renderVersion != _renderVersion)
167 if (tileData !=
null && rgbZarr ==
null && rgbChannels !=
null)
169 tileData = (
byte[])tileData.Clone();
170 for (
int i = 0; i + 3 < tileData.Length; i += 4)
171 for (
int color = 0; color < 3; color++)
172 if (rgbChannels[color] < 0) tileData[i + color] = 0;
174 if (tileData !=
null)
176 int tW = (int)Math.Round(tileInfo.Extent.Width / levelUnitsPerPixel);
177 int tH = (int)Math.Round(tileInfo.Extent.Height / levelUnitsPerPixel);
186 int sourceWidth = schema.GetTileWidth(level);
187 int sourceHeight = schema.GetTileHeight(level);
188 if ((tW != sourceWidth || tH != sourceHeight) &&
189 tileData.Length >= sourceWidth * sourceHeight * 4)
191 byte[] clipped =
new byte[tW * tH * 4];
192 int copyBytes = tW * 4;
193 for (
int row = 0; row < tH; row++)
194 Buffer.BlockCopy(tileData, row * sourceWidth * 4,
195 clipped, row * copyBytes, copyBytes);
200 _glArea.UploadTileTexture(tileInfo.Index, tileData, tW, tH);
201 _uploadedTiles.Add(tileInfo.Index);
205 if (_glArea.HasTileTexture(tileInfo.Index))
207 var renderInfo = CalculateScreenPosition(
213 renderInfos.Add(renderInfo);
217 _glArea.SetTilesToRender(renderInfos);
218 _glArea.RequestRedraw();