Package flash.graphics.g2d

Source Code of flash.graphics.g2d.SpriteGraphics2D

/*
*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*/

package flash.graphics.g2d;

import flash.swf.tags.DefineShape;
import flash.swf.tags.PlaceObject;
import flash.swf.tags.DefineSprite;
import flash.swf.tags.DefineBits;
import flash.swf.tags.DefineBitsLossless;
import flash.swf.builder.tags.DefineShapeBuilder;
import flash.swf.builder.tags.DefineBitsLosslessBuilder;
import flash.swf.builder.tags.DefineBitsBuilder;
import flash.swf.builder.tags.ImageShapeBuilder;
import flash.swf.builder.types.MatrixBuilder;
import flash.swf.types.TagList;
import flash.swf.types.Rect;
import flash.swf.types.Matrix;
import flash.swf.Tag;
import flash.graphics.images.LosslessImage;
import flash.graphics.images.JPEGImage;

import java.awt.Shape;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Paint;
import java.awt.GradientPaint;
import java.awt.image.ImageObserver;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.InputStream;
import java.io.IOException;

/**
* A SWF specific implementation of Java2D's <code>Graphics2D</code>
* API. Calls to this class are converted into a <code>TagList</code>
* that can be used to construct a SWF Sprite.
*
* @author Peter Farland
*/
public class SpriteGraphics2D extends AbstractGraphics2D
{
  /**
   * Constructor.
   * Initializes a new GraphicContext and TagList.
   *
   * @param width
   * @param height
   */
  public SpriteGraphics2D(int width, int height)
  {
    super(new GraphicContext(width, height));
    this.width = width;
    this.height = height;
    init();
  }

  /**
   * Optimized Constructor.
   * Initializes a smaller GraphicContext and TagList, without FontMetrics support.
   */
  public SpriteGraphics2D()
  {
    super(new GraphicContext());
    init();
  }

  private void init()
  {
    defineTags = new TagList();
    graphicContext.validateTransformStack();
    bounds = new Rect();
  }

  /**
   * Private Constructor - used by create().
   * @param swf2d
   * @see #create()
   */
  private SpriteGraphics2D(SpriteGraphics2D swf2d)
  {
    super((GraphicContext)swf2d.graphicContext.clone());
    defineTags = new TagList();
  }

  /**
   * Draws only the outline of an AWT Shape in SWF vectors using the settings of the
   * current graphics context and places it on the SWF display list. The current
   * stroke and paint colors are used to render the shape.
   * @param shape the shape to be drawn
   * @see java.awt.Graphics2D#draw(java.awt.Shape)
   */
  public void draw(Shape shape)
  {
    defineShape(shape, true, false);
  }

  /**
   * Draws only the center of a closed AWT shape in SWF vectors using the settings of the
   * current graphic context and places it on the SWF display list. The current paint
   * is used to render the shape.
   * @param shape
   * @see java.awt.Graphics2D#fill(java.awt.Shape)
   */
  public void fill(Shape shape)
  {
    defineShape(shape, false, true);
  }

  /**
   * This method converts an AWT Shape into a SWF Shape and creates a DefineShape3 instance
   * with an accompanying PlaceObject2 instance.
   * <p>
   * Two non-standard operations are performed to work around unavoidable issues. The first
   * is to apply the current AffineTransform before rendering and moving the drawing pen
   * origin to the first move command's location. The shape is correctly translated
   * to its intended location on the client by using the PlaceObject2's matrix.
   * </p>
   * <p>
   * The second issue is to deal with the incompatibility of SVGs viewport dimensions and
   * SWF Sprite auto-scaling. We have to keep track of the minimum area required to contain
   * the sprites manually, as using the viewport dimensions will produce unexpected scaling
   * for developers.
   * </p>
   * @param shape
   * @param draw
   * @param fill
   */
  private void defineShape(Shape shape, boolean draw, boolean fill)
  {
    Point2D oldPen = null;
    boolean isGradient = false;

    if (fill && isGradientFill(graphicContext.getPaint()))
      isGradient = true;

    if (isGradient)
    {
      shape = graphicContext.getTransform().createTransformedShape(shape);
      oldPen = graphicContext.setPen(getShapeStart(shape));
    }

    DefineShapeBuilder builder = new DefineShapeBuilder(shape, graphicContext, draw, fill);

    DefineShape ds3 = (DefineShape)builder.build();
    defineTags.defineShape3(ds3);

    Matrix matrix;

    if (isGradient)
    {
      double originX = graphicContext.getPen().getX();
      double originY = graphicContext.getPen().getY();
      matrix = MatrixBuilder.getTranslateInstance(originX, originY);
    }
    else
    {
       matrix = MatrixBuilder.build(graphicContext.getTransform());
    }

    applyBounds(ds3.bounds.xMin + matrix.translateX,
        ds3.bounds.yMin + matrix.translateY,
        ds3.bounds.xMax + matrix.translateX,
        ds3.bounds.yMax + matrix.translateY);

    PlaceObject po2 = new PlaceObject(Tag.stagPlaceObject2);
    po2.setMatrix(matrix);
    po2.setRef(ds3);
        po2.depth = depth++;

    if (isGradient)
      graphicContext.setPen(oldPen);

    defineTags.placeObject2(po2);
  }

  /**
   * <b style="color:orange">NOT YET IMPLEMENTED AS DEFINED BELOW, CURRENTLY USING drawStringAsShape()</b><br />
   * Renders the text specified as a series of SWF character glyphs,
   * using the current graphic context to control anti-aliasing and color.
   * Unique glyphs are stored in a SWF font definition, and the defined text
   * references this by index.
   * <p>
   * The baseline of the first character is at position (<i>x</i>, <i>y</i>)
   * in the User Space.
   * </p>
   * @param str the text to be rendered
   * @param x baseline x co-ordinate
   * @param y baseline y co-ordinate
   * @see java.awt.Graphics2D#drawString(java.lang.String, float, float)
   */
  public void drawString(String str, float x, float y)
  {
    drawStringAsShape(str, x, y);
  }

  public void drawString(String str, int x, int y)
  {
    super.drawString(str, x, y);
  }

  public boolean drawImage(Image image, AffineTransform at, ImageObserver obs)
  {
    if (image != null)
    {
        LosslessImage losslessImage = new LosslessImage(image);
        int width = losslessImage.getWidth();
        int height = losslessImage.getHeight();
      DefineBitsLossless defineBits = DefineBitsLosslessBuilder.build(losslessImage.getPixels(), width, height);
      defineTags.defineBitsLossless2(defineBits);

      DefineShape ds3 = ImageShapeBuilder.buildImage(defineBits, defineBits.width, defineBits.height);
      defineTags.defineShape3(ds3);
      applyBounds(ds3.bounds.xMin, ds3.bounds.yMin, ds3.bounds.xMax, ds3.bounds.yMax);

      PlaceObject po2 = new PlaceObject(Tag.stagPlaceObject2);
      po2.setMatrix(MatrixBuilder.build(at));
      po2.setRef(ds3);
      po2.depth = depth++;

      defineTags.placeObject2(po2);
    }

    return false;
  }

  public boolean drawImage(Image image, int x, int y, ImageObserver observer)
  {
    AffineTransform at = graphicContext.getTransform();
    at.translate(x, y);
    return drawImage(image, at, observer);
  }

  public boolean drawImage(Image image, int x, int y, int width, int height, ImageObserver observer)
  {
    AffineTransform at = graphicContext.getTransform();
    at.translate(x, y);
    double sx = (double)width/(double)image.getWidth(observer);
    double sy = (double)height/(double)image.getHeight(observer);
    at.scale(sx, sy);
    return drawImage(image, at, observer);
  }

    /**
   * Converts an AWT image into a SWF <code>DefineBitsLossless</code> tag and adds it to
   * the Sprite <code>TagList</code> context.
   *
   * @param image - an AWT bitmapped image
   * @param name - name to use in the corresponding <code>PlaceObject</code> tag
   */
  public void drawNamedImage(Image image, String name)
  {
    if (image != null)
    {
            LosslessImage losslessImage = new LosslessImage(image);
            int width = losslessImage.getWidth();
            int height = losslessImage.getHeight();
            DefineBitsLossless defineBits = DefineBitsLosslessBuilder.build(losslessImage.getPixels(), width, height);
      defineTags.defineBitsLossless2(defineBits);

      DefineShape ds3 = ImageShapeBuilder.buildImage(defineBits, defineBits.width, defineBits.height);
      defineTags.defineShape3(ds3);
            applyBounds(ds3.bounds.xMin, ds3.bounds.yMin, ds3.bounds.xMax, ds3.bounds.yMax);

      PlaceObject po2 = new PlaceObject(ds3, depth++);
            po2.setMatrix(MatrixBuilder.build(graphicContext.getTransform()));
            po2.setName(name);

      defineTags.placeObject2(po2);
    }
  }


  /**
   * Converts a JPEG binary input stream into a SWF <code>DefineBits</code> tag and adds it
   * to the Sprite <code>TagList</code> context.
   *
   * @param inputStream - the raw JPEG binary stream
   * @param length - number of bits to read from the stream
   * @param width - width of the JPEG image in pixels
   * @param height - height of the JPEG image in pixels
   * @param name - name to use in the corresponding <code>PlaceObject</code> tag
   * @throws IOException
   */
  public void drawJPEG(InputStream inputStream, int length, int width, int height, String name) throws IOException
  {
        if (inputStream != null)
    {
      try
      {
                JPEGImage image = new JPEGImage(inputStream, length);
                DefineBits defineBits = new DefineBits(Tag.stagDefineBitsJPEG2);
                defineBits.data = image.getData();
        defineTags.defineBitsJPEG2(defineBits);

        DefineShape ds3 = ImageShapeBuilder.buildImage(defineBits, width, height);
        defineTags.defineShape3(ds3);
        applyBounds(ds3.bounds.xMin, ds3.bounds.yMin, ds3.bounds.xMax, ds3.bounds.yMax);

                PlaceObject po2 = new PlaceObject(ds3, depth++);
                po2.setMatrix(MatrixBuilder.build(graphicContext.getTransform()));
                po2.setName(name);

        defineTags.placeObject2(po2);
      }
      finally
      {
        try
        {
          inputStream.close();
        }
        catch (IOException e)
        {
        }
      }
    }
  }

  /**
   * Creates a new <code>Graphics</code> object that is a copy of
   * this <code>SpriteGraphics2D</code> object.
   * @return a copy of this Graphics2D instance
   */
  public Graphics create()
  {
    return new SpriteGraphics2D(this);
  }

  public TagList getTags()
  {
    return defineTags;
  }

  public int getWidth()
  {
    return width;
  }

  public int getHeight()
  {
    return height;
  }

  public DefineSprite defineSprite(String name)
  {
    DefineSprite defineSprite = new DefineSprite();
    defineSprite.framecount = 1;
    defineSprite.tagList = defineTags;
    defineSprite.name = name;
    return defineSprite;
  }

  private static boolean isGradientFill(Paint paint)
  {
    return (paint != null
        && (paint instanceof GradientPaint
            || paint.getClass().getName().equals("org.apache.batik.ext.awt.MultipleGradientPaint")));
  }

  /**
   * When trying to negate gradient dilution in filled SWF shapes, it is useful to
   * know where the left most point of the physical shape as this can be used to change
   * the drawing origin to minimize non-drawing move commands contributing to the
   * shape bounds.
   *
   * @param shape
   * @return Point2D the minimum x,y position of this shape's bounds.
   */
  private static Point2D getShapeStart(Shape shape)
  {
    if (shape != null)
    {
      Rectangle2D bounds = shape.getBounds2D();
      return new Point2D.Double(bounds.getMinX(), bounds.getMinY());
    }

    return new Point2D.Double(0, 0);
  }

  private void applyBounds(int x1, int y1, int x2, int y2)
  {
    if (x1 < bounds.xMin) bounds.xMin = x1;
    if (y1 < bounds.yMin) bounds.yMin = y1;
    if (x1 > bounds.xMax) bounds.xMax = x1;
    if (y1 > bounds.yMax) bounds.yMax = y1;
    if (x2 < bounds.xMin) bounds.xMin = x2;
    if (y2 < bounds.yMin) bounds.yMin = y2;
    if (x2 > bounds.xMax) bounds.xMax = x2;
    if (y2 > bounds.yMax) bounds.yMax = y2;
  }

  public Rect getBounds()
  {
    return bounds;
  }

  protected TagList defineTags;
  protected int depth = 1;
  protected int width;
  protected int height;
  protected Rect bounds;
}
TOP

Related Classes of flash.graphics.g2d.SpriteGraphics2D

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.