com.pixelmed.dicom
Class AttributeList

java.lang.Object
  extended by java.util.AbstractMap<K,V>
      extended by java.util.TreeMap
          extended by com.pixelmed.dicom.AttributeList
All Implemented Interfaces:
Serializable, Cloneable, Map, NavigableMap, SortedMap

public class AttributeList
extends TreeMap

The AttributeList class maintains a list of individual DICOM attributes.

Instances of the class may be used for entire composite storage SOP instances, or fragments of such instances such as meta information headers, or simply as lists of attributes to be passed to other methods (e.g. lists of attributes to add or remove from another list).

The class is actually implemented by extending java.util.TreeMap as a map of AttributeTag keys to Attribute values. Consequently, all the methods of the underlying collection are available, including adding key-value pairs and extracting values by key. Iteration through the list of key-value pairs in the map is also supported, and the iterator returns values in the ascending numerical order of the AttributeTag keys, since that is how AttributeTag implements Comparable.

Note that large attribute values such as Pixel Data may be left on disk rather than actually read in when the list is created, and loaded on demand; extreme caution should be taken if the underlying file from which an AttributeList has been read is moved or renamed; a specific method, setFileUsedByOnDiskAttributes(), is provided to address this concern.

The class provides methods for reading entire objects as a list of attributes, from files or streams. For example, the following fragment will read an entire object from the specified file and dump the contents of the attribute list:

        AttributeList list = new AttributeList();
        list.read(arg[0]);
        System.err.print(list);
 

Similarly, methods are provided for writing entire objects. For example, the previous fragment could be extended to write the list to a file unchanged as follows:

        list.write(arg[1],TransferSyntax.ExplicitVRLittleEndian,true,true);
 

Note that in general, one would want to perform significantly more cleaning up before writing an object that has just been read, and a number of such methods are provided either in this class or on related classes as illustrated in this example:

        AttributeList list = new AttributeList();
        list.read(arg[0]);
        //list.removePrivateAttributes();
        list.removeGroupLengthAttributes();
        list.removeMetaInformationHeaderAttributes();
        list.remove(TagFromName.DataSetTrailingPadding);
        list.correctDecompressedImagePixelModule();
        FileMetaInformation.addFileMetaInformation(list,TransferSyntax.ExplicitVRLittleEndian,"OURAETITLE");
        list.write(arg[1],TransferSyntax.ExplicitVRLittleEndian,true,true);
 

Note that this example is essentially the functionality of the main() method of this class, which may be used as a copying utility when invoked with input and output file arguments.

Correction of the PhotometricInterpretation and related attributes by an explicit call to the correctDecompressedImagePixelModule() method is necessary if the color space of a compressed input transfer syntax was changed during decompression (e.g., from YBR_FULL_422 for JPEG lossy to RGB), since the PixelData is always decompressed during reading by the read() method and its ilk; the call does nothing (is harmless) if the input was not compressed or not multi-component.

Individual attributes can be added or deleted as desired, either using a newly created list or one which has been read in from an existing object. For example, to zero out the patient's name one might do something like the following:

        list.replaceWithZeroLengthIfPresent(TagFromName.PatientName);
 

or to replace it with a particular value one might do the following:

        Attribute a = new PersonNameAttribute(TagFromName.PatientName);
        a.addValue(value);
        list.put(TagFromName.PatientName,a);            // one could list.remove(TagFromName.PatientName) first, but this is implicit in the put
 

A more compact shorthand method for adding new (or replacing existing) attributes (if they are in the dictionary so that the VR can be determined) is also supplied:

        list.putNewAttribute(TagFromName.PatientName);
 

and if a specific character set other than the default is in use:

        list.putNewAttribute(TagFromName.PatientName,specificCharacterSet);
 

and since this method returns the generated attribute, values can easily be added as:

        list.putNewAttribute(TagFromName.PatientName,specificCharacterSet).addValue("Blo^Joe");
 

Note also that the Attribute class provides some useful static methods for extracting and manipulating individual attributes within a list. For example:

        String patientName=Attribute.getSingleStringValueOrNull(list,TagFromName.PatientName);
 

Ideally one should take care when adding or manipulating lists of attributes to handle the specific character set correctly and consistently when there is a possibility that it may be other than the default. The previous example of replacing the patient's name could be more properly rewritten as:

        SpecificCharacterSet specificCharacterSet = new SpecificCharacterSet(Attribute.getStringValues(list,TagFromName.SpecificCharacterSet));
        Attribute a = new PersonNameAttribute(TagFromName.PatientName,specificCharacterSet);
        a.addValue(value);
        list.put(TagFromName.PatientName,a);
 

Note that in this example if the SpecificCharacterSet attribute were not found or was present but empty the various intervening methods would return null and the SpecificCharacterSet() constructor would use the default (ascii) character set.

When an attribute list is read in, the SpecificCharacterSet attribute is automatically detected and set and applied to all string attributes as they are read in and converted to the internal string form which is used by Java (Unicode).

The same applies when they are written, with some limitations on which character sets are supported. However, if new attributes have been added to the list with a different SpecificCharacterSet, it is necessary to call insertSuitableSpecificCharacterSetForAllStringValues() before writing, which will check all string values of all attributes affected by SpecificCharacterSet, choose a suitable new SpecificCharacterSet, and insert or replace the existing SpecificCharacterSet attribute. By the time that the list is written out, all of the Attributes must have the same SpecificCharacterSet.

See Also:
Attribute, AttributeTag, FileMetaInformation, SpecificCharacterSet, TagFromName, TransferSyntax, Serialized Form

Nested Class Summary
 
Nested classes/interfaces inherited from class java.util.AbstractMap
AbstractMap.SimpleEntry<K,V>, AbstractMap.SimpleImmutableEntry<K,V>
 
Field Summary
protected static DicomDictionary dictionary
           
protected  boolean pixelDataWasDecompressed
           
 
Constructor Summary
AttributeList()
           
 
Method Summary
 void correctDecompressedImagePixelModule()
          Correct the PhotometricInterpretation and Planar Configuration iff the color space if a compressed input transfer syntax was changed during decompression.
protected static void createDictionaryifNecessary()
           
 Attribute get(AttributeTag t)
          Returns the value (attribute) to which this map maps the specified key (tag).
static DicomDictionary getDictionary()
          Get the dictionary in use for this list.
 SpecificCharacterSet getSuitableSpecificCharacterSetForAllStringValues()
          Get a new SpecificCharacterSet suitable for encoding all of the values of the string attributes of a dataset.
 void insertSuitableSpecificCharacterSetForAllStringValues()
          Insert a new SpecificCharacterSet suitable for encoding all of the values of the string attributes of a dataset into the AttributeList.
 boolean isImage()
          Determine whether or not this list is an image.
 boolean isSRDocument()
          Determine whether or not this list is an SR Document.
static void main(String[] arg)
          Read the DICOM input file as a list of attributes and write it to the specified output file or dump it.
 Attribute put(Attribute a)
          Associates the specified value (attribute) with the key that is the existing tag of the attribute.
 Attribute put(AttributeTag t, Attribute a)
          Associates the specified value (attribute) with the specified key (tag).
 Object put(Object key, Object value)
          Associates the specified value (attribute) with the specified key (tag).
 Attribute putNewAttribute(AttributeTag t)
          Create a new attribute with the specified tag and insert it in the map associating the generated attribute with the specified tag as the key.
 Attribute putNewAttribute(AttributeTag t, SpecificCharacterSet specificCharacterSet)
          Create a new attribute with the specified tag and insert it in the map associating the generated attribute with the specified tag as the key.
 void read(DicomInputStream i)
          Read all the DICOM attributes in the stream until there are no more.
 void read(DicomInputStream i, AttributeTag tag)
          Read all the DICOM attributes in the stream until the specified tag is encountered.
 void read(String name)
          Read an entire DICOM object in the specified file.
 void read(String name, String transferSyntaxUID, boolean hasMeta, boolean useBufferedStream)
          Read an entire DICOM object in the specified file.
 void readOnlyMetaInformationHeader(DicomInputStream i)
          Read the meta information header (if present) and then stop.
 Attribute remove(AttributeTag tag)
          Removes the mapping for this key (tag), if present.
 void removeGroupLengthAttributes()
          Remove any group length attributes present in the list, except the meta information header length, as well as LengthToEnd.
 void removeMetaInformationHeaderAttributes()
          Remove any meta information header attributes present in the list.
 void removePrivateAttributes()
          Remove any private attributes present in the list.
 void replaceWithZeroLengthIfPresent(AttributeTag tag)
          Replaces an attribute with a zero length attribute, if present in the list.
 void setFileUsedByOnDiskAttributes(File file)
          Change the file containing the data used by any attribute whose values are left on disk, for example if the file has been renamed.
 void setSpecificCharacterSet(SpecificCharacterSet specificCharacterSet)
          Set the SpecificCharacterSet suitable for all of the string attributes of a dataset in an AttributeList.
 String toString()
          Dump the contents of the attribute list as a human-readable string.
 String toString(DicomDictionary dictionary)
          Dump the contents of the attribute list as a human-readable string.
 void write(DicomOutputStream dout)
          Write the entire attribute list to the specified stream.
 void write(DicomOutputStream dout, boolean useMeta)
          Write the entire attribute list to the specified stream.
 void write(File file)
          Write the entire attribute list to the specified file in explicit VR little endian transfer syntax with a meta information header.
 void write(File file, String transferSyntaxUID, boolean useMeta, boolean useBufferedStream)
          Write the entire attribute list to the specified file.
 void write(OutputStream o, String transferSyntaxUID, boolean useMeta, boolean useBufferedStream)
          Write the entire attribute list to the specified stream.
 void write(OutputStream o, String transferSyntaxUID, boolean useMeta, boolean useBufferedStream, boolean closeAfterWrite)
          Write the entire attribute list to the specified stream.
 void write(String name)
          Write the entire attribute list to the named file in explicit VR little endian transfer syntax with a meta information header.
 void write(String name, String transferSyntaxUID, boolean useMeta, boolean useBufferedStream)
          Write the entire attribute list to the named file.
protected  void writeFragment(DicomOutputStream dout)
          Write the entire attribute list (which may be part of a larger enclosing dataset) to the specified stream.
 
Methods inherited from class java.util.TreeMap
ceilingEntry, ceilingKey, clear, clone, comparator, containsKey, containsValue, descendingKeySet, descendingMap, entrySet, firstEntry, firstKey, floorEntry, floorKey, get, headMap, headMap, higherEntry, higherKey, keySet, lastEntry, lastKey, lowerEntry, lowerKey, navigableKeySet, pollFirstEntry, pollLastEntry, putAll, remove, size, subMap, subMap, tailMap, tailMap, values
 
Methods inherited from class java.util.AbstractMap
equals, hashCode, isEmpty
 
Methods inherited from class java.lang.Object
finalize, getClass, notify, notifyAll, wait, wait, wait
 
Methods inherited from interface java.util.Map
equals, hashCode, isEmpty
 

Field Detail

dictionary

protected static DicomDictionary dictionary

pixelDataWasDecompressed

protected boolean pixelDataWasDecompressed
Constructor Detail

AttributeList

public AttributeList()
Method Detail

createDictionaryifNecessary

protected static void createDictionaryifNecessary()

readOnlyMetaInformationHeader

public void readOnlyMetaInformationHeader(DicomInputStream i)
                                   throws IOException,
                                          DicomException

Read the meta information header (if present) and then stop.

Leaves the stream opened and positioned at the start of the data set.

Parameters:
i - the stream to read from
Throws:
IOException
DicomException

read

public void read(DicomInputStream i,
                 AttributeTag tag)
          throws IOException,
                 DicomException

Read all the DICOM attributes in the stream until the specified tag is encountered.

Does not read beyond the group element pair of the specified stop tag.

Leaves the stream open.

Parameters:
i - the stream to read from
tag - the tag (in the top level data set) at which to stop
Throws:
IOException
DicomException

read

public void read(DicomInputStream i)
          throws IOException,
                 DicomException

Read all the DICOM attributes in the stream until there are no more.

Leaves the stream open.

Parameters:
i - the stream to read from
Throws:
IOException
DicomException

read

public void read(String name,
                 String transferSyntaxUID,
                 boolean hasMeta,
                 boolean useBufferedStream)
          throws IOException,
                 DicomException

Read an entire DICOM object in the specified file.

Returns the attributes of both the meta information header (if present) and data set.

Parameters:
name - the input file name
transferSyntaxUID - the transfer syntax to use for the data set (leave null for autodetection)
hasMeta - look for a meta information header
useBufferedStream - buffer the input for better performance
Throws:
IOException
DicomException

read

public void read(String name)
          throws IOException,
                 DicomException

Read an entire DICOM object in the specified file.

Returns the attributes of both the meta information header (if present) and data set.

Always tries to automatically detect the meta information header or transfer syntax if no meta information header and buffers the input for better performance.

Parameters:
name - the input file name
Throws:
IOException
DicomException

writeFragment

protected void writeFragment(DicomOutputStream dout)
                      throws IOException,
                             DicomException

Write the entire attribute list (which may be part of a larger enclosing dataset) to the specified stream.

Does not close the output stream, assumes any meta header vs. dataset ransition has occurred and further assumes that any additional codecs (like deflate) have already been pushed onto the stream.

Intended for use only for write datasets that are within sequence items (hence is not public).

Parameters:
dout - the stream to write to
Throws:
IOException
DicomException

write

public void write(DicomOutputStream dout,
                  boolean useMeta)
           throws IOException,
                  DicomException

Write the entire attribute list to the specified stream.

Leaves the stream open.

Parameters:
dout - the stream to write to
useMeta - true if the meta information header attributes are to be written, false if they are to be ommitted
Throws:
IOException
DicomException

write

public void write(DicomOutputStream dout)
           throws IOException,
                  DicomException

Write the entire attribute list to the specified stream.

Leaves the stream open.

Parameters:
dout - the stream to write to
Throws:
IOException
DicomException

write

public void write(OutputStream o,
                  String transferSyntaxUID,
                  boolean useMeta,
                  boolean useBufferedStream)
           throws IOException,
                  DicomException

Write the entire attribute list to the specified stream.

Closes the stream after writing.

Parameters:
o - the stream to write to
transferSyntaxUID - the transfer syntax to use to write the data set
useMeta - write the meta information header attributes (if true they must be present in the list with appropriate values already)
useBufferedStream - buffer the output for better performance (set this true only if the supplied stream is not already buffered)
Throws:
IOException
DicomException

write

public void write(OutputStream o,
                  String transferSyntaxUID,
                  boolean useMeta,
                  boolean useBufferedStream,
                  boolean closeAfterWrite)
           throws IOException,
                  DicomException

Write the entire attribute list to the specified stream.

Parameters:
o - the stream to write to
transferSyntaxUID - the transfer syntax to use to write the data set
useMeta - write the meta information header attributes (if true they must be present in the list with appropriate values already)
useBufferedStream - buffer the output for better performance (set this true only if the supplied stream is not already buffered)
closeAfterWrite - requests that the supplied stream be closed after writing
Throws:
IOException
DicomException

write

public void write(String name,
                  String transferSyntaxUID,
                  boolean useMeta,
                  boolean useBufferedStream)
           throws IOException,
                  DicomException

Write the entire attribute list to the named file.

Parameters:
name - the file name to write to
transferSyntaxUID - the transfer syntax to use to write the data set
useMeta - write the meta information header attributes (if true they must be present in the list with appropriate values already)
useBufferedStream - buffer the output for better performance
Throws:
IOException
DicomException

write

public void write(String name)
           throws IOException,
                  DicomException

Write the entire attribute list to the named file in explicit VR little endian transfer syntax with a meta information header.

Parameters:
name - the file name to write to
Throws:
IOException
DicomException

write

public void write(File file,
                  String transferSyntaxUID,
                  boolean useMeta,
                  boolean useBufferedStream)
           throws IOException,
                  DicomException

Write the entire attribute list to the specified file.

Parameters:
file - the file to write to
transferSyntaxUID - the transfer syntax to use to write the data set
useMeta - write the meta information header attributes (if true they must be present in the list with appropriate values already)
useBufferedStream - buffer the output for better performance
Throws:
IOException
DicomException

write

public void write(File file)
           throws IOException,
                  DicomException

Write the entire attribute list to the specified file in explicit VR little endian transfer syntax with a meta information header.

Parameters:
file - the file to write to
Throws:
IOException
DicomException

put

public Object put(Object key,
                  Object value)

Associates the specified value (attribute) with the specified key (tag).

If the map previously contained a mapping for this key, the old value is replaced.

This untyped method is present to over ride the super class method to be sure that null values are ever inserted.

Specified by:
put in interface Map
Overrides:
put in class TreeMap
Parameters:
key - key (tag) with which the specified value (attribute) is to be associated
value - value (attribute) to be associated with the specified key (tag)
Returns:
previous value associated with specified key, or null if there was no mapping for key
Throws:
NullPointerException - thrown if a or t is null

put

public Attribute put(AttributeTag t,
                     Attribute a)

Associates the specified value (attribute) with the specified key (tag).

If the map previously contained a mapping for this key, the old value is replaced.

Parameters:
t - key (tag) with which the specified value (attribute) is to be associated
a - value (attribute) to be associated with the specified key (tag)
Returns:
previous value (attribute) associated with specified key (tag), or null if there was no mapping for key (tag)
Throws:
NullPointerException - thrown if a or t is null
See Also:
TreeMap.put(Object,Object)

put

public Attribute put(Attribute a)

Associates the specified value (attribute) with the key that is the existing tag of the attribute.

If the map previously contained a mapping for this key, the old value is replaced.

Parameters:
a - value (attribute) to be associated with the specified key (tag)
Returns:
previous value (attribute) associated with specified key (tag), or null if there was no mapping for key (tag)
Throws:
NullPointerException - thrown if a or t is null
See Also:
put(AttributeTag,Attribute)

get

public Attribute get(AttributeTag t)

Returns the value (attribute) to which this map maps the specified key (tag).

Returns null if the map contains no mapping for this key. A return value of null does indicate that the map contains no mapping for the key, unlike java.util.get(Object) since the put operation checks for and disallows null insertions. This contract will hold true unless one goes to great effort to insert a key that maps to a null value by using one of the other insertion methods of the super class, in which case other operations (like writing) may fail later with a NullPointerException.

Parameters:
t - key (tag) whose associated value (attribute) is to be returned

isImage

public boolean isImage()

Determine whether or not this list is an image.

An image is defined to be something with a PixelData attribute at the top level.

Returns:
true if an image

isSRDocument

public boolean isSRDocument()

Determine whether or not this list is an SR Document.

An SR Document is defined to be something with a ContentSequence attribute at the top level.

Returns:
true if an SR Document
See Also:
SOPClass.isStructuredReport(String)

getDictionary

public static DicomDictionary getDictionary()

Get the dictionary in use for this list.

Creates one if necessary.

Returns:
the dictionary

remove

public Attribute remove(AttributeTag tag)

Removes the mapping for this key (tag), if present.

Parameters:
tag - key (tag) for which mapping should be removed
Returns:
previous value (attribute) associated with specified key (tag), or null if there was no mapping for key (tag)

replaceWithZeroLengthIfPresent

public void replaceWithZeroLengthIfPresent(AttributeTag tag)
                                    throws DicomException

Replaces an attribute with a zero length attribute, if present in the list.

Does nothing if the attribute was not already present.

Parameters:
tag - key (tag) for which the attribute should be replaced
Throws:
DicomException - thrown if there is any difficulty creating the new zero length attribute

removePrivateAttributes

public void removePrivateAttributes()

Remove any private attributes present in the list.

Private attributes are all those with an odd group number.


removeMetaInformationHeaderAttributes

public void removeMetaInformationHeaderAttributes()

Remove any meta information header attributes present in the list.

Meta information header attributes are all those in group 0x0002.

Note that this should always be done when modifying the SOP Class or Instance UID of an attribute list what has been read before writing, since it is vital that the corresponding meta information header attributes match those in the data set.

See Also:
FileMetaInformation

removeGroupLengthAttributes

public void removeGroupLengthAttributes()

Remove any group length attributes present in the list, except the meta information header length, as well as LengthToEnd.

Group length attributes are all those with an element of 0x0000.

LengthToEnd (0x0008,0x0001) is always removed if present as well.

These have never been required in DICOM and are a holdover from the old ACR-NEMA days, and are a source of constant problems, so should always be removed.

The meta information header length is left alone, since it is mandatory.

Also recurses into sequences and removes any contained group lengths.

See Also:
FileMetaInformation

toString

public String toString()

Dump the contents of the attribute list as a human-readable string.

Each attribute is written to a separate line, in the form defined for com.pixelmed.dicom.Attribute.toString().

Overrides:
toString in class AbstractMap
Returns:
the string

toString

public String toString(DicomDictionary dictionary)

Dump the contents of the attribute list as a human-readable string.

Each attribute is written to a separate line, in the form defined for com.pixelmed.dicom.Attribute.toString(DicomDictionary dictionary).

Parameters:
dictionary - the dictionary to use to look up the name
Returns:
the string

setFileUsedByOnDiskAttributes

public void setFileUsedByOnDiskAttributes(File file)

Change the file containing the data used by any attribute whose values are left on disk, for example if the file has been renamed.

Parameters:
file - the new file containing the data

putNewAttribute

public Attribute putNewAttribute(AttributeTag t,
                                 SpecificCharacterSet specificCharacterSet)
                          throws DicomException

Create a new attribute with the specified tag and insert it in the map associating the generated attribute with the specified tag as the key.

If the map previously contained a mapping for the tag (key), the old value is replaced.

Parameters:
t - key (AttributeTag tag) with which the generated attribute is to be associated
specificCharacterSet - the SpecificCharacterSet to be used text values
Returns:
the newly created attribute
Throws:
DicomException - if cannot create attribute, such as if cannot find tag in dictionary

putNewAttribute

public Attribute putNewAttribute(AttributeTag t)
                          throws DicomException

Create a new attribute with the specified tag and insert it in the map associating the generated attribute with the specified tag as the key.

If the map previously contained a mapping for the tag (key), the old value is replaced.

Parameters:
t - key (AttributeTag tag) with which the generated attribute is to be associated
Returns:
the newly created attribute
Throws:
DicomException - if cannot create attribute, such as if cannot find tag in dictionary

setSpecificCharacterSet

public void setSpecificCharacterSet(SpecificCharacterSet specificCharacterSet)

Set the SpecificCharacterSet suitable for all of the string attributes of a dataset in an AttributeList.

Any existing SpecificCharacterSet for Attributes (whether read or created de novo) is replaced.

Recurses into SequenceAttributes.


getSuitableSpecificCharacterSetForAllStringValues

public SpecificCharacterSet getSuitableSpecificCharacterSetForAllStringValues()

Get a new SpecificCharacterSet suitable for encoding all of the values of the string attributes of a dataset.

Any existing SpecificCharacterSet within the AttributeList or any SpecificCharacterSet established for specific Attributes (e.g., when read or created de novo) is ignored.

Only a single value is ever used (i.e., ISO 2022 escapes are not created).

Returns:
a new SpecificCharacterSet sufficient to encode all values

insertSuitableSpecificCharacterSetForAllStringValues

public void insertSuitableSpecificCharacterSetForAllStringValues()
                                                          throws DicomException

Insert a new SpecificCharacterSet suitable for encoding all of the values of the string attributes of a dataset into the AttributeList.

Any existing SpecificCharacterSet within the AttributeList or any SpecificCharacterSet established for specific Attributes (e.g., when read or created de novo) is ignored.

Only a single value is ever used (i.e., ISO 2022 escapes are not created).

Throws:
DicomException - if cannot create attribute

correctDecompressedImagePixelModule

public void correctDecompressedImagePixelModule()
                                         throws DicomException

Correct the PhotometricInterpretation and Planar Configuration iff the color space if a compressed input transfer syntax was changed during decompression.

E.g., from YBR_FULL_422 for JPEG lossy to RGB.

Does nothing (is harmless) if the input was not compressed or not multi-component.

Recurses into sequences in case there is icon pixel data that was also decompressed.

Throws:
DicomException - if cannot create replacement attribute

main

public static void main(String[] arg)

Read the DICOM input file as a list of attributes and write it to the specified output file or dump it.

When copying, removes any group lengths and creates a new meta information header.

Parameters:
arg - array of one string (the filename to read and dump), two strings (the filename to read and the filename to write), three strings (the filename to read, the transfer syntax to write, the filename to write), or four strings (the transfer syntax to read (must be zero length if metaheader present), the filename to read, the transfer syntax to write, the filename to write) five strings (the transfer syntax to read (must be zero length if metaheader present), the filename to read, the transfer syntax to write, the filename to write, and whether or not to write a metaheader)