VASSAL.tools.image.FallbackImageTypeConverter.java Source code

Java tutorial

Introduction

Here is the source code for VASSAL.tools.image.FallbackImageTypeConverter.java

Source

/*
 * $Id$
 *
 * Copyright (c) 2010 by Joel Uckelman
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License (LGPL) as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, copies are available
 * at http://www.opensource.org.
 */

package VASSAL.tools.image;

import java.awt.image.BufferedImage;

import org.apache.commons.lang.SystemUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import VASSAL.tools.io.TemporaryFileFactory;
import VASSAL.tools.lang.Reference;

/**
 * Convert a {@link BufferedImage} to a different type, falling back to
 * conversion on disk if convertion in memory fails.
 *
 * @since 3.2.0
 * @author Joel Uckelman
 */
public class FallbackImageTypeConverter implements ImageTypeConverter {
    private static final Logger logger = LoggerFactory.getLogger(FallbackImageTypeConverter.class);

    protected final TemporaryFileFactory tfactory;
    protected final ImageTypeConverter memory_converter;
    protected final ImageTypeConverter file_converter;

    /**
     * Create a converter.
     *
     * @param tfactory the temporary file factory
     */
    public FallbackImageTypeConverter(TemporaryFileFactory tfactory) {
        this(tfactory, new MemoryImageTypeConverter(), new FileImageTypeConverter(tfactory));
    }

    /**
     * Create a converter.
     *
     * @param tfactory the temporary file factory
     * @param memory_converter the in-memory image converter
     * @param file_converter the on-disk image converter
     */
    FallbackImageTypeConverter(TemporaryFileFactory tfactory, ImageTypeConverter memory_converter,
            ImageTypeConverter file_converter) {
        this.tfactory = tfactory;
        this.memory_converter = memory_converter;
        this.file_converter = file_converter;
    }

    private boolean tryConvertingInMemory(Reference<BufferedImage> ref) {
        /*
         * Having an OutOfMemoryException while converting in memory is
         * apparently catastrophic on Apple's Java 6 JVM (and possibly also
         * on their Java 5 JVM as well). In-memory tiling also uses far more
         * memory than it should on Apple's Java 6 JVM due to
         * Graphics2D.drawImage making an intermediate copy of the image data.
         * Hence, we ensure that when using Java 5 or 6 on Mac OS X, we never
         * try in-memory conversion for images which can't comfortably have
         * three copies existing simultaneously in memory.
         */
        return !SystemUtils.IS_OS_MAC_OSX || (!SystemUtils.IS_JAVA_1_6 && !SystemUtils.IS_JAVA_1_5)
                || 4 * ref.obj.getHeight() * ref.obj.getWidth() <= Runtime.getRuntime().maxMemory() / 4;
    }

    /** {@inheritDoc} */
    public BufferedImage convert(Reference<BufferedImage> ref, int type) throws ImageIOException {
        if (tryConvertingInMemory(ref)) {
            try {
                return memory_converter.convert(ref, type);
            } catch (OutOfMemoryError e) {
                // This is ok, we just don't have enough free heap for the conversion.
                logger.info("Switching to FileImageTypeConverter...");
            }
        }

        // Try converting on disk instead.
        return file_converter.convert(ref, type);
    }
}