LAUREL BRIDGE

LaurelBridge.DCF.Examples.CreateBasicOffsetTable Namespace

DICOM Connectivity Framework V3.4
The CreateBasicOffsetTable demonstrates how to use DCF to create basic frame tables for multiframe image datasets.
Classes

  ClassDescription
Public classProgram
DICOM defines the notion of a basic offset table for encapsulated pixel data elements to aid in finding the start of each image frame in a multiframe image. The basic offset table is the first sequence fragment after the pixel data element header, and it is allowed to be empty, or to have a sequence of 32-bit unsigned offset values that indicate the starting offset of each frame in the compressed datastream. Each frame offset is relative to the end of the basic offset table, so the first offset is always zero.

While the basic offset table is useful for readers, it is not required, since readers are required to be able to handle empty basic offset tables. For writers, the creation of the basic offset table can be inefficient since the size of the compressed image fragments that follow is not known in advance, so unless the output that the writer is writing to is seekable, the entire compressed image stream must be buffered in order to write the basic offset table first.

Examples

CreateBasicOffsetTable Sample Code
public class Program
{
    private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();

    private static readonly string HelpString = String.Join(Environment.NewLine,
        "This program works better with command line arguments.",
        "usage: CreateBasicOffsetTable inputPath outputPath [creationMode] [outputSyntax]",
        "",
        "This program will read the DICOM file specified by inputPath, and create a DICOM file in outputPath,",
        "and create a basic frame offset table as specified by creationMode.",
        "The inputPath must exist, and the outputPath path will be overwritten.",
        "The creationMode may be 0 (create empty), 1 (create if empty or invalid) or 2 (replace existing).",
        "If creationMode is unspecified, it will be set to 1.",
        "If outputSyntax is unspecified, the transfer syntax of the outputPath will be the same as the inputPath."
    );

    /// <summary>
    /// Main entry point for CreateBasicOffsetTable.
    /// </summary>
    /// <param name="args">command line arguments</param>
    [STAThread]
    public static void Main(string[] args)
    {
        try
        {
            string inputPath;
            string outputPath;
            int creationMode;
            string outputSyntax;
            if (!TryGetOptions(args, out inputPath, out outputPath, out creationMode, out outputSyntax))
            {
                Logger.Warn(HelpString);
                Environment.ExitCode = 1;
                return;
            }

            // use the frame producer to see if inputPath has usable frame offsets
            using (FrameProducer fp = FrameProducer.CreateFromFile(inputPath))
            {
                fp.GetFrameOffsets(); // loads basic offset table if available, or creates if not available
                Logger.InfoFormat("Path({0}), WasOffsetTableValid({1}){2}{3}",
                    inputPath, fp.WasOffsetTableValid, Environment.NewLine, fp.DumpFrameOffsets());
            }

            using (DicomFileInput dfi = new DicomFileInput(inputPath))
            {
                DicomDataSet inputDataSet = dfi.ReadDataSet();
                string tsUid = String.IsNullOrEmpty(outputSyntax) ? dfi.ActualTsUid : outputSyntax;
                DicomSessionSettings sessionSettings = new DicomSessionSettings() { BasicOffsetTableCreationMode = creationMode };
                using (DicomFileOutput dfo = new DicomFileOutput(outputPath, tsUid, sessionSettings))
                {
                    dfo.WriteDataSet(inputDataSet);
                }
            }

            // use the frame producer to see if inputPath has usable frame offsets
            using (FrameProducer fp = FrameProducer.CreateFromFile(outputPath))
            {
                fp.GetFrameOffsets(); // loads basic offset table if available, or creates if not available
                Logger.InfoFormat("Path({0}), WasOffsetTableValid({1}){2}{3}",
                    outputPath, fp.WasOffsetTableValid, Environment.NewLine, fp.DumpFrameOffsets());
            }
        }
        catch (Exception e)
        {
            Logger.ErrorFormat("error during execution: {0}", e);
        }
        finally
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                Console.Write("Press any key to continue . . . ");
                Console.ReadKey();
            }
        }
    }

    /// <summary>
    /// Replace shorthand transfer syntax strings with their uid equivalent because not all of us can remember.
    /// Note that a uid might be invalid depending upon the image characteristics, so let the transcoder beware.
    /// </summary>
    /// <param name="tsUid">the transfer syntax uid to map.</param>
    /// <returns>Either the tsUid or a uid corresponding to the alias.</returns>
    private static string GetTsUid(string tsUid)
    {
        if (String.IsNullOrWhiteSpace(tsUid))
            return String.Empty;
        tsUid = tsUid.Trim();
        switch (tsUid.ToLowerInvariant())
        {
            case "ele":
                return Uids.ELE;
            case "ebe":
                return Uids.EBE;
            case "rle":
                return Uids.RLELossless;
            case "jpeg50":
            case "50":
                return Uids.Jpeg50;
            case "jpeg57":
            case "57":
                return Uids.Jpeg57;
            case "jpeg70":
            case "70":
                return Uids.Jpeg70;
            case "jpeg90":
            case "90":
                return Uids.J2k90;
            case "jpeg91":
            case "91":
                return Uids.J2k91;
            default:
                return tsUid;
        }
    }

    private static bool TryGetOptions(string[] args, out string inputPath, out string outputPath, out int creationMode, out string tsUid)
    {
        inputPath = outputPath = tsUid = String.Empty;
        creationMode = 1;
        if (args.Length < 2 || args.Length > 4)
            return false;
        inputPath = args[0];
        outputPath = args[1];
        if (args.Length >= 3)
            creationMode = Int32.Parse(args[2]);
        if (args.Length >= 4)
            tsUid = GetTsUid(args[3]);
        return true;
    }
}