1 //---------------------------------------------------------------------------- 2 // Anti-Grain Geometry - Version 2.4 3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) 4 // 5 // Permission to copy, use, modify, sell and distribute this software 6 // is granted provided this copyright notice appears in all copies. 7 // This software is provided "as is" without express or implied 8 // warranty, and with no claim as to its suitability for any purpose. 9 // 10 //---------------------------------------------------------------------------- 11 // Contact: mcseem@antigrain.com 12 // mcseemagg@yahoo.com 13 // http://www.antigrain.com 14 //---------------------------------------------------------------------------- 15 // 16 // Adaptation for high precision colors has been sponsored by 17 // Liberty Technology Systems, Inc., visit http://lib-sys.com 18 // 19 // Liberty Technology Systems, Inc. is the provider of 20 // PostScript and PDF technology for software developers. 21 // 22 //---------------------------------------------------------------------------- 23 24 #ifndef AGG_PIXFMT_GRAY_INCLUDED 25 #define AGG_PIXFMT_GRAY_INCLUDED 26 27 #include <string.h> 28 #include "agg_pixfmt_base.h" 29 #include "agg_rendering_buffer.h" 30 31 namespace agg 32 { 33 34 //============================================================blender_gray 35 template<class ColorT> struct blender_gray 36 { 37 typedef ColorT color_type; 38 typedef typename color_type::value_type value_type; 39 typedef typename color_type::calc_type calc_type; 40 typedef typename color_type::long_type long_type; 41 42 // Blend pixels using the non-premultiplied form of Alvy-Ray Smith's 43 // compositing function. Since the render buffer is opaque we skip the 44 // initial premultiply and final demultiply. 45 blend_pixblender_gray46 static AGG_INLINE void blend_pix(value_type* p, 47 value_type cv, value_type alpha, cover_type cover) 48 { 49 blend_pix(p, cv, color_type::mult_cover(alpha, cover)); 50 } 51 blend_pixblender_gray52 static AGG_INLINE void blend_pix(value_type* p, 53 value_type cv, value_type alpha) 54 { 55 *p = color_type::lerp(*p, cv, alpha); 56 } 57 }; 58 59 60 //======================================================blender_gray_pre 61 template<class ColorT> struct blender_gray_pre 62 { 63 typedef ColorT color_type; 64 typedef typename color_type::value_type value_type; 65 typedef typename color_type::calc_type calc_type; 66 typedef typename color_type::long_type long_type; 67 68 // Blend pixels using the premultiplied form of Alvy-Ray Smith's 69 // compositing function. 70 blend_pixblender_gray_pre71 static AGG_INLINE void blend_pix(value_type* p, 72 value_type cv, value_type alpha, cover_type cover) 73 { 74 blend_pix(p, color_type::mult_cover(cv, cover), color_type::mult_cover(alpha, cover)); 75 } 76 blend_pixblender_gray_pre77 static AGG_INLINE void blend_pix(value_type* p, 78 value_type cv, value_type alpha) 79 { 80 *p = color_type::prelerp(*p, cv, alpha); 81 } 82 }; 83 84 85 86 //=====================================================apply_gamma_dir_gray 87 template<class ColorT, class GammaLut> class apply_gamma_dir_gray 88 { 89 public: 90 typedef typename ColorT::value_type value_type; 91 apply_gamma_dir_gray(const GammaLut & gamma)92 apply_gamma_dir_gray(const GammaLut& gamma) : m_gamma(gamma) {} 93 operator()94 AGG_INLINE void operator () (value_type* p) 95 { 96 *p = m_gamma.dir(*p); 97 } 98 99 private: 100 const GammaLut& m_gamma; 101 }; 102 103 104 105 //=====================================================apply_gamma_inv_gray 106 template<class ColorT, class GammaLut> class apply_gamma_inv_gray 107 { 108 public: 109 typedef typename ColorT::value_type value_type; 110 apply_gamma_inv_gray(const GammaLut & gamma)111 apply_gamma_inv_gray(const GammaLut& gamma) : m_gamma(gamma) {} 112 operator()113 AGG_INLINE void operator () (value_type* p) 114 { 115 *p = m_gamma.inv(*p); 116 } 117 118 private: 119 const GammaLut& m_gamma; 120 }; 121 122 123 124 //=================================================pixfmt_alpha_blend_gray 125 template<class Blender, class RenBuf, unsigned Step = 1, unsigned Offset = 0> 126 class pixfmt_alpha_blend_gray 127 { 128 public: 129 typedef pixfmt_gray_tag pixfmt_category; 130 typedef RenBuf rbuf_type; 131 typedef typename rbuf_type::row_data row_data; 132 typedef Blender blender_type; 133 typedef typename blender_type::color_type color_type; 134 typedef int order_type; // A fake one 135 typedef typename color_type::value_type value_type; 136 typedef typename color_type::calc_type calc_type; 137 enum 138 { 139 num_components = 1, 140 pix_width = sizeof(value_type) * Step, 141 pix_step = Step, 142 pix_offset = Offset, 143 }; 144 struct pixel_type 145 { 146 value_type c[num_components]; 147 setpixel_type148 void set(value_type v) 149 { 150 c[0] = v; 151 } 152 setpixel_type153 void set(const color_type& color) 154 { 155 set(color.v); 156 } 157 getpixel_type158 void get(value_type& v) const 159 { 160 v = c[0]; 161 } 162 getpixel_type163 color_type get() const 164 { 165 return color_type(c[0]); 166 } 167 nextpixel_type168 pixel_type* next() 169 { 170 return (pixel_type*)(c + pix_step); 171 } 172 nextpixel_type173 const pixel_type* next() const 174 { 175 return (const pixel_type*)(c + pix_step); 176 } 177 advancepixel_type178 pixel_type* advance(int n) 179 { 180 return (pixel_type*)(c + n * pix_step); 181 } 182 advancepixel_type183 const pixel_type* advance(int n) const 184 { 185 return (const pixel_type*)(c + n * pix_step); 186 } 187 }; 188 189 private: 190 //-------------------------------------------------------------------- blend_pix(pixel_type * p,value_type v,value_type a,unsigned cover)191 AGG_INLINE void blend_pix(pixel_type* p, 192 value_type v, value_type a, 193 unsigned cover) 194 { 195 blender_type::blend_pix(p->c, v, a, cover); 196 } 197 198 //-------------------------------------------------------------------- blend_pix(pixel_type * p,value_type v,value_type a)199 AGG_INLINE void blend_pix(pixel_type* p, value_type v, value_type a) 200 { 201 blender_type::blend_pix(p->c, v, a); 202 } 203 204 //-------------------------------------------------------------------- blend_pix(pixel_type * p,const color_type & c,unsigned cover)205 AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover) 206 { 207 blender_type::blend_pix(p->c, c.v, c.a, cover); 208 } 209 210 //-------------------------------------------------------------------- blend_pix(pixel_type * p,const color_type & c)211 AGG_INLINE void blend_pix(pixel_type* p, const color_type& c) 212 { 213 blender_type::blend_pix(p->c, c.v, c.a); 214 } 215 216 //-------------------------------------------------------------------- copy_or_blend_pix(pixel_type * p,const color_type & c,unsigned cover)217 AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover) 218 { 219 if (!c.is_transparent()) 220 { 221 if (c.is_opaque() && cover == cover_mask) 222 { 223 p->set(c); 224 } 225 else 226 { 227 blend_pix(p, c, cover); 228 } 229 } 230 } 231 232 //-------------------------------------------------------------------- copy_or_blend_pix(pixel_type * p,const color_type & c)233 AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c) 234 { 235 if (!c.is_transparent()) 236 { 237 if (c.is_opaque()) 238 { 239 p->set(c); 240 } 241 else 242 { 243 blend_pix(p, c); 244 } 245 } 246 } 247 248 public: 249 //-------------------------------------------------------------------- pixfmt_alpha_blend_gray(rbuf_type & rb)250 explicit pixfmt_alpha_blend_gray(rbuf_type& rb) : 251 m_rbuf(&rb) 252 {} attach(rbuf_type & rb)253 void attach(rbuf_type& rb) { m_rbuf = &rb; } 254 //-------------------------------------------------------------------- 255 256 template<class PixFmt> attach(PixFmt & pixf,int x1,int y1,int x2,int y2)257 bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) 258 { 259 rect_i r(x1, y1, x2, y2); 260 if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) 261 { 262 int stride = pixf.stride(); 263 m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), 264 (r.x2 - r.x1) + 1, 265 (r.y2 - r.y1) + 1, 266 stride); 267 return true; 268 } 269 return false; 270 } 271 272 //-------------------------------------------------------------------- width()273 AGG_INLINE unsigned width() const { return m_rbuf->width(); } height()274 AGG_INLINE unsigned height() const { return m_rbuf->height(); } stride()275 AGG_INLINE int stride() const { return m_rbuf->stride(); } 276 277 //-------------------------------------------------------------------- row_ptr(int y)278 int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } row_ptr(int y)279 const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } row(int y)280 row_data row(int y) const { return m_rbuf->row(y); } 281 282 //-------------------------------------------------------------------- pix_ptr(int x,int y)283 AGG_INLINE int8u* pix_ptr(int x, int y) 284 { 285 return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); 286 } 287 pix_ptr(int x,int y)288 AGG_INLINE const int8u* pix_ptr(int x, int y) const 289 { 290 return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); 291 } 292 293 // Return pointer to pixel value, forcing row to be allocated. pix_value_ptr(int x,int y,unsigned len)294 AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len) 295 { 296 return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step + pix_offset)); 297 } 298 299 // Return pointer to pixel value, or null if row not allocated. pix_value_ptr(int x,int y)300 AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const 301 { 302 int8u* p = m_rbuf->row_ptr(y); 303 return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step + pix_offset)) : 0; 304 } 305 306 // Get pixel pointer from raw buffer pointer. pix_value_ptr(void * p)307 AGG_INLINE static pixel_type* pix_value_ptr(void* p) 308 { 309 return (pixel_type*)((value_type*)p + pix_offset); 310 } 311 312 // Get pixel pointer from raw buffer pointer. pix_value_ptr(const void * p)313 AGG_INLINE static const pixel_type* pix_value_ptr(const void* p) 314 { 315 return (const pixel_type*)((const value_type*)p + pix_offset); 316 } 317 318 //-------------------------------------------------------------------- write_plain_color(void * p,color_type c)319 AGG_INLINE static void write_plain_color(void* p, color_type c) 320 { 321 // Grayscale formats are implicitly premultiplied. 322 c.premultiply(); 323 pix_value_ptr(p)->set(c); 324 } 325 326 //-------------------------------------------------------------------- read_plain_color(const void * p)327 AGG_INLINE static color_type read_plain_color(const void* p) 328 { 329 return pix_value_ptr(p)->get(); 330 } 331 332 //-------------------------------------------------------------------- make_pix(int8u * p,const color_type & c)333 AGG_INLINE static void make_pix(int8u* p, const color_type& c) 334 { 335 ((pixel_type*)p)->set(c); 336 } 337 338 //-------------------------------------------------------------------- pixel(int x,int y)339 AGG_INLINE color_type pixel(int x, int y) const 340 { 341 if (const pixel_type* p = pix_value_ptr(x, y)) 342 { 343 return p->get(); 344 } 345 return color_type::no_color(); 346 } 347 348 //-------------------------------------------------------------------- copy_pixel(int x,int y,const color_type & c)349 AGG_INLINE void copy_pixel(int x, int y, const color_type& c) 350 { 351 pix_value_ptr(x, y, 1)->set(c); 352 } 353 354 //-------------------------------------------------------------------- blend_pixel(int x,int y,const color_type & c,int8u cover)355 AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) 356 { 357 copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover); 358 } 359 360 //-------------------------------------------------------------------- copy_hline(int x,int y,unsigned len,const color_type & c)361 AGG_INLINE void copy_hline(int x, int y, 362 unsigned len, 363 const color_type& c) 364 { 365 pixel_type* p = pix_value_ptr(x, y, len); 366 do 367 { 368 p->set(c); 369 p = p->next(); 370 } 371 while(--len); 372 } 373 374 375 //-------------------------------------------------------------------- copy_vline(int x,int y,unsigned len,const color_type & c)376 AGG_INLINE void copy_vline(int x, int y, 377 unsigned len, 378 const color_type& c) 379 { 380 do 381 { 382 pix_value_ptr(x, y++, 1)->set(c); 383 } 384 while (--len); 385 } 386 387 388 //-------------------------------------------------------------------- blend_hline(int x,int y,unsigned len,const color_type & c,int8u cover)389 void blend_hline(int x, int y, 390 unsigned len, 391 const color_type& c, 392 int8u cover) 393 { 394 if (!c.is_transparent()) 395 { 396 pixel_type* p = pix_value_ptr(x, y, len); 397 398 if (c.is_opaque() && cover == cover_mask) 399 { 400 do 401 { 402 p->set(c); 403 p = p->next(); 404 } 405 while (--len); 406 } 407 else 408 { 409 do 410 { 411 blend_pix(p, c, cover); 412 p = p->next(); 413 } 414 while (--len); 415 } 416 } 417 } 418 419 420 //-------------------------------------------------------------------- blend_vline(int x,int y,unsigned len,const color_type & c,int8u cover)421 void blend_vline(int x, int y, 422 unsigned len, 423 const color_type& c, 424 int8u cover) 425 { 426 if (!c.is_transparent()) 427 { 428 if (c.is_opaque() && cover == cover_mask) 429 { 430 do 431 { 432 pix_value_ptr(x, y++, 1)->set(c); 433 } 434 while (--len); 435 } 436 else 437 { 438 do 439 { 440 blend_pix(pix_value_ptr(x, y++, 1), c, cover); 441 } 442 while (--len); 443 } 444 } 445 } 446 447 448 //-------------------------------------------------------------------- blend_solid_hspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)449 void blend_solid_hspan(int x, int y, 450 unsigned len, 451 const color_type& c, 452 const int8u* covers) 453 { 454 if (!c.is_transparent()) 455 { 456 pixel_type* p = pix_value_ptr(x, y, len); 457 458 do 459 { 460 if (c.is_opaque() && *covers == cover_mask) 461 { 462 p->set(c); 463 } 464 else 465 { 466 blend_pix(p, c, *covers); 467 } 468 p = p->next(); 469 ++covers; 470 } 471 while (--len); 472 } 473 } 474 475 476 //-------------------------------------------------------------------- blend_solid_vspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)477 void blend_solid_vspan(int x, int y, 478 unsigned len, 479 const color_type& c, 480 const int8u* covers) 481 { 482 if (!c.is_transparent()) 483 { 484 do 485 { 486 pixel_type* p = pix_value_ptr(x, y++, 1); 487 488 if (c.is_opaque() && *covers == cover_mask) 489 { 490 p->set(c); 491 } 492 else 493 { 494 blend_pix(p, c, *covers); 495 } 496 ++covers; 497 } 498 while (--len); 499 } 500 } 501 502 503 //-------------------------------------------------------------------- copy_color_hspan(int x,int y,unsigned len,const color_type * colors)504 void copy_color_hspan(int x, int y, 505 unsigned len, 506 const color_type* colors) 507 { 508 pixel_type* p = pix_value_ptr(x, y, len); 509 510 do 511 { 512 p->set(*colors++); 513 p = p->next(); 514 } 515 while (--len); 516 } 517 518 519 //-------------------------------------------------------------------- copy_color_vspan(int x,int y,unsigned len,const color_type * colors)520 void copy_color_vspan(int x, int y, 521 unsigned len, 522 const color_type* colors) 523 { 524 do 525 { 526 pix_value_ptr(x, y++, 1)->set(*colors++); 527 } 528 while (--len); 529 } 530 531 532 //-------------------------------------------------------------------- blend_color_hspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)533 void blend_color_hspan(int x, int y, 534 unsigned len, 535 const color_type* colors, 536 const int8u* covers, 537 int8u cover) 538 { 539 pixel_type* p = pix_value_ptr(x, y, len); 540 541 if (covers) 542 { 543 do 544 { 545 copy_or_blend_pix(p, *colors++, *covers++); 546 p = p->next(); 547 } 548 while (--len); 549 } 550 else 551 { 552 if (cover == cover_mask) 553 { 554 do 555 { 556 copy_or_blend_pix(p, *colors++); 557 p = p->next(); 558 } 559 while (--len); 560 } 561 else 562 { 563 do 564 { 565 copy_or_blend_pix(p, *colors++, cover); 566 p = p->next(); 567 } 568 while (--len); 569 } 570 } 571 } 572 573 574 //-------------------------------------------------------------------- blend_color_vspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)575 void blend_color_vspan(int x, int y, 576 unsigned len, 577 const color_type* colors, 578 const int8u* covers, 579 int8u cover) 580 { 581 if (covers) 582 { 583 do 584 { 585 copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++); 586 } 587 while (--len); 588 } 589 else 590 { 591 if (cover == cover_mask) 592 { 593 do 594 { 595 copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++); 596 } 597 while (--len); 598 } 599 else 600 { 601 do 602 { 603 copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover); 604 } 605 while (--len); 606 } 607 } 608 } 609 610 //-------------------------------------------------------------------- for_each_pixel(Function f)611 template<class Function> void for_each_pixel(Function f) 612 { 613 unsigned y; 614 for (y = 0; y < height(); ++y) 615 { 616 row_data r = m_rbuf->row(y); 617 if (r.ptr) 618 { 619 unsigned len = r.x2 - r.x1 + 1; 620 pixel_type* p = pix_value_ptr(r.x1, y, len); 621 do 622 { 623 f(p->c); 624 p = p->next(); 625 } 626 while (--len); 627 } 628 } 629 } 630 631 //-------------------------------------------------------------------- apply_gamma_dir(const GammaLut & g)632 template<class GammaLut> void apply_gamma_dir(const GammaLut& g) 633 { 634 for_each_pixel(apply_gamma_dir_gray<color_type, GammaLut>(g)); 635 } 636 637 //-------------------------------------------------------------------- apply_gamma_inv(const GammaLut & g)638 template<class GammaLut> void apply_gamma_inv(const GammaLut& g) 639 { 640 for_each_pixel(apply_gamma_inv_gray<color_type, GammaLut>(g)); 641 } 642 643 //-------------------------------------------------------------------- 644 template<class RenBuf2> copy_from(const RenBuf2 & from,int xdst,int ydst,int xsrc,int ysrc,unsigned len)645 void copy_from(const RenBuf2& from, 646 int xdst, int ydst, 647 int xsrc, int ysrc, 648 unsigned len) 649 { 650 if (const int8u* p = from.row_ptr(ysrc)) 651 { 652 memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, 653 p + xsrc * pix_width, 654 len * pix_width); 655 } 656 } 657 658 //-------------------------------------------------------------------- 659 // Blend from single color, using grayscale surface as alpha channel. 660 template<class SrcPixelFormatRenderer> blend_from_color(const SrcPixelFormatRenderer & from,const color_type & color,int xdst,int ydst,int xsrc,int ysrc,unsigned len,int8u cover)661 void blend_from_color(const SrcPixelFormatRenderer& from, 662 const color_type& color, 663 int xdst, int ydst, 664 int xsrc, int ysrc, 665 unsigned len, 666 int8u cover) 667 { 668 typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; 669 typedef typename SrcPixelFormatRenderer::color_type src_color_type; 670 671 if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) 672 { 673 pixel_type* pdst = pix_value_ptr(xdst, ydst, len); 674 675 do 676 { 677 copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0])); 678 psrc = psrc->next(); 679 pdst = pdst->next(); 680 } 681 while (--len); 682 } 683 } 684 685 //-------------------------------------------------------------------- 686 // Blend from color table, using grayscale surface as indexes into table. 687 // Obviously, this only works for integer value types. 688 template<class SrcPixelFormatRenderer> blend_from_lut(const SrcPixelFormatRenderer & from,const color_type * color_lut,int xdst,int ydst,int xsrc,int ysrc,unsigned len,int8u cover)689 void blend_from_lut(const SrcPixelFormatRenderer& from, 690 const color_type* color_lut, 691 int xdst, int ydst, 692 int xsrc, int ysrc, 693 unsigned len, 694 int8u cover) 695 { 696 typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; 697 698 if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) 699 { 700 pixel_type* pdst = pix_value_ptr(xdst, ydst, len); 701 702 do 703 { 704 copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover); 705 psrc = psrc->next(); 706 pdst = pdst->next(); 707 } 708 while (--len); 709 } 710 } 711 712 private: 713 rbuf_type* m_rbuf; 714 }; 715 716 typedef blender_gray<gray8> blender_gray8; 717 typedef blender_gray<sgray8> blender_sgray8; 718 typedef blender_gray<gray16> blender_gray16; 719 typedef blender_gray<gray32> blender_gray32; 720 721 typedef blender_gray_pre<gray8> blender_gray8_pre; 722 typedef blender_gray_pre<sgray8> blender_sgray8_pre; 723 typedef blender_gray_pre<gray16> blender_gray16_pre; 724 typedef blender_gray_pre<gray32> blender_gray32_pre; 725 726 typedef pixfmt_alpha_blend_gray<blender_gray8, rendering_buffer> pixfmt_gray8; 727 typedef pixfmt_alpha_blend_gray<blender_sgray8, rendering_buffer> pixfmt_sgray8; 728 typedef pixfmt_alpha_blend_gray<blender_gray16, rendering_buffer> pixfmt_gray16; 729 typedef pixfmt_alpha_blend_gray<blender_gray32, rendering_buffer> pixfmt_gray32; 730 731 typedef pixfmt_alpha_blend_gray<blender_gray8_pre, rendering_buffer> pixfmt_gray8_pre; 732 typedef pixfmt_alpha_blend_gray<blender_sgray8_pre, rendering_buffer> pixfmt_sgray8_pre; 733 typedef pixfmt_alpha_blend_gray<blender_gray16_pre, rendering_buffer> pixfmt_gray16_pre; 734 typedef pixfmt_alpha_blend_gray<blender_gray32_pre, rendering_buffer> pixfmt_gray32_pre; 735 } 736 737 #endif 738 739