DICOM Basics using .NET and C# - Character Set Handling

Introduction

This is part of my series of articles on the DICOM standard. In this tutorial, we'll explore how DICOM handles international character sets for patient names, institution names, and other text data. Proper character set handling is essential for healthcare systems operating in multilingual environments.

DICOM defines specific mechanisms for encoding text in various character sets, from basic ASCII to full Unicode support via UTF-8. Understanding these mechanisms ensures that patient demographic data is correctly displayed and preserved across different systems and locales.

Prerequisites

Before you begin, ensure you have the following:

  • A .NET development environment (Visual Studio or Visual Studio Code)
  • The Fellow Oak DICOM library (fo-dicom) installed via NuGet
  • Basic understanding of DICOM concepts from previous tutorials
  • You can find all the code demonstrated in this tutorial on GitHub here

“Language is the road map of a culture. It tells you where its people come from and where they are going.” ~ Rita Mae Brown

The Theory Behind Character Set Handling

Character encoding is fundamentally about mapping human writing systems to numbers that computers can store and transmit. The challenge is that there are thousands of characters across hundreds of scripts worldwide. Early computing assumed ASCII (128 characters sufficient for English) would be enough. DICOM, as a global standard for healthcare, must handle patient names in any language.

The evolution from code pages to Unicode reflects computing history. ISO 8859 series created separate 256-character sets for different language groups (Latin-1 for Western European, ISO 8859-5 for Cyrillic, etc.). This worked for monolingual systems but failed when a German hospital needed to store a Chinese patient's name. Unicode solved this by creating one universal character set with over 140,000 characters covering virtually all writing systems.

UTF-8's design is elegant: it encodes ASCII characters in one byte (identical to ASCII), uses 2-4 bytes for other characters, and is self-synchronizing (you can find character boundaries by examining any byte). This backward compatibility with ASCII and efficiency for Western text made it the dominant encoding on the web and the recommended choice for DICOM (ISO_IR 192).

The code extension mechanism (ISO 2022) predates Unicode and allows switching between character sets within a single string using escape sequences. This was necessary for Japanese, which uses multiple scripts: kanji (ideographs), hiragana, katakana, and romaji. While complex, it enabled internationalization before Unicode was widely supported. Legacy systems may still use this approach.

The Person Name representation with three component groups (Alphabetic, Ideographic, Phonetic) addresses a specific need in Asian contexts. A Japanese name might be written in kanji (ideographic), have a pronunciation guide in hiragana (phonetic), and a romanization for Western systems (alphabetic). DICOM's structure preserves all three representations, enabling display appropriate to context.

Understanding DICOM Character Sets

DICOM uses the Specific Character Set attribute (0008,0005) to indicate how text data is encoded within a dataset. The key concepts include:

  • Default Character Set: ASCII (ISO 646) when Specific Character Set is absent
  • Single-Byte Sets: ISO 8859 series for European languages
  • Multi-Byte Sets: UTF-8 for Unicode, GB18030 for Chinese
  • Code Extension: ISO 2022 for Asian languages with multiple scripts

Character Set Reference

Here are the commonly used character sets in DICOM:

Character SetCodeUse Case
ASCII(empty)Default, basic Latin characters
ISO 8859-1 (Latin-1)ISO_IR 100Western European (French, German, Spanish)
ISO 8859-2 (Latin-2)ISO_IR 101Central European (Polish, Czech)
ISO 8859-5ISO_IR 144Cyrillic (Russian)
ISO 8859-6ISO_IR 127Arabic
ISO 8859-7ISO_IR 126Greek
ISO 8859-8ISO_IR 138Hebrew
UTF-8ISO_IR 192Unicode (RECOMMENDED)
GB18030GB18030Chinese

Step 1 of 4: Default ASCII Character Set

When no Specific Character Set is specified, DICOM defaults to ASCII. This limits text to basic Latin characters:

using System;
using System.Diagnostics;
using FellowOakDicom;

namespace DicomCharacterSetHandling
{
    public class Program
    {
        public static void Main(string[] args)
        {
            try
            {
                LogToDebugConsole("=== DICOM Character Set Handling Demo ===");
                LogToDebugConsole("");

                // Demo 1: Default ASCII character set
                DemonstrateDefaultCharacterSet();

                // Demo 2: Latin-1 for Western European
                DemonstrateLatin1CharacterSet();

                // Demo 3: UTF-8 Unicode
                DemonstrateUtf8CharacterSet();

                // Demo 4: Japanese character set
                DemonstrateJapaneseCharacterSet();
            }
            catch (Exception e)
            {
                LogToDebugConsole($"Error: {e.Message}");
            }
        }

        /// <summary>
        /// Default ASCII character set - no Specific Character Set specified
        /// </summary>
        private static void DemonstrateDefaultCharacterSet()
        {
            LogToDebugConsole("--- Demo 1: Default (ASCII) ---");

            var dataset = new DicomDataset();

            // No Specific Character Set - defaults to ASCII
            // Only basic Latin characters allowed: A-Z, a-z, 0-9, basic punctuation
            dataset.Add(DicomTag.PatientName, "Doe^John");
            dataset.Add(DicomTag.InstitutionName, "General Hospital");

            LogToDebugConsole("Patient Name: Doe^John");
            LogToDebugConsole("Institution: General Hospital");
            LogToDebugConsole("Specific Character Set: (not specified - ASCII default)");
            LogToDebugConsole("Supported characters: A-Z, a-z, 0-9, basic punctuation");
        }

        private static void LogToDebugConsole(string message)
        {
            Debug.WriteLine(message);
        }
    }
}

Step 2 of 4: ISO 8859-1 (Latin-1) for Western European Languages

For Western European languages with accented characters, use ISO 8859-1 (ISO_IR 100):

/// <summary>
/// ISO 8859-1 (Latin-1) for Western European languages
/// </summary>
private static void DemonstrateLatin1CharacterSet()
{
    LogToDebugConsole("");
    LogToDebugConsole("--- Demo 2: ISO 8859-1 (Latin-1) ---");

    var dataset = new DicomDataset();

    // Set ISO 8859-1 (Latin-1) character set
    dataset.Add(DicomTag.SpecificCharacterSet, "ISO_IR 100");

    // Now we can use accented characters
    // French: François, German: Müller, Spanish: José
    dataset.Add(DicomTag.PatientName, "Müller^François");
    dataset.Add(DicomTag.InstitutionName, "Hôpital Général de Zürich");

    LogToDebugConsole("Patient Name: Müller^François");
    LogToDebugConsole("Institution: Hôpital Général de Zürich");
    LogToDebugConsole("Specific Character Set: ISO_IR 100 (ISO 8859-1, Latin-1)");
    LogToDebugConsole("Supports: Western European languages (French, German, Spanish, etc.)");
}

UTF-8 (ISO_IR 192) is the recommended character set for new implementations. It supports all Unicode characters, including Asian scripts:

/// <summary>
/// UTF-8 Unicode - recommended for new implementations
/// </summary>
private static void DemonstrateUtf8CharacterSet()
{
    LogToDebugConsole("");
    LogToDebugConsole("--- Demo 3: UTF-8 (Unicode) ---");

    var dataset = new DicomDataset();

    // Set UTF-8 character set - supports all Unicode characters
    dataset.Add(DicomTag.SpecificCharacterSet, "ISO_IR 192");

    // UTF-8 supports all scripts
    // Chinese: 王小明, Japanese: 山田太郎, Korean: 김철수
    // Arabic: محمد أحمد, Russian: Иван Петров, Greek: Νίκος Παπαδόπουλος

    LogToDebugConsole("Examples of names in different scripts:");
    LogToDebugConsole("");
    LogToDebugConsole("  Chinese:  王小明 (Wang Xiaoming)");
    LogToDebugConsole("  Japanese: 山田太郎 (Yamada Taro)");
    LogToDebugConsole("  Korean:   김철수 (Kim Cheolsu)");
    LogToDebugConsole("  Arabic:   محمد أحمد (Muhammad Ahmad)");
    LogToDebugConsole("  Russian:  Иван Петров (Ivan Petrov)");
    LogToDebugConsole("  Greek:    Νίκος Παπαδόπουλος (Nikos Papadopoulos)");
    LogToDebugConsole("");
    LogToDebugConsole("Specific Character Set: ISO_IR 192 (UTF-8)");
    LogToDebugConsole("Supports: All Unicode characters - RECOMMENDED for new implementations");
}

Step 4 of 4: Japanese and Code Extension Character Sets

Asian languages like Japanese require special handling with multiple character set components for different scripts (alphabetic, ideographic, phonetic):

/// <summary>
/// Japanese character set with code extensions
/// </summary>
private static void DemonstrateJapaneseCharacterSet()
{
    LogToDebugConsole("");
    LogToDebugConsole("--- Demo 4: Japanese ---");

    var dataset = new DicomDataset();

    // Japanese requires multiple character sets with code extensions
    // The backslash indicates code extension for additional components
    dataset.Add(DicomTag.SpecificCharacterSet, @"\ISO 2022 IR 87");

    LogToDebugConsole("Japanese names use three components:");
    LogToDebugConsole("  Alphabetic:  Yamada^Taro (Romaji)");
    LogToDebugConsole("  Ideographic: 山田^太郎 (Kanji characters)");
    LogToDebugConsole("  Phonetic:    やまだ^たろう (Hiragana characters)");
    LogToDebugConsole("");
    LogToDebugConsole("Person Name format with components:");
    LogToDebugConsole("  Alphabetic=Ideographic=Phonetic");
    LogToDebugConsole("  Yamada^Taro=山田^太郎=やまだ^たろう");
    LogToDebugConsole("");
    LogToDebugConsole(@"Specific Character Set: \ISO 2022 IR 87");
    LogToDebugConsole("Note: Backslash indicates code extension for additional components");
}

Person Name Components in DICOM

DICOM Person Names can have up to three component groups, especially useful for Asian names:

ComponentDescriptionExample
AlphabeticSingle-byte charactersYamada^Taro
IdeographicIdeographic characters山田^太郎
PhoneticPhonetic representationやまだ^たろう

Within each component group, the name is further divided:

Family^Given^Middle^Prefix^Suffix

The complete format for multilingual names:

Alphabetic=Ideographic=Phonetic

Best Practices for Character Set Handling

  • Use UTF-8 (ISO_IR 192): Recommended for all new implementations
  • Always Specify Character Set: Don't rely on defaults
  • Test with International Data: Verify correct display of accented and non-Latin characters
  • Handle Encoding Errors: Gracefully handle malformed character data
  • Consider Legacy Systems: Some older systems may not support UTF-8

Code Extension Character Sets Reference

For systems using ISO 2022 code extensions:

Character SetCodeLanguage/Script
JIS X 0201ISO 2022 IR 13Japanese Katakana
JIS X 0208ISO 2022 IR 87Japanese Kanji
JIS X 0212ISO 2022 IR 159Japanese Supplementary
KS X 1001ISO 2022 IR 149Korean
GB 2312ISO 2022 IR 58Chinese Simplified

Conclusion

Proper character set handling is essential for healthcare systems that serve diverse patient populations. DICOM provides comprehensive support for international character sets, from basic ASCII to full Unicode via UTF-8.

For new implementations, UTF-8 (ISO_IR 192) is strongly recommended as it supports all Unicode characters and simplifies internationalization. However, when integrating with legacy systems, understanding the various ISO 8859 and ISO 2022 character sets remains important for proper data exchange and display.

Please check out the next tutorial in this series where we cover DICOM private tags.