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; 018 019 /** 020 * A Colormap implemented using Catmull-Rom colour splines. The map has a variable number 021 * of knots with a minimum of four. The first and last knots give the tangent at the end 022 * of the spline, and colours are interpolated from the second to the second-last knots. 023 */ 024 public class SplineColormap extends ArrayColormap { 025 026 private int numKnots = 4; 027 private int[] xKnots = { 028 0, 0, 255, 255 029 }; 030 private int[] yKnots = { 031 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 032 }; 033 034 /** 035 * Construct a SplineColormap. 036 */ 037 public SplineColormap() { 038 rebuildGradient(); 039 } 040 041 /** 042 * Construct a SplineColormap. 043 * @param xKnots the knot positions 044 * @param yKnots the knot colors 045 */ 046 public SplineColormap(int[] xKnots, int[] yKnots) { 047 this.xKnots = xKnots; 048 this.yKnots = yKnots; 049 numKnots = xKnots.length; 050 rebuildGradient(); 051 } 052 053 /** 054 * Set a knot color. 055 * @param n the knot index 056 * @param color the color 057 * @see #getKnot 058 */ 059 public void setKnot(int n, int color) { 060 yKnots[n] = color; 061 rebuildGradient(); 062 } 063 064 /** 065 * Get a knot color. 066 * @param n the knot index 067 * @return the knot color 068 * @see #setKnot 069 */ 070 public int getKnot(int n) { 071 return yKnots[n]; 072 } 073 074 /** 075 * Add a new knot. 076 * @param x the knot position 077 * @param color the color 078 * @see #removeKnot 079 */ 080 public void addKnot(int x, int color) { 081 int[] nx = new int[numKnots+1]; 082 int[] ny = new int[numKnots+1]; 083 System.arraycopy(xKnots, 0, nx, 0, numKnots); 084 System.arraycopy(yKnots, 0, ny, 0, numKnots); 085 xKnots = nx; 086 yKnots = ny; 087 xKnots[numKnots] = x; 088 yKnots[numKnots] = color; 089 numKnots++; 090 sortKnots(); 091 rebuildGradient(); 092 } 093 094 /** 095 * Remove a knot. 096 * @param n the knot index 097 * @see #addKnot 098 */ 099 public void removeKnot(int n) { 100 if (numKnots <= 4) 101 return; 102 if (n < numKnots-1) { 103 System.arraycopy(xKnots, n+1, xKnots, n, numKnots-n-1); 104 System.arraycopy(yKnots, n+1, yKnots, n, numKnots-n-1); 105 } 106 numKnots--; 107 rebuildGradient(); 108 } 109 110 /** 111 * Set a knot position. 112 * @param n the knot index 113 * @param x the knot position 114 */ 115 public void setKnotPosition(int n, int x) { 116 xKnots[n] = PixelUtils.clamp(x); 117 sortKnots(); 118 rebuildGradient(); 119 } 120 121 private void rebuildGradient() { 122 xKnots[0] = -1; 123 xKnots[numKnots-1] = 256; 124 yKnots[0] = yKnots[1]; 125 yKnots[numKnots-1] = yKnots[numKnots-2]; 126 for (int i = 0; i < 256; i++) 127 map[i] = ImageMath.colorSpline(i, numKnots, xKnots, yKnots); 128 } 129 130 private void sortKnots() { 131 for (int i = 1; i < numKnots; i++) { 132 for (int j = 1; j < i; j++) { 133 if (xKnots[i] < xKnots[j]) { 134 int t = xKnots[i]; 135 xKnots[i] = xKnots[j]; 136 xKnots[j] = t; 137 t = yKnots[i]; 138 yKnots[i] = yKnots[j]; 139 yKnots[j] = t; 140 } 141 } 142 } 143 } 144 145 }