/* * $Id$ * * Copyright (c) 2007 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.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.builder.HashCodeBuilder; import VASSAL.tools.image.ImageUtils; /** * An {@link ImageOp} which crops its source. * * @since 3.1.0 * @author Joel Uckelman */ public class CropOpBitmapImpl extends AbstractTiledOpImpl implements CropOp { private final ImageOp sop; private final int x0, y0, x1, y1; private final int hash; /** * Constructs an <code>ImageOp</code> which will crop the image * produced by its source <code>ImageOp</code>. * * @param sop the source operation * @param x0 the x coordinate of the upper-left corner * @param y0 the y coordinate of the upper-left corner * @param x1 the x coordinate of the lower-right corner * @param y1 the y coordinate of the lower-right corner */ public CropOpBitmapImpl(ImageOp sop, int x0, int y0, int x1, int y1) { if (sop == null) { throw new IllegalArgumentException(); } if (x0 < 0) { throw new IllegalArgumentException("left = " + x0); } if (y0 < 0) { throw new IllegalArgumentException("top = " + y0); } if (x1 <= x0) { throw new IllegalArgumentException("left = "+ x0 + ", right = " + x1); } if (y1 <= y0) { throw new IllegalArgumentException("top = " + y0 + ", bottom = " + y1); } this.sop = sop; this.x0 = x0; this.y0 = y0; this.x1 = x1; this.y1 = y1; size = new Dimension(x1-x0, y1-y0); hash = new HashCodeBuilder().append(sop) .append(x0) .append(y0) .append(x1) .append(y1) .toHashCode(); } public List<VASSAL.tools.opcache.Op<?>> getSources() { final Point[] tiles = sop.getTileIndices(new Rectangle(x0, y0, x1-x0, y1-y0)); final ArrayList<VASSAL.tools.opcache.Op<?>> ops = new ArrayList<VASSAL.tools.opcache.Op<?>>(tiles.length); for (Point tile : tiles) ops.add(sop.getTileOp(tile)); return ops; } /** * {@inheritDoc} * * @throws Exception passed up from the source <code>ImageOp</code>. * */ public BufferedImage eval() throws Exception { // cobble source from tiles final Point[] tiles = sop.getTileIndices(new Rectangle(x0, y0, x1-x0, y1-y0)); final int tw = sop.getTileWidth(); final int th = sop.getTileHeight(); // match the transparency of the first tile final BufferedImage dst = ImageUtils.createCompatibleImage( size.width, size.height, sop.getTile(tiles[0], null).getTransparency() != BufferedImage.OPAQUE ); final Graphics2D g = dst.createGraphics(); for (Point tile : tiles) { g.drawImage(sop.getTile(tile, null), tile.x*tw-x0, tile.y*th-y0, null); } g.dispose(); return dst; } protected void fixSize() {} protected ImageOp createTileOp(int tileX, int tileY) { return new CropOpBitmapImpl(this, tileX*tileSize.width, tileY*tileSize.height, Math.min((tileX+1)*tileSize.width, size.width), Math.min((tileY+1)*tileSize.height, size.height)); } /** * Returns the crop rectangle. * * @return the rectangle to be cropped. */ public Rectangle getRect() { return new Rectangle(x0, y0, size.width, size.height); } public int getX0() { return x0; } public int getY0() { return y0; } public int getX1() { return x1; } public int getY1() { return y1; } /** {@inheritDoc} */ @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || o.getClass() != this.getClass()) return false; final CropOpBitmapImpl op = (CropOpBitmapImpl) o; return x0 == op.getX0() && y0 == op.getY0() && x1 == op.getX1() && y1 == op.getY1() && sop.equals(op.sop); } /** {@inheritDoc} */ @Override public int hashCode() { return hash; } }