/// <summary>
/// 读取影像的金字塔,从中提取取一个合适的级别,转成JPG格式,从而生成快视图
/// </summary>
/// <param name="dsin">源影像</param>
/// <param name="quickshowPath">生成JPG文件的路径</param>
/// <param name="scale">输入的参考比例(例如,输入10,表示生成一个长宽均为源影像1/10的格式,但由于各级金字塔的比例不一定与该值完全相等,为避免进行重采样计算,程序会找一个最接近的等级,所以最终的快视图比例与这个值不一定相等)</param>
/// <param name="quickShowWidth">生成的快视图宽度方向像素数</param>
/// <param name="quickShowHeight">生成的快视图高度方向像素数</param>
/// <param name="errMsg">错误信息</param>
/// <returns>是否生成成功</returns>
public bool pyramidToQuickshow(Dataset dsin, string quickshowPath,int scale,out int quickShowWidth,out int quickShowHeight, out string errMsg)
{
#region 一些基本检查
quickShowWidth = 0;
quickShowHeight = 0;
errMsg = "";
//确认是8BIT的影像数据
if (dsin.GetRasterBand(1).DataType != DataType.GDT_Byte)
{
errMsg = "暂不支持8位BYTE之外的数据";
return false;
}
//确认影像已经有金字塔
string[] files = dsin.GetFileList();
bool findRRD = false;
for (int i = 0; i < files.Length; i++)
{
if (files[i].ToLower().EndsWith(".rrd"))
{
findRRD = true;
break;
}
}
int pyramidCount = ds.GetRasterBand(1).GetOverviewCount();
if (!findRRD && pyramidCount == 0)
{
errMsg = "影像文件未建立金字塔";
return false;
}
#endregion
//用于输出的Driver,因为GDAL的JPEG Driver似乎不支持直接生成文件并写入,所以用一个内存Driver写入
//并复制一个JPEG
Driver drijpg = Gdal.GetDriverByName("JPEG");
Driver drimen = Gdal.GetDriverByName("MEM");
int rasterCount = dsin.RasterCount; //波段数
#region 找出与输入的scale最接近的金字塔等级,并将其确认为提取的等级,并记录该等级金字塔的长宽
int resLevel = 0, minVal = 0, resScale = 0;
for (int i = 0; i < pyramidCount; i++)
{
Band tmpBand = ds.GetRasterBand(1).GetOverview(i);
if (i == 0)
{
minVal = Math.Abs(ds.RasterXSize / tmpBand.XSize - scale);
resScale = ds.RasterXSize / tmpBand.XSize;
quickShowWidth = tmpBand.XSize;
quickShowHeight = tmpBand.YSize;
}
else
{
int tmpInt = Math.Abs(ds.RasterXSize / tmpBand.XSize - scale);
if (tmpInt < minVal)
{
minVal = tmpInt;
resLevel = i;
resScale = ds.RasterXSize / tmpBand.XSize;
quickShowWidth = tmpBand.XSize;
quickShowHeight = tmpBand.YSize;
}
}
}
#endregion
#region 读取各波段对应等级的金字塔,保存到一个列表中
List<Band> bands = new List<Band>(); //金字塔波段的列表
for (int i = 0; i < rasterCount; i++)
{
Band tmpBand = ds.GetRasterBand(i + 1).GetOverview(resLevel);
bands.Add(tmpBand);
}
#endregion
#region 新建快视图(JPG)对应的Dataset,并向其中写入数据
Dataset dout = drimen.Create(quickshowPath, quickShowWidth,quickShowHeight, rasterCount, DataType.GDT_Byte, null);
//为避免因影像过大无法一次读取并写入完毕,这里按进行读取和写入
//以下为按行读取的一些参数
int rows = 1000000 / quickShowWidth; //一次读取的行数(正常情况下)
int readCount = quickShowHeight / rows; //读取的次数
if (quickShowHeight % rows != 0) readCount++; //不能整除的话,还需要多读一次
byte[] raw = null; //读取和写入用到的数组
//开始读取并写入数据
for (int i = 0; i < bands.Count ; i++)
{
int tmpHeight = rows; //一次读取的行数
raw = new byte[rows * quickShowWidth];
Band tmpBand2 = dout.GetRasterBand(i + 1);
for (int j = 0; j < readCount; j++)
{
//如果是最后一次读取,且行数不能整除一次读取的行数时,那要对剩余部分作一次单独的读取
if (j == readCount - 1 && quickShowHeight % rows != 0)
{
raw = null;
tmpHeight = quickShowHeight % rows;
raw = new byte[quickShowWidth * tmpHeight];
}
bands[i].ReadRaster(0, j * rows, quickShowWidth, tmpHeight, raw, quickShowWidth, tmpHeight, 0, 0);
tmpBand2.WriteRaster(0, j * rows, quickShowWidth, tmpHeight, raw, quickShowWidth, tmpHeight, 0, 0);
}
dout.FlushCache();
}
#endregion
drijpg.CreateCopy(quickshowPath, dout, 1, null, null, null);
dout.Dispose();
return true;
}