001/* 002Copyright 2006 Jerry Huxtable 003 004Licensed under the Apache License, Version 2.0 (the "License"); 005you may not use this file except in compliance with the License. 006You may obtain a copy of the License at 007 008 http://www.apache.org/licenses/LICENSE-2.0 009 010Unless required by applicable law or agreed to in writing, software 011distributed under the License is distributed on an "AS IS" BASIS, 012WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013See the License for the specific language governing permissions and 014limitations under the License. 015*/ 016 017package com.jhlabs.image; 018 019import java.awt.Color; 020import java.util.Vector; 021import java.io.*; 022 023/** 024 * A Colormap implemented using Catmull-Rom colour splines. The map has a variable number 025 * of knots with a minimum of four. The first and last knots give the tangent at the end 026 * of the spline, and colours are interpolated from the second to the second-last knots. 027 */ 028public class SplineColormap extends ArrayColormap { 029 030 private int numKnots = 4; 031 private int[] xKnots = { 032 0, 0, 255, 255 033 }; 034 private int[] yKnots = { 035 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 036 }; 037 038 /** 039 * Construct a SplineColormap. 040 */ 041 public SplineColormap() { 042 rebuildGradient(); 043 } 044 045 /** 046 * Construct a SplineColormap. 047 * @param xKnots the knot positions 048 * @param yKnots the knot colors 049 */ 050 public SplineColormap(int[] xKnots, int[] yKnots) { 051 this.xKnots = xKnots; 052 this.yKnots = yKnots; 053 numKnots = xKnots.length; 054 rebuildGradient(); 055 } 056 057 /** 058 * Set a knot color. 059 * @param n the knot index 060 * @param color the color 061 * @see #getKnot 062 */ 063 public void setKnot(int n, int color) { 064 yKnots[n] = color; 065 rebuildGradient(); 066 } 067 068 /** 069 * Get a knot color. 070 * @param n the knot index 071 * @return the knot color 072 * @see #setKnot 073 */ 074 public int getKnot(int n) { 075 return yKnots[n]; 076 } 077 078 /** 079 * Add a new knot. 080 * @param x the knot position 081 * @param color the color 082 * @see #removeKnot 083 */ 084 public void addKnot(int x, int color) { 085 int[] nx = new int[numKnots+1]; 086 int[] ny = new int[numKnots+1]; 087 System.arraycopy(xKnots, 0, nx, 0, numKnots); 088 System.arraycopy(yKnots, 0, ny, 0, numKnots); 089 xKnots = nx; 090 yKnots = ny; 091 xKnots[numKnots] = x; 092 yKnots[numKnots] = color; 093 numKnots++; 094 sortKnots(); 095 rebuildGradient(); 096 } 097 098 /** 099 * Remove a knot. 100 * @param n the knot index 101 * @see #addKnot 102 */ 103 public void removeKnot(int n) { 104 if (numKnots <= 4) 105 return; 106 if (n < numKnots-1) { 107 System.arraycopy(xKnots, n+1, xKnots, n, numKnots-n-1); 108 System.arraycopy(yKnots, n+1, yKnots, n, numKnots-n-1); 109 } 110 numKnots--; 111 rebuildGradient(); 112 } 113 114 /** 115 * Set a knot position. 116 * @param n the knot index 117 * @param x the knot position 118 */ 119 public void setKnotPosition(int n, int x) { 120 xKnots[n] = PixelUtils.clamp(x); 121 sortKnots(); 122 rebuildGradient(); 123 } 124 125 private void rebuildGradient() { 126 xKnots[0] = -1; 127 xKnots[numKnots-1] = 256; 128 yKnots[0] = yKnots[1]; 129 yKnots[numKnots-1] = yKnots[numKnots-2]; 130 for (int i = 0; i < 256; i++) 131 map[i] = ImageMath.colorSpline(i, numKnots, xKnots, yKnots); 132 } 133 134 private void sortKnots() { 135 for (int i = 1; i < numKnots; i++) { 136 for (int j = 1; j < i; j++) { 137 if (xKnots[i] < xKnots[j]) { 138 int t = xKnots[i]; 139 xKnots[i] = xKnots[j]; 140 xKnots[j] = t; 141 t = yKnots[i]; 142 yKnots[i] = yKnots[j]; 143 yKnots[j] = t; 144 } 145 } 146 } 147 } 148 149}