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.*; 020import java.awt.image.*; 021 022/** 023 * A filter which draws contours on an image at given brightness levels. 024 */ 025public class ContourFilter extends WholeImageFilter { 026 027 private float levels = 5; 028 private float scale = 1; 029 private float offset = 0; 030 private int contourColor = 0xff000000; 031 032 public ContourFilter() { 033 } 034 035 public void setLevels( float levels ) { 036 this.levels = levels; 037 } 038 039 public float getLevels() { 040 return levels; 041 } 042 043 /** 044 * Specifies the scale of the contours. 045 * @param scale the scale of the contours. 046 * @min-value 0 047 * @max-value 1 048 * @see #getScale 049 */ 050 public void setScale( float scale ) { 051 this.scale = scale; 052 } 053 054 /** 055 * Returns the scale of the contours. 056 * @return the scale of the contours. 057 * @see #setScale 058 */ 059 public float getScale() { 060 return scale; 061 } 062 063 public void setOffset( float offset ) { 064 this.offset = offset; 065 } 066 067 public float getOffset() { 068 return offset; 069 } 070 071 public void setContourColor( int contourColor ) { 072 this.contourColor = contourColor; 073 } 074 075 public int getContourColor() { 076 return contourColor; 077 } 078 079 protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) { 080 int index = 0; 081 short[][] r = new short[3][width]; 082 int[] outPixels = new int[width * height]; 083 084 short[] table = new short[256]; 085 int offsetl = (int)(offset * 256 / levels); 086 for ( int i = 0; i < 256; i++ ) 087 table[i] = (short)PixelUtils.clamp( (int)(255 * Math.floor(levels*(i+offsetl) / 256) / (levels-1) - offsetl) ); 088 089 for (int x = 0; x < width; x++) { 090 int rgb = inPixels[x]; 091 r[1][x] = (short)PixelUtils.brightness( rgb ); 092 } 093 for (int y = 0; y < height; y++) { 094 boolean yIn = y > 0 && y < height-1; 095 int nextRowIndex = index+width; 096 if ( y < height-1) { 097 for (int x = 0; x < width; x++) { 098 int rgb = inPixels[nextRowIndex++]; 099 r[2][x] = (short)PixelUtils.brightness( rgb ); 100 } 101 } 102 for (int x = 0; x < width; x++) { 103 boolean xIn = x > 0 && x < width-1; 104 int w = x-1; 105 int e = x+1; 106 int v = 0; 107 108 if ( yIn && xIn ) { 109 short nwb = r[0][w]; 110 short neb = r[0][x]; 111 short swb = r[1][w]; 112 short seb = r[1][x]; 113 short nw = table[nwb]; 114 short ne = table[neb]; 115 short sw = table[swb]; 116 short se = table[seb]; 117 118 if (nw != ne || nw != sw || ne != se || sw != se) { 119 v = (int)(scale * (Math.abs(nwb - neb) + Math.abs(nwb - swb) + Math.abs(neb - seb) + Math.abs(swb - seb))); 120// v /= 255; 121 if (v > 255) 122 v = 255; 123 } 124 } 125 126 if ( v != 0 ) 127 outPixels[index] = PixelUtils.combinePixels( inPixels[index], contourColor, PixelUtils.NORMAL, v ); 128// outPixels[index] = PixelUtils.combinePixels( (contourColor & 0xff)|(v << 24), inPixels[index], PixelUtils.NORMAL ); 129 else 130 outPixels[index] = inPixels[index]; 131 index++; 132 } 133 short[] t; 134 t = r[0]; 135 r[0] = r[1]; 136 r[1] = r[2]; 137 r[2] = t; 138 } 139 140 return outPixels; 141 } 142 143 public String toString() { 144 return "Stylize/Contour..."; 145 } 146 147} 148