/*******************************************************************************
* 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.io.IOException;
import java.net.URI;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import org.dcm4che3.data.ItemPointer;
import org.dcm4che3.data.Tag;
import org.dcm4che3.data.VR;
import org.dcm4che3.imageio.plugins.rle.RLEImageReaderSpi;
import org.dcm4che3.io.BulkDataDescriptor;
import org.dcm4che3.util.TagUtils;
import org.dcm4che3.util.UIDUtils;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.weasis.core.api.media.data.Codec;
import org.weasis.core.api.media.data.MediaReader;
import org.weasis.core.api.service.AuditLog;
import org.weasis.core.api.service.BundlePreferences;
import org.weasis.core.api.service.BundleTools;
import com.sun.media.imageioimpl.common.ImageioUtil;
@org.osgi.service.component.annotations.Component(service = Codec.class, immediate = false)
public class DicomCodec implements Codec {
private static final Logger LOGGER = LoggerFactory.getLogger(DicomCodec.class);
public static final String NAME = "dcm4che"; //$NON-NLS-1$
public static final String[] FILE_EXTENSIONS = { "dcm", "dicm" }; //$NON-NLS-1$ //$NON-NLS-2$
private static final String LOGGER_KEY = "always.info.ItemParser"; //$NON-NLS-1$
private static final String LOGGER_VAL = "org.dcm4che3.imageio.ItemParser"; //$NON-NLS-1$
public static final BulkDataDescriptor BULKDATA_DESCRIPTOR = new BulkDataDescriptor() {
@Override
public boolean isBulkData(List<ItemPointer> itemPointer, String privateCreator, int tag, VR vr, int length) {
switch (TagUtils.normalizeRepeatingGroup(tag)) {
case Tag.PixelDataProviderURL:
case Tag.AudioSampleData:
case Tag.CurveData:
case Tag.SpectroscopyData:
case Tag.OverlayData:
case Tag.EncapsulatedDocument:
case Tag.FloatPixelData:
case Tag.DoubleFloatPixelData:
case Tag.PixelData:
return itemPointer.isEmpty();
case Tag.WaveformData:
return itemPointer.size() == 1 && itemPointer.get(0).sequenceTag == Tag.WaveformSequence;
}
if (TagUtils.isPrivateTag(tag)) {
return length > 5000; // Do no read in memory private value more than 5 KB
}
switch (vr) {
case OB:
case OD:
case OF:
case OL:
case OW:
case UN:
return length > 64;
}
return false;
}
};
private final RLEImageReaderSpi rleImageReaderSpi = new RLEImageReaderSpi();
// private final DicomImageWriterSpi DicomImageWriterSpi = new DicomImageWriterSpi();
// private final RawImageReaderSpi RawImageReaderSpi = new RawImageReaderSpi();
@Override
public String[] getReaderMIMETypes() {
return new String[] { DicomMediaIO.MIMETYPE, DicomMediaIO.SERIES_XDSI, DicomMediaIO.IMAGE_MIMETYPE,
DicomMediaIO.SERIES_VIDEO_MIMETYPE, DicomMediaIO.SERIES_ENCAP_DOC_MIMETYPE };
}
@Override
public String[] getReaderExtensions() {
return FILE_EXTENSIONS;
}
@Override
public boolean isMimeTypeSupported(String mimeType) {
if (mimeType != null) {
for (String mime : getReaderMIMETypes()) {
if (mimeType.equals(mime)) {
return true;
}
}
}
return false;
}
@Override
public MediaReader getMediaIO(URI media, String mimeType, Hashtable<String, Object> properties) {
if (isMimeTypeSupported(mimeType)) {
return new DicomMediaIO(media);
}
return null;
}
@Override
public String getCodecName() {
return NAME;
}
@Override
public String[] getWriterExtensions() {
return FILE_EXTENSIONS;
}
@Override
public String[] getWriterMIMETypes() {
return new String[] { DicomMediaIO.MIMETYPE };
}
// ================================================================================
// OSGI service implementation
// ================================================================================
@Activate
protected void activate(ComponentContext context) {
LOGGER.info("Activate DicomCodec"); //$NON-NLS-1$
/**
* Set value for dicom root UID which should be registered at the
* http://www.iana.org/assignments/enterprise-numbers <br>
* Default value is 2.25, this enables users to generate OIDs without any registration procedure
*
* @see http://www.dclunie.com/medical-image-faq/html/part2.html#UUID <br>
* http://www.oid-info.com/get/2.25 <br>
* http://www.itu.int/ITU-T/asn1/uuid.html<br>
* http://healthcaresecprivacy.blogspot.ch/2011/02/creating-and-using-unique-id-uuid-oid.html
*/
String weasisRootUID = BundleTools.SYSTEM_PREFERENCES.getProperty("weasis.dicom.root.uid", UIDUtils.getRoot()); //$NON-NLS-1$
UIDUtils.setRoot(weasisRootUID);
// Register SPI in imageio registry with the classloader of this bundle (provides also the classpath for
// discovering the SPI files). Here are the codecs:
// org.dcm4che3.imageioimpl.plugins.rle.RLEImageReaderSpi
// org.dcm4che3.imageioimpl.plugins.dcm.DicomImageReaderSpi
// org.dcm4che3.imageioimpl.plugins.dcm.DicomImageWriterSpi
ImageioUtil.registerServiceProvider(rleImageReaderSpi);
ImageioUtil.registerServiceProvider(DicomMediaIO.dicomImageReaderSpi);
ConfigurationAdmin confAdmin =
BundlePreferences.getService(context.getBundleContext(), ConfigurationAdmin.class);
if (confAdmin != null) {
try {
Configuration logConfiguration = AuditLog.getLogConfiguration(confAdmin, LOGGER_KEY, LOGGER_VAL);
if (logConfiguration == null) {
logConfiguration = confAdmin
.createFactoryConfiguration("org.apache.sling.commons.log.LogManager.factory.config", null); //$NON-NLS-1$
Dictionary<String, Object> loggingProperties = new Hashtable<>();
loggingProperties.put("org.apache.sling.commons.log.level", "INFO"); //$NON-NLS-1$ //$NON-NLS-2$
loggingProperties.put("org.apache.sling.commons.log.names", LOGGER_VAL); //$NON-NLS-1$
// add this property to give us something unique to re-find this configuration
loggingProperties.put(LOGGER_KEY, LOGGER_VAL);
logConfiguration.update(loggingProperties);
}
} catch (IOException e) {
LOGGER.error("", e); //$NON-NLS-1$
}
}
}
@Deactivate
protected void deactivate(ComponentContext context) {
LOGGER.info("Deactivate DicomCodec"); //$NON-NLS-1$
ImageioUtil.deregisterServiceProvider(rleImageReaderSpi);
ImageioUtil.deregisterServiceProvider(DicomMediaIO.dicomImageReaderSpi);
}
@Reference(service = DicomSpecialElementFactory.class, cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, unbind = "removeDicomSpecialElementFactory")
void addDicomSpecialElementFactory(DicomSpecialElementFactory factory) {
String name = factory.getClass().getName();
for (String modality : factory.getModalities()) {
DicomSpecialElementFactory prev = DicomMediaIO.DCM_ELEMENT_FACTORIES.put(modality, factory);
if (prev != null) {
LOGGER.warn("{} factory has been replaced by {}", prev.getClass().getName(), name); //$NON-NLS-1$
}
LOGGER.info("Register DicomSpecialElementFactory: {} => {}", modality, name); //$NON-NLS-1$
}
}
void removeDicomSpecialElementFactory(DicomSpecialElementFactory factory) {
String name = factory.getClass().getName();
for (String modality : factory.getModalities()) {
DicomSpecialElementFactory f = DicomMediaIO.DCM_ELEMENT_FACTORIES.get(modality);
if (factory.equals(f)) {
DicomMediaIO.DCM_ELEMENT_FACTORIES.remove(modality);
LOGGER.info("Unregister DicomSpecialElementFactory: {} => {}", modality, name); //$NON-NLS-1$
} else {
LOGGER.warn("{}: Unregistering {} has no effect, {} is registered instead", modality, name, //$NON-NLS-1$
f.getClass().getName());
}
}
}
}