001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019/* 020* 021 022Licensed under the Apache License, Version 2.0 (the "License"); 023you may not use this file except in compliance with the License. 024You may obtain a copy of the License at 025 026 http://www.apache.org/licenses/LICENSE-2.0 027 028Unless required by applicable law or agreed to in writing, software 029distributed under the License is distributed on an "AS IS" BASIS, 030WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 031See the License for the specific language governing permissions and 032limitations under the License. 033*/ 034 035package lucee.runtime.img.filter; 036 037/** 038 * A Colormap implemented using Catmull-Rom colour splines. The map has a variable number 039 * of knots with a minimum of four. The first and last knots give the tangent at the end 040 * of the spline, and colours are interpolated from the second to the second-last knots. 041 */ 042public class SplineColormap extends ArrayColormap { 043 044 private int numKnots = 4; 045 private int[] xKnots = { 046 0, 0, 255, 255 047 }; 048 private int[] yKnots = { 049 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 050 }; 051 052 /** 053 * Construct a SplineColormap. 054 */ 055 public SplineColormap() { 056 rebuildGradient(); 057 } 058 059 /** 060 * Construct a SplineColormap. 061 * @param xKnots the knot positions 062 * @param yKnots the knot colors 063 */ 064 public SplineColormap(int[] xKnots, int[] yKnots) { 065 this.xKnots = xKnots; 066 this.yKnots = yKnots; 067 numKnots = xKnots.length; 068 rebuildGradient(); 069 } 070 071 /** 072 * Set a knot color. 073 * @param n the knot index 074 * @param color the color 075 * @see #getKnot 076 */ 077 public void setKnot(int n, int color) { 078 yKnots[n] = color; 079 rebuildGradient(); 080 } 081 082 /** 083 * Get a knot color. 084 * @param n the knot index 085 * @return the knot color 086 * @see #setKnot 087 */ 088 public int getKnot(int n) { 089 return yKnots[n]; 090 } 091 092 /** 093 * Add a new knot. 094 * @param x the knot position 095 * @param color the color 096 * @see #removeKnot 097 */ 098 public void addKnot(int x, int color) { 099 int[] nx = new int[numKnots+1]; 100 int[] ny = new int[numKnots+1]; 101 System.arraycopy(xKnots, 0, nx, 0, numKnots); 102 System.arraycopy(yKnots, 0, ny, 0, numKnots); 103 xKnots = nx; 104 yKnots = ny; 105 xKnots[numKnots] = x; 106 yKnots[numKnots] = color; 107 numKnots++; 108 sortKnots(); 109 rebuildGradient(); 110 } 111 112 /** 113 * Remove a knot. 114 * @param n the knot index 115 * @see #addKnot 116 */ 117 public void removeKnot(int n) { 118 if (numKnots <= 4) 119 return; 120 if (n < numKnots-1) { 121 System.arraycopy(xKnots, n+1, xKnots, n, numKnots-n-1); 122 System.arraycopy(yKnots, n+1, yKnots, n, numKnots-n-1); 123 } 124 numKnots--; 125 rebuildGradient(); 126 } 127 128 /** 129 * Set a knot position. 130 * @param n the knot index 131 * @param x the knot position 132 */ 133 public void setKnotPosition(int n, int x) { 134 xKnots[n] = PixelUtils.clamp(x); 135 sortKnots(); 136 rebuildGradient(); 137 } 138 139 private void rebuildGradient() { 140 xKnots[0] = -1; 141 xKnots[numKnots-1] = 256; 142 yKnots[0] = yKnots[1]; 143 yKnots[numKnots-1] = yKnots[numKnots-2]; 144 for (int i = 0; i < 256; i++) 145 map[i] = ImageMath.colorSpline(i, numKnots, xKnots, yKnots); 146 } 147 148 private void sortKnots() { 149 for (int i = 1; i < numKnots; i++) { 150 for (int j = 1; j < i; j++) { 151 if (xKnots[i] < xKnots[j]) { 152 int t = xKnots[i]; 153 xKnots[i] = xKnots[j]; 154 xKnots[j] = t; 155 t = yKnots[i]; 156 yKnots[i] = yKnots[j]; 157 yKnots[j] = t; 158 } 159 } 160 } 161 } 162 163}