| 1 18 package org.apache.batik.ext.awt.image.rendered; 19 20 import java.awt.Rectangle ; 21 import java.awt.RenderingHints ; 22 import java.awt.color.ColorSpace ; 23 import java.awt.geom.Point2D ; 24 import java.awt.geom.Rectangle2D ; 25 import java.awt.image.BufferedImage ; 26 import java.awt.image.BufferedImageOp ; 27 import java.awt.image.ColorModel ; 28 import java.awt.image.DataBuffer ; 29 import java.awt.image.DataBufferInt ; 30 import java.awt.image.DirectColorModel ; 31 import java.awt.image.Raster ; 32 import java.awt.image.RasterOp ; 33 import java.awt.image.SampleModel ; 34 import java.awt.image.SinglePixelPackedSampleModel ; 35 import java.awt.image.WritableRaster ; 36 37 import org.apache.batik.ext.awt.image.GraphicsUtil; 38 39 47 public class MorphologyOp implements BufferedImageOp , RasterOp { 48 51 private int radiusX; 52 55 private int radiusY; 56 60 private boolean doDilation; 61 62 65 private final int rangeX; 66 67 70 private final int rangeY; 71 72 75 private final ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB); 76 77 80 private final ColorSpace lRGB = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); 81 82 92 public MorphologyOp (int radiusX, int radiusY, boolean doDilation){ 93 if (radiusX<=0 || radiusY<=0){ 94 throw new IllegalArgumentException (new String ("The radius of X-axis or Y-axis should not be Zero or Negatives.")); 95 } 96 else { 97 this.radiusX = radiusX; 98 this.radiusY = radiusY; 99 this.doDilation = doDilation; 100 rangeX = 2*radiusX + 1; 101 rangeY = 2*radiusY + 1; 102 } 103 } 104 105 public Rectangle2D getBounds2D(Raster src){ 106 checkCompatible(src.getSampleModel()); 107 return new Rectangle (src.getMinX(), src.getMinY(), src.getWidth(), src.getHeight()); 108 } 109 110 public Rectangle2D getBounds2D(BufferedImage src){ 111 return new Rectangle (0, 0, src.getWidth(), src.getHeight()); 112 } 113 114 public Point2D getPoint2D(Point2D srcPt, Point2D destPt){ 115 if(destPt==null) 117 destPt = new Point2D.Float (); 118 destPt.setLocation(srcPt.getX(), srcPt.getY()); 119 return destPt; 120 } 121 122 private void checkCompatible(ColorModel colorModel, 123 SampleModel sampleModel){ 124 ColorSpace cs = colorModel.getColorSpace(); 125 126 if((!cs .equals (sRGB)) && (!cs .equals( lRGB))) 128 throw new IllegalArgumentException ("Expected CS_sRGB or CS_LINEAR_RGB color model"); 129 130 if(!(colorModel instanceof DirectColorModel )) 132 throw new IllegalArgumentException ("colorModel should be an instance of DirectColorModel"); 133 134 if(sampleModel.getDataType() != DataBuffer.TYPE_INT) 136 throw new IllegalArgumentException ("colorModel's transferType should be DataBuffer.TYPE_INT"); 137 138 DirectColorModel dcm = (DirectColorModel )colorModel; 140 if(dcm.getRedMask() != 0x00ff0000) 141 throw new IllegalArgumentException ("red mask in source should be 0x00ff0000"); 142 if(dcm.getGreenMask() != 0x0000ff00) 143 throw new IllegalArgumentException ("green mask in source should be 0x0000ff00"); 144 if(dcm.getBlueMask() != 0x000000ff) 145 throw new IllegalArgumentException ("blue mask in source should be 0x000000ff"); 146 if(dcm.getAlphaMask() != 0xff000000) 147 throw new IllegalArgumentException ("alpha mask in source should be 0xff000000"); 148 } 149 150 private boolean isCompatible(ColorModel colorModel, 151 SampleModel sampleModel){ 152 ColorSpace cs = colorModel.getColorSpace(); 153 if((cs != ColorSpace.getInstance(ColorSpace.CS_sRGB)) 155 && 156 (cs != ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB))) 157 return false; 158 159 if(!(colorModel instanceof DirectColorModel )) 161 return false; 162 163 if(sampleModel.getDataType() != DataBuffer.TYPE_INT) 165 return false; 166 167 DirectColorModel dcm = (DirectColorModel )colorModel; 169 if(dcm.getRedMask() != 0x00ff0000) 170 return false; 171 if(dcm.getGreenMask() != 0x0000ff00) 172 return false; 173 if(dcm.getBlueMask() != 0x000000ff) 174 return false; 175 if(dcm.getAlphaMask() != 0xff000000) 176 return false; 177 return true; 178 } 179 180 private void checkCompatible(SampleModel model){ 181 if(!(model instanceof SinglePixelPackedSampleModel )) 183 throw new IllegalArgumentException  184 ("MorphologyOp only works with Rasters " + 185 "using SinglePixelPackedSampleModels"); 186 int nBands = model.getNumBands(); 188 if(nBands!=4) 189 throw new IllegalArgumentException  190 ("MorphologyOp only words with Rasters having 4 bands"); 191 if(model.getDataType()!=DataBuffer.TYPE_INT) 193 throw new IllegalArgumentException  194 ("MorphologyOp only works with Rasters using DataBufferInt"); 195 196 int bitOffsets[]=((SinglePixelPackedSampleModel )model).getBitOffsets(); 198 for(int i=0; i<bitOffsets.length; i++){ 199 if(bitOffsets[i]%8 != 0) 200 throw new IllegalArgumentException  201 ("MorphologyOp only works with Rasters using 8 bits " + 202 "per band : " + i + " : " + bitOffsets[i]); 203 } 204 } 205 206 public RenderingHints getRenderingHints(){ 207 return null; 208 } 209 210 public WritableRaster createCompatibleDestRaster(Raster src){ 211 checkCompatible(src.getSampleModel()); 212 return src.createCompatibleWritableRaster(); 214 } 215 216 public BufferedImage createCompatibleDestImage(BufferedImage src, 217 ColorModel destCM){ 218 BufferedImage dest = null; 219 if(destCM==null) 220 destCM = src.getColorModel(); 221 222 WritableRaster wr; 223 wr = destCM.createCompatibleWritableRaster(src.getWidth(), 224 src.getHeight()); 225 checkCompatible(destCM, wr.getSampleModel()); 226 227 dest = new BufferedImage (destCM, wr, 228 destCM.isAlphaPremultiplied(), null); 229 return dest; 230 } 231 232 236 static final boolean isBetter (final int v1, final int v2, final boolean doDilation) { 237 if (v1 > v2) 238 return doDilation; 239 if (v1 < v2) 240 return !doDilation; 241 return true; 242 } 243 244 248 private void specialProcessRow(Raster src, WritableRaster dest){ 249 final int w = src.getWidth(); 250 final int h = src.getHeight(); 251 252 DataBufferInt srcDB = (DataBufferInt )src.getDataBuffer(); 254 DataBufferInt dstDB = (DataBufferInt )dest.getDataBuffer(); 255 256 SinglePixelPackedSampleModel sppsm; 258 sppsm = (SinglePixelPackedSampleModel )src.getSampleModel(); 259 260 final int srcOff = srcDB.getOffset() + 261 sppsm.getOffset(src.getMinX() - src.getSampleModelTranslateX(), 262 src.getMinY() - src.getSampleModelTranslateY()); 263 264 265 sppsm = (SinglePixelPackedSampleModel )dest.getSampleModel(); 266 final int dstOff = dstDB.getOffset() + 267 sppsm.getOffset(dest.getMinX() - dest.getSampleModelTranslateX(), 268 dest.getMinY() - dest.getSampleModelTranslateY()); 269 270 final int srcScanStride = ((SinglePixelPackedSampleModel )src.getSampleModel()).getScanlineStride(); 273 final int dstScanStride = ((SinglePixelPackedSampleModel )dest.getSampleModel()).getScanlineStride(); 274 275 final int srcPixels[] = srcDB.getBankData()[0]; 277 final int destPixels[] = dstDB.getBankData()[0]; 278 279 int sp, dp; 281 282 286 int bufferHead; 288 289 int maxIndexA; 290 int maxIndexR; 291 int maxIndexG; 292 int maxIndexB; 293 294 int pel, currentPixel, lastPixel; 296 int a,r,g,b; 297 int a1,r1,g1,b1; 298 299 if (w<=radiusX){ 302 for (int i=0; i<h; i++){ 303 sp = srcOff + i*srcScanStride; 305 dp = dstOff + i*dstScanStride; 306 pel = srcPixels[sp++]; 307 a = pel>>>24; 308 r = pel&0xff0000; 309 g = pel&0xff00; 310 b = pel&0xff; 311 312 for (int k=1; k<w; k++){ 313 currentPixel = srcPixels[sp++]; 314 a1 = currentPixel>>>24; 315 r1 = currentPixel&0xff0000; 316 g1 = currentPixel&0xff00; 317 b1 = currentPixel&0xff; 318 319 if (isBetter(a1, a, doDilation)){ 320 a = a1; 321 } 322 if (isBetter(r1, r, doDilation)){ 323 r = r1; 324 } 325 if (isBetter(g1, g, doDilation)){ 326 g = g1; 327 } 328 if (isBetter(b1, b, doDilation)){ 329 b = b1; 330 } 331 } 332 for (int k=0; k<w; k++){ 334 destPixels[dp++] = (a << 24) | r | g | b; 335 } 336 } 337 } 338 339 else { 341 342 final int [] bufferA = new int [w]; 344 final int [] bufferR = new int [w]; 345 final int [] bufferG = new int [w]; 346 final int [] bufferB = new int [w]; 347 348 for (int i=0; i<h; i++){ 349 sp = srcOff + i*srcScanStride; 352 dp = dstOff + i*dstScanStride; 353 354 bufferHead = 0; 355 maxIndexA = 0; 356 maxIndexR = 0; 357 maxIndexG = 0; 358 maxIndexB = 0; 359 360 pel = srcPixels[sp++]; 361 a = pel>>>24; 362 r = pel&0xff0000; 363 g = pel&0xff00; 364 b = pel&0xff; 365 bufferA[0] = a; 366 bufferR[0] = r; 367 bufferG[0] = g; 368 bufferB[0] = b; 369 370 for (int k=1; k<=radiusX; k++){ 371 currentPixel = srcPixels[sp++]; 372 a1 = currentPixel>>>24; 373 r1 = currentPixel&0xff0000; 374 g1 = currentPixel&0xff00; 375 b1 = currentPixel&0xff; 376 bufferA[k] = a1; 377 bufferR[k] = r1; 378 bufferG[k] = g1; 379 bufferB[k] = b1; 380 381 if (isBetter(a1, a, doDilation)){ 382 a = a1; 383 maxIndexA = k; 384 } 385 if (isBetter(r1, r, doDilation)){ 386 r = r1; 387 maxIndexR = k; 388 } 389 if (isBetter(g1, g, doDilation)){ 390 g = g1; 391 maxIndexG = k; 392 } 393 if (isBetter(b1, b, doDilation)){ 394 b = b1; 395 maxIndexB = k; 396 } 397 } 398 destPixels[dp++] = (a << 24) | r | g | b; 399 400 for (int j=1; j<=w-radiusX-1; j++){ 404 lastPixel = srcPixels[sp++]; 405 406 408 a = bufferA[maxIndexA]; 410 a1 = lastPixel>>>24; 411 bufferA[j+radiusX] = a1; 412 if (isBetter(a1, a, doDilation)){ 413 a = a1; 414 maxIndexA = j+radiusX; 415 } 416 417 419 r = bufferR[maxIndexR]; 420 r1 = lastPixel&0xff0000; 421 bufferR[j+radiusX] = r1; 422 if (isBetter(r1, r, doDilation)){ 423 r = r1; 424 maxIndexR = j+radiusX; 425 } 426 427 429 g = bufferG[maxIndexG]; 430 g1 = lastPixel&0xff00; 431 bufferG[j+radiusX] = g1; 432 if (isBetter(g1, g, doDilation)){ 433 g = g1; 434 maxIndexG = j+radiusX; 435 } 436 437 439 b = bufferB[maxIndexB]; 440 b1 = lastPixel&0xff; 441 bufferB[j+radiusX] = b1; 442 if (isBetter(b1, b, doDilation)){ 443 b = b1; 444 maxIndexB = j+radiusX; 445 } 446 451 destPixels[dp++] = (a << 24) | r | g | b; 452 } 453 for (int j = w-radiusX; j<= radiusX; j++){ 456 destPixels[dp] = destPixels[dp-1]; 457 dp++; 458 } 459 for (int j = radiusX+1; j<w; j++){ 462 463 if (maxIndexA == bufferHead){ 464 a = bufferA[bufferHead+1]; 465 maxIndexA = bufferHead+1; 466 for (int m= bufferHead+2; m< w; m++){ 467 a1 = bufferA[m]; 468 if (isBetter(a1, a, doDilation)){ 469 a = a1; 470 maxIndexA = m; 471 } 472 } 473 } 474 else { 475 a = bufferA[maxIndexA]; 476 } 477 if (maxIndexR == bufferHead){ 478 r = bufferR[bufferHead+1]; 479 maxIndexR = bufferHead+1; 480 for (int m= bufferHead+2; m< w; m++){ 481 r1 = bufferR[m]; 482 if (isBetter(r1, r, doDilation)){ 483 r = r1; 484 maxIndexR = m; 485 } 486 } 487 } 488 else { 489 r = bufferR[maxIndexR]; 490 } 491 492 if (maxIndexG == bufferHead){ 493 g = bufferG[bufferHead+1]; 494 maxIndexG = bufferHead+1; 495 for (int m= bufferHead+2; m< w; m++){ 496 g1 = bufferG[m]; 497 if (isBetter(g1, g, doDilation)){ 498 g = g1; 499 maxIndexG = m; 500 } 501 } 502 } 503 else { 505 g = bufferG[maxIndexG]; 506 } 507 508 if (maxIndexB == bufferHead){ 509 b = bufferB[bufferHead+1]; 510 maxIndexB = bufferHead+1; 511 for (int m= bufferHead+2; m< w; m++){ 512 b1 = bufferB[m]; 513 if (isBetter(b1, b, doDilation)){ 514 b = b1; 515 maxIndexB = m; 516 } 517 } 518 } 519 else { 521 b = bufferB[maxIndexB]; 522 } 523 524 bufferHead++; 526 527 destPixels[dp++] = (a << 24) | r | g | b; 528 } 529 } 531 } } 533 534 538 private void specialProcessColumn(Raster src, WritableRaster dest){ 539 540 final int w = src.getWidth(); 541 final int h = src.getHeight(); 542 543 DataBufferInt dstDB = (DataBufferInt )dest.getDataBuffer(); 545 546 final int dstOff = dstDB.getOffset(); 548 549 final int dstScanStride = ((SinglePixelPackedSampleModel )dest.getSampleModel()).getScanlineStride(); 552 553 final int destPixels[] = dstDB.getBankData()[0]; 555 556 int dp, cp; 558 559 563 int bufferHead; 565 566 int maxIndexA; 567 int maxIndexR; 568 int maxIndexG; 569 int maxIndexB; 570 571 int pel, currentPixel, lastPixel; 573 int a,r,g,b; 574 int a1,r1,g1,b1; 575 576 if (h<=radiusY){ 579 for (int j=0; j<w; j++){ 580 dp = dstOff + j; 581 cp = dstOff + j; 582 pel = destPixels[cp]; 583 cp += dstScanStride; 584 a = pel>>>24; 585 r = pel&0xff0000; 586 g = pel&0xff00; 587 b = pel&0xff; 588 589 for (int k=1; k<h; k++){ 590 currentPixel = destPixels[cp]; 591 cp += dstScanStride; 592 a1 = currentPixel>>>24; 593 r1 = currentPixel&0xff0000; 594 g1 = currentPixel&0xff00; 595 b1 = currentPixel&0xff; 596 597 if (isBetter(a1, a, doDilation)){ 598 a = a1; 599 } 600 if (isBetter(r1, r, doDilation)){ 601 r = r1; 602 } 603 if (isBetter(g1, g, doDilation)){ 604 g = g1; 605 } 606 if (isBetter(b1, b, doDilation)){ 607 b = b1; 608 } 609 } 610 for (int k=0; k<h; k++){ 611 destPixels[dp] = (a << 24) | r | g | b; 612 dp += dstScanStride; 613 } 614 } 616 } 617 618 else { 620 621 final int [] bufferA = new int [h]; 623 final int [] bufferR = new int [h]; 624 final int [] bufferG = new int [h]; 625 final int [] bufferB = new int [h]; 626 627 for (int j=0; j<w; j++){ 628 dp = dstOff + j; 631 cp = dstOff + j; 632 633 bufferHead = 0; 634 maxIndexA = 0; 635 maxIndexR = 0; 636 maxIndexG = 0; 637 maxIndexB = 0; 638 639 pel = destPixels[cp]; 640 cp += dstScanStride; 641 a = pel>>>24; 642 r = pel&0xff0000; 643 g = pel&0xff00; 644 b = pel&0xff; 645 bufferA[0] = a; 646 bufferR[0] = r; 647 bufferG[0] = g; 648 bufferB[0] = b; 649 650 for (int k=1; k<=radiusY; k++){ 651 currentPixel = destPixels[cp]; 652 cp += dstScanStride; 653 a1 = currentPixel>>>24; 654 r1 = currentPixel&0xff0000; 655 g1 = currentPixel&0xff00; 656 b1 = currentPixel&0xff; 657 bufferA[k] = a1; 658 bufferR[k] = r1; 659 bufferG[k] = g1; 660 bufferB[k] = b1; 661 662 if (isBetter(a1, a, doDilation)){ 663 a = a1; 664 maxIndexA = k; 665 } 666 if (isBetter(r1, r, doDilation)){ 667 r = r1; 668 maxIndexR = k; 669 } 670 if (isBetter(g1, g, doDilation)){ 671 g = g1; 672 maxIndexG = k; 673 } 674 if (isBetter(b1, b, doDilation)){ 675 b = b1; 676 maxIndexB = k; 677 } 678 } 679 destPixels[dp] = (a << 24) | r | g | b; 681 dp += dstScanStride; 682 683 for (int i=1; i<=h-radiusY-1; i++){ 687 lastPixel = destPixels[cp]; 688 cp += dstScanStride; 689 690 692 a = bufferA[maxIndexA]; 693 a1 = lastPixel>>>24; 694 bufferA[i+radiusY] = a1; 695 if (isBetter(a1, a, doDilation)){ 696 a = a1; 697 maxIndexA = i+radiusY; 698 } 699 700 702 r = bufferR[maxIndexR]; 703 r1 = lastPixel&0xff0000; 704 bufferR[i+radiusY] = r1; 705 if (isBetter(r1, r, doDilation)){ 706 r = r1; |