it.tidalwave.imageio.test.ImageReaderTestSupport.java Source code

Java tutorial

Introduction

Here is the source code for it.tidalwave.imageio.test.ImageReaderTestSupport.java

Source

/***********************************************************************************************************************
 *
 * jrawio - a Java(TM) Image I/O SPI Provider for Camera Raw files
 * Copyright (C) 2003 - 2016 by Tidalwave s.a.s.
 *
 ***********************************************************************************************************************
 *
 * 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.
 *
 ***********************************************************************************************************************
 *
 * WWW: http://jrawio.rawdarkroom.org
 * SCM: https://kenai.com/hg/jrawio~src
 *
 **********************************************************************************************************************/
package it.tidalwave.imageio.test;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import java.util.Iterator;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.FileNotFoundException;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import org.apache.commons.io.FileUtils;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.spi.ImageReaderSpi;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import it.tidalwave.imageio.util.Logger;
import it.tidalwave.imageio.raw.RAWImageReadParam;
import it.tidalwave.imageio.raw.RAWImageReader;
import org.junit.BeforeClass;
import static org.junit.Assert.*;

/***********************************************************************************************************************
 *
 * @author  Fabrizio Giudici
 * @version $Id$
 *
 **********************************************************************************************************************/
public class ImageReaderTestSupport extends TestSupport {
    private final static String CLASS = ImageReaderTestSupport.class.getName();
    private final static Logger logger = Logger.getLogger(CLASS);

    public final static String PROP_TESTSET_CACHED_FOLDER = "testset.cached.folder";

    private static String testFolder;

    /*******************************************************************************************************************
     * 
     * 
     ******************************************************************************************************************/
    @BeforeClass
    public static void setupTestFolderPath() {
        testFolder = System.getProperty(PROP_TESTSET_CACHED_FOLDER);
        assertNotNull("You must set a property named '" + PROP_TESTSET_CACHED_FOLDER + "' "
                + "to point to the test files", testFolder);
    }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    protected void assertMIMETypes(final String extension, final String... mimeTypes) {
        final Iterator<ImageReader> i = ImageIO.getImageReadersBySuffix(extension);
        assertTrue(i.hasNext());
        final ImageReader ir = i.next();
        assertNotNull(ir);
        assertFalse(i.hasNext());
        final ImageReaderSpi provider = ir.getOriginatingProvider();
        assertEquals(mimeTypes, provider.getMIMETypes());
    }

    /*******************************************************************************************************************
     * 
     * 
     ******************************************************************************************************************/
    protected void assertImageMetadataSize(final ImageReader ir, final int width, final int height)
            throws IOException {
        final Dimension imageSize = new Dimension(ir.getWidth(0), ir.getHeight(0));
        final Dimension expectedSize = new Dimension(width, height);
        assertEquals("metadata image size: ", expectedSize, imageSize);
    }

    /*******************************************************************************************************************
     * 
     * 
     ******************************************************************************************************************/
    protected void assertThumbnailMetadataSize(final ImageReader ir, final int thumbnailIndex, final int width,
            final int height) throws IOException {
        final Dimension thumbnailSize = new Dimension(ir.getThumbnailWidth(0, thumbnailIndex),
                ir.getThumbnailHeight(0, thumbnailIndex));
        final Dimension expectedSize = new Dimension(width, height);
        assertEquals("metadata thumbnail size: ", expectedSize, thumbnailSize);
    }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    @Deprecated
    protected BufferedImage assertLoadImage(final @Nonnull ImageReader ir,
            final @CheckForNull RAWImageReadParam readParam, final @Nonnegative int width,
            final @Nonnegative int height, final @Nonnegative int bandCount, final @Nonnegative int sampleSize)
            throws IOException {
        final BufferedImage image = ir.read(0, readParam);
        assertNotNull(image);
        final Dimension imageSize = new Dimension(image.getWidth(), image.getHeight());
        final Dimension expectedSize = new Dimension(width, height);
        assertEquals("loaded image size: ", expectedSize, imageSize);
        assertEquals("loaded image band count", bandCount, image.getData().getNumBands());

        for (int i = 0; i < bandCount; i++) {
            assertEquals("loaded image sample size for band " + i, sampleSize,
                    image.getData().getSampleModel().getSampleSize(i));
        }

        return image;
    }

    /*******************************************************************************************************************
     * 
     * 
     ******************************************************************************************************************/
    @Nonnull
    protected BufferedImage assertLoadImage(final @Nonnull ImageReader ir,
            final @CheckForNull RAWImageReadParam readParam, final @Nonnegative int width,
            final @Nonnegative int height, final @Nonnegative int bandCount, final @Nonnegative int sampleSize,
            final int type) throws IOException {
        final BufferedImage image = ir.read(0, readParam);
        assertNotNull(image);
        final Dimension imageSize = new Dimension(image.getWidth(), image.getHeight());
        final Dimension expectedSize = new Dimension(width, height);
        assertEquals("loaded image size: ", expectedSize, imageSize);
        assertEquals("loaded image band count", bandCount, image.getData().getNumBands());
        assertEquals(type, image.getType());

        for (int i = 0; i < bandCount; i++) {
            assertEquals("loaded image sample size for band " + i, sampleSize,
                    image.getData().getSampleModel().getSampleSize(i));
        }

        return image;
    }

    /*******************************************************************************************************************
     * 
     * 
     ******************************************************************************************************************/
    @Nonnull
    protected BufferedImage assertLoadThumbnail(final @Nonnull ImageReader ir,
            final @Nonnegative int thumbnailIndex, final @Nonnegative int width, final @Nonnegative int height)
            throws IOException {
        final BufferedImage thumbnail = ir.readThumbnail(0, thumbnailIndex);
        assertNotNull("loaded thumbnail is null", thumbnail);
        final Dimension thumbnailSize = new Dimension(thumbnail.getWidth(), thumbnail.getHeight());
        final Dimension expectedSize = new Dimension(width, height);
        assertEquals("loaded thumbnail size: ", expectedSize, thumbnailSize);
        return thumbnail;
    }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    protected File getTestFile(final @Nonnull String path) throws IOException {
        File file = null;

        if (path.startsWith("http")) {
            final String tmp = System.getProperty("java.io.tmpdir");
            final File cacheFolder = new File(System.getProperty(PROP_TESTSET_CACHED_FOLDER, tmp + "/TestFolder"));
            file = new File(cacheFolder, path.replace("http://", "").replace("https://", "").replace(':', '_'));

            if (!file.exists()) {
                // With Hudson, this could be executed by multiple processes at a time - processes, not threads, so
                // we can't use Java thread-based synchronization.
                final File lockFile = new File(file.getPath() + ".lck");
                lockFile.getParentFile().mkdirs();
                boolean alreadyLocked = !lockFile.createNewFile();

                if (lockFile.lastModified() - System.currentTimeMillis() > 10 * 60 * 1000) {
                    logger.info(">>>> stale lock file %s", lockFile.getAbsolutePath());
                    alreadyLocked = false;
                    // FIXME: unfortunately, both processes would do the same
                }

                if (!alreadyLocked) {
                    logger.info(">>>> downloading to %s...", file.getAbsolutePath());
                    file.getParentFile().mkdirs();
                    FileUtils.copyURLToFile(new URL(path), file);
                    lockFile.delete(); // TODO: consider using a try / finally
                } else {
                    final long time = System.currentTimeMillis();

                    while (lockFile.exists()) {
                        logger.info(">>>> waiting for the download of %s to complete...", file.getAbsolutePath());

                        if (System.currentTimeMillis() - time > 10 * 60 * 1000) {
                            fail("Timeout while waiting for another thread to download " + file.getAbsolutePath());
                        }

                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                        }
                    }
                }
            } else {
                logger.info(">>>> using cached file %s...", file.getAbsolutePath());
            }
        } else {
            file = new File(path.startsWith("/") ? path : (testFolder + "/" + path));
        }

        assertTrue("File not found: " + file, file.exists());

        return file;
    }

    /*******************************************************************************************************************
     * 
     * 
     ******************************************************************************************************************/
    @Nonnull
    protected ImageReader getImageReader(final @Nonnull String path, final @Nonnull RAWImageReadParam readParam)
            throws IOException {
        logger.info("************* TESTING FILE: %s - %s", path, readParam);

        final File file = getTestFile(path);
        final ImageReader ir = ImageIO.getImageReaders(file).next();
        assertNotNull(ir);

        if (readParam != null) {
            ((RAWImageReader) ir).setDefaultReadParam(readParam);
        }

        ir.setInput(ImageIO.createImageInputStream(file));
        return ir;
    }

    /*******************************************************************************************************************
     * 
     * 
     ******************************************************************************************************************/
    protected void assertRaster(final @Nonnull BufferedImage image, final @Nonnull String path,
            final @Nonnull String expectedRasterMD5, final @Nonnull String suffix)
            throws IOException, NoSuchAlgorithmException {
        final File targetDirectory = new File("target/converted-images/");
        final File tiffFile = new File(targetDirectory, path.replace("https://", "").replace("http://", "") + suffix
                + "-" + System.getProperty("java.version") + ".tiff");

        if (Boolean.getBoolean("jrawio.dumpImageAsTIFF")) {
            tiffFile.getParentFile().mkdirs();
            logger.info("***************** Writing %s...", tiffFile.getAbsolutePath());
            System.err.printf(">>>> Writing %s...\n", tiffFile.getAbsolutePath());
            ImageIO.write(image, "TIFF", tiffFile);
        }

        final Raster raster = image.getData();

        if (Boolean.getBoolean("jrawio.dumpRasterAsText")) {
            final File textDumpFile = new File(
                    tiffFile.getAbsolutePath() + "-" + System.getProperty("java.version") + ".txt");
            dumpRasterAsText(raster, textDumpFile);
        }

        if (expectedRasterMD5 != null) // we temporarily accept null since there's no value for thumbnails
        {
            final MessageDigest md5 = md5(raster);

            // Comparisons are broken with JDK 1.5.0, don't make tests fail under Hudson.
            // See http://jrawio.tidalwave.it/issues/browse/JRW-162
            //        if (System.getProperty("java.version").contains("1.5.0"))
            //          {
            //            logger.warning("Not testing raster's MD5 on Java 5 because of JRW-162");
            //          }
            //        else
            //          {
            assertEquals(expectedRasterMD5, asString(md5.digest()));
            //          }
        }
    }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    public static MessageDigest md5(final @Nonnull Raster raster) throws NoSuchAlgorithmException {
        final MessageDigest md5 = MessageDigest.getInstance("MD5");

        for (int b = 0; b < raster.getNumBands(); b++) {
            for (int y = 0; y < raster.getHeight(); y++) {
                for (int x = 0; x < raster.getWidth(); x++) {
                    final int sample = raster.getSample(x, y, b) & 0xffff;
                    md5.update((byte) ((sample >>> 24) & 0xff));
                    md5.update((byte) ((sample >>> 16) & 0xff));
                    md5.update((byte) ((sample >>> 8) & 0xff));
                    md5.update((byte) ((sample >>> 0) & 0xff));
                }
            }
        }

        return md5;
    }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    public static void dumpRasterAsText(final @Nonnull Raster raster, final @Nonnull File file)
            throws FileNotFoundException {
        file.getParentFile().mkdir();
        logger.info("***************** Writing %s...", file.getAbsolutePath());
        final PrintWriter pw = new PrintWriter(file);
        dumpRasterAsText(raster, pw);
        pw.close();
    }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    public static void dumpRasterAsText(final @Nonnull Raster raster, final @Nonnull PrintWriter pw) {
        final int width = raster.getWidth();
        final int height = raster.getHeight();
        final int bandCount = raster.getNumBands();
        logger.fine("Dumping raster %d x %d x %d", width, height, bandCount);

        for (int y = 0; y < height; y++) {
            for (int b = 0; b < bandCount; b++) {
                pw.printf("y=%04d b=%1d : ", y, b);

                for (int x = 0; x < width; x++) {
                    final int sample = raster.getSample(x, y, b) & 0xffff;
                    pw.printf("%04x ", sample);
                }

                pw.println();
            }
        }
    }

    /*******************************************************************************************************************
     * 
     * 
     ******************************************************************************************************************/
    protected void close(final ImageReader ir) throws IOException {
        final ImageInputStream iis = (ImageInputStream) ir.getInput();
        iis.close();
        ir.dispose();
    }

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    //    private static void dump (final File file, final byte[] buffer)
    //      throws IOException
    //      {
    //        final FileOutputStream fos = new FileOutputStream(file);
    //        fos.write(buffer);
    //        fos.close();
    //      }
    //
    //    /*******************************************************************************************************************
    //     *
    //     *
    //     ******************************************************************************************************************/
    //    private static byte[] asBytes (final short[] buffer)
    //      throws IOException
    //      {
    //        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    //        final DataOutputStream dos = new DataOutputStream(baos);
    //
    //        for (final short value : buffer)
    //          {
    //            dos.writeShort(value);
    //          }
    //
    //        dos.close();
    //        return baos.toByteArray();
    //      }

    /*******************************************************************************************************************
     * 
     * 
     ******************************************************************************************************************/
    private static String asString(final byte[] bytes) {
        final StringBuilder builder = new StringBuilder();

        for (final byte b : bytes) {
            final String s = Integer.toHexString(b & 0xff);
            assertTrue(s.length() <= 2);

            if (s.length() < 2) {
                builder.append('0');
            }

            builder.append(s);
        }

        return builder.toString();
    }
}