年度变更建库软件5.0版本
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.

537 lines
21 KiB

4 months ago
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;
}
}
}