1 18 package org.apache.batik.ext.awt.image.rendered; 19 20 import java.awt.Graphics2D ; 21 import java.awt.Point ; 22 import java.awt.RenderingHints ; 23 import java.awt.image.BufferedImage ; 24 import java.awt.image.ColorModel ; 25 import java.awt.image.DataBuffer ; 26 import java.awt.image.IndexColorModel ; 27 import java.awt.image.MultiPixelPackedSampleModel ; 28 import java.awt.image.Raster ; 29 import java.awt.image.SampleModel ; 30 import java.awt.image.WritableRaster ; 31 import java.util.Iterator ; 32 import java.util.Vector ; 33 34 import org.apache.batik.ext.awt.image.GraphicsUtil; 35 36 46 public class IndexImage{ 47 48 51 private static class Counter { 52 public int val; 53 public int count=1; 54 public Counter(int val) { this.val = val; } 55 public boolean add(int val) { 56 if (this.val != val) 58 return false; 59 count++; 60 return true; 61 } 62 } 63 64 68 private static class Cube { 69 int []min={0, 0, 0}, max={255,255,255}; 70 71 boolean done = false; 72 73 Vector []colors = null; 74 int count=0; 75 static final int RED = 0; 76 static final int GRN = 1; 77 static final int BLU = 2; 78 79 84 public Cube(Vector []colors, int count) { 85 this.colors = colors; 86 this.count = count; 87 } 88 89 93 public boolean isDone() { return done; } 94 99 public Cube split() { 100 int dr = max[0]-min[0]+1; 101 int dg = max[1]-min[1]+1; 102 int db = max[2]-min[2]+1; 103 int c0, c1, splitChannel; 104 105 if (dr >= dg) { 108 c0 = GRN; 109 if (dr >= db) { splitChannel = RED; c1=BLU; } 110 else { splitChannel = BLU; c1=RED; } 111 } else if (dg >= db) { 112 splitChannel = GRN; 113 c0=RED; 114 c1=BLU; 115 } else { 116 splitChannel = BLU; 117 c0=RED; 118 c1=GRN; 119 } 120 121 Cube ret; 122 ret = splitChannel(splitChannel, c0, c1); 123 if (ret != null ) return ret; 124 125 ret = splitChannel(c0, splitChannel, c1); 126 if (ret != null ) return ret; 127 128 ret = splitChannel(c1, splitChannel, c0); 129 if (ret != null) return ret; 130 131 done = true; 132 return null; 133 } 134 135 140 public Cube splitChannel(int splitChannel, int c0, int c1) { 141 if (min[splitChannel] == max[splitChannel]) return null; 142 143 int splitSh4 = (2-splitChannel)*4; 144 int c0Sh4 = (2-c0)*4; 145 int c1Sh4 = (2-c1)*4; 146 147 int half = count/2; 148 int counts [] = new int[256]; 153 int tcount = 0; 154 155 160 int [] minIdx = {min[0]>>4, min[1]>>4, min[2]>>4}; 161 int [] maxIdx = {max[0]>>4, max[1]>>4, max[2]>>4}; 162 int minR=min[0], minG=min[1], minB=min[2]; 163 int maxR=max[0], maxG=max[1], maxB=max[2]; 164 int val = 0; 165 int [] vals = {0, 0, 0}; 166 for (int i=minIdx[splitChannel]; i<=maxIdx[splitChannel]; i++) { 167 int idx1 = i<<splitSh4; 168 for (int j=minIdx[c0]; j<=maxIdx[c0]; j++) { 169 int idx2 = idx1 | (j<<c0Sh4); 170 for (int k=minIdx[c1]; k<=maxIdx[c1]; k++) { 171 int idx = idx2 | (k<<c1Sh4); 172 Vector v = colors[idx]; 173 if (v==null) continue; 174 Iterator itr = v.iterator(); 175 Counter c; 176 while (itr.hasNext()) { 177 c = (Counter)itr.next(); 178 val = c.val; 179 vals[0] = (val&0xFF0000)>>16; 180 vals[1] = (val&0xFF00)>>8; 181 vals[2] = (val&0xFF); 182 if (((vals[0] >= minR) && (vals[0] <= maxR))&& 183 ((vals[1] >= minG) && (vals[1] <= maxG))&& 184 ((vals[2] >= minB) && (vals[2] <= maxB))) { 185 counts[vals[splitChannel]] += c.count; 187 tcount += c.count; 188 } 189 } 190 } 191 } 192 if (tcount >= half) break; 195 } 196 197 tcount=0; 198 int lastAdd=-1; 199 int splitLo=min[splitChannel], splitHi=max[splitChannel]; 204 for (int i=min[splitChannel]; i<=max[splitChannel]; i++) { 205 int c = counts[i]; 206 if (c == 0) { 207 if ((tcount == 0) && (i < max[splitChannel])) 209 this.min[splitChannel] = i+1; 210 continue; 211 } 212 213 if (tcount+c < half) { 214 lastAdd = i; 215 tcount+=c; 216 continue; 217 } 218 if ((half-tcount) <= ((tcount+c)-half)) { 219 if (lastAdd == -1) { 221 if (c == this.count) { 223 this.max[splitChannel] = i; 226 return null; } else { 228 splitLo = i; 231 splitHi = i+1; 232 break; 233 } 234 } 235 splitLo = lastAdd; 236 splitHi = i; 237 } else { 238 if (i == this.max[splitChannel]) { 239 if ( c == this.count) { 240 return null; } else { 244 splitLo = lastAdd; 247 splitHi = i; 248 break; 249 } 250 } 251 tcount += c; 253 splitLo = i; 254 splitHi = i+1; 255 } 256 break; 257 } 258 259 264 Cube ret = new Cube(colors, tcount); 266 this.count = this.count-tcount; 267 ret.min[splitChannel] = this.min[splitChannel]; 268 ret.max[splitChannel] = splitLo; 269 this.min[splitChannel] = splitHi; 270 ret.min[c0] = this.min[c0]; 271 ret.max[c0] = this.max[c0]; 272 ret.min[c1] = this.min[c1]; 273 ret.max[c1] = this.max[c1]; 274 return ret; 275 } 276 277 280 public int averageColor() { 281 if (this.count == 0) return 0; 282 283 float red=0, grn=0, blu=0; 284 285 int minR=min[0], minG=min[1], minB=min[2]; 286 int maxR=max[0], maxG=max[1], maxB=max[2]; 287 int [] minIdx = {minR>>4, minG>>4, minB>>4}; 288 int [] maxIdx = {maxR>>4, maxG>>4, maxB>>4}; 289 int val, ired, igrn, iblu; 290 float weight; 291 for (int i=minIdx[0]; i<=maxIdx[0]; i++) { 292 int idx1 = i<<8; 293 for (int j=minIdx[1]; j<=maxIdx[1]; j++) { 294 int idx2 = idx1 | (j<<4); 295 for (int k=minIdx[2]; k<=maxIdx[2]; k++) { 296 int idx = idx2 | k; 297 Vector v = colors[idx]; 298 if (v==null) continue; 299 Iterator itr = v.iterator(); 300 Counter c; 301 while (itr.hasNext()) { 302 c = (Counter)itr.next(); 303 val = c.val; 304 ired = (val&0xFF0000)>>16; 305 igrn = (val&0x00FF00)>>8; 306 iblu = (val&0x0000FF); 307 if (((ired >= minR) && (ired <= maxR))&& 308 ((igrn >= minG) && (igrn <= maxG))&& 309 ((iblu >= minB) && (iblu <= maxB))) { 310 weight = (c.count/(float)this.count); 311 red += (ired*weight); 312 grn += (igrn*weight); 313 blu += (iblu*weight); 314 } 315 } 316 } 317 } 318 } 319 return (((int)(red+0.5))<<16 | 322 ((int)(grn+0.5))<<8 | 323 ((int)(blu+0.5))); 324 } 325 } 326 327 334 static public BufferedImage getIndexedImage 335 (BufferedImage bi, int nColors) { 336 int w=bi.getWidth(); 337 int h=bi.getHeight(); 338 339 Vector [] colors = new Vector [1<<12]; 341 342 int rgb=0; 343 for(int i_w=0; i_w<w; i_w++){ 344 for(int i_h=0; i_h<h; i_h++){ 345 rgb=(bi.getRGB(i_w,i_h) & 0xFFFFFF); 346 int idx = (((rgb&0xF00000)>>> 12) | 348 ((rgb&0x00F000)>>> 8) | 349 ((rgb&0x0000F0)>>> 4)); 350 351 Vector v = colors[idx]; 353 if (v == null) { 354 v = new Vector (); 357 v.add(new Counter(rgb)); 358 colors[idx] = v; 359 } else { 360 Iterator i = v.iterator(); 362 while (true) { 363 if (i.hasNext()) { 364 if (((Counter)i.next()).add(rgb)) break; 366 } else { 367 v.add(new Counter(rgb)); 368 break; 369 } 370 } 371 } 372 } 373 } 374 375 int nCubes=1; 376 int fCube=0; 377 Cube [] cubes = new Cube[nColors]; 378 cubes[0] = new Cube(colors, w*h); 379 380 while (nCubes < nColors) { 381 while (cubes[fCube].isDone()) { 382 fCube++; 383 if (fCube == nCubes) break; 384 } 385 if (fCube == nCubes) break; 386 Cube c = cubes[fCube]; 387 Cube nc = c.split(); 388 if (nc != null) { 389 if (nc.count > c.count) { 390 Cube tmp = c; c= nc; nc = tmp; 391 } 392 int j = fCube; 393 int cnt = c.count; 394 for (int i=fCube+1; i<nCubes; i++) { 395 if (cubes[i].count < cnt) 396 break; 397 cubes[j++] = cubes[i]; 398 } 399 cubes[j++] = c; 400 401 cnt = nc.count; 402 while (j<nCubes) { 403 if (cubes[j].count < cnt) 404 break; 405 j++; 406 } 407 for (int i=nCubes; i>j; i--) 408 cubes[i] = cubes[i-1]; 409 cubes[j++] = nc; 410 nCubes++; 411 } 412 } 413 414 byte [] r = new byte[nCubes]; 415 byte [] g = new byte[nCubes]; 416 byte [] b = new byte[nCubes]; 417 for (int i=0; i<nCubes; i++) { 418 int val = cubes[i].averageColor(); 419 r[i] = (byte)((val>>16)&0xFF); 420 g[i] = (byte)((val>> 8)&0xFF); 421 b[i] = (byte)((val )&0xFF); 422 423 } 427 BufferedImage indexed; 428 429 430 IndexColorModel icm=new IndexColorModel (8,nCubes,r,g,b); 435 indexed =new BufferedImage 436 (w, h, BufferedImage.TYPE_BYTE_INDEXED, icm); 437 Graphics2D g2d=indexed.createGraphics(); 438 g2d.setRenderingHint 439 (RenderingHints.KEY_DITHERING, 440 RenderingHints.VALUE_DITHER_ENABLE); 441 g2d.drawImage(bi, 0, 0, null); 442 g2d.dispose(); 443 444 445 int bits; 446 for (bits=1; bits <=8; bits++) { 447 if ((1<<bits) >= nCubes) break; 448 } 449 451 if (bits > 4) 452 return indexed; 454 455 if (bits ==3) bits = 4; 457 ColorModel cm=new IndexColorModel (bits,nCubes,r,g,b); 458 SampleModel sm = new MultiPixelPackedSampleModel 459 (DataBuffer.TYPE_BYTE, w, h, bits); 460 WritableRaster ras = Raster.createWritableRaster 461 (sm, new Point (0,0)); 462 463 bi = indexed; 465 indexed = new BufferedImage (cm, ras, 466 bi.isAlphaPremultiplied(), null); 467 GraphicsUtil.copyData(bi, indexed); 468 return indexed; 469 } 470 } 471 | Popular Tags |