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 pix_width = sizeof(value_type) * Step, 140 pix_step = Step, 141 pix_offset = Offset, 142 }; 143 struct pixel_type 144 { 145 value_type c[pix_step]; 146 setpixel_type147 void set(value_type v) 148 { 149 c[0] = v; 150 } 151 setpixel_type152 void set(const color_type& color) 153 { 154 set(color.v); 155 } 156 getpixel_type157 void get(value_type& v) const 158 { 159 v = c[0]; 160 } 161 getpixel_type162 color_type get() const 163 { 164 return color_type(c[0]); 165 } 166 nextpixel_type167 pixel_type* next() 168 { 169 return this + 1; 170 } 171 nextpixel_type172 const pixel_type* next() const 173 { 174 return this + 1; 175 } 176 advancepixel_type177 pixel_type* advance(int n) 178 { 179 return this + n; 180 } 181 advancepixel_type182 const pixel_type* advance(int n) const 183 { 184 return this + n; 185 } 186 }; 187 188 private: 189 //-------------------------------------------------------------------- blend_pix(pixel_type * p,value_type v,value_type a,unsigned cover)190 AGG_INLINE void blend_pix(pixel_type* p, 191 value_type v, value_type a, 192 unsigned cover) 193 { 194 blender_type::blend_pix(p->c, v, a, cover); 195 } 196 197 //-------------------------------------------------------------------- blend_pix(pixel_type * p,value_type v,value_type a)198 AGG_INLINE void blend_pix(pixel_type* p, value_type v, value_type a) 199 { 200 blender_type::blend_pix(p->c, v, a); 201 } 202 203 //-------------------------------------------------------------------- blend_pix(pixel_type * p,const color_type & c,unsigned cover)204 AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover) 205 { 206 blender_type::blend_pix(p->c, c.v, c.a, cover); 207 } 208 209 //-------------------------------------------------------------------- blend_pix(pixel_type * p,const color_type & c)210 AGG_INLINE void blend_pix(pixel_type* p, const color_type& c) 211 { 212 blender_type::blend_pix(p->c, c.v, c.a); 213 } 214 215 //-------------------------------------------------------------------- copy_or_blend_pix(pixel_type * p,const color_type & c,unsigned cover)216 AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover) 217 { 218 if (!c.is_transparent()) 219 { 220 if (c.is_opaque() && cover == cover_mask) 221 { 222 p->set(c); 223 } 224 else 225 { 226 blend_pix(p, c, cover); 227 } 228 } 229 } 230 231 //-------------------------------------------------------------------- copy_or_blend_pix(pixel_type * p,const color_type & c)232 AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c) 233 { 234 if (!c.is_transparent()) 235 { 236 if (c.is_opaque()) 237 { 238 p->set(c); 239 } 240 else 241 { 242 blend_pix(p, c); 243 } 244 } 245 } 246 247 public: 248 //-------------------------------------------------------------------- pixfmt_alpha_blend_gray(rbuf_type & rb)249 explicit pixfmt_alpha_blend_gray(rbuf_type& rb) : 250 m_rbuf(&rb) 251 {} attach(rbuf_type & rb)252 void attach(rbuf_type& rb) { m_rbuf = &rb; } 253 //-------------------------------------------------------------------- 254 255 template<class PixFmt> attach(PixFmt & pixf,int x1,int y1,int x2,int y2)256 bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) 257 { 258 rect_i r(x1, y1, x2, y2); 259 if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) 260 { 261 int stride = pixf.stride(); 262 m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), 263 (r.x2 - r.x1) + 1, 264 (r.y2 - r.y1) + 1, 265 stride); 266 return true; 267 } 268 return false; 269 } 270 271 //-------------------------------------------------------------------- width()272 AGG_INLINE unsigned width() const { return m_rbuf->width(); } height()273 AGG_INLINE unsigned height() const { return m_rbuf->height(); } stride()274 AGG_INLINE int stride() const { return m_rbuf->stride(); } 275 276 //-------------------------------------------------------------------- row_ptr(int y)277 int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } row_ptr(int y)278 const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } row(int y)279 row_data row(int y) const { return m_rbuf->row(y); } 280 281 //-------------------------------------------------------------------- pix_ptr(int x,int y)282 AGG_INLINE int8u* pix_ptr(int x, int y) 283 { 284 return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); 285 } 286 pix_ptr(int x,int y)287 AGG_INLINE const int8u* pix_ptr(int x, int y) const 288 { 289 return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); 290 } 291 292 // Return pointer to pixel value, forcing row to be allocated. pix_value_ptr(int x,int y,unsigned len)293 AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len) 294 { 295 return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step + pix_offset)); 296 } 297 298 // Return pointer to pixel value, or null if row not allocated. pix_value_ptr(int x,int y)299 AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const 300 { 301 int8u* p = m_rbuf->row_ptr(y); 302 return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step + pix_offset)) : 0; 303 } 304 305 // Get pixel pointer from raw buffer pointer. pix_value_ptr(void * p)306 AGG_INLINE static pixel_type* pix_value_ptr(void* p) 307 { 308 return (pixel_type*)((value_type*)p + pix_offset); 309 } 310 311 // Get pixel pointer from raw buffer pointer. pix_value_ptr(const void * p)312 AGG_INLINE static const pixel_type* pix_value_ptr(const void* p) 313 { 314 return (const pixel_type*)((const value_type*)p + pix_offset); 315 } 316 317 //-------------------------------------------------------------------- write_plain_color(void * p,color_type c)318 AGG_INLINE static void write_plain_color(void* p, color_type c) 319 { 320 // Grayscale formats are implicitly premultiplied. 321 c.premultiply(); 322 pix_value_ptr(p)->set(c); 323 } 324 325 //-------------------------------------------------------------------- read_plain_color(const void * p)326 AGG_INLINE static color_type read_plain_color(const void* p) 327 { 328 return pix_value_ptr(p)->get(); 329 } 330 331 //-------------------------------------------------------------------- make_pix(int8u * p,const color_type & c)332 AGG_INLINE static void make_pix(int8u* p, const color_type& c) 333 { 334 ((pixel_type*)p)->set(c); 335 } 336 337 //-------------------------------------------------------------------- pixel(int x,int y)338 AGG_INLINE color_type pixel(int x, int y) const 339 { 340 if (const pixel_type* p = pix_value_ptr(x, y)) 341 { 342 return p->get(); 343 } 344 return color_type::no_color(); 345 } 346 347 //-------------------------------------------------------------------- copy_pixel(int x,int y,const color_type & c)348 AGG_INLINE void copy_pixel(int x, int y, const color_type& c) 349 { 350 pix_value_ptr(x, y, 1)->set(c); 351 } 352 353 //-------------------------------------------------------------------- blend_pixel(int x,int y,const color_type & c,int8u cover)354 AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) 355 { 356 copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover); 357 } 358 359 //-------------------------------------------------------------------- copy_hline(int x,int y,unsigned len,const color_type & c)360 AGG_INLINE void copy_hline(int x, int y, 361 unsigned len, 362 const color_type& c) 363 { 364 pixel_type* p = pix_value_ptr(x, y, len); 365 do 366 { 367 p->set(c); 368 p = p->next(); 369 } 370 while(--len); 371 } 372 373 374 //-------------------------------------------------------------------- copy_vline(int x,int y,unsigned len,const color_type & c)375 AGG_INLINE void copy_vline(int x, int y, 376 unsigned len, 377 const color_type& c) 378 { 379 do 380 { 381 pix_value_ptr(x, y++, 1)->set(c); 382 } 383 while (--len); 384 } 385 386 387 //-------------------------------------------------------------------- blend_hline(int x,int y,unsigned len,const color_type & c,int8u cover)388 void blend_hline(int x, int y, 389 unsigned len, 390 const color_type& c, 391 int8u cover) 392 { 393 if (!c.is_transparent()) 394 { 395 pixel_type* p = pix_value_ptr(x, y, len); 396 397 if (c.is_opaque() && cover == cover_mask) 398 { 399 do 400 { 401 p->set(c); 402 p = p->next(); 403 } 404 while (--len); 405 } 406 else 407 { 408 do 409 { 410 blend_pix(p, c, cover); 411 p = p->next(); 412 } 413 while (--len); 414 } 415 } 416 } 417 418 419 //-------------------------------------------------------------------- blend_vline(int x,int y,unsigned len,const color_type & c,int8u cover)420 void blend_vline(int x, int y, 421 unsigned len, 422 const color_type& c, 423 int8u cover) 424 { 425 if (!c.is_transparent()) 426 { 427 if (c.is_opaque() && cover == cover_mask) 428 { 429 do 430 { 431 pix_value_ptr(x, y++, 1)->set(c); 432 } 433 while (--len); 434 } 435 else 436 { 437 do 438 { 439 blend_pix(pix_value_ptr(x, y++, 1), c, cover); 440 } 441 while (--len); 442 } 443 } 444 } 445 446 447 //-------------------------------------------------------------------- blend_solid_hspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)448 void blend_solid_hspan(int x, int y, 449 unsigned len, 450 const color_type& c, 451 const int8u* covers) 452 { 453 if (!c.is_transparent()) 454 { 455 pixel_type* p = pix_value_ptr(x, y, len); 456 457 do 458 { 459 if (c.is_opaque() && *covers == cover_mask) 460 { 461 p->set(c); 462 } 463 else 464 { 465 blend_pix(p, c, *covers); 466 } 467 p = p->next(); 468 ++covers; 469 } 470 while (--len); 471 } 472 } 473 474 475 //-------------------------------------------------------------------- blend_solid_vspan(int x,int y,unsigned len,const color_type & c,const int8u * covers)476 void blend_solid_vspan(int x, int y, 477 unsigned len, 478 const color_type& c, 479 const int8u* covers) 480 { 481 if (!c.is_transparent()) 482 { 483 do 484 { 485 pixel_type* p = pix_value_ptr(x, y++, 1); 486 487 if (c.is_opaque() && *covers == cover_mask) 488 { 489 p->set(c); 490 } 491 else 492 { 493 blend_pix(p, c, *covers); 494 } 495 ++covers; 496 } 497 while (--len); 498 } 499 } 500 501 502 //-------------------------------------------------------------------- copy_color_hspan(int x,int y,unsigned len,const color_type * colors)503 void copy_color_hspan(int x, int y, 504 unsigned len, 505 const color_type* colors) 506 { 507 pixel_type* p = pix_value_ptr(x, y, len); 508 509 do 510 { 511 p->set(*colors++); 512 p = p->next(); 513 } 514 while (--len); 515 } 516 517 518 //-------------------------------------------------------------------- copy_color_vspan(int x,int y,unsigned len,const color_type * colors)519 void copy_color_vspan(int x, int y, 520 unsigned len, 521 const color_type* colors) 522 { 523 do 524 { 525 pix_value_ptr(x, y++, 1)->set(*colors++); 526 } 527 while (--len); 528 } 529 530 531 //-------------------------------------------------------------------- blend_color_hspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)532 void blend_color_hspan(int x, int y, 533 unsigned len, 534 const color_type* colors, 535 const int8u* covers, 536 int8u cover) 537 { 538 pixel_type* p = pix_value_ptr(x, y, len); 539 540 if (covers) 541 { 542 do 543 { 544 copy_or_blend_pix(p, *colors++, *covers++); 545 p = p->next(); 546 } 547 while (--len); 548 } 549 else 550 { 551 if (cover == cover_mask) 552 { 553 do 554 { 555 copy_or_blend_pix(p, *colors++); 556 p = p->next(); 557 } 558 while (--len); 559 } 560 else 561 { 562 do 563 { 564 copy_or_blend_pix(p, *colors++, cover); 565 p = p->next(); 566 } 567 while (--len); 568 } 569 } 570 } 571 572 573 //-------------------------------------------------------------------- blend_color_vspan(int x,int y,unsigned len,const color_type * colors,const int8u * covers,int8u cover)574 void blend_color_vspan(int x, int y, 575 unsigned len, 576 const color_type* colors, 577 const int8u* covers, 578 int8u cover) 579 { 580 if (covers) 581 { 582 do 583 { 584 copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++); 585 } 586 while (--len); 587 } 588 else 589 { 590 if (cover == cover_mask) 591 { 592 do 593 { 594 copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++); 595 } 596 while (--len); 597 } 598 else 599 { 600 do 601 { 602 copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover); 603 } 604 while (--len); 605 } 606 } 607 } 608 609 //-------------------------------------------------------------------- for_each_pixel(Function f)610 template<class Function> void for_each_pixel(Function f) 611 { 612 unsigned y; 613 for (y = 0; y < height(); ++y) 614 { 615 row_data r = m_rbuf->row(y); 616 if (r.ptr) 617 { 618 unsigned len = r.x2 - r.x1 + 1; 619 pixel_type* p = pix_value_ptr(r.x1, y, len); 620 do 621 { 622 f(p->c); 623 p = p->next(); 624 } 625 while (--len); 626 } 627 } 628 } 629 630 //-------------------------------------------------------------------- apply_gamma_dir(const GammaLut & g)631 template<class GammaLut> void apply_gamma_dir(const GammaLut& g) 632 { 633 for_each_pixel(apply_gamma_dir_gray<color_type, GammaLut>(g)); 634 } 635 636 //-------------------------------------------------------------------- apply_gamma_inv(const GammaLut & g)637 template<class GammaLut> void apply_gamma_inv(const GammaLut& g) 638 { 639 for_each_pixel(apply_gamma_inv_gray<color_type, GammaLut>(g)); 640 } 641 642 //-------------------------------------------------------------------- 643 template<class RenBuf2> copy_from(const RenBuf2 & from,int xdst,int ydst,int xsrc,int ysrc,unsigned len)644 void copy_from(const RenBuf2& from, 645 int xdst, int ydst, 646 int xsrc, int ysrc, 647 unsigned len) 648 { 649 if (const int8u* p = from.row_ptr(ysrc)) 650 { 651 memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, 652 p + xsrc * pix_width, 653 len * pix_width); 654 } 655 } 656 657 //-------------------------------------------------------------------- 658 // Blend from single color, using grayscale surface as alpha channel. 659 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)660 void blend_from_color(const SrcPixelFormatRenderer& from, 661 const color_type& color, 662 int xdst, int ydst, 663 int xsrc, int ysrc, 664 unsigned len, 665 int8u cover) 666 { 667 typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; 668 typedef typename SrcPixelFormatRenderer::color_type src_color_type; 669 670 if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) 671 { 672 pixel_type* pdst = pix_value_ptr(xdst, ydst, len); 673 674 do 675 { 676 copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0])); 677 psrc = psrc->next(); 678 pdst = pdst->next(); 679 } 680 while (--len); 681 } 682 } 683 684 //-------------------------------------------------------------------- 685 // Blend from color table, using grayscale surface as indexes into table. 686 // Obviously, this only works for integer value types. 687 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)688 void blend_from_lut(const SrcPixelFormatRenderer& from, 689 const color_type* color_lut, 690 int xdst, int ydst, 691 int xsrc, int ysrc, 692 unsigned len, 693 int8u cover) 694 { 695 typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; 696 697 if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) 698 { 699 pixel_type* pdst = pix_value_ptr(xdst, ydst, len); 700 701 do 702 { 703 copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover); 704 psrc = psrc->next(); 705 pdst = pdst->next(); 706 } 707 while (--len); 708 } 709 } 710 711 private: 712 rbuf_type* m_rbuf; 713 }; 714 715 typedef blender_gray<gray8> blender_gray8; 716 typedef blender_gray<sgray8> blender_sgray8; 717 typedef blender_gray<gray16> blender_gray16; 718 typedef blender_gray<gray32> blender_gray32; 719 720 typedef blender_gray_pre<gray8> blender_gray8_pre; 721 typedef blender_gray_pre<sgray8> blender_sgray8_pre; 722 typedef blender_gray_pre<gray16> blender_gray16_pre; 723 typedef blender_gray_pre<gray32> blender_gray32_pre; 724 725 typedef pixfmt_alpha_blend_gray<blender_gray8, rendering_buffer> pixfmt_gray8; 726 typedef pixfmt_alpha_blend_gray<blender_sgray8, rendering_buffer> pixfmt_sgray8; 727 typedef pixfmt_alpha_blend_gray<blender_gray16, rendering_buffer> pixfmt_gray16; 728 typedef pixfmt_alpha_blend_gray<blender_gray32, rendering_buffer> pixfmt_gray32; 729 730 typedef pixfmt_alpha_blend_gray<blender_gray8_pre, rendering_buffer> pixfmt_gray8_pre; 731 typedef pixfmt_alpha_blend_gray<blender_sgray8_pre, rendering_buffer> pixfmt_sgray8_pre; 732 typedef pixfmt_alpha_blend_gray<blender_gray16_pre, rendering_buffer> pixfmt_gray16_pre; 733 typedef pixfmt_alpha_blend_gray<blender_gray32_pre, rendering_buffer> pixfmt_gray32_pre; 734 } 735 736 #endif 737 738