/******************************************************************************* * 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; import java.awt.Color; import java.awt.color.ICC_ColorSpace; import java.awt.color.ICC_Profile; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.function.Predicate; import org.dcm4che3.data.Attributes; import org.dcm4che3.data.Sequence; import org.dcm4che3.data.Tag; import org.weasis.core.api.gui.util.ActionW; import org.weasis.core.api.media.data.TagW; import org.weasis.core.api.media.data.Tagable; import org.weasis.dicom.codec.display.PresetWindowLevel; import org.weasis.dicom.codec.utils.DicomMediaUtils; public class PresentationStateReader implements Tagable { public static final String TAG_PR_READER = "pr.reader"; //$NON-NLS-1$ public static final int PRIVATE_CREATOR_TAG = 0x71070070; public static final int PR_MODEL_PRIVATE_TAG = 0x71077001; public static final String PR_MODEL_ID = "weasis/model/xml/2.5"; //$NON-NLS-1$ private static final ICC_ColorSpace LAB = new ICC_ColorSpace(ICC_Profile.getInstance(ICC_ColorSpace.CS_sRGB)); private final PRSpecialElement prSpecialElement; private final Attributes dcmobj; private final HashMap<TagW, Object> tags = new HashMap<>(); public PresentationStateReader(PRSpecialElement dicom) { Objects.requireNonNull(dicom, "Dicom parameter cannot be null"); //$NON-NLS-1$ this.prSpecialElement = dicom; DicomMediaIO dicomImageLoader = dicom.getMediaReader(); this.dcmobj = dicomImageLoader.getDicomObject(); } public PRSpecialElement getDicom() { return prSpecialElement; } @Override public String toString() { return prSpecialElement.toString(); } public Attributes getDcmobj() { return dcmobj; } @Override public Object getTagValue(TagW tag) { return tag == null ? null : tags.get(tag); } @Override public void setTag(TagW tag, Object value) { DicomMediaUtils.setTag(tags, tag, value); } @Override public void setTagNoNull(TagW tag, Object value) { if (value != null) { setTag(tag, value); } } @Override public boolean containTagKey(TagW tag) { return tags.containsKey(tag); } @Override public Iterator<Entry<TagW, Object>> getTagEntrySetIterator() { return tags.entrySet().iterator(); } private static Predicate<Attributes> isSequenceApplicable(DicomImageElement img) { return attributes -> isModuleAppicable(attributes, img); } public static boolean isModuleAppicable(Attributes[] refSeriesSeqParent, DicomImageElement img) { if (refSeriesSeqParent != null) { for (Attributes refImgSeqParent : refSeriesSeqParent) { String seriesUID = TagD.getTagValue(img, Tag.SeriesInstanceUID, String.class); if (seriesUID.equals(refImgSeqParent.getString(Tag.SeriesInstanceUID))) { return isModuleAppicable(refImgSeqParent, img); } } } return false; } public static boolean isModuleAppicable(Attributes refImgSeqParent, DicomImageElement img) { Objects.requireNonNull(refImgSeqParent); Objects.requireNonNull(img); Sequence sops = refImgSeqParent.getSequence(Tag.ReferencedImageSequence); if (sops == null || sops.isEmpty()) { return true; } String imgSop = TagD.getTagValue(img, Tag.SOPInstanceUID, String.class); if (imgSop != null) { for (Attributes sop : sops) { if (imgSop.equals(sop.getString(Tag.ReferencedSOPInstanceUID))) { int[] frames = DicomMediaUtils.getIntAyrrayFromDicomElement(sop, Tag.ReferencedFrameNumber, null); if (frames == null || frames.length == 0) { return true; } int dicomFrame = 1; if (img.getKey() instanceof Integer) { dicomFrame = (Integer) img.getKey() + 1; } for (int f : frames) { if (f == dicomFrame) { return true; } } // if the frame has been excluded return false; } } } return false; } public List<PresetWindowLevel> getPresetCollection(DicomImageElement img) { return Optional.ofNullable(PresetWindowLevel.getPresetCollection(img, prSpecialElement, true, "[PR]")) //$NON-NLS-1$ .orElseGet(ArrayList::new); } public void applySpatialTransformationModule(Map<String, Object> actionsInView) { if (dcmobj != null) { // Rotation and then Flip actionsInView.put(ActionW.ROTATION.cmd(), dcmobj.getInt(Tag.ImageRotation, 0)); actionsInView.put(ActionW.FLIP.cmd(), "Y".equalsIgnoreCase(dcmobj.getString(Tag.ImageHorizontalFlip))); //$NON-NLS-1$ } } public void readDisplayArea(DicomImageElement img) { if (dcmobj != null) { TagW[] tagList = TagD.getTagFromIDs(Tag.PresentationPixelSpacing, Tag.PresentationPixelAspectRatio, Tag.PixelOriginInterpretation, Tag.PresentationSizeMode, Tag.DisplayedAreaTopLeftHandCorner, Tag.DisplayedAreaBottomRightHandCorner, Tag.PresentationPixelMagnificationRatio); TagSeq.MacroSeqData data = new TagSeq.MacroSeqData(dcmobj, tagList, isSequenceApplicable(img)); TagD.get(Tag.DisplayedAreaSelectionSequence).readValue(data, this); } } public static Color getRGBColor(int pGray, float[] labColour, int[] rgbColour) { int r, g, b; if (labColour != null) { if (LAB == null) { r = g = b = (int) (labColour[0] * 2.55f); } else { float[] rgb = LAB.toRGB(labColour); r = (int) (rgb[0] * 255); g = (int) (rgb[1] * 255); b = (int) (rgb[2] * 255); } } else if (rgbColour != null) { r = rgbColour[0]; g = rgbColour[1]; b = rgbColour[2]; if (r > 255 || g > 255 || b > 255) { r >>= 8; g >>= 8; b >>= 8; } } else { r = g = b = pGray >> 8; } r &= 0xFF; g &= 0xFF; b &= 0xFF; int conv = (r << 16) | (g << 8) | b | 0x1000000; return new Color(conv); } public static float[] colorToLAB(Color color) { float[] rgb = new float[3]; rgb[0] = color.getRed() / 255.f; rgb[1] = color.getGreen() / 255.f; rgb[2] = color.getBlue() / 255.f; return LAB.fromRGB(rgb); } }