001 /* 002 * 003 004 Licensed under the Apache License, Version 2.0 (the "License"); 005 you may not use this file except in compliance with the License. 006 You may obtain a copy of the License at 007 008 http://www.apache.org/licenses/LICENSE-2.0 009 010 Unless required by applicable law or agreed to in writing, software 011 distributed under the License is distributed on an "AS IS" BASIS, 012 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 See the License for the specific language governing permissions and 014 limitations under the License. 015 */ 016 017 package railo.runtime.img.math; 018 019 import java.awt.Image; 020 import java.awt.image.BufferedImage; 021 import java.awt.image.ImageObserver; 022 import java.awt.image.PixelGrabber; 023 024 import railo.runtime.img.filter.ImageMath; 025 import railo.runtime.img.filter.PixelUtils; 026 027 public class ImageFunction2D implements Function2D { 028 029 public final static int ZERO = 0; 030 public final static int CLAMP = 1; 031 public final static int WRAP = 2; 032 033 protected int[] pixels; 034 protected int width; 035 protected int height; 036 protected int edgeAction = ZERO; 037 protected boolean alpha = false; 038 039 public ImageFunction2D(BufferedImage image) { 040 this(image, false); 041 } 042 043 public ImageFunction2D(BufferedImage image, boolean alpha) { 044 this(image, ZERO, alpha); 045 } 046 047 public ImageFunction2D(BufferedImage image, int edgeAction, boolean alpha) { 048 init( getRGB( image, 0, 0, image.getWidth(), image.getHeight(), null), image.getWidth(), image.getHeight(), edgeAction, alpha); 049 } 050 051 public ImageFunction2D(int[] pixels, int width, int height, int edgeAction, boolean alpha) { 052 init(pixels, width, height, edgeAction, alpha); 053 } 054 055 public ImageFunction2D(Image image) { 056 this( image, ZERO, false ); 057 } 058 059 public ImageFunction2D(Image image, int edgeAction, boolean alpha) { 060 PixelGrabber pg = new PixelGrabber(image, 0, 0, -1, -1, null, 0, -1); 061 try { 062 pg.grabPixels(); 063 } catch (InterruptedException e) { 064 throw new RuntimeException("interrupted waiting for pixels!"); 065 } 066 if ((pg.status() & ImageObserver.ABORT) != 0) { 067 throw new RuntimeException("image fetch aborted"); 068 } 069 init((int[])pg.getPixels(), pg.getWidth(), pg.getHeight(), edgeAction, alpha); 070 } 071 072 /** 073 * A convenience method for getting ARGB pixels from an image. This tries to avoid the performance 074 * penalty of BufferedImage.getRGB unmanaging the image. 075 */ 076 public int[] getRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) { 077 int type = image.getType(); 078 if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB ) 079 return (int [])image.getRaster().getDataElements( x, y, width, height, pixels ); 080 return image.getRGB( x, y, width, height, pixels, 0, width ); 081 } 082 083 public void init(int[] pixels, int width, int height, int edgeAction, boolean alpha) { 084 this.pixels = pixels; 085 this.width = width; 086 this.height = height; 087 this.edgeAction = edgeAction; 088 this.alpha = alpha; 089 } 090 091 public float evaluate(float x, float y) { 092 int ix = (int)x; 093 int iy = (int)y; 094 if (edgeAction == WRAP) { 095 ix = ImageMath.mod(ix, width); 096 iy = ImageMath.mod(iy, height); 097 } else if (ix < 0 || iy < 0 || ix >= width || iy >= height) { 098 if (edgeAction == ZERO) 099 return 0; 100 if (ix < 0) 101 ix = 0; 102 else if (ix >= width) 103 ix = width-1; 104 if (iy < 0) 105 iy = 0; 106 else if (iy >= height) 107 iy = height-1; 108 } 109 return alpha ? ((pixels[iy*width+ix] >> 24) & 0xff) / 255.0f : PixelUtils.brightness(pixels[iy*width+ix]) / 255.0f; 110 } 111 112 public void setEdgeAction(int edgeAction) { 113 this.edgeAction = edgeAction; 114 } 115 116 public int getEdgeAction() { 117 return edgeAction; 118 } 119 120 public int getWidth() { 121 return width; 122 } 123 124 public int getHeight() { 125 return height; 126 } 127 128 public int[] getPixels() { 129 return pixels; 130 } 131 } 132