How to Use fo-dicom to Extract MultiFrames File to Multi DICOM Files For WebRenderer

Installing fo-dicom Dependencies

To begin, install the required fo-dicom packages using NuGet Package Manager in Visual Studio:

dotnet add package fo-dicom             
dotnet add package fo-dicom.Codecs
dotnet add package fo-dicom.Imaging.ImageSharp

Extracting Multi-Frames to Multi-Files

using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using FellowOakDicom;
using FellowOakDicom.Imaging;
using FellowOakDicom.Imaging.Codec;
using FellowOakDicom.IO.Buffer;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png;
using DicomTransferSyntax = FellowOakDicom.DicomTransferSyntax;

namespace RemoveSomeTags
{
    public static class MultiFramesExtrac
    {
        public static async Task<bool> ExtractMultiFramesToMultiFiles(string dicomFileIn, string dicomOutStr)
        {
            if (string.IsNullOrWhiteSpace(dicomFileIn) || string.IsNullOrWhiteSpace(dicomOutStr))
                return false;

            try
            {
                var dicomFile = await DicomFile.OpenAsync(dicomFileIn);
                var ds = dicomFile.Dataset;
                if (!ds.Contains(DicomTag.NumberOfFrames))
                {
                    Console.WriteLine("No NumberOfFrames tag found.");
                    return false;
                }

                int numFrames = ds.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 1);
                if (numFrames <= 1)
                {
                    Console.WriteLine("No frames found. or single frame only.");
                    return false;
                }

                // Create PixelData(maybe encapsulated)
                DicomPixelData pixelData = DicomPixelData.Create(ds, false);

                IByteBuffer[] frameBuffers = Enumerable.Range(0, pixelData.NumberOfFrames)
                    .Select(i => pixelData.GetFrame(i))
                    .ToArray(); 
                Directory.CreateDirectory(dicomOutStr);
                var seriesUid = ds.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, DicomUID.Generate().UID);

                var frames = frameBuffers.Length;
                for (int i = 0; i < frames; i++)
                {
                    var frameBuffer = frameBuffers[i]; 
                    var newDs = ds.Clone();
                    var newSopUid = DicomUID.Generate();
                    newDs.AddOrUpdate(DicomTag.SOPInstanceUID, newSopUid.UID);
                    newDs.AddOrUpdate(DicomTag.InstanceNumber, i + 1);
                    newDs.AddOrUpdate(DicomTag.NumberOfFrames, 1); 
                    newDs.Remove(DicomTag.PixelData);
                    var newPixel = DicomPixelData.Create(newDs, true);
                    newPixel.AddFrame(frameBuffer);
                    var outFile = Path.Combine(dicomOutStr, $"{seriesUid}_{i + 1:D4}.dcm");
                    var newFile = new DicomFile(newDs)
                    {
                        FileMetaInfo =
                        {
                            MediaStorageSOPClassUID = dicomFile.FileMetaInfo.MediaStorageSOPClassUID,
                            MediaStorageSOPInstanceUID = newSopUid,
                            TransferSyntax = dicomFile.FileMetaInfo.TransferSyntax ??
                                             pixelData.Syntax
                        }
                    };

                    await newFile.SaveAsync(outFile);
                }

                return true;
            }
            catch (Exception finalEx)
            {
                await Console.Error.WriteLineAsync("Unexpected error: " + finalEx);
                return false;
            }
        }
    }
}

Important Note

this code is a basic implementation and may not cover all possible scenarios or edge cases. It’s recommended to thoroughly test and modify the code according to your specific requirements.