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> &nbsp; </p> 

 

<p class=Byline><font size="2">By Randy   

Haben</font></p>   

   

<p class=BodyText> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </p>   

   

<p class=BodyText> The   

ImageList referenced by Images is used when the other ImageLists aren't   

assigned. </p>   

   

<p class=BodyText> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </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> &nbsp; </p>   

   

<p class=Code><span class=Code><b>void</b>   

GrayScale(TGraphic *Source, </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;Graphics::TBitmap *Dest, Shortint   

Brightness) </span></p>   

   

<p class=Code><span class=Code>{</span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;Graphics::TBitmap * SourceAsBitmap =</span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;<b> dynamic_cast</b>&lt;Graphics::TBitmap   

*&gt;(Source); </span></p>   

   

<p class=Code><span class=Code>&nbsp; </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;<b> if</b>   

(Source &amp;&amp; (SourceAsBitmap || Dest)) </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;{ </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;Graphics::TBitmap * bmp , * mask; </span></p>   

   

<p class=Code><span class=Code>&nbsp; </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;bmp = <b>new</b>   

Graphics::TBitmap; </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;mask = <b>new</b> Graphics::TBitmap; </span></p>   

   

<p class=Code><span class=Code>&nbsp; </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;<b> try</b></span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;{ </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CopyGraphicToBitmap(Source, bmp); </span></p>   

   

<p class=Code><span class=Code>&nbsp; </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mask-&gt;Assign(bmp); </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mask-&gt;Mask(bmp-&gt;TransparentColor); </span></p>   

   

<p class=Code><span class=Code>&nbsp; </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b> for</b>   

(<b>int</b> y = 0; y &lt;   

bmp-&gt;Canvas-&gt;ClipRect.Bottom; y++)</span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b> for</b>   

(<b>int</b> x = 0; x &lt;   

bmp-&gt;Canvas-&gt;ClipRect.Right; x++)</span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b> if</b>   

(mask-&gt;Canvas-&gt;Pixels[x][y] == clBlack) </span></p>   

   

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?