using Bro.Common.Base;
|
using Bro.Common.Helper;
|
using Bro.Common.Interface;
|
using Bro.Common.Model;
|
using Bro.M071.DBManager;
|
using Bro.M071.Model;
|
using Bro.M071.Model.Model;
|
using Bro.M071.Process.UI;
|
using Bro.Process;
|
using HalconDotNet;
|
using Newtonsoft.Json;
|
using OfficeOpenXml;
|
using OfficeOpenXml.Style;
|
using System;
|
using System.Collections.Generic;
|
using System.ComponentModel;
|
using System.Drawing;
|
using System.Drawing.Imaging;
|
using System.IO;
|
using System.Linq;
|
using System.Text;
|
using System.Threading;
|
using System.Threading.Tasks;
|
using static Bro.Common.Helper.EnumHelper;
|
|
namespace Bro.M071.Process
|
{
|
[Process("M071", EnumHelper.DeviceAttributeType.Device)]
|
public partial class M071Process : ProcessControl
|
{
|
#region 构造函数
|
public M071Process() : base() { }
|
public M071Process(string productionCode) : base(productionCode) { }
|
#endregion
|
|
#region 配置
|
M071Config Config
|
{
|
get => IConfig as M071Config;
|
}
|
#endregion
|
|
#region 事件
|
public event Action OnMeasureStart;
|
public event Action OnClearBarcode;
|
public event Action<IShapeElement> OnElementUpdated;
|
public event Action<MachineState> OnMachineStateChanged;
|
public event Action OnFullResetDone;
|
#endregion
|
|
string _precision = "f3";
|
|
|
public override void Open()
|
{
|
InitialSetting();
|
|
base.Open();
|
|
InitialMotionCardBaseAxisAlarm();
|
|
SwitchBeep(false);
|
SwitchLightGreen(false);
|
SwitchLightRed(false);
|
SwitchLightYellow(false);
|
|
Reset(null, null, null);
|
FullReset(null);
|
|
if (Config.Precision > 0)
|
{
|
_precision = "f" + Config.Precision;
|
}
|
}
|
|
private void InitialMotionCardBaseAxisAlarm()
|
{
|
if (outputCtrlCard != null)
|
{
|
outputCtrlCard.OnAxisAlarmRaised -= MotionCard_OnAxisAlarmRaised;
|
outputCtrlCard.OnAxisAlarmRaised += MotionCard_OnAxisAlarmRaised;
|
}
|
}
|
|
private void MotionCard_OnAxisAlarmRaised(int axisIndex, string alarmMsg)
|
{
|
RaisedAlarm(alarmMsg);
|
MachineState = MachineState.Alarm;
|
}
|
|
private void InitialSetting()
|
{
|
//数据库迁移检查
|
//DatabaseInitialize.Initialize();
|
|
MotionCardSettingCheck();
|
|
Config.SnapshotPointCollection.ForEach(u =>
|
{
|
u.GetHalconToolPathList().ForEach(path =>
|
{
|
LoadHalconTool(path, u.Id);
|
});
|
});
|
|
Config.KeyUnitCollection.ForEach(u =>
|
{
|
if (!u.IsEnabled)
|
return;
|
|
var snapshotPoint = Config.SnapshotPointCollection.FirstOrDefault(s => s.Id == u.SnapshotPointId && s.IsEnabled);
|
if (snapshotPoint == null)
|
throw new ProcessException($"{u.AliasName}未设置可用拍照点位");
|
|
if (u.ImageSeq < 1)
|
throw new ProcessException($"{u.AliasName}图片序号小于1");
|
|
var algo = Config.KeyAlgorithemCollection.FirstOrDefault(a => a.Id == u.KeyAlgorithemId);
|
if (algo == null)
|
throw new ProcessException($"{u.AliasName}未设置检测算法");
|
|
u.KeyAlgorithemPath = algo.AlgorithemPath;
|
LoadHalconTool(u.KeyAlgorithemPath, u.AliasName);
|
|
var resultSet = Config.KeyResultCollection.FirstOrDefault(r => r.Id == u.KeyResultId);
|
if (resultSet == null)
|
throw new ProcessException($"{u.AliasName}未设置检测结果配置");
|
|
u.KeyResultList = new List<string>(resultSet.Results);
|
});
|
|
Config.MeasurementUnitCollection.ForEach(u =>
|
{
|
if (!u.IsEnabled)
|
return;
|
|
var spec = Config.MeasureTypeCollection.FirstOrDefault(s => s.Code == u.MeasureType);
|
if (spec == null)
|
throw new ProcessException($"{u.GetDisplayText()}未设置检测类型");
|
|
u.Spec = new MeasureType();
|
u.Spec.DataFrom(spec);
|
|
LoadHalconTool(u.Spec.AlgorithemPath, u.Id);
|
|
u.KeyUnitCollection.ForEach(b =>
|
{
|
var keyRespone = Config.KeyUnitCollection.Where(ku => ku.IsEnabled && ku.Key == b.Key).ToList();
|
if (keyRespone.Count == 0)
|
throw new ProcessException($"{u.GetDisplayText()}对应的单键不存在或不可用");
|
|
if (b.KeyResultId == "All")
|
{
|
keyRespone.SelectMany(kr => kr.KeyResultList).ToList().ForEach(r =>
|
{
|
b.MeasureValueDict[r] = null;
|
});
|
}
|
else
|
{
|
b.MeasureValueDict[b.KeyResultId] = null;
|
}
|
});
|
});
|
}
|
|
#region 流程中抛出异常
|
public override void ExceptionRaisedInMonitor(Exception ex)
|
{
|
if (ex is ProcessException pEx)
|
{
|
if (pEx.Level >= ExceptionLevel.Fatal)
|
{
|
RaisedAlarm(pEx.Message);
|
MachineState = MachineState.Alarm;
|
}
|
}
|
else
|
{
|
RaisedAlarm(ex.Message);
|
MachineState = MachineState.Alarm;
|
}
|
}
|
#endregion
|
|
public string BarCode { get; set; }
|
|
List<ProductionMeasurement> productionList = new List<ProductionMeasurement>();
|
|
[ProcessMethod("", "StartJob", "开始扫描", InvokeType.TestInvoke)]
|
public ProcessResponse StartJob(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice)
|
{
|
if (!IsAllowedWork)
|
{
|
throw new ProcessException(SafetyMsg, null, ExceptionLevel.Fatal);
|
}
|
|
if (MachineState != MachineState.Ready)
|
throw new ProcessException("机台未就绪,请勿开始测量", null, ExceptionLevel.Fatal);
|
|
if (string.IsNullOrWhiteSpace(BarCode))
|
{
|
OnClearBarcode?.Invoke();
|
throw new ProcessException("未输入产品条码,请勿开始测量");
|
}
|
|
MachineState = MachineState.Running;
|
OnMeasureStart?.Invoke();
|
|
//var measurements = Config.MeasurementUnitCollection.Where(u => u.IsEnabled).ToList().DeepSerializeClone();
|
//measurements.ForEach(m =>
|
//{
|
// m.InitialKeyUnitMeasureChanged();
|
//});
|
|
List<MeasurementUnit> measurements = new List<MeasurementUnit>();
|
Config.MeasurementUnitCollection.Where(u => u.IsEnabled).ToList().ForEach(u =>
|
{
|
var m = u.Copy();
|
m.InitialKeyUnitMeasureChanged();
|
measurements.Add(m);
|
});
|
|
var pMeasure = new ProductionMeasurement()
|
{
|
Barcode = BarCode,
|
Measurements = measurements,
|
StartTime = DateTime.Now,
|
};
|
|
BarCode = "";
|
|
var existedProduction = productionList.FirstOrDefault(u => u.Barcode == pMeasure.Barcode);
|
if (existedProduction != null)
|
{
|
productionList.Remove(existedProduction);
|
existedProduction.Dispose();
|
existedProduction = null;
|
}
|
|
productionList.Add(pMeasure);
|
|
pMeasure.InitialMeasurementsPropertyChanged();
|
pMeasure.PropertyChanged += MeasureProduction_PropertyChanged;
|
|
Config.SnapshotPointCollection.Where(u => u.IsEnabled).ToList().ForEach(s =>
|
{
|
_pausedHandle.Wait();
|
|
if (MachineState == MachineState.Ready)
|
return;
|
|
if (MachineState != MachineState.Running && MachineState != MachineState.Pause)
|
{
|
throw new ProcessException("机台状态不在运行中,退出检测");
|
}
|
|
IDevice device = DeviceCollection.FirstOrDefault(u => u.Id == s.MotionOp.Device);
|
if (device == null)
|
throw new ProcessException($"{s.Name}拍照点位未设置运动设备");
|
|
IMotionCard motionDevice = device as IMotionCard;
|
|
if (motionDevice == null)
|
throw new ProcessException($"{s.Name}拍照点位设置{device.Name}不是运动设备");
|
|
var response = motionDevice.Run(s.MotionOp.OpConfig);
|
if (!response.Result)
|
{
|
throw new ProcessException($"{device.Name}异常,{response.Message}", null, ExceptionLevel.Fatal);
|
}
|
|
CameraBase camera = DeviceCollection.FirstOrDefault(u => u.Id == s.CameraOp.Device) as CameraBase;
|
if (camera == null)
|
return;
|
|
IImageSet set = null;
|
try
|
{
|
set = CollectHImage(camera, s.CameraOp.OpConfig);
|
}
|
catch (ProcessException pEx)
|
{
|
pEx.Level = ExceptionLevel.Fatal;
|
throw pEx;
|
}
|
|
if (set == null)
|
{
|
return;
|
}
|
|
RunImageHandle(s.CameraOp.OpConfig, set, s.Id, s.Name, pMeasure.Measurements);
|
});
|
|
LogAsync(DateTime.Now, $"{pMeasure.Barcode}测量动作完成", "");
|
|
GC.Collect(0, GCCollectionMode.Optimized);
|
|
return new ProcessResponse(true);
|
}
|
|
#region 双手启动
|
bool isLeftStart = false;
|
bool IsLeftStart
|
{
|
get => isLeftStart;
|
set
|
{
|
isLeftStart = value;
|
StartCheck();
|
}
|
}
|
|
bool isRightStart = false;
|
bool IsRightStart
|
{
|
get => isRightStart;
|
set
|
{
|
isRightStart = value;
|
StartCheck();
|
}
|
}
|
|
private void StartCheck()
|
{
|
if (isRightStart && isLeftStart)
|
{
|
StartJob(null, null, null);
|
}
|
}
|
|
[ProcessMethod("", "Start_Left", "左手启动", InvokeType.TestInvoke)]
|
public ProcessResponse Start_Left(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice)
|
{
|
if (opConfig.InputPara != null && opConfig.InputPara.Count > 0)
|
{
|
IsLeftStart = opConfig.InputPara[0] == 1;
|
}
|
|
return new ProcessResponse();
|
}
|
|
[ProcessMethod("", "Start_Right", "右手启动", InvokeType.TestInvoke)]
|
public ProcessResponse Start_Right(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice)
|
{
|
if (opConfig.InputPara != null && opConfig.InputPara.Count > 0)
|
{
|
IsRightStart = opConfig.InputPara[0] == 1;
|
}
|
|
return new ProcessResponse();
|
}
|
#endregion
|
|
#region 私有方法
|
private void MeasureProduction_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
{
|
if (sender is ProductionMeasurement pMeasure)
|
{
|
var production = productionList.FirstOrDefault(u => u.Barcode == pMeasure.Barcode);
|
if (production == null)
|
return;
|
|
lock (production)
|
{
|
//检查是否全部完成
|
pMeasure.Measurements?.ForEach(m =>
|
{
|
if (m.KeyUnitCollection.All(k => k.IsDone != null))
|
{
|
if (!m.IsUpdated)
|
{
|
if (m.KeyUnitCollection.Any(k => k.IsDone == false))
|
{
|
m.Spec.ActualValue = -999;
|
}
|
else
|
{
|
string toolKey = m.Id + "|" + m.Spec.AlgorithemPath;
|
if (!_halconToolDict.ContainsKey(toolKey))
|
{
|
LogAsync(DateTime.Now, $"{m.GetDisplayText()}{m.Spec.Code}算法未初始化", "");
|
m.Spec.ActualValue = -999;
|
}
|
else
|
{
|
//var array = m.KeyUnitCollection.SelectMany(u => u.MeasureValueDict.Values.ToList().ConvertAll(v => v ?? -999)).ToArray();
|
var array = m.KeyUnitCollection.SelectMany(u => u.MeasureValueDict.Values.Select(v => v ?? -999)).ToArray();
|
|
if (array == null || array.Length == 0)
|
{
|
LogAsync(DateTime.Now, $"{m.GetDisplayText()}{m.Spec.Code}未能获取对应检测值", "");
|
m.Spec.ActualValue = -999;
|
}
|
else
|
{
|
|
_halconToolDict[toolKey].InputTupleDic["INPUT_Params"] = new HTuple(array);
|
if (!_halconToolDict[toolKey].RunProcedure(out string error))
|
{
|
LogAsync(DateTime.Now, $"{m.GetDisplayText()}{m.Spec.Code}算法异常,{error}", "");
|
m.Spec.ActualValue = -999;
|
}
|
else
|
{
|
m.Spec.ActualValue = double.Parse(_halconToolDict[toolKey].GetResultTuple("OUTPUT_Result").D.ToString(_precision));
|
//LogAsync(DateTime.Now, $"{m.GetDisplayText()}数据{m.Spec.ActualValue},结果{(m.Spec.MeasureResult == null ? "TBD" : (m.Spec.MeasureResult == true ? "OK" : "NG"))}", "");
|
}
|
}
|
}
|
}
|
|
//LogAsync(DateTime.Now, $"{m.GetDisplayText()}检测结果", $"{((m.Spec.MeasureResult ?? false) ? "OK" : "NG")}");
|
|
KeyIndicator indicator = new KeyIndicator(m.Id, m.DisplayLocation);
|
indicator.Text = (m.Spec.ActualValue == null || m.Spec.ActualValue == -999) ? "NA" : m.Spec.ActualValue.Value.ToString(_precision);
|
indicator.ResultState = m.Spec.MeasureResult;
|
pMeasure.ElementList.Add(indicator);
|
//输出图形基元到界面
|
OnElementUpdated?.Invoke(indicator);
|
|
SaveKeyImages(pMeasure.Barcode, m);
|
|
m.IsUpdated = true;
|
}
|
}
|
});
|
|
if (!pMeasure.Measurements.All(m => m.IsUpdated))
|
{
|
return;
|
}
|
}
|
|
pMeasure.EndTime = DateTime.Now;
|
bool pResult = pMeasure.Measurements.All(u => u.Spec.MeasureResult == true);
|
pMeasure.PResult = pResult ? "OK" : "NG";
|
OnUpdateResult?.Invoke(DateTime.Now, pResult ? 1 : 0);
|
OnUpdateCT?.Invoke((float)(pMeasure.EndTime.Value - pMeasure.StartTime.Value).TotalSeconds);
|
|
LogAsync(DateTime.Now, $"{pMeasure.Barcode} 检测完成,结果 {pMeasure.PResult}", "");
|
|
if (MachineState == MachineState.Running)
|
MachineState = MachineState.Ready;
|
|
var measurementUnitResultAndKeyUnitDataSet = GetMeasurementUnitResultAndKeyUnitData(pMeasure);
|
|
//MES输出 todo
|
if (Config.IsEnableMESUpload)
|
{
|
}
|
|
//Excel报表输出 (单个产品的excel导出)
|
//ExportProductionExcel(measurementUnitResultAndKeyUnitDataSet);
|
|
ExportProductionInColumns(measurementUnitResultAndKeyUnitDataSet);
|
////数据库保存
|
//SaveProductionData(measurementUnitResultAndKeyUnitDataSet);
|
|
SaveWholeImage(pMeasure);
|
|
productionList.RemoveAll(p => p.Barcode == pMeasure.Barcode);
|
pMeasure.Dispose();
|
//LogAsync(DateTime.Now, $"{pMeasure.Barcode}产品信息释放完成", JsonConvert.SerializeObject(pMeasure));
|
}
|
}
|
|
KeyUnitDataManager keyUnitDataManager = new KeyUnitDataManager();
|
MeasurementUnitResultManager measurementUnitResultManager = new MeasurementUnitResultManager();
|
MeasurementAndKeyDataRelationManager measurementAndKeyDataRelationManager = new MeasurementAndKeyDataRelationManager();
|
ProductionMeasurementRecordsManager productionMeasurementRecordsManager = new ProductionMeasurementRecordsManager();
|
|
static object dataSaveLock = new object();
|
|
private async void SaveProductionData(ProductionMeasurementUnitResultAndKeyUnitDataSet measurementUnitResultAndKeyUnitDataSet)
|
{
|
await Task.Run(() =>
|
{
|
try
|
{
|
lock (dataSaveLock)
|
{
|
// 获取 产品数据 并保存
|
var productionMeasurementRecords = measurementUnitResultAndKeyUnitDataSet.ProductionMeasurementRecord;
|
productionMeasurementRecordsManager.CreateModel(productionMeasurementRecords);
|
|
// 获取 原始数据 并保存
|
var keyUnitDatas = measurementUnitResultAndKeyUnitDataSet.KeyUnitDataList;
|
keyUnitDataManager.BatchAddKeyUnitData(keyUnitDatas);
|
|
// 获取 检测结果数据 并保存
|
var measurementUnitResults = measurementUnitResultAndKeyUnitDataSet.MeasurementUnitResultList;
|
measurementUnitResultManager.BatchAddMeasurementUnitResult(measurementUnitResults);
|
|
// 获取 关系数据并保存
|
var measurementAndKeyDataRelationList = measurementUnitResultAndKeyUnitDataSet.MeasurementAndKeyDataRelationList;
|
measurementAndKeyDataRelationManager.BatchAddMeasurementAndKeyDataRelation(measurementAndKeyDataRelationList);
|
}
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, "数据保存异常", ex.GetExceptionMessage());
|
}
|
});
|
}
|
|
private ProductionMeasurementUnitResultAndKeyUnitDataSet GetMeasurementUnitResultAndKeyUnitData(ProductionMeasurement pData)
|
{
|
ProductionMeasurementUnitResultAndKeyUnitDataSet measurementUnitResultAndKeyUnitDataSet = new ProductionMeasurementUnitResultAndKeyUnitDataSet();
|
|
try
|
{
|
|
//产品数据
|
ProductionMeasurementRecords productionMeasurementRecords = new ProductionMeasurementRecords();
|
//关系数据
|
List<MeasurementAndKeyDataRelation> measurementAndKeyDataRelationList = new List<MeasurementAndKeyDataRelation>();
|
//原始数据
|
List<KeyUnitData> keyUnitDatas = new List<KeyUnitData>();
|
// 单个产品的测量汇总
|
List<MeasurementUnitResult> measurementUnitResults = new List<MeasurementUnitResult>();
|
|
productionMeasurementRecords.ProductionBarcode = pData.Barcode;
|
productionMeasurementRecords.ProductionCode = ProductionCode;
|
productionMeasurementRecords.ProductionResult = pData.PResult;
|
productionMeasurementRecords.OperationStartTime = pData.StartTime.GetValueOrDefault();
|
productionMeasurementRecords.OperationEndTime = pData.EndTime.GetValueOrDefault();
|
|
measurementUnitResultAndKeyUnitDataSet.ProductionMeasurementRecord = productionMeasurementRecords;
|
|
foreach (var measurementUnit in pData.Measurements)//获取到单个测量项结果
|
{
|
MeasurementUnitResult measurementUnitResult = new MeasurementUnitResult();
|
measurementUnitResult.ProductionMeasurementRecordsId = productionMeasurementRecords.ID;
|
measurementUnitResult.ProductionBarcode = productionMeasurementRecords.ProductionBarcode;
|
measurementUnitResult.MeasurementName = measurementUnit.GetDisplayText();
|
|
if (measurementUnit.MeasureType == "Alignment" || measurementUnit.MeasureType == "Slant")
|
{
|
measurementUnitResult.Keys = string.Join("-", measurementUnit.KeyUnitCollection.Select(u => u.Key));
|
measurementUnitResult.Positions = string.Join("-", measurementUnit.KeyUnitCollection.Select(u => u.KeyResultId));
|
}
|
else if (measurementUnit.MeasureType == "RowAlignment")
|
{
|
measurementUnitResult.Keys = measurementUnit.KeyUnitCollection[0].Key + "~" + measurementUnit.KeyUnitCollection[measurementUnit.KeyUnitCollection.Count() - 1].Key;
|
measurementUnitResult.Keys = measurementUnit.KeyUnitCollection[0].KeyResultId + "~" + measurementUnit.KeyUnitCollection[measurementUnit.KeyUnitCollection.Count() - 1].KeyResultId;
|
}
|
measurementUnitResult.MeasurementType = measurementUnit.MeasureType;
|
measurementUnitResult.MeasurementValue = measurementUnit.Spec.ActualValue == null ? "NA" : measurementUnit.Spec.ActualValue.Value.ToString(_precision);
|
measurementUnitResult.MeasurementResult = measurementUnit.Spec.MeasureResult.Value ? "OK" : "NG";
|
|
measurementUnitResults.Add(measurementUnitResult);
|
|
foreach (var keyUnit in measurementUnit.KeyUnitCollection)//获取单个键的测量结果
|
{
|
foreach (var keyValue in keyUnit.MeasureValueDict)//获取单个键的单个测量item 结果
|
{
|
bool isExist = keyUnitDatas.Any(u => u.Key == keyUnit.Key && u.MeasurementItem == keyValue.Key);
|
if (!isExist)//已存在 不重复添加原始数据
|
{
|
KeyUnitData keyUnitData = new KeyUnitData();
|
keyUnitData.ProductionBarcode = productionMeasurementRecords.ProductionBarcode;
|
keyUnitData.Key = keyUnit.Key;
|
keyUnitData.MeasurementItem = keyValue.Key;
|
keyUnitData.ItemValue = keyValue.Value == null ? "NA" : keyValue.Value.Value.ToString(_precision);
|
keyUnitDatas.Add(keyUnitData);
|
|
MeasurementAndKeyDataRelation measurementAndKeyDataRelation = new MeasurementAndKeyDataRelation();
|
measurementAndKeyDataRelation.MeasurementUnitResultId = measurementUnitResult.ID;
|
measurementAndKeyDataRelation.KeyUnitDataId = keyUnitData.ID;
|
measurementAndKeyDataRelationList.Add(measurementAndKeyDataRelation);
|
}
|
}
|
}
|
}
|
measurementUnitResultAndKeyUnitDataSet.ProductionMeasurementRecord = productionMeasurementRecords;
|
measurementUnitResultAndKeyUnitDataSet.MeasurementAndKeyDataRelationList = measurementAndKeyDataRelationList;
|
measurementUnitResultAndKeyUnitDataSet.KeyUnitDataList = keyUnitDatas;
|
measurementUnitResultAndKeyUnitDataSet.MeasurementUnitResultList = measurementUnitResults;
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, "数据获取异常", ex.GetExceptionMessage());
|
}
|
return measurementUnitResultAndKeyUnitDataSet;
|
}
|
|
private async void ExportProductionExcel(ProductionMeasurementUnitResultAndKeyUnitDataSet measurementUnitResultAndKeyUnitDataSet)
|
{
|
if (!Config.IsCSVOutputEnabled)
|
return;
|
|
await Task.Run(() =>
|
{
|
ExcelExportSet excelExportDto = new ExcelExportSet();
|
excelExportDto.Worksheets = new List<string>() { "原始数据", "检测结果" };
|
var keyUnitColumns = new Dictionary<string, string>()
|
{
|
{"ProductionBarcode", "产品条码"},
|
{"Key", "键"},
|
{"MeasurementItem", "检测项"},
|
{"ItemValue", "检测值"}
|
};
|
var measurementUnitResultColumns = new Dictionary<string, string>()
|
{
|
{"ProductionBarcode", "产品条码"},
|
{"MeasurementName", "检测名称"},
|
{"MeasurementType", "检测类型"},
|
{"MeasurementValue", "检测值"},
|
{"MeasurementResult", "检测结果"},
|
};
|
excelExportDto.WorksheetColumns[excelExportDto.Worksheets[0]] = keyUnitColumns;
|
excelExportDto.WorksheetColumns[excelExportDto.Worksheets[1]] = measurementUnitResultColumns;
|
|
excelExportDto.WorksheetDataTable[excelExportDto.Worksheets[0]] = ExcelExportHelper.ListToDataTable(measurementUnitResultAndKeyUnitDataSet.KeyUnitDataList, keyUnitColumns);
|
excelExportDto.WorksheetDataTable[excelExportDto.Worksheets[1]] = ExcelExportHelper.ListToDataTable(measurementUnitResultAndKeyUnitDataSet.MeasurementUnitResultList, measurementUnitResultColumns); ;
|
|
if (!Directory.Exists(Config.LogPath))
|
{
|
Directory.CreateDirectory(Config.LogPath);
|
}
|
var fileName = Path.Combine(Config.LogPath, $"ProductionData_{DateTime.Now.ToString("yyyyMMdd")}.xlsx");
|
|
byte[] filecontent = ExcelExportHelper.CreateOrAppendExcel(excelExportDto, fileName);
|
FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
|
fs.Write(filecontent, 0, filecontent.Length);
|
fs.Flush();
|
fs.Close();
|
});
|
}
|
|
static object excelExportLock = new object();
|
private async void ExportProductionInColumns(ProductionMeasurementUnitResultAndKeyUnitDataSet exportData)
|
{
|
if (!Config.IsCSVOutputEnabled)
|
return;
|
|
await Task.Run(() =>
|
{
|
lock (excelExportLock)
|
{
|
if (!Directory.Exists(Config.LogPath))
|
{
|
Directory.CreateDirectory(Config.LogPath);
|
}
|
var fileName = Path.Combine(Config.LogPath, $"LDSData_{DateTime.Now.ToString("yyyyMMdd")}.xlsx");
|
//bool isExisted = File.Exists(fileName);
|
using (ExcelPackage package = new ExcelPackage(new FileInfo(fileName)))
|
{
|
ExcelWorksheet rawDataSheet = null;
|
ExcelWorksheet slantSheet = null;
|
ExcelWorksheet alignmentSheet = null;
|
ExcelWorksheet rowAlignmentSheet = null;
|
|
if (!package.Workbook.Worksheets.Any(s => s.Name == "RawData"))
|
{
|
package.Workbook.Worksheets.Add("RawData");
|
rawDataSheet = package.Workbook.Worksheets["RawData"];
|
for (int i = 0; i < Config.KeyNameCollection.Count; i++)
|
{
|
var cell = rawDataSheet.Cells[i + 3, 1];
|
cell.Value = Config.KeyNameCollection[i];
|
SetTitleCell(cell, false);
|
}
|
}
|
rawDataSheet = package.Workbook.Worksheets["RawData"];
|
|
if (!package.Workbook.Worksheets.Any(s => s.Name == "Slant"))
|
{
|
package.Workbook.Worksheets.Add("Slant");
|
slantSheet = package.Workbook.Worksheets["Slant"];
|
|
var keyCell = slantSheet.Cells[2, 1];
|
keyCell.Value = "Key";
|
SetTitleCell(keyCell);
|
|
for (int i = 0; i < Config.KeyNameCollection.Count; i++)
|
{
|
var cell = slantSheet.Cells[i + 3, 1];
|
cell.Value = Config.KeyNameCollection[i];
|
SetTitleCell(cell, false);
|
}
|
}
|
slantSheet = package.Workbook.Worksheets["Slant"];
|
|
if (!package.Workbook.Worksheets.Any(s => s.Name == "Alignment"))
|
{
|
package.Workbook.Worksheets.Add("Alignment");
|
alignmentSheet = package.Workbook.Worksheets["Alignment"];
|
|
var keysCell = alignmentSheet.Cells[2, 1];
|
keysCell.Value = "Keys";
|
SetTitleCell(keysCell);
|
|
var positionCell = alignmentSheet.Cells[2, 2];
|
positionCell.Value = "Positions";
|
SetTitleCell(positionCell);
|
|
var alignmentMeasures = exportData.MeasurementUnitResultList.Where(u => u.MeasurementType == "Alignment").ToList();
|
for (int i = 0; i < alignmentMeasures.Count(); i++)
|
{
|
var cellKeys = alignmentSheet.Cells[i + 3, 1];
|
cellKeys.Value = alignmentMeasures[i].Keys;
|
SetTitleCell(cellKeys, false);
|
|
var cellPosition = alignmentSheet.Cells[i + 3, 2];
|
cellPosition.Value = alignmentMeasures[i].Positions;
|
SetTitleCell(cellPosition, false);
|
}
|
}
|
alignmentSheet = package.Workbook.Worksheets["Alignment"];
|
|
if (!package.Workbook.Worksheets.Any(s => s.Name == "RowAlignment"))
|
{
|
package.Workbook.Worksheets.Add("RowAlignment");
|
rowAlignmentSheet = package.Workbook.Worksheets["RowAlignment"];
|
|
var keysCell = rowAlignmentSheet.Cells[2, 1];
|
keysCell.Value = "Keys";
|
SetTitleCell(keysCell);
|
|
var positionCell = rowAlignmentSheet.Cells[2, 2];
|
positionCell.Value = "Positions";
|
SetTitleCell(positionCell);
|
|
var rowAlignmentMeasures = exportData.MeasurementUnitResultList.Where(u => u.MeasurementType == "RowAlignment").ToList();
|
for (int i = 0; i < rowAlignmentMeasures.Count(); i++)
|
{
|
var cellKeys = rowAlignmentSheet.Cells[i + 3, 1];
|
cellKeys.Value = rowAlignmentMeasures[i].Keys;
|
SetTitleCell(cellKeys, false);
|
|
var cellPosition = rowAlignmentSheet.Cells[i + 3, 2];
|
cellPosition.Value = rowAlignmentMeasures[i].Positions;
|
SetTitleCell(cellPosition, false);
|
}
|
}
|
rowAlignmentSheet = package.Workbook.Worksheets["RowAlignment"];
|
|
#region RawData
|
{
|
int rowDataStartCol = rawDataSheet.Dimension.Columns;
|
var barcodeCell = rawDataSheet.Cells[1, rowDataStartCol + 1, 1, rowDataStartCol + 4];
|
barcodeCell.Merge = true;
|
barcodeCell.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
|
barcodeCell.Value = exportData.ProductionMeasurementRecord.ProductionBarcode;
|
SetTitleCell(barcodeCell);
|
|
var z1Cell = rawDataSheet.Cells[2, rowDataStartCol + 1];
|
z1Cell.Value = "Z1";
|
SetTitleCell(z1Cell);
|
|
var z2Cell = rawDataSheet.Cells[2, rowDataStartCol + 2];
|
z2Cell.Value = "Z2";
|
SetTitleCell(z2Cell);
|
|
var z3Cell = rawDataSheet.Cells[2, rowDataStartCol + 3];
|
z3Cell.Value = "Z3";
|
SetTitleCell(z3Cell);
|
|
var z4Cell = rawDataSheet.Cells[2, rowDataStartCol + 4];
|
z4Cell.Value = "Z4";
|
SetTitleCell(z4Cell);
|
|
exportData.KeyUnitDataList.ForEach(k =>
|
{
|
int keyIndex = Config.KeyNameCollection.IndexOf(k.Key);
|
if (keyIndex < 0)
|
{
|
LogAsync(DateTime.Now, "Excel导出错误", $"{k.Key}的RawData未能获取行信息,未导出");
|
return;
|
}
|
|
int zIndex = int.Parse(k.MeasurementItem.Substring(1));
|
|
var cell = rawDataSheet.Cells[keyIndex + 1 + 2, rowDataStartCol + zIndex];
|
cell.Value = string.IsNullOrWhiteSpace(k.ItemValue) ? "NA" : k.ItemValue;
|
});
|
}
|
#endregion
|
|
#region Slant
|
var slantMeasures = exportData.MeasurementUnitResultList.Where(u => u.MeasurementType == "Slant").ToList();
|
if (slantMeasures.Count > 0)
|
{
|
int slantStartCol = slantSheet.Dimension.Columns;
|
|
var barcodeCell = slantSheet.Cells[1, slantStartCol + 1];
|
barcodeCell.Value = exportData.ProductionMeasurementRecord.ProductionBarcode;
|
SetTitleCell(barcodeCell);
|
|
var valueCell = slantSheet.Cells[2, slantStartCol + 1];
|
valueCell.Value = "Value";
|
SetTitleCell(valueCell);
|
|
slantMeasures.ForEach(m =>
|
{
|
int rowIndex = Config.KeyNameCollection.IndexOf(m.Keys);
|
if (rowIndex < 0)
|
{
|
LogAsync(DateTime.Now, "Excel导出错误", $"{m.Keys}的Slant未能获取行信息,未导出");
|
return;
|
}
|
|
var cellValue = slantSheet.Cells[rowIndex + 1 + 2, slantStartCol + 1];
|
//var cellResult = slantSheet.Cells[rowIndex + 1 + 2, slantStartCol + 2];
|
|
cellValue.Value = m.MeasurementValue;
|
//cellResult.Value = m.MeasurementResult;
|
|
if (m.MeasurementResult != "OK")
|
{
|
SetNGCell(cellValue);
|
//SetNGCell(cellResult);
|
}
|
});
|
}
|
#endregion
|
|
#region Alignment
|
{
|
var alignmentMeasures = exportData.MeasurementUnitResultList.Where(u => u.MeasurementType == "Alignment").ToList();
|
if (alignmentMeasures.Count > 0)
|
{
|
List<string> keysList = new List<string>();
|
int allRowNums = alignmentSheet.Dimension.Rows;
|
int aligneStartCol = alignmentSheet.Dimension.Columns;
|
|
for (int i = 3; i <= alignmentSheet.Dimension.End.Row; i++)
|
{
|
string keys = alignmentSheet.Cells[i, 1].Value.ToString();
|
string position = alignmentSheet.Cells[i, 2].Value.ToString();
|
|
keysList.Add($"{keys}_{position}");
|
}
|
|
//var barcodeCell = alignmentSheet.Cells[1, aligneStartCol + 1, 1, aligneStartCol + 2];
|
//barcodeCell.Merge = true;
|
//barcodeCell.Value = exportData.ProductionMeasurementRecord.ProductionBarcode;
|
//SetTitleCell(barcodeCell);
|
|
var barcodeCell = alignmentSheet.Cells[1, aligneStartCol + 1];
|
barcodeCell.Value = exportData.ProductionMeasurementRecord.ProductionBarcode;
|
SetTitleCell(barcodeCell);
|
|
var valueCell = alignmentSheet.Cells[2, aligneStartCol + 1];
|
valueCell.Value = "Value";
|
SetTitleCell(valueCell);
|
|
//var resultCell = alignmentSheet.Cells[2, aligneStartCol + 2];
|
//resultCell.Value = "Result";
|
//SetTitleCell(resultCell);
|
|
alignmentMeasures.ForEach(a =>
|
{
|
int rowIndex = keysList.IndexOf($"{a.Keys}_{a.Positions}");
|
if (rowIndex < 0)
|
{
|
LogAsync(DateTime.Now, "Excel导出错误", $"{a.Keys}_{a.Positions}的Alignment未能获取行信息,未导出");
|
return;
|
}
|
|
var cellValue = alignmentSheet.Cells[rowIndex + 1 + 2, aligneStartCol + 1];
|
//var cellResult = alignmentSheet.Cells[rowIndex + 1 + 2, aligneStartCol + 2];
|
|
cellValue.Value = a.MeasurementValue;
|
//cellResult.Value = a.MeasurementResult;
|
|
if (a.MeasurementResult != "OK")
|
{
|
SetNGCell(cellValue);
|
//SetNGCell(cellResult);
|
}
|
});
|
}
|
}
|
#endregion
|
|
#region RowAlignment
|
{
|
var rowAlignmentMeasures = exportData.MeasurementUnitResultList.Where(u => u.MeasurementType == "RowAlignment").ToList();
|
if (rowAlignmentMeasures.Count > 0)
|
{
|
List<string> keysList = new List<string>();
|
int allRowNums = rowAlignmentSheet.Dimension.Rows;
|
int aligneStartCol = rowAlignmentSheet.Dimension.Columns;
|
|
for (int i = 3; i <= allRowNums; i++)
|
{
|
string keys = alignmentSheet.Cells[i, 1].Value.ToString();
|
string position = alignmentSheet.Cells[i, 2].Value.ToString();
|
|
keysList.Add($"{keys}_{position}");
|
}
|
|
//var barcodeCell = rowAlignmentSheet.Cells[1, aligneStartCol + 1, 1, aligneStartCol + 2];
|
//barcodeCell.Merge = true;
|
//barcodeCell.Value = exportData.ProductionMeasurementRecord.ProductionBarcode;
|
//SetTitleCell(barcodeCell);
|
|
var barcodeCell = rowAlignmentSheet.Cells[1, aligneStartCol + 1];
|
barcodeCell.Value = exportData.ProductionMeasurementRecord.ProductionBarcode;
|
SetTitleCell(barcodeCell);
|
|
var valueCell = rowAlignmentSheet.Cells[2, aligneStartCol + 1];
|
valueCell.Value = "Value";
|
SetTitleCell(valueCell);
|
|
//var resultCell = rowAlignmentSheet.Cells[2, aligneStartCol + 2];
|
//resultCell.Value = "Result";
|
//SetTitleCell(resultCell);
|
|
rowAlignmentMeasures.ForEach(a =>
|
{
|
int rowIndex = keysList.IndexOf($"{a.Keys}_{a.Positions}");
|
if (rowIndex < 0)
|
{
|
LogAsync(DateTime.Now, "Excel导出错误", $"{a.Keys}_{a.Positions}的RowAlignment未能获取行信息,未导出");
|
return;
|
}
|
|
var cellValue = rowAlignmentSheet.Cells[rowIndex + 1 + 2, aligneStartCol + 1];
|
//var cellResult = rowAlignmentSheet.Cells[rowIndex + 1 + 2, aligneStartCol + 2];
|
|
cellValue.Value = a.MeasurementValue;
|
//cellResult.Value = a.MeasurementResult;
|
|
if (a.MeasurementResult != "OK")
|
{
|
SetNGCell(cellValue);
|
//SetNGCell(cellResult);
|
}
|
});
|
}
|
}
|
#endregion
|
|
package.Save();
|
|
rawDataSheet.Dispose();
|
slantSheet.Dispose();
|
alignmentSheet.Dispose();
|
rowAlignmentSheet.Dispose();
|
};
|
}
|
});
|
}
|
|
private void SetNGCell(ExcelRange cell)
|
{
|
cell.Style.Font.Color.SetColor(Color.Red);
|
cell.Style.Font.Bold = true;
|
//cell.Style.Fill.PatternType = ExcelFillStyle.Solid;
|
//cell.Style.Fill.BackgroundColor.SetColor(Color.Red);
|
}
|
|
private void SetTitleCell(ExcelRange cell, bool isCenterAlign = true)
|
{
|
cell.Style.Font.Color.SetColor(Color.White);
|
cell.Style.Font.Bold = true;
|
cell.Style.Fill.PatternType = ExcelFillStyle.Solid;
|
cell.Style.Fill.BackgroundColor.SetColor(Color.FromArgb(31, 73, 125));
|
cell.AutoFitColumns();
|
if (isCenterAlign)
|
{
|
cell.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
|
}
|
else
|
{
|
cell.Style.HorizontalAlignment = ExcelHorizontalAlignment.Left;
|
}
|
}
|
|
#region 图像保存
|
private void SaveWholeImage(ProductionMeasurement pMeasure)
|
{
|
try
|
{
|
Bitmap backImage = (Bitmap)Bitmap.FromFile(Config.BackgroundImagePath);
|
|
Bitmap map = new Bitmap(backImage.Width, backImage.Height);
|
using (Graphics g = Graphics.FromImage(map))
|
{
|
g.DrawImage(backImage, new PointF(0, 0));
|
|
pMeasure.ElementList.ForEach(e =>
|
{
|
e.Draw(g);
|
});
|
}
|
|
string dir = Path.Combine(Config.ImageSaveFolder, "TopView", DateTime.Now.ToString("yyyyMMdd"));
|
if (!Directory.Exists(dir))
|
{
|
Directory.CreateDirectory(dir);
|
}
|
|
map.Save(Path.Combine(dir, $"{pMeasure.Barcode}_{pMeasure.PResult}_{DateTime.Now.ToString("HHmmss")}.png"), ImageFormat.Png);
|
}
|
catch (Exception ex)
|
{
|
LogAsync(DateTime.Now, "整体图片保存异常", ex.GetExceptionMessage());
|
}
|
}
|
|
private void SaveKeyImages(string barCode, MeasurementUnit measureUnit)
|
{
|
string measureName = measureUnit.GetDisplayText();
|
if (Config.ImageSaveOption.IsSaveOriginImage)
|
{
|
measureUnit.KeyUnitCollection.ForEach(u => u.ImageSaveStatus++);
|
|
string dir = Path.Combine(Config.ImageSaveFolder, "Origin", DateTime.Now.ToString("yyyyMMdd"), barCode, measureUnit.MeasureType);
|
if (!Directory.Exists(dir))
|
{
|
Directory.CreateDirectory(dir);
|
}
|
|
SaveKeyImages(measureUnit, measureName, dir);
|
}
|
|
string result = (measureUnit.Spec.MeasureResult ?? false) ? "OK" : "NG";
|
if (Config.ImageSaveOption.AddtionalSaveType.ToUpper().Contains(result))
|
{
|
measureUnit.KeyUnitCollection.ForEach(u => u.ImageSaveStatus++);
|
|
string dir = Path.Combine(Config.ImageSaveFolder, result, DateTime.Now.ToString("yyyyMMdd"), barCode, measureUnit.MeasureType);
|
if (!Directory.Exists(dir))
|
{
|
Directory.CreateDirectory(dir);
|
}
|
|
SaveKeyImages(measureUnit, measureName, dir);
|
}
|
}
|
|
private async void SaveKeyImages(MeasurementUnit measureUnit, string measureName, string dir)
|
{
|
await Task.Run(() =>
|
{
|
measureUnit.KeyUnitCollection.ForEach(u =>
|
{
|
int i = 0;
|
u.KeyImages?.ForEach(image =>
|
{
|
string fileName = "";
|
try
|
{
|
fileName = Path.Combine(dir, $"{measureName}_{u.Key}{(i == 0 ? "" : $"-{i}")}_{DateTime.Now.ToString("HHmmss")}.tiff");
|
image.WriteImage("tiff", 0, fileName);
|
}
|
catch (Exception)
|
{
|
LogAsync(DateTime.Now, "切图保存失败", fileName);
|
}
|
i++;
|
});
|
|
u.ImageSaveStatus--;
|
});
|
});
|
}
|
#endregion
|
|
private async void RunImageHandle(IOperationConfig opConfig, IImageSet imgSet, string snapshotId, string snapshotName, List<MeasurementUnit> measureList)
|
{
|
await Task.Run(() =>
|
{
|
var keys = Config.KeyUnitCollection.Where(u => u.IsEnabled && u.SnapshotPointId == snapshotId);
|
var keyBindCollection = measureList.SelectMany(u => u.KeyUnitCollection).Where(u => keys.Any(k => k.Key == u.Key)).ToList();
|
|
string toolKey = (opConfig as CameraOprerationConfigBase).AlgorithemPath;
|
//HObject images = imgSet.HImage;
|
|
HObject images = new HObject();
|
LaserScanParam scanParam = JsonConvert.DeserializeObject<LaserScanParam>(imgSet.ImageData);
|
LogAsync(DateTime.Now, $"扫描参数:{imgSet.ImageData}", "");
|
|
if (!string.IsNullOrWhiteSpace(toolKey))
|
{
|
toolKey = snapshotId + "|" + toolKey;
|
if (!_halconToolDict.ContainsKey(toolKey))
|
{
|
LogAsync(DateTime.Now, $"{snapshotName}未初始化取图算法配置", "");
|
keyBindCollection.ForEach(k => k.FillKeyValues(null));
|
return;
|
}
|
|
//string fileName = Path.Combine(Config.ImageSaveFolder, "BeforeRun", $"{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.tif");
|
//imgSet.HImage.WriteImage("tiff", 0, fileName);
|
|
if (imgSet.HImage == null)
|
{
|
LogAsync(DateTime.Now, $"{snapshotName}图片为空对象", "");
|
keyBindCollection.ForEach(k => k.FillKeyValues(null));
|
return;
|
}
|
|
_halconToolDict[toolKey].InputImageDic["INPUT_Image"] = imgSet.HImage;
|
if (!_halconToolDict[toolKey].RunProcedure(out string error))
|
{
|
LogAsync(DateTime.Now, $"{snapshotName}取图算法异常,{error}", "");
|
keyBindCollection.ForEach(k => k.FillKeyValues(null));
|
return;
|
}
|
|
images = _halconToolDict[toolKey].GetResultObject("OUTPUT_Images");
|
}
|
|
HOperatorSet.CountObj(images, out HTuple count);
|
LogAsync(DateTime.Now, $"{snapshotName}切图{count.I}张", "");
|
|
if (count == 0)
|
{
|
LogAsync(DateTime.Now, $"{snapshotName}取图算法未输出图像", "");
|
keyBindCollection.ForEach(k => k.FillKeyValues(null));
|
return;
|
}
|
|
var excludeKeys = keys.Where(u => u.ImageSeq > count.I).ToList();
|
if (excludeKeys.Count > 0)
|
{
|
LogAsync(DateTime.Now, $"{string.Join(" ", excludeKeys.Select(u => u.AliasName))}未在图片获取序列中", "");
|
keyBindCollection.Where(k => excludeKeys.Any(u => u.Key == k.Key)).ToList().ForEach(k =>
|
{
|
k.FillKeyValues(null);
|
});
|
}
|
|
//string dir = Path.Combine(Config.ImageSaveFolder, "Clips", $"{DateTime.Now.ToString("yyyyMMdd")}", $"{snapshotName}_{DateTime.Now.ToString("HHmmss")}");
|
//if (!Directory.Exists(dir))
|
//{
|
// Directory.CreateDirectory(dir);
|
//}
|
|
//Parallel.For(1, count.I + 1, (i) =>
|
for (int i = 1; i <= count.I; i++)
|
{
|
HOperatorSet.SelectObj(images, out HObject image, i);
|
|
//string fileName = Path.Combine(dir, $"{i}.tif");
|
//using (HImage temp = image.ConvertHObjectToHImage())
|
//{
|
// temp.WriteImage("tiff", 0, fileName);
|
//}
|
|
keys.Where(u => u.ImageSeq == i).ToList().ForEach(k =>
|
{
|
Dictionary<string, double> resultDict = null;
|
|
var keyBindList = keyBindCollection.Where(u => u.Key == k.Key).ToList();
|
|
string keyToolKey = k.AliasName + "|" + k.KeyAlgorithemPath;
|
if (!_halconToolDict.ContainsKey(keyToolKey))
|
{
|
LogAsync(DateTime.Now, $"{k.AliasName}检测算法未初始化", "");
|
}
|
else
|
{
|
_halconToolDict[keyToolKey].InputImageDic["INPUT_Image"] = image;
|
_halconToolDict[keyToolKey].InputTupleDic["INPUT_Resolution_X"] = scanParam.Resolution_X / 1000000.0;
|
_halconToolDict[keyToolKey].InputTupleDic["INPUT_Resolution_Y"] = scanParam.Resolution_Y / 1000000.0;
|
_halconToolDict[keyToolKey].InputTupleDic["INPUT_Resolution_Z"] = scanParam.Resolution_Z / 1000000.0;
|
_halconToolDict[keyToolKey].InputTupleDic["INPUT_ImageId"] = $"{k.AliasName}_{DateTime.Now.ToString("HHmmssfff")}.tif";
|
if (!_halconToolDict[keyToolKey].RunProcedure(out string error))
|
{
|
LogAsync(DateTime.Now, $"{k.AliasName}检测算法异常,{error}", "");
|
}
|
else
|
{
|
var results = _halconToolDict[keyToolKey].GetResultTuple("OUTPUT_Results").DArr.ToList();
|
if (results.Count == 0 || results.Any(u => u < 0))
|
{
|
LogAsync(DateTime.Now, $"{k.AliasName}原始数据异常", "");
|
}
|
else
|
{
|
//LogAsync(DateTime.Now, $"{k.AliasName}原始数据", $"{string.Join(" ", results)}");
|
|
results = results.Select(u => u - Config.PlanCompensation).ToList();
|
resultDict = k.KeyResultList.ToDictionary(u => u, u =>
|
{
|
int index = k.KeyResultList.IndexOf(u);
|
return results[index];
|
});
|
}
|
}
|
}
|
|
keyBindList.ForEach(kb =>
|
{
|
kb.KeyImages.Add(image.ConvertHObjectToHImage());
|
kb.FillKeyValues(resultDict);
|
});
|
});
|
|
image.Dispose();
|
image = null;
|
}
|
//);
|
|
imgSet.HImage.Dispose();
|
imgSet.HImage = null;
|
imgSet.Dispose();
|
|
images.Dispose();
|
images = null;
|
|
//if (count.I != 1)
|
//{
|
// hImage?.Dispose();
|
// hImage = null;
|
//}
|
});
|
}
|
#endregion
|
}
|
}
|