Package com.adobe.internal.fxg.swf

Source Code of com.adobe.internal.fxg.swf.ImageHelper

/*
*
*  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 com.adobe.internal.fxg.swf;

import java.awt.Image;
import java.awt.image.PixelGrabber;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import com.adobe.fxg.FXGVersion;
import com.adobe.internal.fxg.dom.AbstractFXGNode;
import com.adobe.internal.fxg.dom.BitmapGraphicNode;
import com.adobe.internal.fxg.dom.FillNode;
import com.adobe.internal.fxg.dom.fills.BitmapFillNode;
import com.adobe.internal.fxg.dom.types.FillMode;

import flash.graphics.images.ImageUtil;
import flash.swf.SwfConstants;
import flash.swf.Tag;
import flash.swf.TagValues;
import flash.swf.tags.DefineBits;
import flash.swf.tags.DefineBitsLossless;
import flash.swf.tags.DefineShape;
import flash.swf.types.FillStyle;
import flash.swf.types.Matrix;
import flash.swf.types.Rect;
import flash.swf.types.ShapeRecord;
import flash.swf.types.ShapeWithStyle;
import flash.swf.types.StraightEdgeRecord;
import flash.swf.types.StyleChangeRecord;
import flash.util.FileUtils;

/**
* Utilities to help create SWF DefineBits and DefineBitsLossess image tags.
*
* @author Peter Farland
* @author Sujata Das
*/
public class ImageHelper
{
   
    /** The Constant MIME_GIF. */
    public static final String MIME_GIF = "image/gif";
   
    /** The Constant MIME_JPEG. */
    public static final String MIME_JPEG = "image/jpeg";
   
    /** The Constant MIME_JPG. */
    public static final String MIME_JPG = "image/jpg";
   
    /** The Constant MIME_PNG. */
    public static final String MIME_PNG = "image/png";

    /**
     * Creates a rectangle for the given width and height as a DefineShape. The
     * shape is painted with a bitmap FillStyle with the given DefineBits
     * tag.
     *
     * @param tag The DefineBits tag encoding the image.
     * @param node The BitmapGraphicNode.
      * @return A rectangle of given width and height as a DefineShape with a
     * bitmap fill.
     */
    public static DefineShape createShapeForImage(DefineBits tag, BitmapGraphicNode node)
    {
      double width = node.width;
      double height = node.height;
      boolean repeat = node.repeat;
      FillMode fillMode = node.fillMode;
      FXGVersion fileVersion = node.getFileVersion();

        // Use default width/height information if none specified
        if (Double.isNaN(width))
            width = tag.width;

        if (Double.isNaN(height))
            height = tag.height;

        // Create Fill Style
        Matrix matrix = new Matrix();
        matrix.scaleX = (int)(SwfConstants.TWIPS_PER_PIXEL * SwfConstants.FIXED_POINT_MULTIPLE);
        matrix.scaleY = (int)(SwfConstants.TWIPS_PER_PIXEL * SwfConstants.FIXED_POINT_MULTIPLE);
        matrix.hasScale = true; // Apply runtime scale of 20x for twips
       
        FillStyle fs = null;
        if (fileVersion.equalTo(FXGVersion.v1_0))
        {
          if (repeat)
            fs = new FillStyle(FillStyle.FILL_BITS, matrix, tag);
          else
            fs = new FillStyle(FillStyle.FILL_BITS | FillStyle.FILL_BITS_CLIP, matrix, tag);
        }
        else
        {
          if (fillMode.equals(FillMode.REPEAT))
          {
            fs = new FillStyle(FillStyle.FILL_BITS, matrix, tag);
          }
          else if (fillMode.equals(FillMode.CLIP))
          {
            fs = new FillStyle(FillStyle.FILL_BITS | FillStyle.FILL_BITS_CLIP, matrix, tag);
          }
          else if (fillMode.equals(FillMode.SCALE))
          {
            //override the scale for matrix
                matrix.scaleX = (int)StrictMath.rint((width*SwfConstants.TWIPS_PER_PIXEL * SwfConstants.FIXED_POINT_MULTIPLE)/(double)tag.width);
                matrix.scaleY = (int)StrictMath.rint((height*SwfConstants.TWIPS_PER_PIXEL * SwfConstants.FIXED_POINT_MULTIPLE)/(double)tag.height);
           
            //fill style does not matter much since the entire area is filled with bitmap
            fs = new FillStyle(FillStyle.FILL_BITS | FillStyle.FILL_BITS_CLIP, matrix, tag);
          }
        }

        // Apply Fill Styles
        ShapeWithStyle sws = new ShapeWithStyle();
        sws.fillstyles = new ArrayList<FillStyle>(1);
        sws.fillstyles.add(fs);

        // Build Raw SWF Shape
        List<ShapeRecord> shapeRecords = ShapeHelper.rectangle(width, height);
        ShapeHelper.setStyles(shapeRecords, 0, 1, 0);
        sws.shapeRecords = shapeRecords;
       

        // Wrap up into a SWF DefineShape Tag
        DefineShape defineShape = new DefineShape(Tag.stagDefineShape4);
        defineShape.bounds = TypeHelper.rect(width, height);
        defineShape.edgeBounds = defineShape.bounds;
        defineShape.shapeWithStyle = sws;
       

        return defineShape;
    }
   
    /**
     * Determines whether the bitmap image should be clipped.
     *
     * @param node The BitmapGraphicNode.
     * @param imageTag the image tag
     *
     * @return boolean if bitmap should be clipped.
     */   
    public static boolean bitmapImageNeedsClipping(DefineBits imageTag, BitmapGraphicNode node)
    {
      if (((node.getFileVersion().equalTo(FXGVersion.v1_0)) && !node.repeat) ||
          (node.fillMode.equals(FillMode.CLIP)))
      {
        if ((imageTag.width < node.width) || (imageTag.height < node.height))
          return true;
      }
     
      return false;
     
    }
   
    /**
     * Determines whether the bitmap fill mode is repeat.
     *
     * @param node The BitmapFillNode.
     * @return boolean if bitmap should repeat.
     */   
    public static boolean bitmapFillModeIsRepeat(BitmapFillNode node)
    {
      if (((node.getFileVersion().equalTo(FXGVersion.v1_0)) && node.repeat) ||
          (node.fillMode.equals(FillMode.REPEAT)))
      {
        return true;
      }
     
      return false;
     
    }
    /**
     * Checks if bitmap fill is clipped.
     *
     * @param fill the fill
     *
     * @return true, if bitmap fill is clipped
     */
    public static boolean isBitmapFillWithClip(FillNode fill)
    {
        if (fill == null)
        return false;
     
      if (fill instanceof BitmapFillNode)
      {
        BitmapFillNode bFill = (BitmapFillNode) fill;
        if (ImageHelper.bitmapFillModeIsRepeat(bFill))
        {
          return false;
        }
        else
        {
          if ((bFill.getFileVersion().equalTo(FXGVersion.v2_0)) && (bFill.fillMode == FillMode.SCALE))
          {
            if (Double.isNaN(bFill.scaleX) && Double.isNaN(bFill.scaleY) &&
                Double.isNaN(bFill.x) && Double.isNaN(bFill.y) &&
                (Double.isNaN(bFill.rotation) || Math.abs(bFill.rotation) < AbstractFXGNode.EPSILON) &&
                bFill.matrix == null)
              return false;
            else
              return true;
          }
          else
          {
            return true;
          }
        }       
       
      }
      return false;
     
    }
   
    /**
     * Creates the define bits.
     *
     * @param in the in
     * @param mimeType the mime type
     *
     * @return the define bits
     *
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public static DefineBits createDefineBits(InputStream in, String mimeType) throws IOException
    {
        // TODO: Investigate faster mechanisms of getting image info and pixels
        byte[] bytes = FileUtils.toByteArray(in);
        Image image = ImageUtil.getImage(bytes);
        if (mimeType == null)
        {
            throw new IOException("Unsupported MIME type");
        }

        PixelGrabber pixelGrabber = null;
        try
        {
            pixelGrabber = ImageUtil.getPixelGrabber(image, null);
        }
        catch (Exception e)
        {
            throw new IOException("Error reading image");
        }

        int width = pixelGrabber.getWidth();
        int height = pixelGrabber.getHeight();

        // JPEG
        if (MIME_JPG.equals(mimeType) || MIME_JPEG.equals(mimeType))
        {
            DefineBits imageTag = new DefineBits(Tag.stagDefineBitsJPEG2);
            imageTag.data = bytes;
            imageTag.width = width;
            imageTag.height = height;
            return imageTag;
        }
        // PNG or GIF
        else if (MIME_PNG.equals(mimeType) || MIME_GIF.equals(mimeType))
        {
            int[] pixels = (int[])pixelGrabber.getPixels();
            DefineBitsLossless imageTag = createDefineBitsLossless(pixels, width, height);
            return imageTag;
        }
        else
        {
            throw new IOException("Unsupported MIME type: " + mimeType);
        }
    }

    /**
     * Creates the define bits lossless.
     *
     * @param pixels the pixels
     * @param width the width
     * @param height the height
     *
     * @return the define bits lossless
     */
    public static DefineBitsLossless createDefineBitsLossless(int[] pixels, int width, int height)
    {
        DefineBitsLossless defineBitsLossless = new DefineBitsLossless(TagValues.stagDefineBitsLossless2);
        defineBitsLossless.format = DefineBitsLossless.FORMAT_24_BIT_RGB;
        defineBitsLossless.width = width;
        defineBitsLossless.height = height;
        defineBitsLossless.data = new byte[pixels.length * 4];

        for (int i = 0; i < pixels.length; i++)
        {
            int offset = i * 4;
            int alpha = (pixels[i] >> 24) & 0xFF;
            defineBitsLossless.data[offset] = (byte)alpha;

            // Premultiply the alpha channel
            if (defineBitsLossless.data[offset] != 0)
            {
                int red = (pixels[i] >> 16) & 0xFF;
                defineBitsLossless.data[offset + 1] = (byte)((red * alpha) / 255);
                int green = (pixels[i] >> 8) & 0xFF;
                defineBitsLossless.data[offset + 2] = (byte)((green * alpha) / 255);
                int blue = pixels[i] & 0xFF;
                defineBitsLossless.data[offset + 3] = (byte)((blue * alpha) / 255);
            }
        }

        return defineBitsLossless;
    }

    /**
     * Create 9 sliced shape.
     *
     * @param bitmap the bitmap
     * @param r the r
     * @param width the width
     * @param height the height
     *
     * @return the define shape
     */
    public static DefineShape create9SlicedShape(DefineBits bitmap, Rect r, double width, double height)
    {
        // Use default width/height information if none specified
        if (Double.isNaN(width))
            width = bitmap.width;

        if (Double.isNaN(height))
            height = bitmap.height;

        int slt = r.xMin;
        int srt = r.xMax;
        int stt = r.yMin;
        int sbt = r.yMax;

        List<ShapeRecord> shapeRecords = new ArrayList<ShapeRecord>(50);
        ShapeWithStyle sws = new ShapeWithStyle();
        sws.fillstyles = new ArrayList<FillStyle>(9);
        sws.shapeRecords = shapeRecords;

        // Apply runtime scale of 20x for twips
        Matrix matrix = new Matrix();
        matrix.scaleX = (int)(SwfConstants.TWIPS_PER_PIXEL * SwfConstants.FIXED_POINT_MULTIPLE);
        matrix.scaleY = (int)(SwfConstants.TWIPS_PER_PIXEL * SwfConstants.FIXED_POINT_MULTIPLE);
        matrix.hasScale = true;

        // Create 9 identical fillstyles as a work around
        for (int i = 0; i < 9; i++)
        {
            FillStyle fs = new FillStyle(FillStyle.FILL_BITS | FillStyle.FILL_BITS_NOSMOOTH, matrix, bitmap);
            sws.fillstyles.add(fs);
        }

        int dxa = slt;
        int dxb = srt - slt;
        int dxc = (int)(bitmap.width * SwfConstants.TWIPS_PER_PIXEL) - srt;

        int dya = stt;
        int dyb = sbt - stt;
        int dyc = (int)(bitmap.height * SwfConstants.TWIPS_PER_PIXEL) - sbt;

        // border
        shapeRecords.add(new StyleChangeRecord(0, dya, 0, 0, 1));
        shapeRecords.add(new StraightEdgeRecord(0, -dya));
        shapeRecords.add(new StraightEdgeRecord(dxa, 0));
        shapeRecords.add(new StyleChangeRecord(0, 0, 2));
        shapeRecords.add(new StraightEdgeRecord(dxb, 0));
        shapeRecords.add(new StyleChangeRecord(0, 0, 3));
        shapeRecords.add(new StraightEdgeRecord(dxc, 0));
        shapeRecords.add(new StraightEdgeRecord(0, dya));
        shapeRecords.add(new StyleChangeRecord(0, 0, 6));
        shapeRecords.add(new StraightEdgeRecord(0, dyb));
        shapeRecords.add(new StyleChangeRecord(0, 0 ,9));
        shapeRecords.add(new StraightEdgeRecord(0, dyc));
        shapeRecords.add(new StraightEdgeRecord(-dxc, 0));
        shapeRecords.add(new StyleChangeRecord(0, 0, 8));
        shapeRecords.add(new StraightEdgeRecord(-dxb, 0));
        shapeRecords.add(new StyleChangeRecord(0, 0, 7));
        shapeRecords.add(new StraightEdgeRecord(-dxa, 0));
        shapeRecords.add(new StraightEdgeRecord(0, -dyc));
        shapeRecords.add(new StyleChangeRecord(0, 0, 4));
        shapeRecords.add(new StraightEdgeRecord(0, -dyb));

        // down 1
        shapeRecords.add(new StyleChangeRecord(dxa, 0, 0, 2, 1));
        shapeRecords.add(new StraightEdgeRecord(0, dya));
        shapeRecords.add(new StyleChangeRecord(0, 5, 4));
        shapeRecords.add(new StraightEdgeRecord(0, dyb));
        shapeRecords.add(new StyleChangeRecord(0, 8, 7));
        shapeRecords.add(new StraightEdgeRecord(0, dyc));

        // down 2
        shapeRecords.add(new StyleChangeRecord(dxa + dxb, 0, 0, 3, 2));
        shapeRecords.add(new StraightEdgeRecord(0, dya));
        shapeRecords.add(new StyleChangeRecord(0, 6, 5));
        shapeRecords.add(new StraightEdgeRecord(0, dyb));
        shapeRecords.add(new StyleChangeRecord(0, 9, 8));
        shapeRecords.add(new StraightEdgeRecord(0, dyc));

        // right 1
        shapeRecords.add(new StyleChangeRecord(0, dya, 0, 1, 4));
        shapeRecords.add(new StraightEdgeRecord(dxa, 0));
        shapeRecords.add(new StyleChangeRecord(0, 2, 5));
        shapeRecords.add(new StraightEdgeRecord(dxb, 0));
        shapeRecords.add(new StyleChangeRecord(0, 3, 6));
        shapeRecords.add(new StraightEdgeRecord(dxc, 0));

        // right 2
        shapeRecords.add(new StyleChangeRecord(0, dya + dyb, 0, 4, 7));
        shapeRecords.add(new StraightEdgeRecord(dxa, 0));
        shapeRecords.add(new StyleChangeRecord(0, 5, 8));
        shapeRecords.add(new StraightEdgeRecord(dxb, 0));
        shapeRecords.add(new StyleChangeRecord(0, 6, 9));
        shapeRecords.add(new StraightEdgeRecord(dxc, 0));

        DefineShape shape = new DefineShape(TagValues.stagDefineShape4);
        shape.bounds = TypeHelper.rect(width, height);
        shape.edgeBounds = shape.bounds;
        shape.shapeWithStyle = sws;
        return shape;
    }

    /**
     * Guess mime type.
     *
     * @param path the path
     *
     * @return the string
     */
    public static String guessMimeType(String path)
    {
        if (path != null)
        {
            path = path.toLowerCase();
            if (path.endsWith(".png"))
                return MIME_PNG;
            if (path.endsWith(".gif"))
                return MIME_GIF;
            if (path.endsWith(".jpg"))
                return MIME_JPG;
            if (path.endsWith(".jpeg"))
                return MIME_JPEG;
        }

        return null;
    }
}
TOP

Related Classes of com.adobe.internal.fxg.swf.ImageHelper

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.