using OSGeo.GDAL; using OSGeo.OGR; using OSGeo.OSR; using System; using System.Collections.Generic; using System.Data.SQLite; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace Kingo.Plugin.RasterToKOTilesApp.KoDataBase { public class RasterInfo : IDisposable { public string Projection { get; private set; } public Dataset Dataset { get; private set; } public int XSize { get; set; } public int YSize { get; set; } public double TransScale { get; set; } public Envelope Extent { get; set; } public double[] Geotransform { get; private set; } public int Bands { get; private set; } private RasterInfo() { } public static RasterInfo Create(string fileName) { try { //消除中文路径无法识别的问题 OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); Dataset dataset = Gdal.Open(fileName, Access.GA_ReadOnly); return Create(dataset); } catch (Exception ex) { return null; } } public static RasterInfo Create(Dataset dataset) { RasterInfo pRasterInfo = new RasterInfo(); pRasterInfo.Dataset = dataset; pRasterInfo.XSize = pRasterInfo.Dataset.RasterXSize; pRasterInfo.YSize = pRasterInfo.Dataset.RasterYSize; pRasterInfo.Geotransform = new double[6]; pRasterInfo.Dataset.GetGeoTransform(pRasterInfo.Geotransform); double north = pRasterInfo.Geotransform[3]; double south = pRasterInfo.Geotransform[3] + pRasterInfo.Geotransform[5] * pRasterInfo.YSize; double east = pRasterInfo.Geotransform[0] + pRasterInfo.Geotransform[1] * pRasterInfo.XSize; double west = pRasterInfo.Geotransform[0]; if (Math.Round(pRasterInfo.Geotransform[1] + pRasterInfo.Geotransform[5], 1) != 0) throw new Exception("栅格对象被压缩"); pRasterInfo.TransScale = pRasterInfo.Geotransform[1]; pRasterInfo.Bands = pRasterInfo.Dataset.RasterCount; //this.ScaleY = geotransform[5]; pRasterInfo.Projection = pRasterInfo.Dataset.GetProjection(); pRasterInfo.Extent = new Envelope() { XMax = east, XMin = west, YMax = north, YMin = south }; return pRasterInfo; } public void Dispose() { Dataset.Dispose(); } } public delegate List CompareTileInfo(List tileInfos); public class MultRaster2MBTiles { static MultRaster2MBTiles() { } public ImageFormat ImgFormat { get; set; } public int Level { get; set; } public Layer TopLayer { get; set; } private List Rasters = new List(); private Dataset topRasterDs = null; private RasterInfo topRaster = null; public int CompressRate { get; set; } = 25; /// /// 相交 /// public event CompareTileInfo CompareIntersect = null; public EnumSaveType SaveType { get; set; } public void Dispose() { if (topRasterDs != null) topRasterDs.Dispose(); if (topRaster != null) topRaster.Dispose(); } public MultRaster2MBTiles() { //Rasters = new List(); //codecInfo = GetEncoder(ImageFormat.Png); //System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality; //EncoderParameters myEncoderParameters = new EncoderParameters(1); //EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder,8); //myEncoderParameters.Param[0] = myEncoderParameter; //encoderParameters = myEncoderParameters; ImgFormat = ImageFormat.Jpeg; } private Envelope rasterExtent; public int TiledSize { get; set; } public string MBTilesPath { get; set; } private List GetAllTiles(Envelope extent, Envelope envelopeCut = null) { List tiles = new List(); double originX = extent.XMin; double originY = extent.YMax; for (int level = 0; level < Level; level++) { int count = (int)Math.Pow(2, level); double del = extent.Width / count; for (int col = 0; col < count; col++) { for (int row = 0; row < count; row++) { double minx = originX + col * del; double maxy = originY - row * del; Envelope e = new Envelope() { XMin = minx, YMin = maxy - del, XMax = minx + del, YMax = maxy }; if (envelopeCut != null) { if (!e.Intersects(envelopeCut)) continue; } tiles.Add(new TileInfo(e, level, row, col)); } } } return tiles; } public static Rectangle Envelope2Rect(RasterInfo rasterInfo, Envelope extent) { //int width = (int)((extent.XMax - extent.XMin) / rasterInfo.TransScale + 0.5); //int height = (int)((extent.YMax - extent.YMin) / rasterInfo.TransScale + 0.5); //int x = (int)((rasterInfo.Extent.XMax - extent.XMax) / rasterInfo.TransScale + 0.5); //int y = (int)((rasterInfo.Extent.YMax - extent.YMax) / rasterInfo.TransScale + 0.5); //return new Rectangle(x, y, width, height); Rectangle rect = Envelope2Rect(rasterInfo.Extent, extent, rasterInfo.TransScale); if (rect.Right > rasterInfo.XSize) { rect.Width -= rect.Right - rasterInfo.XSize; } if (rect.Bottom > rasterInfo.YSize) { rect.Height -= rect.Bottom - rasterInfo.YSize; } return rect; } public static Rectangle Envelope2Rect(Envelope baseExtent, Envelope extent, double resolution) { int width = (int)((extent.XMax - extent.XMin) / resolution + 0.5); int height = (int)((extent.YMax - extent.YMin) / resolution + 0.5); int x = (int)((extent.XMin - baseExtent.XMin) / resolution + 0.5); int y = (int)((baseExtent.YMax - extent.YMax) / resolution + 0.5); return new Rectangle(x, y, width, height); } private Envelope GetExtent() { return GetExtent(this.Rasters); } private static Envelope GetExtent(List rasters) { Envelope extent = rasters[0].Extent; ; for (int i = 1; i < rasters.Count; i++) { extent = extent.Union(rasters[i].Extent); } return extent; } private static Envelope GetExtentZ(Envelope e) { Envelope extent = new Envelope() { XMax = e.XMax, XMin = e.XMin, YMax = e.YMax, YMin = e.YMin }; double del = (extent.Width - extent.Height) / 2; if (del > 0) { extent.YMax += del; extent.YMin -= del; } else { extent.XMax -= del; extent.XMin += del; } return extent; } private Envelope maxExtent = null; private string EnCode(object value) { if (value == null) return ""; string str = value.ToString(); return str; if (string.IsNullOrEmpty(str)) return ""; string outStr = ""; foreach (char item in str) { outStr += (char)(item + 22); } return outStr; } //多线程去切 private List readRasterList = new List(); private WriteDatabase pWriteDatabase = null; public void CreateMulFilesKOTiles(List files, int threadnumber, bool converWebMercator, SpatialReference spatialReference, Envelope envelopeCut = null) { foreach (var fileName in files) { try { RasterInfo raster = RasterInfo.Create(fileName); if (converWebMercator == true) { if (spatialReference != null) { Dataset mercatorDataSet = GdalWarp(fileName, spatialReference); if (mercatorDataSet != null) raster = RasterInfo.Create(mercatorDataSet); } } if (raster != null) Rasters.Add(raster); } catch (Exception ex) { Console.WriteLine("获取影像信息失败:" + ex.Message); }; } //创建遮罩层 if (TopLayer != null) CreateLayer(); //计算全部图层的最小外接正方形 this.rasterExtent = GetExtent(); maxExtent = GetExtentZ(rasterExtent); //开始切片,获取范围内的瓦片 //根据层级开始计算网格个数 List allTiles = GetAllTiles(maxExtent, envelopeCut); List> tileGroups = new List>(); int start = 0; int count = allTiles.Count / threadnumber; if (topRasterDs != null) topRaster = RasterInfo.Create(topRasterDs); pWriteDatabase = new WriteDatabase(); for (int i = 0; i < threadnumber; i++) { if (i == threadnumber - 1) { count += allTiles.Count % threadnumber; } List tileGroup = allTiles.GetRange(start, count); start += count; ReadRaster pReadRaster = new ReadRaster() { ImgFormat = ImgFormat, TiledSize = TiledSize, TileInfos = tileGroup, TopRasterInfo = topRaster, CompressRate = this.CompressRate, Rasters = Rasters }; pReadRaster.Dowork(); pReadRaster.Event2 += (d, e) => { pWriteDatabase.InsertDataRange(d as TileInfo[]); }; readRasterList.Add(pReadRaster); } SQLiteConnection conn = null; if (SaveType == EnumSaveType.Level) conn = CreateDataBase(); else if (SaveType == EnumSaveType.Resolution) conn = CreateBestDataBase(); pWriteDatabase.Conn = conn; pWriteDatabase.TileCount = allTiles.Count; pWriteDatabase.Done += (s, e) => { if (topRaster != null) topRaster.Dispose(); if (topRasterDs != null) { topRasterDs.Dispose(); topRasterDs = null; } if (TopLayer != null) { TopLayer.Dispose(); TopLayer = null; } this.CreatDown(s, e); }; pWriteDatabase.Report += (s, e) => { if (Report != null) { Report(s, e); } }; if (SaveType == EnumSaveType.Level) { pWriteDatabase.DoWorkLevel(); } else if (SaveType == EnumSaveType.Resolution) { pWriteDatabase.BestDoWork(); } } public void CreateMulFilesKOTiles(List files, int threadnumber, bool converWebMercator, Envelope envelopeCut = null) { foreach (string file in files) { try { RasterInfo rasterInfo = RasterInfo.Create(file); if (converWebMercator) { SpatialReference spatialReference = new SpatialReference(""); spatialReference.ImportFromEPSG(3857); Dataset dataset = GdalWarp(file, spatialReference); if (dataset != null) { rasterInfo = RasterInfo.Create(dataset); } } if (rasterInfo != null) { Rasters.Add(rasterInfo); } } catch { } } if (TopLayer != null) { CreateLayer(); } rasterExtent = GetExtent(); maxExtent = GetExtentZ(rasterExtent); List allTiles = GetAllTiles(maxExtent, envelopeCut); List> list = new List>(); int num = 0; int num2 = allTiles.Count / threadnumber; if (topRasterDs != null) { topRaster = RasterInfo.Create(topRasterDs); } pWriteDatabase = new WriteDatabase(); for (int i = 0; i < threadnumber; i++) { if (i == threadnumber - 1) { num2 += allTiles.Count % threadnumber; } List range = allTiles.GetRange(num, num2); num += num2; ReadRaster readRaster = new ReadRaster(files, converWebMercator) { ImgFormat = ImgFormat, TiledSize = TiledSize, TileInfos = range, TopRasterInfo = topRaster, CompressRate = CompressRate }; readRaster.Dowork(); readRaster.Event2 += delegate (object d, EventArgs e) { pWriteDatabase.InsertDataRange(d as TileInfo[]); }; readRasterList.Add(readRaster); } SQLiteConnection conn = null; if (SaveType == EnumSaveType.Level) { conn = CreateDataBase(); } else if (SaveType == EnumSaveType.Resolution) { conn = CreateBestDataBase(); } pWriteDatabase.Conn = conn; pWriteDatabase.TileCount = allTiles.Count; pWriteDatabase.Done += delegate (object s, EventArgs e) { if (topRaster != null) { topRaster.Dispose(); } if (topRasterDs != null) { topRasterDs.Dispose(); topRasterDs = null; } if (TopLayer != null) { TopLayer.Dispose(); TopLayer = null; } this.CreatDown(s, e); }; pWriteDatabase.Report += delegate (int s, int e) { if (this.Report != null) { this.Report(s, e); } }; if (SaveType == EnumSaveType.Level) { pWriteDatabase.DoWorkLevel(); } else if (SaveType == EnumSaveType.Resolution) { pWriteDatabase.BestDoWork(); } } public static Dataset GdalWarp(string inputFile, SpatialReference tileSpatialReference) { Dataset inputDataset = Gdal.OpenShared(inputFile, Access.GA_ReadOnly); OSGeo.OSR.SpatialReference sSpatialReference = inputDataset.GetSpatialRef(); if (sSpatialReference.IsSame(tileSpatialReference, null) > 0) { return inputDataset; } try { string tempFolder = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Temp"); if (!Directory.Exists(tempFolder)) { Directory.CreateDirectory(tempFolder); } string outputFile = System.IO.Path.Combine(tempFolder, Guid.NewGuid().ToString().Replace("-", "") + ".VRT"); tileSpatialReference.ExportToWkt(out string wkt, null); string[] options = new string[] { "-t_srs", wkt, "-r", "rms", "-of", "VRT" }; Gdal.GDALProgressFuncDelegate progressFuncDelegate = new Gdal.GDALProgressFuncDelegate((complete, msg, data) => { if (complete >= 1) { //isProgressCompleted = true; } return 1; }); return Gdal.Warp(outputFile, new Dataset[] { inputDataset }, new GDALWarpAppOptions(options), progressFuncDelegate, null); } finally { inputDataset.Dispose(); } } private SQLiteConnection CreateDataBase() { string connString = "Data Source=" + this.MBTilesPath; if (File.Exists(this.MBTilesPath)) { GC.Collect(); System.Windows.Forms.Application.DoEvents(); try { File.Delete(this.MBTilesPath); } catch (Exception ex) { Console.WriteLine("输出文件监测到被占用,请重试!" + ex.Message); } } string dir = Path.GetDirectoryName(this.MBTilesPath); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } try { File.WriteAllBytes(this.MBTilesPath, Properties.Resources.Template); } catch (Exception ex) { Console.WriteLine("创建数据库失败:" + ex.Message); } System.Data.SQLite.SQLiteConnection conn = new System.Data.SQLite.SQLiteConnection(connString); conn.Open(); try { SQLiteTransaction pTan = conn.BeginTransaction(); SQLiteCommand cmd = new SQLiteCommand(conn); string sqlFormat = "insert into metadata values('{0}','{1}')"; //写入图片大小 cmd.CommandText = string.Format(sqlFormat, "Size", EnCode(this.TiledSize)); int result= cmd.ExecuteNonQuery(); //写入图片格式 cmd.CommandText = string.Format(sqlFormat, "Format", EnCode(ImgFormat.ToString())); result=cmd.ExecuteNonQuery(); //写入空间参考 cmd.CommandText = string.Format(sqlFormat, "Projection", EnCode(this.Rasters[0].Dataset.GetProjection())); result = cmd.ExecuteNonQuery(); //写入Extend cmd.CommandText = string.Format(sqlFormat, "Bounds", EnCode(string.Format("{0},{1},{2},{3}", this.rasterExtent.XMin, rasterExtent.YMin, rasterExtent.XMax, rasterExtent.YMax))); result = cmd.ExecuteNonQuery(); //写入origin cmd.CommandText = string.Format(sqlFormat, "Origin", EnCode(string.Format("{0},{1}", maxExtent.XMin, maxExtent.YMax))); result = cmd.ExecuteNonQuery(); //写入分辨率 double dbResolution = maxExtent.Width / this.TiledSize; cmd.CommandText = string.Format(sqlFormat, "Resolution", EnCode(dbResolution)); result = cmd.ExecuteNonQuery(); //写入比例尺 double dbScale = (96 / 0.0254) * dbResolution; cmd.CommandText = string.Format(sqlFormat, "Scale", EnCode(dbScale)); result = cmd.ExecuteNonQuery(); //写入Level cmd.CommandText = string.Format(sqlFormat, "Level", EnCode(this.Level)); result = cmd.ExecuteNonQuery(); //写入Kingo cmd.CommandText = string.Format(sqlFormat, "Kingo", "false"); cmd.ExecuteNonQuery(); cmd.Dispose(); pTan.Commit(); pTan.Dispose(); } catch (Exception ex) { Console.WriteLine("写入metadata表数据失败:" + ex.Message); } finally { conn.Close(); GC.Collect(); } return conn; } public event EventHandler CreatDown; public event ProgressReport Report; private void CreateLayer() { // 注册所有的驱动 // Ogr.RegisterAll(); //Gdal.AllRegister(); //消除中文路径无法识别的问题 OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); //解决shape文件字段中文内容读取问题 OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8"); //获取transform Envelope maxEnvelope = GetExtent(this.Rasters); int[] rasterSize = GetRasterSize(maxEnvelope); double[] geoTransform = GetGeoTransform(maxEnvelope, rasterSize[0], rasterSize[1]); Layer layer = TopLayer; topRasterDs = null; string tempFile = Application.StartupPath + "\\temp.img"; if (File.Exists(tempFile)) File.Delete(tempFile); OSGeo.GDAL.Driver dirver = Gdal.GetDriverByName("HFA");//MEM HFA GTiff topRasterDs = dirver.Create(tempFile, rasterSize[0], rasterSize[1], 1, DataType.GDT_Byte, null); topRasterDs.SetProjection(this.Rasters[0].Projection); topRasterDs.SetGeoTransform(geoTransform); Gdal.GDALProgressFuncDelegate callback = new Gdal.GDALProgressFuncDelegate(GDALProgressFuncDelegate); try { int rst = Gdal.RasterizeLayer(topRasterDs, 1, new int[] { 1 }, layer, IntPtr.Zero, IntPtr.Zero, 1, new double[] { 255 }, new string[] { "ALL_TOUCHED=TRUE" }, callback, "callback"); } catch (Exception ex) { } } private double[] GetGeoTransform(Envelope envelope, int x, int y) { double[] geoTransform = new double[6]; geoTransform[0] = envelope.XMin; geoTransform[1] = envelope.Width / x; geoTransform[2] = 0; geoTransform[3] = envelope.YMax; geoTransform[4] = 0; geoTransform[5] = -envelope.Height / y; return geoTransform; } private int[] GetRasterSize(Envelope envelope) { int[] rasterSize = new int[2]; rasterSize[0] = (int)(envelope.Width / 10); rasterSize[1] = (int)(envelope.Height / 10); return rasterSize; } bool isComplete = false; private int GDALProgressFuncDelegate(double Complete, IntPtr Message, IntPtr Data) { if (Complete >= 1) { isComplete = true; } return 1; } #region 裁取图斑最高分辨率 2015-11-11 chendewen private SQLiteConnection CreateBestDataBase() { string connString = "Data Source=" + this.MBTilesPath; if (File.Exists(this.MBTilesPath)) { GC.Collect(); System.Windows.Forms.Application.DoEvents(); try { File.Delete(this.MBTilesPath); } catch (Exception ex) { throw new Exception("输出文件监测到被占用,请重试!"); } } string dir = Path.GetDirectoryName(this.MBTilesPath); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } File.WriteAllBytes(this.MBTilesPath, Properties.Resources.model); System.Data.SQLite.SQLiteConnection conn = new System.Data.SQLite.SQLiteConnection(connString); return conn; } #endregion } public class TileInfo { public Envelope Bound { get; private set; } public int Level { get; private set; } public int Row { get; private set; } public int Column { get; private set; } public byte[] Data { get; set; } public double Resolution { get; set; } public TileInfo(Envelope bound, int level, int row, int col) { this.Bound = bound; this.Level = level; this.Row = row; this.Column = col; } } internal class ReadRaster : IDisposable { public ImageFormat ImgFormat { get; set; } public int TiledSize { get; set; } public List Rasters { get; set; } public List TileInfos { get; set; } public int CompressRate { get; set; } = 25; public ReadRaster() { } public RasterInfo TopRasterInfo { get; set; } public ReadRaster(List files, bool converWebMercator) { Rasters = new List(); foreach (var fileName in files) { try { RasterInfo raster = RasterInfo.Create(fileName); if (converWebMercator == true) { SpatialReference spatialReference = new SpatialReference(""); spatialReference.ImportFromEPSG(3857); Dataset mercatorDataSet = GdalWarp(fileName, spatialReference); if (mercatorDataSet != null) raster = RasterInfo.Create(mercatorDataSet); } if (raster != null) Rasters.Add(raster); } catch { }; } } private static Dataset GdalWarp(string inputFile, SpatialReference tileSpatialReference) { Dataset inputDataset = Gdal.OpenShared(inputFile, Access.GA_ReadOnly); OSGeo.OSR.SpatialReference sSpatialReference = inputDataset.GetSpatialRef(); if (sSpatialReference.IsSame(tileSpatialReference, null) > 0) { return inputDataset; } try { string tempFolder = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Temp"); if (!Directory.Exists(tempFolder)) { Directory.CreateDirectory(tempFolder); } string outputFile = System.IO.Path.Combine(tempFolder, Guid.NewGuid().ToString().Replace("-", "") + ".VRT"); tileSpatialReference.ExportToWkt(out string wkt, null); string[] options = new string[] { "-t_srs", wkt, "-r", "rms", "-of", "VRT" }; Gdal.GDALProgressFuncDelegate progressFuncDelegate = new Gdal.GDALProgressFuncDelegate((complete, msg, data) => { if (complete >= 1) { //isProgressCompleted = true; } return 1; }); return Gdal.Warp(outputFile, new Dataset[] { inputDataset }, new GDALWarpAppOptions(options), progressFuncDelegate, null); } finally { inputDataset.Dispose(); } } //创建单个瓦片 private void CreateKOTiles(TileInfo tile) { try { byte[] bgra = new byte[TiledSize * TiledSize * 4]; double resolution = tile.Bound.Width / this.TiledSize; bool isExist = false; byte[] rgbTop = null; Rectangle dTopRect = new Rectangle(); if (TopRasterInfo != null) { Envelope topEnvelope = tile.Bound.Intersection(TopRasterInfo.Extent); if (topEnvelope != null) { try { Rectangle sTopRect = MultRaster2MBTiles.Envelope2Rect(TopRasterInfo, topEnvelope); dTopRect = MultRaster2MBTiles.Envelope2Rect(tile.Bound, topEnvelope, resolution); rgbTop = new byte[dTopRect.Width * dTopRect.Height]; CPLErr err = TopRasterInfo.Dataset.GetRasterBand(1).ReadRaster(sTopRect.X, sTopRect.Y, sTopRect.Width, sTopRect.Height, rgbTop, dTopRect.Width, dTopRect.Height, 0, 0); if (err != CPLErr.CE_None) { Console.WriteLine(string.Format("读取Level:{0},Column:{1},Row:{2}的瓦片出错!", tile.Level, tile.Column, tile.Row)); } } catch (Exception ex) { //Console.WriteLine(string.Format("读取Level:{0},Column:{1},Row:{2}的瓦片出错!", tile.Level, tile.Column, tile.Row)); } //填充数据到bgra for (int i = 0; i < dTopRect.Width; i++) { for (int j = 0; j < dTopRect.Height; j++) { try { int offset = i + j * dTopRect.Width; byte rVal = rgbTop[offset]; if (rVal > 250) { isExist = true; break; } } catch (Exception ex) { Console.WriteLine("填充数据到bgra失败:" + ex.Message); } } } } //没有数据 if (!isExist) return; } foreach (var raster in Rasters) { Envelope pEnvelope = tile.Bound.Intersection(raster.Extent); if (pEnvelope == null) continue; Rectangle sRect = MultRaster2MBTiles.Envelope2Rect(raster, pEnvelope); Rectangle dRect = MultRaster2MBTiles.Envelope2Rect(tile.Bound, pEnvelope, resolution); if (raster.Bands > 2) { byte[] rgb = new byte[dRect.Width * dRect.Height * 3]; try { CPLErr err = raster.Dataset.ReadRaster(sRect.X, sRect.Y, sRect.Width, sRect.Height, rgb, dRect.Width, dRect.Height, 3, new int[] { 1, 2, 3 }, 0, 0, 0); if (err != CPLErr.CE_None) { Console.WriteLine(string.Format("读取Level:{0},Column:{1},Row:{2}的瓦片出错!", tile.Level, tile.Column, tile.Row)); } } catch (Exception ex) { } //填充数据到bgra for (int i = 0; i < dRect.Width; i++) { for (int j = 0; j < dRect.Height; j++) { try { int offset = i + j * dRect.Width; byte rVal = rgb[offset]; byte gVal = rgb[offset + dRect.Width * dRect.Height]; byte bVal = rgb[offset + dRect.Width * dRect.Height * 2]; if ((rVal == 0 && gVal == 0 && bVal == 0) || (rVal == 255 && gVal == 255 && bVal == 255)) { continue; } int pixelPos = (dRect.X + i) + (dRect.Y + j) * this.TiledSize; bgra[pixelPos * 4] = bVal; bgra[pixelPos * 4 + 1] = gVal; bgra[pixelPos * 4 + 2] = rVal; bgra[pixelPos * 4 + 3] = 255; } catch (Exception ex) { Console.WriteLine("填充数据到bgra失败:" +ex.Message); } } } } else { byte[] r = new byte[dRect.Width * dRect.Height]; try { CPLErr err = raster.Dataset.GetRasterBand(1).ReadRaster(sRect.X, sRect.Y, sRect.Width, sRect.Height, r, dRect.Width, dRect.Height, 0, 0); if (err != CPLErr.CE_None) { Console.WriteLine(string.Format("读取Level:{0},Column:{1},Row:{2}的瓦片出错!", tile.Level, tile.Column, tile.Row)); } } catch (Exception ex) { } //填充数据到bgra for (int i = 0; i < dRect.Width; i++) { for (int j = 0; j < dRect.Height; j++) { try { int offset = i + j * dRect.Width; byte rVal = r[offset]; if (rVal < 5) continue; int pixelPos = (dRect.X + i) + (dRect.Y + j) * this.TiledSize; bgra[pixelPos * 4] = rVal; bgra[pixelPos * 4 + 1] = rVal; bgra[pixelPos * 4 + 2] = rVal; bgra[pixelPos * 4 + 3] = 255; } catch (Exception ex) { Console.WriteLine("填充数据到bgra失败:" + ex.Message); } } } } } if (rgbTop != null) { //填充数据到bgra for (int i = 0; i < dTopRect.Width; i++) { for (int j = 0; j < dTopRect.Height; j++) { try { int offset = i + j * dTopRect.Width; byte rVal = rgbTop[offset]; if (rVal > 250) { continue; } int pixelPos = (dTopRect.X + i) + (dTopRect.Y + j) * this.TiledSize; bgra[pixelPos * 4] = 255; bgra[pixelPos * 4 + 1] = 255; bgra[pixelPos * 4 + 2] = 255; bgra[pixelPos * 4 + 3] = 0; } catch (Exception ex) { Console.WriteLine("填充数据到bgra失败:" + ex.Message); } } } } int dataHasValue = 0; for (int i = 0; i < TiledSize * TiledSize; i++) { if (bgra[i * 4 + 3] != 0) { dataHasValue++; } } //没有数据 if (dataHasValue < 1) return; //写入数据文件 using (MemoryStream ms = new MemoryStream()) { Bitmap bitmap = new Bitmap(TiledSize, TiledSize, System.Drawing.Imaging.PixelFormat.Format32bppArgb); try { BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb); try { Marshal.Copy(bgra, 0, bitmapData.Scan0, bgra.Length); } catch (Exception ex) { Console.WriteLine("拷贝bgra失败:" + ex.Message); } finally { bitmap.UnlockBits(bitmapData); } if (ImageFormat.Jpeg.Equals(ImgFormat) || dataHasValue > this.TiledSize * (this.TiledSize - 1)) { EncoderParameter p; EncoderParameters ps; ps = new EncoderParameters(1); p = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)this.CompressRate); ps.Param[0] = p; ImageCodecInfo pngEncoder = GetEncoder(ImageFormat.Jpeg); bitmap.Save(ms, pngEncoder, ps); } else { string path = AppDomain.CurrentDomain.BaseDirectory + @"pngquant\pngquant.exe"; if (File.Exists(path)) { PngQuant.Run(bitmap, ms, path); } else { bitmap.Save(ms, ImageFormat.Png); } } } catch (Exception ex) { Console.WriteLine("写入数据文件失败:" + ex.Message); } finally { bitmap.Dispose(); } tile.Data = ms.ToArray(); tile.Resolution = resolution; } } catch (Exception ex) { Console.WriteLine("创建单个瓦片失败:" + ex.Message); } } bool isY = false; private ImageCodecInfo GetEncoder(ImageFormat format) { ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders(); foreach (ImageCodecInfo codec in codecs) { if (codec.FormatID == format.Guid) { return codec; } } return null; } private Thread doThread; public event EventHandler Event2; public void Dowork() { doThread = new Thread(new ThreadStart(read)); doThread.IsBackground = true; doThread.Name = "读取图片线程" + Guid.NewGuid().ToString(); doThread.Priority = ThreadPriority.Highest; doThread.Start(); } private List doneList = new List(); public void read() { foreach (var item in TileInfos) { try { CreateKOTiles(item); } catch (Exception ex) { Console.WriteLine("读取图片线程异常" + ex.Message); } finally { doneList.Add(item); if (doneList.Count > 20) { Event2?.Invoke(doneList.ToArray(), null); doneList.Clear(); } } } if (doneList.Count > 0) { Event2?.Invoke(doneList.ToArray(), null); doneList.Clear(); } Console.WriteLine(doThread.Name + "结束"); } public void Stop() { this.Dispose(); } public void Dispose() { if (this.doThread != null) { try { this.doThread.Abort(); } catch { } finally { this.doThread = null; } } } } public delegate void ProgressReport(int sum, int current); internal class WriteDatabase : IDisposable { public event ProgressReport Report; public SQLiteConnection Conn { get; set; } public int TileCount { get; set; } private List needInsertDataList = new List(); public void InsertDataRange(TileInfo[] data) { lock (needInsertDataList) { needInsertDataList.AddRange(data); } } Thread doworkThread = null; public event EventHandler Done; public void Dispose() { if (doworkThread != null) { try { doworkThread.Abort(); } catch { } finally { doworkThread = null; } } } public void BestDoWork() { doworkThread = new Thread(new ThreadStart(WriteTodb)); doworkThread.IsBackground = true; doworkThread.Name = "写入图片线程" + Guid.NewGuid().ToString(); doworkThread.Start(); } private void WriteTodb() { Conn.Open(); try { SQLiteTransaction pTan = Conn.BeginTransaction(); SQLiteCommand cmd = new SQLiteCommand(Conn); cmd.CommandText = "insert into tiles (centerX,centerY,maxX,maxY,minX,minY,resolution,tile_Data) values(@centerX,@centerY,@maxX,@maxY,@minX,@minY,@resolution,@tile_Data)"; cmd.Parameters.Add(new SQLiteParameter("@centerX", System.Data.DbType.Double)); cmd.Parameters.Add(new SQLiteParameter("@centerY", System.Data.DbType.Double)); cmd.Parameters.Add(new SQLiteParameter("@maxX", System.Data.DbType.Double)); cmd.Parameters.Add(new SQLiteParameter("@maxY", System.Data.DbType.Double)); cmd.Parameters.Add(new SQLiteParameter("@minX", System.Data.DbType.Double)); cmd.Parameters.Add(new SQLiteParameter("@minY", System.Data.DbType.Double)); cmd.Parameters.Add(new SQLiteParameter("@resolution", System.Data.DbType.Double)); cmd.Parameters.Add(new SQLiteParameter("@tile_Data", System.Data.DbType.Binary)); int dealTileCount = 0; while (dealTileCount < TileCount) { TileInfo[] datas = null; lock (needInsertDataList) { datas = needInsertDataList.ToArray(); needInsertDataList.Clear(); } if (datas == null || datas.Length == 0) { Thread.Sleep(1000); } else { foreach (var item in datas) { if (item.Data == null) continue; cmd.Parameters[0].Value = (item.Bound.XMax - item.Bound.XMin) / 2 + item.Bound.XMin; cmd.Parameters[1].Value = (item.Bound.YMax - item.Bound.YMin) / 2 + item.Bound.YMin; cmd.Parameters[2].Value = item.Bound.XMax; cmd.Parameters[3].Value = item.Bound.YMax; cmd.Parameters[4].Value = item.Bound.XMin; cmd.Parameters[5].Value = item.Bound.YMin; cmd.Parameters[6].Value = item.Resolution; cmd.Parameters[7].Value = item.Data; cmd.ExecuteNonQuery(); item.Data = null; } dealTileCount += datas.Length; if (Report != null) { Report(TileCount, dealTileCount); } } Thread.Sleep(0); } cmd.CommandText = "CREATE INDEX tiles_index ON tiles (centerX,centerY,maxX,maxY,minX,minY);"; cmd.ExecuteNonQuery(); pTan.Commit(); pTan.Dispose(); if (Done != null) { Done(null, null); } } finally { Conn.Close(); Conn.Dispose(); SQLiteConnection.ClearPool(Conn); Thread.Sleep(10); GC.Collect(); Thread.Sleep(10); } } Thread doworkThreadLevel = null; public void DoWorkLevel() { //doworkThreadLevel = new Thread(new ThreadStart(WriteTodbLevel)); //doworkThreadLevel.IsBackground = true; //doworkThreadLevel.Name = "写入图片线程" + Guid.NewGuid().ToString(); //doworkThreadLevel.Start(); WriteTodbLevel(); } private void WriteTodbLevel() { Conn.Open(); try { SQLiteTransaction pTan = Conn.BeginTransaction(); SQLiteCommand cmd = new SQLiteCommand(Conn); cmd.CommandText = "insert into tiles (zoom_level,tile_column,tile_row,tile_data) values(@zoom_level,@tile_column,@tile_row,@tile_data)"; cmd.Parameters.Add(new SQLiteParameter("@zoom_level", System.Data.DbType.Int32)); cmd.Parameters.Add(new SQLiteParameter("@tile_column", System.Data.DbType.Int32)); cmd.Parameters.Add(new SQLiteParameter("@tile_row", System.Data.DbType.Int32)); cmd.Parameters.Add(new SQLiteParameter("@tile_data", System.Data.DbType.Binary)); int dealTileCount = 0; while (dealTileCount < TileCount) { TileInfo[] datas = null; lock (needInsertDataList) { datas = needInsertDataList.ToArray(); needInsertDataList.Clear(); } if (datas == null || datas.Length == 0) { Thread.Sleep(1000); } else { foreach (var item in datas) { if (item.Data == null) continue; cmd.Parameters[0].Value = item.Level; cmd.Parameters[1].Value = item.Column; cmd.Parameters[2].Value = item.Row; cmd.Parameters[3].Value = item.Data; cmd.ExecuteNonQuery(); item.Data = null; } dealTileCount += datas.Length; if (Report != null) { Report(TileCount, dealTileCount); } } //Thread.Sleep(3000); Thread.Sleep(0); } cmd.CommandText = "CREATE INDEX tiles_index ON tiles (zoom_level,tile_column,tile_row);"; cmd.ExecuteNonQuery(); cmd.Dispose(); pTan.Commit(); pTan.Dispose(); if (Done != null) { Done(null, null); } } catch (Exception ex) { Console.WriteLine("图片写入db失败:" + ex.Message); } finally { Conn.Close(); Conn.Dispose(); SQLiteConnection.ClearPool(Conn); Thread.Sleep(10); GC.Collect(); Thread.Sleep(10); } } } public class UnionVector { public static Layer UnionVectorLayers(List layers, double distance = 100.0) { Layer rstLayer = null; Geometry rstGeometry = null; foreach (Layer item in layers) { rstGeometry = UnionGeometry(rstGeometry, UnionVectorLayer(item)); } //double distance = 100.0; //double.TryParse(System.Configuration.ConfigurationManager.AppSettings["BufferDistance"], out distance); if (rstGeometry == null) return null; rstGeometry = rstGeometry.Buffer(distance, 30); OSGeo.OGR.Driver ogrDirver = Ogr.GetDriverByName("Memory"); DataSource dsLayers = ogrDirver.CreateDataSource("", null); rstLayer = dsLayers.CreateLayer("", null, wkbGeometryType.wkbPolygon, null); Feature f = new Feature(rstLayer.GetLayerDefn()); f.SetGeometry(rstGeometry); rstLayer.CreateFeature(f); return rstLayer; } public static Geometry UnionVectorLayer(Layer layer) { Feature feature = layer.GetNextFeature(); if (feature == null) return null; Geometry rstGeometry = feature.GetGeometryRef(); while ((feature = layer.GetNextFeature()) != null) { Geometry geo = feature.GetGeometryRef(); try { rstGeometry = rstGeometry.Union(geo); } catch { } } return rstGeometry; } public static Geometry UnionGeometry(Geometry geometry1, Geometry geometry2) { if (geometry1 == null) return geometry2; return geometry1.Union(geometry2); } public static Layer UnionVectorLayers(List layerPaths, double distance = 100.0) { //消除中文路径无法识别的问题 OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); //解决shape文件字段中文内容读取问题 OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8"); List layers = new List(); foreach (LayerInfo item in layerPaths) { DataSource dataSource = Ogr.Open(item.LayerSourcePath, 0); if (string.IsNullOrEmpty(item.LayerName)) layers.Add(dataSource.GetLayerByIndex(0)); else layers.Add(dataSource.GetLayerByName(item.LayerName)); } return UnionVectorLayers(layers, distance); } public static Layer CreateLayer(List geometrys, double distance = 100.0) { //消除中文路径无法识别的问题 OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); //解决shape文件字段中文内容读取问题 OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8"); Geometry rstGeometry = null; foreach (Geometry item in geometrys) { rstGeometry = UnionGeometry(rstGeometry, item); } if (rstGeometry == null) return null; Layer rstLayer = null; rstGeometry = rstGeometry.Buffer(distance, 30); OSGeo.OGR.Driver ogrDirver = Ogr.GetDriverByName("Memory"); DataSource dsLayers = ogrDirver.CreateDataSource("", null); rstLayer = dsLayers.CreateLayer("", null, wkbGeometryType.wkbPolygon, null); Feature f = new Feature(rstLayer.GetLayerDefn()); f.SetGeometry(rstGeometry); rstLayer.CreateFeature(f); return rstLayer; } public static List GetVectorLayerFeatures(List layerPaths) { //消除中文路径无法识别的问题 OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); //解决shape文件字段中文内容读取问题 OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8"); List layers = new List(); foreach (LayerInfo item in layerPaths) { DataSource dataSource = Ogr.Open(item.LayerSourcePath, 0); Layer layer = null; if (string.IsNullOrEmpty(item.LayerName)) { layer = dataSource.GetLayerByIndex(0); } else { layer = dataSource.GetLayerByName(item.LayerName); } if (layer != null) layers.AddRange(GetLayerFeatures(layer)); } return layers; } private static List GetLayerFeatures(Layer layer) { List lst = new List(); Feature feature = layer.GetNextFeature(); if (feature == null) return null; int fieldNameIndex = layer.FindFieldIndex("XIJXZQMC", 0); int fieldCodeIndex = layer.FindFieldIndex("XIJXZQDM", 0); while ((feature = layer.GetNextFeature()) != null) { FeatureInfo featureInfo = new FeatureInfo(); if (fieldCodeIndex >= 0) { featureInfo.Code = feature.GetFieldAsString("XIJXZQDM"); } if (fieldNameIndex >= 0) { featureInfo.Name = feature.GetFieldAsString("XIJXZQMC"); } featureInfo.Shape = feature; lst.Add(featureInfo); } return lst; } public static Layer CreateVectorLayer(FeatureInfo featureInfo) { Layer rstLayer = null; OSGeo.OGR.Driver ogrDirver = Ogr.GetDriverByName("Memory"); DataSource dsLayers = ogrDirver.CreateDataSource("", null); rstLayer = dsLayers.CreateLayer("", null, wkbGeometryType.wkbPolygon, null); rstLayer.CreateFeature(featureInfo.Shape); return rstLayer; } /// /// 获取影像 /// /// /// /// public static List GetTileInfosByLayer(LayerInfo layerInfo, double distance = 100.0) { DataSource dataSource = null; Layer layer = null; try { List tileInfos = new List(); dataSource = Ogr.Open(layerInfo.LayerSourcePath, 0); if (string.IsNullOrEmpty(layerInfo.LayerName)) layer = dataSource.GetLayerByIndex(0); else layer = dataSource.GetLayerByName(layerInfo.LayerName); Feature feature = null; OSGeo.OGR.Envelope geoEnvelope = new OSGeo.OGR.Envelope(); while ((feature = layer.GetNextFeature()) != null) { Geometry geo = feature.GetGeometryRef(); geo = geo.Buffer(distance, 30); geo.GetEnvelope(geoEnvelope); if (geoEnvelope != null) { Envelope e = new Envelope() { XMin = geoEnvelope.MinX, YMin = geoEnvelope.MinY, XMax = geoEnvelope.MaxX, YMax = geoEnvelope.MaxY }; tileInfos.Add(new TileInfo(e, 0, 0, 0)); geoEnvelope.Dispose(); geoEnvelope = new OSGeo.OGR.Envelope(); } } return tileInfos; } catch (Exception ex) { throw ex; } finally { if (dataSource != null) { dataSource.Dispose(); } if (layer != null) { layer.Dispose(); } } } } public class LayerInfo { public string LayerSourcePath { get; set; } public string LayerName { get; set; } public int LayerIndex { get; set; } } public class FeatureInfo { public string Name { get; set; } public string Code { get; set; } public Feature Shape { get; set; } } public enum EnumSaveType { Level = 0, Resolution = 1 } }