678 lines
24 KiB
C#
678 lines
24 KiB
C#
using HalconDotNet;
|
||
using System.Diagnostics;
|
||
using System.Drawing;
|
||
using System.Drawing.Imaging;
|
||
using System.Runtime.ExceptionServices;
|
||
using System.Runtime.InteropServices;
|
||
|
||
namespace XKRS.Common.Model
|
||
{
|
||
public class HDevEngineTool : IDisposable
|
||
{
|
||
#region 常量
|
||
|
||
// path of external procedures
|
||
readonly string ProcedurePath = Environment.CurrentDirectory + "\\Vision\\";
|
||
|
||
#endregion
|
||
|
||
#region 成员变量
|
||
|
||
/// <summary>
|
||
/// 处理过程名
|
||
/// </summary>
|
||
public string ProcedureName;
|
||
|
||
/// <summary>
|
||
/// hdev程序启动引擎
|
||
/// </summary>
|
||
private readonly HDevEngine myEngine;
|
||
|
||
/// <summary>
|
||
/// 过程载入工具 .hdvp
|
||
/// </summary>
|
||
private HDevProcedureCall procedureCall;
|
||
|
||
/// <summary>
|
||
/// 程序运行是否成功
|
||
/// </summary>
|
||
public bool IsSuccessful { get; set; } = false;
|
||
|
||
/// <summary>
|
||
/// 控制参数字典
|
||
/// </summary>
|
||
public Dictionary<string, HTuple> InputTupleDic { get; set; }
|
||
|
||
/// <summary>
|
||
/// 图形参数字典
|
||
/// </summary>
|
||
public Dictionary<string, HObject> InputImageDic { get; set; }
|
||
|
||
#endregion
|
||
|
||
#region 初始化
|
||
/// <summary>
|
||
/// 实例化 默认搜索路径为: 启动路径//Vision//
|
||
/// </summary>
|
||
public HDevEngineTool()
|
||
{
|
||
ProcedureName = "";
|
||
myEngine = new HDevEngine();
|
||
myEngine.SetProcedurePath(ProcedurePath);
|
||
|
||
InputImageDic = new Dictionary<string, HObject>();
|
||
InputTupleDic = new Dictionary<string, HTuple>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 实例化
|
||
/// </summary>
|
||
/// <param name="path">外部函数搜索路径</param>
|
||
public HDevEngineTool(string path)
|
||
{
|
||
myEngine = new HDevEngine();
|
||
myEngine.SetProcedurePath(path);
|
||
|
||
InputImageDic = new Dictionary<string, HObject>();
|
||
InputTupleDic = new Dictionary<string, HTuple>();
|
||
}
|
||
#endregion
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 设置函数运行所需参数
|
||
/// </summary>
|
||
/// <param name="_tupleDictionary">控制参数</param>
|
||
/// <param name="_imageDictionary">图形参数</param>
|
||
public void SetDictionary(Dictionary<string, HTuple> _tupleDictionary, Dictionary<string, HObject> _imageDictionary)
|
||
{
|
||
InputTupleDic = _tupleDictionary;
|
||
InputImageDic = _imageDictionary;
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 载入过程 .hdvp
|
||
/// </summary>
|
||
/// <param name="procedureName">过程名</param>
|
||
public void LoadProcedure(string procedureName)
|
||
{
|
||
ProcedureName = procedureName;
|
||
try
|
||
{
|
||
HDevProcedure procedure = new HDevProcedure(procedureName);
|
||
procedureCall = new HDevProcedureCall(procedure);
|
||
}
|
||
catch (HDevEngineException Ex)
|
||
{
|
||
Trace.TraceInformation("HDevProgram {0} Load fail ,Error Line : {1}, Line number: {2}, Halcon error number : {3}", Ex.ProcedureName, Ex.LineText, Ex.LineNumber, Ex.HalconError);
|
||
return;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 执行过程
|
||
/// </summary>
|
||
[HandleProcessCorruptedStateExceptions]
|
||
public bool RunProcedure(out string errorMsg, out int timeElasped)
|
||
{
|
||
//lock (_runLock)
|
||
{
|
||
errorMsg = "";
|
||
Stopwatch sw = new Stopwatch();
|
||
sw.Start();
|
||
try
|
||
{
|
||
foreach (KeyValuePair<string, HTuple> pair in InputTupleDic)
|
||
{
|
||
procedureCall.SetInputCtrlParamTuple(pair.Key, pair.Value);
|
||
}
|
||
|
||
foreach (KeyValuePair<string, HObject> pair in InputImageDic)
|
||
{
|
||
procedureCall.SetInputIconicParamObject(pair.Key, pair.Value);
|
||
}
|
||
|
||
procedureCall.Execute();
|
||
|
||
IsSuccessful = true;
|
||
}
|
||
catch (HDevEngineException ex)
|
||
{
|
||
IsSuccessful = false;
|
||
errorMsg = $"HDevProgram {ex.ProcedureName} Run fail , Line number: {ex.LineNumber}, Halcon error number : {ex.HalconError},ex:{ex.Message}";
|
||
}
|
||
finally
|
||
{
|
||
sw.Stop();
|
||
timeElasped = (int)sw.ElapsedMilliseconds;
|
||
}
|
||
return IsSuccessful;
|
||
}
|
||
}
|
||
|
||
object _runLock = new object();
|
||
/// <summary>
|
||
/// 执行过程
|
||
/// </summary>
|
||
public Tuple<bool, Dictionary<string, HTuple>, Dictionary<string, HObject>, string, int> RunProcedure(Dictionary<string, HTuple> inputHTupleDict, Dictionary<string, HObject> inputImgDict, List<string> outputHTuples = null, List<string> outputObjs = null)
|
||
{
|
||
lock (_runLock)
|
||
{
|
||
string errorMsg = "";
|
||
int timeElasped = 0;
|
||
bool result = false;
|
||
Dictionary<string, HTuple> outputHTupleDict = new Dictionary<string, HTuple>();
|
||
Dictionary<string, HObject> outputObjDict = new Dictionary<string, HObject>();
|
||
|
||
Stopwatch sw = new Stopwatch();
|
||
sw.Start();
|
||
try
|
||
{
|
||
if (inputHTupleDict != null && inputHTupleDict.Count > 0)
|
||
{
|
||
foreach (KeyValuePair<string, HTuple> pair in inputHTupleDict)
|
||
{
|
||
procedureCall.SetInputCtrlParamTuple(pair.Key, pair.Value);
|
||
}
|
||
}
|
||
|
||
if (InputImageDic != null && inputImgDict.Count > 0)
|
||
{
|
||
foreach (KeyValuePair<string, HObject> pair in inputImgDict)
|
||
{
|
||
procedureCall.SetInputIconicParamObject(pair.Key, pair.Value);
|
||
}
|
||
}
|
||
|
||
procedureCall.Execute();
|
||
|
||
result = true;
|
||
}
|
||
catch (HDevEngineException ex)
|
||
{
|
||
result = false;
|
||
errorMsg += $"HDevProgram {ex.ProcedureName} Run fail , Line number: {ex.LineNumber}, Halcon error number : {ex.HalconError},ex:{ex.Message}";
|
||
}
|
||
finally
|
||
{
|
||
sw.Stop();
|
||
timeElasped = (int)sw.ElapsedMilliseconds;
|
||
}
|
||
|
||
if (result)
|
||
{
|
||
if (outputHTuples != null && outputHTuples.Count > 0)
|
||
{
|
||
outputHTuples.ForEach(t =>
|
||
{
|
||
try
|
||
{
|
||
outputHTupleDict[t] = procedureCall.GetOutputCtrlParamTuple(t);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
result = false;
|
||
errorMsg += $"\r\n获取{t}结果异常:{ex.Message}";
|
||
|
||
outputHTupleDict[t] = null;
|
||
}
|
||
});
|
||
}
|
||
|
||
if (outputObjs != null && outputObjs.Count > 0)
|
||
{
|
||
outputObjs.ForEach(t =>
|
||
{
|
||
try
|
||
{
|
||
outputObjDict[t] = procedureCall.GetOutputIconicParamObject(t);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
result = false;
|
||
errorMsg += $"\r\n获取{t}结果异常:{ex.Message}";
|
||
|
||
outputObjDict[t] = null;
|
||
}
|
||
});
|
||
}
|
||
}
|
||
Tuple<bool, Dictionary<string, HTuple>, Dictionary<string, HObject>, string, int> ret = new Tuple<bool, Dictionary<string, HTuple>, Dictionary<string, HObject>, string, int>(result, outputHTupleDict, outputObjDict, errorMsg, timeElasped);
|
||
return ret;
|
||
}
|
||
}
|
||
|
||
public HTuple GetResultTuple(string key)
|
||
{
|
||
try
|
||
{
|
||
if (IsSuccessful)
|
||
{
|
||
return procedureCall.GetOutputCtrlParamTuple(key);
|
||
}
|
||
else
|
||
{
|
||
return new HTuple();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return new HTuple();
|
||
}
|
||
|
||
}
|
||
|
||
public HObject GetResultObject(string key, bool ignoreError = false)
|
||
{
|
||
try
|
||
{
|
||
if (ignoreError || IsSuccessful)
|
||
{
|
||
return procedureCall.GetOutputIconicParamObject(key);
|
||
}
|
||
else
|
||
{
|
||
return new HObject();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return new HObject();
|
||
}
|
||
}
|
||
|
||
public void Dispose()
|
||
{
|
||
procedureCall?.Dispose();
|
||
myEngine?.Dispose();
|
||
}
|
||
}
|
||
|
||
public static class HalconHelper
|
||
{
|
||
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
|
||
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
|
||
|
||
public static HImage Convert8GrayBitmapToHImage(this Bitmap bmp)
|
||
{
|
||
HImage himage = new HImage();
|
||
try
|
||
{
|
||
//判断输入图像不为null
|
||
if (bmp == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
{
|
||
//重绘himage
|
||
//HImage curImage = new HImage();
|
||
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
|
||
himage.GenImage1("byte", bmp.Width, bmp.Height, bmpData.Scan0);
|
||
bmp.UnlockBits(bmpData);
|
||
//himage = curImage;
|
||
}
|
||
return himage;
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
|
||
public static Bitmap ConvertHImageToBitmap(this HObject hImage)
|
||
{
|
||
HOperatorSet.CountChannels(hImage, out HTuple chanels);
|
||
if (chanels.I == 1)
|
||
{
|
||
return hImage.ConvertHImageTo8GrayBitmap();
|
||
}
|
||
else
|
||
{
|
||
return hImage.ConvertHImageToRGBBitmap();
|
||
//return hImage.HObject2BitmapRGB();
|
||
}
|
||
}
|
||
|
||
public static Bitmap HObject2BitmapRGB(this HObject hObject)
|
||
{
|
||
////获取图像尺寸
|
||
HTuple width0, height0, type, width, height;
|
||
//获取图像尺寸
|
||
HOperatorSet.GetImageSize(hObject, out width0, out height0);
|
||
// 创建交错格式图像
|
||
HOperatorSet.InterleaveChannels(hObject, out HObject InterImage, "argb", "match", 255); //"rgb", 4 * width0, 0 "argb", "match", 255
|
||
|
||
//获取交错格式图像指针
|
||
HOperatorSet.GetImagePointer1(InterImage, out HTuple Pointer, out type, out width, out height);
|
||
IntPtr ptr = Pointer;
|
||
//构建新Bitmap图像
|
||
Bitmap res32 = new Bitmap(width / 4, height, width, PixelFormat.Format32bppArgb, ptr); // Format32bppArgb Format24bppRgb
|
||
|
||
//32位Bitmap转24位
|
||
var res24 = new Bitmap(res32.Width, res32.Height, PixelFormat.Format24bppRgb);
|
||
Graphics graphics = Graphics.FromImage(res24);
|
||
graphics.DrawImage(res32, new Rectangle(0, 0, res32.Width, res32.Height));
|
||
|
||
return res24;
|
||
}
|
||
|
||
public static Bitmap ConvertHImageTo8GrayBitmap(this HObject hImage)
|
||
{
|
||
try
|
||
{
|
||
HTuple type, width, height, pointer;
|
||
HOperatorSet.GetImagePointer1(hImage, out pointer, out type, out width, out height);
|
||
|
||
Bitmap bmp = new Bitmap(width.I, height.I, PixelFormat.Format8bppIndexed);
|
||
ColorPalette pal = bmp.Palette;
|
||
for (int i = 0; i <= 255; i++)
|
||
{
|
||
pal.Entries[i] = Color.FromArgb(255, i, i, i);
|
||
}
|
||
bmp.Palette = pal;
|
||
|
||
BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||
|
||
if (width % 4 == 0)
|
||
{
|
||
CopyMemory(bitmapData.Scan0, (IntPtr)pointer.D, (uint)(bitmapData.Stride * height.I));
|
||
}
|
||
else
|
||
{
|
||
Parallel.For(0, height.I, h =>
|
||
{
|
||
CopyMemory(bitmapData.Scan0 + h * bitmapData.Stride, (IntPtr)(pointer.D + h * width.I), (uint)width.I);
|
||
});
|
||
}
|
||
|
||
bmp.UnlockBits(bitmapData);
|
||
return bmp;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
|
||
public static Bitmap ConvertHImageToRGBBitmap(this HObject hImage)
|
||
{
|
||
try
|
||
{
|
||
HOperatorSet.GetImagePointer3(hImage, out HTuple pointRed, out HTuple pointGreen, out HTuple pointBlue, out HTuple type, out HTuple width, out HTuple height);
|
||
Bitmap image = new Bitmap(width.I, height.I, PixelFormat.Format24bppRgb);
|
||
BitmapData imageData = image.LockBits(new Rectangle(0, 0, width.I, height.I), ImageLockMode.ReadWrite, image.PixelFormat);
|
||
IntPtr pR = (IntPtr)pointRed.D;
|
||
IntPtr pG = (IntPtr)pointGreen.D;
|
||
IntPtr pB = (IntPtr)pointBlue.D;
|
||
Parallel.For(0, imageData.Height, h =>
|
||
{
|
||
Parallel.For(0, imageData.Width, w =>
|
||
{
|
||
int dest = h * imageData.Stride + w * 3;
|
||
int source = h * imageData.Width + w;
|
||
|
||
Marshal.WriteByte(imageData.Scan0, dest, Marshal.ReadByte(pB, source));
|
||
Marshal.WriteByte(imageData.Scan0, dest + 1, Marshal.ReadByte(pG, source));
|
||
Marshal.WriteByte(imageData.Scan0, dest + 2, Marshal.ReadByte(pR, source));
|
||
});
|
||
});
|
||
|
||
image.UnlockBits(imageData);
|
||
return image;
|
||
}
|
||
catch (Exception exc)
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
|
||
public static Bitmap ConvertHImageTo16GrayBitmap(this HImage originHImage)
|
||
{
|
||
//IntPtr pointer = hImage.GetImagePointer1(out string type, out int width, out int height);
|
||
|
||
//int widthIn4 = (int)Math.Ceiling(width / 4.0) * 4;
|
||
|
||
////Bitmap bmp = new Bitmap(widthIn4, height, PixelFormat.Format48bppRgb);
|
||
//Bitmap showImage = new Bitmap(widthIn4, height, PixelFormat.Format48bppRgb);
|
||
|
||
//Rectangle rect = new Rectangle(0, 0, widthIn4, height);
|
||
////BitmapData bitmapData = bmp.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format48bppRgb);
|
||
//BitmapData showImageData = showImage.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format48bppRgb);
|
||
//unsafe
|
||
//{
|
||
// byte* data = (byte*)pointer;
|
||
// //byte* bitmapBuffer = (byte*)bitmapData.Scan0;
|
||
// byte* showBitmapBuffer = (byte*)showImageData.Scan0;
|
||
|
||
// Parallel.For(0, width * height, i =>
|
||
// {
|
||
// int index = (i + 1) % width + widthIn4 * ((int)Math.Floor((double)(i + 1) / width)) - 1;
|
||
|
||
// //showBitmapBuffer[index * 6] = bitmapBuffer[index * 6] = data[i * 2];
|
||
// //showBitmapBuffer[index * 6 + 1] = bitmapBuffer[index * 6 + 1] = data[i * 2 + 1];
|
||
// showBitmapBuffer[index * 6] = data[i * 2];
|
||
// showBitmapBuffer[index * 6 + 1] = data[i * 2 + 1];
|
||
// });
|
||
//}
|
||
|
||
////bmp.UnlockBits(bitmapData);
|
||
//showImage.UnlockBits(showImageData);
|
||
|
||
//return showImage;
|
||
|
||
// dev_set_draw('margin')
|
||
//read_image(Image, '0.tif')
|
||
|
||
HImage hImage = originHImage.Clone();
|
||
|
||
//* 如果16位图像非常暗的话,建议在这一步进行提亮,因为后面8位图像大幅度提亮易造成色阶断裂,出现不连续的像素块
|
||
// * scale_image(Image, Image, 25, 0)
|
||
//hImage = hImage.ScaleImage(25.0, 0.0);
|
||
|
||
//get_domain(Image, rectangle)
|
||
//* 获取全图中像素灰度值的最大和最小值
|
||
//min_max_gray(rectangle, Image, 0, Min, Max, range)
|
||
hImage.MinMaxGray(hImage.GetDomain(), 0, out double min, out double max, out double range);
|
||
|
||
//* 将16位图的灰度值映射到0 - 255上
|
||
double mult = 255.0 / (max - min);
|
||
double add = -mult * min;
|
||
hImage = hImage.ScaleImage(mult, add);
|
||
|
||
//* 转换为'byte'类型
|
||
//convert_image_type(Image_scaled, ImageConverted, 'byte')
|
||
hImage = hImage.ConvertImageType("byte");
|
||
|
||
Bitmap showImage = hImage.ConvertHImageTo8GrayBitmap();
|
||
|
||
hImage.Dispose();
|
||
|
||
return showImage;
|
||
|
||
//* 如果转换以后图像整体对比度太低的话,可以提高对比度(这里是对8位图像处理)
|
||
//Min:= 20
|
||
//Max:= 160
|
||
//Mult:= 255.0 / (Max - Min)
|
||
//Add:= -Mult * Min
|
||
//scale_image(ImageConverted, ImageConverted_scaled, Mult, Add)
|
||
}
|
||
|
||
public static List<double> HTupleToDouble(this HTuple tuple)
|
||
{
|
||
List<double> list = new List<double>();
|
||
|
||
for (int i = 0; i < tuple.Length; i++)
|
||
{
|
||
list.Add(tuple[i].D);
|
||
}
|
||
|
||
return list;
|
||
}
|
||
|
||
|
||
|
||
|
||
public static HImage ConvertHObjectToHImage(this HObject obj)
|
||
{
|
||
HOperatorSet.CountChannels(obj, out HTuple channels);
|
||
|
||
HImage img = new HImage();
|
||
if (channels.I == 1)
|
||
{
|
||
HTuple pointer, type, width, height;
|
||
HOperatorSet.GetImagePointer1(obj, out pointer, out type, out width, out height);
|
||
|
||
img.GenImage1(type, width, height, pointer);
|
||
}
|
||
else
|
||
{
|
||
HTuple pRed, pGreen, pBlue, type, width, height;
|
||
HOperatorSet.GetImagePointer3(obj, out pRed, out pGreen, out pBlue, out type, out width, out height);
|
||
|
||
img.GenImage3(type, width, height, pRed, pGreen, pBlue);
|
||
}
|
||
|
||
return img;
|
||
}
|
||
|
||
#region 灰度图转换为伪彩图
|
||
public static Bitmap ConvertGrayImageToPesudoColorfulImage(this HImage hImage, double max = 0, double min = 0, double zoom = 1, bool isShowHeightTip = false, int zResolution = 100000)
|
||
{
|
||
hImage.GetImageSize(out int width, out int height);
|
||
hImage.MinMaxGray(new HRegion(0.0, 0.0, width, height), 3, out HTuple roiMin, out HTuple roiMax, out _);
|
||
|
||
if (max == 0)
|
||
{
|
||
max = roiMax;
|
||
}
|
||
|
||
if (min == 0)
|
||
{
|
||
min = roiMin;
|
||
}
|
||
|
||
double mult = 235 / (zoom * (max - min));
|
||
double add = (0 - mult) * min * zoom + 10;
|
||
HOperatorSet.ScaleImage(hImage, out HObject imageScaled, mult, add);
|
||
HOperatorSet.ConvertImageType(imageScaled, out imageScaled, "byte");
|
||
Stopwatch sw = new Stopwatch();
|
||
sw.Start();
|
||
|
||
HOperatorSet.GetImagePointer1(imageScaled, out HTuple pointer, out HTuple type, out _, out _);
|
||
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
|
||
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
|
||
|
||
unsafe
|
||
{
|
||
byte* data = (byte*)(IntPtr)pointer;
|
||
byte* bitmapDataBuff = (byte*)bitmapData.Scan0;
|
||
|
||
if (width % 4 != 0)
|
||
{
|
||
Parallel.For(0, height, h =>
|
||
{
|
||
Parallel.For(0, width, w =>
|
||
{
|
||
byte gray = data[h * width + w];
|
||
byte[] convertBytes = ConvertByteToColorfulArray(gray);
|
||
|
||
Marshal.Copy(convertBytes, 0, (IntPtr)(bitmapDataBuff + h * bitmapData.Stride + w * 3), 3);
|
||
});
|
||
});
|
||
}
|
||
else
|
||
{
|
||
Parallel.For(0, width * height, i =>
|
||
{
|
||
byte gray = data[i];
|
||
byte[] convertBytes = ConvertByteToColorfulArray(gray);
|
||
|
||
Marshal.Copy(convertBytes, 0, (IntPtr)(bitmapDataBuff + i * 3), 3);
|
||
});
|
||
}
|
||
}
|
||
bitmap.UnlockBits(bitmapData);
|
||
|
||
if (isShowHeightTip)
|
||
{
|
||
List<byte> lableList = new List<byte>() { 5, 30, 60, 90, 120, 150, 180, 210, 240, 255 };
|
||
Dictionary<double, Color> lableColorDict = lableList.ToDictionary(
|
||
u => (u - add) / (mult * zResolution),
|
||
u =>
|
||
{
|
||
byte[] colorBytes = ConvertByteToColorfulArray(u);
|
||
return Color.FromArgb(colorBytes[2], colorBytes[1], colorBytes[0]);
|
||
});
|
||
|
||
using (Graphics g = Graphics.FromImage(bitmap))
|
||
{
|
||
int rectHeight = (int)(bitmap.Height / (5.0 * lableColorDict.Count));
|
||
Font font = new Font("宋体", (int)(rectHeight * 0.75), GraphicsUnit.Pixel);
|
||
|
||
string lable = lableColorDict.ElementAt(0).Key.ToString("f3");
|
||
SizeF lableSize = g.MeasureString(lable, font);
|
||
int rectWidth = (int)(lableSize.Width * 1.5);
|
||
|
||
int startX = 0;
|
||
int startY = 0;
|
||
foreach (KeyValuePair<double, Color> pair in lableColorDict)
|
||
{
|
||
g.FillRectangle(new SolidBrush(pair.Value), startX, startY, rectWidth, rectHeight);
|
||
g.DrawString(pair.Key.ToString("f3"), font, new SolidBrush(Color.White), (float)(startX + (rectWidth - lableSize.Width) / 2.0), (float)(startY + (rectHeight - lableSize.Height) / 2.0));
|
||
|
||
startY += rectHeight;
|
||
}
|
||
}
|
||
}
|
||
|
||
sw.Stop();
|
||
//LogAsync(DateTime.Now, EnumHelper.LogLevel.Information, $"转换耗时{sw.ElapsedMilliseconds}ms");
|
||
return bitmap;
|
||
}
|
||
|
||
private static byte[] ConvertByteToColorfulArray(byte gray)
|
||
{
|
||
byte[] bytes = new byte[3];
|
||
if (gray == 0)
|
||
{
|
||
bytes[2] = 255;
|
||
bytes[1] = 255;
|
||
bytes[0] = 255;
|
||
}
|
||
if (gray > 0 && gray <= 63)
|
||
{
|
||
bytes[2] = 0;
|
||
bytes[+1] = (byte)(254 - 4 * gray);
|
||
bytes[0] = 255;
|
||
}
|
||
if (gray >= 64 && gray <= 127)
|
||
{
|
||
bytes[2] = 0;
|
||
bytes[1] = (byte)(4 * gray - 254);
|
||
bytes[0] = (byte)(510 - 4 * gray);
|
||
}
|
||
if (gray >= 128 && gray <= 191)
|
||
{
|
||
bytes[2] = (byte)(4 * gray - 510);
|
||
bytes[1] = 255;
|
||
bytes[0] = 0;
|
||
}
|
||
if (gray >= 192 && gray <= 255)
|
||
{
|
||
bytes[2] = 255;
|
||
bytes[1] = (byte)(1022 - 4 * gray);
|
||
bytes[0] = 0;
|
||
}
|
||
|
||
return bytes;
|
||
}
|
||
#endregion
|
||
}
|
||
}
|