private Bitmap ReadRegion(SizeL location, int level, SizeL size) { Stopwatch sw = new Stopwatch(); sw.Start(); OpenSlide.TraceMsg("start ReadRegion " + level + "/" + location.Height + "_" + location.Width + ": " + GetBytesReadable(size.Width * size.Height * 3)); Bitmap bmp = new Bitmap((int)size.Width, (int)size.Height); bmp.SetPixel(0, 0, Color.AliceBlue); var bmpdata = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb); OpenSlide.TraceMsg("bmp locked " + level + "/" + location.Height + "_" + location.Width); unsafe { void *p = bmpdata.Scan0.ToPointer(); openslide_read_region(handle, p, location.Width, location.Height, level, size.Width, size.Height); } OpenSlide.TraceMsg("read finished " + level + "/" + location.Height + "_" + location.Width + ": " + GetBytesReadable(size.Width * size.Height * 3 / Math.Max(sw.ElapsedMilliseconds, 1)) + "/ms"); bmp.UnlockBits(bmpdata); OpenSlide.TraceMsg("unlock bits " + level + "/" + location.Height + "_" + location.Width); if (bmp.GetPixel(0, 0) == Color.Black) { var error = CheckForLastError(); if (error != null) { throw new ArgumentException($"error reading region loc:{location}, level:{level}, size:{size}" + error); } //else just a black image? } OpenSlide.TraceMsg("end ReadRegion " + level + "/" + location.Height + "_" + location.Width); return(bmp); }
private SKBitmap ReadRegion(SizeL location, int level, SizeL size) { Stopwatch sw = new Stopwatch(); sw.Start(); OpenSlide.TraceMsg("start ReadRegion " + level + "/" + location.Height + "_" + location.Width + ": " + GetBytesReadable(size.Width * size.Height * 3)); SKBitmap bmp = new SKBitmap((int)size.Width, (int)size.Height); bmp.SetPixel(0, 0, SKColors.AliceBlue); bmp.LockPixels(); var bmpdata = bmp.GetPixels(); OpenSlide.TraceMsg("bmp locked " + level + "/" + location.Height + "_" + location.Width); unsafe { void *p = bmpdata.ToPointer(); Import.openslide_read_region(handle, p, location.Width, location.Height, level, size.Width, size.Height); } OpenSlide.TraceMsg("read finished " + level + "/" + location.Height + "_" + location.Width + ": " + GetBytesReadable(size.Width * size.Height * 3 / Math.Max(sw.ElapsedMilliseconds, 1)) + "/ms"); bmp.UnlockPixels(); OpenSlide.TraceMsg("unlock bits " + level + "/" + location.Height + "_" + location.Width); if (bmp.GetPixel(0, 0) == SKColors.Black) { var error = CheckForLastError(); if (error != null) { throw new ArgumentException($"error reading region loc:{location}, level:{level}, size:{size}" + error); } //else just a black image? } OpenSlide.TraceMsg("end ReadRegion " + level + "/" + location.Height + "_" + location.Width); return(bmp); }
public MemoryStream GetTile(int level, long row, long col) { OpenSlide.TraceMsg("start gettile " + level + "/" + col + "_" + row); if (level < 0 || level >= max_dz_level) { throw new ArgumentException($"wrong level level {level}, row {row}, col {col}"); } if (t_dimensions[level].Width <= col || t_dimensions[level].Height <= row || 0 > col || 0 > row) { throw new ArgumentException($"wrong address level {level}, row {row}, col {col}"); } var os_level = os_level_for_dz_level[level]; //Calculate top/ left and bottom/ right overlap var z_overlap_tl = new SizeL(col == 0 ? 0 : 1, row == 0 ? 0 : 1); var z_overlap_br = new SizeL(col == t_dimensions[level].Width ? 0 : 1, row == t_dimensions[level].Height ? 0 : 1); var z_size = new SizeL(Math.Min(TILE_DOWNSAMPLE, z_dimensions[level].Width - TILE_DOWNSAMPLE * col) + z_overlap_tl.Width + z_overlap_br.Width, Math.Min(TILE_DOWNSAMPLE, z_dimensions[level].Height - TILE_DOWNSAMPLE * row) + z_overlap_tl.Height + z_overlap_br.Height); if (z_size.Width < 0 || z_size.Height < 0) { throw new ArgumentException($"out of bounds level {level}, row {row}, col {col}"); } var z_location = new SizeL(TILE_DOWNSAMPLE * col, TILE_DOWNSAMPLE * row); var l_location = new System.Drawing.SizeF((float)l_z_downsamples[level] * (z_location.Width - z_overlap_tl.Width), (float)l_z_downsamples[level] * (z_location.Height - z_overlap_tl.Height)); //Round location down and size up, and add offset of active area var l0_location = new SizeL((long)(downsamples[os_level] * l_location.Width), (long)(downsamples[os_level] * l_location.Height)); var l_size = new SizeL((long)Math.Min(Math.Ceiling(l_z_downsamples[level] * z_size.Width), dimensions[os_level].Width), (long)Math.Min(Math.Ceiling(l_z_downsamples[level] * z_size.Height), dimensions[os_level].Height)); OpenSlide.TraceMsg("calcs done " + level + "/" + col + "_" + row); var bmp = ReadRegion(l0_location, os_level, l_size); if (l_size.Width != z_size.Width || l_size.Height != z_size.Height) { //only resize when necessary OpenSlide.TraceMsg("resize " + level + "/" + col + "_" + row); var oldbmp = bmp; bmp = new SKBitmap((int)z_size.Width, (int)z_size.Height); oldbmp.Resize(bmp, SKBitmapResizeMethod.Box); } OpenSlide.TraceMsg("new bmp " + level + "/" + col + "_" + row); var stream = new MemoryStream(); //Prints tile coords for testing //var g = Graphics.FromImage(resizedbmp); //g.DrawString(level + "/" + col + "_" + row, new Font(FontFamily.GenericSansSerif, 18), new SolidBrush(Color.Black), resizedbmp.Width / 2, resizedbmp.Height / 2); bmp.Encode(new SKManagedWStream(stream), SKEncodedImageFormat.Jpeg, 80); OpenSlide.TraceMsg("end gettile " + level + "/" + col + "_" + row); stream.Position = 0; return(stream); }
public MemoryStream GetJpg(string filename, string path) { //url = '/<ID>_files/<int:level>/<int:col>_<int:row>.<format>' OpenSlide.TraceMsg("start getjpg " + path); var m = rxDZ.Match(path); if (m.Success) { var ost = GetOpenSlide(filename); OpenSlide.TraceMsg("open os " + path); var level = Int32.Parse(m.Groups[1].Value); var col = Int64.Parse(m.Groups[2].Value); var row = Int64.Parse(m.Groups[3].Value); var ret = ost.GetTile(level, row, col); OpenSlide.TraceMsg("end getjpg " + path); return(ret); } return(null); }
public Openslide(string filename) { OpenSlide.TraceMsg("start openslide " + filename); origfile = filename; if (!File.Exists(filename)) { throw new ArgumentException($"File '{filename}' can't be opened"); } handle = openslide_open(filename); unsafe { if (handle == null || handle[0] == 0) { var vendor = openslide_detect_vendor(filename); //GetLastError(); if (vendor.ToInt32() != 0) { throw new ArgumentException("Vendor " + Marshal.PtrToStringAnsi(vendor) + " unsupported?"); } else { throw new ArgumentException("File unrecognized"); } } } OpenSlide.TraceMsg("opened openslide " + filename); max_os_level = openslide_get_level_count(handle); if (max_os_level == -1) { GetLastError(); } for (int level = 0; level < max_os_level; level++) { long w = 0, h = 0; openslide_get_level_dimensions(handle, level, out w, out h); if (w == -1 || h == -1) { GetLastError(); } dimensions.Add(new SizeL(w, h)); var downsample = openslide_get_level_downsample(handle, level); if (downsample == -1.0) { GetLastError(); } downsamples.Add(downsample); } InitZDimensions(); t_dimensions = z_dimensions.Select(x => new SizeL((long)Math.Ceiling(x.Width / (double)TILE_DOWNSAMPLE), (long)Math.Ceiling(x.Height / (double)TILE_DOWNSAMPLE))).ToArray(); max_dz_level = z_dimensions.Count; l0_z_downsamples = Enumerable.Range(0, max_dz_level).Select(x => (int)Math.Pow(2, max_dz_level - x - 1)).ToArray(); os_level_for_dz_level = l0_z_downsamples.Select(x => { var best_level = openslide_get_best_level_for_downsample(handle, x * 1.01); if (best_level == -1) { GetLastError(); } return(best_level); }).ToArray(); l_z_downsamples = Enumerable.Range(0, max_dz_level).Select(l => l0_z_downsamples[l] / downsamples[os_level_for_dz_level[l]]).ToArray(); InitEasyLevels(); OpenSlide.TraceMsg("end openslide " + filename); }