/* * MorphBitmapFill.java * Transform * * Copyright (c) 2001-2010 Flagstone Software Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Flagstone Software Ltd. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package com.flagstone.transform.fillstyle; import java.io.IOException; import com.flagstone.transform.coder.Coder; import com.flagstone.transform.coder.Context; import com.flagstone.transform.coder.SWFDecoder; import com.flagstone.transform.coder.SWFEncoder; import com.flagstone.transform.datatype.CoordTransform; import com.flagstone.transform.exception.IllegalArgumentRangeException; /** * MorphBitmapFill uses a bitmap image to fill an area of a morphing shape. Four * types of bitmap fill are supported: * * <ol> * <li>Clipped - If the image is larger than the shape then it will be clipped. * Conversely if the area to be filled is larger than the image the colour at * the edge of the image is used to fill the remainder of the shape.</li> * * <li>Tiled - if the area to be filled is larger than the image then the image * is tiled to fill the area, otherwise as with the Clipped style the colour at * the edge of the image will be use to fill the space available.</li> * * <li>Unsmoothed Clipped - Same as Clipped but if the image is smaller than the * shape the colour used to fill the space available is not smoothed. This style * was added to increase performance with few visible artifacts.</li> * * <li>Unsmoothed Tiled - Same as Tiled but no smoothing is applied if the * colour at the edge of the image is used to fill the space available. Again * this was introduced to increase performance.</li> * </ol> * * <p> * Two coordinate transforms define the appearance of the image at the start and * end of the morphing process. The most common use of the coordinate transform * is to scale an image so it displayed at the correct resolution. When an image * is loaded its width and height default to twips rather than pixels. An image * 300 x 200 pixels will be displayed as 300 x 200 twips (15 x 10 pixels). * Scaling the image by 20 (20 twips = 1 pixel) using the CoordTransform object * will restore it to its original size. * </p> * * <p> * The coordinate transform is also used to control the image registration. An * image is drawn with the top left corner placed at the origin (0, 0) of the * shape being filled. The transform can be used to apply different translations * to the image so its position can be adjusted relative to the origin of the * enclosing shape. * </p> */ public final class MorphBitmapFill implements FillStyle { /** Format string used in toString() method. */ private static final String FORMAT = "MorphBitmapFill: { identifier=%d;" + " start=%s; end=%s}"; /** Bit mask for tiled or clipped field in bitmap fills. */ private static final int CLIPPED_MASK = 1; /** Bit mask for smoothed or unsmoothed field in bitmap fills. */ private static final int SMOOTHED_MASK = 2; /** Code used to identify the fill style when it is encoded. */ private transient int type; /** The unique identifier of the image that will be displayed. */ private int identifier; /** Coordinate transform at start of morphing process. */ private CoordTransform startTransform; /** Coordinate transform at end of morphing process. */ private CoordTransform endTransform; /** * Creates and initialises a MorphBitmapFill fill style using values encoded * in the Flash binary format. * * @param fillType the value used to identify the fill style when it is * encoded. * * @param coder * an SWFDecoder object that contains the encoded Flash data. * * @throws IOException * if an error occurs while decoding the data. */ public MorphBitmapFill(final int fillType, final SWFDecoder coder) throws IOException { type = fillType; identifier = coder.readUnsignedShort(); startTransform = new CoordTransform(coder); endTransform = new CoordTransform(coder); } /** * Creates a MorphBitmapFill specifying the type, bitmap image and * coordinate transforms for the image at the start and end of the morphing * process. * * @param uid * the unique identifier for the image. Must be in the range * 1..65535. * * @param tiled indicates whether the image will be tiled across the area * defined by the shape. * * @param smoothed whether smoothing will be applied to the image to * improve its appearance. * * @param start * the coordinate transform defining the appearance of the image * at the start of the morphing process. * @param end * the coordinate transform defining the appearance of the image * at the end of the morphing process. */ public MorphBitmapFill(final boolean tiled, final boolean smoothed, final int uid, final CoordTransform start, final CoordTransform end) { type = FillStyleTypes.TILED_BITMAP; setTiled(tiled); setSmoothed(smoothed); setIdentifier(uid); setStartTransform(start); setEndTransform(end); } /** * Creates and initialises a MorphBitmapFill fill style using the values * copied from another MorphBitmapFill object. * * @param object * a MorphBitmapFill fill style from which the values will be * copied. */ public MorphBitmapFill(final MorphBitmapFill object) { type = object.type; identifier = object.identifier; startTransform = object.startTransform; endTransform = object.endTransform; } /** * Is the image tiled across the filled area. * @return true if the image is tiled to completely cover the area to be * filled, false otherwise. */ public boolean isTiled() { return (type & CLIPPED_MASK) != 0; } /** * Indicate whether the image tiled across the filled area. * @param tiled true if the image is tiled to completely cover the area to * be filled, false otherwise. */ public void setTiled(final boolean tiled) { if (tiled) { type &= ~CLIPPED_MASK; } else { type |= CLIPPED_MASK; } } /** * Is the image smoothed to improve display quality. * @return true if the image will be smoothed, false if smoothing is not * applied to increase performance. */ public boolean isSmoothed() { return (type & SMOOTHED_MASK) != 0; } /** * Indicate whether the image will be smoothed to improve display quality. * @param smoothed true if the image will be smoothed, false if smoothing * is not applied. */ public void setSmoothed(final boolean smoothed) { if (smoothed) { type &= ~SMOOTHED_MASK; } else { type |= SMOOTHED_MASK; } } /** * Get the unique identifier of the bitmap image. * * @return the image identifier. */ public int getIdentifier() { return identifier; } /** * Get the coordinate transform defining the appearance of the image at * the start of the morphing process. * * @return the starting coordinate transform applied to the image. */ public CoordTransform getStartTransform() { return startTransform; } /** * Get the coordinate transform defining the appearance of the image at * the end of the morphing process. * * @return the final coordinate transform applied to the image. */ public CoordTransform getEndTransform() { return endTransform; } /** * Sets the identifier of the bitmap image to be used in the morphing * process. * * @param uid * the unique identifier of the bitmap image. Must be in the * range 1..65535. */ public void setIdentifier(final int uid) { if ((uid < 1) || (uid > Coder.USHORT_MAX)) { throw new IllegalArgumentRangeException( 1, Coder.USHORT_MAX, uid); } identifier = uid; } /** * Sets the coordinate transform defining the appearance of the image at the * start of the morphing process. * * @param matrix * the starting coordinate transform. Must not be null. */ public void setStartTransform(final CoordTransform matrix) { if (matrix == null) { throw new IllegalArgumentException(); } startTransform = matrix; } /** * Sets the coordinate transform defining the appearance of the image at the * end of the morphing process. * * @param matrix * the ending coordinate transform. Must not be null. */ public void setEndTransform(final CoordTransform matrix) { if (matrix == null) { throw new IllegalArgumentException(); } endTransform = matrix; } /** {@inheritDoc} */ public MorphBitmapFill copy() { return new MorphBitmapFill(this); } @Override public String toString() { return String.format(FORMAT, identifier, startTransform, endTransform); } /** {@inheritDoc} */ public int prepareToEncode(final Context context) { // CHECKSTYLE:OFF return 3 + startTransform.prepareToEncode(context) + endTransform.prepareToEncode(context); // CHECKSTYLE:ON } /** {@inheritDoc} */ public void encode(final SWFEncoder coder, final Context context) throws IOException { coder.writeByte(type); coder.writeShort(identifier); startTransform.encode(coder, context); endTransform.encode(coder, context); } }