Package org.apache.flex.compiler.internal.fxg.swf

Source Code of org.apache.flex.compiler.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 org.apache.flex.compiler.internal.fxg.swf;

import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.ImageObserver;
import java.awt.image.PixelGrabber;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.flex.compiler.fxg.FXGVersion;
import org.apache.flex.compiler.internal.embedding.transcoders.JPEGTranscoder;
import org.apache.flex.compiler.internal.fxg.dom.AbstractFXGNode;
import org.apache.flex.compiler.internal.fxg.dom.BitmapGraphicNode;
import org.apache.flex.compiler.internal.fxg.dom.IFillNode;
import org.apache.flex.compiler.internal.fxg.dom.fills.BitmapFillNode;
import org.apache.flex.compiler.internal.fxg.dom.types.FillMode;

import org.apache.flex.swf.ISWFConstants;
import org.apache.flex.swf.tags.DefineBitsJPEG2Tag;
import org.apache.flex.swf.tags.DefineBitsLossless2Tag;
import org.apache.flex.swf.tags.DefineBitsLosslessTag;
import org.apache.flex.swf.tags.DefineShape4Tag;
import org.apache.flex.swf.tags.DefineShapeTag;
import org.apache.flex.swf.types.FillStyle;
import org.apache.flex.swf.types.FillStyleArray;
import org.apache.flex.swf.types.LineStyleArray;
import org.apache.flex.swf.types.Matrix;
import org.apache.flex.swf.types.Rect;
import org.apache.flex.swf.types.ShapeRecord;
import org.apache.flex.swf.types.ShapeWithStyle;
import org.apache.flex.swf.types.StraightEdgeRecord;
import org.apache.flex.swf.types.StyleChangeRecord;
import org.apache.flex.swf.types.Styles;
import org.apache.flex.utils.FileUtils;
import org.apache.flex.utils.Trace;

/**
* Utilities to help create SWF DefineBits and DefineBitsLossess image tags.
*/
public class ImageHelper
{
    public static final String MIME_GIF = "image/gif";
    public static final String MIME_JPEG = "image/jpeg";
    public static final String MIME_JPG = "image/jpg";
    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 image 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 DefineShapeTag createShapeForImage(DefineImage image, 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 = image.getWidth();

        if (Double.isNaN(height))
            height = image.getHeight();

        // Create Fill Style
        Matrix matrix = new Matrix();
        double twx = (ISWFConstants.TWIPS_PER_PIXEL);
        matrix.setScale(twx, twx);
       
        FillStyle fs = null;
        if (fileVersion.equalTo(FXGVersion.v1_0))
        {
          if (repeat)
            fs = new FillStyle(FillStyle.REPEATING_BITMAP_FILL, matrix, image.getTag());
          else
            fs = new FillStyle(FillStyle.CLIPPED_BITMAP_FILL, matrix, image.getTag());
        }
        else
        {
          if (fillMode.equals(FillMode.REPEAT))
          {
            fs = new FillStyle(FillStyle.REPEATING_BITMAP_FILL, matrix, image.getTag());
          }
          else if (fillMode.equals(FillMode.CLIP))
          {
            fs = new FillStyle(FillStyle.CLIPPED_BITMAP_FILL, matrix, image.getTag());
          }
          else if (fillMode.equals(FillMode.SCALE))
          {
            //override the scale for matrix
              double fwidth = (width*ISWFConstants.TWIPS_PER_PIXEL)/(double)image.getWidth();
              double fheight = (height*ISWFConstants.TWIPS_PER_PIXEL)/(double)image.getHeight();
               
              //For consistency with the 4.5.1 snapshot of the flex compiler.
              fwidth = ((double)StrictMath.rint(0x10000 * fwidth))/((double)0x10000);
              fheight = ((double)StrictMath.rint(0x10000 * fheight))/((double)0x10000);
             
              matrix.setScale(fwidth, fheight);
           
            //fill style does not matter much since the entire area is filled with bitmap
            fs = new FillStyle(FillStyle.CLIPPED_BITMAP_FILL, matrix, image.getTag());
          }
        }

        // Apply Fill Styles
        FillStyleArray styleArray = new FillStyleArray();
        styleArray.add(fs);
        LineStyleArray lineStyleArray = new LineStyleArray();
       
        Styles styles = new Styles(styleArray, lineStyleArray);

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

        // Wrap up into a SWF DefineShape Tag
        DefineShape4Tag defineShape = new DefineShape4Tag();
        defineShape.setShapeBounds(TypeHelper.rect(width, height));
        defineShape.setEdgeBounds(defineShape.getShapeBounds());
        defineShape.setShapes(sws);

        return defineShape;
    }
   
    /**
     * Determines whether the bitmap image should be clipped.
     *
     * @param defImage The  tag encoding the image.
     * @param node The BitmapGraphicNode.
      * @return boolean if bitmap should be clipped.
     */   
    public static boolean bitmapImageNeedsClipping(DefineImage defImage, BitmapGraphicNode node)
    {
      if (((node.getFileVersion().equalTo(FXGVersion.v1_0)) && !node.repeat) ||
          (node.fillMode.equals(FillMode.CLIP)))
      {
        if ((defImage.getWidth() < node.width) || (defImage.getHeight() < 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;
     
    }
    public static boolean isBitmapFillWithClip(IFillNode 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;
     
    }

    public static DefineImage createDefineBits(InputStream in, String mimeType) throws IOException
    {
        // TODO: Investigate faster mechanisms of getting image info and pixels
        byte[] bytes = FileUtils.toByteArray(in);
        Image image = getImage(bytes);
        if (mimeType == null)
        {
            throw new IOException("Unsupported MIME type");
        }

        PixelGrabber pixelGrabber = null;
        try
        {
            pixelGrabber = 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))
        {
            DefineBitsJPEG2Tag imageTag = new DefineBitsJPEG2Tag();
            imageTag.setImageData(bytes);
            return new DefineImage(imageTag, width, height);
        }
        // PNG or GIF
        else if (MIME_PNG.equals(mimeType) || MIME_GIF.equals(mimeType))
        {
            int[] pixels = (int[])pixelGrabber.getPixels();
            DefineImage defimage = createDefineBitsLossless(pixels, width, height);
            return defimage;
        }
        else
        {
            throw new IOException("Unsupported MIME type: " + mimeType);
        }
    }

    public static DefineImage createDefineBitsLossless(int[] pixels, int width, int height) throws IOException
    {
        DefineBitsLossless2Tag defineBitsLossless = new DefineBitsLossless2Tag();
        defineBitsLossless.setBitmapFormat(DefineBitsLosslessTag.BF_24BIT_RGB_IMAGE);
        defineBitsLossless.setBitmapWidth(width);
        defineBitsLossless.setBitmapHeight(height);

        byte data[] = new byte[pixels.length * 4];

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

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

    public static DefineShapeTag create9SlicedShape(DefineImage bitmap, Rect r, double width, double height)
    {
        // Use default width/height information if none specified
        if (Double.isNaN(width))
            width = bitmap.getWidth();

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

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

        FillStyleArray fillStyleArray = new FillStyleArray(9);
        LineStyleArray lineStyleArray = new LineStyleArray();
        List<ShapeRecord> shapeRecords = new ArrayList<ShapeRecord>(50);

        // Apply runtime scale of 20x for twips
        Matrix matrix = new Matrix();
       
        double twx = (ISWFConstants.TWIPS_PER_PIXEL);
        matrix.setScale(twx, twx);
       
        // Create 9 identical fillstyles as a work around
        for (int i = 0; i < 9; i++)
        {
            FillStyle fs = new FillStyle(FillStyle.NON_SMOOTHED_REPEATING_BITMAP, matrix, bitmap.getTag());
            fillStyleArray.add(fs);
        }
        Styles styles = new Styles(fillStyleArray, lineStyleArray);
       
        int dxa = slt;
        int dxb = srt - slt;
        int dxc = (int)(bitmap.getWidth() * ISWFConstants.TWIPS_PER_PIXEL) - srt;

        int dya = stt;
        int dyb = sbt - stt;
        int dyc = (int)(bitmap.getHeight() * ISWFConstants.TWIPS_PER_PIXEL) - sbt;

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

        shapeRecords.add(new StraightEdgeRecord(0, -dyb));

        // down 1
       
        scr = new StyleChangeRecord();
        scr.setMove(dxa, 0);
        scr.setDefinedStyles(2, 1, -1, styles);
        shapeRecords.add(scr);
       
        shapeRecords.add(new StraightEdgeRecord(0, dya));
       
        scr = new StyleChangeRecord();
        scr.setDefinedStyles(5, 4, -1, styles);
        shapeRecords.add(scr);
       
        shapeRecords.add(new StraightEdgeRecord(0, dyb));
       
        scr = new StyleChangeRecord();
        scr.setDefinedStyles(8, 7, -1, styles);
        shapeRecords.add(scr);
       
        shapeRecords.add(new StraightEdgeRecord(0, dyc));

        // down 2
        scr = new StyleChangeRecord();
        scr.setMove(dxa + dxb, 0);
        scr.setDefinedStyles(3, 2, -1, styles);
        shapeRecords.add(scr);
       
        shapeRecords.add(new StraightEdgeRecord(0, dya));
       
        scr = new StyleChangeRecord();
        scr.setDefinedStyles(6, 5, -1, styles);
        shapeRecords.add(scr);
       
        shapeRecords.add(new StraightEdgeRecord(0, dyb));
       
        scr = new StyleChangeRecord();
        scr.setDefinedStyles(9, 8, -1, styles);
        shapeRecords.add(scr);
       
        shapeRecords.add(new StraightEdgeRecord(0, dyc));

        // right 1
        scr = new StyleChangeRecord();
        scr.setMove(0, dya);
        scr.setDefinedStyles(1, 4, -1, styles);
        shapeRecords.add(scr);
       
        shapeRecords.add(new StraightEdgeRecord(dxa, 0));
       
        scr = new StyleChangeRecord();
        scr.setDefinedStyles(2, 5, -1, styles);
        shapeRecords.add(scr);

        shapeRecords.add(new StraightEdgeRecord(dxb, 0));
       
        scr = new StyleChangeRecord();
        scr.setDefinedStyles(3, 6, -1, styles);
        shapeRecords.add(scr);

        shapeRecords.add(new StraightEdgeRecord(dxc, 0));

        // right 2       
        scr = new StyleChangeRecord();
        scr.setMove(0, dya + dyb);
        scr.setDefinedStyles(4, 7, -1, styles);
        shapeRecords.add(scr);
        shapeRecords.add(new StraightEdgeRecord(dxa, 0));

        scr = new StyleChangeRecord();
        scr.setDefinedStyles(5, 8, -1, styles);
        shapeRecords.add(scr);

        shapeRecords.add(new StraightEdgeRecord(dxb, 0));

        scr = new StyleChangeRecord();
        scr.setDefinedStyles(6, 9, -1, styles);
        shapeRecords.add(scr);

        shapeRecords.add(new StraightEdgeRecord(dxc, 0));

        ShapeWithStyle sws = new ShapeWithStyle(styles);
        sws.addShapeRecords(shapeRecords);
       
        DefineShape4Tag shape = new DefineShape4Tag();
        shape.setShapeBounds(TypeHelper.rect(width, height));
        shape.setEdgeBounds(shape.getShapeBounds());
        shape.setShapes(sws);
        return shape;
    }

    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;
    }

    private static Image getImage(byte[] bytes)
    {
        Image image;
        try
      {
            image = Toolkit.getDefaultToolkit().createImage(bytes);
        }
        catch (InternalError ie)
        {
            if (Trace.error)
            {
                ie.printStackTrace();
            }
            throw new InternalError("An error occurred because there is no graphics environment available.  Please set the headless-server setting in the Flex configuration file to true.");
        }
        catch (NoClassDefFoundError ce)
        {
            if (Trace.error)
            {
                ce.printStackTrace();
            }
            throw new InternalError("An error occurred because there is no graphics environment available.  Please set the headless-server setting in the Flex configuration file to true.");
        }
        return image;
    }

    private static PixelGrabber getPixelGrabber(Image image, String location)
    {
        PixelGrabber pixelGrabber = new PixelGrabber(image, 0, 0, -1, -1, true);
   
        try
        {
            pixelGrabber.grabPixels();
        }
        catch (InterruptedException interruptedException)
        {
            if (Trace.error)
            {
              interruptedException.printStackTrace();
            }
            throw new RuntimeException("Failed to grab pixels for image " + location);
        }
   
        if (((pixelGrabber.getStatus() & ImageObserver.WIDTH) == 0) ||
        ((pixelGrabber.getStatus() & ImageObserver.HEIGHT) == 0))
        {
          throw new RuntimeException("Failed to grab pixels for image " + location);
        }
   
        return pixelGrabber;
    }
}
TOP

Related Classes of org.apache.flex.compiler.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.