using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Drawing; using OSGeo.GDAL; using System.Data.SQLite; using System.IO; using System.Drawing.Imaging; using System.Runtime.InteropServices; namespace Kingo.Plugin.RasterToKOTilesApp.KoDataBase { class Raster2MBTiles { public ImageFormat ImgFormat { get; set; } private Envelope rasterExtent; private Envelope gridExtent; private Rectangle rasterRect; private Rectangle gridRect; public int Level { get; set; } //public Color TransparentColor { get; set; } public int TiledSize { get; set; } public string MBTilesPath { get; set; } public Raster2MBTiles() { ImgFormat = ImageFormat.Jpeg; } //private //设定层级,瓦片尺寸大小,计算初始网格, //获取栅格数据的范围 // private void CreateGrid() { } private Dataset dataset = null; public void Open(string fileName) { //@"C:\Users\admin\Desktop\img\3203212013SPOT6DOM.img" Gdal.AllRegister(); dataset = Gdal.Open(fileName, Access.GA_ReadOnly); int xsize = dataset.RasterXSize; int ysize = dataset.RasterYSize; double[] geotransform = new double[6]; dataset.GetGeoTransform(geotransform); double north = geotransform[3]; double south = geotransform[3] + geotransform[5] * ysize; double east = geotransform[0] + geotransform[1] * xsize; double west = geotransform[0]; //获取栅格范围 this.rasterExtent = new Envelope() { XMax = east, XMin = west, YMax = north, YMin = south }; this.rasterRect = new Rectangle(0, 0, xsize, ysize); //计算最小外接正方形 double width = east - west; double height = north - south; double maxLength = width > height ? width : height; this.gridExtent = new Envelope() { YMax = north + (maxLength - height) / 2, YMin = south - (maxLength - height) / 2, XMax = east + (maxLength - width) / 2, XMin = west - (maxLength - width) / 2, }; int gridWidth = xsize > ysize ? xsize : ysize; this.gridRect = new Rectangle(0, 0, gridWidth, gridWidth); //CreateMBTiles2(dataset); } private void CreateMBTiles(Dataset dataset) { string dir = System.Windows.Forms.Application.StartupPath + "\\Tiles"; if (!System.IO.Directory.Exists(dir)) { System.IO.Directory.CreateDirectory(dir); } for (int level = 0; level < Level; level++) { int count = (int)Math.Pow(2, level); int delSize = (int)(this.gridRect.Width / count); for (int col = 0; col < count; col++) { int offsetx = col * delSize; int sizex = delSize; int BufferWidth = TiledSize; bool isOutX = (offsetx + delSize) >= this.rasterRect.Width; if (isOutX) { //计算x方向真正的偏移量 sizex = this.rasterRect.Width - offsetx; BufferWidth = (int)((sizex * 1.0 / delSize) * TiledSize); } for (int row = 0; row < count; row++) { int offsety = row * delSize; int sizey = delSize; int BufferHeight = TiledSize; bool isOutY = (offsety + delSize) >= this.rasterRect.Height; if (isOutY) { //计算y方向真正的偏移量 sizey = this.rasterRect.Height - offsety; BufferHeight = (int)((sizey * 1.0 / delSize) * TiledSize); } //读取数据 Bitmap bitmap = new Bitmap(TiledSize, TiledSize, System.Drawing.Imaging.PixelFormat.Format32bppPArgb); int bufferSize = BufferWidth * BufferHeight; int[] r = new int[bufferSize]; Band band1 = dataset.GetRasterBand(1); band1.ReadRaster(offsetx, offsety, sizex, sizey, r, BufferWidth, BufferHeight, 0, 0); //读取图像到内存 int[] g = new int[bufferSize]; Band band2 = dataset.GetRasterBand(2); band2.ReadRaster(offsetx, offsety, sizex, sizey, g, BufferWidth, BufferHeight, 0, 0); int[] b = new int[bufferSize]; Band band3 = dataset.GetRasterBand(3); band3.ReadRaster(offsetx, offsety, sizex, sizey, b, BufferWidth, BufferHeight, 0, 0); int i, j, numNoColor = 0; for (i = 0; i < BufferWidth; i++) { for (j = 0; j < BufferHeight; j++) { int cur = i + j * BufferWidth; if (r[cur] != 0 || g[cur] != 0 || b[cur] != 0) { Color newColor = Color.FromArgb(255, r[cur], g[cur], b[cur]); bitmap.SetPixel(i, j, newColor); } else { numNoColor++; } } } if (numNoColor != bufferSize) { //写入数据文件 bitmap.Save(string.Format("{0}\\{1}-{2}-{3}.png", dir, level, col, row)); } else { } bitmap.Dispose(); //越界后停止读取 if (isOutY) { break; } } //越界后停止读取 if (isOutX) { break; } } } } public void CreateMBTiles2() { string connString = "Data Source=" + this.MBTilesPath; if (File.Exists(this.MBTilesPath)) { File.Delete(this.MBTilesPath); } File.WriteAllBytes(this.MBTilesPath, Properties.Resources.Template); System.Data.SQLite.SQLiteConnection conn = new System.Data.SQLite.SQLiteConnection(connString); 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)); CreateKOTiles(cmd); cmd.CommandText = "CREATE INDEX tiles_index ON tiles (zoom_level,tile_column,tile_row);"; cmd.ExecuteNonQuery(); string sqlFormat = "insert into metadata values('{0}','{1}')"; //写入图片大小 cmd.CommandText = string.Format(sqlFormat, "Size", this.TiledSize); cmd.ExecuteNonQuery(); //写入图片格式 cmd.CommandText = string.Format(sqlFormat, "Format", "png"); cmd.ExecuteNonQuery(); //写入空间参考 cmd.CommandText = string.Format(sqlFormat, "Projection", this.dataset.GetProjection()); cmd.ExecuteNonQuery(); //写入Extend cmd.CommandText = string.Format(sqlFormat, "Bounds", string.Format("{0},{1},{2},{3}", this.rasterExtent.XMin, rasterExtent.YMin, rasterExtent.XMax, rasterExtent.YMax)); cmd.ExecuteNonQuery(); //写入origin cmd.CommandText = string.Format(sqlFormat, "Origin", string.Format("{0},{1}", rasterExtent.XMin, rasterExtent.YMax)); cmd.ExecuteNonQuery(); //写入分辨率 double dbResolution = (this.gridExtent.XMax - this.gridExtent.XMin) / this.TiledSize; cmd.CommandText = string.Format(sqlFormat, "Resolution", dbResolution); cmd.ExecuteNonQuery(); //写入比例尺 double dbScale = (96 / 0.0254) * dbResolution; cmd.CommandText = string.Format(sqlFormat, "Scale", dbScale); cmd.ExecuteNonQuery(); //写入Level cmd.CommandText = string.Format(sqlFormat, "Level", this.Level); cmd.ExecuteNonQuery(); cmd.Dispose(); pTan.Commit(); pTan.Dispose(); } catch (Exception ex) { throw; } finally { conn.Close(); GC.Collect(); } } private void CreateKOTiles(SQLiteCommand cmd) { for (int level = 0; level < Level; level++) { int count = (int)Math.Pow(2, level); double delSize = this.gridRect.Width * 1.0 / count; for (int col = 0; col < count; col++) { double offsetx = col * delSize; double sizex = delSize; int bufferWidth = TiledSize; bool isOutX = (offsetx + delSize) >= this.rasterRect.Width; if (isOutX) { //计算x方向真正的偏移量 sizex = this.rasterRect.Width - offsetx; bufferWidth = (int)Math.Round((sizex / delSize) * TiledSize); } for (int row = 0; row < count; row++) { double offsety = row * delSize; double sizey = delSize; int bufferHeight = TiledSize; bool isOutY = (offsety + delSize) >= this.rasterRect.Height; if (isOutY) { //计算y方向真正的偏移量 sizey = this.rasterRect.Height - offsety; bufferHeight = (int)Math.Round((sizey / delSize) * TiledSize); } //读取数据 byte[] bytes = GetBitmap(bufferWidth, bufferHeight, (int)Math.Round(offsetx), (int)Math.Round(offsety), (int)Math.Round(sizex), (int)Math.Round(sizey)); if (bytes != null) { cmd.Parameters[0].Value = level; cmd.Parameters[1].Value = col; cmd.Parameters[2].Value = row; cmd.Parameters[3].Value = bytes; cmd.ExecuteNonQuery(); //for (int i = 0; i < 10000; i++) //{ // cmd.ExecuteNonQuery(); //} //return; //bitmap.Save(string.Format("{0}\\{1}-{2}-{3}.png", dir, level, col, row)); //File.WriteAllBytes(string.Format("{0}\\tiles\\{1}-{2}-{3}.png", System.Windows.Forms.Application.StartupPath, level, col, row),bytes); } //越界后停止读取 if (isOutY) { break; } } //越界后停止读取 if (isOutX) { break; } } } } private byte[] GetBitmap(int bufferWidth, int bufferHeight, int offsetx, int offsety, int sizex, int sizey) { int bufferSize = bufferWidth * bufferHeight; byte[] argb = new byte[TiledSize * TiledSize * 4]; for (int i = 0; i < TiledSize * TiledSize; i++) { argb[i * 4] = 255; argb[i * 4 + 1] = 255; argb[i * 4 + 2] = 255; } int numNoColor = 0; if (this.dataset.RasterCount >= 3) { byte[] rgb = new byte[bufferSize * 3]; dataset.ReadRaster(offsetx, offsety, sizex, sizey, rgb, bufferWidth, bufferHeight, 3, new int[] { 1, 2, 3 }, 0, 0, 0); int i, j; for (i = 0; i < bufferWidth; i++) { for (j = 0; j < bufferHeight; j++) { int offset = i + j * bufferWidth; byte rVal = rgb[offset]; byte gVal = rgb[offset + bufferSize]; byte bVal = rgb[offset + bufferSize * 2]; if (rVal != 0 || gVal != 0 || bVal != 0) { int pixelPos = i + j * this.TiledSize; argb[pixelPos * 4] = bVal; argb[pixelPos * 4 + 1] = gVal; argb[pixelPos * 4 + 2] = rVal; argb[pixelPos * 4 + 3] = 255; //Color newColor = Color.FromArgb(255, rVal, gVal, bVal); //bitmap.SetPixel(i, j, newColor); } else { numNoColor++; } } } } else { //bitmap.LockBits( byte[] r = new byte[bufferSize]; Band band1 = dataset.GetRasterBand(1); band1.ReadRaster(offsetx, offsety, sizex, sizey, r, bufferWidth, bufferHeight, 0, 0); int i, j; for (i = 0; i < bufferWidth; i++) { for (j = 0; j < bufferHeight; j++) { int offset = i + j * bufferWidth; byte rVal = r[offset]; if (rVal != 0) { int pixelPos = i + j * this.TiledSize; argb[pixelPos * 4] = rVal; argb[pixelPos * 4 + 1] = rVal; argb[pixelPos * 4 + 2] = rVal; argb[pixelPos * 4 + 3] = 255; //Color newColor = Color.FromArgb(255, rVal, rVal, rVal); //bitmap.SetPixel(i, j, newColor); } else { numNoColor++; } } } } if (numNoColor != bufferSize) { //写入数据文件 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(argb, 0, bitmapData.Scan0, argb.Length); } finally { bitmap.UnlockBits(bitmapData); } bitmap.Save(ms, ImgFormat); } finally { bitmap.Dispose(); } return ms.ToArray(); } } return null; } public void Close() { if (dataset != null) { dataset.Dispose(); dataset = null; } } } public class Envelope { public double XMax { get; set; } public double YMax { get; set; } public double XMin { get; set; } public double YMin { get; set; } public double Width { get { return this.XMax - this.XMin; } } public double Height { get { return this.YMax - this.YMin; } } public Envelope() { } public Envelope(double x1, double y1, double x2, double y2) { //this.XMin = double.NaN; //this.XMax = double.NaN; //this.YMin = double.NaN; //this.YMax = double.NaN; //this.XMin = Math.Min(x1, x2); //this.YMin = Math.Min(y1, y2); //this.XMax = Math.Max(x1, x2); //this.YMax = Math.Max(y1, y2); this.XMin = double.NaN; this.XMax = double.NaN; this.YMin = double.NaN; this.YMax = double.NaN; this.XMin = Math.Min(x1, x2); this.YMin = Math.Min(y1, y2); this.XMax = Math.Max(x1, x2); this.YMax = Math.Max(y1, y2); } public Envelope Intersection(Envelope extent) { if (!this.Intersects(extent)) { return null; } //return new Envelope(Math.Max(this.XMin, extent.XMin), Math.Max(this.YMin, extent.YMin), Math.Min(this.XMax, extent.XMax), Math.Min(this.YMax, extent.YMax)); return new Envelope(Math.Max(this.XMin, extent.XMin), Math.Max(this.YMin, extent.YMin), Math.Min(this.XMax, extent.XMax), Math.Min(this.YMax, extent.YMax)); } public bool Intersects(Envelope other) { if (other == null) { return false; } return ((((other.XMin <= this.XMax) && (other.XMax >= this.XMin)) && (other.YMin <= this.YMax)) && (other.YMax >= this.YMin)); //return ((((other.XMin <= this.XMax) && (other.XMax >= this.XMax)) && (other.YMin <= this.YMin)) && (other.YMax >= this.YMax)); } public bool Within(Envelope other) { return ((((this.XMin >= other.XMin) && (this.XMax <= other.XMax)) && (this.YMin >= other.YMin)) && (this.YMax <= other.YMax)); } public Envelope Union(Envelope extent) { Envelope envelope = new Envelope(); if (extent == null) { extent = this; } if (double.IsNaN(this.XMin)) { envelope.XMin = extent.XMin; } else if (double.IsNaN(extent.XMin)) { envelope.XMin = this.XMin; } else { envelope.XMin = Math.Min(extent.XMin, this.XMin); } if (double.IsNaN(this.XMax)) { envelope.XMax = extent.XMax; } else if (double.IsNaN(extent.XMax)) { envelope.XMax = this.XMax; } else { envelope.XMax = Math.Max(extent.XMax, this.XMax); } if (double.IsNaN(this.YMin)) { envelope.YMin = extent.YMin; } else if (double.IsNaN(extent.YMin)) { envelope.YMin = this.YMin; } else { envelope.YMin = Math.Min(extent.YMin, this.YMin); } if (double.IsNaN(this.YMax)) { envelope.YMax = extent.YMax; return envelope; } if (double.IsNaN(extent.YMax)) { envelope.YMax = this.YMax; return envelope; } envelope.YMax = Math.Max(extent.YMax, this.YMax); return envelope; } } }