ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: button

[其他资源] [转载]Win32 API讲座

[复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2005-2-11 00:35 | 显示全部楼层
本帖已被收录到知识树中,索引项:Windows API应用

三、与设备有关的位图(DDB)

与设备有关的位图,相对与与设备无关位图来讲,比较简单。只所以简单是因为我们根本没有必要去学习它的结构。因为,与设备有关的位图的格式总是与其设备场景(顺便说一下,很多书把设备场景叫做“设备上下文”)有关。但2色位图除外。如果你正坐在计算机前,不要认为计算机中只存在一种与设备有关的位图,其实不然。所谓设备并不是指一台计算机,内存,显示缓存,打印机,等都有各自的位图数据格式。不要对与设备有关的位图进行对其结构的任何猜测。你见过我吗?没有吧?但你是否觉得与我交往仍然是很有效呢?我们可以通过Email,因特网进行交流。你就把我理解为一个人,一个远方的朋友就可以了,是不是?对与设备有关的位图也就这样想就可以了。它的确是存在着的,就在计算机的某个设备内部(比如内存,打印机)。当然我们不能通过Email跟它交往,而是要靠函数,范围包括创建,获取信息,设置信息,销毁等等。用惯了你会发现,这也很得劲儿,其难度也就相当与给我发一个E-Mail── 填写需要的地址,需要的标题和内容,然后发送。当然,这里要做的是为一个函数的调用为其添写需要的参数。如果你真的想见它一面,我倒有个方法,是家传秘方呦!好好听,你可以拿锤子把你的计算机用力,请记住一定要用力,用力砸一下,然后打开机箱看看它出来了没有,一般成功率能达到99%。但由于存在那1%的失败的可能,我得先声明如果见不到后果自负∶)

使用与设备无关位图的过程当中始终不能忘记的一点是,确保位图与设备的兼容性。你不能把一个内存设备场景中的位图直接选入到打印机设备场景,会出现异常或错误。这里所说的设备其实就是指设备场景。为了创建一个与指定设备场景兼容的设备相关位图,可以使用CreateBitmap或者CreateCompatibleBitmap。但两个函数的功能是不同的。我的经验是,在创建一个Mask(掩模位图)图象的时候使用CreateBitmap,而创建一个彩色位图的时候使用CreateCompatibleBitmap。还有几个函数,如CreateDIBitmap,它可以根据一个DIB(设备无关位图)的基础上创建一个与设备相关位图。反正,你应该注意到,几乎所有的与设备相关位图有关的API函数都具有一个hDC参数,有时候看起来没有必要的,但应当清楚这主要是为了保证设备的兼容性而给出的。说明与设备有关位图的有些信息是记录在设备场景中的。

作为GDI对象,设备相关位图被创建后,需要把它选入到设备场景,这和向设备场景选入一个画笔完全一样,可以用SelectObject函数,只是在先前要写画笔句柄的参数位置上写下位图句柄即可。当你不再使用一个被你创建的位图的时候,应当用DeleteObject函数删除之,以释放系统资源。为了删除它,你还需要用SelectObject函数把原来的位图选回到设备场景,这样你为设备场景选入过的位图就退了回来,处于可以删除或重新被选入的状态。这需要你在为设备场景选入一个你自己创建的位图时保存旧的(原先的)位图句柄。反正这和操纵画笔或画刷之类的GDI对象完全一样。同样,不可将一个位图同时选入两个不同的设备场景。

创建和使用位图的常用技巧是,创建一个DC或多个DC以及相应的位图,然后在后台(用户看不到)进行各种光栅运算和加工处理后,最后把形成的图象一次性发送到关联设备场景中(关联设备场景中的图象会自动影射到视频内存,如PictureBox和hDC所代表的内存。详细情况请参考前期教程设备场景部分)中(常用BitBlt),以获取速度和最大限度地避免屏幕闪烁(后面给出了例子)。这主要是因为向屏幕输出图象的函数执行速度比较慢,而且图象的加工过程对用户来说没有必要看到的。为了创建若干个设备场景,你需要多次用CreateCompatibleDc函数(这也是最简单的方法),它可以使你获得一个与指定设备场景兼容的设备场景。反正你应该保证创建位图中所使用的hDC参数和创建设备场景中所使用的hDC参数保持一致。别忘了最后用DeleteDC来删除你自己创建的设备场景。在删除设备场景前,应当从该设备场景中抽出为其选入的位图,并将其销毁。以上这种技巧在一本VC书上叫做“双缓冲”,意识是把操作分成前台和后台两部分同时进行。

接下来给出与设备有关位图的函数吧,请您不要客气随便看。

与设备有关位图函数

函 数 说 明 CreateBitmap 创建一幅位图,并选择性地初始化位图数据 CreateBitmapIndirect 在一个BITMAP数据结构的基础上创建一幅位图 CreateCompatibleBitmap 创建与指定设备场景兼容的一幅位图 GetBitmapBits 获取位图的像素位数据 GetBitmapDimensionEx 取得一幅位图的大小 LoadBitmap 从资源文件中载入一幅固有的系统位图 LoadImage 一个常规用途的函数,用于装载图象、图标及指针 SetBitmapBits 根据一个数据缓冲区设置位图图象。使用GetDIBits吧,更好用。 SetBitmapDimensionEx 设置位图的大小。

位图传输函数

函 数 说 明 BitBlt 位块传输。将一个图象区域传到另一个图象区域。必须掌握到熟背。 PatBlt 图案块传输。根据指定图案(就象由一个刷子表示的那样)填充一个图象区域。 GetStretchBltMode 进行伸缩处理时,用于判断Windows删除线段或像素方式。 MaskBlt 执行复杂的图象传输,同时进行掩模(MASK)处理 PlgBlt 平行四边形块传输。允许我们伸缩、扭曲及放置一幅图象。这个函数我在Windows95中用过,可始终没有成功。功能看起来很不错。 SetStretchBltMode 进行伸缩处理时,用于决定Windows删除线段或像素的方式。 StretchBlt 将一幅位图从一个设备场景复制到另一个。源和目标DC相互间必须兼容。这个函数会在设备场景中定义一个目标矩形,并在位图中定义一个源图象。源矩形会根据需要进行伸缩,以便与目标矩形的大小相符。 DIB并不存在于设备场景中(device context)。在它被选入设备场景或在它被画入设备场景前,DIB必须被翻译为DDB。你可以用StretchDIBits函数完成这一工作。本教程提供了一个源代码例程。通过它你能够学习DDB到DIB,再从DIB到DDB的转化过程。程序名为vbplay46.vbp。实际上是源码解析中的演示程序第46号。

为了使用好位块传输,你需要掌握图形光栅方面的知识。其内容和上一期给出的位操作运算在其原理上相同。只是需要进行的并不是一个、两个或四个直接等的数据,而是一个位图数据。位图数据也是以字节来构成的,只是长度要长得多。为了使用光栅运算,你需要有一个自己的表格,以便从中查找并计划光栅方案。以下是Dan的书中的,也是我最喜欢的一个表(详细的中文说明格式的表不如它好用)∶

SRCCOPY Destination = Source

SRCPAINT Destination = Source OR Destination

SRCAND Destination = Source AND Destination

SRCINVERT Destination = Source XOR Destination

SRCERASE Destination = Source AND (NOT Destination)

NOTSRCCOPY Destination = NOT Source

NOTSRCERASE Destination = (NOT Source) AND (NOT Destination)

MERGECOPY Destination = Source AND Pattern

MERGEPAINT Destination = (NOT Source) OR Destination

PATCOPY Destination = Pattern

PATPAINT Destination = (NOT Source) OR Pattern OR Destination

PATINVERT Destination = Pattern XOR Destination

DSTINVERT Destination = NOT Destination

BLACKNESS Destination = 0

WHITENESS Destination = All bits set to 1

可惜,少一个很重要的。可别担心,本老师有办法∶

&H220326 Destination=(NOT Source) AND Detination

注∶以上,Destination指的是目标位图(BitBlt中前一个DC中的),Source是来源位图(BitBlt中的后一个DC中的)。

以下给出一个例子,是我常用的一个函数。它用来实现透明复制位图。你可以在你的程序中直接粘贴使用。它总结了本节给出的内容。

作者(xing) 1999年10月17日 整理备用

功能∶

透明复制位图

参数表∶

hDestDC -------- Long,目标设备场景

x,y ------------ Long,对目标DC中目标矩形左上角位置进行描述的那个点。用目标DC的逻辑坐标表示

nWidth,nHeight - Long,欲传输图象的宽度和高度

hSrcDC --------- Long,源设备场景。如光栅运算未指定源,则应设为0

xSrc,ySrc ------ Long,对源DC中源矩形左上角位置进行描述的那个点。用源DC的逻辑坐标表示

TransColor ----- OLE_COLOR,被透明处理的颜色

Sub TransBlt(ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal TransColor As OLE_COLOR)

Dim dl As Long

Dim OrigColor As Long

Dim OrigMode As Long

Dim saveDC As Long

Dim maskDC As Long

Dim invDC As Long

Dim resultDC As Long

Dim hSaveBmp As Long

Dim hMaskBmp As Long

Dim hInvBmp As Long

Dim hResultBmp As Long

Dim hSavePrevBmp As Long

Dim hMaskPrevBmp As Long

Dim hInvPrevBmp As Long

Dim hDestPrevBmp As Long

saveDC = CreateCompatibleDC(hDestDC)

maskDC = CreateCompatibleDC(hDestDC)

invDC = CreateCompatibleDC(hDestDC)

resultDC = CreateCompatibleDC(hDestDC)

'按照规定的格式创建一幅与设备有关位图

hMaskBmp = CreateBitmap(nWidth, nHeight, 1, 1, ByVal 0&)

hInvBmp = CreateBitmap(nWidth, nHeight, 1, 1, ByVal 0&)

'创建一幅与设备有关位图

hResultBmp = CreateCompatibleBitmap(hDestDC, nWidth, nHeight)

hSaveBmp = CreateCompatibleBitmap(hDestDC, nWidth, nHeight)

hSavePrevBmp = SelectObject(saveDC, hSaveBmp)

hMaskPrevBmp = SelectObject(maskDC, hMaskBmp)

hInvPrevBmp = SelectObject(invDC, hInvBmp)

hDestPrevBmp = SelectObject(resultDC, hResultBmp)

'产生Mask图象

OrigColor = SetBkColor(hSrcDC, TransColor)

dl& = BitBlt(maskDC, 0, 0, nWidth, nHeight, hSrcDC, xSrc, ySrc, vbSrcCopy)

TransColor = SetBkColor(hSrcDC, OrigColor)

'invDC的图象将与maskDC图象相反

dl& = BitBlt(invDC, 0, 0, nWidth, nHeight, maskDC, 0, 0, vbNotSrcCopy)

'resultDC的图象将成为被写位置的图象

dl& = BitBlt(resultDC, 0, 0, nWidth, nHeight, hDestDC, x, y, vbSrcCopy)

'resultDC中,需要新写的位置将变为黑色

dl& = BitBlt(resultDC, 0, 0, nWidth, nHeight, maskDC, 0, 0, vbSrcAnd)

dl& = BitBlt(saveDC, 0, 0, nWidth, nHeight, hSrcDC, xSrc, ySrc, vbSrcCopy)

'resultDC中不被写入的颜色成为黑色

dl& = BitBlt(saveDC, 0, 0, nWidth, nHeight, invDC, 0, 0, vbSrcAnd)

'将两幅图合并起来

dl& = BitBlt(resultDC, 0, 0, nWidth, nHeight, saveDC, 0, 0, vbSrcInvert)

'完工后输出

dl& = BitBlt(hDestDC, x, y, nWidth, nHeight, resultDC, 0, 0, vbSrcCopy)

SelectObject saveDC, hSavePrevBmp

SelectObject resultDC, hDestPrevBmp

SelectObject maskDC, hMaskPrevBmp

SelectObject invDC, hInvPrevBmp

DeleteObject hSaveBmp

DeleteObject hMaskBmp

DeleteObject hInvBmp

DeleteObject hResultBmp

DeleteDC saveDC

DeleteDC maskDC

DeleteDC invDC

DeleteDC resultDC

End Sub

TA的精华主题

TA的得分主题

 楼主| 发表于 2005-2-11 00:35 | 显示全部楼层

函数需要的API

Private Declare Function BitBlt& Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long)

Private Declare Function CreateCompatibleBitmap& Lib "gdi32" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long)

Private Declare Function CreateCompatibleDC& Lib "gdi32" (ByVal hdc As Long)

Private Declare Function DeleteObject& Lib "gdi32" (ByVal hObject As Long)

Private Declare Function SelectObject& Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long)

Private Declare Function SetBkColor& Lib "gdi32" (ByVal hdc As Long, ByVal crColor As Long)

Private Declare Function CreateBitmap& Lib "gdi32" ( ByVal nWidth As Long, ByVal nHeight As Long, ByVal nPlanes As Long, ByVal nBitCount As Long, lpBits As Any)

四、关于ImageIo.dll

在前一段时间,有很多朋友来信问我如何把BMP图象或图片框中的图象保存为JPG或GIF格式文件。我还没有回答过一次。因为我始终没有找到称心的DLL(动态连接库)。最近3个月,我一直学了VC,也算是勉强入门。我发现VC界的很多人都在使用一个叫ImageLoad.dll的动态连接库来完成这些工作。可惜,这个动态连接库到VB就不好使了。因为其函数使用了指针(而不是句柄)。然而,可但是,只要本老师在,你就可以用这个动态连接库了。本老师写了一个叫ImageIo.dll的动态连接库,用VC编写的。此连接库完全面对VB编写的,自然参数上完全考虑了VB用户。该连接库可以把你在VB中传送的句柄适当地改成指针并再调用ImageLoad.dll这个动态连接库,然后把处理结果以VB能够接受的方式返回给VB用户。另外一点是,ImageLoad.dll的函数比较低级的,用起来也不方面。为此,我在ImageIo.dll中写了一些代码,使得使用起来更加方便,更加可靠。

然而,也出现了一个接着一个的让我伤心的事情。第一个是,函数不能读取部分GIF格式的文件(有些可以读出,但不是动画,只有一张静态画面);另一个是无法存成GIF格式,最后一点就古怪了,当像素位不等于24的时候位图文件不能存成JPG格式。该连接库可以操纵6中格式文件,有BMP,GIF,JPG,PCX,TGA,TIF。我对TGA和TIF没有怎么考虑过,因为在GIF中出现一些问题后感到这个ImageIo.dll不能使其功能齐全了,而且TGA和TIF也并不是常用文件,也就不大测试了。那么,是因为我还不懂VC吗?不,并不是我写错了代码,而是该动态连接库提供的演示程序同样不能解决我遇到的问题。据图象处理方面的书上说,一个JPG库代码,需要一个人用半年的时间才能写完。我总不能花半年去写一个这种库文件吧。其实我手里有一个,而我却懒得去用它。

我考虑了,你能拿ImageIo.dll能做什么?想编写一个图象处理软件?如果你这样想的话,那么我建议你不要用它,如果你真的想编一个图象处理软件,最好还是自己从头编写一个完整的DLL文件。我想,算是出了著名的图象处理软件的公司都是如此。而且我建议你不要用VB来编写这种软件,不适合。我想,对绝大部分VB届的朋友来讲,对JPG的需求无疑是将一些图象文件压缩起来,以节约磁盘空间。比如,你需要编写一个人事档案管理系统,把人员照片扫描后保存成JGP文件。那么我想,你用这个ImageIo.dll文件,算是很不错的。我曾经在网络上下载过一个DLL文件,但其压缩质量实在差,而ImageLoad.dll却做得很出色。

你在本教程的打包文件中可以找到一个Test.vbp文件,正是对这个ImageIo.dll写的。有关ImageIo.dll的技术文档,现给出如下,欢迎提一些宝贵意见∶

ImageIo.dll

本动态连接库是为了解决VB用户不能使用ImageLoad.dll动态连接库文件而编写的。它可以作为一个桥梁,使VB用户能够使用ImageLoad.dll。但它并不是对ImageLoad.dll的简单转化,而是添加了诸多代码,使其用起来更加简单、方便。它可以帮助用户完成 Bmp,Gif,Jpg 等多种图象文件的数据的读取和存盘工作。

制作者∶Xing

编程环境∶VC6.0

日期∶1999,12,20

常量∶

1∶文件格式

Const IMAGETYPE_NONE = 0 '未知格式

Const IMAGETYPE_BMP = 1 'bmp 文件格式

Const IMAGETYPE_GIF = 2 'gif 文件格式

Const IMAGETYPE_PCX = 3 'pcx 文件格式

Const IMAGETYPE_TGA = 4 'tga 文件格式

Const IMAGETYPE_JPG = 5 'jpg 文件格式

Const IMAGETYPE_TIF = 6 'tif 文件格式

Const IMAGETYPE_FIRSTTYPE = IMAGETYPE_BMP '第一个文件格式 (bmp) = 1

Const IMAGETYPE_LASTTYPE = IMAGETYPE_TIF '最后一个文件格式 (tif) = 6

函数∶

GetImageType

VB∶

Private Declare Function GetImageType Lib "ImageIo.dll" (lpsFilename As String) As Long

VC∶

__API int GetImageType(LPTSTR & pszFilename);

说 明∶

获取图形文件类型

返回值∶

文件类型 0--6,0 表示出错或未知文件类型

参数∶

lpsFilename String 文件名

ImageLoad

VB∶

Declare Function ImageLoad Lib "ImageIo.dll" (lpsFilename As String, ByVal hDC As Long, ByVal nX As Long, ByVal nY As Long) As Long

VC∶

_API HGLOBAL ImageLoad( LPTSTR & pszFilename,HDC hDC, int nX, int nY);

说明∶

装载一个图象文件,并必要时输出到指定的DC

返回∶

返回指向装有图象文件数据的一个缓冲区的指针。不管你打开任何文件,装载到缓冲区的数据都已经是转换为DIB格式,也就是说和BMP文件一样。在不在使用该缓冲区的时候,应该用API函数GlobalFree或者本动态连接库提供的KillImage函数释放掉。

参数∶

KillImage:

VB∶

Declare Function KillImage Lib "ImageIo.dll" (ByVal hDib As Long) As Long

VC∶

__API HGLOBAL KillImage(HGLOBAL hDib);

说明∶

本函数与API函数GlobalFree在其功能上完全一样,当然可以改用GlobalFree 。VC代码如下∶

HGLOBAL CImageIoApp::KillImage(HGLOBAL hDib)

{ return(GlobalFree(hDib)); } 注∶如果成功返回0,否则返回hDib。

ImageDraw: VB∶ Declare Function ImageDraw Lib "ImageIo.dll" (ByVal hDib As Long, ByVal hDC As Long, ByVal nX As Long, ByVal nY As Long) As Long VC∶ __API BOOL ImageDraw(HGLOBAL hDib,HDC hDC, int nX, int nY ); 说明∶ 将图象输出到指定DC。 返回值∶ 成功返回1,否则返回0。 参数∶ hDib 一个指向缓冲区的指针。该缓冲区中装有DIB位图数据。可以用LoadImage函数获取它。也可以自己创建。

hDC 需要绘制图象的设备常场景句柄 nX,nY 设备场景中被绘制图象的左上角的坐标。

GetInf VB: Declare Function GetInfo Lib "ImageIo.dll" (ByVal hDib As Long, BIH As BITMAPINFOHEADER) As Long VC: __API BOOL GetInfo(HGLOBAL hDib,BITMAPINFOHEADER & BIH); 说明∶ 本来是想用GetImageInfo作为函数名,但VC中用此名发生一些冲突,改用了GetInfo。此函数用于获取DIB文件中的BITMAPINFOHEADER结构信息。 返回值∶ 成功返回1,失败返回0。

参数∶ hDib 一个指向缓冲区的指针。该缓冲区中装有DIB位图数据。 BIH 一个准备装载信息的BITMAPINFOHEADER结构。传递前没有必要设置其biSize(结构长度)成员变量。

__API BOOL ImageSave(LPTSTR & pszFilename,HGLOBAL hDib,int nType,int nQuality);

只适用于BMP,JPG,TGA

五、图表与指针

图表是一幅小位图,图表文件的常用附加名是ICO。它的一项特殊能力就是不仅允许任何像素使用某种位图颜色,也允许它们使用屏幕或反转的屏幕颜色。Windows3.x中的图表通常是32×32像素大小,但在Windows95(98)和NT4.0中,对16×16和64×64像素图标的支持已非常普遍了。图标实际包含两幅独立位图。第一幅位图可能是单色的或彩色的,其中包含了要与显示屏幕图象合并到一起的一幅图象。这种合并是通过异或(XOR)操作实现的。我们将其称为XOR位图,其中包含了一个掩模。在显示屏幕图象与XOR位图合并到一起之前,这个掩模会先与屏幕图象进行AND操作,然后才是XOR位图和屏幕进行XOR。

鼠标指针在其内部结构上和图表完全一致,只是它多出一个斎鹊銛,即该指针位图中代表指针位置的准确坐标点。该文件的附加名一般是CUR。能对图标进行操作的大部分函数也能对(鼠标)指针。

图标被装入到内存之后将产生一个句柄。但需要注意的是,图表并不属于GDI对象,而是属于USER对象。所以有可能在应用程序间共享图表资源。

以下给出了有关图标和指针的API函数

函 数 说 明 CopyCursor 复制指针,使用CopyIcon CopyIcon 复制图表。 CreateCursor 创建指针 CreateIcon 创建图表 CreateIconIndirect 在一个ICONINFO结构的基础上创建一个图标 DestroyCursor 清除指针 DestroyIcon 清除图表 DrawIcon 向指定设备场景绘制图标 DrawIconEx 用附加的选项描绘图标 ExtractIcon 从一个可执行文件或DLL中载入图标 ExtractAssociatedIcon 载入指定文件内部或与它相关的一个图标 GetIconInfo 取得关于图标的信息 LoadCursor 从一个资源文件中载入指针,或者装载一个固有系统指针。 LoadCursorFromFile 通过读取标准指针文件(.cur)或动画指针(.ani)创建指针 LoadIcon 从一个资源文件中载入图表,或载入一个固有系统图标。

六、颜色区间

RGB 我们已经知道IBM兼容视频系统上的颜色由RGB三色体现。RGB三色中的每一种颜色都包含颜色中的红色、绿色和蓝色成分的值。这三部分的值组合在一起确定屏幕上所显示的颜色。RGB是常见颜色空间,红色、绿色和蓝色被认为是基本色,不能够被进一步的分解。而色彩系统可以分为两类,加法色彩系统和减法色彩系统。加法色彩系统,例如RGB系统中的颜色可通过将颜色添加到黑色中创建新颜色。添加的颜色越多,结果颜色也就越趋向于白色。足够的主要颜色可以创建出纯白色,而缺少所有主要颜色只能得出纯黑色。

一个RGB是用四个字节来构成的。好象该字节中除了表示红、绿、蓝三个字节以外的剩余一个字节是多余的,其实不然。从一个API绘图函数引用一种颜色,都不只是用容纳红、绿、蓝颜色值的三个字节,而且还用第四个字节(最高字节)。这个字节包含一个标志值。顺序排列的最低字节包含红色值,其次两个字节分别是绿色和蓝色,而最后位字节则包含一个标志。此标志用于指示是否引用一个高频脉动色,或者一个调色板匹配色,或者一个明显的调色板索引。这个字节的值决定顺序排列的三个低位字节如何选择一种颜色。当你想指定一个建立这些对象的API函数中的笔或刷子的颜色时,可以把高位字节设置为如下表中的三个值之一。

高字节值 结果 &H00 在对象绘出后,Windows高频脉动20个保留色,这叫RGB颜色引用。(普通情况) &H01 最低字节不是红色的值,而是指一个调色板项的数目或索引值,因此Windows使用在那个调色板项中的颜色,中间的两个字节(字节1和2,原绿色和蓝色字节)应保持值&H00,这叫调色板索引引用。 &H02 Windows定位与由红、绿、蓝决定的在三个顺序排列的低位字节指定的颜色最相匹配的调色板项。这叫作调色板RGB引用。 因此,严密地讲,一个RGB值是通过以下方式构成的。

Dim RGBColor As Long

RGBColor=RedValue + (GreenValue * 256) + (BlueValue * 65536) + _

(FlagValue * 16777216)

这种技术的使用请参考本教程附带的程序Palette.vbp。

CMY 在计算机领域还存在几种RGB颜色区间的变种。一个是叫做CMY的颜色区间。指的是蓝绿色、紫红色以及黄色。打印机和照相机通过加墨乳剂渲染颜色时,采用的是减法色彩系统。它由将颜色色素沉淀到白色纸上的大部分硬拷贝设备使用,例如激光打印机和喷墨打印机。当被现实时,这三种颜色都吸收与自身互补的浅颜色。蓝绿色吸收红色,紫红色吸收绿色,黄色吸收蓝色。例如,可增加黄色墨的量,图象中的蓝色量减少。RGB模式和 CMY模式之间的转换是非常简单的。为了计算蓝绿色,请从255中减去RGB中的红色值;对于紫红色,则从255中减去RGB中的绿色值;至于黄色嘛,喔!你已经猜测到了,即从255中减去RGB中的蓝色值。例如,RGB(240,12,135)的CMY值分别是15,243和120。然而,这种颜色区间大概并不是我们所感兴趣的,当然也有人感兴趣的。但下面给出的颜色区间更吸引我们,起码是我。

HSV(颜色,浓度,亮度) HSV是众多色彩系统中的一个。如果你打开了通用对话框的颜色对话框家会发现,除了RGB调解器,还有一个类似的但其值很古怪的调解器。很多3D动画软件和图象处理软件中,这种HSV颜色空间也被广泛采用。它的基本原理是更改颜色属性值以创建新颜色,而不是使用颜色本身的混合色。色调般指颜色,例如红色、桔黄色、蓝色等等。饱和度(也被称为浓度)指示指示色调中的白色量∶全饱和和色调不包含白色,显示纯色。而部分包含色调根据所混合的白色的情况,显示的颜色浅。例如,50%的饱和度的红色色调显示为粉红色。值(也被称为亮度)是颜色自身的发光度,也就是它所发出的光的多少。高饱和度色调非常亮,而低饱和度色调非常暗。

HSV与画家以及其他通过将白色、黑色和灰色增加到纯色素中以创建色彩、底纹、以及色调的艺术家们使用的色彩系统非常相似。色彩是纯色,是组合了白色的全饱和度颜色,而底纹是组合了黑色的全饱和度颜色。如果使用这两种颜色混合,那么HSV的饱和度是白色量,值是黑色量,色调是增加了黑白两色后的颜色。 更详细的情况不再这里说了,说起来也费劲,也不常用,以后做个程序放到站点里。

TA的精华主题

TA的得分主题

 楼主| 发表于 2005-2-11 00:35 | 显示全部楼层

七、关于调色板的基础知识

关于调色板,很少书谈得深入,Dan的书上讲得也就那么一点点,少得实在可怜,连一个有关调色板的API都没有给出。为了弄懂它,我也付出了不少时间。当然,现在就给你讲解讲解。把各个角落中学来的知识总结在这里,想来也是满不错的主意感兴趣的朋友可以看,不看也无访。。

用户显示于简报的图片很可能需要大量不同的颜色。可以想象∶艳绿色可滚动的爱尔兰小山的照片会比火星的图片需要更多的套不同的颜色、若用户想同时显示这两幅图象,会碰到一个很现实的问题。即使不限制逼真度,甚至用256种颜色,用户都不可能有足够的浓淡级别同时提供给两个图象。值得庆幸的是,若一次只有一幅图片显示,用户可以要求Windows交换颜色,使每个图象能激活自己的256种颜色选择--它自己的颜色调色板。

那么,什么是调色板?它是一种Windows对象,但适当地,如果你把它想象成一种特定长度的结构数组,对理解会有帮助的。还记得RECT结构吧,如果声明 Dim MyRect(0 to 255) as RECT 以上,我们定义了一个RECT结构数组。当然,所有的笨蛋都知道调色板并不是RECT的。调色板结构比RECT要复杂一点。首先调色板是一种叫LOGPALETTE 的结构来构成的。如下∶

Type LOGPALETTE palVersion As Integer palNumEntries As Integer palPalEntry ( 1 ) As PALETTEENTRY

End Type

palVersion 指Windows的版本号,数值300代表Windows3.0或3.1,不过请记住,在Windows9X中仍然使用该数值,即300。第二个参数值调色板登录项的数目。也就是说,它指的是第三个参数palPalEntry的元素个数。这个例子中显然是1喽!那么在以下的情况呢?

Type LOGPALETTE palVersion As Integer palNumEntries As Integer palPalEntry ( 255 ) As PALETTEENTRY End Type 当然是256。但这也不一定,比255小也无妨。比如在4位模式中,应当是16,就算你声明为palPalEntry ( 255 ),创建调色板时,函数只使用其前面的0到15的数组元素。

接下来,正如你已经看到的那样,第三个参数是一种结构数组。当然不是RECT喽,而是 PALETTEENTRY。它的内容如下∶

Type PALETTEENTRY peRed As Byte peGreen As Byte peBlue As Byte peFlags As Byte End Type

Red,Green,Blue,不用我说了吧?最后一个peFlags是什么呢? 它是包含用来描述调色板项类型的一个或多个颜色标志的值。如下表显示了个些标志∶

标志 值 说 明 PC_EXPLICIT &H2 创建一个调色板条目,该调色板条目在系统调色板中指定一个索引而不是颜色。有显示系统调色板内容的程序使用。 PC_NOCOLLAPSE &H4 创建一个被影射到系统调色板中未用条目上的调色板条目,即使该颜色条目已经存在。用于当两个条目影射到同一颜色上时确保调色板颜色的唯一性。 PC_RESERVED &H1 创建一个某应用程序专有的调色板条目。当PC_RESERVED条目被添加到系统调色板时,它不被影射到其他逻辑调色板中的颜色上,即使这些颜色匹配。由执行调色板动画的程序使用。

在8位显示器上,一个像素的颜色是通过查看一个色彩表中自己的8位像素值来决定的。一个调色板包含一套(数组)24位RGB色彩值(peRed,peGreen,peBlue)。一个调色板中的颜色数目最多256个(从0到255)。每个显示内存的像素选项包含一个从0到255的值,这个像素指定哪一个调色板项被用来为这个像素着色。要改变一个像素的颜色,用户有两个选择∶其一,可改变这个像素的颜色索引值;其二,改变调色板登录项上的颜色值(RGB值,24位)。在后一种情况下,这种改变使得所有引用这个调色板登录项的像素均同时引起颜色变化。

然而你应当清楚,初始化一个LOGPALETTE变量,并不能说它是一个调色板。因为调色板是GDI对象的一员,就像画笔、画刷之类的GDI对象一样,必须通过特定的函数创建它。创建后,我们可以获得一个调色板句柄,那么这个句柄所代表的就是真正的调色板了。

每个用户显示的图象能带自身的色彩调色板。另外,每个活动窗口能根据自身目的来操作调色板。但是,记住,应用于全屏幕,具有256种颜色的限制,这并不是对于每个窗口或应用程序而言。对于这些,还得用Windows调色板管理器来进行管理。Windows调色板管理器决定在给定时间哪个窗口拥有调色板控制。在前台活动的窗口常常拥有优先权。若此窗口不使用调色板,优先权则传给Z向(Z-order,听说过吧?它垂直于屏幕。因为我们常把屏幕坐标用X和Y来表示。而三维坐标是用X,Y,Z来表示的。这里指的Z并不是说真的三维坐标中的那个Z轴,而只是一个形象的比喻中被命名的,是指桌面窗口垂直方向)的下一个窗口。一旦带最高优先权的窗口认清自己的调色板作为前台调色板,其他窗口将被依次通知为背景调色板,这是由调色板管理器来通知。在一般情况下调色板管理器是自动工作的。

刚才我说了一句“认清”这么一个单词。那么,什么叫“认清一个调色板”呢?每个用户显示的图象能带自己的调色板(几个调色板能被同时放在内存中)。存放在内存的调色板叫做逻辑调色板。在用户显示系统的调色板决定着哪一种颜色实际出现在屏幕上,这个调色板被叫做系统调色板或者硬件调色板(集中精力!系统调色板是硬件层的)只有一个硬件调色板并且调色板管理器保留一个它的复制调色板。当一个应用程序激活自己的颜色时,它必须在设备场景(device context)中选入逻辑调色板并认清它。这意味着,应用程序必须要求调色板管理器装载它的逻辑调色板给系统(硬件)调色板。所以,所谓“认清”实际上是一种“拜托”,或者就象日本人常说的“多多关照”∶请多多关照,使用我的调色板吧。因为只有这样,应用程序才能显示出符合自己口味的颜色。

由于调色板的大小会发生改变,调色板管理器不会傻呵呵地硬着从逻辑调色板复制一个固定大小的256种颜色元素的块给硬件调色板。而是,这个调色板管理器只装载它在每个逻辑调色板中找到的那么多的颜色。系统调色板可以容纳多个逻辑调色板,只要颜色总数不超过256即可。Windows为它静态颜色(用于画按钮、边框、文本、图表等等,叫做系统保留色。可以用GetSystemColor函数获取的那几种)保留了20种调色板登录项。因此,只为我们剩下236个可变颜色位置。但这并不意味着一个调色板将只包括它需要的236种颜色来支持它的位图。把8位图象调色板转化为Windows本体调色板是明智的。Windows本体调色板包括20种保留色,特别是用户打算用调色板绘图时,否则不能用保留的颜色。本教程附带的Palette.vbp程序如果在16位或24位模式下运行,将只显示这20种颜色。若用户愿意,可以用系统静态颜色把可定义的颜色范围扩展到256。GDI就是为这个目的提供了特殊函数。但这将干扰其他活动程序的基本命令,因为它将动态改变活动程序的外观。因此除非你的程序独占整个屏幕(比如一些游戏就是这样的,不与其他窗口程序同时显示),否则这种做法是不应采取的。

一个逻辑调色板中的颜色在系统调色板中一般不占据与在逻辑调色板中相同的位置。这是因为在认清一个调色板的时候,调色板管理器建立一个交叉引用表,也叫做调色板映像(palette mapping),正如它把一个逻辑调色板加载给系统调色板。这个表用于GDI绘图函数把像素从逻辑调色板翻译到系统调色板索引。很好理解的。可以把它想象为一种两列的表,左列中填写有逻辑调色板的颜色索引值,对应的右列中填写有系统调色板的索引值。就像英语词典里一个英语单词对应着一个中文单词。记住,计算机中所谓映像都是指这种情况。比如消息映像,它为各种消息值调用相应的消息处理函数。接着来。正如前面所解释的,一个像素的颜色是通过在颜色表中查看它的值来决定的。在设备相关位图和DIB(设备无关位图)的情况下,这是256种颜色位图文件的最通用窗体,组成位图像素数据的字节包含在文件的颜色表中的登录项的值。当GDI把图象从文件转移到屏幕时,也就是说,从一个设备相关位图转移到另一个依赖于设备的位图或DDB(设备相关位图)时,它用调色板映像来改变像素值,使它能引用系统调色板中当前正确的颜色。为一个逻辑调色板建立的调色板映像叫做前台映像。

若从活动窗口没有获取所有调色板登录项,则剩下的位置被填入从非活动窗口拿来的颜色,直到或者所有的位置占据,或者没有其他的窗口要求识别自己的调色板位置。若前台窗口需要所有的236个自由颜色位置,则所有的非活动窗口必须受前台活动调色板的支配。调色板管理器还能自动地执行这个服务,这是通过把非活动窗口中的颜色映像给当前被辨认出的调色板中的最匹配的颜色来实现的。这就是所谓的后台影像。这有时会产生有趣的但对大多数人来讲是糟糕的结果。比如,最匹配色=很不匹配,其他色=更不匹配的情况下。另外,你需要记住的一点是,当焦点每次从一个基于调色板的应用程序更换到另一个基于调色板的应用程序时,整个辨认过程重复执行一次。

DIB中的像素包含与位图一起的逻辑调色板中的颜色索引,通常一个颜色表存在于DIB文件中;DDB中的像素包含系统调色板中的颜色索引。当用户是根据索引值来访问一种颜色时,用户是在逻辑调色板中根据它的位置来访问颜色的,而不是在系统调色板中的它的位置。也就是说,你只能用逻辑调色板的索引值。因此,假如逻辑调色板中不存在20中系统颜色,那么我们就无法访问它,这并不是说它不存在。因此,如果你需要系统颜色,就应当把这些颜色值装载的逻辑调色板。

TA的精华主题

TA的得分主题

 楼主| 发表于 2005-2-11 00:36 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2005-2-11 08:37 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2005-4-13 15:09 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2005-5-16 21:05 | 显示全部楼层
确实有点复杂,但还得学,谢谢!

TA的精华主题

TA的得分主题

发表于 2005-5-18 21:31 | 显示全部楼层

楼主辛苦了,谢谢

建议:您能不能把它做成一个文件(如TXT文件),这样我们就不用按这么多次CTRL+C,CTRL+V了(偶是不是太懒了?)

TA的精华主题

TA的得分主题

发表于 2005-6-4 14:04 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
同意楼上看法

TA的精华主题

TA的得分主题

发表于 2005-6-9 08:43 | 显示全部楼层
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-3-29 22:58 , Processed in 0.054071 second(s), 7 queries , Gzip On, Redis On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表