cb200005rh_f.asp.htm
来自「C++builder学习资料C++builder」· HTM 代码 · 共 956 行 · 第 1/3 页
HTM
956 行
<HTML>
<HEAD>
<TITLE>Grayscaled ImageLists</TITLE>
</HEAD>
<BODY>
<TABLE border=0 width="100%" cellpadding=0 cellspacing=0>
<TR valign=top>
<TD width="100%">
<p class=ColumnTitle><font size="2">Sound+Vision</font></p>
<p class=ColumnSubtitle><font size="2">ImageLists
/ Grayscaling / Transparency</font> </p>
<p class=BodyText> </p>
<p class=Byline><font size="2">By Randy
Haben</font></p>
<p class=BodyText> </p>
<p class=StoryTitle><font size="2"><b>Grayscaled
ImageLists</b></font></p>
<p class=StorySubtitle><font size="2">Creating
and Maintaining Transparency</font></p>
<p class=BodyText> </p>
<p class=BodyText> Anybody
who has used Internet Explorer has seen the interesting twist Microsoft
introduced in its toolbar starting with version 3.0. All the button images are
displayed in shades of gray until the user moves the mouse over a button. This
capability is built into the Toolbar component provided in the Common Controls
Library (comctl32.dll). The Toolbar component is wrapped in the VCL as <i
style='mso-bidi-font-style:normal'>TToolbar</i>, and appears on the Win32 page
of C++Builder's Component palette. </p>
<p class=BodyText> </p>
<p class=BodyText> This
article could just as easily be entitled "Grayscaling Transparent Images," as
the bulk of the material deals with how transparency works, and demonstrates a
grayscaling technique that could be used for any transparent image. However,
the origins of the material were driven by the need for an Internet
Explorer-like toolbar. First, we'll examine the concept of masks and
transparency and how they apply to ImageLists. Then we'll explore the topic of
grayscaling. We'll wrap things up by grayscaling an ImageList while preserving
transparency. </p>
<p class=BodyText> </p>
<p class=BodyText> A
variation of the code accompanying this article has been used in a commercial
product for a couple of years. I mention this because the September, 1999 issue
of <i>Windows Developer Journal</i> contains an article named "Generating
Grayed Toolbar Image Lists" by Fran Heeran. Although both of us use color
averaging to obtain grayscale values, Fran's code is, overall, quite different,
because it does all of its work using Windows API functions. </p>
<p class=BodyText> </p>
<p class=BodyText> The
grayscaling technique used in this article takes full advantage of the fact
that the VCL dispenses with a lot of the work that would be required if all we
had was the Windows API. Fran does mention one thing, though, that isn't
addressed in this article. Generating disabled images from a grayscaled
ImageList can lead to button images that aren't recognizable. In practice, this
doesn't seem to pose much of a problem. </p>
<p class=BodyText> </p>
<p class=BodyText> The
source code accompanying this article (available for download; see end of
article for details) includes an application that copies, masks, and grayscales
images. The resulting image can be saved as a bitmap regardless of the format
of the source file. One possible practical use would be to load icons and save
them as bitmaps. The sample application uses a component named <i
style='mso-bidi-font-style:normal'>TGSImageList</i>. When attached to an
existing <i>TImageList</i>, the component
will automatically copy and grayscale all of the images in the existing
ImageList (see Figure 1). </p>
<p class=BodyText> </p>
<p class=Captions><img width=333 height=220
src="images/cb200005rh_f_image002.jpg" tppabs="http://www.cbuilderzine.com/features/2000/05/cb200005rh_f/cb200005rh_f_image002.jpg"> <br>
<b>Figure 1: </b>The sample application. </p>
<p class=BodyText> </p>
<p class=Subheads>ImageLists</p>
<p class=BodyText> <i>TImageList</i> also wraps a common control and
appears on the Win32 page. ImageLists are used to manage large sets of
same-sized icons or bitmaps. The images in an ImageList are actually all on one
bitmap. When an image is added to an ImageList, it's spliced onto the end of
the bitmap. An individual bitmap or icon is retrieved using an index. The index
is used to calculate the rectangular area on the internal bitmap that will be
copied. </p>
<p class=BodyText> </p>
<p class=BodyText> The
images used by the buttons in a toolbar are read from one of three <i
style='mso-bidi-font-style:normal'>TImageList</i> components, depending on the
state of the button: </p>
<ul>
<li><i>DisabledImages</i>. Images to use for disabled
buttons.
<li><i>HotImages</i>. Images to use when a button is
"hot," i.e. when the mouse pointer is hovering over it.
<li><i>Images</i>. Images to use for buttons that
are enabled, but not hot - default ImageList.
</ul>
<p class=BodyText> </p>
<p class=BodyText> The
ImageList referenced by Images is used when the other ImageLists aren't
assigned. </p>
<p class=BodyText> </p>
<p class=Subheads>Transparency</p>
<p class=BodyText> A bitmap
or an icon can be retrieved from an ImageList. Although the internal format of
an ImageList is a bitmap, an icon can be created from any portion of the
bitmap. When a bitmap or icon is added to the list, its transparency is
preserved through the use of a mask (see Figure 2). </p>
<p class=BodyText> </p>
<p class=Captions><img width=330 height=179
src="images/cb200005rh_f_image003.gif" tppabs="http://www.cbuilderzine.com/features/2000/05/cb200005rh_f/cb200005rh_f_image003.gif"> <br>
<b>Figure 2:</b> Masking an image. </p>
<p class=BodyText> </p>
<p class=BodyText> A mask
is a monochrome (typically black and white) bitmap that specifies which pixels
are actually part of the image, and which are part of the background (and
therefore should be transparent). Figure 2 shows a Windows metafile, and the
mask that's generated for it when it's translated into a bitmap. </p>
<p class=BodyText> </p>
<p class=BodyText> Metafiles
and icons support transparency natively. However, they do it quite differently.
A metafile contains instructions for drawing an image, not the image itself. So
when it's drawn, it only paints the pixels necessary to complete its
instructions. Any other area is unaffected, and therefore transparent. The mask
generated for Figure 2 shows all of the pixels "walked on" by the metafile's
drawing instructions. The metafile itself knows nothing of masks. (Note: Metafiles
cannot be added to ImageLists, but they're supported by the Image component and
can be used effectively with the sample application that accompanies this
article.) </p>
<p class=BodyText> </p>
<p class=BodyText> Icons,
on the other hand, contain images and the associated masks. Technically, the
image portion (color bitmap) of an icon is considered the XOR mask, and the
mask portion (monochrome bitmap) is considered the AND mask. For our purposes
we'll simply refer to them as the image and the mask. When an icon is added to
an ImageList, it's first converted into a bitmap using the mask. Then the mask
is added to the ImageList's mask bitmap. Because the ImageList maintains two
bitmaps, the collection of images, and the collection of masks, it actually
works more like an icon than a bitmap. </p>
<p class=BodyText> </p>
<p class=BodyText> Bitmaps
don't natively support transparency. The bitmap data structure doesn't include
a mask, so it has to be generated using the bitmap's <i>TransparentColor</i> property. <i>TransparentColor</i>
can be set to a specific value, or it can be determined automatically. If it's
not specified, it's determined by the first pixel defined in the bitmap's
internal data structure. In the vast majority of cases, bitmaps are drawn
starting at the lower-left corner of the image. So it's generally safe to
assume that the lower-left pixel will be the first pixel in the structure. The
generated mask will contain a black pixel for every pixel whose color isn't the
transparent color. </p>
<p class=BodyText> </p>
<p class=BodyText> If the
bitmap wasn't designed with transparency in mind, then using the first pixel
approach can cause a bitmap to "wash out," because its color may be used
throughout the image. You have two options when adding a bitmap to an ImageList
at run time: <i>Add</i> and <i>AddMasked</i>. The <i>Add</i> method accepts two
parameters: your bitmap image, and a mask you create outside the ImageList. The
<i>AddMasked</i> method allows you to pass
the bitmap and a specific color to use for transparency when the ImageList
generates the mask. </p>
<p class=BodyText> </p>
<p class=BodyText> When a
bitmap is added to an ImageList at design time, <i>AddMasked</i> is used, but the transparent color is always determined
by the first pixel. All the button bitmaps that come with C++Builder and Delphi
are specifically designed to be transparent. They use either purple or olive
backgrounds depending on whether those colors are used in the image. If you
create your own button images, be sure to flood the background with an
appropriate color (any color is fine as long as it isn't used in the image).
Also, be certain that the lower-left pixel is the same color. Figure 3 shows
the bitmap used for the Load button in the sample application. </p>
<p class=BodyText> </p>
<p class=Captions><img width=308 height=296
src="images/cb200005rh_f_image004.gif" tppabs="http://www.cbuilderzine.com/features/2000/05/cb200005rh_f/cb200005rh_f_image004.gif"> <br>
<b>Figure 3:</b> Flooding a bitmap with a
transparent color. </p>
<p class=BodyText> </p>
<p class=BodyText> When
creating bitmaps using Microsoft Paint, or snagging them using screen capture
programs, chances are that the bitmaps will be saved using the color depth
specified for the current screen resolution, which is 16- or 24-bit for most of
us. This can result in bitmaps that take up far more memory/file space than
necessary. Most button bitmaps can be drawn using 256 colors or less. You can
load your bitmap into Paint, and use Save As
to convert the bitmap to a different resolution. </p>
<p class=BodyText> </p>
<p class=Subheads>Grayscaling</p>
<p class=BodyText> There
are a number of ways to grayscale a bitmap. One of the fastest involves
manipulating the color palette referenced by the bitmap. However, the faster
methods generally don't take transparency into account and grayscale the entire
image, including the area that should remain transparent. Our approach will be
to use a mask to apply grayscale values on a pixel-by-pixel basis. We'll obtain
our grayscale values using color averaging. </p>
<p class=BodyText> </p>
<p class=BodyText> The
logic is broken into several routines, some of which are useful on their own.
We'll start with the <i>GrayScale</i>
function (see Figure 4), and introduce the others as they're used. </p>
<p class=BodyText> </p>
<p class=Code><span class=Code><b>void</b>
GrayScale(TGraphic *Source, </span></p>
<p class=Code><span class=Code> Graphics::TBitmap *Dest, Shortint
Brightness) </span></p>
<p class=Code><span class=Code>{</span></p>
<p class=Code><span class=Code> Graphics::TBitmap * SourceAsBitmap =</span></p>
<p class=Code><span class=Code> <b> dynamic_cast</b><Graphics::TBitmap
*>(Source); </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> <b> if</b>
(Source && (SourceAsBitmap || Dest)) </span></p>
<p class=Code><span class=Code> { </span></p>
<p class=Code><span class=Code> Graphics::TBitmap * bmp , * mask; </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> bmp = <b>new</b>
Graphics::TBitmap; </span></p>
<p class=Code><span class=Code> mask = <b>new</b> Graphics::TBitmap; </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> <b> try</b></span></p>
<p class=Code><span class=Code> { </span></p>
<p class=Code><span class=Code> CopyGraphicToBitmap(Source, bmp); </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> mask->Assign(bmp); </span></p>
<p class=Code><span class=Code> mask->Mask(bmp->TransparentColor); </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> <b> for</b>
(<b>int</b> y = 0; y <
bmp->Canvas->ClipRect.Bottom; y++)</span></p>
<p class=Code><span class=Code> { </span></p>
<p class=Code><span class=Code> <b> for</b>
(<b>int</b> x = 0; x <
bmp->Canvas->ClipRect.Right; x++)</span></p>
<p class=Code><span class=Code> { </span></p>
<p class=Code><span class=Code> <b> if</b>
(mask->Canvas->Pixels[x][y] == clBlack) </span></p>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?