DICOM Basics using Java - Private Tags

Introduction

This is part of my series of articles on the DICOM standard. In this tutorial, we'll explore DICOM private tags, which allow vendors to store proprietary data in DICOM objects. Understanding private tags is essential for working with data from various scanner manufacturers.

Private tags use odd group numbers (0009, 0011, 0019, etc.) to avoid conflicts with standard DICOM tags.

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

“With great power comes great responsibility.” ~ Uncle Ben

The Theory Behind Private Tags

Private tags represent DICOM's solution to the extensibility vs. interoperability tension that affects all standards. Vendors need to store proprietary information, but uncontrolled extension would fragment the standard.

The Namespace Problem

Consider the challenge: GE, Siemens, Philips, and hundreds of other vendors all need to store scanner-specific parameters. Without a coordination mechanism, they might all choose the same tag numbers for different purposes, creating chaos when data moves between systems.

DICOM's solution divides the 16-bit group number space:

  • Even Groups (0000, 0002, 0008, etc.): Reserved for standard DICOM-defined attributes
  • Odd Groups (0009, 0011, 0019, etc.): Available for private (vendor-specific) use

The Private Creator Mechanism

Within each private group, DICOM further subdivides using Private Creator elements. This provides namespace isolation within a group:

  • Elements (gggg,0010) through (gggg,00FF) are Private Creator identification codes
  • Each Private Creator "reserves" a block of 256 elements
  • Block 10 (creator at xx10) reserves elements xx1000-xx10FF
  • Block 11 (creator at xx11) reserves elements xx1100-xx11FF

This means two vendors can use the same group number (e.g., 0019) without conflict, as long as they register different Private Creator strings.

Information Preservation Challenges

Private tags create interoperability challenges that system designers must understand:

  • Semantic Opacity: Receiving systems cannot interpret private tags without vendor documentation
  • Transfer Stripping: Many systems remove private tags during transfer, considering them non-essential
  • De-identification Risk: Private tags may contain PHI in unexpected ways
  • Version Dependencies: Private tag meanings may change between vendor software versions

When to Use Private Tags

Private tags should be used only when no standard tag exists and the information is:

  • Truly vendor-specific (scanner calibration parameters, proprietary algorithms)
  • Not clinically essential (loss during transfer is acceptable)
  • Not duplicating information that should be in standard tags

Before creating a private tag, check the DICOM standard for existing tags and consider submitting a Change Proposal if the information type has general applicability.

Private Tag Structure

Private Tag Anatomy:

Standard tag: (gggg,eeee)
  gggg = group number (even for standard, odd for private)
  eeee = element number

Private tag blocks:
  Group 0009, Block 10:
    (0009,0010) = Private Creator Identification
    (0009,1000) through (0009,10FF) = Private data elements

  Group 0009, Block 11:
    (0009,0011) = Private Creator Identification
    (0009,1100) through (0009,11FF) = Private data elements

Creating Private Tags

package com.saravanansubramanian.dicom.pixelmedtutorial;

import com.pixelmed.dicom.*;

public class PrivateTagsDemo {

    public static void main(String[] args) {

        try {

            System.out.println("=== DICOM Private Tags Demo ===\n");

            AttributeList list = new AttributeList();

            // Add standard attributes first
            Attribute patientName = new PersonNameAttribute(TagFromName.PatientName);
            patientName.addValue("Doe^John");
            list.put(patientName);

            // === Step 1: Reserve a private block ===
            // Use group 0009, block 10 (element 0010)
            AttributeTag creatorTag = new AttributeTag(0x0009, 0x0010);
            Attribute creatorAttr = new LongStringAttribute(creatorTag);
            creatorAttr.addValue("MY_APPLICATION");  // Your identifier
            list.put(creatorAttr);

            System.out.println("Step 1: Reserve private block");
            System.out.println("  Tag: (0009,0010)");
            System.out.println("  Creator: MY_APPLICATION");

            // === Step 2: Add private data elements ===

            // Private element (0009,1000) - block 10, element 00
            AttributeTag privateTag1 = new AttributeTag(0x0009, 0x1000);
            Attribute privateAttr1 = new LongStringAttribute(privateTag1);
            privateAttr1.addValue("Custom Value 1");
            list.put(privateAttr1);

            // Private element (0009,1001) - block 10, element 01
            AttributeTag privateTag2 = new AttributeTag(0x0009, 0x1001);
            Attribute privateAttr2 = new LongStringAttribute(privateTag2);
            privateAttr2.addValue("Custom Value 2");
            list.put(privateAttr2);

            System.out.println("\nStep 2: Add private data elements");
            System.out.println("  (0009,1000) = \"Custom Value 1\"");
            System.out.println("  (0009,1001) = \"Custom Value 2\"");

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

Reading Private Tags

// Check for creator before reading private data
Attribute creator = list.get(new AttributeTag(0x0009, 0x0010));

if (creator != null &&
    creator.getSingleStringValueOrNull().equals("MY_APPLICATION")) {

    // Safe to read our private data
    Attribute data = list.get(new AttributeTag(0x0009, 0x1000));
    String value = data.getSingleStringValueOrNull();
    System.out.println("Private data: " + value);
}

Common Vendor Private Tags

VendorCreator ExamplesGroups
GE HealthcareGEMS_IDEN_01, GEMS_ACQU_010009, 0019, 0021, 0043
SiemensSIEMENS MR HEADER, SIEMENS CT VA00019, 0021, 0029, 0051
PhilipsPHILIPS MR, Philips Imaging DD 0012001, 2005, 7053
Canon/ToshibaTOSHIBA_MEC_CT_017005, 700D

Example: GE Scanner Private Tags

(0009,0010) LO "GEMS_IDEN_01"         <- Creator ID for block 10
(0009,1001) LO "CT01"                  <- Product ID
(0009,1002) SH "CT Lightspeed"         <- Scanner model
(0009,1027) SL 123456                  <- Internal code

Example: Siemens Scanner Private Tags

(0019,0010) LO "SIEMENS MR HEADER"    <- Creator ID
(0019,100C) IS 1                       <- Gradient mode
(0019,100F) DS 2.3                     <- Flow compensation

Best Practices

DO:

  • Always register a Private Creator Identification
  • Use unique, identifiable creator names
  • Document your private tag definitions
  • Use appropriate VRs for your data
  • Check if a standard tag already exists first

DON’T:

  • Use private tags without a creator identification
  • Assume private tags will survive transfer
  • Store PHI in private tags without proper handling
  • Use even group numbers for private data
  • Conflict with known vendor private tags

Anonymization Considerations

Private tags may contain PHI and require special handling during anonymization:

// Option 1: Remove all private tags
list.removePrivateAttributes();

// Option 2: Selectively remove known PHI-containing tags
// (requires knowledge of vendor-specific tag contents)

// Option 3: Document private tag contents in de-identification policy

Interoperability Notes

  • Private tags may be stripped during transfer
  • Some PACS/archives don't preserve private tags
  • Use standard tags when data is clinically important
  • Private tags are best for supplementary/vendor-specific data

Useful Resources

  • DICOM Innolitics - Private tag database
  • DCMTK private tag documentation
  • Grassroots DICOM wiki

Conclusion

Private tags are a powerful mechanism for storing vendor-specific data in DICOM files. When properly implemented with creator identification, they enable extending DICOM for proprietary use cases while maintaining interoperability.

Understanding private tags is essential for working with data from various scanner manufacturers and for implementing custom data storage requirements in your DICOM applications. In the next tutorial in this series, I will cover DICOM anonymization and de-identification for protecting patient privacy. See you then!