Wednesday, December 25, 2013


                                      (Draft - work in progress)

This page we will discuss how DICOM stores a Person’s Name. Later we will discuss specific character sets, ASCII, Unicode, UTF etc.

What is so special about Name? Well!
  1. Name usually contains many components like family name, middle name , given name , suffix , prefix 
  2. Most complex part is the language (characters set) you use to write name. Since memory size to store characters are variable
  3. Further internationalization issues arise in countries where the language has a phonetic or ideographic representation, such as in Japan and Korea. For these situations, DICOM allows up to three “component groups,” the first a single-byte representation as is used for western languages, then an ideographic (Kanji or Hanga) representation and then a phonetic representation (Hiragana or Hangul). These are separated by ‘=’ (0x3d) characters. ISO 2022 escape sequences (code extension techniques) may be used to change character sets, depending on the choices specified in the Specific Character Set attribute.Each of the component groups is limited to 64 characters. A typical Japanese PNAME looks like this: Miyamoto^Musashi= 宮本 ^ 武蔵 = みやもと ^ むさし


Algorithm to read DICOM Patient Name(Thanks to DCMTK):




// Comment
bool getNameComponentsFromString(const std::string &dicomName,
                                                       std::string &lastName,
                                                       std::string &firstName,
                                                       std::string &middleName,
                                                       std::string &namePrefix,
                                                       std::string &nameSuffix,
                                                       const unsigned int componentGroup)
{
    
    /* initialize all name components */
    lastName.clear();
    firstName.clear();
    middleName.clear();
    namePrefix.clear();
    nameSuffix.clear();
    if (dicomName.length() > 0)
    {
    /* Excerpt from DICOM part 5:
           "For the purpose of writing names in ideographic characters and in
            phonetic characters, up to 3 groups of components may be used."
        */
        if (componentGroup < 3)
        {
            std::string name;
            // find component group (0..2)
            const size_t posA = dicomName.find('=');
   if (posA != std::string::npos)
            {
                if (componentGroup > 0)
                {
                    const size_t posB = dicomName.find('=', posA + 1);
                    if (posB !=std::string::npos)
                    {
                        if (componentGroup == 1)
                            name = dicomName.substr(posA + 1, posB - posA - 1);
                        else /* componentGroup == 2 */
                            name = dicomName.substr(posB + 1);
                    } else if (componentGroup == 1)
                        name = dicomName.substr(posA + 1);
                } else /* componentGroup == 0 */
                    name = dicomName.substr(0, posA);
            } else if (componentGroup == 0)
                name = dicomName;
            /* check whether component group is valid (= non-empty) */
            if (name.length() > 0)
            {
                /* find caret separators */
                /* (tbd: add more sophisticated heuristics for comma and space separated names) */
                const size_t pos1 = name.find('^');
                if (pos1 != std::string::npos)
                {
                    const size_t pos2 = name.find('^', pos1 + 1);
                    lastName = name.substr(0, pos1);
                    if (pos2 != std::string::npos)
                    {
                        const size_t pos3 = name.find('^', pos2 + 1);
                        firstName = name.substr(pos1 + 1, pos2 - pos1 - 1);
                        if (pos3 != std::string::npos)
                        {
                            const size_t pos4 = name.find('^', pos3 + 1);
                            middleName = name.substr(pos2 + 1, pos3 - pos2 - 1);
                            if (pos4 != std::string::npos)
                            {
                                namePrefix = name.substr(pos3 + 1, pos4 - pos3 - 1);
                                nameSuffix = name.substr(pos4 + 1);
                            } else
                                namePrefix = name.substr(pos3 + 1);
                        } else
                            middleName = name.substr(pos2 + 1);
                    } else
                        firstName = name.substr(pos1 + 1);
                } else
                    lastName = name;
            }
        } else
           return false;
    }
    return true;
}