| 1 18 package org.apache.batik.ext.awt.image; 19 20 import java.awt.AlphaComposite ; 21 import java.awt.Composite ; 22 import java.awt.CompositeContext ; 23 import java.awt.RenderingHints ; 24 import java.awt.color.ColorSpace ; 25 import java.awt.image.ColorModel ; 26 import java.awt.image.DataBufferInt ; 27 import java.awt.image.PackedColorModel ; 28 import java.awt.image.Raster ; 29 import java.awt.image.SinglePixelPackedSampleModel ; 30 import java.awt.image.WritableRaster ; 31 32 38 public class SVGComposite 39 implements Composite { 40 41 public static final SVGComposite OVER 42 = new SVGComposite(CompositeRule.OVER); 43 44 public static final SVGComposite IN 45 = new SVGComposite(CompositeRule.IN); 46 47 public static final SVGComposite OUT 48 = new SVGComposite(CompositeRule.OUT); 49 50 public static final SVGComposite ATOP 51 = new SVGComposite(CompositeRule.ATOP); 52 53 public static final SVGComposite XOR 54 = new SVGComposite(CompositeRule.XOR); 55 56 public static final SVGComposite MULTIPLY 57 = new SVGComposite(CompositeRule.MULTIPLY); 58 59 public static final SVGComposite SCREEN 60 = new SVGComposite(CompositeRule.SCREEN); 61 62 public static final SVGComposite DARKEN 63 = new SVGComposite(CompositeRule.DARKEN); 64 65 public static final SVGComposite LIGHTEN 66 = new SVGComposite(CompositeRule.LIGHTEN); 67 68 69 CompositeRule rule; 70 71 public CompositeRule getRule() { return rule; } 72 73 public SVGComposite(CompositeRule rule) { 74 this.rule = rule; 75 } 76 77 public boolean equals(Object o) { 78 if (o instanceof SVGComposite) { 79 SVGComposite svgc = (SVGComposite)o; 80 return (svgc.getRule() == getRule()); 81 } else if (o instanceof AlphaComposite ) { 82 AlphaComposite ac = (AlphaComposite )o; 83 switch (getRule().getRule()) { 84 case CompositeRule.RULE_OVER: 85 return (ac == AlphaComposite.SrcOver); 86 case CompositeRule.RULE_IN: 87 return (ac == AlphaComposite.SrcIn); 88 case CompositeRule.RULE_OUT: 89 return (ac == AlphaComposite.SrcOut); 90 default: 91 return false; 92 } 93 } 94 return false; 95 } 96 97 public boolean is_INT_PACK(ColorModel cm) { 98 if(!(cm instanceof PackedColorModel )) return false; 100 101 PackedColorModel pcm = (PackedColorModel )cm; 102 103 int [] masks = pcm.getMasks(); 104 105 if(masks.length != 4) return false; 107 108 if (masks[0] != 0x00ff0000) return false; 109 if (masks[1] != 0x0000ff00) return false; 110 if (masks[2] != 0x000000ff) return false; 111 if (masks[3] != 0xff000000) return false; 112 113 return true; 114 } 115 116 public CompositeContext createContext(ColorModel srcCM, 117 ColorModel dstCM, 118 RenderingHints hints) { 119 if (false) { 120 ColorSpace srcCS = srcCM.getColorSpace(); 121 ColorSpace dstCS = dstCM.getColorSpace(); 122 System.out.println("srcCS: " + srcCS); 123 System.out.println("dstCS: " + dstCS); 124 System.out.println 125 ("lRGB: " + ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)); 126 System.out.println 127 ("sRGB: " + ColorSpace.getInstance(ColorSpace.CS_sRGB)); 128 } 129 130 boolean use_int_pack = (is_INT_PACK(srcCM) && is_INT_PACK(dstCM)); 133 135 switch (rule.getRule()) { 136 case CompositeRule.RULE_OVER: 137 if (!dstCM.hasAlpha()) { 138 if (use_int_pack) 139 return new OverCompositeContext_INT_PACK_NA(srcCM, dstCM); 140 else 141 return new OverCompositeContext_NA (srcCM, dstCM); 142 } 143 144 if (!use_int_pack) 145 return new OverCompositeContext(srcCM, dstCM); 146 147 if (srcCM.isAlphaPremultiplied()) 148 return new OverCompositeContext_INT_PACK(srcCM, dstCM); 149 else 150 return new OverCompositeContext_INT_PACK_UNPRE(srcCM, dstCM); 151 152 case CompositeRule.RULE_IN: 153 if (use_int_pack) 154 return new InCompositeContext_INT_PACK(srcCM, dstCM); 155 else 156 return new InCompositeContext (srcCM, dstCM); 157 158 case CompositeRule.RULE_OUT: 159 if (use_int_pack) 160 return new OutCompositeContext_INT_PACK(srcCM, dstCM); 161 else 162 return new OutCompositeContext (srcCM, dstCM); 163 164 case CompositeRule.RULE_ATOP: 165 if (use_int_pack) 166 return new AtopCompositeContext_INT_PACK(srcCM, dstCM); 167 else 168 return new AtopCompositeContext(srcCM, dstCM); 169 170 case CompositeRule.RULE_XOR: 171 if (use_int_pack) 172 return new XorCompositeContext_INT_PACK(srcCM, dstCM); 173 else 174 return new XorCompositeContext (srcCM, dstCM); 175 176 case CompositeRule.RULE_ARITHMETIC: 177 float [] coeff = rule.getCoefficients(); 178 if (use_int_pack) 179 return new ArithCompositeContext_INT_PACK_LUT 180 (srcCM, dstCM, coeff[0], coeff[1], coeff[2], coeff[3]); 181 else 182 return new ArithCompositeContext 183 (srcCM, dstCM, coeff[0], coeff[1], coeff[2], coeff[3]); 184 185 case CompositeRule.RULE_MULTIPLY: 186 if (use_int_pack) 187 return new MultiplyCompositeContext_INT_PACK(srcCM, dstCM); 188 else 189 return new MultiplyCompositeContext(srcCM, dstCM); 190 191 case CompositeRule.RULE_SCREEN: 192 if (use_int_pack) 193 return new ScreenCompositeContext_INT_PACK(srcCM, dstCM); 194 else 195 return new ScreenCompositeContext (srcCM, dstCM); 196 197 case CompositeRule.RULE_DARKEN: 198 if (use_int_pack) 199 return new DarkenCompositeContext_INT_PACK(srcCM, dstCM); 200 else 201 return new DarkenCompositeContext (srcCM, dstCM); 202 203 case CompositeRule.RULE_LIGHTEN: 204 if (use_int_pack) 205 return new LightenCompositeContext_INT_PACK(srcCM, dstCM); 206 else 207 return new LightenCompositeContext (srcCM, dstCM); 208 209 default: 210 throw new UnsupportedOperationException  211 ("Unknown composite rule requested."); 212 } 213 214 } 215 216 public static abstract class AlphaPreCompositeContext 217 implements CompositeContext { 218 219 ColorModel srcCM, dstCM; 220 AlphaPreCompositeContext(ColorModel srcCM, ColorModel dstCM) { 221 this.srcCM = srcCM; 222 this.dstCM = dstCM; 223 } 224 225 public void dispose() { 226 srcCM = null; 227 dstCM = null; 228 } 229 230 protected abstract void precompose(Raster src, Raster dstIn, 231 WritableRaster dstOut); 232 233 public void compose(Raster src, Raster dstIn, WritableRaster dstOut) { 234 ColorModel srcPreCM = srcCM; 235 if (!srcCM.isAlphaPremultiplied()) 236 srcPreCM = GraphicsUtil.coerceData((WritableRaster )src, 237 srcCM, true); 238 239 ColorModel dstPreCM = dstCM; 240 if (!dstCM.isAlphaPremultiplied()) 241 dstPreCM = GraphicsUtil.coerceData((WritableRaster )dstIn, 242 dstCM, true); 243 244 precompose(src, dstIn, dstOut); 245 246 if (!srcCM.isAlphaPremultiplied()) 247 GraphicsUtil.coerceData((WritableRaster )src, 248 srcPreCM, false); 249 250 if (!dstCM.isAlphaPremultiplied()) { 251 GraphicsUtil.coerceData(dstOut, dstPreCM, false); 252 253 if (dstIn != dstOut) 254 GraphicsUtil.coerceData((WritableRaster )dstIn, 255 dstPreCM, false); 256 } 257 } 258 } 259 260 public static abstract class AlphaPreCompositeContext_INT_PACK 261 extends AlphaPreCompositeContext { 262 263 AlphaPreCompositeContext_INT_PACK(ColorModel srcCM, ColorModel dstCM) { 264 super(srcCM, dstCM); 265 } 266 267 protected abstract void precompose_INT_PACK 268 (final int width, final int height, 269 final int [] srcPixels, final int srcAdjust, int srcSp, 270 final int [] dstInPixels, final int dstInAdjust, int dstInSp, 271 final int [] dstOutPixels, final int dstOutAdjust, int dstOutSp); 272 273 protected void precompose(Raster src, Raster dstIn, 274 WritableRaster dstOut) { 275 276 int x0=dstOut.getMinX(); 277 int w =dstOut.getWidth(); 278 279 int y0=dstOut.getMinY(); 280 int h =dstOut.getHeight(); 281 282 SinglePixelPackedSampleModel srcSPPSM; 283 srcSPPSM = (SinglePixelPackedSampleModel )src.getSampleModel(); 284 285 final int srcScanStride = srcSPPSM.getScanlineStride(); 286 DataBufferInt srcDB = (DataBufferInt )src.getDataBuffer(); 287 final int [] srcPixels = srcDB.getBankData()[0]; 288 final int srcBase = 289 (srcDB.getOffset() + 290 srcSPPSM.getOffset(x0-src.getSampleModelTranslateX(), 291 y0-src.getSampleModelTranslateY())); 292 293 294 SinglePixelPackedSampleModel dstInSPPSM; 295 dstInSPPSM = (SinglePixelPackedSampleModel )dstIn.getSampleModel(); 296 297 final int dstInScanStride = dstInSPPSM.getScanlineStride(); 298 DataBufferInt dstInDB = (DataBufferInt )dstIn.getDataBuffer(); 299 final int [] dstInPixels = dstInDB.getBankData()[0]; 300 final int dstInBase = 301 (dstInDB.getOffset() + 302 dstInSPPSM.getOffset(x0-dstIn.getSampleModelTranslateX(), 303 y0-dstIn.getSampleModelTranslateY())); 304 305 SinglePixelPackedSampleModel dstOutSPPSM 306 = (SinglePixelPackedSampleModel )dstOut.getSampleModel(); 307 308 final int dstOutScanStride = dstOutSPPSM.getScanlineStride(); 309 DataBufferInt dstOutDB = (DataBufferInt )dstOut.getDataBuffer(); 310 final int [] dstOutPixels = dstOutDB.getBankData()[0]; 311 final int dstOutBase = 312 (dstOutDB.getOffset() + 313 dstOutSPPSM.getOffset(x0-dstOut.getSampleModelTranslateX(), 314 y0-dstOut.getSampleModelTranslateY())); 315 316 final int srcAdjust = srcScanStride - w; 317 final int dstInAdjust = dstInScanStride - w; 318 final int dstOutAdjust = dstOutScanStride - w; 319 320 precompose_INT_PACK(w, h, 321 srcPixels, srcAdjust, srcBase, 322 dstInPixels, dstInAdjust, dstInBase, 323 dstOutPixels, dstOutAdjust, dstOutBase); 324 } 325 } 326 327 328 331 public static class OverCompositeContext 332 extends AlphaPreCompositeContext { 333 OverCompositeContext(ColorModel srcCM, ColorModel dstCM) { 334 super(srcCM, dstCM); 335 } 336 337 public void precompose(Raster src, Raster dstIn, 338 WritableRaster dstOut) { 339 int [] srcPix = null; 340 int [] dstPix = null; 341 342 int x=dstOut.getMinX(); 343 int w=dstOut.getWidth(); 344 345 int y0=dstOut.getMinY(); 346 int y1=y0 + dstOut.getHeight(); 347 348 final int norm = (1<<24)/255; 349 final int pt5 = (1<<23); 350 351 for (int y = y0; y<y1; y++) { 352 srcPix = src.getPixels (x, y, w, 1, srcPix); 353 dstPix = dstIn.getPixels(x, y, w, 1, dstPix); 354 int sp = 0; 355 int end = w*4; 356 while(sp<end) { 357 final int dstM = (255-srcPix[sp+3])*norm; 358 dstPix[sp] = srcPix[sp] + ((dstPix[sp]*dstM +pt5)>>>24); 359 ++sp; 360 dstPix[sp] = srcPix[sp] + ((dstPix[sp]*dstM +pt5)>>>24); 361 ++sp; 362 dstPix[sp] = srcPix[sp] + ((dstPix[sp]*dstM +pt5)>>>24); 363 ++sp; 364 dstPix[sp] = srcPix[sp] + ((dstPix[sp]*dstM +pt5)>>>24); 365 ++sp; 366 } 367 dstOut.setPixels(x, y, w, 1, dstPix); 368 } 369 370 } 371 } 372 373 377 public static class OverCompositeContext_NA 378 extends AlphaPreCompositeContext { 379 OverCompositeContext_NA(ColorModel srcCM, ColorModel dstCM) { 380 super(srcCM, dstCM); 381 } 382 383 public void precompose(Raster src, Raster dstIn, 384 WritableRaster dstOut) { 385 int [] srcPix = null; 386 int [] dstPix = null; 387 388 int x=dstOut.getMinX(); 389 int w=dstOut.getWidth(); 390 391 int y0=dstOut.getMinY(); 392 int y1=y0 + dstOut.getHeight(); 393 394 final int norm = (1<<24)/255; 395 final int pt5 = (1<<23); 396 397 for (int y = y0; y<y1; y++) { 398 srcPix = src.getPixels (x, y, w, 1, srcPix); 399 dstPix = dstIn.getPixels(x, y, w, 1, dstPix); 400 int srcSP = 0; 401 int dstSP = 0; 402 int end = w*4; 403 while (srcSP<end) { 404 final int dstM = (255-srcPix[srcSP+3])*norm; 405 dstPix[dstSP] = 406 srcPix[srcSP] + ((dstPix[dstSP]*dstM +pt5)>>>24); 407 ++srcSP; ++dstSP; 408 dstPix[dstSP] = 409 srcPix[srcSP] + ((dstPix[dstSP]*dstM +pt5)>>>24); 410 ++srcSP; ++dstSP; 411 dstPix[dstSP] = 412 srcPix[srcSP] + ((dstPix[dstSP]*dstM +pt5)>>>24); 413 srcSP+=2; ++dstSP; 414 } 415 dstOut.setPixels(x, y, w, 1, dstPix); 416 } 417 } 418 } 419 420 424 public static class OverCompositeContext_INT_PACK 425 extends AlphaPreCompositeContext_INT_PACK { 426 OverCompositeContext_INT_PACK(ColorModel srcCM, ColorModel dstCM) { 427 super(srcCM, dstCM); 428 } 429 430 public void precompose_INT_PACK 431 (final int width, final int height, 432 final int [] srcPixels, final int srcAdjust, int srcSp, 433 final int [] dstInPixels, final int dstInAdjust, int dstInSp, 434 final int [] dstOutPixels, final int dstOutAdjust, int dstOutSp) { 435 436 final int norm = (1<<24)/255; 437 final int pt5 = (1<<23); 438 439 int srcP, dstInP, dstM; 440 441 for (int y = 0; y<height; y++) { 442 final int end = dstOutSp+width; 443 while (dstOutSp<end) { 444 srcP = srcPixels [srcSp++]; 445 dstInP = dstInPixels[dstInSp++]; 446 447 dstM = (255-(srcP>>>24))*norm; 448 dstOutPixels[dstOutSp++] = 449 ((( srcP & 0xFF000000) + 450 (((((dstInP>>>24) )*dstM+pt5)&0xFF000000) ))| 451 (( srcP & 0x00FF0000) + 452 (((((dstInP>> 16)&0xFF)*dstM+pt5)&0xFF000000)>>> 8))| 453 (( srcP & 0x0000FF00) + 454 (((((dstInP>> 8)&0xFF)*dstM+pt5)&0xFF000000)>>>16))| 455 (( srcP & 0x000000FF) + 456 (((((dstInP )&0xFF)*dstM+pt5) )>>>24))); 457 } 458 srcSp += srcAdjust; 459 dstInSp += dstInAdjust; 460 dstOutSp += dstOutAdjust; 461 } 462 } 463 } 464 465 468 public static class OverCompositeContext_INT_PACK_NA 469 extends AlphaPreCompositeContext_INT_PACK { 470 OverCompositeContext_INT_PACK_NA(ColorModel srcCM, ColorModel dstCM) { 471 super (srcCM, dstCM); 472 } 473 474 public void precompose_INT_PACK 476 (final int width, final int height, 477 final int [] srcPixels, final int srcAdjust, int srcSp, 478 final int [] dstInPixels, final int dstInAdjust, int dstInSp, 479 final int [] dstOutPixels, final int dstOutAdjust, int dstOutSp) { 480 481 final int norm = (1<<24)/255; 482 final int pt5 = (1<<23); 483 484 int srcP, dstInP, dstM; 485 486 for (int y = 0; y<height; y++) { 487 final int end = dstOutSp+width; 488 while (dstOutSp<end) { 489 srcP = srcPixels [srcSp++]; 490 dstInP = dstInPixels[dstInSp++]; 491 492 dstM = (255-(srcP>>>24))*norm; 493 dstOutPixels[dstOutSp++] = 494 ((( srcP & 0x00FF0000) + 495 (((((dstInP>> 16)&0xFF)*dstM+pt5)&0xFF000000)>>> 8))| 496 (( srcP & 0x0000FF00) + 497 (((((dstInP>> 8)&0xFF)*dstM+pt5)&0xFF000000)>>>16))| 498 (( srcP & 0x000000FF) + 499 (((((dstInP )&0xFF)*dstM+pt5) )>>>24))); 500 } 501 srcSp += srcAdjust; 502 dstInSp += dstInAdjust; 503 dstOutSp += dstOutAdjust; 504 } 505 } 506 } 507 508 513 public static class OverCompositeContext_INT_PACK_UNPRE 514 extends AlphaPreCompositeContext_INT_PACK { 515 OverCompositeContext_INT_PACK_UNPRE 516 (ColorModel srcCM, ColorModel dstCM) { 517 super(srcCM, dstCM); 518 519 if (srcCM.isAlphaPremultiplied()) 520 throw new IllegalArgumentException  521 ("OverCompositeContext_INT_PACK_UNPRE is only for" + 522 "sources with unpremultiplied alpha"); 523 } 524 525 public void compose(Raster src, Raster dstIn, WritableRaster dstOut) { 526 ColorModel dstPreCM = dstCM; 527 if (!dstCM.isAlphaPremultiplied()) 528 dstPreCM = GraphicsUtil.coerceData((WritableRaster )dstIn, 529 dstCM, true); 530 531 precompose(src, dstIn, dstOut); 532 533 if (!dstCM.isAlphaPremultiplied()) { 534 GraphicsUtil.coerceData(dstOut, dstPreCM, false); 535 536 if (dstIn != dstOut) 537 GraphicsUtil.coerceData((WritableRaster )dstIn, 538 dstPreCM, false); 539 } 540 } 541 542 public void precompose_INT_PACK 543 (final int width, final int height, 544 final int [] srcPixels, final int srcAdjust, int srcSp, 545 final int [] dstInPixels, final int dstInAdjust, int dstInSp, 546 final int [] dstOutPixels, final int dstOutAdjust, int dstOutSp) { 547 548 final int norm = (1<<24)/255; 549 final int pt5 = (1<<23); 550 551 int srcP, srcM, dstP, dstM; 552 553 for (int y = 0; y<height; y++) { 554 final int end = dstOutSp+width; 555 while (dstOutSp<end) { 556 srcP = srcPixels [srcSp++]; 557 dstP = dstInPixels[dstInSp++]; 558 559 srcM = ( (srcP>>>24))*norm; 560 dstM = (255-(srcP>>>24))*norm; 561 562 dstOutPixels[dstOutSp++] = 563 ((((( srcP&0xFF000000) + 564 ((dstP>>>24) )*dstM + pt5)&0xFF000000) ) | 565 (((((srcP>> 16)&0xFF)*srcM + 566 ((dstP>> 16)&0xFF)*dstM + pt5)&0xFF000000)>>> 8) | 567 (((((srcP>> 8)&0xFF)*srcM + 568 ((dstP>> 8)&0xFF)*dstM + pt5)&0xFF000000)>>>16) | 569 (((((srcP )&0xFF)*srcM + 570 ((dstP )&0xFF)*dstM + pt5) )>>>24)); 571 } 572 srcSp += srcAdjust; 573 dstInSp += dstInAdjust; 574 dstOutSp += dstOutAdjust; 575 } 576 } 577 } 578 579 public static class InCompositeContext 580 extends AlphaPreCompositeContext { 581 InCompositeContext(ColorModel srcCM, ColorModel dstCM) { 582 super(srcCM, dstCM); 583 } 584 585 public void precompose(Raster src, Raster dstIn, 586 WritableRaster dstOut) { 587 int [] srcPix = null; 588 int [] dstPix = null; 589 590 int x=dstOut.getMinX(); 591 int w=dstOut.getWidth(); 592 593 int y0=dstOut.getMinY(); 594 int y1=y0 + dstOut.getHeight(); 595 596 final int norm = (1<<24)/255; 597 final int pt5 = (1<<23); 598 599 for (int y = y0; y<y1; y++) { 600 srcPix = src.getPixels (x, y, w, 1, srcPix); 601 dstPix = dstIn.getPixels(x, y, w, 1, dstPix); 602 int sp = 0; 603 int end = w*4; 604 while(sp<end) { 605 final int srcM = dstPix[sp+3]*norm; 606 dstPix[sp] = (srcPix[sp]*srcM + pt5)>>>24; ++sp; 607 dstPix[sp] = (srcPix[sp]*srcM + pt5)>>>24; ++sp; 608 dstPix[sp] = (srcPix[sp]*srcM + pt5)>>>24; ++sp; 609 dstPix[sp] = (srcPix[sp]*srcM + pt5)>>>24; ++sp; 610 } 611 dstOut.setPixels(x, y, w, 1, dstPix); 612 } 613 614 } 615 } 616 617 public static class InCompositeContext_INT_PACK 618 extends AlphaPreCompositeContext_INT_PACK { 619 InCompositeContext_INT_PACK(ColorModel srcCM, ColorModel dstCM) { 620 super(srcCM, dstCM); 621 } 622 623 public void precompose_INT_PACK 624 (final int width, final int height, 625 final int [] srcPixels, final int srcAdjust, int srcSp, 626 final int [] dstInPixels, final int dstInAdjust, int dstInSp, 627 final int [] dstOutPixels, final int dstOutAdjust, int dstOutSp) { 628 629 final int norm = (1<<24)/255; 630 final int pt5 = (1<<23); 631 632 int srcP, srcM; 633 634 for (int y = 0; y<height; y++) { 635 final int end = dstOutSp+width; 636 while (dstOutSp<end) { 637 srcM = (dstInPixels[dstInSp++]>>>24)*norm; 638 srcP = srcPixels [srcSp++]; 639 dstOutPixels[dstOutSp++] = 640 ((((((srcP>>>24) )*srcM + pt5)&0xFF000000) ) | 641 (((((srcP>> 16)&0xFF)*srcM + pt5)&0xFF000000)>>> 8) | 642 (((((srcP>> 8)&0xFF)*srcM + pt5)&0xFF000000)>>>16) | 643 (((((srcP )&0xFF)*srcM + pt5) )>>>24)); 644 } 645 srcSp += srcAdjust; 646 dstInSp += dstInAdjust; 647 dstOutSp += dstOutAdjust; 648 } 649 } 650 } 651 652 public static class OutCompositeContext 653 extends AlphaPreCompositeContext { 654 OutCompositeContext(ColorModel srcCM, ColorModel dstCM) { 655 &nbs
|