Package railo.runtime.img

Source Code of railo.runtime.img.Image

package railo.runtime.img;

import java.awt.AWTException;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.font.TextAttribute;
import java.awt.geom.AffineTransform;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.QuadCurve2D;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.PackedColorModel;
import java.awt.image.PixelGrabber;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.ParameterBlock;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.text.AttributedString;
import java.util.Iterator;
import java.util.Locale;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.FileImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
import javax.media.jai.BorderExtender;
import javax.media.jai.BorderExtenderConstant;
import javax.media.jai.Interpolation;
import javax.media.jai.JAI;
import javax.media.jai.LookupTableJAI;
import javax.media.jai.operator.ShearDir;
import javax.media.jai.operator.TransposeType;
import javax.swing.ImageIcon;

import org.apache.commons.codec.binary.Base64;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import railo.commons.io.IOUtil;
import railo.commons.io.res.Resource;
import railo.commons.lang.StringUtil;
import railo.commons.lang.font.FontUtil;
import railo.runtime.PageContext;
import railo.runtime.dump.DumpData;
import railo.runtime.dump.DumpProperties;
import railo.runtime.dump.DumpTable;
import railo.runtime.exp.CasterException;
import railo.runtime.exp.ExpressionException;
import railo.runtime.exp.PageException;
import railo.runtime.exp.PageRuntimeException;
import railo.runtime.img.filter.QuantizeFilter;
import railo.runtime.img.gif.GifEncoder;
import railo.runtime.op.Caster;
import railo.runtime.op.Constants;
import railo.runtime.op.Decision;
import railo.runtime.text.xml.XMLUtil;
import railo.runtime.type.Array;
import railo.runtime.type.ArrayImpl;
import railo.runtime.type.Collection;
import railo.runtime.type.ObjectWrap;
import railo.runtime.type.Struct;
import railo.runtime.type.StructImpl;
import railo.runtime.type.dt.DateTime;
import railo.runtime.type.util.ArrayUtil;
import railo.runtime.type.util.ListUtil;
import railo.runtime.type.util.StructSupport;

public class Image extends StructSupport implements Cloneable,Struct {
  private static final long serialVersionUID = -2370381932689749657L;


  public static final int BORDER_TYPE_CONSTANT=-1;

 
  public static final int INTERPOLATION_NONE=0;
  public static final int INTERPOLATION_NEAREST=1;
  public static final int INTERPOLATION_BILINEAR=2;
  public static final int INTERPOLATION_BICUBIC=3;

  public static final int IP_NONE=0;
 
  public static final int IPC_NEAREST=1;
  public static final int IPC_BILINEAR=2;
  public static final int IPC_BICUBIC=3;
  public static final int IPC_MAX=3;
 
  public static final int IP_HIGHESTQUALITY=100;
  public static final int IP_HIGHQUALITY=101;
  public static final int IP_MEDIUMQUALITY=102;
  public static final int IP_HIGHESTPERFORMANCE=103;
  public static final int IP_HIGHPERFORMANCE=104;
  public static final int IP_MEDIUMPERFORMANCE=105;
 
  public static final int IP_BESSEL=109;
  public static final int IP_BLACKMAN=110;
  public static final int IP_HAMMING=111;
  public static final int IP_HANNING=112;
  public static final int IP_HERMITE=113;
  public static final int IP_LANCZOS=114;
  public static final int IP_MITCHELL=115;
  public static final int IP_QUADRATIC=116;
  public static final int IP_TRIANGLE=117;

  private static final int ANTI_ALIAS_NONE=0;
  private static final int ANTI_ALIAS_ON=1;
  private static final int ANTI_ALIAS_OFF=2;


  private static final String FORMAT = "javax_imageio_1.0";
 
  private BufferedImage _image;
  private Resource source=null;
  private String format;

  private Graphics2D graphics;

  private Color bgColor;
  private Color fgColor;
  private Color xmColor;

  private float tranparency=-1;
  private int antiAlias=ANTI_ALIAS_NONE;

  private Stroke stroke;

  private Struct sctInfo;


  private float alpha=1;


  private Composite composite;
  private static Object sync=new Object();

 
  static {
    ImageIO.scanForPlugins();
  }

  public Image(byte[] binary) throws IOException {
    this(binary, null);
  }
 
  public Image(byte[] binary, String format) throws IOException {
    if(StringUtil.isEmpty(format))format=ImageUtil.getFormat(binary,null);
    checkRestriction();
    this.format=format;
    _image=ImageUtil.toBufferedImage(binary,format);
    if(_image==null) throw new IOException("can not read in image");
  }

  public Image(Resource res) throws IOException {
    this(res,null);
  }
  public Image(Resource res, String format) throws IOException {
    if(StringUtil.isEmpty(format))format=ImageUtil.getFormat(res);
    checkRestriction();
    this.format=format;
    _image=ImageUtil.toBufferedImage(res,format);
    this.source=res;
    if(_image==null) throw new IOException("can not read in file "+res);
  }


  public Image(BufferedImage image) {
    checkRestriction();
    this._image=image;
  }
 

  public Image(String b64str) throws IOException, ExpressionException {
    this(ImageUtil.readBase64(b64str),null);
  }
 
  public Image(String b64str, String format) throws IOException, ExpressionException {
    this(ImageUtil.readBase64(b64str),format);
  }

  public Image(int width, int height, int imageType, Color canvasColor) throws ExpressionException {
    checkRestriction();
    _image = new BufferedImage(width, height, imageType);
    if(!StringUtil.isEmpty(canvasColor)){
     
      setBackground(canvasColor);
      clearRect(0, 0, width, height);
    }
  }

  public Image() {
    checkRestriction();
  }

   
 

  /**
   * add a border to image
   * @param thickness
   * @param color
   * @param borderType
   */
  public void addBorder(int thickness, Color color, int borderTypethrows ExpressionException{
   
    double colorArray[] = {color.getRed(), color.getGreen(), color.getBlue()};
    BorderExtender borderExtender = new BorderExtenderConstant(colorArray);
   
    ParameterBlock params = new ParameterBlock();
    params.addSource(image());
    params.add(thickness);
    params.add(thickness);
    params.add(thickness);
    params.add(thickness);
    if(BORDER_TYPE_CONSTANT==borderTypeparams.add(borderExtender);
    else   params.add(BorderExtender.createInstance(borderType));
    //else if(BORDER_TYPE_WRAP==borderType)params.add(BorderExtender.createInstance(BorderExtender.BORDER_REFLECT));

    image((JAI.create("border", params)).getAsBufferedImage());
   
  }
 
  public void blur(int blurFactorthrows ExpressionException{
      ParameterBlock params = new ParameterBlock();
    params.addSource(image());
    params.add(blurFactor);
    RenderingHints hint= new RenderingHints(JAI.KEY_BORDER_EXTENDER,BorderExtender.createInstance(1));
    image(JAI.create("boxfilter", params, hint).getAsBufferedImage());
  }

  public void clearRect(int x, int y, int width, int heightthrows ExpressionException{
    getGraphics().clearRect(x, y, width, height);
  }
 

  public Struct info()  throws ExpressionException{
    if(sctInfo!=null) return sctInfo;
   
    Struct sctInfo=new StructImpl(),sct;
   
   
    sctInfo.setEL("height",new Double(getHeight()));
    sctInfo.setEL("width",new Double(getWidth()));
    sctInfo.setEL("source",source==null?"":source.getAbsolutePath());
    //sct.setEL("mime_type",getMimeType());
   
    ColorModel cm = image().getColorModel();
    sct=new StructImpl();
    sctInfo.setEL("colormodel",sct);
   
    sct.setEL("alpha_channel_support",Caster.toBoolean(cm.hasAlpha()));
    sct.setEL("alpha_premultiplied",Caster.toBoolean(cm.isAlphaPremultiplied()));
    sct.setEL("transparency",toStringTransparency(cm.getTransparency()));
    sct.setEL("pixel_size",Caster.toDouble(cm.getPixelSize()));
    sct.setEL("num_components",Caster.toDouble(cm.getNumComponents()));
    sct.setEL("num_color_components",Caster.toDouble(cm.getNumColorComponents()));
    sct.setEL("colorspace",toStringColorSpace(cm.getColorSpace()));
   
      //bits_component
    int[] bitspercomponent = cm.getComponentSize();
    Array arr=new ArrayImpl();
    Double value;
      for (int i = 0; i < bitspercomponent.length; i++) {
        sct.setEL("bits_component_" + (i + 1),value=new Double(bitspercomponent[i]));
        arr.appendEL(value);
      }
    sct.setEL("bits_component",arr);
   
      // colormodel_type
    if (cm instanceof ComponentColorModel)    sct.setEL("colormodel_type", "ComponentColorModel");
    else if (cm instanceof IndexColorModel)    sct.setEL("colormodel_type", "IndexColorModel");
    else if (cm instanceof PackedColorModelsct.setEL("colormodel_type", "PackedColorModel");
    else sct.setEL("colormodel_type", ListUtil.last(cm.getClass().getName(), '.'));

   
    getMetaData(sctInfo);
   
    ImageMeta.addInfo(format,source,sctInfo);
   
    this.sctInfo=sctInfo;
    return sctInfo;
  }

  public IIOMetadata getMetaData(Struct parent) {
        InputStream is=null;
        javax.imageio.stream.ImageInputStreamImpl iis=null;
      try {
         
          if(source instanceof File) {
        iis=new FileImageInputStream((File) source);
      }
      else if(source==null)iis=new MemoryCacheImageInputStream(new ByteArrayInputStream(getImageBytes(format,true)));
      else iis=new MemoryCacheImageInputStream(is=source.getInputStream());
     
            Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
            if (readers.hasNext()) {
              // pick the first available ImageReader
                ImageReader reader = readers.next();
                IIOMetadata meta=null;
                synchronized (sync) {
                  // attach source to the reader
                  reader.setInput(iis, true);
 
                  // read metadata of first image
                  meta = reader.getImageMetadata(0);
                  meta.setFromTree(FORMAT, meta.getAsTree(FORMAT));
                  reader.reset();
                }
                // generating dump
                if(parent!=null){
                  String[] formatNames = meta.getMetadataFormatNames();
          for(int i=0;i<formatNames.length;i++) {
            Node root = meta.getAsTree(formatNames[i]);
            //print.out(XMLCaster.toString(root));
            addMetaddata(parent,"metadata",root);
          }
                }
                return meta;
            }
        }
        catch (Throwable t) {}
        finally{
          ImageUtil.closeEL(iis);
      IOUtil.closeEL(is);
        }
        return null;
    }

  private void addMetaddata(Struct parent, String name, Node node) {
   
   
    // attributes
    NamedNodeMap attrs = node.getAttributes();
    Attr attr;
    int len=attrs.getLength();
    if(len==1 && "value".equals(attrs.item(0).getNodeName())) {
      parent.setEL(name, attrs.item(0).getNodeValue());
    }
    else {
      Struct sct=metaGetChild(parent,name);
      for(int i=attrs.getLength()-1;i>=0;i--) {
        attr=(Attr) attrs.item(i);
        sct.setEL(attr.getName(), attr.getValue());
      }
    }
   
   
    // child nodes
    NodeList children = XMLUtil.getChildNodes(node, Node.ELEMENT_NODE);
    Element el;
    for(int i=children.getLength()-1;i>=0;i--) {
      el=(Element) children.item(i);
      Struct sct = metaGetChild(parent,name);
      addMetaddata(sct, el.getNodeName(),children.item(i));
    }
  }

  private Struct metaGetChild(Struct parent, String name) {
    Object child=parent.get(name,null);
    if(child instanceof Struct) return (Struct) child;
    Struct sct=new StructImpl();
    parent.setEL(name, sct);
    return sct;
  }

  public void sharpen(float gainthrows ExpressionException{
    ParameterBlock params = new ParameterBlock();
    params.addSource(image());
    params.add((Object) null);
    params.add(new Float(gain));
    image(JAI.create("unsharpmask", params).getAsBufferedImage());
  }
 
  public void setTranparency(float percentthrows ExpressionException{
    if(percent==-1)return;
    tranparency=percent;
    AlphaComposite rule = AlphaComposite.getInstance(3, 1.0F-(percent/100.0F));
    getGraphics().setComposite(rule);
  }

   public void invert()  throws ExpressionException{
    ParameterBlock params = new ParameterBlock();
    params.addSource(image());
    image(JAI.create("invert", params).getAsBufferedImage());
  }

    public Image copy(float x, float y, float width, float heightthrows ExpressionException{
      ParameterBlock params = new ParameterBlock();
      params.addSource(image());
      params.add(x);
      params.add(y);
      params.add(width);
      params.add(height);
      //image(JAI.create("crop", params).getAsBufferedImage());
      return new Image(JAI.create("crop", params).getAsBufferedImage());
    }
   
    public Image copy(float x, float y, float width, float height, float dx,float dythrows ExpressionException{
      Image img = copy(x, y, width, height);
    img.getGraphics().copyArea((int)x, (int)y, (int)width, (int)height, (int)(dx-x), (int)(dy-y));
    return img;
    }

    public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle, boolean filledthrows ExpressionException{
      if (filled)
        getGraphics().fillArc(x, y, width, height, startAngle, arcAngle);
      else
        getGraphics().drawArc(x, y, width, height, startAngle, arcAngle);
    }
   

    public void draw3DRect(int x, int y, int width, int height, boolean raised, boolean filledthrows ExpressionException{
      if (filled)
        getGraphics().fill3DRect(x, y, width+1, height+1, raised);
      else
        getGraphics().draw3DRect(x, y, width, height, raised);
    }
   
    public void drawCubicCurve(double ctrlx1, double ctrly1, double ctrlx2, double ctrly2,double x1, double y1, double x2, double y2throws ExpressionException{
      CubicCurve2D curve = new CubicCurve2D.Double(x1,y1,ctrlx1,ctrly1,ctrlx2,ctrly2,x2,y2);
    getGraphics().draw(curve);
    }

    public void drawPoint(int x, int y) throws ExpressionException {
      drawLine(x, y, x + 1, y);
    }
   
    public void drawQuadraticCurve(double x1, double y1, double ctrlx, double ctrly, double x2, double y2throws ExpressionException {
      QuadCurve2D curve = new QuadCurve2D.Double(x1, y1, ctrlx, ctrly, x2, y2);
      getGraphics().draw(curve);
    }
   
    public void drawRect(int x, int y, int width, int height, boolean filledthrows ExpressionException {
      if (filled)
          getGraphics().fillRect(x, y, width + 1, height + 1);
      else
        getGraphics().drawRect(x, y, width, height);
    }
   
    public void drawRoundRect(int x, int y, int width, int height,int arcWidth, int arcHeight, boolean filledthrows ExpressionException{
      if (filled)
        getGraphics().fillRoundRect(x, y, width + 1, height + 1, arcWidth,arcHeight);
      else
        getGraphics().drawRoundRect(x, y, width, height, arcWidth, arcHeight);
    }
   


  public void drawLine(int x1, int y1, int x2, int y2throws ExpressionException{
      getGraphics().drawLine(x1, y1, x2, y2);
    }

  public void drawImage(Image img,int x, int ythrows ExpressionException{
      getGraphics().drawImage(img.image(), x, y,null);
    }

  public void drawImage(Image img,int x, int y, int width, int heightthrows ExpressionException{
      getGraphics().drawImage(img.image(), x, y,width,height,null);
    }
 
    public void drawLines(int[] xcoords, int[] ycoords, boolean isPolygon,boolean filledthrows ExpressionException{
      if (isPolygon) {
        if (filledgetGraphics().fillPolygon(xcoords, ycoords, xcoords.length);
        else     getGraphics().drawPolygon(xcoords, ycoords, xcoords.length);
      }
      else {
              getGraphics().drawPolyline(xcoords, ycoords, xcoords.length);
      }
    }
    public void drawOval(int x, int y, int width, int height, boolean filled) throws ExpressionException {
      if (filledgetGraphics().fillOval(x, y, width, height);
      else getGraphics().drawOval(x, y, width, height);
  }
   
    public void drawString(String text, int x, int y, Struct attr) throws PageException {
     
      if (attr != null && attr.size()>0) {

          // font
           String font=StringUtil.toLowerCase(Caster.toString(attr.get("font",""))).trim();
             if(!StringUtil.isEmpty(font)) {
               font=FontUtil.getFont(font).getFontName();
             }
             else font = "Serif";
            
       // alpha
        //float alpha=Caster.toFloatValue(attr.get("alpha",null),1F);
         
       // size
          int size=Caster.toIntValue(attr.get("size", Constants.INTEGER_10));

       // style
          int style=Font.PLAIN;
          String strStyle=StringUtil.toLowerCase(Caster.toString(attr.get("style","")));
          strStyle=StringUtil.removeWhiteSpace(strStyle);
          if(!StringUtil.isEmpty(strStyle)) {
            if("plain".equals(strStyle)) style=Font.PLAIN;
            else if("bold".equals(strStyle)) style=Font.BOLD;
            else if("italic".equals(strStyle)) style=Font.ITALIC;
            else if("bolditalic".equals(strStyle)) style=Font.BOLD+Font.ITALIC;
            else if("bold,italic".equals(strStyle)) style=Font.BOLD+Font.ITALIC;
            else if("italicbold".equals(strStyle)) style=Font.BOLD+Font.ITALIC;
            else if("italic,bold".equals(strStyle)) style=Font.BOLD+Font.ITALIC;
            else throw new ExpressionException(
                "key style of argument attributeCollection has an invalid value ["+strStyle+"], valid values are [plain,bold,italic,bolditalic]");
          }

       // strikethrough
          boolean strikethrough = Caster.toBooleanValue(attr.get("strikethrough",Boolean.FALSE));
         
       // underline
          boolean underline = Caster.toBooleanValue(attr.get("underline",Boolean.FALSE));
         
          AttributedString as = new AttributedString(text);
          as.addAttribute(TextAttribute.FONT, new Font(font, style, size));
          if(strikethroughas.addAttribute(TextAttribute.STRIKETHROUGH,TextAttribute.STRIKETHROUGH_ON);
          if(underline)    as.addAttribute(TextAttribute.UNDERLINE,TextAttribute.UNDERLINE_ON);
          Graphics2D g = getGraphics();
          //if(alpha!=1D) setAlpha(g,alpha);
         
          g.drawString(as.getIterator(), x, y);
      }
      else getGraphics().drawString(text, x, y);
       
    }
   
   
    /*private void setAlpha(Graphics2D graphics,float alpha) {
      //Composite originalComposite = graphics.getComposite();
     
      AlphaComposite alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
       
      graphics.setComposite(alphaComposite);
      //graphics.setComposite(originalComposite); 
  }*/

  public void setDrawingStroke(Struct attr) throws PageException {
     
      // empty
      if(attr==null || attr.size()==0) {
        setDrawingStroke(new BasicStroke());
        return;
      }
     
      // width
      float width=Caster.toFloatValue(attr.get("width",new Float(1F)));
      if(width<0) throw new ExpressionException("key [width] should be a none negativ number");
     
      // endcaps
      String strEndcaps=Caster.toString(attr.get("endcaps","square"));
      strEndcaps=strEndcaps.trim().toLowerCase();
      int endcaps;
      if("square".equals(strEndcaps))    endcaps = BasicStroke.CAP_SQUARE;
      else if("butt".equals(strEndcaps))  endcaps = BasicStroke.CAP_BUTT;
      else if("round".equals(strEndcaps))  endcaps = BasicStroke.CAP_ROUND;
      else throw new ExpressionException("key [endcaps] has an invalid value ["+strEndcaps+"], valid values are [square,round,butt]");
     
      // linejoins
      String strLinejoins=Caster.toString(attr.get("linejoins","miter"));
      strLinejoins=strLinejoins.trim().toLowerCase();
      int linejoins;
      if("bevel".equals(strLinejoins))    linejoins = BasicStroke.JOIN_BEVEL;
      else if("miter".equals(strLinejoins))  linejoins = BasicStroke.JOIN_MITER;
      else if("round".equals(strLinejoins))  linejoins = BasicStroke.JOIN_ROUND;
      else throw new ExpressionException("key [linejoins] has an invalid value ["+strLinejoins+"], valid values are [bevel,miter,round]");
     
      // miterlimit
      float miterlimit = 10.0F;
      if(linejoins==BasicStroke.JOIN_MITER) {
        miterlimit=Caster.toFloatValue(attr.get("miterlimit",new Float(10F)));
          if(miterlimit<1F) throw new ExpressionException("key [miterlimit] should be greater or equal to 1");
      }
     
      // dashArray
      Object oDashArray=attr.get("dashArray",null);
      float[] dashArray=null;
      if(oDashArray!=null) {
        dashArray=ArrayUtil.toFloatArray(oDashArray);
      }
     
      // dash_phase
      float dash_phase=Caster.toFloatValue(attr.get("dash_phase",new Float(0F)));
     
     
     
      setDrawingStroke(width, endcaps, linejoins, miterlimit, dashArray, dash_phase);
    }
       
    public void setDrawingStroke(float width, int endcaps, int linejoins,float miterlimit, float[] dash,float dash_phasethrows ExpressionException {
      setDrawingStroke(new BasicStroke(width, endcaps, linejoins, miterlimit, dash, dash_phase));
  }
     
  public void setDrawingStroke(Stroke stroke) throws ExpressionException {
    if(stroke==null) return;
    this.stroke=stroke;
      getGraphics().setStroke(stroke);
  }
   
   
    public void flip(TransposeType transpose) throws ExpressionException {
      ParameterBlock params = new ParameterBlock();
      params.addSource(image());
      params.add(transpose);
      image(JAI.create("transpose", params).getAsBufferedImage());
    }

    public void grayscale() throws ExpressionException {
      BufferedImage img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_BYTE_GRAY);
      Graphics2D graphics = img.createGraphics();
      graphics.drawImage(image(),new AffineTransformOp(AffineTransform.getTranslateInstance(0.0, 0.0),1),0, 0);
      graphics.dispose();
      image(img);
    }

    public void rgb() throws ExpressionException {
      BufferedImage img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_BYTE_INDEXED);
      Graphics2D graphics = img.createGraphics();
      graphics.drawImage(image(),new AffineTransformOp(AffineTransform.getTranslateInstance(0.0, 0.0),1),0, 0);
      graphics.dispose();
      image(img);
     
    }
    public void threeBBger() throws ExpressionException {
      BufferedImage img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
      Graphics2D graphics = img.createGraphics();
      graphics.drawImage(image(),new AffineTransformOp(AffineTransform.getTranslateInstance(0.0, 0.0),1),0, 0);
      graphics.dispose();
      image(img);
    }
   
    public void overlay(Image topImage) throws ExpressionException {
      ParameterBlock params = new ParameterBlock();
      params.addSource(image());
      params.addSource(topImage.image());
      image(JAI.create("overlay", params).getAsBufferedImage());
    }
   
    public void paste(Image topImage, int x, int y) throws ExpressionException {
      RenderingHints interp = new RenderingHints(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);
      BorderExtender extender = BorderExtender.createInstance(1);
      Graphics2D g = getGraphics();
      g.addRenderingHints(new RenderingHints(JAI.KEY_BORDER_EXTENDER,extender));
      g.drawImage(topImage.image(), (new AffineTransformOp(AffineTransform.getTranslateInstance(x,y),interp)), 0, 0);
     
    }
   
    public void setXorMode(Color color) throws ExpressionException {
      if(color==null) return;
      xmColor=color;
      getGraphics().setXORMode(color);
    }
   

    public void translate(int xtrans, int ytrans, Object interpolation) throws ExpressionException {
     
      RenderingHints hints = new RenderingHints(RenderingHints.KEY_INTERPOLATION,interpolation);
      if(interpolation!=RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR) {
        hints.add(new RenderingHints(JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(1)));
      }
     
      ParameterBlock pb = new ParameterBlock();
      pb.addSource(image());
      BufferedImage img = JAI.create("translate", pb).getAsBufferedImage();
      Graphics2D graphics = img.createGraphics();
      graphics.clearRect(0, 0, img.getWidth(), img.getHeight());
      AffineTransform at = new AffineTransform();
      at.setToIdentity();
      graphics.drawImage(image(), new AffineTransformOp(at, hints), xtrans, ytrans);
      graphics.dispose();
      image(img);
    }
   
    public void translateAxis(int x, int y) throws ExpressionException {
      getGraphics().translate(x, y);
    }

    public void rotateAxis(double angle) throws ExpressionException {
      getGraphics().rotate(Math.toRadians(angle));
    }
       
    public void rotateAxis(double angle, double x, double y) throws ExpressionException {
      getGraphics().rotate(Math.toRadians(angle), x, y);
    }
       
    public void shearAxis(double shx, double shy) throws ExpressionException {
      getGraphics().shear(shx, shy);
    }
   
    public void shear(float shear, ShearDir direction, Object interpolation) throws ExpressionException {
      ParameterBlock params = new ParameterBlock();
      params.addSource(image());
      params.add(shear);
      params.add(direction);
      params.add(0.0F);
      params.add(0.0F);
      RenderingHints hints = null;
     
      if (interpolation==RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
          params.add(Interpolation.getInstance(0));
      else if (interpolation==RenderingHints.VALUE_INTERPOLATION_BILINEAR) {
          params.add(Interpolation.getInstance(1));
          BorderExtender extender = BorderExtender.createInstance(1);
          hints = new RenderingHints(JAI.KEY_BORDER_EXTENDER, extender);
      }
      else if (interpolation==RenderingHints.VALUE_INTERPOLATION_BICUBIC) {
          params.add(Interpolation.getInstance(2));
          BorderExtender extender = BorderExtender.createInstance(1);
          hints = new RenderingHints(JAI.KEY_BORDER_EXTENDER, extender);
      }
      // TODO
      Color bg = getGraphics().getBackground();
      params.add(new double[]{bg.getRed(),bg.getGreen(),bg.getBlue()});
      image(JAI.create("shear", params, hints).getAsBufferedImage());
    }
   
  public BufferedImage getBufferedImage() throws ExpressionException {
    return image();
  }
  public BufferedImage image() throws ExpressionException {
    if(_image==null) throw (new ExpressionException("image is not initalized"));
    return _image;
  }
  public void image(BufferedImage image) {
    this._image=image;
    graphics=null;
   
    sctInfo=null;
  }
 
    private Graphics2D getGraphics() throws ExpressionException {
    if(graphics==null) {
      graphics=image() .createGraphics();
      // reset all properties
      if(antiAlias!=ANTI_ALIAS_NONEsetAntiAliasing(antiAlias==ANTI_ALIAS_ON);
      if(bgColor!=nullsetBackground(bgColor);
      if(fgColor!=nullsetColor(fgColor);
      if(alpha!=1)    setAlpha(alpha);
      if(tranparency!=-1setTranparency(tranparency);
      if(xmColor!=nullsetXorMode(xmColor);
      if(stroke!=nullsetDrawingStroke(stroke);
    }
      return graphics;
  }
   
   
  private String toStringColorSpace(ColorSpace colorSpace) {
    switch (colorSpace.getType()) {
      case 0: return "Any of the family of XYZ color spaces";
      case 1: return "Any of the family of Lab color spaces";
      case 2: return "Any of the family of Luv color spaces";
      case 3: return "Any of the family of YCbCr color spaces";
      case 4:return "Any of the family of Yxy color spaces";
      case 5: return "Any of the family of RGB color spaces";
      case 6: return "Any of the family of GRAY color spaces";
      case 7: return "Any of the family of HSV color spaces";
      case 8: return "Any of the family of HLS color spaces";
      case 9: return "Any of the family of CMYK color spaces";
      case 11: return "Any of the family of CMY color spaces";
      case 12: return "Generic 2 component color space.";
      case 13: return "Generic 3 component color space.";
      case 14: return "Generic 4 component color space.";
      case 15: return "Generic 5 component color space.";
      case 16: return "Generic 6 component color space.";
      case 17: return "Generic 7 component color space.";
      case 18: return "Generic 8 component color space.";
      case 19: return "Generic 9 component color space.";
      case 20: return "Generic 10 component color space.";
      case 21: return "Generic 11 component color space.";
      case 22: return "Generic 12 component color space.";
      case 23: return "Generic 13 component color space.";
      case 24: return "Generic 14 component color space.";
      case 25: return "Generic 15 component color space.";
      case 1001: return "CIEXYZ";
      case 1003: return "GRAY";
      case 1004: return "LINEAR_RGB";
      case 1002: return "PYCC";
      case 1000: return "sRGB";
      }
   
    return "Unknown ColorSpace" + colorSpace;
  }

  private Object toStringTransparency(int transparency) {
    if(Transparency.OPAQUE==transparency)     return "OPAQUE";
    if(Transparency.BITMASK==transparency)     return "BITMASK";
    if(Transparency.TRANSLUCENT==transparencyreturn "TRANSLUCENT";
    return "Unknown type of transparency";
  }
 
  public String writeBase64(Resource destination, String format, boolean inHTMLFormat) throws PageException, IOException {
    // destination
    if(destination==null) {
      if(source!=null)destination=source;
      else throw new IOException("missing destination file");
    }
   
    String content = getBase64String(format);
    if(inHTMLFormat) content="data:image/" + format + ";base64,"+content;
    IOUtil.write(destination, content, (Charset)null, false);
    return content;
  }
 
  public String getBase64String(String format) throws PageException {
    byte[] imageBytes = getImageBytes(format);
    return new String(Base64.encodeBase64(imageBytes));
  }
 
  public void writeOut(Resource destination, boolean overwrite, float quality) throws IOException, ExpressionException {
    String format = ImageUtil.getFormatFromExtension(destination,null);
    writeOut(destination, format, overwrite, quality);
  }
 
  public void writeOut(Resource destination, String format,boolean overwrite, float quality) throws IOException, ExpressionException {
    if(destination==null) {
      if(source!=null)destination=source;
      else throw new IOException("missing destination file");
    }
   
    if(destination.exists()) {
      if(!overwrite)throw new IOException("can't overwrite existing image");
    }

      if(JAIUtil.isSupportedWriteFormat(format)){
        JAIUtil.write(getBufferedImage(),destination,format);
        return;
      }
    OutputStream os=null;
    ImageOutputStream ios = null;
    try {
      os=destination.getOutputStream();
      ios = ImageIO.createImageOutputStream(os);
      _writeOut(ios, format, quality);
    }
    finally {
      ImageUtil.closeEL(ios);
      IOUtil.closeEL(os);
    }   
  }

 
  public static void writeOutGif(BufferedImage src, OutputStream os) throws IOException {
    BufferedImage dst = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_ARGB);
    QuantizeFilter filter=new QuantizeFilter();
    filter.setSerpentine(true);
    filter.setDither(true);
    //filter.setNumColors(8);
    filter.filter(src, dst);
   

    //image(Quantizer.quantize(image(), 8));
    try {
      GifEncoder enc = new GifEncoder(dst);
      enc.Write(os);
      os.flush();
    } catch (AWTException e) {
      throw new IOException(e.getMessage());
    }
  }
 
  public void writeOut(OutputStream os, String format,float quality, boolean closeStream) throws IOException, ExpressionException {
    ImageOutputStream ios = ImageIO.createImageOutputStream(os);
    try{
      _writeOut(ios, format, quality);
    }
    finally{
      IOUtil.closeEL(ios);
    }
  }

  private void _writeOut(ImageOutputStream ios, String format,float quality) throws IOException, ExpressionException {
    _writeOut(ios, format, quality, false);
  }
 
  private void _writeOut(ImageOutputStream ios, String format,float quality,boolean noMeta) throws IOException, ExpressionException {
    if(quality<0 || quality>1)
      throw new IOException("quality has an invalid value ["+quality+"], value has to be between 0 and 1");
    if(StringUtil.isEmpty(format))  format=this.format;
    if(StringUtil.isEmpty(format))  throw new IOException("missing format");
   
    BufferedImage im = image();
   
    //IIOMetadata meta = noMeta?null:metadata(format);
    IIOMetadata meta = noMeta?null:getMetaData(null);
   
   
   
    ImageWriter writer = null;
      ImageTypeSpecifier type =ImageTypeSpecifier.createFromRenderedImage(im);
      Iterator<ImageWriter> iter = ImageIO.getImageWriters(type, format);
     
     
      if (iter.hasNext()) {
        writer = iter.next();
      }
      if (writer == null) throw new IOException("no writer for format ["+format+"] available, available writer formats are ["+ListUtil.arrayToList(ImageUtil.getWriterFormatNames(), ",")+"]");
     
     
    ImageWriteParam iwp=null;
      if("jpg".equalsIgnoreCase(format)) {
        ColorModel cm = im.getColorModel();
        if(cm.hasAlpha())im=jpgImage(im);
        JPEGImageWriteParam jiwp = new JPEGImageWriteParam(Locale.getDefault());
        jiwp.setOptimizeHuffmanTables(true);
        iwp=jiwp;
      }
      else iwp = writer.getDefaultWriteParam();
     
    setCompressionModeEL(iwp,ImageWriteParam.MODE_EXPLICIT);
      setCompressionQualityEL(iwp,quality);
      writer.setOutput(ios);
      try {
        writer.write(meta, new IIOImage(im, null, meta), iwp);
       
      }
      finally {
        writer.dispose();
        ios.flush();
      }
  }
 
  private BufferedImage jpgImage(BufferedImage src) {
        int w = src.getWidth();
        int h = src.getHeight();
        SampleModel srcSM = src.getSampleModel();
        WritableRaster srcWR = src.getRaster();
        java.awt.image.DataBuffer srcDB = srcWR.getDataBuffer();
       
        ColorModel rgb = new DirectColorModel(32, 0xff0000, 65280, 255);
        int[] bitMasks = new int[]{0xff0000, 65280, 255};
       
        SampleModel csm = new SinglePixelPackedSampleModel(3, w, h, bitMasks);
        int data[] = new int[w * h];
        for(int i = 0; i < h; i++) {
            for(int j = 0; j < w; j++) {
                int pix[] = null;
                int sample[] = srcSM.getPixel(j, i, pix, srcDB);
                if(sample[3] == 0 && sample[2] == 0 && sample[1] == 0 && sample[0] == 0)
                    data[i * w + j] = 0xffffff;
                else
                    data[i * w + j] = sample[0] << 16 | sample[1] << 8 | sample[2];
            }

        }

        java.awt.image.DataBuffer db = new DataBufferInt(data, w * h * 3);
        WritableRaster wr = Raster.createWritableRaster(csm, db, new Point(0, 0));
        return new BufferedImage(rgb, wr, false, null);
    }

  private void setCompressionModeEL(ImageWriteParam iwp, int mode) {
    try {
      iwp.setCompressionMode(mode);
    }
    catch(Throwable t) {}
  }

  private void setCompressionQualityEL(ImageWriteParam iwp, float quality) {
    try {
      iwp.setCompressionQuality(quality);
    }
    catch(Throwable t) {}
  }

  public void convert(String format) {
    this.format=format;
  }

  public void scaleToFit(String fitWidth, String fitHeight,String interpolation, double blurFactor) throws PageException {
    if (StringUtil.isEmpty(fitWidth) || StringUtil.isEmpty(fitHeight)) 
      resize(fitWidth, fitHeight, interpolation, blurFactor);
    else {
      float width = Caster.toFloatValue(fitWidth) / getWidth();
      float height= Caster.toFloatValue(fitHeight) / getHeight();
      if (width < heightresize(fitWidth, "", interpolation, blurFactor);
      else        resize("", fitHeight, interpolation, blurFactor);
    }
  }
 
 
 
  /**
     * Convenience method that returns a scaled instance of the
     * provided {@code BufferedImage}.
     *
     * @param img the original image to be scaled
     * @param targetWidth the desired width of the scaled instance,
     *    in pixels
     * @param targetHeight the desired height of the scaled instance,
     *    in pixels
     * @param hint one of the rendering hints that corresponds to
     *    {@code RenderingHints.KEY_INTERPOLATION} (e.g.
     *    {@code RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR},
     *    {@code RenderingHints.VALUE_INTERPOLATION_BILINEAR},
     *    {@code RenderingHints.VALUE_INTERPOLATION_BICUBIC})
     * @param higherQuality if true, this method will use a multi-step
     *    scaling technique that provides higher quality than the usual
     *    one-step technique (only useful in downscaling cases, where
     *    {@code targetWidth} or {@code targetHeight} is
     *    smaller than the original dimensions, and generally only when
     *    the {@code BILINEAR} hint is specified)
     * @return a scaled version of the original {@code BufferedImage}
     */
    private BufferedImage getScaledInstance(BufferedImage img,
                                           int targetWidth,
                                           int targetHeight,
                                           Object hint,
                                           boolean higherQuality)
    {
        // functionality not supported in java 1.4
      int transparency=Transparency.OPAQUE;
      try {
      transparency=img.getTransparency();
    }
      catch (Throwable t) {}
      int type = (transparency == Transparency.OPAQUE) ?BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
       
     
     
      BufferedImage ret = img;
        int w, h;
        if (higherQuality) {
            // Use multi-step technique: start with original size, then
            // scale down in multiple passes with drawImage()
            // until the target size is reached
            w = img.getWidth();
            h = img.getHeight();
        } else {
            // Use one-step technique: scale directly from original
            // size to target size with a single drawImage() call
            w = targetWidth;
            h = targetHeight;
        }
       
        do {
            if (higherQuality && w > targetWidth) {
                w /= 2;
                if (w < targetWidth) {
                    w = targetWidth;
                }
            }

            if (higherQuality && h > targetHeight) {
                h /= 2;
                if (h < targetHeight) {
                    h = targetHeight;
                }
            }

            BufferedImage tmp = new BufferedImage(w, h, type);
            Graphics2D g2 = tmp.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
            g2.drawImage(ret, 0, 0, w, h, null);
            g2.dispose();

            ret = tmp;
        } while (w != targetWidth || h != targetHeight);

        return ret;
    }

 
 
 
 
    public void resize(int scale, String interpolation, double blurFactor) throws PageException {
      if (blurFactor <= 0.0 || blurFactor > 10.0)
      throw new ExpressionException("blurFactor must be between 0 and 10");
     
    float width=getWidth()/100F*scale;
    float height=getHeight()/100F*scale;
     
    resize((int)width, (int)height, toInterpolation(interpolation), blurFactor);
    }
 
    public void resize(String strWidth, String strHeight, String interpolation, double blurFactor) throws PageException {
    if (StringUtil.isEmpty(strWidth,true) && StringUtil.isEmpty(strHeight,true))
      throw new ExpressionException("you have to define width or height");
    if (blurFactor <= 0.0 || blurFactor > 10.0)
      throw new ExpressionException("blurFactor must be between 0 and 10");
    int w = getWidth();
    int h = getHeight();
    float height=resizeDimesion("height",strHeight, h);
    float width=resizeDimesion("width",strWidth, w);
   
    if(height==-1height=h*(width/w);
    if(width==-1width=w*(height/h);
     
    resize((int)width, (int)height, toInterpolation(interpolation), blurFactor);
    }
 
    public void resizeImage2(int width, int height) throws ExpressionException{
      image(getScaledInstance(image(),width,height,RenderingHints.VALUE_INTERPOLATION_BILINEAR,false));
    }
 
    public void resizeImage(int width, int height, int interpolation) throws ExpressionException{
      Object ip;
      if(interpolation==IPC_NEAREST)    ip=RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
      else if(interpolation==IPC_BICUBICip=RenderingHints.VALUE_INTERPOLATION_BICUBIC;
      else if(interpolation==IPC_BILINEARip=RenderingHints.VALUE_INTERPOLATION_BILINEAR;
      else throw new ExpressionException("invalid interpoltion definition");
     
      BufferedImage dst = new BufferedImage(width,height,image().getType());
        Graphics2D graphics = dst.createGraphics();
        graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,ip);
        graphics.drawImage(image(), 0, 0, width, height, null);
        graphics.dispose();
        image(dst);
       
    }
 
  private float resizeDimesion(String label,String strDimension, float originalDimension) throws PageException {
    if (StringUtil.isEmpty(strDimension,true)) return -1;
    strDimension=strDimension.trim();
   
    if (StringUtil.endsWith(strDimension, '%')) {
      float p = Caster.toFloatValue(strDimension.substring(0,(strDimension.length()- 1))) / 100.0F;
      return originalDimension*p;
    }
    float dimension = Caster.toFloatValue(strDimension);
    if (dimension <= 0F)
      throw new ExpressionException(label+" has to be a none negative number");
    return dimension;
  }
 
 

    public void resize(int width, int height, int interpolation, double blurFactor) throws ExpressionException {
     
    ColorModel cm = image().getColorModel();
   
      if (interpolation==IP_HIGHESTPERFORMANCE)  {
        interpolation = IPC_BICUBIC;
      }
     
      if (cm.getColorSpace().getType() == ColorSpace.TYPE_GRAY && cm.getComponentSize()[0] == 8) {
        if (interpolation==IP_HIGHESTQUALITY || interpolation==IP_HIGHPERFORMANCE || interpolation==IP_HIGHQUALITY || interpolation==IP_MEDIUMPERFORMANCE || interpolation==IP_MEDIUMQUALITY)  {
          interpolation = IPC_BICUBIC;
        }
        if (interpolation!=IPC_BICUBIC && interpolation!=IPC_BILINEAR && interpolation!=IPC_NEAREST)  {
          throw new ExpressionException("invalid grayscale interpolation");
        }
      }
     
      if (interpolation<=IPC_MAX)  {
        resizeImage(width, height, interpolation);
      }
      else {
        image(ImageResizer.resize(image(), width, height, interpolation, blurFactor));
     
      }
  }
   
   
   
    /*private BufferedImage resizeImageWithJAI(float scaleWidth, float scaleHeight, int interpolation) throws ExpressionException {
      ParameterBlock params = new ParameterBlock();
      params.addSource(image());
    params.add(scaleWidth);
    params.add(scaleHeight);
    params.add(0.0F);
    params.add(0.0F);
    RenderingHints hints = null;
    if (interpolation != IP_NONE) {
        if (interpolation==IP_NEAREST)  {
          params.add(Interpolation.getInstance(0));
        }
        else if (interpolation==IP_BILINEAR) {
          params.add(Interpolation.getInstance(1));
          BorderExtender extender = BorderExtender.createInstance(1);
          hints = new RenderingHints(JAI.KEY_BORDER_EXTENDER, extender);
        }
        else if (interpolation==IP_BICUBIC) {
          params.add(Interpolation.getInstance(2));
          BorderExtender extender = BorderExtender.createInstance(1);
          hints = new RenderingHints(JAI.KEY_BORDER_EXTENDER, extender);
        }
        else  {
          throw new ExpressionException("invalid interpolation definition");
        }
    }
    return JAI.create("scale", params, hints).getAsBufferedImage();
    }*/
 
    private double toScale(int src, int dst) {
      double tmp = Math.round((int)((Caster.toDoubleValue(dst)/Caster.toDoubleValue(src))*100D));
      return tmp/100D;
  }

  public void rotate(float x, float y, float angle, int interpolation) throws ExpressionException {
      if(x==-1)x = (float)getWidth() / 2;
      if(y==-1)y = (float)getHeight() / 2;
   
      angle = (float) Math.toRadians(angle);
      ColorModel cmSource = image().getColorModel();
     
      if (cmSource instanceof IndexColorModel && cmSource.hasAlpha() && !cmSource.isAlphaPremultiplied()) {
        image(PaletteToARGB(image()));
          cmSource = image().getColorModel();
      }
     
      BufferedImage alpha = null;
      if (cmSource.hasAlpha() && !cmSource.isAlphaPremultiplied()) {
          alpha = getAlpha(image());
          image(removeAlpha(image()));
      }
     
      Interpolation interp = Interpolation.getInstance(0);
      if (INTERPOLATION_BICUBIC==interpolationinterp = Interpolation.getInstance(1);
      else if (INTERPOLATION_BILINEAR==interpolation)    interp = Interpolation.getInstance(2);
     
      if (alpha != null) {
          ParameterBlock params = new ParameterBlock();
          params.addSource(alpha);
          params.add(x);
          params.add(y);
          params.add(angle);
          params.add(interp);
          params.add(new double[] { 0.0 });
          RenderingHints hints= new RenderingHints(RenderingHints.KEY_INTERPOLATION,(RenderingHints.VALUE_INTERPOLATION_BICUBIC));
          hints.add(new RenderingHints(JAI.KEY_BORDER_EXTENDER,new BorderExtenderConstant(new double[] { 255.0 })));
          hints.add(new RenderingHints(JAI.KEY_REPLACE_INDEX_COLOR_MODEL,Boolean.TRUE));
          alpha = JAI.create("rotate", params, hints).getAsBufferedImage();
      }
     
      ParameterBlock params = new ParameterBlock();
      params.addSource(image());
      params.add(x);
      params.add(y);
      params.add(angle);
      params.add(interp);
      params.add(new double[] { 0.0 });
      BorderExtender extender= new BorderExtenderConstant(new double[] { 0.0 });
      RenderingHints hints= new RenderingHints(JAI.KEY_BORDER_EXTENDER, extender);
      hints.add(new RenderingHints(JAI.KEY_REPLACE_INDEX_COLOR_MODEL, Boolean.TRUE));
      image(JAI.create("rotate", params, hints).getAsBufferedImage());
      if (alpha != null)image(addAlpha(image(), alpha, 0, 0));
    }
   
    private static BufferedImage PaletteToARGB(BufferedImage src) {
      IndexColorModel icm = (IndexColorModel) src.getColorModel();
      int bands = icm.hasAlpha()?4:3;
     
      byte[][] data = new byte[bands][icm.getMapSize()];
      if (icm.hasAlpha()) icm.getAlphas(data[3]);
      icm.getReds(data[0]);
      icm.getGreens(data[1]);
      icm.getBlues(data[2]);
      LookupTableJAI rtable = new LookupTableJAI(data);
      return JAI.create("lookup", src, rtable).getAsBufferedImage();
    }

   
    private static BufferedImage getAlpha(BufferedImage src) {
  return JAI.create("bandselect", src, new int[] { 3 }).getAsBufferedImage();
    }
   
    private static BufferedImage removeAlpha(BufferedImage src) {
      return JAI.create("bandselect", src, new int[] { 0, 1, 2 }).getAsBufferedImage();
    }
   
    private static BufferedImage addAlpha(BufferedImage src, BufferedImage alpha, int x, int y) {
      int w = src.getWidth();
      int h = src.getHeight();
      BufferedImage bi = new BufferedImage(w, h, 2);
      WritableRaster wr = bi.getWritableTile(0, 0);
      WritableRaster wr3 = wr.createWritableChild(0, 0, w, h, 0, 0, new int[] { 0, 1, 2 });
      WritableRaster wr1 = wr.createWritableChild(0, 0, w, h, 0, 0, new int[] { 3 });
      wr3.setRect(src.getData());
      wr1.setRect(alpha.getData());
      bi.releaseWritableTile(0, 0);
      return bi;
    }

 

  public void _rotate(float x, float y, float angle, String interpolation) throws ExpressionException {

    float radiansAngle = (float)Math.toRadians(angle);

    // rotation center
    float centerX = (float)getWidth() / 2;
    float centerY = (float)getHeight() / 2;
   
    ParameterBlock pb = new ParameterBlock();
    pb.addSource(image());
    pb.add(centerX);
    pb.add(centerY);
    pb.add(radiansAngle);
    pb.add(new javax.media.jai.InterpolationBicubic(10));
   
    // create a new, rotated image
    image(JAI.create("rotate", pb).getAsBufferedImage());

  }

  public static Image toImage(Object obj) throws PageException {
    if(obj instanceof Image) return (Image) obj;
    if(obj instanceof ObjectWrap) return toImage(((ObjectWrap)obj).getEmbededObject());
    throw new CasterException(obj,"Image");
  }
 
  public static boolean isImage(Object obj) {
    if(obj instanceof Image) return true;
    if(obj instanceof ObjectWrap) return isImage(((ObjectWrap)obj).getEmbededObject(""));
    return false;
  }

  public static Image createImage(PageContext pc,Object obj, boolean check4Var, boolean clone, boolean checkAccess, String format) throws PageException {
    try {
      if(obj instanceof String || obj instanceof Resource || obj instanceof File) {
        try {
          Resource res = Caster.toResource(pc,obj,true);
          pc.getConfig().getSecurityManager().checkFileLocation(res);
          return new Image(res,format);
        }
        catch (ExpressionException ee) {
          if(check4Var && Decision.isVariableName(Caster.toString(obj))) {
            try {
              return createImage(pc, pc.getVariable(Caster.toString(obj)), false,clone,checkAccess,format);
            }
            catch (Throwable t) {
              throw ee;
            }
          }
          try {
            return new Image(Caster.toString(obj),format);
          }
          catch (Throwable t) {
            throw ee;
          }
        }
      }
      if(obj instanceof Image)  {
        if(clone)return (Image) ((Image)obj).clone();
        return (Image)obj;
      }
      if(Decision.isBinary(obj))      return new Image(Caster.toBinary(obj),format);
      if(obj instanceof BufferedImagereturn new Image(((BufferedImage) obj));
      if(obj instanceof java.awt.Imagereturn new Image(toBufferedImage((java.awt.Image) obj));
     
    } catch (Throwable t) {
      throw Caster.toPageException(t);
    }
    throw new CasterException(obj,"Image");
  }

  @Override
  public Collection duplicate(boolean deepCopy) {
    try {
      //if(_image!=null) return new Image(getBufferedImage());
      return new Image(getImageBytes(null));
     
    } catch (Exception e) {
      throw new PageRuntimeException(e.getMessage());
    }
  }
 
 
 

  public ColorModel getColorModel() throws ExpressionException {
    return image().getColorModel();
  }
   
    public void crop(float x, float y, float width, float height) throws ExpressionException {
      ParameterBlock params = new ParameterBlock();
      params.addSource(image());
      params.add(x);
      params.add(y);

      float w = getWidth();
      float h = getHeight();
     
      if (w < x + width) params.add(w - x);
      else params.add(width);
     
      if (h < y + height) params.add(h - y);
      else params.add(height);
     
      image(JAI.create("crop", params).getAsBufferedImage());
    }
   
    public int getWidth() throws ExpressionException {
      return image().getWidth();
    }
   
    public int getHeight() throws ExpressionException {
      return image().getHeight();
    }

  public String getFormat() {
    return format;
  }

  public byte[] getImageBytes(String format) throws PageException{
    return getImageBytes(format,false);
  }
  public byte[] getImageBytes(String format,boolean noMeta) throws PageException {
   
   
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
   
    if(JAIUtil.isSupportedWriteFormat(format)){
        try {
        JAIUtil.write(getBufferedImage(),baos,format);
      }catch (IOException e) {
        throw Caster.toPageException(e);
      }
      }
    else {
      ImageOutputStream ios = null;
      try {
        ios = ImageIO.createImageOutputStream(baos);
        _writeOut(ios, format, 1,noMeta);
      } catch (IOException e) {
        throw Caster.toPageException(e);
      }
      finally {
        IOUtil.closeEL(ios);
      }
    }
    return baos.toByteArray();
  }

  public void setColor(Color color) throws ExpressionException {
    if(color==null) return;
    fgColor=color;
    getGraphics().setColor(color);
  }
 
  public void setAlpha(float alpha) throws ExpressionException {
    this.alpha=alpha;
    Graphics2D g = getGraphics();
   
    Composite alphaComposite;
    if(composite==null) {
      if(alpha==1) return;
      composite = g.getComposite();
    }
    if(alpha==1) alphaComposite=composite;
    else alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
       
      g.setComposite(alphaComposite);
      //graphics.setComposite(originalComposite); 
 
 
  public void setBackground(Color color) throws ExpressionException {
    if(color==null) return;
    bgColor=color;
    getGraphics().setBackground(color);
  }
 
  public void setAntiAliasing(boolean antiAlias) throws ExpressionException {
    this.antiAlias=antiAlias?ANTI_ALIAS_ON:ANTI_ALIAS_OFF;
    Graphics2D graphics = getGraphics();
    if(antiAlias) {
        graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
    }
    else {
        graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
    }
  }
 
  private Struct _info() {
    try {
      return info();
    } catch (ExpressionException e) {
      throw new PageRuntimeException(e);
    }
  }

  @Override
  public void clear() {
    throw new RuntimeException("can't clear struct, struct is readonly");
  }

  @Override
  public boolean containsKey(Key key) {
    return _info().containsKey(key);
  }

  @Override
  public Object get(Key key) throws PageException {
    return info().get(key);
  }

  @Override
  public Object get(Key key, Object defaultValue) {
    return _info().get(key, defaultValue);
  }

  @Override
  public Key[] keys() {
    return _info().keys();
  }

  @Override
  public Object remove(Key key) throws PageException {
    throw new ExpressionException("can't remove key ["+key.getString()+"] from struct, struct is readonly");
  }

  @Override
  public Object removeEL(Key key) {
    throw new PageRuntimeException("can't remove key ["+key.getString()+"] from struct, struct is readonly");
  }

  @Override
  public Object set(Key key, Object value) throws PageException {
    throw new ExpressionException("can't set key ["+key.getString()+"] to struct, struct is readonly");
  }

  @Override
  public Object setEL(Key key, Object value) {
    throw new PageRuntimeException("can't set key ["+key.getString()+"] to struct, struct is readonly");
  }

  @Override
  public int size() {
    return _info().size();
  }

  @Override
  public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
    DumpData dd = _info().toDumpData(pageContext, maxlevel,dp);
    if(dd instanceof DumpTable)((DumpTable)dd).setTitle("Struct (Image)");
    return dd;
  }

  @Override
  public Iterator<Collection.Key> keyIterator() {
    return _info().keyIterator();
  }
   
    @Override
  public Iterator<String> keysAsStringIterator() {
      return _info().keysAsStringIterator();
    }
 
  @Override
  public Iterator<Entry<Key, Object>> entryIterator() {
    return _info().entryIterator();
  }
 
  @Override
  public Iterator<Object> valueIterator() {
    return _info().valueIterator();
  }

  @Override
  public boolean castToBooleanValue() throws PageException {
    return info().castToBooleanValue();
  }

  @Override
  public Boolean castToBoolean(Boolean defaultValue) {
    try {
      return info().castToBoolean(defaultValue);
    } catch (ExpressionException e) {
      return defaultValue;
    }
  }

  @Override
  public DateTime castToDateTime() throws PageException {
    return info().castToDateTime();
  }
   
    @Override
    public DateTime castToDateTime(DateTime defaultValue) {
        try {
      return info().castToDateTime(defaultValue);
    } catch (ExpressionException e) {
      return defaultValue;
    }
    }

  @Override
  public double castToDoubleValue() throws PageException {
    return info().castToDoubleValue();
  }
   
    @Override
    public double castToDoubleValue(double defaultValue) {
        try {
      return info().castToDoubleValue(defaultValue);
    } catch (ExpressionException e) {
      return defaultValue;
    }
    }

  @Override
  public String castToString() throws PageException {
    return info().castToString();
  }
  @Override
  public String castToString(String defaultValue) {
    try {
      return info().castToString(defaultValue);
    } catch (ExpressionException e) {
      return defaultValue;
    }
  }

  @Override
  public int compareTo(String str) throws PageException {
    return info().compareTo(str);
  }

  @Override
  public int compareTo(boolean b) throws PageException {
    return info().compareTo(b);
  }

  @Override
  public int compareTo(double d) throws PageException {
    return info().compareTo(d);
  }

  @Override
  public int compareTo(DateTime dt) throws PageException {
    return info().compareTo(dt);
  }

  private static void checkRestriction()  {
    try {
      if(JAI.class==null) return;
    }
    catch(Throwable t) {
      throw new PageRuntimeException("the JAI extension is missing, please download [railo-x.x.x.xxx-jars.zip] on http://www.railo-technologies.com/en/download and copy it into the railo lib directory");
   
  }
 
  public static int toInterpolation(String strInterpolation) throws ExpressionException {
    if(StringUtil.isEmpty(strInterpolation))
      throw new ExpressionException("interpolation definition is empty");
    strInterpolation=strInterpolation.trim().toLowerCase();
   
    if("highestquality".equals(strInterpolation))      return IP_HIGHESTQUALITY;
    else if("highquality".equals(strInterpolation))     return IP_HIGHQUALITY;
    else if("mediumquality".equals(strInterpolation))     return IP_MEDIUMQUALITY;
    else if("highestperformance".equals(strInterpolation))   return IP_HIGHESTPERFORMANCE;
    else if("highperformance".equals(strInterpolation))   return IP_HIGHPERFORMANCE;
    else if("mediumperformance".equals(strInterpolation))   return IP_MEDIUMPERFORMANCE;
    else if("nearest".equals(strInterpolation))       return IPC_NEAREST;
    else if("bilinear".equals(strInterpolation))       return IPC_BILINEAR;
    else if("bicubic".equals(strInterpolation))       return IPC_BICUBIC;
    else if("bessel".equals(strInterpolation))         return IP_BESSEL;
    else if("blackman".equals(strInterpolation))       return IP_BLACKMAN;
    else if("hamming".equals(strInterpolation))       return IP_HAMMING;
    else if("hanning".equals(strInterpolation))       return IP_HANNING;
    else if("hermite".equals(strInterpolation))       return IP_HERMITE;
    else if("lanczos".equals(strInterpolation))       return IP_LANCZOS;
    else if("mitchell".equals(strInterpolation))       return IP_MITCHELL;
    else if("quadratic".equals(strInterpolation))       return IP_QUADRATIC;

    throw new ExpressionException("interpolation definition ["+strInterpolation+"] is invalid");
  }

  /**
   * @return the source
   */
  public Resource getSource() {
    return source;
  }

  @Override
  public boolean containsValue(Object value) {
    try {
      return info().containsValue(value);
    }
    catch (ExpressionException e) {
      return false;
    }
  }

  @Override
  public java.util.Collection values() {
    try {
      return info().values();
    } catch (ExpressionException e) {
      throw new PageRuntimeException(e);
    }
  }

  /**
   * This method returns true if the specified image has transparent pixels
   * @param image
   * @return
   */
  public static boolean hasAlpha(java.awt.Image image) {
      // If buffered image, the color model is readily available
      if (image instanceof BufferedImage) {
          BufferedImage bimage = (BufferedImage)image;
          return bimage.getColorModel().hasAlpha();
      }

      // Use a pixel grabber to retrieve the image's color model;
      // grabbing a single pixel is usually sufficient
       PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
      try {
          pg.grabPixels();
      } catch (InterruptedException e) {
      }

      // Get the image's color model
      ColorModel cm = pg.getColorModel();
      return cm.hasAlpha();
  }
 
  // This method returns a buffered image with the contents of an image
  public static BufferedImage toBufferedImage(java.awt.Image image) {
      if (image instanceof BufferedImage) {
          return (BufferedImage)image;
      }

      // This code ensures that all the pixels in the image are loaded
      image = new ImageIcon(image).getImage();

      // Determine if the image has transparent pixels; for this method's
      boolean hasAlpha = hasAlpha(image);

      // Create a buffered image with a format that's compatible with the screen
      BufferedImage bimage = null;
      GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
      try {
          // Determine the type of transparency of the new buffered image
          int transparency = Transparency.OPAQUE;
          if (hasAlpha) {
              transparency = Transparency.BITMASK;
          }

          // Create the buffered image
          GraphicsDevice gs = ge.getDefaultScreenDevice();
          GraphicsConfiguration gc = gs.getDefaultConfiguration();
          bimage = gc.createCompatibleImage(
              image.getWidth(null), image.getHeight(null), transparency);
      } catch (HeadlessException e) {
          // The system does not have a screen
      }

      if (bimage == null) {
          // Create a buffered image using the default color model
          int type = BufferedImage.TYPE_INT_RGB;
          if (hasAlpha) {
              type = BufferedImage.TYPE_INT_ARGB;
          }
          bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
      }

      // Copy image to buffered image
      Graphics g = bimage.createGraphics();

      // Paint the image onto the buffered image
      g.drawImage(image, 0, 0, null);
      g.dispose();

      return bimage;
  }
 
}
TOP

Related Classes of railo.runtime.img.Image

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.