The Alpha Channel
One of our testers inserted a Microsoft logo image into RichEdit and saw an inky black rectangle. Ignoring any connotation that this might be a bad omen (!), I proceeded to study image formats in Wikipedia and in MSDN. (Not that I hadn't already scoured such documentation). Pretty soon I started to suspect that the image, which is a png (portable network graphics), might have an alpha channel. Such a channel isn't something from outer space; it's a channel that lets you blend an image with the background or make portions of the image transparent. When a pixel's alpha-channel value is transparent (0), the pixel's color is typically black. If so and the pixel's alpha-channel value is ignored, the pixel renders as black, because the pixel is not treated as transparent.
More generally, nonzero alpha-channel values blend the image pixel colors with the background pixels. The alpha-channel value α gives the degree to which the image pixel is opaque. For byte values, α /255 of the pixel's red, green, and blue are combined with 1 - α /255 of the background pixel's red, green, and blue, respectively. So α = 0 implies that the image pixel color isn't used; only the background pixel is seen. Unless you ignore the alpha-channel value.
Not all image formats can have an alpha channel. For example, jpeg images can contain EXIF metadata that gives information about the image, such as time and place where the picture was taken, the kind of camera used, and the exposure settings. But jpegs cannot have an alpha channel. Meanwhile png images can have an alpha channel, but cannot have EXIF metadata. Png's can have other kinds of metadata.
In testing various png’s, we found that a number of them displayed as a completely black rectangles. The png specification shows how to know if an alpha channel is present. Specifically, a png begins with the 8 bytes 89 50 4E 47 0D 0A 1A 0A followed by the IHDR chunk. Note that hex 50 4E 47 are the ASCII values of PNG. The IHDR chunk has the content
Chunk count (13) |
4 bytes |
Type (IHDR) |
4 bytes |
Width |
4 bytes |
Height |
4 bytes |
Bit depth |
1 byte |
Color type |
1 byte |
Compression method |
1 byte |
Filter method |
1 byte |
Interlace method |
1 byte |
CRC |
4 bytes |
If bit 2 of the color type is nonzero, the image has an alpha channel.
The Microsoft logo png shown later in this post starts with the bytes (each consecutive pair of hexadigits gives a byte) 89504E470D0A1A0A 0000000D 49484452 000000FA 0000002D 08 06. These bytes have the meanings
png header |
Chunk length |
IHDR |
Width |
Height |
Bit depth |
Color type |
89504E470D0A1A0A |
0000000D |
49484452 |
000000FA |
0000002D |
08 |
06 |
Bit 2 of the color type 06 is 1, so there is an alpha channel. In fact, 06 means “Truecolour with alpha”.
Using GDI, it’s easy to display the image with its built-in (alpha-channel) transparency. The AlphaBlend() function has a BLENDFUNCTION argument that lets you say an image has an alpha channel. Check the image’s pixel format (call IWICBitmapFrameDecode::GetPixelFormat()) and note whether the GUID returned corresponds to a bitmap with an alpha channel. If so, use a BLENDFUNCTION saying the image has an alpha channel.
Here’s a picture of the png logo on a yellow background and another on a red background. The red and yellow backgrounds are displayed because the png is transparent in those areas.
Direct 2D (D2D) doesn’t support all bitmap formats, so in converting from a WIC bitmap to a D2D bitmap you need to choose carefully. For example, the premultiplied bitmap format GUID_WICPixelFormat32bppPBGRA is supported by D2D, but I wasn’t able to get the straight GUID_WICPixelFormat32bppBGRA format to work correctly. With D2D that format always displays as a black rectangle. Maybe someone noted that the premultiplied alpha-channel bitmap is more efficient and therefore chose not to support the straight alpha-channel bitmap. In contrast, GDI handles all formats that I tried.
Mystery of the black rectangles solved!