/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is part of dcm4che, an implementation of DICOM(TM) in * Java(TM), hosted at https://github.com/gunterze/dcm4che. * * The Initial Developer of the Original Code is * Agfa Healthcare. * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * See @authors listed below * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ package org.dcm4chee.archive.wado; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import javax.enterprise.context.RequestScoped; import javax.enterprise.event.Event; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.stream.ImageInputStream; import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.StreamingOutput; import javax.xml.transform.Templates; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import org.dcm4che3.conf.core.api.ConfigurationException; import org.dcm4che3.data.Attributes; import org.dcm4che3.data.DatasetWithFMI; import org.dcm4che3.data.Tag; import org.dcm4che3.data.UID; import org.dcm4che3.imageio.codec.ImageReaderFactory; import org.dcm4che3.imageio.codec.ImageWriterFactory; import org.dcm4che3.imageio.codec.TransferSyntaxType; import org.dcm4che3.imageio.plugins.dcm.DicomImageReadParam; import org.dcm4che3.imageio.plugins.dcm.DicomMetaData; import org.dcm4che3.io.DicomInputStream; import org.dcm4che3.io.SAXWriter; import org.dcm4che3.io.TemplatesCache; import org.dcm4che3.net.ApplicationEntity; import org.dcm4che3.net.service.BasicCStoreSCUResp; import org.dcm4che3.util.SafeClose; import org.dcm4che3.util.StringUtils; import org.dcm4che3.ws.rs.MediaTypes; import org.dcm4chee.archive.dto.ArchiveInstanceLocator; import org.dcm4chee.archive.dto.GenericParticipant; import org.dcm4chee.archive.dto.ServiceType; import org.dcm4chee.archive.fetch.forward.FetchForwardCallBack; import org.dcm4chee.archive.fetch.forward.FetchForwardService; import org.dcm4chee.archive.retrieve.impl.RetrieveAfterSendEvent; import org.dcm4chee.archive.rs.HostAECache; import org.dcm4chee.archive.rs.HttpSource; import org.dcm4chee.archive.store.scu.CStoreSCUContext; import org.dcm4chee.task.ImageProcessingTaskTypes; import org.dcm4chee.task.MemoryConsumingTask; import org.dcm4chee.task.TaskType; import org.dcm4chee.task.WeightWatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; /** * Service implementing DICOM PS 3.18-2011 (WADO), URI based communication. * * @see <a href= * "http://medical.nema.org/medical/dicom/current/output/html/part18.html"> * DICOM PS3.18 2015c - Web Services</a> * * @author Gunter Zeilinger <gunterze@gmail.com> * @author Umberto Cappellini <umberto.cappellini@agfa.com> * @author Hesham Elbadawi <bsdreko@gmail.com> * @author Hermann Czedik-Eysenberg <hermann-agfa@czedik.net> * @author Alessio Roselli <alessio.roselli@agfa.com> */ @RequestScoped @Path("/{AETitle}") public class WadoURI extends Wado { private static final Logger LOG = LoggerFactory.getLogger(WadoURI.class); @Inject private Event<RetrieveAfterSendEvent> retrieveEvent; @Inject private HostAECache hostAECache; @Inject private WeightWatcher weightWatcher; private CStoreSCUContext context; private static final int STATUS_NOT_IMPLEMENTED = 501; public enum Anonymize { yes } public enum Annotation { patient, technique } public static final class Strings { final String[] values; public Strings(String s) { values = StringUtils.split(s, ','); } } public static final class ContentTypes { final MediaType[] values; public ContentTypes(String s) { String[] ss = StringUtils.split(s, ','); values = new MediaType[ss.length]; for (int i = 0; i < ss.length; i++) values[i] = MediaType.valueOf(ss[i]); } } public static final class Annotations { final Annotation[] values; public Annotations(String s) { String[] ss = StringUtils.split(s, ','); values = new Annotation[ss.length]; for (int i = 0; i < ss.length; i++) values[i] = Annotation.valueOf(ss[i]); } } public static final class Region { final double left; final double top; final double right; final double bottom; public Region(String s) { String[] ss = StringUtils.split(s, ','); if (ss.length != 4) throw new IllegalArgumentException(s); left = Double.parseDouble(ss[0]); top = Double.parseDouble(ss[1]); right = Double.parseDouble(ss[2]); bottom = Double.parseDouble(ss[3]); if (left < 0. || right > 1. || top < 0. || bottom > 1. || left >= right || top >= bottom) throw new IllegalArgumentException(s); } } @Context private HttpServletRequest request; @Context private HttpHeaders headers; @QueryParam("requestType") private String requestType; @QueryParam("studyUID") private String studyUID; @QueryParam("seriesUID") private String seriesUID; @QueryParam("objectUID") private String objectUID; @QueryParam("contentType") private ContentTypes contentType; @QueryParam("charset") private Strings charset; @QueryParam("anonymize") private Anonymize anonymize; @QueryParam("annotation") private Annotations annotation; @QueryParam("rows") private int rows; @QueryParam("columns") private int columns; @QueryParam("region") private Region region; @QueryParam("windowCenter") private float windowCenter; @QueryParam("windowWidth") private float windowWidth; @QueryParam("frameNumber") private int frameNumber; @QueryParam("imageQuality") private int imageQuality; @QueryParam("presentationUID") private String presentationUID; @QueryParam("presentationSeriesUID") private String presentationSeriesUID; @QueryParam("transferSyntax") private List<String> transferSyntax; @QueryParam("overlays") private boolean overlays; @Inject private FetchForwardService fetchForwardService; @GET public Response retrieve() throws WebApplicationException { List<ArchiveInstanceLocator> insts = new ArrayList<ArchiveInstanceLocator>(); List<ArchiveInstanceLocator> instswarning = new ArrayList<ArchiveInstanceLocator>(); List<ArchiveInstanceLocator> instscompleted = new ArrayList<ArchiveInstanceLocator>(); List<ArchiveInstanceLocator> instsfailed = new ArrayList<ArchiveInstanceLocator>(); try { ApplicationEntity sourceAE; try { sourceAE = hostAECache.findAE(new HttpSource(request)); } catch (ConfigurationException e) { throw new WebApplicationException(e, Status.INTERNAL_SERVER_ERROR); } context = new CStoreSCUContext(arcAE.getApplicationEntity(), sourceAE, ServiceType.WADOSERVICE); checkRequest(); final List<ArchiveInstanceLocator> ref = retrieveService.calculateMatches(studyUID, seriesUID, objectUID, queryParam, false); if (ref == null || ref.size() == 0) throw new WebApplicationException(Status.NOT_FOUND); else insts.addAll(ref); if (ref.size() != 1) { instsfailed.addAll(ref); throw new WebApplicationException(Status.BAD_REQUEST); } //internal ArchiveInstanceLocator instance = null; Attributes attrs = null; Response resp = null; if (ref.get(0).getStorageSystem() != null) { instance = ref.get(0); resp = retrieve(instscompleted, instsfailed, ref, instance); } //external else { //try to forward by redirecting HTTP request ApplicationEntity forwardingAE = null; if ((forwardingAE = fetchForwardService.getPrefersForwardingAE(aetitle, ref)) != null) { Response redirectResponse = fetchForwardService.redirectRequest(forwardingAE, request.getQueryString()); if( redirectResponse != null && redirectResponse.getStatus() != Status.CONFLICT.getStatusCode()) { return redirectResponse; } } //fetch FetchForwardCallBack fetchCallBack = new FetchForwardCallBack() { @Override public void onFetch(Collection<ArchiveInstanceLocator> instances, BasicCStoreSCUResp basicCStoreSCUresp) { ref.clear(); ref.addAll(instances); } }; instsfailed = fetchForwardService.fetchForward(aetitle, ref, fetchCallBack, fetchCallBack); instance = ref.get(0); resp = retrieve(instscompleted, instsfailed, ref, instance); } if (resp == null) { throw new WebApplicationException(STATUS_NOT_IMPLEMENTED); } else { return resp; } } finally { // audit retrieveEvent.fire(new RetrieveAfterSendEvent( new GenericParticipant(request.getRemoteAddr(), request .getRemoteUser()), new GenericParticipant(request .getLocalAddr(), null), new GenericParticipant( request.getRemoteAddr(), request.getRemoteUser()), device, insts, instscompleted, instswarning, instsfailed)); } } private Response retrieve(List<ArchiveInstanceLocator> instscompleted, List<ArchiveInstanceLocator> instsfailed, List<ArchiveInstanceLocator> ref, ArchiveInstanceLocator instance) { if(!instsfailed.isEmpty()) throw new WebApplicationException(Status.CONFLICT); MediaType mediaType = selectMediaType(instance.tsuid, instance.cuid, (Attributes) instance.getObject()); if (!isAccepted(mediaType)) { instsfailed.addAll(ref); throw new WebApplicationException(Status.NOT_ACCEPTABLE); } if (mediaType == MediaTypes.APPLICATION_DICOM_TYPE) { instscompleted.addAll(ref); return retrieveNativeDicomObject(instance); } if (mediaType == MediaTypes.IMAGE_JPEG_TYPE || mediaType == MediaTypes.IMAGE_PNG_TYPE || mediaType == MediaTypes.IMAGE_GIF_TYPE) { instscompleted.addAll(ref); return retrieveImage(instance, mediaType); } if (mediaType.isCompatible(MediaTypes.APPLICATION_PDF_TYPE) || mediaType.isCompatible(MediaType.TEXT_XML_TYPE) // || mediaType.isCompatible(MediaType.TEXT_PLAIN_TYPE) || mediaType.isCompatible(MediaTypes.TEXT_RTF_TYPE)) { instscompleted.addAll(ref); return retrievePDFXMLOrText(mediaType, instance); } if (mediaType == MediaType.TEXT_HTML_TYPE) { try { instscompleted.addAll(ref); return retrieveSRHTML(instance); } catch (TransformerConfigurationException e) { return retrieveNativeDicomObject(instance); } } return null; } private boolean isSupportedSR(String cuid) { for (String c_uid : arcAE.getWadoSupportedSRClasses()) { if (c_uid.equals(cuid)) return true; } return false; } private void checkRequest() throws WebApplicationException { ApplicationEntity ae = device.getApplicationEntity(aetitle); if (ae == null || !ae.isInstalled()) throw new WebApplicationException(Status.SERVICE_UNAVAILABLE); if (!"WADO".equals(requestType)) throw new WebApplicationException(Status.BAD_REQUEST); if (studyUID == null || seriesUID == null || objectUID == null) throw new WebApplicationException(Status.BAD_REQUEST); boolean applicationDicom = false; if (contentType != null) { for (MediaType mediaType : contentType.values) { if (!isAccepted(mediaType)) throw new WebApplicationException(Status.BAD_REQUEST); if (mediaType.isCompatible(MediaTypes.APPLICATION_DICOM_TYPE)) applicationDicom = true; } } if (applicationDicom) { if (annotation != null || rows != 0 || columns != 0 || region != null || windowCenter != 0 || windowWidth != 0 || frameNumber != 0 || imageQuality != 0 || presentationUID != null || presentationSeriesUID != null) { throw new WebApplicationException(Status.BAD_REQUEST); } } else { if (anonymize != null || !transferSyntax.isEmpty() || rows < 0 || columns < 0 || imageQuality < 0 || imageQuality > 100 || presentationUID != null && presentationSeriesUID == null) { throw new WebApplicationException(Status.BAD_REQUEST); } } } private boolean isAccepted(MediaType mediaType) { for (MediaType accepted : headers.getAcceptableMediaTypes()) if (mediaType.isCompatible(accepted)) return true; return false; } private Response retrieveSRHTML(final ArchiveInstanceLocator ref) throws TransformerConfigurationException { return Response.ok(new StreamingOutput() { @Override public void write(OutputStream out) throws IOException { BufferedOutputStream bout = new BufferedOutputStream(out); Templates templates = null; SAXTransformerFactory factory = (SAXTransformerFactory) TransformerFactory.newInstance(); TransformerHandler th = null; try { String uri = StringUtils.replaceSystemProperties( arcAE.getWadoSRTemplateURI()); templates = TemplatesCache.getDefault().get(uri); } catch (TransformerConfigurationException e) { LOG.error("Unable to apply transformation for SR - check archive AE Configuration",e); } try { th = factory.newTransformerHandler(templates); } catch (TransformerConfigurationException e2) { LOG.error("Error configuring transformer handler - reason {}",e2); } Transformer tr = th.getTransformer(); String wado = request.getRequestURL().toString(); tr.setParameter("wadoURL", wado); SAXWriter w = null; th.setResult(new StreamResult(bout)); w = new SAXWriter(th); Attributes data = readAttributes(ref); data.addAll((Attributes) ref.getObject()); try { w.write(data); } catch (SAXException e) { LOG.error("Unable to write SR using defined template - reason {}",e); } } }, MediaType.TEXT_HTML_TYPE).build(); } private Response retrievePDFXMLOrText(MediaType mediaType, final ArchiveInstanceLocator ref) { return Response.ok(new StreamingOutput() { @Override public void write(OutputStream out) throws IOException, WebApplicationException { Attributes attrs = readAttributes(ref); try (BufferedOutputStream bOut = new BufferedOutputStream(out)) { bOut.write(attrs.getBytes(Tag.EncapsulatedDocument)); } } }, mediaType).build(); } private Attributes readAttributes(ArchiveInstanceLocator ref) throws IOException { for (;;) try (DicomInputStream in = new DicomInputStream( storescuService.getFile(ref).toFile())) { return in.readDataset(-1, -1); } catch (IOException e) { LOG.info("Failed to read Data Set with iuid={} from {}@{}", ref.iuid, ref.getFilePath(), ref.getStorageSystem(), e); ref = ref.getFallbackLocator(); if (ref == null) { throw e; } LOG.info("Try read Data Set from alternative location"); } } private Response retrieveNativeDicomObject(ArchiveInstanceLocator ref) { LocatorDatasetReader locatorDatasetReader; try { locatorDatasetReader = new LocatorDatasetReader(ref, context, storescuService).read(); } catch (IOException e) { throw new WebApplicationException(e); } ArchiveInstanceLocator selectedLocator = locatorDatasetReader.getSelectedLocator(); DatasetWithFMI datasetWithFMI = locatorDatasetReader.getDatasetWithFMI(); String selectedTransferSyntaxUID = selectTransferSyntax(selectedLocator, datasetWithFMI); MediaType mediaType = MediaType.valueOf("application/dicom;transfer-syntax=" + selectedTransferSyntaxUID); return Response.ok( new DicomObjectOutput(datasetWithFMI.getDataset(), selectedLocator.tsuid, selectedTransferSyntaxUID, weightWatcher), mediaType).build(); } private String selectTransferSyntax(ArchiveInstanceLocator inst, DatasetWithFMI datasetWithFMI) { String tsuid = inst.tsuid; // prevent that (possibly) faulty JPEG-LS data leaves the system, // we only want to give it out uncompressed if (inst.getStorageSystem().getStorageSystemGroup().isPossiblyFaultyJPEGLS(datasetWithFMI)) { return selectFirstUncompressedTransferSyntax(); } // no need of decompression if (transferSyntax.contains("*") || transferSyntax.contains(tsuid)) return tsuid; // cannot decompress to required ts if (!ImageReaderFactory.canDecompress(tsuid)) return tsuid; return selectFirstUncompressedTransferSyntax(); } private String selectFirstUncompressedTransferSyntax() { for (String singleTransferSyntax : transferSyntax) if (TransferSyntaxType.forUID(singleTransferSyntax).equals(TransferSyntaxType.NATIVE)) return singleTransferSyntax; //default return UID.ExplicitVRLittleEndian; } private Response retrieveImage(ArchiveInstanceLocator ref, final MediaType mediaType) { Attributes attrs = (Attributes) ref.getObject(); ImageInputStream iis = null; ImageReader reader = null; ImageWriter imageWriter = null; try { DicomImageReadParam param; try { iis = getImageInputStream(ref); reader = getDicomImageReader(); reader.setInput(iis); DicomMetaData metaData = (DicomMetaData) reader.getStreamMetadata(); metaData.getAttributes().addAll(attrs); param = (DicomImageReadParam) reader.getDefaultReadParam(); init(param); } catch (IOException e) { throw new WebApplicationException(e, Status.INTERNAL_SERVER_ERROR); } imageWriter = ImageWriterFactory.getImageWriterForMimeType(mediaType.toString()); ImageWriteParam imageWriteParam = getImageWriterParam(imageWriter); int numberOfFrames = attrs.getInt(Tag.NumberOfFrames, 1); int frameNumberZeroBased; if (numberOfFrames == 1) { // single frame if (frameNumber < 0 || frameNumber > 1) throw new WebApplicationException(Status.NOT_FOUND); frameNumberZeroBased = 0; // first frame } else { // multi frame if (frameNumber != 0) { if (frameNumber < 0 || frameNumber > numberOfFrames) throw new WebApplicationException(Status.NOT_FOUND); frameNumberZeroBased = frameNumber - 1; } else { if (mediaType == MediaTypes.IMAGE_GIF_TYPE) // animated GIF case frameNumberZeroBased = -1; // all frames else frameNumberZeroBased = 0; // first frame } } RenderedImageOutput renderedImageOutput = new RenderedImageOutput(reader, param, rows, columns, frameNumberZeroBased, imageWriter, imageWriteParam); StreamingOutputWrapper wrapper = new StreamingOutputWrapper(renderedImageOutput, iis); // make sure the stream/reader/writer is not closed early, but later on when doing the streaming iis = null; reader = null; imageWriter = null; return Response.ok(wrapper, mediaType).build(); } finally { if (imageWriter != null) imageWriter.dispose(); if (reader != null) reader.dispose(); if (iis != null) { try { iis.close(); } catch (IOException e) { LOG.error("Error closing input stream", e); } } } } private ImageInputStream getImageInputStream(ArchiveInstanceLocator ref) throws IOException { ImageInputStream iis = null; for (; ; ) { try { iis = createImageInputStream(ref); break; } catch (IOException e) { SafeClose.close(iis); LOG.info("Failed to read image with iuid={} from {}@{}", ref.iuid, ref.getFilePath(), ref.getStorageSystem(), e); ref = ref.getFallbackLocator(); if (ref == null) { throw e; } LOG.info("Try read image from alternative location"); } } return iis; } private class StreamingOutputWrapper implements StreamingOutput { private final RenderedImageOutput renderedImageOutput; private final ImageInputStream inputStream; public StreamingOutputWrapper(RenderedImageOutput renderedImageOutput, ImageInputStream inputStream) { this.renderedImageOutput = renderedImageOutput; this.inputStream = inputStream; } @Override public void write(OutputStream output) throws IOException { // we wrap the RenderedImageOutput for two reasons: // 1) we need to close the input stream in a finally // 2) we want to run it through the WeightWatcher try { weightWatcher.execute(new RenditionTask(renderedImageOutput, output)); } catch (Exception e) { if (e instanceof IOException) throw (IOException) e; else if (e instanceof RuntimeException) throw (RuntimeException) e; else throw new RuntimeException(e); // should not happen } finally { inputStream.close(); } } } private static class RenditionTask implements MemoryConsumingTask<Void> { private final RenderedImageOutput renderedImageOutput; private final OutputStream output; public RenditionTask(RenderedImageOutput renderedImageOutput, OutputStream output) { this.renderedImageOutput = renderedImageOutput; this.output = output; } @Override public TaskType getTaskType() { return ImageProcessingTaskTypes.TRANSCODE_OUTGOING; } @Override public long getEstimatedWeight() { try { return renderedImageOutput.getEstimatedNeededMemory(); } catch (IOException e) { // shouldn't happen in this case, as the dicom stream metadata was already read before throw new RuntimeException(e); } } @Override public Void call() throws IOException { renderedImageOutput.write(output); return null; } } private ImageInputStream createImageInputStream(ArchiveInstanceLocator ref) throws IOException { return ImageIO.createImageInputStream(storescuService.getFile(ref).toFile()); } private static ImageReader getDicomImageReader() { Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("DICOM"); if (!readers.hasNext()) { ImageIO.scanForPlugins(); readers = ImageIO.getImageReadersByFormatName("DICOM"); } return readers.next(); } private void init(DicomImageReadParam param) throws WebApplicationException, IOException { if (!request.getQueryString().contains("overlays")) overlays = arcAE.isWadoOverlayRendering(); //set overlay activation mask param.setOverlayActivationMask(overlays ? 0xf : 0x0); param.setWindowCenter(windowCenter); param.setWindowWidth(windowWidth); if (presentationUID != null) { List<ArchiveInstanceLocator> ref = retrieveService .calculateMatches(studyUID, presentationSeriesUID, presentationUID, queryParam, false); if (ref == null || ref.size() == 0) throw new WebApplicationException(Status.NOT_FOUND); if (ref.size() != 1) throw new WebApplicationException(Status.BAD_REQUEST); param.setPresentationState(readAttributes(ref.get(0))); } } private ImageWriteParam getImageWriterParam(ImageWriter imageWriter) { ImageWriteParam imageWriteParam = imageWriter .getDefaultWriteParam(); if (imageQuality > 0) { imageWriteParam .setCompressionMode(ImageWriteParam.MODE_EXPLICIT); imageWriteParam.setCompressionQuality(imageQuality / 100f); } return imageWriteParam; } /** * Returns the first media type that is supported and compatible with the contentType * request parameter. If none is compatible an exception is thrown. */ private MediaType selectMediaType(String transferSyntaxUID, String sopClassUID, Attributes attrs) { List<MediaType> supportedMediaTypes = supportedMediaTypesOf( transferSyntaxUID, sopClassUID, attrs); if (contentType != null) { for (MediaType requestedType : contentType.values) for (MediaType supportedType : supportedMediaTypes) if (requestedType.isCompatible(supportedType)) return supportedType; throw new WebApplicationException(Status.NOT_ACCEPTABLE); } else { return supportedMediaTypes.get(0); } } public List<MediaType> supportedMediaTypesOf(String transferSyntaxUID, String sopClassUID, Attributes attrs) { List<MediaType> list = new ArrayList<MediaType>(4); if (attrs.contains(Tag.BitsAllocated)) { if (attrs.getInt(Tag.NumberOfFrames, 1) > 1) { list.add(MediaTypes.APPLICATION_DICOM_TYPE); if (UID.MPEG2.equals(transferSyntaxUID) || UID.MPEG2MainProfileHighLevel .equals(transferSyntaxUID)) list.add(MediaTypes.VIDEO_MPEG_TYPE); else if (UID.MPEG4AVCH264HighProfileLevel41 .equals(transferSyntaxUID) || UID.MPEG4AVCH264BDCompatibleHighProfileLevel41 .equals(transferSyntaxUID)) list.add(MediaTypes.VIDEO_MP4_TYPE); else{ list.addAll(getRenderedImageMediaTypes()); } } else { list.addAll(getRenderedImageMediaTypes()); list.add(MediaTypes.APPLICATION_DICOM_TYPE); } } else if (isSupportedSR(sopClassUID)) { list.add(MediaType.TEXT_HTML_TYPE); list.add(MediaType.TEXT_PLAIN_TYPE); list.add(MediaTypes.APPLICATION_DICOM_TYPE); } else { list.add(MediaTypes.APPLICATION_DICOM_TYPE); if (UID.EncapsulatedPDFStorage.equals(sopClassUID)) list.add(MediaTypes.APPLICATION_PDF_TYPE); else if (UID.EncapsulatedCDAStorage.equals(sopClassUID)) list.add(MediaType.TEXT_XML_TYPE); else{ String encapsulatedMimeType = attrs.getString(Tag.MIMETypeOfEncapsulatedDocument); if (encapsulatedMimeType != null) { MediaType mimeType = MediaType.valueOf(encapsulatedMimeType); list.add(mimeType); } } } return list; } public List<MediaType> getRenderedImageMediaTypes() { return Arrays.asList(MediaTypes.IMAGE_JPEG_TYPE, MediaTypes.IMAGE_GIF_TYPE, MediaTypes.IMAGE_PNG_TYPE); } }