diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractDatasetDownloadServlet.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractDatasetDownloadServlet.java index 65e1eac3e697b93c8423076f9bb1740eeb3c211c..198c558b332c3ce6b2c57f4b304ca42e21100b4c 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractDatasetDownloadServlet.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractDatasetDownloadServlet.java @@ -47,6 +47,7 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.DatasetLocationUtil; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseInstance; @@ -376,29 +377,6 @@ abstract public class AbstractDatasetDownloadServlet extends HttpServlet } } - public static final class Size - { - private final int width; - - private final int height; - - public Size(int width, int height) - { - this.width = width; - this.height = height; - } - - public int getWidth() - { - return width; - } - - public int getHeight() - { - return height; - } - } - protected final File createDataSetRootDirectory(String dataSetCode, HttpSession session) { DatabaseInstance databaseInstance = getDatabaseInstance(session); diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetDownloadServlet.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetDownloadServlet.java index 3810dcb6df5ebbd95f3a53c7c2d7a547899e4220..d84bd2abfd3930439c7ec2fdb0c96341a7ec2eb1 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetDownloadServlet.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetDownloadServlet.java @@ -42,6 +42,7 @@ import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.common.filesystem.FileUtilities; import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData; /** diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/dto/Size.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/dto/Size.java new file mode 100644 index 0000000000000000000000000000000000000000..39830f7d9a808f382f7b78fc4731d0dc9f88925f --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/dto/Size.java @@ -0,0 +1,40 @@ +/* + * Copyright 2010 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.generic.shared.dto; + +public final class Size +{ + private final int width; + + private final int height; + + public Size(int width, int height) + { + this.width = width; + this.height = height; + } + + public int getWidth() + { + return width; + } + + public int getHeight() + { + return height; + } +} \ No newline at end of file diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java index 7e2d3012d9b6c86f1d83028777c9b9420e03250d..6c7b708eb1e7eff5d0cfc3aa7843daa7e3e13132 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/AbsoluteImageReference.java @@ -18,7 +18,7 @@ package ch.systemsx.cisd.openbis.dss.etl; import ch.systemsx.cisd.base.image.IImageTransformerFactory; import ch.systemsx.cisd.common.io.IContent; -import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDatasetDownloadServlet.Size; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent; /** diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/IHCSImageDatasetLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/IHCSImageDatasetLoader.java index 6efe74c9d1cc289a537cce654d8e628fc4f79884..6e1dbfe8de52df0a6fef7e36630f949e7ed6d831 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/IHCSImageDatasetLoader.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/IHCSImageDatasetLoader.java @@ -16,8 +16,8 @@ package ch.systemsx.cisd.openbis.dss.etl; -import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDatasetDownloadServlet.Size; import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelStackReference; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.IHCSDatasetLoader; /** 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 c65d486fc23f74ff63925ab332c9b694723df967..19d0eb0f74846988f72c9d405e29603e9494f56d 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 @@ -22,9 +22,9 @@ import ch.systemsx.cisd.common.io.IContent; 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.ImageChannelStackReference; import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelStackReference.LocationImageChannelStackReference; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.HCSDatasetLoader; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.IImagingReadonlyQueryDAO; 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 67870306f2e194f2694ccb019d2c849f8a19907b..831197d5541ebcae7f82ea050346bc09608b766d 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 @@ -37,7 +37,7 @@ import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.openbis.dss.etl.AbsoluteImageReference; 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.shared.dto.Size; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ColorComponent; diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/TileImageReference.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/TileImageReference.java index e2c45bb876eb318a570858f68ced87d9bbd8cd33..b58411aed2d4765fa8444b1f0ae3811993914c89 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/TileImageReference.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/images/TileImageReference.java @@ -16,7 +16,7 @@ package ch.systemsx.cisd.openbis.dss.generic.server.images; -import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDatasetDownloadServlet.Size; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants; /** @@ -45,28 +45,59 @@ public class TileImageReference return sessionId; } + public final void setSessionId(String sessionId) + { + this.sessionId = sessionId; + } + public String getDatasetCode() { return datasetCode; } + public final void setDatasetCode(String datasetCode) + { + this.datasetCode = datasetCode; + } + public Size tryGetThumbnailSize() { return thumbnailSizeOrNull; } + + public final void setThumbnailSizeOrNull(Size thumbnailSizeOrNull) + { + this.thumbnailSizeOrNull = thumbnailSizeOrNull; + } public boolean isMergeAllChannels() { return mergeAllChannels; } + public final void setMergeAllChannels(boolean mergeAllChannels) + { + this.mergeAllChannels = mergeAllChannels; + } + public String getChannel() { return channel; } + public final void setChannel(String channel) + { + this.channel = channel; + } + public ImageChannelStackReference getChannelStack() { return channelStackReference; } + + public final void setChannelStack(ImageChannelStackReference channelStackReference) + { + this.channelStackReference = channelStackReference; + } + } \ No newline at end of file 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 ead7a1a114cb76881f039a4fb3d2232144e5bb01..cb30794dffc405d207e3c45a0a8669458b922183 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 @@ -41,12 +41,12 @@ import ch.systemsx.cisd.common.io.IContent; import ch.systemsx.cisd.openbis.dss.etl.AbsoluteImageReference; import ch.systemsx.cisd.openbis.dss.etl.HCSImageDatasetLoaderFactory; 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.AbstractDssServiceRpc; import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelStackReference; import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelsUtils; import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.CodeAndLabelUtil; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil; import ch.systemsx.cisd.openbis.dss.screening.shared.api.v1.IDssServiceRpcScreeningInternal; diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtilsTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtilsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..134ec92678ffda96ce380c72bc1af59e603473fe --- /dev/null +++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/ImageChannelsUtilsTest.java @@ -0,0 +1,256 @@ +/* + * Copyright 2010 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.generic.server.images; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.testng.AssertJUnit; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; +import ch.systemsx.cisd.base.image.IImageTransformer; +import ch.systemsx.cisd.base.image.IImageTransformerFactory; +import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; +import ch.systemsx.cisd.common.io.ByteArrayBasedContent; +import ch.systemsx.cisd.common.io.FileBasedContent; +import ch.systemsx.cisd.common.io.IContent; +import ch.systemsx.cisd.openbis.dss.etl.AbsoluteImageReference; +import ch.systemsx.cisd.openbis.dss.etl.IHCSImageDatasetLoader; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.Size; +import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil; + +/** + * + * + * @author Franz-Josef Elmer + */ +public class ImageChannelsUtilsTest extends AssertJUnit +{ + private static final String SESSION_ID = "session-42"; + private static final String DATASET_CODE = "dataset-123"; + + private static final String CHANNEL = "GFP"; + + private static final IImageTransformer TRANSFORMER = new IImageTransformer() + { + public BufferedImage transform(BufferedImage image) + { + int width = image.getWidth(); + int height = image.getHeight(); + BufferedImage output = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < width; x++) + { + for (int y = 0; y < height; y++) + { + int rgb = image.getRGB(x, y); + output.setRGB(x, y, (rgb & 0xff) << 16); + } + } + return output; + } + }; + + private Mockery context; + private IHCSImageDatasetLoader loader; + private File imageFolder; + private IImageTransformerFactory transformerFactory; + + @BeforeMethod + public void setUp() + { + context = new Mockery(); + loader = context.mock(IHCSImageDatasetLoader.class); + transformerFactory = context.mock(IImageTransformerFactory.class); + + imageFolder = new File("../screening/sourceTest/java/" + getClass().getPackage().getName().replace('.', '/')); + } + + @AfterMethod + public void tearDown() + { + // The following line of code should also be called at the end of each test method. + // Otherwise one do not known which test failed. + context.assertIsSatisfied(); + } + + @Test + public void testGetUnkownImage() + { + final TileImageReference imageRef = new TileImageReference(); + imageRef.setChannel(CHANNEL); + imageRef.setDatasetCode(DATASET_CODE); + imageRef.setSessionId(SESSION_ID); + imageRef.setChannelStack(ImageChannelStackReference.createFromId(4711)); + context.checking(new Expectations() + { + { + one(loader) + .tryGetImage(imageRef.getChannel(), imageRef.getChannelStack(), null); + will(returnValue(null)); + } + }); + + try + { + ImageChannelsUtils.getImage(loader, imageRef); + fail("EnvironmentFailureException expected"); + } catch (EnvironmentFailureException ex) + { + assertEquals("No image found for channel stack " + + "ImageChannelStackReference{locationRefOrNull=<null>,idRefOrNull=4711} " + + "and channel GFP", ex.getMessage()); + } + + context.assertIsSatisfied(); + } + + @Test + public void testGetTiffImage() + { + final TileImageReference imageRef = new TileImageReference(); + imageRef.setChannel(CHANNEL); + imageRef.setDatasetCode(DATASET_CODE); + imageRef.setSessionId(SESSION_ID); + imageRef.setChannelStack(ImageChannelStackReference.createFromId(4711)); + context.checking(new Expectations() + { + { + one(loader) + .tryGetImage(imageRef.getChannel(), imageRef.getChannelStack(), null); + will(returnValue(new AbsoluteImageReference( + image("img1.tiff"), "id42", null, null, null))); + } + }); + + IContent image = ImageChannelsUtils.getImage(loader, imageRef); + assertEquals(getImageContentDescription(image("img1.png")), getImageContentDescription(image)); + + context.assertIsSatisfied(); + } + + @Test + public void testGetJpegImageAsPngThumbnail() + { + final TileImageReference imageRef = new TileImageReference(); + imageRef.setChannel(CHANNEL); + imageRef.setDatasetCode(DATASET_CODE); + imageRef.setSessionId(SESSION_ID); + imageRef.setChannelStack(ImageChannelStackReference.createFromId(4711)); + context.checking(new Expectations() + { + { + one(loader) + .tryGetImage(imageRef.getChannel(), imageRef.getChannelStack(), null); + will(returnValue(new AbsoluteImageReference(image("img1.jpg"), "id42", null, + null, new Size(4, 2)))); + } + }); + + IContent image = ImageChannelsUtils.getImage(loader, imageRef); + assertPNG(image); + assertEquals("c4dce6 c5dce4\nc3dbe5 c4dbe3\n", getImageContentDescription(image)); + + context.assertIsSatisfied(); + } + + @Test + public void testGetTransformedImage() + { + final TileImageReference imageRef = new TileImageReference(); + imageRef.setChannel(CHANNEL); + imageRef.setDatasetCode(DATASET_CODE); + imageRef.setSessionId(SESSION_ID); + imageRef.setChannelStack(ImageChannelStackReference.createFromId(4711)); + context.checking(new Expectations() + { + { + one(loader) + .tryGetImage(imageRef.getChannel(), imageRef.getChannelStack(), null); + AbsoluteImageReference imgRef = + new AbsoluteImageReference(image("img1.gif"), "id42", null, null, + null); + imgRef.setTransformerFactory(transformerFactory); + will(returnValue(imgRef)); + + one(transformerFactory).createTransformer(); + will(returnValue(TRANSFORMER)); + } + }); + + IContent image = ImageChannelsUtils.getImage(loader, imageRef); + assertPNG(image); + assertEquals("e50000 f00000 f00000 e40000\n" + "f20000 cf0000 cf0000 f00000\n" + + "f00000 cf0000 cf0000 f00000\n" + "e50000 f00000 f00000 e50000\n", + getImageContentDescription(image)); + + context.assertIsSatisfied(); + } + + public void assertPNG(IContent image) + { + InputStream inputStream = image.getInputStream(); + try + { + byte[] signature = new byte[3]; + inputStream.read(); // skip first byte + inputStream.read(signature); + inputStream.close(); + assertEquals("PNG", new String(signature)); + } catch (IOException ex) + { + throw CheckedExceptionTunnel.wrapIfNecessary(ex); + } finally + { + IOUtils.closeQuietly(inputStream); + } + } + + private IContent image(String fileName) + { + return new FileBasedContent(new File(imageFolder, fileName)); + } + + private String getImageContentDescription(IContent image) + { + BufferedImage bufferedImage = ImageUtil.loadImage(image.getInputStream()); + int width = bufferedImage.getWidth(); + int height = bufferedImage.getHeight(); + StringBuilder builder = new StringBuilder(); + for (int j = 0; j < height; j++) + { + for (int i = 0; i < width; i++) + { + int pixel = bufferedImage.getRGB(i, j); + if (i > 0) + { + builder.append(' '); + } + builder.append(Integer.toHexString(pixel).substring(2)); + } + builder.append('\n'); + } + return builder.toString(); + } +} diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/img1.gif b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/img1.gif new file mode 100644 index 0000000000000000000000000000000000000000..1019a6cc6d9eeea1ba926c5c9a84e3f1afa3f8f5 Binary files /dev/null and b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/img1.gif differ diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/img1.jpg b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/img1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e314cfa75f1dfa61345c23b517e1ddcfdbe8c994 Binary files /dev/null and b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/img1.jpg differ diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/img1.png b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/img1.png new file mode 100644 index 0000000000000000000000000000000000000000..e5ac76d2cfaf1df79d203679888029a10be00e88 Binary files /dev/null and b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/img1.png differ diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/img1.tiff b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/img1.tiff new file mode 100644 index 0000000000000000000000000000000000000000..b82e58a4f8aea671a59b0d9432c5cd00658bab17 Binary files /dev/null and b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/images/img1.tiff differ