357 lines
18 KiB
C#
357 lines
18 KiB
C#
using IRaCIS.Core.Domain.Share;
|
||
using System.Text;
|
||
using Microsoft.AspNetCore.Hosting;
|
||
using IRaCIS.Core.Infrastructure;
|
||
using Medallion.Threading;
|
||
using FellowOakDicom;
|
||
using FellowOakDicom.Imaging.Codec;
|
||
using System.Data;
|
||
using IRaCIS.Core.Domain.Models;
|
||
using FellowOakDicom.Network;
|
||
using IRaCIS.Core.SCP.Service;
|
||
using IRaCIS.Core.Infra.EFCore;
|
||
using MassTransit;
|
||
using System.Runtime.Intrinsics.X86;
|
||
using Serilog.Sinks.File;
|
||
|
||
namespace IRaCIS.Core.SCP.Service
|
||
{
|
||
public class DicomArchiveService : BaseService, IDicomArchiveService
|
||
{
|
||
private readonly IRepository<SCPPatient> _patientRepository;
|
||
private readonly IRepository<SCPStudy> _studyRepository;
|
||
private readonly IRepository<SCPSeries> _seriesRepository;
|
||
private readonly IRepository<SCPInstance> _instanceRepository;
|
||
private readonly IRepository<Dictionary> _dictionaryRepository;
|
||
private readonly IDistributedLockProvider _distributedLockProvider;
|
||
|
||
|
||
private List<Guid> _instanceIdList = new List<Guid>();
|
||
|
||
public DicomArchiveService(IRepository<SCPPatient> patientRepository, IRepository<SCPStudy> studyRepository,
|
||
IRepository<SCPSeries> seriesRepository,
|
||
IRepository<SCPInstance> instanceRepository,
|
||
IRepository<Dictionary> dictionaryRepository,
|
||
IDistributedLockProvider distributedLockProvider)
|
||
{
|
||
_distributedLockProvider = distributedLockProvider;
|
||
_studyRepository = studyRepository;
|
||
_patientRepository = patientRepository;
|
||
_seriesRepository = seriesRepository;
|
||
_instanceRepository = instanceRepository;
|
||
_dictionaryRepository = dictionaryRepository;
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 单个文件接收 归档
|
||
/// </summary>
|
||
/// <param name="dataset"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<Guid> ArchiveDicomFileAsync(DicomDataset dataset, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize)
|
||
{
|
||
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
||
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
|
||
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
|
||
|
||
string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID,string.Empty);
|
||
|
||
//Guid patientId= IdentifierHelper.CreateGuid(patientIdStr);
|
||
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid,trialId.ToString());
|
||
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, trialId.ToString());
|
||
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, trialId.ToString());
|
||
|
||
var isStudyNeedAdd = false;
|
||
var isSeriesNeedAdd = false;
|
||
var isInstanceNeedAdd = false;
|
||
var isPatientNeedAdd = false;
|
||
|
||
//var @lock = _distributedLockProvider.CreateLock($"{studyInstanceUid}");
|
||
|
||
//using (@lock.Acquire())
|
||
{
|
||
var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr && t.TrialSiteId==trialSiteId );
|
||
var findStudy = await _studyRepository.FindAsync(studyId);
|
||
var findSerice = await _seriesRepository.FindAsync(seriesId);
|
||
var findInstance = await _instanceRepository.FindAsync(instanceId);
|
||
|
||
DateTime? studyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.StudyTime).TimeOfDay);
|
||
|
||
//先传输了修改了患者编号的,又传输了没有修改患者编号的,导致后传输的没有修改患者编号的下面的检查为0
|
||
if (findPatient == null && findStudy==null)
|
||
{
|
||
isPatientNeedAdd = true;
|
||
|
||
|
||
findPatient = new SCPPatient()
|
||
{
|
||
Id = NewId.NextSequentialGuid(),
|
||
TrialId=trialId,
|
||
TrialSiteId=trialSiteId,
|
||
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
|
||
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
|
||
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
|
||
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
|
||
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
|
||
|
||
EarliestStudyTime = studyTime,
|
||
LatestStudyTime = studyTime,
|
||
LatestPushTime = DateTime.Now,
|
||
};
|
||
|
||
if (findPatient.PatientBirthDate.Length == 8)
|
||
{
|
||
var birthDateStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}-{findPatient.PatientBirthDate[4]}{findPatient.PatientBirthDate[5]}-{findPatient.PatientBirthDate[6]}{findPatient.PatientBirthDate[7]}";
|
||
|
||
var yearStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}";
|
||
|
||
int year = 0;
|
||
|
||
var canParse = int.TryParse(yearStr, out year);
|
||
|
||
if (canParse && year > 1900)
|
||
{
|
||
findPatient.PatientBirthDate = birthDateStr;
|
||
|
||
DateTime birthDate;
|
||
|
||
if (findPatient.PatientAge == string.Empty && studyTime.HasValue && DateTime.TryParse(findPatient.PatientBirthDate,out birthDate))
|
||
{
|
||
var patientAge = studyTime.Value.Year - birthDate.Year;
|
||
// 如果生日还未到,年龄减去一岁
|
||
if (studyTime.Value < birthDate.AddYears(patientAge))
|
||
{
|
||
patientAge--;
|
||
}
|
||
|
||
findPatient.PatientAge = patientAge.ToString();
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
findPatient.PatientBirthDate = string.Empty;
|
||
}
|
||
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (studyTime < findPatient.EarliestStudyTime)
|
||
{
|
||
findPatient.EarliestStudyTime = studyTime;
|
||
}
|
||
if (studyTime > findPatient.LatestStudyTime)
|
||
{
|
||
findPatient.LatestStudyTime = studyTime;
|
||
}
|
||
|
||
findPatient.LatestPushTime = DateTime.Now;
|
||
}
|
||
|
||
if (findStudy == null)
|
||
{
|
||
isStudyNeedAdd = true;
|
||
findStudy = new SCPStudy
|
||
{
|
||
CalledAE = calledAE,
|
||
CallingAE = callingAE,
|
||
|
||
PatientId = findPatient.Id,
|
||
Id = studyId,
|
||
TrialId = trialId,
|
||
TrialSiteId = trialSiteId,
|
||
StudyInstanceUid = studyInstanceUid,
|
||
StudyTime = studyTime,
|
||
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||
//ModalityForEdit = modalityForEdit,
|
||
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
|
||
InstitutionName = dataset.GetSingleValueOrDefault(DicomTag.InstitutionName, string.Empty),
|
||
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
|
||
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
|
||
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
|
||
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
|
||
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
|
||
|
||
StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
|
||
AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),
|
||
|
||
//需要特殊处理
|
||
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
|
||
|
||
|
||
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
|
||
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
|
||
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
|
||
|
||
|
||
|
||
//IsDoubleReview = addtionalInfo.IsDoubleReview,
|
||
SeriesCount = 0,
|
||
InstanceCount = 0
|
||
};
|
||
|
||
|
||
if (findStudy.PatientBirthDate.Length == 8)
|
||
{
|
||
findStudy.PatientBirthDate = $"{findStudy.PatientBirthDate[0]}{findStudy.PatientBirthDate[1]}{findStudy.PatientBirthDate[2]}{findStudy.PatientBirthDate[3]}-{findStudy.PatientBirthDate[4]}{findStudy.PatientBirthDate[5]}-{findStudy.PatientBirthDate[6]}{findStudy.PatientBirthDate[7]}";
|
||
}
|
||
}
|
||
|
||
|
||
if (findSerice == null)
|
||
{
|
||
isSeriesNeedAdd = true;
|
||
|
||
findSerice = new SCPSeries
|
||
{
|
||
Id = seriesId,
|
||
StudyId = findStudy.Id,
|
||
|
||
StudyInstanceUid = findStudy.StudyInstanceUid,
|
||
SeriesInstanceUid = seriesInstanceUid,
|
||
SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
|
||
//SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay),
|
||
//SeriesTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.SeriesDate) + dataset.GetSingleValue<string>(DicomTag.SeriesTime), out DateTime dt) ? dt : null,
|
||
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay),
|
||
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
|
||
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
||
|
||
ImagePositionPatient = dataset.GetSingleValueOrDefault(DicomTag.ImagePositionPatient, string.Empty),
|
||
ImageOrientationPatient = dataset.GetSingleValueOrDefault(DicomTag.ImageOrientationPatient, string.Empty),
|
||
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
|
||
SequenceName = dataset.GetSingleValueOrDefault(DicomTag.SequenceName, string.Empty),
|
||
ProtocolName = dataset.GetSingleValueOrDefault(DicomTag.ProtocolName, string.Empty),
|
||
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
||
|
||
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
|
||
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
|
||
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
|
||
|
||
|
||
InstanceCount = 0
|
||
};
|
||
|
||
++findStudy.SeriesCount;
|
||
}
|
||
|
||
|
||
if (findInstance == null)
|
||
{
|
||
isInstanceNeedAdd = true;
|
||
findInstance = new SCPInstance
|
||
{
|
||
Id = instanceId,
|
||
StudyId = findStudy.Id,
|
||
SeriesId = findSerice.Id,
|
||
StudyInstanceUid = findStudy.StudyInstanceUid,
|
||
SeriesInstanceUid = findSerice.SeriesInstanceUid,
|
||
|
||
SopInstanceUid = sopInstanceUid,
|
||
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
|
||
InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.ContentDate).Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.ContentTime).TimeOfDay),
|
||
//InstanceTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.ContentDate) + dataset.GetSingleValue<string>(DicomTag.ContentTime), out DateTime dt) ? dt : null,
|
||
//InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate,(DateTime?)null)?.Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, TimeSpan.Zero)),
|
||
//dataset.GetSingleValueOrDefault(DicomTag.ContentDate,DateTime.Now);//, DicomTag.ContentTime)
|
||
CPIStatus = false,
|
||
ImageRows = dataset.GetSingleValueOrDefault(DicomTag.Rows, 0),
|
||
ImageColumns = dataset.GetSingleValueOrDefault(DicomTag.Columns, 0),
|
||
SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0),
|
||
|
||
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
||
NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 0),
|
||
PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty),
|
||
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
||
FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty),
|
||
WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty),
|
||
WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty),
|
||
|
||
Path = fileRelativePath,
|
||
|
||
FileSize= fileSize,
|
||
|
||
};
|
||
|
||
++findStudy.InstanceCount;
|
||
++findSerice.InstanceCount;
|
||
}
|
||
|
||
if (isPatientNeedAdd)
|
||
{
|
||
var ss = await _patientRepository.AddAsync(findPatient);
|
||
}
|
||
if (isStudyNeedAdd)
|
||
{
|
||
var dd = await _studyRepository.AddAsync(findStudy);
|
||
}
|
||
else
|
||
{
|
||
await _studyRepository.BatchUpdateNoTrackingAsync(t => t.Id == findStudy.Id, t => new SCPStudy() { IsUploadFinished = false });
|
||
}
|
||
|
||
if (isSeriesNeedAdd)
|
||
{
|
||
await _seriesRepository.AddAsync(findSerice);
|
||
}
|
||
if (isInstanceNeedAdd)
|
||
{
|
||
await _instanceRepository.AddAsync(findInstance);
|
||
}
|
||
else
|
||
{
|
||
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath,FileSize=fileSize });
|
||
}
|
||
|
||
//await _studyRepository.SaveChangesAsync();
|
||
|
||
return findStudy.Id;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
// 从DICOM文件中获取使用的字符集
|
||
private string GetEncodingVaulueFromDicomFile(DicomDataset dataset, DicomTag dicomTag)
|
||
{
|
||
|
||
// 获取DICOM文件的特定元素,通常用于指示使用的字符集
|
||
var charset = dataset.GetSingleValueOrDefault(DicomTag.SpecificCharacterSet, string.Empty);
|
||
|
||
var dicomEncoding = DicomEncoding.GetEncoding(charset);
|
||
|
||
|
||
var dicomStringElement = dataset.GetDicomItem<DicomStringElement>(dicomTag);
|
||
|
||
var bytes = dicomStringElement.Buffer.Data;
|
||
|
||
|
||
return dicomEncoding.GetString(bytes);
|
||
|
||
|
||
//// 从DICOM文件中获取使用的字符集
|
||
//string filePath = "C:\\Users\\hang\\Documents\\WeChat Files\\wxid_r2imdzb7j3q922\\FileStorage\\File\\2024-05\\1.2.840.113619.2.80.169103990.5390.1271401378.4.dcm";
|
||
//DicomFile dicomFile = DicomFile.Open(filePath);
|
||
|
||
//// 获取DICOM文件的特定元素,通常用于指示使用的字符集
|
||
//var charset = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.SpecificCharacterSet, string.Empty);
|
||
|
||
//var dicomEncoding = DicomEncoding.GetEncoding(charset);
|
||
|
||
//var value = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
|
||
|
||
//var dicomStringElement = dicomFile.Dataset.GetDicomItem<DicomStringElement>(DicomTag.PatientName);
|
||
|
||
//var bytes = dicomStringElement.Buffer.Data;
|
||
|
||
//var aa= dicomEncoding.GetString(bytes);
|
||
|
||
|
||
}
|
||
}
|
||
}
|