Boost logo

Boost :

From: Martijn W. van der Lee (gmane_at_[hidden])
Date: 2002-05-14 13:35:56


> > This means that if you look at the mixed anti-alias in monochrome, the
> mixed
> > anti-aliassed yellow would be brighter than the two colors it is
composed
> of
> > and, IMHO looks totally unrealistic.
>
> Hmm, interesting. I've just tested it and the result looks at least
> appropriate.
> Here it the entire text of the scanline rendering function:
>
> void render_bgr24_solid::render(scanline* sl)
> {
> if(!sl->reset_iterator(rbuf()->get_clip_box())) return;
>
> unsigned char* start = rbuf()->get_row(sl->get_y());
> register unsigned num_spans = sl->get_num_spans();
>
> while(num_spans--)
> {
> if(sl->next_span())
> {
> register const unsigned char* covers = sl->get_covers();
> register unsigned count = sl->get_count();
> register unsigned char* pix_ptr = start + sl->get_x() * 3;
>
> while(count--)
> {
> register int alpha = (*covers++) * m_a;
> register int b = pix_ptr[0];
> register int g = pix_ptr[1];
> register int r = pix_ptr[2];
> *pix_ptr++ = (((m_b - b) * alpha) + (b << 16)) >> 16;
> *pix_ptr++ = (((m_g - g) * alpha) + (g << 16)) >> 16;
> *pix_ptr++ = (((m_r - r) * alpha) + (r << 16)) >> 16;
> }
> }
> }
> }
>
> As you can see there's nothing interesting in the mixing formula, but
> Here're the results:
> http://www.antigrain.com/img/color_mix1.gif (non-transparent)
> http://www.antigrain.com/img/color_mix2.gif (half-transparent on black)
> http://www.antigrain.com/img/color_mix3.gif (half-transparent on white)
>
> At least there're no visible artifacts in anti-aliased edges.
> Maybe 50% transparent red on white shouldn't look so pink :-)

Seems like you're only handling alpha of the top-layer. With only one
transparent layer (considering the bottom layer is always 100% opaque), your
code works perfectly but you'll need to write alpha info to the bottom layer
as well. Here's a small example of my approximation coded in the
FilterMeister FF+ language, which is very closely related to C and should be
very simple to translate.

------------------------------------------------------------
%ffp

ForEveryTile:
{
 // Background
 for(x = 0; x < X; ++x)
  for(y = 0; y < Y; ++y)
  {
   pset(x, y, 0, 127);
   pset(x, y, 1, 0);
   pset(x, y, 2, 255);
   pset(x, y, 3, 255);
  }

 // Layer X
 for(x = 0; x < X; ++x)
  for(y = 0; y < Y; ++y)
  {
   const int a_top = scl(x, 0, X, 0, 255);
   const int r = 255;
   const int g = 127;
   const int b = 0;

   const int a_btm = pget(x, y, 3);
   const int a_new = a_btm + ((255 - a_btm) * a_top / 255);
   pset(x, y, 0, mix(r, pget(x, y, 0), a_top, a_new));
   pset(x, y, 1, mix(g, pget(x, y, 1), a_top, a_new));
   pset(x, y, 2, mix(b, pget(x, y, 2), a_top, a_new));
   pset(x, y, 3, a_new);
  }

 // Layer Y
 for(x = 0; x < X; ++x)
  for(y = 0; y < Y; ++y)
  {
   const int a_top = scl(y, 0, Y, 0, 255);
   const int r = 0;
   const int g = 127;
   const int b = 255;

   const int a_btm = pget(x, y, 3);
   const int a_new = a_btm + ((255 - a_btm) * a_top / 255);
   pset(x, y, 0, mix(r, pget(x, y, 0), a_top, a_new));
   pset(x, y, 1, mix(g, pget(x, y, 1), a_top, a_new));
   pset(x, y, 2, mix(b, pget(x, y, 2), a_top, a_new));
   pset(x, y, 3, a_new);
  }

 return true;
}
-------------------------------------------------------
pget(x,y,z) reads a byte from the z channel.
pset(x,y,z,byte) writes a byte to the z channel.
scl(byte, a1, b1, a2, b2) scales byte from range a1-b1 to range a2-b2. In
this case; (byte * b2) / b1.
mix(a, b, c, d) ((c * a) + ((d - c) * b)) / d

In my test it proved to be nearly identical to PhotoShop with at most 1/255
error.

regards,
Martijn van der Lee


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk