diff --git a/common/resource/test-data/DataTypeUtilTest/gif-example.gif b/common/resource/test-data/DataTypeUtilTest/gif-example.gif deleted file mode 100644 index a089c5480ead7c72db8decb183d778ecc4d88613..0000000000000000000000000000000000000000 Binary files a/common/resource/test-data/DataTypeUtilTest/gif-example.gif and /dev/null differ diff --git a/common/resource/test-data/DataTypeUtilTest/jpeg-example.jpg b/common/resource/test-data/DataTypeUtilTest/jpeg-example.jpg deleted file mode 100644 index fa97090568b41105877fbaf52def668f196271f0..0000000000000000000000000000000000000000 Binary files a/common/resource/test-data/DataTypeUtilTest/jpeg-example.jpg and /dev/null differ diff --git a/common/resource/test-data/DataTypeUtilTest/png-example.png b/common/resource/test-data/DataTypeUtilTest/png-example.png deleted file mode 100644 index 610fe3d7e0f3bf4a722f6477690ec437b6b4cf82..0000000000000000000000000000000000000000 Binary files a/common/resource/test-data/DataTypeUtilTest/png-example.png and /dev/null differ diff --git a/common/resource/test-data/DataTypeUtilTest/tiff-example.tiff b/common/resource/test-data/DataTypeUtilTest/tiff-example.tiff deleted file mode 100644 index d13e812def95446be2d7e038848e5de20a2501c7..0000000000000000000000000000000000000000 Binary files a/common/resource/test-data/DataTypeUtilTest/tiff-example.tiff and /dev/null differ diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/DataTypeUtil.java b/common/source/java/ch/systemsx/cisd/common/utilities/DataTypeUtil.java deleted file mode 100644 index 22ffcdf5e0dd33d4285fdc4a493b5240378842fb..0000000000000000000000000000000000000000 --- a/common/source/java/ch/systemsx/cisd/common/utilities/DataTypeUtil.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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.common.utilities; - -import ch.systemsx.cisd.base.io.IRandomAccessFile; - -/** - * Utility methods about the type of (binary) data. - * - * @author Franz-Josef Elmer - */ -public class DataTypeUtil -{ - public static final String TIFF_FILE = "tif"; - - public static final String PNG_FILE = "png"; - - public static final String JPEG_FILE = "jpg"; - - public static final String GIF_FILE = "gif"; - - private static final class MagicNumber - { - private final String fileType; - - private final String[] magicHexNumbers; - - private final int maxLength; - - MagicNumber(String fileType, String... magicHexNumbers) - { - this.fileType = fileType; - this.magicHexNumbers = magicHexNumbers; - int length = 0; - for (String magicNumber : magicHexNumbers) - { - length = Math.max(length, magicNumber.length()); - } - maxLength = length / 2; - } - - public String getFileType() - { - return fileType; - } - - int getMaxLength() - { - return maxLength; - } - - public boolean matches(byte[] bytes) - { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < maxLength; i++) - { - byte b = bytes[i]; - builder.append(Integer.toHexString((b >> 4) & 0xf)); - builder.append(Integer.toHexString(b & 0xf)); - } - String initialBytes = builder.toString().toLowerCase(); - for (String magicNumber : magicHexNumbers) - { - if (initialBytes.startsWith(magicNumber)) - { - return true; - } - } - return false; - } - } - - private static final class MagicNumbersManager - { - private final MagicNumber[] magicNumbers; - - MagicNumbersManager(MagicNumber... magicNumbers) - { - this.magicNumbers = magicNumbers; - } - - int getMaxLength() - { - int max = 0; - for (MagicNumber magicNumber : magicNumbers) - { - max = Math.max(max, magicNumber.getMaxLength()); - } - return max; - } - - String tryToFigureOutFileTypeOf(byte[] initialBytes) - { - for (MagicNumber magicNumber : magicNumbers) - { - if (magicNumber.matches(initialBytes)) - { - return magicNumber.getFileType(); - } - } - return null; - } - } - - private static final MagicNumbersManager MAGIC_NUMBERS_MANAGER = - new MagicNumbersManager(new MagicNumber(GIF_FILE, "474946383961", "474946383761"), - new MagicNumber(JPEG_FILE, "ffd8ff"), new MagicNumber(PNG_FILE, - "89504e470d0a1a0a"), new MagicNumber(TIFF_FILE, "49492a00", "4d4d002a")); - - /** - * Tries to figure out the file type of the specified binary content. It uses the first few - * bytes as a finger print (so-called 'magic numbers') as a heuristic to get the type of - * content. Currently only the following types are recognized: <code>gif, jpg, png, tif</code>. - * - * @param handle {@link IRandomAccessFile} which supports marking. - * @return <code>null</code> if file type couldn't be figured out. - */ - public static String tryToFigureOutFileTypeOf(IRandomAccessFile handle) - { - if (handle.markSupported() == false) - { - throw new IllegalArgumentException("Input stream does not support marking. " - + "Wrap input stream with a BufferedInputStream to solve the problem."); - } - int maxLength = MAGIC_NUMBERS_MANAGER.getMaxLength(); - handle.mark(maxLength); - byte[] initialBytes = new byte[maxLength]; - handle.read(initialBytes); - handle.reset(); - return MAGIC_NUMBERS_MANAGER.tryToFigureOutFileTypeOf(initialBytes); - } - - /** - * Returns <code>true</code> if the <var>fileTypeOrNull</var> is a tiff file. - */ - public static boolean isTiff(String fileTypeOrNull) - { - return TIFF_FILE.equals(fileTypeOrNull); - } - - /** - * Returns <code>true</code> if the <var>fileTypeOrNull</var> is a jpeg file. - */ - public static boolean isJpeg(String fileTypeOrNull) - { - return JPEG_FILE.equals(fileTypeOrNull); - } - - /** - * Returns <code>true</code> if the <var>fileTypeOrNull</var> is a png file. - */ - public static boolean isPng(String fileTypeOrNull) - { - return PNG_FILE.equals(fileTypeOrNull); - } - - /** - * Returns <code>true</code> if the <var>fileTypeOrNull</var> is a gif file. - */ - public static boolean isGif(String fileTypeOrNull) - { - return GIF_FILE.equals(fileTypeOrNull); - } - - private DataTypeUtil() - { - } -} diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/DataTypeUtilTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/DataTypeUtilTest.java deleted file mode 100644 index f2c2a3298aa36fdb600e539e325de1bb28fa37dd..0000000000000000000000000000000000000000 --- a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/DataTypeUtilTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.common.utilities; - -import java.io.File; - -import org.testng.AssertJUnit; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import ch.systemsx.cisd.base.io.ByteBufferRandomAccessFile; -import ch.systemsx.cisd.base.io.RandomAccessFileImpl; - -/** - * - * - * @author Franz-Josef Elmer - */ -public class DataTypeUtilTest extends AssertJUnit -{ - private File dir; - - @BeforeMethod - public void setUp() - { - dir = new File("resource/test-data/DataTypeUtilTest"); - } - - @Test - public void testGif() throws Exception - { - assertFileType("gif", "gif-example.gif"); - } - - @Test - public void testJpg() throws Exception - { - assertFileType("jpg", "jpeg-example.jpg"); - } - - @Test - public void testPng() throws Exception - { - assertFileType("png", "png-example.png"); - } - - @Test - public void testTiff() throws Exception - { - assertFileType("tif", "tiff-example.tiff"); - } - - @Test - public void testFileContainingOnlyOneUmlaut() throws Exception - { - assertFileType(null, "one-umlaut.txt"); - } - - @Test - public void testMarkUnsupportedInputStream() - { - try - { - DataTypeUtil.tryToFigureOutFileTypeOf(new ByteBufferRandomAccessFile(1) - { - @Override - public boolean markSupported() - { - return false; - } - }); - fail("IllegalArgumentException expected"); - } catch (IllegalArgumentException ex) - { - assertEquals("Input stream does not support marking. " - + "Wrap input stream with a BufferedInputStream to solve the problem.", - ex.getMessage()); - } - } - - @Test - public void testInputStreamAtTheBeginning() throws Exception - { - byte[] bytes = "hello world".getBytes(); - ByteBufferRandomAccessFile buffer = new ByteBufferRandomAccessFile(bytes); - - DataTypeUtil.tryToFigureOutFileTypeOf(buffer); - - assertEquals(0, buffer.getFilePointer()); - } - - private void assertFileType(String expectedFileType, String fileName) throws Exception - { - RandomAccessFileImpl handle = null; - try - { - handle = new RandomAccessFileImpl(new File(dir, fileName), "r"); - String type = DataTypeUtil.tryToFigureOutFileTypeOf(handle); - - assertEquals(expectedFileType, type); - } finally - { - closeQuetly(handle); - } - - } - - private void closeQuetly(RandomAccessFileImpl handle) - { - try { - handle.close(); - } catch (Exception ex) - { - // keep quiet - } - - } -} diff --git a/common/resource/test-data/DataTypeUtilTest/one-umlaut.txt b/datastore_server/resource/test-data/ImageUtilTest/one-umlaut.txt similarity index 100% rename from common/resource/test-data/DataTypeUtilTest/one-umlaut.txt rename to datastore_server/resource/test-data/ImageUtilTest/one-umlaut.txt diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtil.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtil.java index aeda19fb78d638219056e54d55e7151a598c9fd8..a68f7dea7ee96d0051defcf38742cddaebeb8e08 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtil.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtil.java @@ -16,11 +16,6 @@ package ch.systemsx.cisd.openbis.dss.generic.shared.utils; -import static ch.systemsx.cisd.common.utilities.DataTypeUtil.GIF_FILE; -import static ch.systemsx.cisd.common.utilities.DataTypeUtil.JPEG_FILE; -import static ch.systemsx.cisd.common.utilities.DataTypeUtil.PNG_FILE; -import static ch.systemsx.cisd.common.utilities.DataTypeUtil.TIFF_FILE; - import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.RenderingHints; @@ -58,7 +53,6 @@ import ch.systemsx.cisd.common.io.FileBasedContentNode; import ch.systemsx.cisd.common.io.hierarchical_content.api.IHierarchicalContentNode; import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; -import ch.systemsx.cisd.common.utilities.DataTypeUtil; import ch.systemsx.cisd.imagereaders.IImageReader; import ch.systemsx.cisd.imagereaders.IReadParams; import ch.systemsx.cisd.imagereaders.ImageID; @@ -72,6 +66,14 @@ import ch.systemsx.cisd.imagereaders.ImageReaderFactory; */ public class ImageUtil { + public static final String TIFF_FILE = "tif"; + + public static final String PNG_FILE = "png"; + + public static final String JPEG_FILE = "jpg"; + + public static final String GIF_FILE = "gif"; + /** * When a grayscale image with color depth > 8 bits has to be displayed and user has not decided * how it should be converted, then this threshold will be used. @@ -90,6 +92,94 @@ public class ImageUtil public Dimension readDimension(IRandomAccessFile handle, ImageID imageID); } + private static final class MagicNumber + { + private final String fileType; + + private final String[] magicHexNumbers; + + private final int maxLength; + + MagicNumber(String fileType, String... magicHexNumbers) + { + this.fileType = fileType; + this.magicHexNumbers = magicHexNumbers; + int length = 0; + for (String magicNumber : magicHexNumbers) + { + length = Math.max(length, magicNumber.length()); + } + maxLength = length / 2; + } + + public String getFileType() + { + return fileType; + } + + int getMaxLength() + { + return maxLength; + } + + public boolean matches(byte[] bytes) + { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < maxLength; i++) + { + byte b = bytes[i]; + builder.append(Integer.toHexString((b >> 4) & 0xf)); + builder.append(Integer.toHexString(b & 0xf)); + } + String initialBytes = builder.toString().toLowerCase(); + for (String magicNumber : magicHexNumbers) + { + if (initialBytes.startsWith(magicNumber)) + { + return true; + } + } + return false; + } + } + + private static final class MagicNumbersManager + { + private final MagicNumber[] magicNumbers; + + MagicNumbersManager(MagicNumber... magicNumbers) + { + this.magicNumbers = magicNumbers; + } + + int getMaxLength() + { + int max = 0; + for (MagicNumber magicNumber : magicNumbers) + { + max = Math.max(max, magicNumber.getMaxLength()); + } + return max; + } + + String tryToFigureOutFileTypeOf(byte[] initialBytes) + { + for (MagicNumber magicNumber : magicNumbers) + { + if (magicNumber.matches(initialBytes)) + { + return magicNumber.getFileType(); + } + } + return null; + } + } + + private static final MagicNumbersManager MAGIC_NUMBERS_MANAGER = + new MagicNumbersManager(new MagicNumber(GIF_FILE, "474946383961", "474946383761"), + new MagicNumber(JPEG_FILE, "ffd8ff"), new MagicNumber(PNG_FILE, + "89504e470d0a1a0a"), new MagicNumber(TIFF_FILE, "49492a00", "4d4d002a")); + private static final class TiffImageLoader implements ImageLoader { private final static int MAX_READ_AHEAD = 30000000; @@ -565,7 +655,7 @@ public class ImageUtil ImageID imageID) { IRandomAccessFile handle = contentNode.getFileContent(); - String fileType = DataTypeUtil.tryToFigureOutFileTypeOf(handle); + String fileType = tryToFigureOutFileTypeOf(handle); return loadImageGuessingLibrary(handle, fileType, imageID); } @@ -573,7 +663,7 @@ public class ImageUtil IHierarchicalContentNode contentNode, ImageID imageID) { IRandomAccessFile handle = contentNode.getFileContent(); - String fileType = DataTypeUtil.tryToFigureOutFileTypeOf(handle); + String fileType = tryToFigureOutFileTypeOf(handle); return loadImageDimensionGuessingLibrary(handle, fileType, imageID); } @@ -809,4 +899,59 @@ public class ImageUtil } } + /** + * Tries to figure out the file type of the specified binary content. It uses the first few + * bytes as a finger print (so-called 'magic numbers') as a heuristic to get the type of + * content. Currently only the following types are recognized: <code>gif, jpg, png, tif</code>. + * + * @param handle {@link IRandomAccessFile} which supports marking. + * @return <code>null</code> if file type couldn't be figured out. + */ + public static String tryToFigureOutFileTypeOf(IRandomAccessFile handle) + { + if (handle.markSupported() == false) + { + throw new IllegalArgumentException("Input stream does not support marking. " + + "Wrap input stream with a BufferedInputStream to solve the problem."); + } + int maxLength = MAGIC_NUMBERS_MANAGER.getMaxLength(); + handle.mark(maxLength); + byte[] initialBytes = new byte[maxLength]; + handle.read(initialBytes); + handle.reset(); + return MAGIC_NUMBERS_MANAGER.tryToFigureOutFileTypeOf(initialBytes); + } + + /** + * Returns <code>true</code> if the <var>fileTypeOrNull</var> is a tiff file. + */ + public static boolean isTiff(String fileTypeOrNull) + { + return TIFF_FILE.equals(fileTypeOrNull); + } + + /** + * Returns <code>true</code> if the <var>fileTypeOrNull</var> is a jpeg file. + */ + public static boolean isJpeg(String fileTypeOrNull) + { + return JPEG_FILE.equals(fileTypeOrNull); + } + + /** + * Returns <code>true</code> if the <var>fileTypeOrNull</var> is a png file. + */ + public static boolean isPng(String fileTypeOrNull) + { + return PNG_FILE.equals(fileTypeOrNull); + } + + /** + * Returns <code>true</code> if the <var>fileTypeOrNull</var> is a gif file. + */ + public static boolean isGif(String fileTypeOrNull) + { + return GIF_FILE.equals(fileTypeOrNull); + } + } diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtilTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtilTest.java index 06f909c7c68ad359492a8135fb78e191a3154ba2..6e4c97203f632f4bc32ddb0b671f786456ef6464 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtilTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtilTest.java @@ -29,6 +29,7 @@ import ch.rinn.restrictions.Friend; import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked; import ch.systemsx.cisd.base.io.ByteBufferRandomAccessFile; import ch.systemsx.cisd.base.io.IRandomAccessFile; +import ch.systemsx.cisd.base.io.RandomAccessFileImpl; import ch.systemsx.cisd.common.io.FileBasedContentNode; import ch.systemsx.cisd.common.io.hierarchical_content.api.IHierarchicalContentNode; import ch.systemsx.cisd.imagereaders.ImageReaderConstants; @@ -240,4 +241,94 @@ public class ImageUtilTest extends AssertJUnit return ImageUtil.loadImage(content); } + @Test + public void testGif() throws Exception + { + assertFileType("gif", "gif-example.gif"); + } + + @Test + public void testJpg() throws Exception + { + assertFileType("jpg", "jpeg-example.jpg"); + } + + @Test + public void testPng() throws Exception + { + assertFileType("png", "png-example.png"); + } + + @Test + public void testTiff() throws Exception + { + assertFileType("tif", "tiff-example.tiff"); + } + + @Test + public void testFileContainingOnlyOneUmlaut() throws Exception + { + assertFileType(null, "one-umlaut.txt"); + } + + @Test + public void testMarkUnsupportedInputStream() + { + try + { + ImageUtil.tryToFigureOutFileTypeOf(new ByteBufferRandomAccessFile(1) + { + @Override + public boolean markSupported() + { + return false; + } + }); + fail("IllegalArgumentException expected"); + } catch (IllegalArgumentException ex) + { + assertEquals("Input stream does not support marking. " + + "Wrap input stream with a BufferedInputStream to solve the problem.", + ex.getMessage()); + } + } + + @Test + public void testInputStreamAtTheBeginning() throws Exception + { + byte[] bytes = "hello world".getBytes(); + ByteBufferRandomAccessFile buffer = new ByteBufferRandomAccessFile(bytes); + + ImageUtil.tryToFigureOutFileTypeOf(buffer); + + assertEquals(0, buffer.getFilePointer()); + } + + private void assertFileType(String expectedFileType, String fileName) throws Exception + { + RandomAccessFileImpl handle = null; + try + { + handle = new RandomAccessFileImpl(new File(dir, fileName), "r"); + String type = ImageUtil.tryToFigureOutFileTypeOf(handle); + + assertEquals(expectedFileType, type); + } finally + { + closeQuetly(handle); + } + + } + + private void closeQuetly(RandomAccessFileImpl handle) + { + try { + handle.close(); + } catch (Exception ex) + { + // keep quiet + } + + } + }