/* * FillStyles.java * Examples * * Created by Stuart MacKay on Fri Jul 25 2003. * Copyright (c) 2001-2004 Flagstone Software Ltd. All rights reserved. * * This code is distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND Flagstone HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING * WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. */ package com.flagstone.transform.examples; import com.flagstone.transform.*; import java.util.*; import java.io.*; /* * This example shows how the different fill styles can be used to fill a shape. * A shape can be filled with solid colour, an image or a colour gradient. If an * image is smaller than the shape it may be tiled to fill the area or clipped * where colour around the edge of the image is used to fill the remaining area. * Gradients may be linear - changing in one dimension or radial - changing in two * dimensions. * * To run this example, type the following on a command line: * * java com.flagstone.transform.examples.FillStyles \ * --image image-file [--resultDir path] * where * * resultDir is the directory where the Flash file generated by the example is * written to. * * image-file is the path to a file containing a JPEG image. The image should * be 185 pixels wide and 135 pixels high to illustrate how images are placed * within the shape they are filling however any size of image will work. */ public class FillStyles extends Example { public static void main(String[] args) { new FillStyles(args); } public FillStyles(String[] args) { super(args); createMovie(); writeFile("FillStyles.swf"); } public void createMovie() { int width = 3200; int height = 2400; String imageFile = getOption("image", "."); /* * A row of five rectangles will be displayed - one for each fill style. */ movie.setFrameRate(1.0f); movie.setFrameSize(new FSBounds(0, 0, (width+800)*5 , height+800)); movie.add(new FSSetBackgroundColor(FSColorTable.lightblue())); /* * Define the rectangle that is filled with the different fill styles. */ FSBounds bounds = new FSBounds(-width/2, -height/2, width/2, height/2); ArrayList rectangle = new ArrayList(); rectangle.add(new FSShapeStyle(1, 1, 0, -width/2, -height/2)); rectangle.add(new FSLine(width, 0)); rectangle.add(new FSLine(0, height)); rectangle.add(new FSLine(-width, 0)); rectangle.add(new FSLine(0, -height)); rectangle.add(new FSLine(width, 0)); /* * The following variables are reused for each fill style to simplify the code. * The arrays will be cloned to create a shallow copy, so the line style and * fill style arrays can be safely reused. */ int identifier = 0; ArrayList lineStyles = new ArrayList(); ArrayList fillStyles = new ArrayList(); ArrayList gradients = new ArrayList(); /************************************************* * Create a rectangle filled with a solid colour. *************************************************/ identifier = movie.newIdentifier(); lineStyles.add(new FSSolidLine(20, FSColorTable.black())); fillStyles.add(new FSSolidFill(FSColorTable.red())); movie.add(new FSDefineShape(identifier, bounds, fillStyles, lineStyles, new FSShape(rectangle))); movie.add(new FSPlaceObject(identifier, 1, 2000, 1600)); /****************************************** * Create a rectangle tiled with an image. ******************************************/ try { identifier = movie.newIdentifier(); lineStyles = new ArrayList(); fillStyles = new ArrayList(); lineStyles.add(new FSSolidLine(20, FSColorTable.black())); FSDefineJPEGImage image = new FSDefineJPEGImage(movie.newIdentifier(), dataFromFile(imageFile)); /* * Scale the loaded image to half its original size so it will tile four times inside the * ractangle. 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) would restore it to its original size. * The rectangle inside which the images are tiled is sized to the width and height of the * image in pixels. So scaling the image to half its original size (x10) will result in the * image being tiled four times in the rectangle. * * The image is drawn from the top left corner of the rectangle so the scaling transform * must be composited with a translation transform. Compositing transforms are not commutative * so the order is important. If the order was reversed so the translate transform was the * second argument to the composite method then the coordinates for the translation would be * multiplied by the scaling factor. */ FSCoordTransform transform = new FSCoordTransform(-1600, -1200, 10.0, 10.0); fillStyles.add(new FSBitmapFill(FSFillStyle.Tiled, image.getIdentifier(), transform)); movie.add(image); movie.add(new FSDefineShape(identifier, bounds, fillStyles, lineStyles, new FSShape(rectangle))); movie.add(new FSPlaceObject(identifier, 2, 6000, 1600)); } catch (FileNotFoundException e) { System.err.println("Cannot open file: " + e.getMessage()); } catch (IOException e) { System.err.println("Cannot read file: " + e.getMessage()); } /************************************************** * Create a rectangle filled with a clipped image. **************************************************/ try { identifier = movie.newIdentifier(); lineStyles = new ArrayList(); fillStyles = new ArrayList(); lineStyles.add(new FSSolidLine(20, FSColorTable.black())); FSDefineJPEGImage image = new FSDefineJPEGImage(movie.newIdentifier(), dataFromFile(imageFile)); /* * Scale the loaded image to twice its original size so it will be clipped inside the * ractangle. * * The image is drawn from the top left corner of the rectangle so the scaling transform * must be composited with a translation transform. */ FSCoordTransform transform = new FSCoordTransform(-1200, -900, 15.0, 15.0); fillStyles.add(new FSBitmapFill(FSFillStyle.Clipped, image.getIdentifier(), transform)); movie.add(new FSJPEGEncodingTable(null)); // The image will still be displayed with a null table movie.add(image); movie.add(new FSDefineShape(identifier, bounds, fillStyles, lineStyles, new FSShape(rectangle))); movie.add(new FSPlaceObject(identifier, 3, 10000, 1600)); } catch (FileNotFoundException e) { System.err.println("Cannot open file: " + e.getMessage()); } catch (IOException e) { System.err.println("Cannot read file: " + e.getMessage()); } /********************************************************* * Create a rectangle filled with linear gradient colour. *********************************************************/ identifier = movie.newIdentifier(); lineStyles = new ArrayList(); fillStyles = new ArrayList(); /* * The gradient square must be mapped to the rectangle being filled. The square * measures 32768 x 32768 twips. The coordinates range from -16384, -16384 at the * bottom left corner to (16384, 16384) at the top right corner. Mapping takes place * in three steps: * * 1. The coordinate system of the gradient square is translated to match the coordinate * system of the shape in which the gradient is displayed. In this example, both the * gradient square and the rectangle in which it will be displayed are both centred at * (0,0) - see the FSBounds object created above. For this example the full range of the * gradient will be displayed so no translation is required. The second example that * displays a radial gradient illustrates how the translation can be calculated to change * the portion of the gradient being displayed. * * 2. The gradient square is scaled so that the full range of the gradient will be * dislayed inside the rectangle. If a smaller scaling factor is set then the * portion of the gradient being displayed will change. The second example shows * how the scaling factor affects the gradient. * * 3. The gradient can be rotated to change the direction of the colour change. If a * rotation is not applied then the gradient changes in the positive x axis - front left * to right on the Flash Player's screen. */ /* To display the full gradient, calculate the ratio of the shape's width to the width * of the gradient square. The gradient wil rotated so the width is used rather than * caclulating the length of the diagonal. */ float scale = bounds.getWidth() / 32768.0f; /* Since the centre of the rectangle and the gradient square are both at (0,0) no * additional translation is required. */ int translateX = 0; int translateY = 0; /* The order of composition is important. If the scale transform was the first argument * then the translation coordinates would also be scaled. * * The scaling is performed in the x and y direction as the gradient is rotated in the * the following step. */ FSCoordTransform transform = new FSCoordTransform(translateX, translateY, scale, scale); /* * Apply a rotation so the gradient changes across the diagonal of the rectangle. */ transform.rotate(45); /* * The array of FSGradient objects defines how the colour changes across the gradient * square. The ratio defines the proportion across the square: 0 is the left side and * 255 is the right side. */ gradients.add(new FSGradient(0, FSColorTable.white())); gradients.add(new FSGradient(255, FSColorTable.black())); lineStyles.add(new FSSolidLine(1, FSColorTable.black())); fillStyles.add(new FSGradientFill(FSFillStyle.Linear, transform, gradients)); movie.add(new FSDefineShape(identifier, bounds, fillStyles, lineStyles, new FSShape(rectangle))); movie.add(new FSPlaceObject(identifier, 4, 14000, 1600)); /********************************************************* * Create a rectangle filled with radial gradient colour. *********************************************************/ identifier = movie.newIdentifier(); lineStyles = new ArrayList(); fillStyles = new ArrayList(); gradients = new ArrayList(); /* The gradient will be centred in the bottom left corner of the rectangle * since the full spectrum of the radial gradient will be displayed the * gradient square need only be scaled by half the amount compared to the * linear gradient above. */ float scaleX = (bounds.getWidth() / 32768.0f) * 2.0f; float scaleY = (bounds.getHeight() / 32768.0f) * 2.0f; /* Here the translation is calculated so the centre is expressed as a percentage * of the width of the rectangle. The general form of the calculation is: * * translateX = bounds.getMinX() + bounds.getWidth() * 0.0; * translateY = bounds.getMinY() + bounds.getHeight() * 0.25; */ translateX = bounds.getMinX(); translateY = bounds.getMinY(); transform = new FSCoordTransform(translateX, translateY, scaleX, scaleY); gradients.add(new FSGradient(15, FSColorTable.red())); gradients.add(new FSGradient(63, FSColorTable.orange())); gradients.add(new FSGradient(127, FSColorTable.yellow())); gradients.add(new FSGradient(255, FSColorTable.green())); lineStyles.add(new FSSolidLine(20, FSColorTable.black())); fillStyles.add(new FSGradientFill(FSFillStyle.Radial, transform, gradients)); movie.add(new FSDefineShape(identifier, bounds, fillStyles, lineStyles, new FSShape(rectangle))); movie.add(new FSPlaceObject(identifier, 5, 18000, 1600)); movie.add(new FSShowFrame()); } private byte[] dataFromFile(String filename) throws FileNotFoundException, IOException { File aFile = new File(filename); FileInputStream imageContents = null; byte[] bytes = new byte[(int)aFile.length()]; imageContents = new FileInputStream(aFile); imageContents.read(bytes); imageContents.close(); return bytes; } }