/// <summary> /// Render the full raster block by block, and then save the values to the pyramid raster. /// This will probably be nasty and time consuming, but what can you do. /// </summary> /// <param name="pyrFile">File name of the file the pyramid image should be saved to.</param> /// <param name="progressHandler">The progress handler.</param> /// <returns>The created pyramid image.</returns> public IImageData CreatePyramidImage(string pyrFile, IProgressHandler progressHandler) { PyramidImage py = new PyramidImage(pyrFile, DataSet.Bounds); int width = DataSet.Bounds.NumColumns; int blockHeight = 32000000 / width; if (blockHeight > DataSet.Bounds.NumRows) { blockHeight = DataSet.Bounds.NumRows; } int numBlocks = (int)Math.Ceiling(DataSet.Bounds.NumRows / (double)blockHeight); int count = DataSet.NumRows; if (_symbolizer.ShadedRelief.IsUsed) { count = count * 2; } ProgressMeter pm = new ProgressMeter(progressHandler, "Creating Pyramids", count); PerformanceCounter pcRemaining = new PerformanceCounter("Memory", "Available Bytes"); Process proc = Process.GetCurrentProcess(); for (int j = 0; j < numBlocks; j++) { int h = blockHeight; if (j == numBlocks - 1) { h = DataSet.Bounds.NumRows - (j * blockHeight); } #if DEBUG var mem = proc.PrivateMemorySize64 / 1000000; var freeRam = Convert.ToInt64(pcRemaining.NextValue()) / 1000000; Debug.WriteLine("Memory before: " + mem + ", " + freeRam + " remaining."); #endif pm.BaseMessage = "Reading from Raster"; pm.SendProgress(); using (IRaster r = DataSet.ReadBlock(0, j * blockHeight, width, h)) { byte[] vals = new byte[h * 4 * width]; r.DrawToBitmap(Symbolizer, vals, width * 4, pm); pm.BaseMessage = "Writing to Pyramids"; pm.SendProgress(); py.WriteWindow(vals, j * blockHeight, 0, h, width, 0); Symbolizer.HillShade = null; } #if DEBUG mem = proc.PrivateMemorySize64 / 1000000; freeRam = Convert.ToInt64(pcRemaining.NextValue()) / 1000000; Debug.WriteLine("Memory after: " + mem + "Mb | " + freeRam + " remaining Mb."); #endif } pm.Reset(); py.ProgressHandler = ProgressHandler; py.CreatePyramids(); py.WriteHeader(pyrFile); return(py); }
/// <summary> /// /// </summary> /// <param name="fileName"></param> /// <returns></returns> private IImageData OpenFile(string fileName) { Dataset dataset; try { dataset = Gdal.Open(fileName, Access.GA_Update); } catch { try { dataset = Gdal.Open(fileName, Access.GA_ReadOnly); } catch (Exception ex) { throw new GdalException(ex.ToString()); } } Band red = dataset.GetRasterBand(1); ColorInterp bandType = red.GetRasterColorInterpretation(); if (bandType != ColorInterp.GCI_PaletteIndex && bandType != ColorInterp.GCI_GrayIndex && bandType != ColorInterp.GCI_RedBand && bandType != ColorInterp.GCI_AlphaBand) { // This is an image, not a raster, so return null. dataset.Dispose(); dataset = null; return null; } GdalImage result = new GdalImage(fileName); if (result.Width > 8000 || result.Height > 8000) { // Firstly, if there are pyramids inside of the GDAL file itself, we can just work with this directly, // without creating our own pyramid image. // For now, we can't get fast, low-res versions without some kind of pyramiding happening. // since that can take a while for huge images, I'd rather do this once, and create a kind of // standardized file-based pyramid system. Maybe in future pyramid tiffs could be used instead? string pyrFile = Path.ChangeExtension(fileName, ".mwi"); if (File.Exists(pyrFile)) { if (File.Exists(Path.ChangeExtension(pyrFile, ".mwh"))) { return new PyramidImage(fileName); } File.Delete(pyrFile); } GdalImageSource gs = new GdalImageSource(fileName); PyramidImage py = new PyramidImage(pyrFile, gs.Bounds); int width = gs.Bounds.NumColumns; int blockHeight = 64000000 / width; if (blockHeight > gs.Bounds.NumRows) blockHeight = gs.Bounds.NumRows; int numBlocks = (int)Math.Ceiling(gs.Bounds.NumRows / (double)blockHeight); ProgressMeter pm = new ProgressMeter(ProgressHandler, "Copying Data To Pyramids", numBlocks * 2); //ProgressHandler.Progress("pyramid", 0, "Copying Data To Pyramids: 0% Complete"); Application.DoEvents(); for (int j = 0; j < numBlocks; j++) { int h = blockHeight; if (j == numBlocks - 1) { h = gs.Bounds.NumRows - j * blockHeight; } Stopwatch sw = new Stopwatch(); sw.Start(); byte[] vals = gs.ReadWindow(j * blockHeight, 0, h, width, 0); Debug.WriteLine("Reading Value time: " + sw.ElapsedMilliseconds); pm.CurrentValue = j * 2 + 1; sw.Reset(); sw.Start(); py.WriteWindow(vals, j * blockHeight, 0, h, width, 0); sw.Stop(); Debug.WriteLine("Writing Pyramid time: " + sw.ElapsedMilliseconds); pm.CurrentValue = (j + 1) * 2; } gs.Dispose(); pm.Reset(); py.ProgressHandler = ProgressHandler; py.CreatePyramids(); py.WriteHeader(pyrFile); return py; } result.Open(); return result; }
private IImageData OpenFile(string fileName) { var dataset = Helpers.Open(fileName); bool hasOverviews; using (var red = dataset.GetRasterBand(1)) { ColorInterp bandType = red.GetRasterColorInterpretation(); if (bandType != ColorInterp.GCI_PaletteIndex && bandType != ColorInterp.GCI_GrayIndex && bandType != ColorInterp.GCI_RedBand && bandType != ColorInterp.GCI_AlphaBand) { // This is an image, not a raster, so return null. dataset.Dispose(); return(null); } hasOverviews = red.GetOverviewCount() > 0; } GdalImage result = new GdalImage(fileName); // Firstly, if there are pyramids inside of the GDAL file itself, we can just work with this directly, // without creating our own pyramid image. if ((result.Width > 8000 || result.Height > 8000) && !hasOverviews) { // For now, we can't get fast, low-res versions without some kind of pyramiding happening. // since that can take a while for huge images, I'd rather do this once, and create a kind of // standardized file-based pyramid system. Maybe in future pyramid tiffs could be used instead? string pyrFile = Path.ChangeExtension(fileName, ".mwi"); if (File.Exists(pyrFile)) { if (File.Exists(Path.ChangeExtension(pyrFile, ".mwh"))) { return(new PyramidImage(fileName)); } File.Delete(pyrFile); } GdalImageSource gs = new GdalImageSource(fileName); PyramidImage py = new PyramidImage(pyrFile, gs.Bounds); int width = gs.Bounds.NumColumns; int blockHeight = 64000000 / width; if (blockHeight > gs.Bounds.NumRows) { blockHeight = gs.Bounds.NumRows; } int numBlocks = (int)Math.Ceiling(gs.Bounds.NumRows / (double)blockHeight); ProgressMeter pm = new ProgressMeter(ProgressHandler, "Copying Data To Pyramids", numBlocks * 2); //ProgressHandler.Progress("pyramid", 0, "Copying Data To Pyramids: 0% Complete"); Application.DoEvents(); for (int j = 0; j < numBlocks; j++) { int h = blockHeight; if (j == numBlocks - 1) { h = gs.Bounds.NumRows - j * blockHeight; } byte[] vals = gs.ReadWindow(j * blockHeight, 0, h, width, 0); pm.CurrentValue = j * 2 + 1; py.WriteWindow(vals, j * blockHeight, 0, h, width, 0); pm.CurrentValue = (j + 1) * 2; } gs.Dispose(); pm.Reset(); py.ProgressHandler = ProgressHandler; py.CreatePyramids(); py.WriteHeader(pyrFile); result.Dispose(); return(py); } result.Open(); return(result); }