LAUREL BRIDGE

LaurelBridge.DCFExamples.DatasetDump Namespace

DICOM Connectivity Framework V3.4
The DatasetDump example demonstrates how to use DCF to dump a dataset header.
Classes

  ClassDescription
Public classOptions
Command line options class for parsing user options for DatasetDump.
Public classProgram
The ToString method of DicomDataSet is used to convert an object instance to a human readable string.

Behind the scenes, the ToString method uses the DataSetDumper class which uses DataSetDumperOptions to provide extensive control over the formatting and output options. The second output demonstrates how to get the file offsets for a chapter 10 file.

This example also demonstrates usage of TryReadDataSet(DicomDataSet, DCSException). This method allows the invoker to read a dataset with encoding errors and return the elements that were successfully read and diagnostics that aid in determining where the encoding errors occurred.

Remarks

Supported OS Platforms:

  • Windows - .Net Framework 4.7.2 64-bit and 32-bit
  • Windows - .Net Core 2.1 64-bit and 32-bit
  • Linux - .Net Core 2.1 64-bit

Examples

DatasetDump Sample Code
public class Program
{
    private static readonly long TooBigToBuffer = IntPtr.Size == 4 ? 100 * 1024 * 1024 : 1024 * 1024 * 1024;

    /// <summary>
    /// Main entry point for DatasetDump. See the <see cref="Options"/> class for usage and options.
    /// </summary>
    /// <param name="args">command line arguments</param>
    public static void Main(string[] args)
    {
        Console.WriteLine("DCF Library using target framework {0}", DCFVersion.TargetFramework);
        try
        {
            if (!Options.TryParse(args, out Options options))
            {
                throw new ArgumentException("bad command line parameters");
            }

            // EnableStreamingMode is the default, but just in case somebody changed it
            DicomSessionSettings ss = new DicomSessionSettings() { EnableStreamingMode = true };
            List<string> fileNames = new List<string>(options.FileNames);
            if (fileNames.Count > 1)
            {
                throw new InvalidOperationException("only one path name is expected");
            }

            using (DicomFileInput dfi = new DicomFileInput(fileNames[0], ss))
            {
                DicomDataSet dds = DoRead(dfi, options.TryRead);
                // If we want the first few pixels to be dumped, expand the streaming mode data,
                // which will cause encapsulated data to be decoded.  But don't do this unless
                // the transfer syntax of the dataset is one that can be decoded.
                // Also check if we have a pixel data element that is too big to buffer.
                DicomElement pixelData = dds.GetElement(Tags.PixelData);
                bool expandPixelData =
                    DecodableTsUids.Contains(dds.OriginalTransferSyntax)
                    &&
                    (pixelData == null || pixelData.LongLength < TooBigToBuffer);
                if (expandPixelData)
                {
                    dds.ExpandStreamingModeData(true);
                }

                Console.WriteLine(dds);
            }

            using (DicomFileInput dfi = new DicomFileInput(fileNames[0], ss))
            {
                // also have to tell the file input to track element offsets
                // the element offsets are stored in the dataset object
                dfi.TrackElementOffsets = true;
                DicomDataSet dds = DoRead(dfi, options.TryRead);
                // set the dumper options for this dataset to show element offsets and not to show hex values
                dds.DumperOptions = new DataSetDumperOptions() { ShowElementOffsets = true, ShowHexValues = false };
                Console.WriteLine("With element offsets and no hex values{0}{1}", Environment.NewLine, dds);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception caught during execution: {0}", e);
            Environment.ExitCode = 1;
        }
        finally
        {
            if (Debugger.IsAttached)
            {
                Console.Write("Press any key to continue . . . ");
                Console.ReadKey();
            }
        }
    }

    /// <summary>
    /// Read a dataset from a DicomFileInput.  If tryRead is true use TryReadDataSet, else use ReadDataSet.
    /// If TryReadDataSet fails, print an error message and the diagnostic summary, but return the partial dataset.
    /// </summary>
    /// <param name="dfi">the DicomFileInput which should be non-null.</param>
    /// <param name="tryRead">true to use TryReadDataSet; false to use ReadDataSet</param>
    /// <returns>the dataset that was read</returns>
    /// <exception cref="DCSException">if tryRead is false and and an error occurred reading the dataset</exception>
    private static DicomDataSet DoRead(DicomFileInput dfi, bool tryRead)
    {
        string path = dfi.FileName ?? "unknown";
        if (tryRead)
        {
            bool readOk = dfi.TryReadDataSet(out DicomDataSet dds, out DCSException failure);
            if (!readOk)
            {
                string lastElement = (string) failure.Data["LastElement"];
                long lastOffset = (long) failure.Data["LastOffset"];
                string parseHistory = (string) failure.Data["ParseHistory"];
                string diagnostics = string.Format("last element: {1}{0}last offset: {2}{0}: parse history: {3}{0}",
                    Environment.NewLine,
                    string.IsNullOrEmpty(lastElement) ? "none" : lastElement,
                    lastOffset,
                    string.IsNullOrEmpty(parseHistory) ? "none" : parseHistory);
                Console.WriteLine("TryReadDataSet({1}) ERROR: some elements were not successfully processed:{0}{2}", Environment.NewLine, path, diagnostics);
            }
            return dds;
        }

        return dfi.ReadDataSet();
    }

    /// <summary>
    /// These are the transfer syntax uids that DCF can decode out of the box.
    /// </summary>
    private static readonly List<string> DecodableTsUids = new List<string>
    {
        // Implicit and Explicit Little Endian
        Uids.ILE, Uids.ELE,
        // Big Endian is deprecated but there are still plenty in the field
        Uids.EBE,
        // Run Length Encoded
        Uids.RLELossless,
        // Jpeg flavors
        Uids.Jpeg50, Uids.Jpeg51, Uids.Jpeg57, Uids.Jpeg70,
        // JpegLs flavors
        Uids.Jpeg80, Uids.Jpeg81,
        // Jpeg 2000 flavors
        Uids.J2k90, Uids.J2k91
    };
}