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.filter;import java.awt.Rectangle; 018 import java.awt.image.BufferedImage; 019 020 import railo.runtime.engine.ThreadLocalPageContext; 021 import railo.runtime.exp.FunctionException; 022 import railo.runtime.exp.PageException; 023 import railo.runtime.img.ImageUtil; 024 import railo.runtime.type.KeyImpl; 025 import railo.runtime.type.Struct; 026 import railo.runtime.type.util.CollectionUtil; 027 028 /** 029 * A filter which produces a "oil-painting" effect. 030 */ 031 public class OilFilter extends WholeImageFilter implements DynFiltering { 032 033 private int range = 3; 034 private int levels = 256; 035 036 public OilFilter() { 037 } 038 039 /** 040 * Set the range of the effect in pixels. 041 * @param range the range 042 * @see #getRange 043 */ 044 public void setRange( int range ) { 045 this.range = range; 046 } 047 048 /** 049 * Get the range of the effect in pixels. 050 * @return the range 051 * @see #setRange 052 */ 053 public int getRange() { 054 return range; 055 } 056 057 /** 058 * Set the number of levels for the effect. 059 * @param levels the number of levels 060 * @see #getLevels 061 */ 062 public void setLevels( int levels ) { 063 this.levels = levels; 064 } 065 066 /** 067 * Get the number of levels for the effect. 068 * @return the number of levels 069 * @see #setLevels 070 */ 071 public int getLevels() { 072 return levels; 073 } 074 075 protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) { 076 int index = 0; 077 int[] rHistogram = new int[levels]; 078 int[] gHistogram = new int[levels]; 079 int[] bHistogram = new int[levels]; 080 int[] rTotal = new int[levels]; 081 int[] gTotal = new int[levels]; 082 int[] bTotal = new int[levels]; 083 int[] outPixels = new int[width * height]; 084 085 for (int y = 0; y < height; y++) { 086 for (int x = 0; x < width; x++) { 087 for (int i = 0; i < levels; i++) 088 rHistogram[i] = gHistogram[i] = bHistogram[i] = rTotal[i] = gTotal[i] = bTotal[i] = 0; 089 090 for (int row = -range; row <= range; row++) { 091 int iy = y+row; 092 int ioffset; 093 if (0 <= iy && iy < height) { 094 ioffset = iy*width; 095 for (int col = -range; col <= range; col++) { 096 int ix = x+col; 097 if (0 <= ix && ix < width) { 098 int rgb = inPixels[ioffset+ix]; 099 int r = (rgb >> 16) & 0xff; 100 int g = (rgb >> 8) & 0xff; 101 int b = rgb & 0xff; 102 int ri = r*levels/256; 103 int gi = g*levels/256; 104 int bi = b*levels/256; 105 rTotal[ri] += r; 106 gTotal[gi] += g; 107 bTotal[bi] += b; 108 rHistogram[ri]++; 109 gHistogram[gi]++; 110 bHistogram[bi]++; 111 } 112 } 113 } 114 } 115 116 int r = 0, g = 0, b = 0; 117 for (int i = 1; i < levels; i++) { 118 if (rHistogram[i] > rHistogram[r]) 119 r = i; 120 if (gHistogram[i] > gHistogram[g]) 121 g = i; 122 if (bHistogram[i] > bHistogram[b]) 123 b = i; 124 } 125 r = rTotal[r] / rHistogram[r]; 126 g = gTotal[g] / gHistogram[g]; 127 b = bTotal[b] / bHistogram[b]; 128 outPixels[index++] = 0xff000000 | ( r << 16 ) | ( g << 8 ) | b; 129 } 130 } 131 return outPixels; 132 } 133 134 public String toString() { 135 return "Stylize/Oil..."; 136 } 137 138 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 139 Object o; 140 if((o=parameters.removeEL(KeyImpl.init("Levels")))!=null)setLevels(ImageFilterUtil.toIntValue(o,"Levels")); 141 if((o=parameters.removeEL(KeyImpl.init("Range")))!=null)setRange(ImageFilterUtil.toIntValue(o,"Range")); 142 143 // check for arguments not supported 144 if(parameters.size()>0) { 145 throw new FunctionException(ThreadLocalPageContext.get(), "ImageFilter", 3, "parameters", "the parameter"+(parameters.size()>1?"s":"")+" ["+CollectionUtil.getKeyList(parameters,", ")+"] "+(parameters.size()>1?"are":"is")+" not allowed, only the following parameters are supported [Levels, Range]"); 146 } 147 148 return filter(src, dst); 149 } 150 } 151