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 performs ordered dithering on an image. 024 */ 025public class DitherFilter extends PointFilter { 026 027 /** 028 * 2x2 magic square. 029 */ 030 protected final static int[] ditherMagic2x2Matrix = { 031 0, 2, 032 3, 1 033 }; 034 035 /** 036 * 4x4 magic square. 037 */ 038 protected final static int[] ditherMagic4x4Matrix = { 039 0, 14, 3, 13, 040 11, 5, 8, 6, 041 12, 2, 15, 1, 042 7, 9, 4, 10 043 }; 044 045 /** 046 * 4x4 ordered dither. 047 */ 048 public final static int[] ditherOrdered4x4Matrix = { 049 0, 8, 2, 10, 050 12, 4, 14, 6, 051 3, 11, 1, 9, 052 15, 7, 13, 5 053 }; 054 055 /** 056 * 4x4 lines. 057 */ 058 public final static int[] ditherLines4x4Matrix = { 059 0, 1, 2, 3, 060 4, 5, 6, 7, 061 8, 9, 10, 11, 062 12, 13, 14, 15 063 }; 064 065 /** 066 * 6x6 90 degree halftone. 067 */ 068 public final static int[] dither90Halftone6x6Matrix = { 069 29, 18, 12, 19, 30, 34, 070 17, 7, 4, 8, 20, 28, 071 11, 3, 0, 1, 9, 27, 072 16, 6, 2, 5, 13, 26, 073 25, 15, 10, 14, 21, 31, 074 33, 25, 24, 23, 33, 36 075 }; 076 077 /* 078 * The following dithering matrices are taken from "Digital Halftoning" 079 * by Robert Ulichney, MIT Press, ISBN 0-262-21009-6. 080 */ 081 082 /** 083 * Order-6 ordered dither. 084 */ 085 public final static int[] ditherOrdered6x6Matrix = { 086 1, 59, 15, 55, 2, 56, 12, 52, 087 33, 17, 47, 31, 34, 18, 44, 28, 088 9, 49, 5, 63, 10, 50, 6, 60, 089 41, 25, 37, 21, 42, 26, 38, 22, 090 3, 57, 13, 53, 0, 58, 14, 54, 091 35, 19, 45, 29, 32, 16, 46, 30, 092 11, 51, 7, 61, 8, 48, 4, 62, 093 43, 27, 39, 23, 40, 24, 36, 20 094 }; 095 096 /** 097 * Order-8 ordered dither. 098 */ 099 public final static int[] ditherOrdered8x8Matrix = { 100 1,235, 59,219, 15,231, 55,215, 2,232, 56,216, 12,228, 52,212, 101 129, 65,187,123,143, 79,183,119,130, 66,184,120,140, 76,180,116, 102 33,193, 17,251, 47,207, 31,247, 34,194, 18,248, 44,204, 28,244, 103 161, 97,145, 81,175,111,159, 95,162, 98,146, 82,172,108,156, 92, 104 9,225, 49,209, 5,239, 63,223, 10,226, 50,210, 6,236, 60,220, 105 137, 73,177,113,133, 69,191,127,138, 74,178,114,134, 70,188,124, 106 41,201, 25,241, 37,197, 21,255, 42,202, 26,242, 38,198, 22,252, 107 169,105,153, 89,165,101,149, 85,170,106,154, 90,166,102,150, 86, 108 3,233, 57,217, 13,229, 53,213, 0,234, 58,218, 14,230, 54,214, 109 131, 67,185,121,141, 77,181,117,128, 64,186,122,142, 78,182,118, 110 35,195, 19,249, 45,205, 29,245, 32,192, 16,250, 46,206, 30,246, 111 163, 99,147, 83,173,109,157, 93,160, 96,144, 80,174,110,158, 94, 112 11,227, 51,211, 7,237, 61,221, 8,224, 48,208, 4,238, 62,222, 113 139, 75,179,115,135, 71,189,125,136, 72,176,112,132, 68,190,126, 114 43,203, 27,243, 39,199, 23,253, 40,200, 24,240, 36,196, 20,254, 115 171,107,155, 91,167,103,151, 87,168,104,152, 88,164,100,148, 84 }; 116 117 /** 118 * Order-3 clustered dither. 119 */ 120 public final static int[] ditherCluster3Matrix = { 121 9,11,10, 8, 6, 7, 122 12,17,16, 5, 0, 1, 123 13,14,15, 4, 3, 2, 124 8, 6, 7, 9,11,10, 125 5, 0, 1,12,17,16, 126 4, 3, 2,13,14,15 }; 127 128 /** 129 * Order-4 clustered dither. 130 */ 131 public final static int[] ditherCluster4Matrix = { 132 18,20,19,16,13,11,12,15, 133 27,28,29,22, 4, 3, 2, 9, 134 26,31,30,21, 5, 0, 1,10, 135 23,25,24,17, 8, 6, 7,14, 136 13,11,12,15,18,20,19,16, 137 4, 3, 2, 9,27,28,29,22, 138 5, 0, 1,10,26,31,30,21, 139 8, 6, 7,14,23,25,24,17 }; 140 141 /** 142 * Order-8 clustered dither. 143 */ 144 public final static int[] ditherCluster8Matrix = { 145 64, 69, 77, 87, 86, 76, 68, 67, 63, 58, 50, 40, 41, 51, 59, 60, 146 70, 94,100,109,108, 99, 93, 75, 57, 33, 27, 18, 19, 28, 34, 52, 147 78,101,114,116,115,112, 98, 83, 49, 26, 13, 11, 12, 15, 29, 44, 148 88,110,123,124,125,118,107, 85, 39, 17, 4, 3, 2, 9, 20, 42, 149 89,111,122,127,126,117,106, 84, 38, 16, 5, 0, 1, 10, 21, 43, 150 79,102,119,121,120,113, 97, 82, 48, 25, 8, 6, 7, 14, 30, 45, 151 71, 95,103,104,105, 96, 92, 74, 56, 32, 24, 23, 22, 31, 35, 53, 152 65, 72, 80, 90, 91, 81, 73, 66, 62, 55, 47, 37, 36, 46, 54, 61, 153 63, 58, 50, 40, 41, 51, 59, 60, 64, 69, 77, 87, 86, 76, 68, 67, 154 57, 33, 27, 18, 19, 28, 34, 52, 70, 94,100,109,108, 99, 93, 75, 155 49, 26, 13, 11, 12, 15, 29, 44, 78,101,114,116,115,112, 98, 83, 156 39, 17, 4, 3, 2, 9, 20, 42, 88,110,123,124,125,118,107, 85, 157 38, 16, 5, 0, 1, 10, 21, 43, 89,111,122,127,126,117,106, 84, 158 48, 25, 8, 6, 7, 14, 30, 45, 79,102,119,121,120,113, 97, 82, 159 56, 32, 24, 23, 22, 31, 35, 53, 71, 95,103,104,105, 96, 92, 74, 160 62, 55, 47, 37, 36, 46, 54, 61, 65, 72, 80, 90, 91, 81, 73, 66 }; 161 162 private int[] matrix; 163 private int rows, cols, levels; 164 private int[] mod; 165 private int[] div; 166 private int[] map; 167 private boolean colorDither; 168 private boolean initialized = false; 169 170 /** 171 * Constuct a DitherFilter. 172 */ 173 public DitherFilter() { 174 rows = 2; 175 cols = 2; 176 matrix = ditherMagic4x4Matrix; 177 levels = 6; 178 colorDither = true; 179 } 180 181 /** 182 * Set the dither matrix. 183 * @param matrix the dither matrix 184 * @see #getMatrix 185 */ 186 public void setMatrix(int[] matrix) { 187 this.matrix = matrix; 188 } 189 190 /** 191 * Get the dither matrix. 192 * @return the dither matrix 193 * @see #setMatrix 194 */ 195 public int[] getMatrix() { 196 return matrix; 197 } 198 199 /** 200 * Set the number of dither levels. 201 * @param levels the number of levels 202 * @see #getLevels 203 */ 204 public void setLevels(int levels) { 205 this.levels = levels; 206 } 207 208 /** 209 * Get the number of dither levels. 210 * @return the number of levels 211 * @see #setLevels 212 */ 213 public int getLevels() { 214 return levels; 215 } 216 217 /** 218 * Set whether to use a color dither. 219 * @param colorDither whether to use a color dither 220 * @see #getColorDither 221 */ 222 public void setColorDither(boolean colorDither) { 223 this.colorDither = colorDither; 224 } 225 226 /** 227 * Get whether to use a color dither. 228 * @return whether to use a color dither 229 * @see #getColorDither 230 */ 231 public boolean getColorDither() { 232 return colorDither; 233 } 234 235 /** 236 * Initialize the filter. 237 */ 238 protected void initialize() { 239 rows = cols = (int)Math.sqrt(matrix.length); 240 map = new int[levels]; 241 for (int i = 0; i < levels; i++) { 242 int v = 255 * i / (levels-1); 243 map[i] = v; 244 } 245 div = new int[256]; 246 mod = new int[256]; 247 int rc = (rows*cols+1); 248 for (int i = 0; i < 256; i++) { 249 div[i] = (levels-1)*i / 256; 250 mod[i] = i*rc/256; 251 } 252 } 253 254 public int filterRGB(int x, int y, int rgb) { 255 if (!initialized) { 256 initialized = true; 257 initialize(); 258 } 259 int a = rgb & 0xff000000; 260 int r = (rgb >> 16) & 0xff; 261 int g = (rgb >> 8) & 0xff; 262 int b = rgb & 0xff; 263 int col = x % cols; 264 int row = y % rows; 265 int v = matrix[row*cols+col]; 266 if (colorDither) { 267 r = map[mod[r] > v ? div[r] + 1 : div[r]]; 268 g = map[mod[g] > v ? div[g] + 1 : div[g]]; 269 b = map[mod[b] > v ? div[b] + 1 : div[b]]; 270 } else { 271 int value = (r+g+b)/3; 272 r = g = b = map[mod[value] > v ? div[value] + 1 : div[value]]; 273 } 274 return a | (r << 16) | (g << 8) | b; 275 } 276 277 public String toString() { 278 return "Colors/Dither..."; 279 } 280 281} 282