cb200005rh_f.asp.htm

来自「C++builder学习资料C++builder」· HTM 代码 · 共 956 行 · 第 1/3 页

HTM
956
字号
(mask-&gt;Canvas-&gt;Pixels[x][y] == clBlack) </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;bmp-&gt;Canvas-&gt;Pixels[x][y] =</span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ShadeOfGray(bmp-&gt;Canvas-&gt;Pixels[x][y], Brightness); </span></p>   

   

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

   

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

   

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

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> The <i   

style='mso-bidi-font-style:normal'>ShadeOfGray</i> function is named for each   

pixel that is masked. This is the real workhorse of the <i>GrayScale</i> function (see Figure 7). </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=Code><span class=Code>TColor   

ShadeOfGray(TColor Color, Shortint Brightness) </span></p>   

   

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

   

<p class=Code><span class=Code>&nbsp;&nbsp;Byte r = RED(Color), </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g = GREEN(Color), </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b = BLUE(Color); </span></p>   

   

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

   

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

avg = ((r + g + b) / 3) + Brightness; </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;Byte gray = (Byte) LIMIT(avg, 0, 255); </span></p>   

   

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

   

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

(TColor) RGB(gray, gray, gray); </span></p>   

   

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

   

<p class=Captions><b>Figure   

7: </b>The <i>ShadeOfGray</i>   

function. </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> To   

understand the <i>ShadeOfGray</i> function,   

it's necessary to understand the macros that support it. Given a composite   

color value, the RED, GREEN, and BLUE macros determine the intensity of each of   

the corresponding constituent colors. <i>TColor</i>   

is defined as an enumerated data type, which is, of course, compatible with an   

integer. In reality, though, the 32-bit value is mapped into four separate   

bytes (see Figure 8). </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=Captions><img width=330 height=213   

 src="images/cb200005rh_f_image005.gif" tppabs="http://www.cbuilderzine.com/features/2000/05/cb200005rh_f/cb200005rh_f_image005.gif"> <br>   

<b>Figure 8:</b> Byte layout of a color value   

(values are hexadecimal). </p>   

   

<p class=BodyText> &nbsp; </p>   

   

   

   

<p class=BodyText> For   

example, the value 0x000000FF is pure Red, 0x0000FF00 is pure Green, and   

0x00FF0000 is pure Blue. When all three colors are at the same intensity, the   

result is a shade of gray. Using this definition, black is the darkest shade of   

gray (0x00000000) and white is the brightest (0x00FFFFFF). </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> The   

value of any color intensity can be obtained by isolating its byte position.   

For Red this means simply <b>and</b>ing the value with 0xFF, the highest value   

a byte can hold. This has the effect of trimming off the byte positions to the   

left leaving only the Red value. For Green, we need to shift the color value to   

the right by 8 bits (1 byte) and, again, with 0xFF to zero out the other bytes.   

The same process applies to Blue, except that we shift to the right by 16 bits   

(2 bytes): </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=Code><span class=Code><span Class=CodeGrn>#define   

RED(value)&nbsp;&nbsp; (Byte) (value &amp; 0xFF) </span></span></p>   

   

<p class=Code><span class=Code><span Class=CodeGrn>#define   

GREEN(value) (Byte) ((value &gt;&gt; 8) &amp; 0xFF) </span></span></p>   

   

<p class=Code><span class=Code><span Class=CodeGrn>#define   

BLUE(value) (Byte) ((value &gt;&gt; 16) &amp; 0xFF) </span></span></p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> In the <i   

style='mso-bidi-font-style:normal'>ShadeOfGray</i> function, we use these   

macros to get the intensities for each of the Red, Green, and Blue values. Then   

we average them and add the <i>Brightness</i> value. Many images tend to be   

darker when grayscaled. Adding or subtracting a value to the average of the   

colors will lighten or darken the resulting shade of gray. Adding or   

subtracting to the average can also cause the value to go below zero, or above   

255 (the maximum value of a byte). The LIMIT macro resolves this issue: </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=Code><span class=Code><span Class=CodeGrn>#define   

LIMIT(value, low, high) ((value &lt; low) ? low : ((value &gt; high) ? high :   

value)) </span></span></p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> Casting   

a signed ordinal value (<i>int</i>) to an unsigned value (<i>Byte</i>) can   

result in the value "wrapping." For example, the integer value -10 becomes the <i>Byte</i>   

value 245, and the integer value 300 becomes the <i>Byte</i> value 45. This is   

undesirable in the case where we are attempting to lighten or darken our   

grayscale value. We want negative values to come out as zero, and positive   

values greater than 255 to be 255. </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> The RGB   

macro from the Windows API is used to create a composite color from individual   

red, green, and blue values. Once the gray value has been determined, the RGB   

macro is called passing the same value - the grayscale value - for each color. </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> Once all   

of the masked pixels have been processed, we're ready for the last step. </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> <b>Copy   

the local bitmap to the destination bitmap, if supplied, or back into the   

source.</b> Here's the   

source code for this step: </p>   

   

<p class=BodyText> &nbsp; </p>   

   

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

(Dest) </span></p>   

   

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

   

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

style='mso-bidi-font-weight:normal'>if</b> (SourceAsBitmap) </span></p>   

   

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

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> Now that   

the local bitmap has been placed, the grayscale process is complete. It's time   

to apply this process to ImageLists. </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=Subheads>The   

Grayscaled ImageList Component</p>   

   

<p class=BodyText> The <i   

style='mso-bidi-font-style:normal'>TGSImageList</i> component included with   

this article is derived from <i>TCustomImageList</i>. Therefore, it has all of   

the capabilities of an ImageList, but many of the properties are protected.   

This allows us to surface only the properties we want. We don't want the   

component user to change the images. We've added one key property: <i>ImageList</i>.   

When the <i>ImageList</i> property is assigned to point to a normal ImageList,   

the normal images are automatically copied and grayscaled. </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> The   

dynamic nature of <i>GSImageList</i> is important, because images are often   

added at run time. Using the <i>SHGetFileInfo</i> function, "system" ImageLists   

containing file icons can be accessed. (Further discussion of system ImageLists   

is beyond the scope of this article.) Assigning the <i>ImageList</i> property   

causes the <i>Refresh</i> method to be called (see Figure 9). </p>   

   

<p class=BodyText> &nbsp; </p>   

   

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

style='mso-bidi-font-weight:normal'>__fastcall</b> TGSImageList::Refresh(<b   

style='mso-bidi-font-weight:normal'>void</b>)</span></p>   

   

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

   

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

   

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

   

<p class=Code><span class=Code>&nbsp;&nbsp;Clear();</span></p>   

   

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

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

   

<p class=Code><span class=Code>&nbsp;&nbsp;bmp-&gt;Height = ImageList-&gt;Height; </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;bmp-&gt;Width = ImageList-&gt;Width; </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;bmp-&gt;TransparentColor = clPurple; </span></p>   

   

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

   

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

   

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

(<b>int</b> i = 0; i &lt; ImageList-&gt;Count;   

i++)</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;bmp-&gt;Canvas-&gt;Brush-&gt;Color =   

bmp-&gt;TransparentColor; </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bmp-&gt;Canvas-&gt;FillRect(bmp-&gt;Canvas-&gt;ClipRect); </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ImageList-&gt;GetBitmap(i, bmp); </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GrayScale(bmp, NULL, 20); </span></p>   

   

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AddMasked(bmp,   

bmp-&gt;TransparentColor); </span></p>   

   

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

   

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

   

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

   

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

   

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

bmp; </span></p>   

   

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

   

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

   

<p class=Captions><b>Figure   

9:</b> The <i>Refresh</i>   

method of <i>TGSImageList</i>.</p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> The <i>Refresh</i>   

method can be separated into three steps: </p>   

   

<p class=BodyText> 1) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   

Empty   

the current bitmap list. </p>   

   

<p class=BodyText> 2) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   

Create   

a bitmap that is the size specified by the <i>Height</i> and <i>Width</i>   

properties. All images in an ImageList are exactly the same size. This bitmap   

will be re-used for each bitmap in the assigned (full-color) ImageList. The   

default color for transparency will be purple (applies to images other than   

bitmaps, such as icons). </p>   

   

<p class=BodyText> 3) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   

For   

each image in the full-color ImageList, <i>GrayScale</i>   

it and add it the internal list using the <i>AddMasked</i>   

method. The temporary bitmap is filled with the default <i>TransparentColor</i>, so an icon or metafile will retain its   

transparency when converted to a bitmap. </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> You may   

install this component and use it any way you please. When you install it, make   

sure all three <i>GSImageLists</i> source files (.cpp, .h and .dcr) are in the   

same directory. The .dcr file contains a bitmap resource that will be   

associated with the GSImageList component on the Component palette. </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=Subheads>Conclusion</p>   

   

<p class=BodyText> Just a   

few touches can often have a big impact on how a user perceives a given piece   

of software. Microsoft has mastered the art of making a product seem fresh by   

changing its visual aspects. The grayscaled ImageList isn't a major   

enhancement, and doesn't even add appreciable functionality. But using such   

subtle visual enhancements implies an attention to detail that can help assure   

- or convince - your users that you're on top of the latest technologies. </p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> Updates   

to this article and the accompanying source code can be found in the Reusable   

Objects library at <span Class=CodeBlue><a   

href="http://reusable.com/Library">http://reusable.com/Library</a></span>.<span Class=CodeBlue></span></p>   

   

<p class=BodyText> &nbsp; </p>   

   

<p class=BodyText> <i>The   

files accompanying this article are available for <a href="download/cb200005rh_f.zip" tppabs="http://www.cbuilderzine.com/features/2000/05/cb200005rh_f/cb200005rh_d.asp">download</a>. </i></p>  

  

<p class=BodyText> &nbsp; </p>  

  

</td>  

</TR>  

</TABLE>  

  

  

</BODY>  

</HTML>  

⌨️ 快捷键说明

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