Quantcast
Channel: VBForums - CodeBank - Visual Basic 6 and earlier
Viewing all articles
Browse latest Browse all 1529

GDI+ Workaround: ICONs

$
0
0
Major caveat: The noted limitations apply to at least Vista and lower. Windows 7 and above may have corrected some of these limitations. Since Vista is still an active operating system, you may be interested. Also, the term "icon" used below is interchangeable with "cursor" and vice versa.

First a little background about icons within Windows. The icon structure is fairly straightforward and well documented, so won't spend any serious time on that. What people may not be aware of is how icons/cursors are rendered. Icons are drawn as a result of the combination of the icon color data (considered the XOR bits) and the icon mask (AND bits). With the exception of 32 bit icons, discussed in a bit, there are only 3 scenarios for each icon pixel rendered:

1. Icon pixel is transparent. The icon pixel must be black, the mask pixel must be white (value of 1 in a 1 bit mask)
2. Icon pixel is opaque. The mask pixel must be black (value of 0 in a 1 bit mask)
3. Icon pixel is inverted relative to its pixel color and the destination pixel color. Mask pixel must be white & icon pixel must not be black.

The formula is quite simple: ([destination pixel color] And [mask color value]) Xor [icon color value]
So looking at the 3 scenarios above, the icon pixel rendered in each scenario can be calculated. Just using one color channel for simplicity in the example.

D = destination color. M = mask color. S = icon source color

1. Transparent: M=255, S=0, D=any color. (D And M) Xor S = D
2. Opaque: M=0, S=any color, D=any color. (D And M) Xor S = S
3. Inverted. Icon color cannot be black else icon pixel becomes transparent when mask pixel is white
a) white icon color produces pure inverted color: M=255, S=255, D=222. (D And M) Xor S = 33
b) non-black/white produces relative inversion: M=255, S=111, D=222. (D And M) Xor S = 177

Inverted pixel colors are typically used for 1 bit cursors only. This allows a cursor to invert its color over any background to prevent it from visually disappearing over a background of same color as the cursor. Technically, this is not restricted to 1 bit icons/cursors. However, a 32 bit icon using the alpha channel will never invert pixels because the icon mask (which dictates inversion) is ignored when the alpha channel is used.

So, where does GDI+ break? With icons, nearly everywhere. Here are specific limitations with GDI+

- GDI+ won't load cursors from handle nor file/stream
- All icons. Ignores any inverted pixels and they are treated as transparent. GDI+ has no XOR ability.
- PNG embedded icon. Cannot load it as an icon file/stream
- 1 bit icon: Cannot load it by handle, but can load it by file/stream
- 16,24 bit icon: Cannot load it by file/stream, but can load it by handle
- 32 bit icon. Well, Windows uses the mask only in this case: every icon alpha channel value is zero. Otherwise, the mask will be ignored. GDI+ will not properly render a 32 bit icon when the mask should be ignored. GDI+ never ignores the mask but ignores the alpha channel. Go figure.

Workarounds. Everything except the XOR limitation can be worked around relatively easily; but lots more code.

- 32 bit icons with alpha channel usage. Whether by handle or by file, doesn't matter. Transfer the icon color pixel data + alpha channel to a GDI+ hImage created with GdipCreateBitmapFromScan0 and pixel format declared as ARGB. Use GdipBitmapLockBits to transfer. Rest of comments below exclude 32 bit icons

- Cursors and 1 bit icons loaded by handle. Use GetIconInfo & GetDIBits APIs to convert 1 bit to 32 bit. Use existing mask. Then use CreateIconFromResourceEx to create hIcon, not cursor. Destroy original icon/cursor. Assuming 32 bit icons are processed separately, then since no alpha channel is used here, we can use any bit depth other than 1. Internally, GDI+ converts icons to 32 bit bitmaps.

- 16,24 bit icons loaded from file/stream. You can load these via LoadImage API and then let GDI+ load via handle. Destroy icon.

- PNG encoded icon/cursor loaded from file. PNG-icons loaded by handle are hIcon. If from icon file, the entire PNG-file format starts at the icon offset within the icon file format. Load those PNG bytes at that offset, no other icon header info.

In the next couple of replies, I'll address some workarounds, specifically, regarding loading by handle or stream/file.

See also:
GDI+ Workaround: JPG > Zero-Length App Markers
GDI+ Workaround: TIFF > JPEG-compressed images
GDI+ Workaround: BMP > Alpha Channels + JPG/PNG Encoded
GDI+ Workaround: PNG > adding/removing metadata


A really simple example project is added that can highlight whether or not your system's version of GDI+ is loading icons correctly.
Attached Files

Viewing all articles
Browse latest Browse all 1529

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>