diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractDssServiceRpc.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractDssServiceRpc.java index 4ef88f85c215824b8fb921ed230481618e818e08..3a88d1913ef84c3a71a0b7ccfedaa7f5e6890af2 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractDssServiceRpc.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractDssServiceRpc.java @@ -135,9 +135,9 @@ public abstract class AbstractDssServiceRpc /** * Asserts that specified data sets are all accessible by the user of the specified session. */ - protected void assertDatasetsAreAccessible(String sessionToken, List<String> dataSetCodes) + protected void checkDatasetsAuthorization(String sessionToken, List<String> dataSetCodes) { - if (areDatasetsAccessible(sessionToken, dataSetCodes) == false) + if (isSessionAuthorizedForDatasets(sessionToken, dataSetCodes) == false) { throw new IllegalArgumentException( "User is not allowed to access at least one of the following data sets: " @@ -153,7 +153,7 @@ public abstract class AbstractDssServiceRpc * @param dataSetCodes The data set codes we want to check access for. * @return True if all the data sets are accessible, false if one or more are not accessible. */ - protected boolean areDatasetsAccessible(String sessionToken, List<String> dataSetCodes) + protected boolean isSessionAuthorizedForDatasets(String sessionToken, List<String> dataSetCodes) { boolean access; if (operationLog.isInfoEnabled()) @@ -201,7 +201,7 @@ public abstract class AbstractDssServiceRpc protected Map<String, File> checkAccessAndGetRootDirectories(String sessionToken, List<String> dataSetCodes) throws IllegalArgumentException { - if (areDatasetsAccessible(sessionToken, dataSetCodes) == false) + if (isSessionAuthorizedForDatasets(sessionToken, dataSetCodes) == false) { throw new IllegalArgumentException("Path does not exist."); } diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/HCSImageDatasetLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/HCSImageDatasetLoader.java index ec93ee30c00da85bb7930d8780050d4c53b995f2..4cf24d106f04f919137f3d8c4f9c51eb00eff352 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/HCSImageDatasetLoader.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dataaccess/HCSImageDatasetLoader.java @@ -26,13 +26,21 @@ import javax.imageio.ImageIO; import org.apache.commons.lang.StringUtils; +import com.sun.media.jai.codec.ImageCodec; +import com.sun.media.jai.codec.ImageEncoder; +import com.sun.media.jai.codec.TIFFEncodeParam; + import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; import ch.systemsx.cisd.bds.hcs.Location; +import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; +import ch.systemsx.cisd.common.io.ByteArrayBasedContent; import ch.systemsx.cisd.common.io.IContent; +import ch.systemsx.cisd.common.utilities.DataTypeUtil; import ch.systemsx.cisd.openbis.dss.etl.AbsoluteImageReference; import ch.systemsx.cisd.openbis.dss.etl.IContentRepository; import ch.systemsx.cisd.openbis.dss.etl.IHCSImageDatasetLoader; import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDatasetDownloadServlet.Size; +import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelsUtils; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.HCSDatasetLoader; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImagingQueryDAO; @@ -106,6 +114,21 @@ public class HCSImageDatasetLoader extends HCSDatasetLoader implements IHCSImage if (imageDTO != null) { content = contentRepository.getContent(imageDTO.getFilePath()); + final InputStream is = content.getInputStream(); + final String fileType = DataTypeUtil.tryToFigureOutFileTypeOf(is); + if (DataTypeUtil.isTiff(fileType) == false || imageDTO.getColorComponent() != null + || imageDTO.getPage() != null) + { + final int page = (imageDTO.getPage() != null) ? imageDTO.getPage() : 0; + BufferedImage image = ImageUtil.loadImage(is, fileType, page); + if (imageDTO.getColorComponent() != null) + { + image = + ImageChannelsUtils.transformToChannel(image, imageDTO + .getColorComponent()); + } + content = asContent(image, fileType, content.getName(), content.getUniqueId()); + } } } if (content != null && imageDTO != null) @@ -118,6 +141,29 @@ public class HCSImageDatasetLoader extends HCSDatasetLoader implements IHCSImage } } + private static IContent asContent(BufferedImage image, String fileType, String name, String id) + { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final TIFFEncodeParam param = new TIFFEncodeParam(); + param.setLittleEndian(true); + if (DataTypeUtil.isJpeg(fileType)) + { + param.setCompression(TIFFEncodeParam.COMPRESSION_JPEG_TTN2); + } else + { + param.setCompression(TIFFEncodeParam.COMPRESSION_DEFLATE); + } + final ImageEncoder enc = ImageCodec.createImageEncoder("tiff", out, param); + try + { + enc.encode(image); + return new ByteArrayBasedContent(out.toByteArray(), name, id); + } catch (IOException ex) + { + throw EnvironmentFailureException.fromTemplate("Cannot encode image.", ex); + } + } + private static final class ThumbnailContent implements IContent { private final IContent content; @@ -166,6 +212,7 @@ public class HCSImageDatasetLoader extends HCSDatasetLoader implements IHCSImage { return content.getUniqueId(); } + } } \ No newline at end of file diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java index 649a762c2f5c223fc1c142fdbe51584a53b59c67..c0a27640060a339101572332e3b0db8b9cb2b195 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtils.java @@ -18,7 +18,9 @@ package ch.systemsx.cisd.openbis.dss.generic.server.images; import java.awt.Color; import java.awt.image.BufferedImage; +import java.awt.image.RenderedImage; import java.io.File; +import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -82,9 +84,18 @@ public class ImageChannelsUtils */ public static BufferedImage mergeImageChannels(TileImageReference params, List<AbsoluteImageReference> imageReferences) + { + return mergeImageChannels(imageReferences, params.isMergeAllChannels()); + } + + /** + * Creates an images of the specified tile and with requested channels merged.<br> + */ + public static BufferedImage mergeImageChannels(List<AbsoluteImageReference> imageReferences, + boolean mergeChannels) { BufferedImage resultImage; - if (params.isMergeAllChannels()) + if (mergeChannels) { resultImage = mergeAllChannels(imageReferences); } else @@ -93,16 +104,26 @@ public class ImageChannelsUtils + "but more have been specified: " + imageReferences; AbsoluteImageReference imageReference = imageReferences.get(0); - resultImage = selectSingleChannel(params, imageReference); + resultImage = selectSingleChannel(imageReference); } return resultImage; } - private static BufferedImage selectSingleChannel(TileImageReference params, - AbsoluteImageReference imageReference) + /** + * Reads the given content and selects a single channel from it. + */ + public static BufferedImage selectSingleChannel(AbsoluteImageReference imageReference) + { + return selectSingleChannel(imageReference.getContent().getInputStream(), imageReference + .tryGetColorComponent()); + } + + /** + * Reads the given content and selects a single channel from it. + */ + public static BufferedImage selectSingleChannel(InputStream input, ColorComponent colorComponent) { - BufferedImage image = ImageUtil.loadImage(imageReference.getContent().getInputStream()); - ColorComponent colorComponent = imageReference.tryGetColorComponent(); + BufferedImage image = ImageUtil.loadImage(input); if (colorComponent == null) { // TODO 2010-06-15 Izabela Adamczyk: We have to select a single channel from the (most @@ -238,7 +259,10 @@ public class ImageChannelsUtils } } - private static BufferedImage transformToChannel(BufferedImage bufferedImage, + /** + * Transforms the given <var>bufferedImage</var> as + */ + public static BufferedImage transformToChannel(BufferedImage bufferedImage, ColorComponent colorComponent) { BufferedImage newImage = createNewImage(bufferedImage); @@ -256,7 +280,7 @@ public class ImageChannelsUtils return newImage; } - private static BufferedImage createNewImage(BufferedImage bufferedImage) + private static BufferedImage createNewImage(RenderedImage bufferedImage) { BufferedImage newImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java index f1970227f39756dbdca595dd1e62c1a748fa24c9..c1c0e96785444139a13915207f5215d4bbbe4d96 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java @@ -77,7 +77,7 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements /** * The minor version of this service. */ - private static final int MINOR_VERSION = 1; + public static final int MINOR_VERSION = 1; private IImagingQueryDAO dao; @@ -114,7 +114,7 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements public List<String> listAvailableFeatureNames(String sessionToken, List<? extends IFeatureVectorDatasetIdentifier> featureDatasets) { - assertDataSetsAreAccessible(sessionToken, featureDatasets); + checkDatasetsAuthorizationForIDatasetIdentifier(sessionToken, featureDatasets); List<String> result = new ArrayList<String>(); // keep the order for (IFeatureVectorDatasetIdentifier identifier : featureDatasets) { @@ -135,6 +135,7 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements public List<ImageDatasetMetadata> listImageMetadata(String sessionToken, List<? extends IImageDatasetIdentifier> imageDatasets) { + checkDatasetsAuthorizationForIDatasetIdentifier(sessionToken, imageDatasets); ArrayList<String> datasetCodes = new ArrayList<String>(); for (IImageDatasetIdentifier dataset : imageDatasets) { @@ -194,7 +195,7 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements public List<FeatureVectorDataset> loadFeatures(String sessionToken, List<FeatureVectorDatasetReference> featureDatasets, List<String> featureNames) { - assertDataSetsAreAccessible(sessionToken, featureDatasets); + checkDatasetsAuthorizationForIDatasetIdentifier(sessionToken, featureDatasets); List<FeatureVectorDataset> result = new ArrayList<FeatureVectorDataset>(); for (FeatureVectorDatasetReference dataset : featureDatasets) { @@ -224,7 +225,7 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements String sessionToken, List<FeatureVectorDatasetWellReference> datasetWellReferences, List<String> featureNames) { - assertDataSetsAreAccessible(sessionToken, datasetWellReferences); + checkDatasetsAuthorizationForIDatasetIdentifier(sessionToken, datasetWellReferences); final FeatureTableBuilder builder = createFeatureTableBuilder(datasetWellReferences, featureNames); return createFeatureVectorList(builder); @@ -265,26 +266,19 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements public InputStream loadImages(String sessionToken, List<PlateImageReference> imageReferences) { - Map<String, IHCSImageDatasetLoader> imageLoadersMap = + checkDatasetsAuthorizationForIDatasetIdentifier(sessionToken, imageReferences); + final Map<String, IHCSImageDatasetLoader> imageLoadersMap = getImageDatasetsMap(sessionToken, imageReferences); - List<IContent> imageFiles = new ArrayList<IContent>(); + final List<IContent> imageFiles = new ArrayList<IContent>(); try { for (PlateImageReference imageReference : imageReferences) { - IHCSImageDatasetLoader imageAccessor = + final IHCSImageDatasetLoader imageAccessor = imageLoadersMap.get(imageReference.getDatasetCode()); assert imageAccessor != null : "imageAccessor not found for: " + imageReference; - AbsoluteImageReference image = tryGetImage(imageAccessor, imageReference); - if (image == null - || (image.tryGetColorComponent() != null || image.tryGetPage() != null)) - { - // TODO 2010-06-01, Tomasz Pylak: support paging/merged channels images in API - imageFiles.add(null); - } else - { - imageFiles.add(image.getContent()); - } + final AbsoluteImageReference imageRef = tryGetImage(imageAccessor, imageReference); + imageFiles.add((imageRef == null) ? null : imageRef.getContent()); } } finally { @@ -340,6 +334,7 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements .getChannel(), null); } catch (EnvironmentFailureException e) { + operationLog.error("Error reading image.", e); return null; // no image found } } @@ -412,7 +407,7 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements return getDAO().listFeatureDefsByDataSetId(dataSet.getId()); } - private void assertDataSetsAreAccessible(String sessionToken, + private void checkDatasetsAuthorizationForIDatasetIdentifier(String sessionToken, List<? extends IDatasetIdentifier> identifiers) { List<String> dataSetCodes = new ArrayList<String>(); @@ -420,7 +415,7 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements { dataSetCodes.add(identifier.getDatasetCode()); } - assertDatasetsAreAccessible(sessionToken, dataSetCodes); + checkDatasetsAuthorization(sessionToken, dataSetCodes); } private IImagingQueryDAO getDAO()