西比亚这个东西还是有点坑的。明明仪器软件就几行代码的事,把自己图转base64串传输不就完了。非得要每个lis按他文档画图。画图也就算了,还有蛋白电泳、尿蛋白电泳、固定电泳等。画图还有差异,有的要参考区间,有的要参照先,有的要标记峰值。搞的真是难受。本身这些事是仪器自己的事,lis有什么义务给还原图,无奈市面上无底线lis太多了,行情不好。
仪器原图
lis还原的图
仪器数据
S0003 000 00000g/dl TS 2402202305Albumin Alpha 1 Alpha 2 Beta Gamma 055.1003.5009.7009.0022.70000000000000000000000000000000000000000000000000000000000000000000000000001 015.4000.0000.0000.000000000000000000000001.2301.00 000300A01000079006400000000000000000000000080080008000800070007000600060005000500060006000700080009000A000A000A000A000A000A000A000A000A000A000B000B000B000B000A000A00090008000800070007000600060006000700070007000800080009000B000E00120019002300320048006A009C00E4014801D102850370049C061307CD09AC0B600C830CC40C2A0AF3097007DB065C050703E402F302310198012300CC008D00610043002E00210018001400128012001300150018001D0023002B00350041004E005D006C007A0086008E00920092008D0085007A006E00620057004D00460040003D003B803A003B003D004000440049004F00570060006B00770085009500A600B800CB00DD00ED00FC01090113011A011F0120011E0118010D00FE00EB00D400BC00A4008D007A006A005E0055004F004C004A804A004C004F0054005B006500720082009500AB00C500E100FE011B013401480153015401490136011D010000E200C300A6008C0075006100510045003C00350030002D002A00280026002400220020001E001C801B001B001C001D001F002200250028002B002F00330037003B00400045004B0052005A006400700080009400AC00CB00F0011E0156019801E30235028902D8031B0349035D0352032C02EF02A3025001FC01AB0161012000E900BD009A007F006B005C005100490043003E003B003800350032002E002A00260022001E001B00180015001300110010000F000E000D000C000B0009000800060005000400020001000000000001000200040006000700080008000900090009000A000A000A000A000A000A000A000B000D000F00108012|
仪器说明,反正很懵,不如拿具体数据说明
以前一直没搞明白峰值的解释,所以一直没画峰值。这次不上了。峰值那段文档的解释是结果串那些位置的串每4位表示一个坐标。数字是10进制的数,如果不足4位就把前面补0到4位。所以画图时候去了前面0得到10进制数。而这个10进制数还不是直接的x坐标。他表示的是300个点最后一个点的偏离点乘10。即x坐标由那个数字按这个公式算:drawX=300-(峰值数字/10)
C#绘图和解析结果源码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PreDeal.Interface;
using LIS.Model.Bussiness;
using LIS.DAL.DataAccess;
using PreDeal.Ftp;
using PreDeal.Attributes;
using System.Text.RegularExpressions;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.IO;
using System.Collections;
namespace PreDeal
{
///<summary NoteObject="Class">
/// [功能描述:Sebia蛋白电泳仪的数据和图像处理,不画Z区间坐标系,画峰值,处理数据格式] <para/>
/// [创建者:zlz] <para/>
/// [创建时间:2023年2月25日] <para/>
///<说明>
/// [说明:Sebia蛋白电泳仪的数据和图像处理,处理数据格式
/// ]<para/>
///</说明>
///<修改记录>
/// [修改时间:2016-11-15]<para/>
/// S0003 000 00000g/dl TS 2402202305Albumin Alpha 1 Alpha 2 Beta Gamma 055.1003.5009.7009.0022.70000000000000000000000000000000000000000000000000000000000000000000000000001 015.4000.0000.0000.000000000000000000000001.2301.00 000300A01000079006400000000000000000000000080080008000800070007000600060005000500060006000700080009000A000A000A000A000A000A000A000A000A000A000B000B000B000B000A000A00090008000800070007000600060006000700070007000800080009000B000E00120019002300320048006A009C00E4014801D102850370049C061307CD09AC0B600C830CC40C2A0AF3097007DB065C050703E402F302310198012300CC008D00610043002E00210018001400128012001300150018001D0023002B00350041004E005D006C007A0086008E00920092008D0085007A006E00620057004D00460040003D003B803A003B003D004000440049004F00570060006B00770085009500A600B800CB00DD00ED00FC01090113011A011F0120011E0118010D00FE00EB00D400BC00A4008D007A006A005E0055004F004C004A804A004C004F0054005B006500720082009500AB00C500E100FE011B013401480153015401490136011D010000E200C300A6008C0075006100510045003C00350030002D002A00280026002400220020001E001C801B001B001C001D001F002200250028002B002F00330037003B00400045004B0052005A006400700080009400AC00CB00F0011E0156019801E30235028902D8031B0349035D0352032C02EF02A3025001FC01AB0161012000E900BD009A007F006B005C005100490043003E003B003800350032002E002A00260022001E001B00180015001300110010000F000E000D000C000B0009000800060005000400020001000000000001000200040006000700080008000900090009000A000A000A000A000A000A000A000B000D000F00108012|
/// [修改内容:画出Z区间坐标系]<para/>
///</修改记录>
///<修改记录>
/// [修改时间:本次修改时间]<para/>
/// [修改内容:本次修改内容]<para/>
///</修改记录>
///</summary>
[Remark(Remark = "Sebia血清蛋白电泳仪的数据和图像处理处理,画出Z区间坐标系,处理数据格式。")]
public class DealSebiaNoLine : BaseDeal, IPreDeal, ITimer
{
/// <summary>
/// 前处理,抛过来一行数据
/// </summary>
/// <param name="result">结果</param>
/// <param name="machID">仪器ID</param>
/// <param name="dealProcess">处理程序</param>
/// <param name="index">当前文件的第几行</param>
/// <param name="fileName">当前读取的文件全名</param>
/// <returns></returns>
public bool PreDeal(string result, string machID, string dealProcess, int index, string fileName)
{
//提前流水
string sampleNo = result.Substring(1, 4);
string episAll = result.Split(' ')[0];
//去掉前面多余的0
sampleNo =sampleNo.TrimStart(new char[] { '0' });
string LabNo = result.Substring(5, 20);
LabNo = LabNo.Trim();
LabNo = LabNo.Replace(":","");
if (LabNo != "")
{
sampleNo = LabNo;
}
//取结果值
string value1Name = result.Substring(266, 10);
string value1 = result.Substring(367, 5);
string value2Name = result.Substring(276, 10);
string value2 = result.Substring(372, 5);
string value3Name = result.Substring(286, 10);
string value3 = result.Substring(377, 5);
string value4Name = result.Substring(296, 10);
string value4 = result.Substring(382, 5);
string value5Name = result.Substring(306, 10);
string value5 = result.Substring(387, 5);
string value6Name = result.Substring(316, 10);
string value6 = result.Substring(392, 5);
string value7Name = result.Substring(326, 10);
string value7 = result.Substring(397, 5);
string value8Name = result.Substring(336, 10);
string value8 = result.Substring(402, 5);
string value9Name = result.Substring(346, 10);
string value9 = result.Substring(407, 5);
string value10Name = result.Substring(356, 10);
string value10 = result.Substring(412, 5);
string value11 = result.Substring(557, 170).Trim();
//取峰值,封值表示为每个坐标用4位表示。去掉前面0后当做10进制数字。这个数字不是直接坐标,要把这个数据除10后得到的是和最后一点
//往前偏移的点数,即:去前面(300-(0的十进制数/10))就是峰值的第几个点坐标
Hashtable hsFen = new Hashtable();
string fen1Start = result.Substring(799, 4);
int fen1StartNum = DealToNum(fen1Start);
string fen1End = result.Substring(803, 4);
int fen1EndNum = DealToNum(fen1End);
if (fen1StartNum > 0)
{
for (int i = fen1StartNum; i < fen1EndNum; i++)
{
if (!hsFen.ContainsKey(i))
{
hsFen.Add(i, "");
}
}
}
string fen2Start = result.Substring(807, 4).Trim();
int fen2StartNum = DealToNum(fen2Start);
string fen2End = result.Substring(811, 4).Trim();
int fen2EndNum = DealToNum(fen2End);
if (fen2StartNum > 0)
{
for (int i = fen2StartNum; i < fen2EndNum; i++)
{
if (!hsFen.ContainsKey(i))
{
hsFen.Add(i, "");
}
}
}
string fen3Start = result.Substring(815, 4).Trim();
int fen3StartNum = DealToNum(fen3Start);
string fen3End = result.Substring(819, 4).Trim();
int fen3EndNum = DealToNum(fen3End);
if (fen3StartNum > 0)
{
for (int i = fen3StartNum; i < fen3EndNum; i++)
{
if (!hsFen.ContainsKey(i))
{
hsFen.Add(i, "");
}
}
}
string fen4Start = result.Substring(823, 4).Trim();
int fen4StartNum = DealToNum(fen4Start);
string fen4End = result.Substring(827, 4).Trim();
int fen4EndNum = DealToNum(fen4End);
if (fen4StartNum > 0)
{
for (int i = fen4StartNum; i < fen4EndNum; i++)
{
if (!hsFen.ContainsKey(i))
{
hsFen.Add(i, "");
}
}
}
//处理数据
DealData(value1Name + "\\" + value1 + "," + value2Name + "\\" + value2 + "," + value3Name + "\\" + value3 + "," + value4Name + "\\" + value4 + "," + value5Name + "\\" + value5 + "," + value6Name + "\\" + value6 + "," + value7Name + "\\" + value7 + "," + value8Name + "\\" + value8 + "," + value9Name + "\\" + value9 + "," + value10Name + "\\" + value10 + ",Remark" + "\\" + value11 + ",episall\\" + episAll, machID, sampleNo, dealProcess);
//取出图形串
string imgStr = result.Substring(830, 1200);
List<Dto> dataList = new List<Dto>();
int maxY = 0;
int max1Index = 0;
int max1Data = 0;
int max2Index = 0;
int max2Data = 0;
int max3Index = 0;
int max3Data = 0;
//分割点数据
for (int i = 0; i < imgStr.Length && i < 1200; i += 4)
{
int startIndex = i;
int endIndex = i + 4;
if (endIndex > imgStr.Length)
{
endIndex = imgStr.Length;
}
Dto dto = new Dto();
dto.Type = imgStr.Substring(startIndex, 1);
if (dto.Type == "4" || dto.Type == "C" || dto.Type == "1" || dto.Type == "5")
{
continue;
}
else
{
dto.Y = Convert.ToInt32(imgStr.Substring(startIndex + 1, endIndex - startIndex - 1), 16);
}
if (dto.Y > maxY)
{
maxY = dto.Y;
}
if (i/4 > 135 && i/4 < 165)
{
if (max1Data < dto.Y)
{
max1Data = dto.Y;
max1Index = i/4;
}
}
if (i/4 > 170 && i/4 < 195)
{
if (max2Data < dto.Y)
{
max2Data = dto.Y;
max2Index = i/4;
}
}
if (i/4 > 230 && i/4 < 245)
{
if (max3Data < dto.Y)
{
max3Data = dto.Y;
max3Index = i/4;
}
}
dataList.Add(dto);
}
int imgY = 580;
//创建空位图
Image img = new Bitmap(680, imgY);
//获得画图句柄
Graphics g = Graphics.FromImage(img);
g.Clear(Color.White);
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
int x = 40;
int y = 40;
//画坐标
Pen pen = new Pen(Color.Black);
pen.Width = 2;
//画横坐标线
g.DrawLine(pen, 40, imgY - y, 640, imgY - y);
//画下面横坐标
for (int i = 0; i < 300; i += 15)
{
g.DrawLine(pen, 40 + i * 2, imgY - y, 40 + i * 2, imgY - y - 4);
Point p = new Point(40 + i * 2, imgY - y + 3);
Font myFont = new Font("宋体", 8, FontStyle.Regular);
Brush bush = new SolidBrush(Color.Black);
g.DrawString(i.ToString(), myFont, bush, p);
}
int preY = -1;
int curindex = 0;
//遍历点画图
foreach (var d in dataList)
{
if (preY == -1)
{
pen = new Pen(Color.Black);
pen.Width = 1;
g.DrawLine(pen, x, imgY - Convert.ToInt32(d.Y * (imgY - y - 65.0) / maxY) - y, x, imgY - Convert.ToInt32(d.Y * (imgY - y - 25.0) / maxY) - y);
}
else
{
pen = new Pen(Color.Black);
pen.Width = 1;
g.DrawLine(pen, x, imgY - Convert.ToInt32(d.Y * (imgY - y - 65.0) / maxY) - y, x - 1, preY - y);
}
if (curindex == max1Index)
{
if (value1Name != " ")
{
Point p = new Point(x-8, imgY - Convert.ToInt32(d.Y * (imgY - y - 65.0) / maxY) - y - 20);
Font myFont = new Font("宋体", 12, FontStyle.Regular);
Brush bush = new SolidBrush(Color.Black);
//g.DrawString("Hb A", myFont, bush, p);
}
}
if (curindex == max2Index)
{
if (value2Name != " ")
{
Point p = new Point(x-8, imgY - Convert.ToInt32(d.Y * (imgY - y - 65.0) / maxY) - y - 20);
Font myFont = new Font("宋体", 12, FontStyle.Regular);
Brush bush = new SolidBrush(Color.Black);
//g.DrawString("Hb F or Hb", myFont, bush, p);
}
}
if (curindex == max3Index)
{
if (value3Name!=" ")
{
Point p = new Point(x-8, imgY - Convert.ToInt32(d.Y * (imgY - y - 65.0) / maxY) - y - 20);
Font myFont = new Font("宋体", 12, FontStyle.Regular);
Brush bush = new SolidBrush(Color.Black);
//g.DrawString("Hb A2", myFont, bush, p);
}
}
preY = imgY - Convert.ToInt32(d.Y * (imgY - y - 65.0) / maxY);
//画峰值阴影
if (hsFen.ContainsKey(curindex))
{
pen = new Pen(Color.Black);
pen.Width = 1;
g.DrawLine(pen, x, imgY - 40, x, preY - y);
}
x += 2;
curindex++;
}
//存图
img.Save(Application.StartupPath + "\\temp\\" + sampleNo + ".bmp");
string ftpPath = "";
//得到ftp
FtpService ftp = GetFtpHelper(machID, dealProcess, out ftpPath);
//上传图片
ftp.Upload(Application.StartupPath + "\\temp\\" + sampleNo + ".bmp");
System.IO.FileInfo fInfo = new System.IO.FileInfo(Application.StartupPath + "\\temp\\" + sampleNo + ".bmp");
System.IO.File.Delete(Application.StartupPath + "\\temp\\" + sampleNo + ".bmp");
//保存图片
SaveImg(machID, sampleNo, "Sebia", ftpPath.Split('^')[3] + fInfo.Name, dealProcess, episAll);
return false;
}
/// <summary>
/// 峰值处理成坐标
/// </summary>
/// <param name="numStr"></param>
/// <returns></returns>
private int DealToNum(string numStr)
{
string res = "";
for (int i = 0; i < numStr.Length; i++)
{
if (numStr[i] == '0' && res == "")
{
continue;
}
res += numStr[i];
}
if (res != "")
{
return 300 - Convert.ToInt32(res) / 10;
}
return 0;
}
/// <summary>
/// 处理数据库数据
/// </summary>
/// <param name="row">当前行数据</param>
/// <param name="machID">仪器ID</param>
/// <param name="dealProcess">处理程序</param>
/// <param name="index">当前数据的第几行</param>
/// <param name="otherPara">其他参数</param>
/// <returns></returns>
public bool PreDealDataBase(System.Data.DataRow row, string machID, string dealProcess, int index, string otherPara)
{
throw new NotImplementedException();
}
/// <summary>
/// 定时执行
/// </summary>
/// <param name="machID"></param>
/// <param name="dealProcess"></param>
public void Action(string machID, string dealProcess)
{
//按流水号取图上传,路径不带最后的\
string OtherPara = Flag.DealFlag.GetConfigStr(machID, "OtherPara");
if (OtherPara != null && OtherPara != "")
{
string[] picList = OtherPara.Split(',');
foreach (var picPath in picList)
{
LIS.Core.Util.LogUtils.WriteDebugLog("检测目录:" + picPath + "下的图片");
//血清图片存储
if (Directory.Exists(picPath))
{
LIS.Core.Util.LogUtils.WriteDebugLog("检测到目录:" + picPath);
string[] picPaths = Directory.GetFiles(picPath, "*.jpeg");
string[] picPaths1 = Directory.GetFiles(picPath, "*.jpg");
string ftpPath = "";
LIS.Core.Util.LogUtils.WriteDebugLog("目录包含:" + picPaths.Length + "个图片");
try
{
if (picPaths.Length > 0)
{
//得到ftp
FtpService ftp = GetFtpHelper(machID, dealProcess, out ftpPath);
foreach (string picFile in picPaths)
{
FileInfo fInfo = new FileInfo(picFile);
//上传图片
ftp.Upload(picFile);
LIS.Core.Util.LogUtils.WriteDebugLog(picFile + "上传成功!");
//保存图片
SaveImg(machID, fInfo.Name, "P", ftpPath.Split('^')[3] + fInfo.Name, dealProcess);
LIS.Core.Util.LogUtils.WriteDebugLog(picFile + "保存成功!");
//删除图片
System.IO.File.Delete(picFile);
LIS.Core.Util.LogUtils.WriteDebugLog(picFile + "删除成功!");
}
}
if (picPaths1.Length > 0)
{
//得到ftp
FtpService ftp = GetFtpHelper(machID, dealProcess, out ftpPath);
foreach (string picFile in picPaths1)
{
FileInfo fInfo = new FileInfo(picFile);
//上传图片
ftp.Upload(picFile);
LIS.Core.Util.LogUtils.WriteDebugLog(picFile + "上传成功!");
//保存图片
SaveImg(machID, fInfo.Name, "P", ftpPath.Split('^')[3] + fInfo.Name, dealProcess);
LIS.Core.Util.LogUtils.WriteDebugLog(picFile + "保存成功!");
//删除图片
System.IO.File.Delete(picFile);
LIS.Core.Util.LogUtils.WriteDebugLog(picFile + "删除成功!");
}
}
}
catch (Exception ex)
{
LIS.Core.Util.LogUtils.WriteDebugLog("上传图片异常:" + ex.Message);
}
}
else
{
LIS.Core.Util.LogUtils.WriteDebugLog("不存在目录:" + picPath + "不做图片上传");
}
}
}
else
{
LIS.Core.Util.LogUtils.WriteDebugLog("未配置:OtherPara图片目录不做图片上传");
}
}
/// <summary>
/// 内部数据实体
/// </summary>
private class Dto
{
/// <summary>
/// 类型
/// </summary>
public string Type
{
get;
set;
}
/// <summary>
/// Y坐标
/// </summary>
public int Y
{
get;
set;
}
}
}
}
把经验分享给大家,没必要内耗在这种事上