You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
536 lines
21 KiB
536 lines
21 KiB
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; |
|
|
|
|
|
} |
|
} |
|
}
|
|
|