Logo Search packages:      
Sourcecode: pixelmed version File versions  Download package

ClinicalTrialsAttributes.java

/* Copyright (c) 2001-2009, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */

package com.pixelmed.dicom;

import java.util.*;

/**
 * <p>An abstract class of static methods to support removing identifying attributes and adding
 * Clinical Trials Patient, Study and Series Modules attributes.</p>
 *
 * <p>UID attributes are handled specially, in that they may be kept, removed or remapped. Remapping
 * means that any UID that is not standard (e.g., not a SOP Class, etc.) will be replaced consistently
 * with another generated UID, such that when that UID is encountered again, the same replacement
 * value will be used. The replacement mapping persists within the invocation of the JVM until it is explciitly
 * flushed. A different JVM invocation will replace the UIDs with different values. Therefore, multiple
 * instances that need to be remapped consistently must be cleaned within the same invocation.</p>
 *
 * <p>Note that this map could grow quite large and consumes resources in memory, and hence in a server
 * application should be flushed at appropriate intervals using the appropriate method.</p>
 *
 * @author  dclunie
 */
00023 abstract public class ClinicalTrialsAttributes {

      /***/
      private static final String identString = "@(#) $Header: /userland/cvs/pixelmed/imgbook/com/pixelmed/dicom/ClinicalTrialsAttributes.java,v 1.35 2009/04/29 20:53:09 dclunie Exp $";
      
      protected static final String defaultValueForMissingNonZeroLengthStrings = "NONE";
      protected static final String defaultValueForMissingPossiblyZeroLengthStrings = "";
      
      protected static Map mapOfOriginalToReplacementUIDs = null;
      protected static UIDGenerator uidGenerator = null;    

      private ClinicalTrialsAttributes() {};
      
      protected static void addType1LongStringAttribute(AttributeList list,AttributeTag t,String value,SpecificCharacterSet specificCharacterSet) throws DicomException {
            if (value == null || value.length() == 0) {
                  value=defaultValueForMissingNonZeroLengthStrings;
            }
            Attribute a = new LongStringAttribute(t,specificCharacterSet);
            a.addValue(value);
            list.put(t,a);
      }

      protected static void addType2LongStringAttribute(AttributeList list,AttributeTag t,String value,SpecificCharacterSet specificCharacterSet) throws DicomException {
            if (value == null) {
                  value=defaultValueForMissingPossiblyZeroLengthStrings;
            }
            Attribute a = new LongStringAttribute(t,specificCharacterSet);
            a.addValue(value);
            list.put(t,a);
      }

      protected static void addType3ShortTextAttribute(AttributeList list,AttributeTag t,String value,SpecificCharacterSet specificCharacterSet) throws DicomException {
            if (value != null) {
                  Attribute a = new ShortTextAttribute(t,specificCharacterSet);
                  a.addValue(value);
                  list.put(t,a);
            }
      }

      protected static void addType3ShortStringAttribute(AttributeList list,AttributeTag t,String value,SpecificCharacterSet specificCharacterSet) throws DicomException {
            if (value != null) {
                  Attribute a = new ShortStringAttribute(t,specificCharacterSet);
                  a.addValue(value);
                  list.put(t,a);
            }
      }

      protected static void addType3LongStringAttribute(AttributeList list,AttributeTag t,String value,SpecificCharacterSet specificCharacterSet) throws DicomException {
            if (value != null) {
                  Attribute a = new LongStringAttribute(t,specificCharacterSet);
                  a.addValue(value);
                  list.put(t,a);
            }
      }

      protected static void addType3DateTimeAttribute(AttributeList list,AttributeTag t,String value) throws DicomException {
            if (value != null) {
                  Attribute a = new DateTimeAttribute(t);
                  a.addValue(value);
                  list.put(t,a);
            }
      }

      /**
       * <p>Add the attributes of the Contributing Equipment Sequence to a list of attributes.</p>
       *
       * <p>Attributes are added if supplied string value are added if not null. May be zero length.</p>
       *
       * <p>Retains any existing items in Contributing Equipment Sequence.</p>
       *
       * <p>Uses <code>("109104","DCM","De-identifying Equipment")</code> for the Purpose of Reference.</p>
       *
       * <p>Uses <code>"Deidentified"</code> for the Contribution Description.</p>
       *
       * <p>Uses the current date and time for the Contribution DateTime.</p>
       *
       * @param   list                                      the list of attributes to which to add the Contributing Equipment Sequence
       * @param   manufacturer
       * @param   institutionName
       * @param   institutionalDepartmentName
       * @param   institutionAddress
       * @param   stationName
       * @param   manufacturerModelName
       * @param   deviceSerialNumber
       * @param   softwareVersion
       * @throws  DicomException
       */
00110       public static void addContributingEquipmentSequence(AttributeList list,
                  String manufacturer,
                  String institutionName,
                  String institutionalDepartmentName,
                  String institutionAddress,
                  String stationName,
                  String manufacturerModelName,
                  String deviceSerialNumber,
                  String softwareVersion) throws DicomException {
            addContributingEquipmentSequence(list,true,new CodedSequenceItem("109104","DCM","De-identifying Equipment"),      // per CP 892
                  manufacturer,institutionName,institutionalDepartmentName,institutionAddress,stationName,manufacturerModelName,deviceSerialNumber,softwareVersion,
                  "Deidentified",DateTimeAttribute.getFormattedString(new java.util.Date()));
      }

      /**
       * <p>Add the attributes of the Contributing Equipment Sequence to a list of attributes.</p>
       *
       * <p>Attributes are added if supplied string value are added if not null. May be zero length.</p>
       *
       * @param   list                                      the list of attributes to which to add the Contributing Equipment Sequence
       * @param   retainExistingItems                       if true, retain any existing items in Contributing Equipment Sequence, otherwise remove them
       * @param   purposeOfReferenceCodeSequence
       * @param   manufacturer
       * @param   institutionName
       * @param   institutionalDepartmentName
       * @param   institutionAddress
       * @param   stationName
       * @param   manufacturerModelName
       * @param   deviceSerialNumber
       * @param   softwareVersion
       * @param   contributionDescription
       * @param   contributionDateTime
       * @throws  DicomException
       */
00144       public static void addContributingEquipmentSequence(AttributeList list,boolean retainExistingItems,
                  CodedSequenceItem purposeOfReferenceCodeSequence,
                  String manufacturer,
                  String institutionName,
                  String institutionalDepartmentName,
                  String institutionAddress,
                  String stationName,
                  String manufacturerModelName,
                  String deviceSerialNumber,
                  String softwareVersion,
                  String contributionDescription,
                  String contributionDateTime) throws DicomException {
            addContributingEquipmentSequence(list,true,purposeOfReferenceCodeSequence,
                  manufacturer,institutionName,institutionalDepartmentName,institutionAddress,stationName,manufacturerModelName,deviceSerialNumber,softwareVersion,
                  contributionDescription,contributionDateTime,
                  null,null);
      }
      
      /**
       * <p>Add the attributes of the Contributing Equipment Sequence to a list of attributes.</p>
       *
       * <p>Attributes are added if supplied string value are added if not null. May be zero length.</p>
       *
       * @param   list                                      the list of attributes to which to add the Contributing Equipment Sequence
       * @param   retainExistingItems                       if true, retain any existing items in Contributing Equipment Sequence, otherwise remove them
       * @param   purposeOfReferenceCodeSequence
       * @param   manufacturer
       * @param   institutionName
       * @param   institutionalDepartmentName
       * @param   institutionAddress
       * @param   stationName
       * @param   manufacturerModelName
       * @param   deviceSerialNumber
       * @param   softwareVersion
       * @param   contributionDescription
       * @param   contributionDateTime
       * @param   operatorNames                             an array of Strings of one or more operator's names, or null if not to be added
       * @param   operatorIdentifications             an array of {@link com.pixelmed.dicom.PersonIdentification PersonIdentification}, or null if not to be added
       * @throws  DicomException
       */
00184       public static void addContributingEquipmentSequence(AttributeList list,boolean retainExistingItems,
                  CodedSequenceItem purposeOfReferenceCodeSequence,
                  String manufacturer,
                  String institutionName,
                  String institutionalDepartmentName,
                  String institutionAddress,
                  String stationName,
                  String manufacturerModelName,
                  String deviceSerialNumber,
                  String softwareVersion,
                  String contributionDescription,
                  String contributionDateTime,
                  String[] operatorNames,
                  PersonIdentification[] operatorIdentifications) throws DicomException {

            Attribute aSpecificCharacterSet = list.get(TagFromName.SpecificCharacterSet);
            SpecificCharacterSet specificCharacterSet = aSpecificCharacterSet == null ? null : new SpecificCharacterSet(aSpecificCharacterSet.getStringValues());

            AttributeList newItemList = new AttributeList();
            
            if (purposeOfReferenceCodeSequence != null) {
                  SequenceAttribute aPurposeOfReferenceCodeSequence = new SequenceAttribute(TagFromName.PurposeOfReferenceCodeSequence);
                  aPurposeOfReferenceCodeSequence.addItem(purposeOfReferenceCodeSequence.getAttributeList());
                  newItemList.put(aPurposeOfReferenceCodeSequence);
            }
            addType3LongStringAttribute (newItemList,TagFromName.Manufacturer,manufacturer,specificCharacterSet);
            addType3LongStringAttribute (newItemList,TagFromName.InstitutionName,institutionName,specificCharacterSet);
            addType3LongStringAttribute (newItemList,TagFromName.InstitutionalDepartmentName,institutionalDepartmentName,specificCharacterSet);
            addType3ShortTextAttribute  (newItemList,TagFromName.InstitutionAddress,institutionAddress,specificCharacterSet);
            addType3ShortStringAttribute(newItemList,TagFromName.StationName,stationName,specificCharacterSet);
            addType3LongStringAttribute (newItemList,TagFromName.ManufacturerModelName,manufacturerModelName,specificCharacterSet);
            addType3LongStringAttribute (newItemList,TagFromName.DeviceSerialNumber,deviceSerialNumber,specificCharacterSet);
            addType3LongStringAttribute (newItemList,TagFromName.SoftwareVersion,softwareVersion,specificCharacterSet);
            addType3ShortTextAttribute  (newItemList,TagFromName.ContributionDescription,contributionDescription,specificCharacterSet);
            addType3DateTimeAttribute   (newItemList,TagFromName.ContributionDateTime,contributionDateTime);
            
            if (operatorNames != null && operatorNames.length > 0) {
                  Attribute aOperatorName = new PersonNameAttribute(TagFromName.OperatorName);
                  for (int i=0; i<operatorNames.length; ++i) {
                        aOperatorName.addValue(operatorNames[i]);
                  }
                  newItemList.put(aOperatorName);
            }
            
            if (operatorIdentifications != null && operatorIdentifications.length > 0) {
                  SequenceAttribute aOperatorIdentificationSequence = new SequenceAttribute(TagFromName.OperatorIdentificationSequence);
                  for (int i=0; i<operatorIdentifications.length; ++i) {
                        PersonIdentification operator = operatorIdentifications[i];
                        if (operator != null) {
                              aOperatorIdentificationSequence.addItem(new SequenceItem(operator.getAttributeList()));
                        }
                  }
                  newItemList.put(aOperatorIdentificationSequence);
            }
            
            SequenceAttribute aContributingEquipmentSequence = null;
            if (retainExistingItems) {
                  aContributingEquipmentSequence = (SequenceAttribute)list.get(TagFromName.ContributingEquipmentSequence);    // may be absent
            }
            if (aContributingEquipmentSequence == null) {
                  aContributingEquipmentSequence = new SequenceAttribute(TagFromName.ContributingEquipmentSequence);
            }
            aContributingEquipmentSequence.addItem(newItemList);
            list.remove(TagFromName.ContributingEquipmentSequence);
            list.put(aContributingEquipmentSequence);
      }
      
      /**
       * <p>Add the attributes of the Clinical Trials Patient, Study and Series Modules, to a list of attributes.</p>
       *
       * @param   list                    the list of attributes to which to add the attributes
       * @param   replaceConventionalAttributes if true, use the supplied clinical trials attributes in place of the conventional ID attributes as well
       * @param   clinicalTrialSponsorName
       * @param   clinicalTrialProtocolID
       * @param   clinicalTrialProtocolName
       * @param   clinicalTrialSiteID
       * @param   clinicalTrialSiteName
       * @param   clinicalTrialSubjectID
       * @param   clinicalTrialSubjectReadingID
       * @param   clinicalTrialTimePointID
       * @param   clinicalTrialTimePointDescription
       * @param   clinicalTrialCoordinatingCenterName
       * @throws  DicomException
       */
00268       public static void addClinicalTrialsAttributes(AttributeList list,boolean replaceConventionalAttributes,
                  String clinicalTrialSponsorName,
                  String clinicalTrialProtocolID,
                  String clinicalTrialProtocolName,
                  String clinicalTrialSiteID,
                  String clinicalTrialSiteName,
                  String clinicalTrialSubjectID,
                  String clinicalTrialSubjectReadingID,
                  String clinicalTrialTimePointID,
                  String clinicalTrialTimePointDescription,
                  String clinicalTrialCoordinatingCenterName) throws DicomException {
                  
            Attribute aSpecificCharacterSet = list.get(TagFromName.SpecificCharacterSet);
            SpecificCharacterSet specificCharacterSet = aSpecificCharacterSet == null ? null : new SpecificCharacterSet(aSpecificCharacterSet.getStringValues());
                  
            // Clinical Trial Subject Module

            addType1LongStringAttribute(list,TagFromName.ClinicalTrialSponsorName,clinicalTrialSponsorName,specificCharacterSet);
            addType1LongStringAttribute(list,TagFromName.ClinicalTrialProtocolID,clinicalTrialProtocolID,specificCharacterSet);
            addType2LongStringAttribute(list,TagFromName.ClinicalTrialProtocolName,clinicalTrialProtocolName,specificCharacterSet);
            addType2LongStringAttribute(list,TagFromName.ClinicalTrialSiteID,clinicalTrialSiteID,specificCharacterSet);
            addType2LongStringAttribute(list,TagFromName.ClinicalTrialSiteName,clinicalTrialSiteName,specificCharacterSet);
            if (clinicalTrialSubjectID != null || clinicalTrialSubjectReadingID == null)  // must be one or the other present
                  addType1LongStringAttribute(list,TagFromName.ClinicalTrialSubjectID,clinicalTrialSubjectID,specificCharacterSet);
            if (clinicalTrialSubjectReadingID != null)
                  addType1LongStringAttribute(list,TagFromName.ClinicalTrialSubjectReadingID,clinicalTrialSubjectReadingID,specificCharacterSet);

            // Clinical Trial Study Module

            addType2LongStringAttribute(list,TagFromName.ClinicalTrialTimePointID,clinicalTrialTimePointID,specificCharacterSet);
            addType3ShortTextAttribute(list,TagFromName.ClinicalTrialTimePointDescription,clinicalTrialTimePointDescription,specificCharacterSet);

            // Clinical Trial Series Module

            addType2LongStringAttribute(list,TagFromName.ClinicalTrialCoordinatingCenterName,clinicalTrialCoordinatingCenterName,specificCharacterSet);
            
            if (replaceConventionalAttributes) {
                  // Use ClinicalTrialSubjectID to replace both PatientName and PatientID
                  {
                        String value = clinicalTrialSubjectID;
                        if (value == null) value=defaultValueForMissingNonZeroLengthStrings;
                        {
                              //list.remove(TagFromName.PatientName);
                              Attribute a = new PersonNameAttribute(TagFromName.PatientName,specificCharacterSet);
                              a.addValue(value);
                              list.put(TagFromName.PatientName,a);
                        }
                        {
                              //list.remove(TagFromName.PatientID);
                              Attribute a = new LongStringAttribute(TagFromName.PatientID,specificCharacterSet);
                              a.addValue(value);
                              list.put(TagFromName.PatientID,a);
                        }
                  }
                  // Use ClinicalTrialTimePointID to replace Study ID
                  {
                        String value = clinicalTrialTimePointID;
                        if (value == null) value=defaultValueForMissingNonZeroLengthStrings;
                        {
                              //list.remove(TagFromName.StudyID);
                              Attribute a = new ShortStringAttribute(TagFromName.StudyID,specificCharacterSet);
                              a.addValue(value);
                              list.put(TagFromName.StudyID,a);
                        }
                  }
            }
      }
      
      /**
       * <p>Is a private tag safe.</p>
       *
       * <p>Safe private attributes are all those that are known not to contain individually identifiable information.</p>
       *
       * <p>Private creators are always considered safe.</p>
       *
       * @param   tag         the tag in question
       * @param   list  the list in which the tag is contained from which the private creator can be extracted
       */
00346       public static boolean isSafePrivateAttribute(AttributeTag tag,AttributeList list) {
//System.err.println("ClinicalTrialsAttributes.isSafePrivateAttribute(): checking "+tag);
            boolean safe = false;
            if (tag.isPrivateCreator()) {
                  safe = true;            // keep all creators, since may need them, and are harmless (and need them to check real private tags later)
            }
            else {
                  String creator = list.getPrivateCreatorString(tag);
                  int group = tag.getGroup();
                  int element = tag.getElement();
                  if (group == 0x7053) {
                        if (creator.equals("Philips PET Private Group")) {
                              int elementInBlock = element & 0x00ff;
                              if (elementInBlock == 0x0000) {                 // DS SUV Factor – Multiplying stored pixel values by Rescale Slope then this factor results in SUVbw in g/l
                                    safe = true;
                              }
                              else if (elementInBlock == 0x0009) {      // DS Activity Concentration Factor – Multiplying stored pixel values by Rescale Slope then this factor results in MBq/ml.
                                    safe = true;
                              }
                        }
                  }
            }
            return safe;
      }
      
      /**
       * <p>Flush (remove all entries in) the map of original UIDs to replacement UIDs.</p>
       */
00374       public static void flushMapOfUIDs() {
            mapOfOriginalToReplacementUIDs = null;
      }
      
      public class HandleUIDs {
            public static final int keep = 0;
            public static final int remove = 1;
            public static final int remap = 2;
      }

      /**
       * <p>Remap UID attributes in a list of attributes, recursively iterating through nested sequences.</p>
       *
       * @param   list        the list of attributes to be cleaned up
       * @throws  DicomException
       */
00390       public static void remapUIDAttributes(AttributeList list) throws DicomException {
            removeOrRemapUIDAttributes(list,HandleUIDs.remap);
      }
      
      /**
       * <p>Remove UID attributes in a list of attributes, recursively iterating through nested sequences.</p>
       *
       * @param   list        the list of attributes to be cleaned up
       * @throws  DicomException
       */
00400       public static void removeUIDAttributes(AttributeList list) throws DicomException {
            removeOrRemapUIDAttributes(list,HandleUIDs.remove);
      }
      
      /**
       * <p>Remove or remap UID attributes in a list of attributes, recursively iterating through nested sequences.</p>
       *
       * @param   list        the list of attributes to be cleaned up
       * @param   handleUIDs  remove or remap the UIDs
       * @throws  DicomException
       */
00411       protected static void removeOrRemapUIDAttributes(AttributeList list,int handleUIDs) throws DicomException {
            // iterate through list to remove all UIDs, and recursively iterate through any sequences ...
            LinkedList forRemovalOrRemapping = null;
            Iterator i = list.values().iterator();
            while (i.hasNext()) {
                  Object o = i.next();
                  if (o instanceof SequenceAttribute) {
                        SequenceAttribute a = (SequenceAttribute)o;
                        Iterator items = a.iterator();
                        if (items != null) {
                              while (items.hasNext()) {
                                    SequenceItem item = (SequenceItem)(items.next());
                                    if (item != null) {
                                          AttributeList itemAttributeList = item.getAttributeList();
                                          if (itemAttributeList != null) {
                                                removeOrRemapUIDAttributes(itemAttributeList,handleUIDs);
                                          }
                                    }
                              }
                        }
                  }
                  else if (handleUIDs != HandleUIDs.keep && o instanceof UniqueIdentifierAttribute) {
                        // remove all UIDs except those that are not instance-related
                        UniqueIdentifierAttribute a = (UniqueIdentifierAttribute)o;
                        AttributeTag tag = a.getTag();
//if (tag.equals(TagFromName.SOPInstanceUID)) { System.err.println("ClinicalTrialsAttributes.removeOrRemapUIDAttributes(): encountered SOP Instance UID"); }
                        if (UniqueIdentifierAttribute.isTransient(tag)) {
                              if (forRemovalOrRemapping == null) {
                                    forRemovalOrRemapping = new LinkedList();
                              }
                              forRemovalOrRemapping.add(tag);
//if (tag.equals(TagFromName.SOPInstanceUID)) { System.err.println("ClinicalTrialsAttributes.removeOrRemapUIDAttributes(): added SOP Instance UID to list"); }
                        }
                  }
            }
            if (forRemovalOrRemapping != null) {
                  Iterator i2 = forRemovalOrRemapping.iterator();
                  while (i2.hasNext()) {
                        AttributeTag tag = (AttributeTag)(i2.next());
                        if (handleUIDs == HandleUIDs.remove) {
                              list.remove(tag);
                        }
                        else if (handleUIDs == HandleUIDs.remap) {
                              String originalUIDValue = Attribute.getSingleStringValueOrNull(list,tag);
//if (tag.equals(TagFromName.SOPInstanceUID)) { System.err.println("ClinicalTrialsAttributes.removeOrRemapUIDAttributes(): requesting replacement of SOP Instance UID "+originalUIDValue); }
                              if (originalUIDValue != null) {
                                    String replacementUIDValue = null;
                                    if (mapOfOriginalToReplacementUIDs == null) {
                                          mapOfOriginalToReplacementUIDs = new HashMap();
                                    }
                                    replacementUIDValue = (String)(mapOfOriginalToReplacementUIDs.get(originalUIDValue));
                                    if (replacementUIDValue == null) {
                                          if (uidGenerator == null) {
                                                uidGenerator = new UIDGenerator();
                                          }
                                          replacementUIDValue = uidGenerator.getAnotherNewUID();
                                          mapOfOriginalToReplacementUIDs.put(originalUIDValue,replacementUIDValue);
                                    }
                                    assert replacementUIDValue != null;
                                    list.remove(tag);
                                    Attribute a = new UniqueIdentifierAttribute(tag);
                                    a.addValue(replacementUIDValue);
                                    list.put(tag,a);
//if (tag.equals(TagFromName.SOPInstanceUID)) { System.err.println("ClinicalTrialsAttributes.removeOrRemapUIDAttributes(): replacing SOP Instance UID "+originalUIDValue+" with "+replacementUIDValue); }
                              }
                              else {
                                    // we have a problem ... just remove it to be safe
                                    list.remove(tag);
                              }
                        }
                  }
            }
      }

      /**
       * <p>Deidentify a list of attributes.</p>
       *
       * <p>De-identifies attributes within nested sequences, other than Context Sequence.</p>
       *
       * <p>Handles UIDs as requested, including within nested sequences, including Context Sequence.</p>
       *
       * <p>Also adds record that de-identification has been performed.</p>
       *
       * @param   list        the list of attributes to be cleaned up
       * @param   keepUIDs    if true, keep the UIDs
       * @param   keepDescriptors   if true, keep the text description and comment attributes
       * @param   keepCharacteristics     if true, keep patient characteristics (such as might be needed for PET SUV calculations)
       * @throws  DicomException
       */
00500       public static void removeOrNullIdentifyingAttributes(AttributeList list,boolean keepUIDs,boolean keepDescriptors,boolean keepCharacteristics) throws DicomException {
            removeOrNullIdentifyingAttributes(list,keepUIDs ? HandleUIDs.keep : HandleUIDs.remove,keepDescriptors,keepCharacteristics);
      }
      
      /**
       * <p>Deidentify a list of attributes.</p>
       *
       * <p>De-identifies attributes within nested sequences, other than Context Sequence.</p>
       *
       * <p>Handles UIDs as requested, including within nested sequences, including Context Sequence.</p>
       *
       * <p>Also adds record that de-identification has been performed.</p>
       *
       * @param   list        the list of attributes to be cleaned up
       * @param   handleUIDs  keep, remove or remap the UIDs
       * @param   keepDescriptors   if true, keep the text description and comment attributes
       * @param   keepCharacteristics     if true, keep patient characteristics (such as might be needed for PET SUV calculations)
       * @throws  DicomException
       */
00519       public static void removeOrNullIdentifyingAttributes(AttributeList list,int handleUIDs,boolean keepDescriptors,boolean keepCharacteristics) throws DicomException {
            removeOrNullIdentifyingAttributesRecursively(list,handleUIDs,keepDescriptors,keepCharacteristics);
            
            if (handleUIDs != HandleUIDs.keep) {
                  removeOrRemapUIDAttributes(list,handleUIDs);
            }
            
            { AttributeTag tag = TagFromName.PatientIdentityRemoved; list.remove(tag); Attribute a = new CodeStringAttribute(tag); a.addValue("YES"); list.put(tag,a); }
            {
                  AttributeTag tag = TagFromName.DeidentificationMethod;
                  list.remove(tag);
                  Attribute a = new LongStringAttribute(tag);
                  a.addValue("Deidentified");
                  a.addValue("Descriptors " + (keepDescriptors ? "retained" : "removed"));
                  a.addValue("Patient Characteristics " + (keepCharacteristics ? "retained" : "removed"));
                  if (handleUIDs != HandleUIDs.keep) {
                        a.addValue("UIDs " + (handleUIDs == HandleUIDs.remap ? "remapped" : "replaced"));
                  }
                  // else say nothing; may end up dealing with UIDs later
                  list.put(tag,a);
            }
      }

      
      /**
       * <p>Deidentify a list of attributes, recursively iterating through nested sequences.</p>
       *
       * <p>Does not process UIDs, but does remove sequences that would be invalidated by removing UIDs, e.g., Source Image Sequence and Referenced Image Sequence.</p>
       *
       * @param   list        the list of attributes to be cleaned up
       * @param   handleUIDs  keep, remove or remap the UIDs
       * @param   keepDescriptors   if true, keep the text description and comment attributes
       * @param   keepCharacteristics     if true, keep patient characteristics (such as might be needed for PET SUV calculations)
       * @throws  DicomException
       */
00554       protected static void removeOrNullIdentifyingAttributesRecursively(AttributeList list,int handleUIDs,boolean keepDescriptors,boolean keepCharacteristics) throws DicomException {
            // use the list from the Basic Application Level Confidentiality Profile in PS 3.15 2003, as updated per draft of Sup 142
      
            if (!keepDescriptors) {
                  list.remove(TagFromName.StudyDescription);
                  list.remove(TagFromName.SeriesDescription);
            }

            list.replaceWithZeroLengthIfPresent(TagFromName.AccessionNumber);
            list.remove(TagFromName.InstitutionName);
            list.remove(TagFromName.InstitutionAddress);
            list.replaceWithZeroLengthIfPresent(TagFromName.ReferringPhysicianName);
            list.remove(TagFromName.ReferringPhysicianAddress);
            list.remove(TagFromName.ReferringPhysicianTelephoneNumber);
            list.remove(TagFromName.StationName);
            list.remove(TagFromName.InstitutionalDepartmentName);
            list.remove(TagFromName.PhysicianOfRecord);
            list.remove(TagFromName.PerformingPhysicianName);
            list.remove(TagFromName.PhysicianReadingStudy);
            list.remove(TagFromName.RequestingPhysician);         // not in IOD; from Detached Study Mx; seen in Philips CT, ADAC NM
            
            list.remove(TagFromName.OperatorName);
            list.remove(TagFromName.AdmittingDiagnosesDescription);
            list.remove(TagFromName.DerivationDescription);
            list.replaceWithZeroLengthIfPresent(TagFromName.PatientName);
            list.replaceWithZeroLengthIfPresent(TagFromName.PatientID);
            list.replaceWithZeroLengthIfPresent(TagFromName.PatientBirthDate);
            list.remove(TagFromName.PatientBirthTime);
            list.remove(TagFromName.OtherPatientID);
            list.remove(TagFromName.OtherPatientName);

            if (!keepCharacteristics) {
                  list.replaceWithZeroLengthIfPresent(TagFromName.PatientSex);
                  list.remove(TagFromName.PatientAge);
                  list.remove(TagFromName.PatientSize);
                  list.remove(TagFromName.PatientWeight);
                  list.remove(TagFromName.EthnicGroup);
                  list.remove(TagFromName.PregnancyStatus);       // not in IOD; from Detached Patient Mx
                  list.remove(TagFromName.SmokingStatus);               // not in IOD; from Detached Patient Mx
                  list.replaceWithZeroLengthIfPresent(TagFromName.PatientSexNeutered);
                  list.remove(TagFromName.SpecialNeeds);
            }
            
            list.remove(TagFromName.MedicalRecordLocator);
            list.remove(TagFromName.Occupation);
            list.remove(TagFromName.AdditionalPatientHistory);
            list.remove(TagFromName.PatientComments);
            list.remove(TagFromName.DeviceSerialNumber);
            list.remove(TagFromName.PlateID);
            list.remove(TagFromName.GantryID);
            list.remove(TagFromName.CassetteID);
            list.remove(TagFromName.GeneratorID);
            list.remove(TagFromName.DetectorID);
            list.remove(TagFromName.ProtocolName);
            list.replaceWithZeroLengthIfPresent(TagFromName.StudyID);
            list.remove(TagFromName.RequestAttributesSequence);
            
            // remove all issuers, whether in composite IODs or not
            list.remove(TagFromName.IssuerOfAccessionNumberSequence);
            list.remove(TagFromName.IssuerOfPatientID);
            list.remove(TagFromName.IssuerOfPatientIDQualifiersSequence);
            list.remove(TagFromName.StudyIDIssuer);
            list.remove(TagFromName.IssuerOfAdmissionID);
            list.remove(TagFromName.IssuerOfAdmissionIDSequence);
            list.remove(TagFromName.IssuerOfServiceEpisodeID);
            list.remove(TagFromName.IssuerOfServiceEpisodeIDSequence);
            list.remove(TagFromName.ResultsIDIssuer);
            list.remove(TagFromName.InterpretationIDIssuer);
            
            list.remove(TagFromName.StudyStatusID);               // not in IOD; from Detached Study Mx; seen in Philips CT
            list.remove(TagFromName.StudyPriorityID);       // not in IOD; from Detached Study Mx; seen in Philips CT
            list.remove(TagFromName.CurrentPatientLocation);      // not in IOD; from Detached Study Mx; seen in Philips CT
            
            list.remove(TagFromName.PatientAddress);                          // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.MilitaryRank);                                  // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.BranchOfService);                         // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.PatientBirthName);                              // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.PatientMotherBirthName);                        // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.ConfidentialityConstraintOnPatientDataDescription);   // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.PatientInsurancePlanCodeSequence);              // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.PatientPrimaryLanguageCodeSequence);                  // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.CountryOfResidence);                            // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.RegionOfResidence);                             // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.PatientTelephoneNumber);                        // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.PatientReligiousPreference);                    // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.MedicalAlerts);                                 // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.Allergies);                                     // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.LastMenstrualDate);                             // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.SpecialNeeds);                                  // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.PatientState);                                  // not in IOD; from Detached Patient Mx
            list.remove(TagFromName.AdmissionID);                                   // not in IOD
            list.remove(TagFromName.AdmittingDate);                                 // not in IOD
            list.remove(TagFromName.AdmittingTime);                                 // not in IOD

            if (!keepDescriptors) {
                  list.remove(TagFromName.ImageComments);
            }

            // ContentSequence

            // others that it would seem necessary to remove ...
            
            list.remove(TagFromName.ReferencedPatientSequence);
            list.remove(TagFromName.ReferringPhysicianIdentificationSequence);
            list.remove(TagFromName.PhysicianOfRecordIdentificationSequence);
            list.remove(TagFromName.PhysicianReadingStudyIdentificationSequence);
            list.remove(TagFromName.ReferencedStudySequence);
            list.remove(TagFromName.AdmittingDiagnosesCodeSequence);
            list.remove(TagFromName.PerformingPhysicianIdentificationSequence);
            list.remove(TagFromName.OperatorIdentificationSequence);
            list.remove(TagFromName.ReferencedPerformedProcedureStepSequence);
            list.remove(TagFromName.PerformedProcedureStepID);
            list.remove(TagFromName.DataSetTrailingPadding);
            
            list.remove(TagFromName.ActualHumanPerformersSequence);
            list.remove(TagFromName.Arbitrary);
            list.remove(TagFromName.AuthorObserverSequence);
            list.remove(TagFromName.ContributionDescription);
            list.remove(TagFromName.CustodialOrganizationSequence);
            list.remove(TagFromName.DistributionAddress);
            list.remove(TagFromName.DistributionName);
            list.replaceWithZeroLengthIfPresent(TagFromName.FillerOrderNumberOfImagingServiceRequest);
            list.remove(TagFromName.HumanPerformersName);
            list.remove(TagFromName.HumanPerformersOrganization);
            list.remove(TagFromName.IconImageSequence);
            list.remove(TagFromName.IdentifyingComments);
            list.remove(TagFromName.InsurancePlanIdentification);
            list.remove(TagFromName.IntendedRecipientsOfResultsIdentificationSequence);
            list.remove(TagFromName.InterpretationApproverSequence);
            list.remove(TagFromName.InterpretationAuthor);
            list.remove(TagFromName.InterpretationIDIssuer);
            list.remove(TagFromName.InterpretationRecorder);
            list.remove(TagFromName.InterpretationTranscriber);
            list.remove(TagFromName.IssuerOfAdmissionID);
            list.remove(TagFromName.IssuerOfServiceEpisodeID);
            list.remove(TagFromName.ModifyingDeviceID);
            list.remove(TagFromName.ModifyingDeviceManufacturer);
            list.remove(TagFromName.NamesOfIntendedRecipientsOfResults);
            list.remove(TagFromName.OrderCallbackPhoneNumber);
            list.remove(TagFromName.OrderEnteredBy);
            list.remove(TagFromName.OrderEntererLocation);
            list.remove(TagFromName.ParticipantSequence);
            list.remove(TagFromName.PerformedLocation);
            list.remove(TagFromName.PerformedStationAETitle);
            list.remove(TagFromName.PerformedStationGeographicLocationCodeSequence);
            list.remove(TagFromName.PerformedStationName);
            list.remove(TagFromName.PerformedStationNameCodeSequence);
            list.remove(TagFromName.PersonAddress);
            list.remove(TagFromName.PersonIdentificationCodeSequence);
            list.remove(TagFromName.PersonName);
            list.remove(TagFromName.PersonTelephoneNumbers);
            list.remove(TagFromName.PhysicianApprovingInterpretation);
            list.replaceWithZeroLengthIfPresent(TagFromName.PlacerOrderNumberOfImagingServiceRequest);
            list.remove(TagFromName.PreMedication);
            list.remove(TagFromName.ReferencedPatientAliasSequence);
            list.remove(TagFromName.RequestedProcedureLocation);
            list.remove(TagFromName.RequestingService);
            list.remove(TagFromName.ResponsibleOrganization);
            list.remove(TagFromName.ResponsiblePerson);
            list.remove(TagFromName.ResultsDistributionListSequence);
            list.remove(TagFromName.ResultsIDIssuer);
            list.remove(TagFromName.ScheduledHumanPerformersSequence);
            list.remove(TagFromName.ScheduledPatientInstitutionResidence);
            list.remove(TagFromName.ScheduledPerformingPhysicianIdentificationSequence);
            list.remove(TagFromName.ScheduledPerformingPhysicianName);
            list.remove(TagFromName.ScheduledProcedureStepLocation);
            list.remove(TagFromName.ScheduledStationAETitle);
            list.remove(TagFromName.ScheduledStationGeographicLocationCodeSequence);
            list.remove(TagFromName.ScheduledStationName);
            list.remove(TagFromName.ScheduledStationNameCodeSequence);
            list.remove(TagFromName.ScheduledStudyLocation);
            list.remove(TagFromName.ScheduledStudyLocationAETitle);
            list.remove(TagFromName.ServiceEpisodeID);
            list.remove(TagFromName.StudyIDIssuer);
            list.remove(TagFromName.TextComments);
            list.remove(TagFromName.TextString);
            list.remove(TagFromName.TopicAuthor);
            list.remove(TagFromName.TopicKeyWords);
            list.remove(TagFromName.TopicSubject);
            list.remove(TagFromName.TopicTitle);
            list.replaceWithZeroLengthIfPresent(TagFromName.VerifyingObserverIdentificationCodeSequence);
            list.replaceWithDummyValueIfPresent(TagFromName.VerifyingObserverName,"Observer^Deidentified");
            // Do nothing with VerifyingObserverSequence ... we handle the attributes inside it individually
            list.remove(TagFromName.VerifyingOrganization);

            if (!keepDescriptors) {
                  list.remove(TagFromName.PerformedProcedureStepDescription);
                  list.remove(TagFromName.CommentsOnPerformedProcedureStep);
                  list.remove(TagFromName.AcquisitionComments);
                  list.remove(TagFromName.ReasonForStudy);        // not in IOD; from Detached Study Mx; seen in Philips CT
                  list.remove(TagFromName.RequestedProcedureDescription);     // not in IOD; from Detached Study Mx; seen in Philips CT
                  list.remove(TagFromName.StudyComments);               // not in IOD; from Detached Study Mx; seen in Philips CT
                  list.replaceWithZeroLengthIfPresent(TagFromName.AcquisitionDeviceProcessingDescription);
                  list.remove(TagFromName.DischargeDiagnosisDescription);
                  list.remove(TagFromName.ImagePresentationComments);
                  list.remove(TagFromName.ImagingServiceRequestComments);
                  list.remove(TagFromName.Impressions);
                  list.remove(TagFromName.InterpretationDiagnosisDescription);
                  list.remove(TagFromName.InterpretationText);
                  list.remove(TagFromName.OverlayComments);
                  list.remove(TagFromName.ReasonForImagingServiceRequest);
                  list.remove(TagFromName.RequestedContrastAgent);
                  list.remove(TagFromName.RequestedProcedureComments);
                  list.remove(TagFromName.ResultsComments);
                  list.remove(TagFromName.ScheduledProcedureStepDescription);
                  list.remove(TagFromName.ServiceEpisodeDescription);
                  list.remove(TagFromName.VisitComments);
            }

            if (handleUIDs == HandleUIDs.remove) {
                  // these are not UI VR, and hence don't get taken care of later,
                  // but if left, would be made invalid when Instance UIDs were removed and
                  // incomplete items left
                  list.remove(TagFromName.ReferencedImageSequence);
                  list.remove(TagFromName.SourceImageSequence);
            }

            Iterator i = list.values().iterator();
            while (i.hasNext()) {
                  Object o = i.next();
                  if (o instanceof SequenceAttribute) {
                        SequenceAttribute a = (SequenceAttribute)o;
                        if (!a.getTag().equals(TagFromName.ContentSequence)) {      // i.e. do NOT descend into SR content tree
                              Iterator items = a.iterator();
                              if (items != null) {
                                    while (items.hasNext()) {
                                          SequenceItem item = (SequenceItem)(items.next());
                                          if (item != null) {
                                                AttributeList itemAttributeList = item.getAttributeList();
//System.err.println("Recursed into item of "+a);
                                                if (itemAttributeList != null) {
                                                      removeOrNullIdentifyingAttributesRecursively(itemAttributeList,handleUIDs,keepDescriptors,keepCharacteristics);
                                                }
                                          }
                                    }
                              }
                        }
                  }
            }
      }
      
      /**
       * <p>For testing.</p>
       *
       * <p>Read a DICOM object from the file specified on the command line, and remove identifying attributes, and add sample clinical trials attributes.</p>
       *
       * @param   arg
       */
00802       public static void main(String arg[]) {

            System.err.println("do it buffered, looking for metaheader, no uid specified");
            try {
                  AttributeList list = new AttributeList();
                  //list.read(arg[0],null,true,true);
                  list.read(arg[0]);
                  System.err.println("As read ...");
                  System.err.print(list.toString());
                  
                  list.removeUnsafePrivateAttributes();
                  System.err.println("After remove unsafe private ...");
                  System.err.print(list.toString());
                  
                  list.removePrivateAttributes();
                  System.err.println("After remove private ...");
                  System.err.print(list.toString());
                  
                  list.removeGroupLengthAttributes();
                  System.err.println("After remove group lengths ...");
                  System.err.print(list.toString());
                  
                  list.removeMetaInformationHeaderAttributes();
                  System.err.println("After remove meta information header ...");
                  System.err.print(list.toString());

                  removeOrNullIdentifyingAttributes(list,true/*keepUIDs*/,true/*keepDescriptors)*/,true/*keepCharacteristics)*/);
                  System.err.println("After deidentify, keeping descriptions and characteristics and UIDs ...");
                  System.err.print(list.toString());
                  
                  removeOrNullIdentifyingAttributes(list,true/*keepUIDs*/,false/*keepDescriptors)*/,true/*keepCharacteristics)*/);
                  System.err.println("After deidentify, keeping characteristics and UIDs ...");
                  System.err.print(list.toString());
                  
                  removeOrNullIdentifyingAttributes(list,true/*keepUIDs*/,false/*keepDescriptors)*/,false/*keepCharacteristics)*/);
                  System.err.println("After deidentify, keeping only UIDs ...");
                  System.err.print(list.toString());
                  
                  removeOrNullIdentifyingAttributes(list,HandleUIDs.remap,false/*keepDescriptors)*/,false/*keepCharacteristics)*/);
                  System.err.println("After deidentify, remapping UIDs ...");
                  System.err.print(list.toString());
                  
                  removeOrNullIdentifyingAttributes(list,false/*keepUIDs*/,false/*keepDescriptors)*/,false/*keepCharacteristics)*/);
                  System.err.println("After deidentify, removing everything ...");
                  System.err.print(list.toString());
                  {
                        // need to create minimal set of UIDs to be valid
                        // should probably also do FrameOfReferenceUID
                        String studyID = Attribute.getSingleStringValueOrEmptyString(list,TagFromName.StudyID);
                        String seriesNumber = Attribute.getSingleStringValueOrEmptyString(list,TagFromName.SeriesNumber);
                        String instanceNumber =  Attribute.getSingleStringValueOrEmptyString(list,TagFromName.InstanceNumber);
                        UIDGenerator u = new UIDGenerator();      
                        { Attribute a = new UniqueIdentifierAttribute(TagFromName.SOPInstanceUID); a.addValue(u.getNewSOPInstanceUID(studyID,seriesNumber,instanceNumber)); list.put(a); }
                        { Attribute a = new UniqueIdentifierAttribute(TagFromName.SeriesInstanceUID); a.addValue(u.getNewSeriesInstanceUID(studyID,seriesNumber)); list.put(a); }
                        { Attribute a = new UniqueIdentifierAttribute(TagFromName.StudyInstanceUID); a.addValue(u.getNewStudyInstanceUID(studyID)); list.put(a); }
                  }
                  
                  addClinicalTrialsAttributes(list,true/*replaceConventionalAttributes*/,
                        "ourSponsorName",
                        "ourProtocolID",
                        "ourProtocolName",
                        "ourSiteID",
                        "ourSiteName",
                        "ourSubjectID",
                        "ourSubjectReadingID",
                        "ourTimePointID",
                        "ourTimePointDescription",
                        "ourCoordinatingCenterName");
                  
                  System.err.println("After addClinicalTrialsAttributes ...");
                  System.err.print(list.toString());

                  String[] operatorNames = { "smithj","doej" };
                  CodedSequenceItem[] operatorPersonIdentificationCodeSequence1 =  { new CodedSequenceItem("634872364","99MYH","Smith^John") };
                  CodedSequenceItem[] operatorPersonIdentificationCodeSequence2 =  { new CodedSequenceItem("346234622","99MYH","Doe^Jane") };
                  String[] phoneNumbers1 = { "555-1212" };
                  PersonIdentification[] operatorIdentifications =  new PersonIdentification[2];
                  operatorIdentifications[0] = new PersonIdentification(operatorPersonIdentificationCodeSequence1,"John address",phoneNumbers1,null,"My hospital address",new CodedSequenceItem("47327864","99MYH","My Hospital"));
                  operatorIdentifications[1] = new PersonIdentification(operatorPersonIdentificationCodeSequence2,"Jane address",phoneNumbers1,"My hospital","My hospital address",(CodedSequenceItem)null);
                  //operatorIdentifications[1] = new PersonIdentification(operatorPersonIdentificationCodeSequence2,null,null,"My hospital",null,(CodedSequenceItem)null);
                  //operatorIdentifications[1] = new PersonIdentification(operatorPersonIdentificationCodeSequence2,"Jane address",phoneNumbers1,null,"My hospital address",(CodedSequenceItem)null);
                  
                  addContributingEquipmentSequence(list,
                        true,
                        new CodedSequenceItem("109104","DCM","De-identifying Equipment"),
                        "PixelMed",                                                                               // Manufacturer
                        "PixelMed",                                                                               // Institution Name
                        "Software Development",                                                             // Institutional Department Name
                        "Bangor, PA",                                                                             // Institution Address
                        null,                                                                                     // Station Name
                        "com.pixelmed.dicom.ClinicalTrialsAttributes.main()",             // Manufacturer's Model Name
                        null,                                                                                     // Device Serial Number
                        "Vers. 20080429",                                                                   // Software Version(s)
                        "Deidentified",
                        DateTimeAttribute.getFormattedString(new java.util.Date()),
                        operatorNames,
                        operatorIdentifications);
                  
                  System.err.println("After addContributingEquipmentSequence ...");
                  System.err.print(list.toString());

                  list.remove(TagFromName.DataSetTrailingPadding);
                  list.correctDecompressedImagePixelModule();
                  FileMetaInformation.addFileMetaInformation(list,TransferSyntax.ExplicitVRLittleEndian,"OURAETITLE");
                  list.write(arg[1],TransferSyntax.ExplicitVRLittleEndian,true,true);
            } catch (Exception e) {
                  e.printStackTrace(System.err);
            }
      }

}


Generated by  Doxygen 1.6.0   Back to index