DICOM Basics using Java - Presentation States (GSPS)

Introduction

This is part of my series of articles on the DICOM standard. In this tutorial, we'll explore DICOM Presentation States, which allow you to store display settings like window/level, annotations, and overlays separately from the original image data.

Presentation States enable saving "views" of images without modifying the original pixel data, supporting use cases like multiple window presets (lung, bone, soft tissue) and annotation sharing.

Prerequisites

Before you begin, ensure you have the following:

  • Java JDK installed (Java 8 or later)
  • PixelMed Java DICOM Toolkit
  • You can find all the code demonstrated in this tutorial on GitHub here

“The details are not the details. They make the design.” ~ Charles Eames

The Theory Behind Presentation States

Presentation States implement a crucial principle in medical imaging: separation of data from presentation. The original pixel data should never be modified, but multiple "views" of that data should be shareable.

The Diagnostic Display Challenge

Consider a CT scan with 500 images. A single image might be viewed with:

  • Lung Window: WW=1500, WL=-600 to see pulmonary structures
  • Mediastinal Window: WW=400, WL=40 to see soft tissue
  • Bone Window: WW=1800, WL=400 to see osseous structures

Each window reveals different diagnostic information from the same data. Without Presentation States, there's no standard way to share these views - a finding noted on lung windows might not be visible with the recipient's default display settings.

The Data Integrity Principle

Presentation States enforce original data preservation:

  • Pixel data is never modified
  • Display transformations are stored separately
  • Multiple Presentation States can reference the same image
  • Viewers can ignore Presentation States and use raw data

This is critical for legal and regulatory compliance - the original acquisition data remains untouched and available for alternative interpretations.

The Annotation Problem

When a radiologist circles a finding on an image, where should that annotation live?

  • Burned into pixels: Modifies original data (bad), visible to everyone (good)
  • Stored in viewer database: Preserves data (good), not shareable (bad)
  • In Presentation State: Preserves data (good), standardized and shareable (good)

Presentation States store annotations as Graphic Annotation Sequences with coordinates in the image coordinate system, making them portable between compliant viewers.

Grayscale Pipeline Model

DICOM defines a precise grayscale display pipeline that Presentation States can modify at each stage:

Stored Pixel Values
    ↓ Modality LUT Transformation:
      Either Rescale Slope/Intercept OR Modality LUT
      (these are mutually exclusive alternatives)
Modality LUT Output
    ↓ Window Width/Center or VOI LUT
VOI LUT Output
    ↓ Presentation LUT
Display-ready Values

Note that Rescale Slope/Intercept and the Modality LUT are mutually exclusive alternatives for the Modality LUT transformation stage -- either one or the other is used, but not both. Each stage in this pipeline can be overridden by Presentation State attributes, giving complete control over how stored pixels map to displayed brightness.

Presentation State Types

TypeSOP Class UIDUse Case
Grayscale Softcopy PS1.2.840.10008.5.1.4.1.1.11.1Grayscale images
Color Softcopy PS1.2.840.10008.5.1.4.1.1.11.2Color images
Pseudo-Color Softcopy PS1.2.840.10008.5.1.4.1.1.11.3Pseudo-color mapping
Blending Softcopy PS1.2.840.10008.5.1.4.1.1.11.4Image blending
XA/XRF Grayscale Softcopy PS1.2.840.10008.5.1.4.1.1.11.5Fluoroscopy

What Can Be Stored in a Presentation State?

  • Window Width/Level: Brightness and contrast settings
  • Zoom and Pan: Displayed area selection
  • Rotation and Flip: Image orientation
  • Annotations: Text and graphic overlays
  • Display Shutters: Hide portions of the image
  • LUTs: Lookup tables for intensity mapping

Creating a Grayscale Presentation State

package com.saravanansubramanian.dicom.pixelmedtutorial;

import java.text.SimpleDateFormat;
import java.util.Date;
import com.pixelmed.dicom.*;

public class CreatePresentationStateDemo {

    public static void main(String[] args) {

        try {

            System.out.println("=== DICOM Presentation State Demo ===\n");

            // The image this presentation state references
            String referencedStudyUID = "1.2.3.4.5.6.7.8.9";
            String referencedSeriesUID = "1.2.3.4.5.6.7.8.9.1";
            String referencedSOPInstanceUID = "1.2.3.4.5.6.7.8.9.1.1";
            String referencedSOPClassUID = SOPClass.CTImageStorage;

            String outputFile = "C:\\temp\\presentation_state.dcm";

            // Create the presentation state
            AttributeList psList = createGrayscalePresentationState(
                referencedStudyUID,
                referencedSeriesUID,
                referencedSOPInstanceUID,
                referencedSOPClassUID
            );

            // Add file meta information
            FileMetaInformation.addFileMetaInformation(
                psList,
                TransferSyntax.ExplicitVRLittleEndian,
                "OurAET"
            );

            psList.write(outputFile);

            System.out.println("Presentation State created: " + outputFile);
            System.out.println("Window Width: 1500, Window Center: -600 (Lung)");

        } catch (Exception e) {
            e.printStackTrace(System.err);
        }
    }
}

Setting Window Width and Level

// === Softcopy VOI LUT Module (Window Width/Level) ===
SequenceAttribute voiLutSeq = new SequenceAttribute(TagFromName.SoftcopyVOILUTSequence);
AttributeList voiLutItem = new AttributeList();

// Reference the image this applies to
SequenceAttribute refImageSeq = new SequenceAttribute(TagFromName.ReferencedImageSequence);
AttributeList refImageItem = new AttributeList();
refImageItem.put(createUID(TagFromName.ReferencedSOPClassUID, sopClassUID));
refImageItem.put(createUID(TagFromName.ReferencedSOPInstanceUID, sopInstanceUID));
refImageSeq.addItem(refImageItem);
voiLutItem.put(refImageSeq);

// Window Center and Width for lung window
Attribute windowCenter = new DecimalStringAttribute(TagFromName.WindowCenter);
windowCenter.addValue("-600"); // Lung window center
voiLutItem.put(windowCenter);

Attribute windowWidth = new DecimalStringAttribute(TagFromName.WindowWidth);
windowWidth.addValue("1500"); // Lung window width
voiLutItem.put(windowWidth);

// VOI LUT Function
Attribute voiFunc = new CodeStringAttribute(TagFromName.VOILUTFunction);
voiFunc.addValue("LINEAR");
voiLutItem.put(voiFunc);

voiLutSeq.addItem(voiLutItem);
list.put(voiLutSeq);

Adding Text Annotations

// === Graphic Annotation Module ===
SequenceAttribute graphicAnnotationSeq = new SequenceAttribute(
    TagFromName.GraphicAnnotationSequence);
AttributeList annotationItem = new AttributeList();

// Graphic Layer
annotationItem.put(createCode(TagFromName.GraphicLayer, "LAYER1"));

// Text Object Sequence
SequenceAttribute textObjectSeq = new SequenceAttribute(TagFromName.TextObjectSequence);
AttributeList textItem = new AttributeList();

// Bounding box for text
Attribute boundingBoxTLHC = new DecimalStringAttribute(
    TagFromName.BoundingBoxTopLeftHandCorner);
boundingBoxTLHC.addValue("10");
boundingBoxTLHC.addValue("10");
textItem.put(boundingBoxTLHC);

Attribute boundingBoxBRHC = new DecimalStringAttribute(
    TagFromName.BoundingBoxBottomRightHandCorner);
boundingBoxBRHC.addValue("200");
boundingBoxBRHC.addValue("50");
textItem.put(boundingBoxBRHC);

// The text to display
Attribute unformattedText = new ShortTextAttribute(TagFromName.UnformattedTextValue);
unformattedText.addValue("Lung Window Preset");
textItem.put(unformattedText);

textObjectSeq.addItem(textItem);
annotationItem.put(textObjectSeq);
graphicAnnotationSeq.addItem(annotationItem);
list.put(graphicAnnotationSeq);

Common Window Presets for CT

PresetWindow CenterWindow WidthUse Case
Lung-6001500Lung parenchyma
Mediastinum40400Soft tissue
Bone4001800Bone detail
Brain4080Brain tissue
Liver60150Abdominal organs
Stroke3535Acute stroke

Presentation State Key Attributes

TagNameDescription
(0008,0060)ModalityPR (Presentation State)
(0070,0080)Content LabelUser-friendly name
(0070,0081)Content DescriptionDescription
(0070,0082)Presentation Creation DateWhen created
(0008,1115)Referenced Series SequenceLinks to images
(0028,3110)Softcopy VOI LUT SequenceWindow/level
(0070,0001)Graphic Annotation SequenceAnnotations
(0070,0060)Graphic Layer SequenceLayer definitions

Conclusion

DICOM Presentation States provide a powerful mechanism for storing display settings separately from image data. This enables multiple views of the same image (different window presets), annotation sharing between users, and preservation of original pixel data while documenting specific findings.

Understanding Presentation States is particularly important for building diagnostic viewing applications that need to save and restore user-defined display configurations. In the next tutorial in this series, I will cover DICOM Key Object Selection for marking significant images. See you then!