[racket-dev] Bug report and complaint: Bitmap drawing and masks

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Thu Dec 16 23:21:26 EST 2010

Thanks for the bug reports! I've pushed some fixes to the repo -- more
details and answers below.

At Tue, 14 Dec 2010 20:46:27 -0800, John Boyle wrote:
> Problem: The dc% method 'draw-bitmap-section disregards the boundaries of
> the drawing section when the 'color argument is the color black.

You're right that the color should not have mattered. For a non-black
color, `draw-bitmap-section' was taking an unnecessary slow path; the
slow path turned out to be more correct than the faster path. I've
fixed both the unnecessary indirection and the fast path.

> Next, I complain about some other weird behavior of bitmaps (this behavior
> has, I think, existed for a long time).  In the following example (code at
> the bottom of this email), I load a black-and-white bitmap (which seems to
> load as color), then create two bitmaps inside bitmap-dc%s (one monochrome
> and the other color), draw the original black-and-white bitmap to each of
> these bitmap-dc%s, and extract the bitmaps from the bitmap-dc%s.  Now I have
> three black-and-white bitmaps that all look identical: the originally loaded
> one, the monochrome copy, and the color copy.
> Now I try to use them as masks to draw the "valkyrie" bitmaps.  What
> happens?  The first one works, the second and third don't.  Why is this?  I
> investigated and found that, while the pixels of the copies are identical to
> those of the original (at least, the color copy is identical to the
> original), the "alpha" channel is different: the alpha bytes are all 0 on
> the original, but they're all 255 on both of the copies.
> Questions/complaints:
> 1. Why does the alpha channel of a bitmap matter when it's being used as a
> mask?

It turns out that if a bitmap has an alpha channel, then when the
bitmap is used as a mask, only its alpha channel is used for masking.
That wasn't documented (and it took me a while to remember); I've fixed
the docs.

While this rule may seem somewhat arbitrary, it works well with the
underlying Cairo API. The idea is that if you want to construct a
grayscale mask separate from content to draw, it's really better to
think in terms of constructing a suitable alpha channel.

> 2. Why doesn't drawing a bitmap to another one of the same size produce an
> exact copy of the first? 

In the case of `u' versus `cu', you're starting with a bitmap that has
no alpha channel and drawing into a bitmap that does have an alpha
channel. If you add a #f to the call to `make-bitmap' to disable the
alpha channel, then you do get the same bitmap for `cu'.

> (Or, if, say, the second one is monochrome while
> the first is color, why doesn't it produce the monochrome equivalent of the
> first?  And vice versa.)

The result of drawing with `mu' as a mask was broken. The problem was
in `draw-bitmap' with a monochrome target bitmap. A monochome bitmap
actually has an alpha channel internally, where drawing with black sets
the alpha channel to 255 and drawing with white sets it to 255. The
`draw-bitmap' operation wasn't preserving that correspondence, and it's
now fixed.

There was also a bug related to using a color bitmaps as a mask,
drawing on it, and then using the bitmap as a mask again. That's also
now fixed.

Posted on the dev mailing list.