/* * ImageUtils.java * Transform * * Copyright (c) 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.util.image; import java.util.ArrayList; import com.flagstone.transform.datatype.Bounds; import com.flagstone.transform.datatype.CoordTransform; import com.flagstone.transform.datatype.HorizontalAlign; import com.flagstone.transform.datatype.VerticalAlign; import com.flagstone.transform.fillstyle.BitmapFill; import com.flagstone.transform.fillstyle.FillStyle; import com.flagstone.transform.image.ImageTag; import com.flagstone.transform.linestyle.LineStyle; import com.flagstone.transform.linestyle.LineStyle1; import com.flagstone.transform.linestyle.LineStyle2; import com.flagstone.transform.shape.DefineShape3; import com.flagstone.transform.shape.DefineShape4; import com.flagstone.transform.shape.Line; import com.flagstone.transform.shape.Shape; import com.flagstone.transform.shape.ShapeRecord; import com.flagstone.transform.shape.ShapeStyle; import com.flagstone.transform.shape.ShapeStyle2; import com.flagstone.transform.shape.ShapeTag; /** * ImageShape is used to generate the shape definition that is required to * display images in a Flash file. */ public final class ImageShape { /** The number of twips in a pixel. */ private static final int TWIPS_PER_PIXEL = 20; /** The horizontal alignment of the image. */ private transient HorizontalAlign xAlign; /** The vertical alignment of the image. */ private transient VerticalAlign yAlign; /** The style used to draw the outline, if any of the shape. */ private transient LineStyle style; /** * Set the line style used to draw the border around the image. * * @param lineStyle a LineStyle. May be null if no border will be drawn. */ public void setStyle(final LineStyle lineStyle) { style = lineStyle.copy(); } /** * Set the registration point, definition the position of the image * relative to the origin of the shape. * * @param halign the alignment along the x-axis. * @param valign the alignment along the y-axis. */ public void setRegistration(final HorizontalAlign halign, final VerticalAlign valign) { xAlign = halign; yAlign = valign; } /** * Generates the shape definition used to display an image using the * predefined registration point and border style. * * @param uid * an unique identifier that is used to reference the shape * definition in a Flash movie. * * @param image * the image definition. * * @return the shape that is used to display the image in a Flash movie. */ public ShapeTag defineShape(final int uid, final ImageTag image) { int xOffset; int yOffset; if (xAlign == HorizontalAlign.LEFT) { xOffset = -(image.getWidth() >> 2); } else if (xAlign == HorizontalAlign.RIGHT) { xOffset = image.getWidth() >> 2; } else { xOffset = 0; } if (yAlign == VerticalAlign.TOP) { yOffset = -(image.getHeight() >> 2); } else if (yAlign == VerticalAlign.BOTTOM) { yOffset = image.getHeight() >> 2; } else { yOffset = 0; } return defineShape(uid, image, xOffset, yOffset, style); } /** * Generates the shape definition used to display an image. * * @param uid * an unique identifier that is used to reference the shape * definition in a Flash movie. * * @param image * the image definition. * * @param xOrigin * the offset in pixels along the x-axis, relative to the top * left corner of the image, where the origin (0,0) of the shape * will be located. * * @param yOrigin * the offset in pixels along the y-axis, relative to the top * left corner of the image, where the origin (0,0) of the shape * will be located. * * @param border * the style drawn around the border of the image. May be null if * no border is drawn. * * @return the shape that is used to display the image in a Flash movie. */ public ShapeTag defineShape(final int uid, final ImageTag image, final int xOrigin, final int yOrigin, final LineStyle border) { final Bounds bounds = getBounds(xOrigin, yOrigin, image.getWidth(), image.getHeight(), border); final Shape shape = getShape(xOrigin, yOrigin, image.getWidth(), image.getHeight(), border); ShapeTag definition; if (border == null || border instanceof LineStyle1) { definition = new DefineShape3(uid, bounds, new ArrayList<FillStyle>(), new ArrayList<LineStyle>(), shape); } else { final Bounds edges = getEdges(xOrigin, yOrigin, image.getWidth(), image.getHeight()); definition = new DefineShape4(uid, bounds, edges, new ArrayList<FillStyle>(), new ArrayList<LineStyle>(), shape); } if (border != null) { definition.add(border); } definition.add(getFillStyle(image.getIdentifier(), xOrigin, yOrigin)); return definition; } /** * Get the bound box that encloses the shape taking into account the * thickness of the outline. * @param xOrigin the x-coordinate of the origin. * @param yOrigin the y-coordinate of the origin. * @param width the width of the image. * @param height the height of the image. * @param border the style used to draw the outline around the image. * @return the bounding box that completely encloses the shape. */ private Bounds getBounds(final int xOrigin, final int yOrigin, final int width, final int height, final LineStyle border) { int lineWidth; if (border instanceof LineStyle1) { lineWidth = ((LineStyle1) border).getWidth() / 2; } else if (border instanceof LineStyle2) { lineWidth = ((LineStyle2) border).getWidth() / 2; } else { lineWidth = 0; } final Bounds bounds = new Bounds( -xOrigin * TWIPS_PER_PIXEL - lineWidth, -yOrigin * TWIPS_PER_PIXEL - lineWidth, (width - xOrigin) * TWIPS_PER_PIXEL + lineWidth, (height - yOrigin) * TWIPS_PER_PIXEL + lineWidth); return bounds; } /** * Get the bound box that encloses the shape. * @param xOrigin the x-coordinate of the origin. * @param yOrigin the y-coordinate of the origin. * @param width the width of the image. * @param height the height of the image. * @return the bounding box that encloses the shape. */ private Bounds getEdges(final int xOrigin, final int yOrigin, final int width, final int height) { return new Bounds( -xOrigin * TWIPS_PER_PIXEL, -yOrigin * TWIPS_PER_PIXEL, (width - xOrigin) * TWIPS_PER_PIXEL, (height - yOrigin) * TWIPS_PER_PIXEL); } /** * Get the shape used to display the image. * @param xOrigin the x-coordinate of the origin. * @param yOrigin the y-coordinate of the origin. * @param width the width of the image. * @param height the height of the image. * @param border the style used to draw the outline around the image. * @return the shape definition size correctly to display the image. */ private Shape getShape(final int xOrigin, final int yOrigin, final int width, final int height, final LineStyle border) { final Shape shape = new Shape(new ArrayList<ShapeRecord>()); if (style instanceof LineStyle2) { final ShapeStyle2 shapeStyle = new ShapeStyle2(); shapeStyle.setLineStyle(1); shapeStyle.setFillStyle(1); shapeStyle.setMove( -xOrigin * TWIPS_PER_PIXEL, -yOrigin * TWIPS_PER_PIXEL); shape.add(shapeStyle); } else { final ShapeStyle shapeStyle = new ShapeStyle(); shapeStyle.setLineStyle(border == null ? 0 : 1); shapeStyle.setFillStyle(1); shapeStyle.setMove( -xOrigin * TWIPS_PER_PIXEL, -yOrigin * TWIPS_PER_PIXEL); shape.add(shapeStyle); } shape.add(new Line(width * TWIPS_PER_PIXEL, 0)); shape.add(new Line(0, height * TWIPS_PER_PIXEL)); shape.add(new Line(-width * TWIPS_PER_PIXEL, 0)); shape.add(new Line(0, -height * TWIPS_PER_PIXEL)); return shape; } /** * Return the fill style that references the image and scales it to the * correct size. * @param uid the unique identifier of the image. * @param xOrigin the x-coordinate of the image origin. * @param yOrigin the y-coordinate of the image origin. * @return the FillStyle used to display the image. */ private FillStyle getFillStyle(final int uid, final int xOrigin, final int yOrigin) { final CoordTransform transform = new CoordTransform( TWIPS_PER_PIXEL, TWIPS_PER_PIXEL, 0, 0, -xOrigin * TWIPS_PER_PIXEL, -yOrigin * TWIPS_PER_PIXEL); return new BitmapFill(false, false, uid, transform); } }