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.image.BufferedImage; 018 019 import railo.runtime.engine.ThreadLocalPageContext; 020 import railo.runtime.exp.FunctionException; 021 import railo.runtime.exp.PageException; 022 import railo.runtime.img.ImageUtil; 023 import railo.runtime.type.KeyImpl; 024 import railo.runtime.type.List; 025 import railo.runtime.type.Struct; 026 027 028 029 public class CurvesFilter extends TransferFilter implements DynFiltering { 030 031 private Curve[] curves = new Curve[1]; 032 033 public static class Curve { 034 public float[] x; 035 public float[] y; 036 037 public Curve() { 038 x = new float[] { 0, 1 }; 039 y = new float[] { 0, 1 }; 040 } 041 042 public Curve( Curve curve ) { 043 x = curve.x.clone(); 044 y = curve.y.clone(); 045 } 046 047 public int addKnot( float kx, float ky ) { 048 int pos = -1; 049 int numKnots = x.length; 050 float[] nx = new float[numKnots+1]; 051 float[] ny = new float[numKnots+1]; 052 int j = 0; 053 for ( int i = 0; i < numKnots; i++ ) { 054 if ( pos == -1 && x[i] > kx ) { 055 pos = j; 056 nx[j] = kx; 057 ny[j] = ky; 058 j++; 059 } 060 nx[j] = x[i]; 061 ny[j] = y[i]; 062 j++; 063 } 064 if ( pos == -1 ) { 065 pos = j; 066 nx[j] = kx; 067 ny[j] = ky; 068 } 069 x = nx; 070 y = ny; 071 return pos; 072 } 073 074 public void removeKnot( int n ) { 075 int numKnots = x.length; 076 if ( numKnots <= 2 ) 077 return; 078 float[] nx = new float[numKnots-1]; 079 float[] ny = new float[numKnots-1]; 080 int j = 0; 081 for ( int i = 0; i < numKnots-1; i++ ) { 082 if ( i == n ) 083 j++; 084 nx[i] = x[j]; 085 ny[i] = y[j]; 086 j++; 087 } 088 x = nx; 089 y = ny; 090 for ( int i = 0; i < x.length; i++ ) 091 System.out.println( i+": "+x[i]+" "+y[i]); 092 } 093 094 private void sortKnots() { 095 int numKnots = x.length; 096 for (int i = 1; i < numKnots-1; i++) { 097 for (int j = 1; j < i; j++) { 098 if (x[i] < x[j]) { 099 float t = x[i]; 100 x[i] = x[j]; 101 x[j] = t; 102 t = y[i]; 103 y[i] = y[j]; 104 y[j] = t; 105 } 106 } 107 } 108 } 109 110 protected int[] makeTable() { 111 int numKnots = x.length; 112 float[] nx = new float[numKnots+2]; 113 float[] ny = new float[numKnots+2]; 114 System.arraycopy( x, 0, nx, 1, numKnots); 115 System.arraycopy( y, 0, ny, 1, numKnots); 116 nx[0] = nx[1]; 117 ny[0] = ny[1]; 118 nx[numKnots+1] = nx[numKnots]; 119 ny[numKnots+1] = ny[numKnots]; 120 121 int[] table = new int[256]; 122 for (int i = 0; i < 1024; i++) { 123 float f = i/1024.0f; 124 int x = (int)(255 * ImageMath.spline( f, nx.length, nx ) + 0.5f); 125 int y = (int)(255 * ImageMath.spline( f, nx.length, ny ) + 0.5f); 126 x = ImageMath.clamp( x, 0, 255 ); 127 y = ImageMath.clamp( y, 0, 255 ); 128 table[x] = y; 129 } 130 // System.out.println(); 131 // for ( int i = 0; i < 256; i++ ) 132 // System.out.println( i+": "+table[i]); 133 return table; 134 } 135 } 136 137 public CurvesFilter() { 138 curves = new Curve[3]; 139 curves[0] = new Curve(); 140 curves[1] = new Curve(); 141 curves[2] = new Curve(); 142 } 143 144 protected void initialize() { 145 initialized = true; 146 if ( curves.length == 1 ) 147 rTable = gTable = bTable = curves[0].makeTable(); 148 else { 149 rTable = curves[0].makeTable(); 150 gTable = curves[1].makeTable(); 151 bTable = curves[2].makeTable(); 152 } 153 } 154 155 public void setCurve( Curve curve ) { 156 curves = new Curve[] { curve }; 157 initialized = false; 158 } 159 160 public void setCurves( Curve[] curves ) { 161 if ( curves == null || (curves.length != 1 && curves.length != 3) ) 162 throw new IllegalArgumentException( "Curves must be length 1 or 3" ); 163 this.curves = curves; 164 initialized = false; 165 } 166 167 public Curve[] getCurves() { 168 return curves; 169 } 170 171 public String toString() { 172 return "Colors/Curves..."; 173 } 174 175 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 176 Object o; 177 if((o=parameters.removeEL(KeyImpl.init("Curves")))!=null)setCurves(ImageFilterUtil.toACurvesFilter$Curve(o,"Curves")); 178 if((o=parameters.removeEL(KeyImpl.init("Curve")))!=null)setCurve(ImageFilterUtil.toCurvesFilter$Curve(o,"Curve")); 179 if((o=parameters.removeEL(KeyImpl.init("Dimensions")))!=null){ 180 int[] dim=ImageFilterUtil.toDimensions(o,"Dimensions"); 181 setDimensions(dim[0],dim[1]); 182 } 183 184 // check for arguments not supported 185 if(parameters.size()>0) { 186 throw new FunctionException(ThreadLocalPageContext.get(), "ImageFilter", 3, "parameters", "the parameter"+(parameters.size()>1?"s":"")+" ["+List.arrayToList(parameters.keysAsString(),", ")+"] "+(parameters.size()>1?"are":"is")+" not allowed, only the following parameters are supported [Curves, Curve, Dimensions]"); 187 } 188 189 return filter(src, dst); 190 } 191 } 192