/******************************************************************************* * Copyright (c) 2016 Weasis Team and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Nicolas Roduit - initial API and implementation *******************************************************************************/ package org.weasis.dicom.codec.display; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.EnumMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import org.dcm4che3.data.Tag; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.weasis.core.api.media.data.TagUtil; import org.weasis.core.api.media.data.TagView; import org.weasis.core.api.media.data.TagW; import org.weasis.core.api.util.FileUtil; import org.weasis.core.api.util.ResourceUtil; import org.weasis.core.api.util.StringUtil; import org.weasis.dicom.codec.Messages; import org.weasis.dicom.codec.TagD; public class ModalityView { private static final Logger LOGGER = LoggerFactory.getLogger(ModalityView.class); static final Map<Modality, ModalityInfoData> MODALITY_VIEW_MAP = new EnumMap<>(Modality.class); public static final ModalityInfoData DEFAULT_MODALITY_VIEW = new ModalityInfoData(Modality.DEFAULT, null); static { // Format associated to DICOM field: // $V => the value // $V:l$25$ => the value is limited to 25 characters followed by "..." // $V:f$#,##0.##$ => java pattern to display decimal number /* * See IHE BIR RAD TF-­‐2: 4.16.4.2.2.5.8 */ // Default profile of tag formats TagView[] disElements = DEFAULT_MODALITY_VIEW.getCornerInfo(CornerDisplay.TOP_LEFT).getInfos(); disElements[0] = new TagView(TagD.get(Tag.PatientName)); disElements[1] = new TagView(TagD.get(Tag.PatientBirthDate)); disElements[2] = new TagView(Messages.getString("ModalityView.id"), TagD.get(Tag.PatientID)); //$NON-NLS-1$ disElements[3] = new TagView(Messages.getString("ModalityView.sex"), TagD.get(Tag.PatientSex)); //$NON-NLS-1$ disElements[4] = new TagView(TagD.get(Tag.PatientAge)); disElements = DEFAULT_MODALITY_VIEW.getCornerInfo(CornerDisplay.TOP_RIGHT).getInfos(); disElements[0] = new TagView(TagD.get(Tag.InstitutionName)); disElements[1] = new TagView(Messages.getString("ModalityView.desc25"), TagD.get(Tag.StudyDescription)); //$NON-NLS-1$ disElements[2] = new TagView(Messages.getString("ModalityView.study"), TagD.get(Tag.StudyID)); //$NON-NLS-1$ disElements[3] = new TagView(Messages.getString("ModalityView.ac_nb"), TagD.get(Tag.AccessionNumber)); //$NON-NLS-1$ // else content date, else Series date, else Study date disElements[4] = new TagView(Messages.getString("ModalityView.acq"), //$NON-NLS-1$ TagD.getTagFromIDs(Tag.AcquisitionDate, Tag.ContentDate, Tag.DateOfSecondaryCapture, Tag.SeriesDate, Tag.StudyDate)); // else content time, else Series time, else Study time disElements[5] = new TagView(Messages.getString("ModalityView.acq"), //$NON-NLS-1$ TagD.getTagFromIDs(Tag.AcquisitionTime, Tag.ContentTime, Tag.TimeOfSecondaryCapture, Tag.SeriesTime, Tag.StudyTime)); disElements = DEFAULT_MODALITY_VIEW.getCornerInfo(CornerDisplay.BOTTOM_RIGHT).getInfos(); disElements[1] = new TagView(Messages.getString("ModalityView.series_nb"), TagD.get(Tag.SeriesNumber)); //$NON-NLS-1$ disElements[2] = new TagView(Messages.getString("ModalityView.laterality"), TagD.getTagFromIDs(Tag.FrameLaterality, //$NON-NLS-1$ Tag.ImageLaterality, Tag.Laterality)); // TODO add sequence // derived from Contrast/Bolus Agent Sequence (0018,0012), if // present, else Contrast/Bolus Agent (0018,0010) // http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.4b.html disElements[3] = new TagView(Messages.getString("ModalityView.desc25"), TagD.get(Tag.ContrastBolusAgent)); //$NON-NLS-1$ disElements[4] = new TagView(Messages.getString("ModalityView.desc25"), TagD.get(Tag.SeriesDescription)); //$NON-NLS-1$ disElements[5] = new TagView(Messages.getString("ModalityView.thick"), TagD.get(Tag.SliceThickness)); //$NON-NLS-1$ disElements[6] = new TagView(Messages.getString("ModalityView.location"), TagD.get(Tag.SliceLocation)); //$NON-NLS-1$ /* * Spacing Between Slices (0018,0088), if present, else a value derived from successive values of Image Position * (Patient) (0020,0032) perpendicular to the Image Orientation (Patient) (0020,0037) */ MODALITY_VIEW_MAP.put(Modality.DEFAULT, DEFAULT_MODALITY_VIEW); readTagDisplayByModality(); } private ModalityView() { } public static ModalityInfoData getModlatityInfos(Modality mod) { ModalityInfoData mdata = MODALITY_VIEW_MAP.get(mod); if (mdata == null) { mdata = MODALITY_VIEW_MAP.get(Modality.DEFAULT); } if (mdata == null) { mdata = DEFAULT_MODALITY_VIEW; } return mdata; } public static Set<Entry<Modality, ModalityInfoData>> getModalityViewEntries() { return MODALITY_VIEW_MAP.entrySet(); } private static Modality getModdality(String name) { try { return Modality.valueOf(name); } catch (Exception e) { LOGGER.error("Modality reference of {} is missing", name, e); //$NON-NLS-1$ } return null; } private static CornerDisplay getCornerDisplay(String name) { try { return CornerDisplay.valueOf(name); } catch (Exception e) { LOGGER.error("CornerDisplay reference of {} doesn't exist", name, e); //$NON-NLS-1$ } return null; } private static TagView getTagView(String name, String format) { if (name != null) { String[] vals = name.split(","); //$NON-NLS-1$ ArrayList<TagW> list = new ArrayList<>(vals.length); for (String s : vals) { TagW t = TagW.get(s); if (t == null) { LOGGER.warn("Cannot find tag \"{}\"", s); //$NON-NLS-1$ } else { list.add(t); } } if (!list.isEmpty()) { return new TagView(format, list.toArray(new TagW[list.size()])); } } return null; } private static void readTagDisplayByModality() { XMLStreamReader xmler = null; InputStream stream = null; try { File file = ResourceUtil.getResource("attributes-view.xml"); //$NON-NLS-1$ if (!file.canRead()) { return; } XMLInputFactory xmlif = XMLInputFactory.newInstance(); stream = new FileInputStream(file); // $NON-NLS-1$ xmler = xmlif.createXMLStreamReader(stream); while (xmler.hasNext()) { switch (xmler.next()) { case XMLStreamConstants.START_ELEMENT: String key = xmler.getName().getLocalPart(); if ("modalities".equals(key)) { //$NON-NLS-1$ readModalities(xmler); } break; default: break; } } } catch (Exception e) { LOGGER.error("Cannot read attributes-view.xml! ", e); //$NON-NLS-1$ } finally { FileUtil.safeClose(xmler); FileUtil.safeClose(stream); } } private static void readModalities(XMLStreamReader xmler) throws XMLStreamException { while (xmler.hasNext()) { switch (xmler.next()) { case XMLStreamConstants.START_ELEMENT: String key = xmler.getName().getLocalPart(); if ("modality".equals(key) && xmler.getAttributeCount() >= 1) { //$NON-NLS-1$ String name = xmler.getAttributeValue(null, "name");//$NON-NLS-1$ Modality m = getModdality(name); if (m != null) { try { String extend = xmler.getAttributeValue(null, "extend");//$NON-NLS-1$ ModalityInfoData data = new ModalityInfoData(m, getModdality(extend)); readModality(data, xmler); MODALITY_VIEW_MAP.put(m, data); } catch (Exception e) { LOGGER.error("Modality {} cannot be read from attributes-view.xml", //$NON-NLS-1$ name, e); } } } break; default: break; } } } private static void readModality(ModalityInfoData data, XMLStreamReader xmler) throws XMLStreamException { boolean state = true; while (xmler.hasNext() && state) { switch (xmler.next()) { case XMLStreamConstants.START_ELEMENT: if ("corner".equals(xmler.getName().getLocalPart()) && xmler.getAttributeCount() >= 1) { //$NON-NLS-1$ String name = xmler.getAttributeValue(null, "name");//$NON-NLS-1$ CornerDisplay corner = getCornerDisplay(name); if (corner != null) { readCorner(data, corner, xmler); } } break; case XMLStreamConstants.END_ELEMENT: if ("modality".equals(xmler.getName().getLocalPart())) { //$NON-NLS-1$ state = false; } break; default: break; } } } private static void readCorner(ModalityInfoData data, CornerDisplay corner, XMLStreamReader xmler) throws XMLStreamException { TagView[] disElements = data.getCornerInfo(corner).getInfos(); boolean state = true; int index = -1; String format = null; while (xmler.hasNext() && state) { switch (xmler.next()) { case XMLStreamConstants.CHARACTERS: if (index > 0 && index <= 7) { disElements[index - 1] = getTag(xmler.getText(), format); index = -1; // Reset current index and format format = null; } break; case XMLStreamConstants.START_ELEMENT: if ("p".equals(xmler.getName().getLocalPart()) && xmler.getAttributeCount() >= 1) { //$NON-NLS-1$ index = TagUtil.getIntegerTagAttribute(xmler, "index", -1); //$NON-NLS-1$ format = xmler.getAttributeValue(null, "format");//$NON-NLS-1$ } break; case XMLStreamConstants.END_ELEMENT: if ("corner".equals(xmler.getName().getLocalPart())) { //$NON-NLS-1$ state = false; } break; default: break; } } } private static TagView getTag(String name, String format) { if (StringUtil.hasText(name)) { return getTagView(name, format); } return null; } }