/* * $Id$ * * Copyright (c) 2007-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.imageop; import java.awt.Dimension; import java.awt.image.BufferedImage; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.List; import VASSAL.build.GameModule; import VASSAL.tools.DataArchive; import VASSAL.tools.ErrorDialog; import VASSAL.tools.image.ImageIOException; import VASSAL.tools.image.ImageNotFoundException; import VASSAL.tools.image.ImageUtils; import VASSAL.tools.io.FileArchive; import VASSAL.tools.io.IOUtils; /** * An {@link ImageOp} which loads an image from the {@link DataArchive}. * * @since 3.1.0 * @author Joel Uckelman */ public class SourceOpBitmapImpl extends AbstractTiledOpImpl implements SourceOp { /** The name of the image file. */ protected final String name; /** The cached hash code of this object. */ protected final int hash; /** The archive file from which the image will be loaded */ protected final DataArchive darch; protected final FileArchive farch; /** * Constructs an <code>ImageOp</code> which will load the given file. * * @param name the name of the image to load * @throws IllegalArgumentException * if <code>name</code> is <code>null</code>. */ public SourceOpBitmapImpl(String name) { this(name, GameModule.getGameModule().getDataArchive()); } public SourceOpBitmapImpl(String name, DataArchive archive) { this(name, archive, null); } public SourceOpBitmapImpl(String name, FileArchive archive) { this(name, null, archive); } protected SourceOpBitmapImpl(String name, DataArchive da, FileArchive fa) { if (name == null) { throw new IllegalArgumentException(); } if (name.length() == 0) { throw new IllegalArgumentException(); } if (da == null && fa == null) { throw new IllegalArgumentException(); } this.name = name; this.darch = da; this.farch = fa; hash = name.hashCode() ^ (darch != null ? darch.hashCode() : farch.hashCode()); } public List<VASSAL.tools.opcache.Op<?>> getSources() { return Collections.emptyList(); } protected InputStream getInputStream() throws IOException { return darch != null ? darch.getInputStream(name) : farch.getInputStream(name); } /** * {@inheritDoc} * * @throws IOException if the image cannot be loaded from the image file. */ public BufferedImage eval() throws ImageIOException { InputStream in = null; try { in = getInputStream(); final BufferedImage img = ImageUtils.getImage(name, in); in.close(); return img; } catch (ImageIOException e) { // Don't wrap, just rethrow. throw e; } catch (FileNotFoundException e) { throw new ImageNotFoundException(name, e); } catch (IOException e) { throw new ImageIOException(name, e); } finally { IOUtils.closeQuietly(in); } } /** {@inheritDoc} */ protected void fixSize() { if ((size = getSizeFromCache()) == null) { size = getImageSize(); } } // FIXME: we need a way to invalidate ImageOps when an exception is thrown? // Maybe size should go to -1,-1 when invalid? protected Dimension getImageSize() { try { InputStream in = null; try { in = getInputStream(); final Dimension d = ImageUtils.getImageSize(name, in); in.close(); return d; } catch (ImageIOException e) { // Don't wrap, just rethrow. throw e; } catch (FileNotFoundException e) { throw new ImageNotFoundException(name, e); } catch (IOException e) { throw new ImageIOException(name, e); } finally { IOUtils.closeQuietly(in); } } catch (IOException e) { if (!Op.handleException(e)) ErrorDialog.bug(e); } return new Dimension(); } protected ImageOp createTileOp(int tileX, int tileY) { return new SourceTileOpBitmapImpl(this, tileX, tileY); } /** * Returns the name of the image which {@link #getImage} will produce. * * @return the name of the image in the {@link DataArchive}. */ public String getName() { return name; } /** {@inheritDoc} */ @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || o.getClass() != this.getClass()) return false; final SourceOpBitmapImpl s = (SourceOpBitmapImpl) o; return darch == s.darch && farch == s.farch && name.equals(s.name); } /** {@inheritDoc} */ @Override public int hashCode() { return hash; } /** {@inheritDoc} */ @Override public String toString() { return getClass().getName() + "[name=" + name + "]"; } }