diff --git a/IRC.Core.SCP/Service/CStoreSCPService.cs b/IRC.Core.SCP/Service/CStoreSCPService.cs index 6ecaeae28..1f5183bd3 100644 --- a/IRC.Core.SCP/Service/CStoreSCPService.cs +++ b/IRC.Core.SCP/Service/CStoreSCPService.cs @@ -334,44 +334,227 @@ namespace IRaCIS.Core.SCP.Service ms.Position = 0; var dicomFile = DicomFile.Open(ms); - var pixelData = DicomPixelData.Create(dicomFile.Dataset); - var syntax = pixelData.Syntax; + var numberOfFrames = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 1); - // 每个 fragment 固定大小 (64KB 示例,可以自己调整) - int fragmentSize = 20 * 1024; - - if (syntax.IsEncapsulated) + //多帧处理逻辑 + if (numberOfFrames > 1) { - var newFragments = new DicomOtherByteFragment(DicomTag.PixelData); + //一定要有像素数据才处理 + var pixelData = DicomPixelData.Create(dicomFile.Dataset); - for (int n = 0; n < pixelData.NumberOfFrames; n++) + if (pixelData != null) { - var frameData = pixelData.GetFrame(n); // 获取完整一帧 - var data = frameData.Data; - int offset = 0; - - while (offset < data.Length) + try { - int size = Math.Min(fragmentSize, data.Length - offset); - var buffer = new byte[size]; - Buffer.BlockCopy(data, offset, buffer, 0, size); - newFragments.Fragments.Add(new MemoryByteBuffer(buffer)); - offset += size; + Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 开始处理多帧instanceId:{instanceId}"); + + var syntax = pixelData.Syntax; + + // 每个 fragment 固定大小 (64KB 示例,可以自己调整) + int fragmentSize = 20 * 1024; + + + + var frag = dicomFile.Dataset.GetDicomItem(DicomTag.PixelData); + + int fragmentCount = frag?.Fragments?.Count() ?? 0; + + var originOffsetTable = frag?.OffsetTable; //有可能没有表,需要自己重建 + + var bot = new List(); + + uint botOffset = 0; + + //需要拆成固定片段的 + if (syntax.IsEncapsulated && fragmentCount == pixelData.NumberOfFrames && numberOfFrames > 1) + { + + + + var newFragments = new DicomOtherByteFragment(DicomTag.PixelData); + + #region test + //var newDicomFile = dicomFile.Clone(); + + //var newDataset = newDicomFile.Dataset; + + //var dstPd = DicomPixelData.Create(newDataset, true); + + //for (int i = 0; i < pixelData.NumberOfFrames; i++) + //{ + // var frame = pixelData.GetFrame(i); + + // dstPd.AddFrame(frame); + + // var data = frame.Data; + // int offset = 0; + + // while (offset < data.Length) + // { + // int size = Math.Min(fragmentSize, data.Length - offset); + // var buffer = new byte[size]; + // Buffer.BlockCopy(data, offset, buffer, 0, size); + + // newFragments.Fragments.Add(new MemoryByteBuffer(buffer)); + + // offset += size; + + // } + + + //} + //var newOffsetTable = newDataset.GetDicomItem(DicomTag.PixelData).OffsetTable; + + //newFragments.OffsetTable.AddRange(newOffsetTable.ToArray()); + #endregion + + #region test fo-dicom auto bot + //var newDicomFile = dicomFile.Clone(); + + //var newDataset = newDicomFile.Dataset; + + //var dstPd = DicomPixelData.Create(newDataset, true); + + //for (int i = 0; i < pixelData.NumberOfFrames; i++) + //{ + // var frame = pixelData.GetFrame(i); + + // dstPd.AddFrame(frame); + //} + //var newOffsetTable = newDataset.GetDicomItem(DicomTag.PixelData).OffsetTable; + + //Console.WriteLine(newOffsetTable.ToJsonStr()); + #endregion + + #region 最终使用 + + for (int n = 0; n < pixelData.NumberOfFrames; n++) + { + var frameData = pixelData.GetFrame(n); // 获取完整一帧 + var data = frameData.Data; + int offset = 0; + + bot.Add(botOffset); + + botOffset += (uint)data.Length; + + + while (offset < data.Length) + { + botOffset += 8; + + + int size = Math.Min(fragmentSize, data.Length - offset); + var buffer = new byte[size]; + Buffer.BlockCopy(data, offset, buffer, 0, size); + + newFragments.Fragments.Add(new MemoryByteBuffer(buffer)); + + offset += size; + + } + } + + //保留原始偏移表 + + if (originOffsetTable.Count == pixelData.NumberOfFrames) + { + newFragments.OffsetTable.AddRange(originOffsetTable.ToArray()); + + } + else + { + newFragments.OffsetTable.AddRange(bot.ToArray()); + + //Console.WriteLine(bot.ToJsonStr()); + } + + #endregion + + + dicomFile.Dataset.AddOrUpdate(newFragments); + + + // 重新保存 dicom 到流 + ms.SetLength(0); + + dicomFile.Save(ms); + } + //传递过来的就是拆分的,但是是没有偏移表的,我需要自己创建偏移表,不然生成缩略图失败 + else if (syntax.IsEncapsulated && fragmentCount > pixelData.NumberOfFrames && originOffsetTable.Count == 0) + { + + + + uint offset = 0; + + bot.Add(offset); + + var fistSize = frag.Fragments.FirstOrDefault()?.Size ?? 0; + + //和上一个大小不一样 + var isDiffrentBefore = false; + + uint count = 0; + + // 假设你知道每帧对应的 fragment 数量 + foreach (var frameFragments in frag.Fragments) + { + count++; + + if (frameFragments.Size == fistSize) + { + isDiffrentBefore = false; + // 累加这一帧所有 fragment 的大小 + offset += (uint)frameFragments.Size; + continue; + } + else + { + offset += (uint)frameFragments.Size; + isDiffrentBefore = true; + + } + + if (isDiffrentBefore) + { + //每个Fragment 也占用字节 + offset += 8 * count; + bot.Add(offset); + count = 0; + + } + + } + + bot.RemoveAt(bot.Count - 1); + // 设置到新的 PixelData + frag.OffsetTable.AddRange(bot.ToArray()); + + + // 重新保存 DICOM 到流 + ms.SetLength(0); + + dicomFile.Save(ms); + + } + + } + catch (Exception mutiEx) + { + Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 处理多帧失败,上传原始文件:{mutiEx.ToString()}"); } } - - // 替换原 PixelData - dicomFile.Dataset.AddOrUpdate(newFragments); - - - // 重新保存 dicom 到流 - ms.SetLength(0); - dicomFile.Save(ms); } - ms.Position = 0; + + + + + + #endregion @@ -387,6 +570,7 @@ namespace IRaCIS.Core.SCP.Service #endregion + ms.Position = 0; //irc 从路径最后一截取Guid storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false); @@ -429,9 +613,8 @@ namespace IRaCIS.Core.SCP.Service // 上传缩略图到 OSS - var seriesPath = await ossService.UploadToOSSAsync(memoryStream, ossFolderPath, seriesId.ToString() + ".preview.jpg", false); + var seriesPath = await ossService.UploadToOSSAsync(memoryStream, ossFolderPath, $"{seriesId.ToString()}_{instanceId.ToString()}.preview.jpg", false); - Console.WriteLine(seriesPath + " Id: " + seriesId); series.ImageResizePath = seriesPath; diff --git a/IRC.Core.SCP/Service/DicomArchiveService.cs b/IRC.Core.SCP/Service/DicomArchiveService.cs index 6a28537d4..5a032e611 100644 --- a/IRC.Core.SCP/Service/DicomArchiveService.cs +++ b/IRC.Core.SCP/Service/DicomArchiveService.cs @@ -334,7 +334,7 @@ namespace IRaCIS.Core.SCP.Service SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0), SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty), - NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 0), + NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 1), PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty), ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty), FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty), diff --git a/IRaCIS.Core.Application/Helper/OSSService.cs b/IRaCIS.Core.Application/Helper/OSSService.cs index 42b804947..af6a95223 100644 --- a/IRaCIS.Core.Application/Helper/OSSService.cs +++ b/IRaCIS.Core.Application/Helper/OSSService.cs @@ -238,7 +238,6 @@ public class OSSService : IOSSService new Aliyun.OSS.LifecycleRule.LifeCycleTransition { - // 关键设置:Days = 0 表示对最后修改时间≤当前的所有文件生效 LifeCycleExpiration = { Days = 1 diff --git a/IRaCIS.Core.Application/TestService.cs b/IRaCIS.Core.Application/TestService.cs index cbcdfde06..43dcbbacb 100644 --- a/IRaCIS.Core.Application/TestService.cs +++ b/IRaCIS.Core.Application/TestService.cs @@ -76,9 +76,13 @@ namespace IRaCIS.Core.Application.Service public static int IntValue = 100; [AllowAnonymous] - public async Task TestOSS() + public async Task TestOSS(StorageClass storageClass) { - _IOSSService.SetImmediateArchiveRule("Test-Archive", StorageClass.Archive); + if (storageClass == StorageClass.IA || storageClass == StorageClass.Archive || storageClass == StorageClass.ColdArchive || storageClass == StorageClass.DeepColdArchive) + { + _IOSSService.SetImmediateArchiveRule($"Test-Archive/Archive{(int)storageClass}", storageClass); + + } return ResponseOutput.Ok(); }