1
This commit is contained in:
parent
b19feb5a44
commit
e08386333a
@ -13,13 +13,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AntdUI" Version="1.8.9" />
|
<PackageReference Include="AntdUI" Version="1.8.9" />
|
||||||
<PackageReference Include="OpenCvSharp4" Version="4.10.0.20241108" />
|
<PackageReference Include="OpenCvSharp4" Version="4.10.0.20241108" />
|
||||||
|
162
DH.Commons/Helper/AttributeHelper.cs
Normal file
162
DH.Commons/Helper/AttributeHelper.cs
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
using DH.Commons.Enums;
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using static DH.Commons.Enums.EnumHelper;
|
||||||
|
|
||||||
|
|
||||||
|
namespace DH.Commons.Enums
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 设备特性,指示该信息的设备类型,适用于设备信息和配置信息
|
||||||
|
/// </summary>
|
||||||
|
public class DeviceAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 设备类型
|
||||||
|
/// </summary>
|
||||||
|
public string TypeCode { get; set; }
|
||||||
|
|
||||||
|
public string TypeDescription { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 特性修饰类别
|
||||||
|
/// </summary>
|
||||||
|
public DeviceAttributeType AttrType { get; set; }
|
||||||
|
|
||||||
|
public DeviceAttribute(string typeCode, string typeDesc, EnumHelper.DeviceAttributeType attrType)
|
||||||
|
{
|
||||||
|
TypeCode = typeCode;
|
||||||
|
TypeDescription = typeDesc;
|
||||||
|
AttrType = attrType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 预置状态特性 指定该修饰信息的前置状态允许范围
|
||||||
|
/// </summary>
|
||||||
|
public class PreStateAttribute : Attribute
|
||||||
|
{
|
||||||
|
public int PreState { get; set; }
|
||||||
|
public PreStateAttribute(int _preState)
|
||||||
|
{
|
||||||
|
PreState = _preState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查当前待执行操作的前置状态要求是否合法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="currentState"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool CheckPreStateValid(int currentState)
|
||||||
|
{
|
||||||
|
return (currentState & PreState) == currentState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ColorSelectAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string SelectedColor { get; set; }
|
||||||
|
public ColorSelectAttribute(string selectedColor)
|
||||||
|
{
|
||||||
|
SelectedColor = selectedColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FontColorSelectAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string SelectedColor { get; set; }
|
||||||
|
public FontColorSelectAttribute(string selectedColor)
|
||||||
|
{
|
||||||
|
SelectedColor = selectedColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum InvokeType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 不公开调用
|
||||||
|
/// </summary>
|
||||||
|
[Description("不公开调用")]
|
||||||
|
NoneInvoke = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// 测试调用
|
||||||
|
/// </summary>
|
||||||
|
[Description("测试调用")]
|
||||||
|
TestInvoke = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// 标定调用
|
||||||
|
/// </summary>
|
||||||
|
[Description("标定调用")]
|
||||||
|
CalibInvoke = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用来修饰对外开放的调用方法的特性
|
||||||
|
/// 调用方法参数顺序:IOperationConfig,InvokeDevice,SourceDevice
|
||||||
|
/// </summary>
|
||||||
|
public class ProcessMethodAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string MethodCode { get; set; }
|
||||||
|
public string MethodDesc { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否提供人工调用测试
|
||||||
|
/// </summary>
|
||||||
|
public InvokeType InvokeType { get; set; }
|
||||||
|
|
||||||
|
public string DeviceType { get; set; }
|
||||||
|
|
||||||
|
public ProcessMethodAttribute(string deviceType, string code, string description, InvokeType invokeType)
|
||||||
|
{
|
||||||
|
DeviceType = deviceType;
|
||||||
|
MethodCode = code;
|
||||||
|
MethodDesc = description;
|
||||||
|
InvokeType = invokeType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SwitchDisplayAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string SwitchName { get; set; }
|
||||||
|
|
||||||
|
public bool SwithOnStatus { get; set; } = true;
|
||||||
|
|
||||||
|
public SwitchDisplayAttribute(string name, bool status)
|
||||||
|
{
|
||||||
|
SwitchName = name;
|
||||||
|
SwithOnStatus = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ElementAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string Desc { get; set; }
|
||||||
|
|
||||||
|
public string IconPath { get; set; }
|
||||||
|
|
||||||
|
public bool IsShowInToolBar { get; set; }
|
||||||
|
|
||||||
|
public ElementAttribute(string desc, string iconPath, bool isShowInToolBar = true, [CallerMemberName] string name = "")
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Desc = desc;
|
||||||
|
IconPath = iconPath;
|
||||||
|
IsShowInToolBar = isShowInToolBar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProcessAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string ProcessCode { get; set; }
|
||||||
|
public DeviceAttributeType AttrType { get; set; }
|
||||||
|
|
||||||
|
public ProcessAttribute(string stationCode, DeviceAttributeType attrType)
|
||||||
|
{
|
||||||
|
ProcessCode = stationCode;
|
||||||
|
AttrType = attrType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -252,6 +252,37 @@ namespace DH.Commons.Enums
|
|||||||
MeasureResult = 31,
|
MeasureResult = 31,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum LogLevel
|
||||||
|
{
|
||||||
|
[Description("详细")]
|
||||||
|
[ColorSelect("White")]
|
||||||
|
[FontColorSelect("Green")]
|
||||||
|
Detail = 2,
|
||||||
|
[Description("信息")]
|
||||||
|
[ColorSelect("White")]
|
||||||
|
[FontColorSelect("Dark")]
|
||||||
|
Information = 3,
|
||||||
|
[Description("辅助")]
|
||||||
|
[ColorSelect("White")]
|
||||||
|
[FontColorSelect("Blue")]
|
||||||
|
Assist = 4,
|
||||||
|
[Description("动作")]
|
||||||
|
[ColorSelect("DarkGreen")]
|
||||||
|
[FontColorSelect("Yellow")]
|
||||||
|
Action = 5,
|
||||||
|
[Description("错误")]
|
||||||
|
[ColorSelect("Orange")]
|
||||||
|
[FontColorSelect("White")]
|
||||||
|
Error = 6,
|
||||||
|
[Description("警报")]
|
||||||
|
[ColorSelect("Brown")]
|
||||||
|
[FontColorSelect("White")]
|
||||||
|
Warning = 7,
|
||||||
|
[Description("异常")]
|
||||||
|
[ColorSelect("Red")]
|
||||||
|
[FontColorSelect("White")]
|
||||||
|
Exception = 8,
|
||||||
|
}
|
||||||
//public enum CameraDriverType
|
//public enum CameraDriverType
|
||||||
//{
|
//{
|
||||||
// Halcon,
|
// Halcon,
|
||||||
|
126
DH.Commons/Helper/LoggerHelper.cs
Normal file
126
DH.Commons/Helper/LoggerHelper.cs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
using DH.Commons.Helper;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static DH.Commons.Enums.EnumHelper;
|
||||||
|
|
||||||
|
namespace DH.Commons.Enums
|
||||||
|
{
|
||||||
|
public class LoggerHelper
|
||||||
|
{
|
||||||
|
public event Action<DateTime, string> OnLogExceptionRaised;
|
||||||
|
|
||||||
|
public string LogPath { get; set; }
|
||||||
|
public string LogPrefix { get; set; }
|
||||||
|
|
||||||
|
LogLevel LogLevel = LogLevel.Information;
|
||||||
|
|
||||||
|
public LoggerHelper() { }
|
||||||
|
public LoggerHelper(string logPath, string logPrefix, LogLevel logLevel = LogLevel.Information)
|
||||||
|
{
|
||||||
|
LogPath = logPath;
|
||||||
|
LogPrefix = logPrefix;
|
||||||
|
|
||||||
|
LogLevel = logLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetLogLevel(LogLevel logLevel)
|
||||||
|
{
|
||||||
|
if (LogLevel != logLevel)
|
||||||
|
LogLevel = logLevel;
|
||||||
|
}
|
||||||
|
////耗时操作从 _taskFactory分配线程
|
||||||
|
//public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
|
||||||
|
readonly ConcurrentQueue<LogMsg> _logQueue = new ConcurrentQueue<LogMsg>();
|
||||||
|
Task _logTask = null;
|
||||||
|
readonly object _logLock = new object();
|
||||||
|
|
||||||
|
public async void LogAsync(LogMsg msg)
|
||||||
|
{
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
_logQueue.Enqueue(msg);
|
||||||
|
|
||||||
|
lock (_logLock)
|
||||||
|
{
|
||||||
|
if (_logTask == null)
|
||||||
|
{
|
||||||
|
_logTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
string filePath = Path.Combine(LogPath, $"{(string.IsNullOrWhiteSpace(LogPrefix) ? "Log_" : ("Log_" + LogPrefix + "_"))}{DateTime.Now.ToString("yyyyMMdd")}.txt");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!StaticHelper.CheckFilesCanUse(filePath))
|
||||||
|
{
|
||||||
|
OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}被占用,无法写入");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
using (StreamWriter writer = new StreamWriter(filePath, true, System.Text.Encoding.UTF8))
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(LogPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(LogPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (_logQueue.Count > 0)
|
||||||
|
{
|
||||||
|
if (_logQueue.TryDequeue(out LogMsg log))
|
||||||
|
{
|
||||||
|
if (log.LogLevel >= LogLevel)
|
||||||
|
{
|
||||||
|
writer.WriteLine($"{log.LogTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}[{log.ThreadId}]\t{log.LogLevel.GetEnumDescription()}\t{log.Msg}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.Flush();
|
||||||
|
|
||||||
|
await Task.Delay(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
//OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}写入异常:/*{ex.GetExceptionMessage()*/}");
|
||||||
|
OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}写入异常");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogAsync(DateTime dt, LogLevel logLevel, string msg)
|
||||||
|
{
|
||||||
|
LogAsync(new LogMsg(dt, logLevel, msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LogMsg
|
||||||
|
{
|
||||||
|
public DateTime LogTime { get; set; }
|
||||||
|
public LogLevel LogLevel { get; set; }
|
||||||
|
//public string Prefix { get; set; }
|
||||||
|
public string Msg { get; set; }
|
||||||
|
|
||||||
|
public string MsgSource { get; set; }
|
||||||
|
|
||||||
|
public int ThreadId { get; set; }
|
||||||
|
|
||||||
|
public LogMsg() { }
|
||||||
|
public LogMsg(DateTime dt, LogLevel logLevel, string msg)
|
||||||
|
{
|
||||||
|
LogTime = dt;
|
||||||
|
LogLevel = logLevel;
|
||||||
|
Msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{LogTime.ToString("HH:mm:ss.fff")}\t{MsgSource}\t{Msg}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
677
DH.Commons/Helper/StaticHelper.cs
Normal file
677
DH.Commons/Helper/StaticHelper.cs
Normal file
@ -0,0 +1,677 @@
|
|||||||
|
using Microsoft.CSharp.RuntimeBinder;
|
||||||
|
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Dynamic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.ExceptionServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Serialization.Formatters.Binary;
|
||||||
|
|
||||||
|
namespace DH.Commons.Helper
|
||||||
|
{
|
||||||
|
public static class StaticHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 数值转换为byte数组 高位在前,低位在后
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="number"></param>
|
||||||
|
/// <param name="size"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static byte[] IntToBytes(this int number, int size = 2)
|
||||||
|
{
|
||||||
|
byte[] result = new byte[size];
|
||||||
|
|
||||||
|
int temp = size;
|
||||||
|
while (temp > 0)
|
||||||
|
{
|
||||||
|
result[size - temp] = (byte)(number >> ((temp - 1) * 8) & 0xff);
|
||||||
|
|
||||||
|
temp--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 字节数组转换为整数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">字节数组</param>
|
||||||
|
/// <param name="HtL">true:数组序号低的在高位 false:数组序号低的在低位</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int BytesToInt(this byte[] data, bool HtL = true)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < data.Length; i++)
|
||||||
|
{
|
||||||
|
int index = i;
|
||||||
|
|
||||||
|
if (HtL)
|
||||||
|
{
|
||||||
|
index = data.Length - 1 - i;
|
||||||
|
}
|
||||||
|
|
||||||
|
res += data[index] << (8 * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取一个类指定的属性值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">object对象</param>
|
||||||
|
/// <param name="field">属性名称</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static object GetPropertyValue(object info, string field)
|
||||||
|
{
|
||||||
|
if (info == null) return null;
|
||||||
|
Type t = info.GetType();
|
||||||
|
IEnumerable<System.Reflection.PropertyInfo> property = from pi in t.GetProperties() where pi.Name.ToLower() == field.ToLower() select pi;
|
||||||
|
return property.First().GetValue(info, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将32位整形拆分为无符号16位整形
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="num">需要拆分的32位整形</param>
|
||||||
|
/// <param name="bitNum">拆分为16位整形的位数 1或者2</param>
|
||||||
|
/// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static List<ushort> ParseIntToUnsignShortList(this int num, int bitNum = 2, bool HtL = false)
|
||||||
|
{
|
||||||
|
if (bitNum == 2)
|
||||||
|
{
|
||||||
|
ushort high = (ushort)(num >> 16);
|
||||||
|
ushort low = (ushort)num;
|
||||||
|
|
||||||
|
if (HtL)
|
||||||
|
{
|
||||||
|
return new List<ushort>() { high, low };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new List<ushort>() { low, high };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (num < 0)
|
||||||
|
{
|
||||||
|
num = ushort.MaxValue + 1 + num;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new List<ushort>() { (ushort)num };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将32位整形数组拆分为无符号16位整形数组
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="list">需要拆分的32位整形</param>
|
||||||
|
/// <param name="bitNum">拆分为16位整形的位数 1或者2</param>
|
||||||
|
/// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static List<ushort> ParseIntToUnsignShortList(this List<int> list, int bitNum = 2, bool HtL = false)
|
||||||
|
{
|
||||||
|
return list.SelectMany(u => u.ParseIntToUnsignShortList(bitNum, HtL)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将ushort的集合转换为16位带符号整形
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="numList"></param>
|
||||||
|
/// <param name="bitNum">合并的位数 1或者2</param>
|
||||||
|
/// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static List<int> ParseUnsignShortListToInt(this List<int> numList, int bitNum = 2, bool HtL = false)
|
||||||
|
{
|
||||||
|
if (bitNum == 1)
|
||||||
|
{
|
||||||
|
return numList.ConvertAll(n =>
|
||||||
|
{
|
||||||
|
int num = n;
|
||||||
|
if (num > short.MaxValue)
|
||||||
|
{
|
||||||
|
num = num - ushort.MaxValue - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<int> list = new List<int>();
|
||||||
|
for (int i = 0; i < numList.Count; i += 2)
|
||||||
|
{
|
||||||
|
int high = HtL ? numList[i] : numList[i + 1];
|
||||||
|
int low = HtL ? numList[i + 1] : numList[i];
|
||||||
|
list.Add((high << 16) | low);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//public static T DeepSerializeClone<T>(this T t)
|
||||||
|
//{
|
||||||
|
// return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(t));
|
||||||
|
//}
|
||||||
|
|
||||||
|
public static void DataFrom<T1, T2>(this T1 destT, T2 sourceT, List<string> exceptionProps = null) where T1 : class where T2 : class
|
||||||
|
{
|
||||||
|
if (sourceT == null)
|
||||||
|
{
|
||||||
|
destT = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyInfo[] propDest = destT.GetType().GetProperties();//.Where(p => !(p.GetMethod.IsVirtual && !p.GetMethod.IsFinal)).ToArray();
|
||||||
|
PropertyInfo[] propSource = sourceT.GetType().GetProperties();
|
||||||
|
|
||||||
|
Array.ForEach(propDest, prop =>
|
||||||
|
{
|
||||||
|
if (exceptionProps == null || !exceptionProps.Contains(prop.Name))
|
||||||
|
{
|
||||||
|
if (prop.CanWrite)
|
||||||
|
{
|
||||||
|
PropertyInfo propS = propSource.FirstOrDefault(p => p.Name == prop.Name);
|
||||||
|
if (propS != null && propS.CanRead)
|
||||||
|
{
|
||||||
|
prop.SetValue(destT, propS.GetValue(sourceT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//RtlMoveMemory
|
||||||
|
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
|
||||||
|
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
|
||||||
|
[HandleProcessCorruptedStateExceptions]
|
||||||
|
//public static Bitmap CopyBitmap(this Bitmap source)
|
||||||
|
//{
|
||||||
|
// Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
|
||||||
|
// if (PixelSize == 1)
|
||||||
|
// {
|
||||||
|
// ColorPalette cp = clone.Palette;
|
||||||
|
// for (int i = 0; i < 256; i++)
|
||||||
|
// {
|
||||||
|
// cp.Entries[i] = Color.FromArgb(255, i, i, i);
|
||||||
|
// }
|
||||||
|
// clone.Palette = cp;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
|
||||||
|
// BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
|
||||||
|
// BitmapData cloneData = clone.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
|
||||||
|
// if (source.Width % 4 == 0)
|
||||||
|
// {
|
||||||
|
// unsafe
|
||||||
|
// {
|
||||||
|
// CopyMemory(cloneData.Scan0, sourceData.Scan0, (uint)(sourceData.Stride * sourceData.Height));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// Parallel.For(0, source.Height, h =>
|
||||||
|
// {
|
||||||
|
// unsafe
|
||||||
|
// {
|
||||||
|
// CopyMemory(cloneData.Scan0 + h * sourceData.Stride, sourceData.Scan0 + h * sourceData.Stride, (uint)sourceData.Width);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// clone.UnlockBits(cloneData);
|
||||||
|
// source.UnlockBits(sourceData);
|
||||||
|
|
||||||
|
// }
|
||||||
|
// catch (Exception ex)
|
||||||
|
// {
|
||||||
|
// return clone;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return clone;
|
||||||
|
//}
|
||||||
|
public static Bitmap CopyBitmap(this Bitmap source)
|
||||||
|
{
|
||||||
|
Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int pixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
|
||||||
|
if (pixelSize == 1)
|
||||||
|
{
|
||||||
|
ColorPalette cp = clone.Palette;
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
cp.Entries[i] = Color.FromArgb(255, i, i, i);
|
||||||
|
}
|
||||||
|
clone.Palette = cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
|
||||||
|
BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadOnly, source.PixelFormat);
|
||||||
|
BitmapData cloneData = clone.LockBits(rect, ImageLockMode.WriteOnly, source.PixelFormat);
|
||||||
|
|
||||||
|
int stride = sourceData.Stride;
|
||||||
|
int height = sourceData.Height;
|
||||||
|
|
||||||
|
if (stride % 4 == 0)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
CopyMemory(cloneData.Scan0, sourceData.Scan0, (uint)(stride * height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Parallel.For(0, height, h =>
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
CopyMemory(cloneData.Scan0 + h * stride, sourceData.Scan0 + h * stride, (uint)stride);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
source.UnlockBits(sourceData); clone.UnlockBits(cloneData);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{ // Handle or log exception if needed
|
||||||
|
} return clone; }
|
||||||
|
|
||||||
|
|
||||||
|
public static Bitmap BitmapDeepClone(Bitmap source)
|
||||||
|
{
|
||||||
|
Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
|
||||||
|
if (PixelSize == 1)
|
||||||
|
{
|
||||||
|
ColorPalette cp = clone.Palette;
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
cp.Entries[i] = Color.FromArgb(255, i, i, i);
|
||||||
|
}
|
||||||
|
clone.Palette = cp;
|
||||||
|
}
|
||||||
|
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
|
||||||
|
BitmapData source_bitmap = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
|
||||||
|
BitmapData destination_bitmap = clone.LockBits(rect, ImageLockMode.ReadWrite, clone.PixelFormat);
|
||||||
|
|
||||||
|
int depth_width = source_bitmap.Width * PixelSize;
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
byte* source_ptr = (byte*)source_bitmap.Scan0;
|
||||||
|
byte* destination_ptr = (byte*)destination_bitmap.Scan0;
|
||||||
|
|
||||||
|
int offset = source_bitmap.Stride - depth_width;
|
||||||
|
|
||||||
|
for (int i = 0; i < source_bitmap.Height; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < depth_width; j++, source_ptr++, destination_ptr++)
|
||||||
|
{
|
||||||
|
*destination_ptr = *source_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
source_ptr += offset;
|
||||||
|
destination_ptr += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
source.UnlockBits(source_bitmap);
|
||||||
|
clone.UnlockBits(destination_bitmap);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Bitmap HConnectBitmap(this Bitmap map1, Bitmap map2)
|
||||||
|
{
|
||||||
|
Bitmap connectImage = null;
|
||||||
|
if (map1 == null || map2 == null)
|
||||||
|
return null;
|
||||||
|
//横向拼接
|
||||||
|
int width = map1.Width + map2.Width;
|
||||||
|
//高度不变
|
||||||
|
int height = Math.Max(map1.Height, map2.Height);
|
||||||
|
connectImage = new Bitmap(width, height);
|
||||||
|
using (Graphics graph = Graphics.FromImage(connectImage))
|
||||||
|
{
|
||||||
|
graph.DrawImage(connectImage, width, height);
|
||||||
|
graph.Clear(System.Drawing.Color.White);
|
||||||
|
graph.DrawImage(map1, 0, 0);
|
||||||
|
graph.DrawImage(map2, map1.Width, 0);
|
||||||
|
}
|
||||||
|
return connectImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntPtr FloatToIntptr(float[] bytes)
|
||||||
|
{
|
||||||
|
GCHandle hObject = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||||
|
return hObject.AddrOfPinnedObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将Btimap类转换为byte[]类函数
|
||||||
|
public static byte[] GetBGRValues(Bitmap bmp, out int stride)
|
||||||
|
{
|
||||||
|
var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
|
||||||
|
var bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
|
||||||
|
stride = bmpData.Stride;
|
||||||
|
var rowBytes = bmpData.Width * Image.GetPixelFormatSize(bmp.PixelFormat) / 8;
|
||||||
|
var imgBytes = bmp.Height * rowBytes;
|
||||||
|
byte[] rgbValues = new byte[imgBytes];
|
||||||
|
IntPtr ptr = bmpData.Scan0;
|
||||||
|
for (var i = 0; i < bmp.Height; i++)
|
||||||
|
{
|
||||||
|
Marshal.Copy(ptr, rgbValues, i * rowBytes, rowBytes);
|
||||||
|
ptr += bmpData.Stride;
|
||||||
|
}
|
||||||
|
bmp.UnlockBits(bmpData);
|
||||||
|
return rgbValues;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 缺陷灰度图转彩色图像函数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="src">灰度图</param>
|
||||||
|
/// <returns>返回构造的伪彩色图像</returns>
|
||||||
|
public static Bitmap GrayMapToColorMap(this Bitmap src, Dictionary<int, Color> indexColorDict = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Stopwatch sw = new Stopwatch();
|
||||||
|
//sw.Start();
|
||||||
|
|
||||||
|
Bitmap dest = new Bitmap(src.Width, src.Height, PixelFormat.Format32bppArgb);
|
||||||
|
|
||||||
|
int destHeight = dest.Height;
|
||||||
|
int destWidth = dest.Width;
|
||||||
|
|
||||||
|
Rectangle rect = new Rectangle(0, 0, destWidth, destHeight);
|
||||||
|
BitmapData bmpDataDest = dest.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||||
|
BitmapData bmpDataSrc = src.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
|
||||||
|
int strideDest = bmpDataDest.Stride;
|
||||||
|
|
||||||
|
int strideSrc = bmpDataSrc.Stride;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
byte* pDest = (byte*)bmpDataDest.Scan0.ToPointer();
|
||||||
|
byte* pSrc = (byte*)bmpDataSrc.Scan0.ToPointer();
|
||||||
|
|
||||||
|
Parallel.For(0, destHeight, y =>
|
||||||
|
{
|
||||||
|
Parallel.For(0, destWidth, x =>
|
||||||
|
{
|
||||||
|
int pixel = pSrc[y * strideSrc + x];
|
||||||
|
int startIndex = y * strideDest + x * 4;
|
||||||
|
if (pixel >= 0 && pixel <= 63)
|
||||||
|
{
|
||||||
|
Color color = Color.Red;
|
||||||
|
if (indexColorDict != null && indexColorDict.ContainsKey(pixel))
|
||||||
|
{
|
||||||
|
color = indexColorDict[pixel];
|
||||||
|
}
|
||||||
|
|
||||||
|
byte R = color.R;
|
||||||
|
byte G = color.G;
|
||||||
|
byte B = color.B;
|
||||||
|
|
||||||
|
pDest[startIndex] = B;
|
||||||
|
pDest[startIndex + 1] = G;
|
||||||
|
pDest[startIndex + 2] = R;
|
||||||
|
pDest[startIndex + 3] = 100;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pDest[startIndex] = 255;
|
||||||
|
pDest[startIndex + 1] = 255;
|
||||||
|
pDest[startIndex + 2] = 255;
|
||||||
|
pDest[startIndex + 3] = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
dest.UnlockBits(bmpDataDest);
|
||||||
|
src.UnlockBits(bmpDataSrc);
|
||||||
|
|
||||||
|
//sw.Stop();
|
||||||
|
//Console.WriteLine($"转换耗时:{sw.ElapsedMilliseconds}");
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Sort<T>(this ObservableCollection<T> collection) where T : IComparable<T>
|
||||||
|
{
|
||||||
|
List<T> sortedList = collection.OrderByDescending(x => x).ToList();//这里用降序
|
||||||
|
for (int i = 0; i < sortedList.Count(); i++)
|
||||||
|
{
|
||||||
|
collection.Move(collection.IndexOf(sortedList[i]), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得字符串中开始和结束字符串中间的值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sourse"></param>
|
||||||
|
/// <param name="startstr"></param>
|
||||||
|
/// <param name="endstr"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string GetMidString(string sourse, string startstr, string endstr)
|
||||||
|
{
|
||||||
|
string result = string.Empty;
|
||||||
|
int startindex, endindex;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
startindex = sourse.IndexOf(startstr);
|
||||||
|
if (startindex == -1)
|
||||||
|
return result;
|
||||||
|
string tmpstr = sourse.Substring(startindex + startstr.Length);
|
||||||
|
endindex = tmpstr.IndexOf(endstr);
|
||||||
|
if (endindex == -1)
|
||||||
|
return result;
|
||||||
|
result = tmpstr.Remove(endindex);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得字符串中开始和结束字符串中间的值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="t">字符串</param>
|
||||||
|
/// <param name="k">开始</param>
|
||||||
|
/// <param name="j">结束</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static string GetMidString2(string sourse, string startstr, string endstr) //截取指定文本,和易语言的取文本中间差不多
|
||||||
|
{
|
||||||
|
try //异常捕捉
|
||||||
|
{
|
||||||
|
var kn = sourse.IndexOf(startstr, StringComparison.Ordinal) + startstr.Length;
|
||||||
|
var jn = sourse.IndexOf(endstr, kn, StringComparison.Ordinal);
|
||||||
|
return sourse.Substring(kn, jn - kn);
|
||||||
|
}
|
||||||
|
catch //如果发现未知的错误,比如上面的代码出错了,就执行下面这句代码
|
||||||
|
{
|
||||||
|
return ""; //返回空
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 布尔类型转换为整型
|
||||||
|
public static int ToInt(this object obj)
|
||||||
|
{
|
||||||
|
if (Convert.ToBoolean(obj) == true)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 整型转换为布尔类型
|
||||||
|
public static bool ToBool(this object obj)
|
||||||
|
{
|
||||||
|
if (Convert.ToInt32(obj) == 1)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static object GetProperty(this object o, string member)
|
||||||
|
{
|
||||||
|
if (o == null) throw new ArgumentNullException("o");
|
||||||
|
if (member == null) throw new ArgumentNullException("member");
|
||||||
|
Type scope = o.GetType();
|
||||||
|
IDynamicMetaObjectProvider provider = o as IDynamicMetaObjectProvider;
|
||||||
|
if (provider != null)
|
||||||
|
{
|
||||||
|
ParameterExpression param = Expression.Parameter(typeof(object));
|
||||||
|
DynamicMetaObject mobj = provider.GetMetaObject(param);
|
||||||
|
GetMemberBinder binder = (GetMemberBinder)Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, member, scope, new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(0, null) });
|
||||||
|
DynamicMetaObject ret = mobj.BindGetMember(binder);
|
||||||
|
BlockExpression final = Expression.Block(
|
||||||
|
Expression.Label(CallSiteBinder.UpdateLabel),
|
||||||
|
ret.Expression
|
||||||
|
);
|
||||||
|
LambdaExpression lambda = Expression.Lambda(final, param);
|
||||||
|
Delegate del = lambda.Compile();
|
||||||
|
return del.DynamicInvoke(o);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return o.GetType().GetProperty(member, BindingFlags.Public | BindingFlags.Instance).GetValue(o, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 检测文件状态及操作方式选择
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
private static extern IntPtr _lopen(string lpPathName, int iReadWrite);
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
private static extern bool CloseHandle(IntPtr hObject);
|
||||||
|
private const int OF_READWRITE = 2;
|
||||||
|
private const int OF_SHARE_DENY_NONE = 0x40;
|
||||||
|
private static readonly IntPtr HFILE_ERROR = new IntPtr(-1);
|
||||||
|
/// <summary>
|
||||||
|
/// 检测文件是否只读或被使用
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="FileNames">要检测的文件</param>
|
||||||
|
/// <returns>true可用,false在用或只读</returns>
|
||||||
|
public static bool CheckFilesCanUse(string fileName)
|
||||||
|
{
|
||||||
|
if (!File.Exists(fileName))
|
||||||
|
return true;//文件不存在
|
||||||
|
if ((File.GetAttributes(fileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
|
||||||
|
return false; //文件只读
|
||||||
|
IntPtr vHandle = _lopen(fileName, OF_READWRITE | OF_SHARE_DENY_NONE);
|
||||||
|
if (vHandle == HFILE_ERROR)
|
||||||
|
{
|
||||||
|
CloseHandle(vHandle);
|
||||||
|
return false; //文件被占用
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(vHandle); //文件没被占用
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取指定文件夹下所有的文件名称
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderName">指定文件夹名称,绝对路径</param>
|
||||||
|
/// <param name="fileFilter">文件类型过滤,根据文件后缀名,如:*,*.txt,*.xls</param>
|
||||||
|
/// <param name="isContainSubFolder">是否包含子文件夹</param>
|
||||||
|
/// <returns>ArrayList数组,为所有需要的文件路径名称</returns>
|
||||||
|
public static List<FileInfo> GetAllFilesByFolder(string folderName, string fileFilter, bool isContainSubFolder = false)
|
||||||
|
{
|
||||||
|
List<FileInfo> resList = new List<FileInfo>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DirectoryInfo currDir = new DirectoryInfo(folderName);//当前目录
|
||||||
|
FileInfo[] currFiles = currDir.GetFiles(fileFilter);//当前目录文件
|
||||||
|
foreach (FileInfo file in currFiles)
|
||||||
|
{
|
||||||
|
if (fileFilter.ToLower().IndexOf(file.Extension.ToLower()) >= 0)
|
||||||
|
{
|
||||||
|
resList.Add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isContainSubFolder)
|
||||||
|
{
|
||||||
|
string[] subFolders = Directory.GetDirectories(folderName);
|
||||||
|
foreach (string subFolder in subFolders)
|
||||||
|
{
|
||||||
|
resList.AddRange(GetAllFilesByFolder(subFolder, fileFilter));//递归
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
return resList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取指定文件夹下所有的文件名称,不过滤文件类型
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderName">指定文件夹名称,绝对路径</param>
|
||||||
|
/// <param name="isContainSubFolder">是否包含子文件夹</param>
|
||||||
|
/// <returns>ArrayList数组,为所有需要的文件路径名称</returns>
|
||||||
|
public static List<FileInfo> GetAllFilesByFolder(string folderName, bool isContainSubFolder)
|
||||||
|
{
|
||||||
|
return GetAllFilesByFolder(folderName, "*", isContainSubFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Compare<T, C> : IEqualityComparer<T>
|
||||||
|
{
|
||||||
|
private Func<T, C> _getField;
|
||||||
|
public Compare(Func<T, C> getfield)
|
||||||
|
{
|
||||||
|
_getField = getfield;
|
||||||
|
}
|
||||||
|
public bool Equals(T x, T y)
|
||||||
|
{
|
||||||
|
return EqualityComparer<C>.Default.Equals(_getField(x), _getField(y));
|
||||||
|
}
|
||||||
|
public int GetHashCode(T obj)
|
||||||
|
{
|
||||||
|
return EqualityComparer<C>.Default.GetHashCode(_getField(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ObjectExtensions
|
||||||
|
{
|
||||||
|
public static IEnumerable<T> DistinctBy<T, C>(this IEnumerable<T> source, Func<T, C> getfield)
|
||||||
|
{
|
||||||
|
return source.Distinct(new Compare<T, C>(getfield));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IQueryable<T> DistinctBy<T, C>(this IQueryable<T> source, Func<T, C> getfield)
|
||||||
|
{
|
||||||
|
return source.Distinct(new Compare<T, C>(getfield));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user