牙周手术临床指南pdf:没事看看。绘图相关

来源:百度文库 编辑:偶看新闻 时间:2024/04/29 19:45:06
比bitblt和stretchblt效率更高的函数,200分!

在paintbox中使用上面两个函数,发现效率非常低,在800x600的图像上用stretchblt加双缓冲作个动画要1秒种,呵呵,哪位高手有好的解决方案,请不吝赐教!


不要directX,哪位能搞定,送200分!


呵呵,我自己回答算了,csdn的高手走光了
BMP位图文件结构及平滑缩放
---- 用普通方法显示BMP位图,占内存大,速度慢,在图形缩小时,失真严重,在低颜色位数的设备上显示高颜色位数的图形图形时失真大。本文采用视频函数显示BMP位图,可以消除以上的缺点。
---- 一、BMP文件结构
---- 1. BMP文件组成
---- BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。
---- 2. BMP文件头
---- BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。
---- 其结构定义如下:
typedef struct tagBITMAPFILEHEADER
{
WORDbfType; // 位图文件的类型,必须为BM
DWORD bfSize; // 位图文件的大小,以字节为单位
WORDbfReserved1; // 位图文件保留字,必须为0
WORDbfReserved2; // 位图文件保留字,必须为0
DWORD bfOffBits; // 位图数据的起始位置,以相对于位图
// 文件头的偏移量表示,以字节为单位
} BITMAPFILEHEADER;
---- 3. 位图信息头
----
BMP位图信息头数据用于说明位图的尺寸等信息。
typedef struct tagBITMAPINFOHEADER{
DWORD biSize; // 本结构所占用字节数
LONGbiWidth; // 位图的宽度,以像素为单位
LONGbiHeight; // 位图的高度,以像素为单位
WORD biPlanes; // 目标设备的级别,必须为1
WORD biBitCount// 每个像素所需的位数,必须是1(双色),
// 4(16色),8(256色)或24(真彩色)之一
DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),
// 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
DWORD biSizeImage; // 位图的大小,以字节为单位
LONGbiXPelsPerMeter; // 位图水平分辨率,每米像素数
LONGbiYPelsPerMeter; // 位图垂直分辨率,每米像素数
DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数
DWORD biClrImportant;// 位图显示过程中重要的颜色数
} BITMAPINFOHEADER;
---- 4. 颜色表
---- 颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:
typedef struct tagRGBQUAD {
BYTErgbBlue;// 蓝色的亮度(值范围为0-255)
BYTErgbGreen; // 绿色的亮度(值范围为0-255)
BYTErgbRed; // 红色的亮度(值范围为0-255)
BYTErgbReserved;// 保留,必须为0
} RGBQUAD;
颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
当biBitCount=1,4,8时,分别有2,16,256个表项;
当biBitCount=24时,没有颜色表项。
位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader; // 位图信息头
RGBQUAD bmiColors[1]; // 颜色表
} BITMAPINFO;
---- 5. 位图数据
---- 位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节;
Windows规定一个扫描行所占的字节数必须是
4的倍数(即以long为单位),不足的以0填充,
一个扫描行所占的字节数计算方法:
DataSizePerLine= (biWidth* biBitCount+31)/8;
// 一个扫描行所占的字节数
DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数
位图数据的大小(不压缩情况下):
DataSize= DataSizePerLine* biHeight;
---- 二、BMP位图一般显示方法
---- 1. 申请内存空间用于存放位图文件
---- GlobalAlloc(GHND,FileLength);
---- 2. 位图文件读入所申请内存空间中
---- LoadFileToMemory( mpBitsSrc,mFileName);
---- 3. 在OnPaint等函数中用创建显示用位图
---- 用CreateDIBitmap()创建显示用位图,用CreateCompatibleDC()创建兼容DC,
---- 用SelectBitmap()选择显示位图。
---- 4. 用BitBlt或StretchBlt等函数显示位图
---- 5. 用DeleteObject()删除所创建的位图
---- 以上方法的缺点是: 1)显示速度慢; 2) 内存占用大; 3) 位图在缩小显示时图形失真大,(可通过安装字体平滑软件来解决); 4) 在低颜色位数的设备上(如256显示模式)显示高颜色位数的图形(如真彩色)图形失真严重。
---- 三、BMP位图缩放显示
---- 用DrawDib视频函数来显示位图,内存占用少,速度快,而且还可以对图形进行淡化(Dithering)处理。淡化处理是一种图形算法,可以用来在一个支持比图像所用颜色要少的设备上显示彩色图像。BMP位图显示方法如下:
---- 1. 打开视频函数DrawDibOpen(),一般放在在构造函数中
---- 2. 申请内存空间用于存放位图文件
---- GlobalAlloc(GHND,FileLength);
---- 3. 位图文件读入所申请内存空间中
---- LoadFileToMemory( mpBitsSrc,mFileName);
---- 4. 在OnPaint等函数中用DrawDibRealize(),DrawDibDraw()显示位图
---- 5. 关闭视频函数DrawDibClose(),一般放在在析构函数中
---- 以上方法的优点是: 1)显示速度快; 2) 内存占用少; 3) 缩放显示时图形失真小,4) 在低颜色位数的设备上显示高颜色位数的图形图形时失真小; 5) 通过直接处理位图数据,可以制作简单动画。
---- 四、CViewBimap类编程要点
---- 1. 在CViewBimap类中添加视频函数等成员
HDRAWDIB m_hDrawDib; // 视频函数
HANDLEmhBitsSrc; // 位图文件句柄(内存)
LPSTR mpBitsSrc; // 位图文件地址(内存)
BITMAPINFOHEADER *mpBitmapInfo; // 位图信息头
---- 2. 在CViewBimap类构造函数中添加打开视频函数
---- m_hDrawDib= DrawDibOpen();
---- 3. 在CViewBimap类析构函数中添加关闭视频函数
if( m_hDrawDib != NULL)
{
DrawDibClose( m_hDrawDib);
m_hDrawDib = NULL;
}
---- 4. 在CViewBimap类图形显示函数OnPaint中添加GraphicDraw()
voidCViewBitmap::OnPaint()
{
CPaintDC dc(this); // device context for painting
GraphicDraw( );
}
voidCViewBitmap::GraphicDraw( void )
{
CClientDC dc(this); // device context for painting
BITMAPFILEHEADER *pBitmapFileHeader;
ULONG bfoffBits= 0;
CPoint Wid;
// 图形文件名有效 (=0 BMP)
if( mBitmapFileType < ID_BITMAP_BMP ) return;
// 图形文件名有效 (=0 BMP)
// 准备显示真彩位图
pBitmapFileHeader= (BITMAPFILEHEADER *) mpBitsSrc;
bfoffBits= pBitmapFileHeader->bfOffBits;
// 使用普通函数显示位图
if( m_hDrawDib == NULL || mDispMethod == 0)
{
HBITMAP hBitmap=::CreateDIBitmap(dc.m_hDC,
mpBitmapInfo, CBM_INIT, mpBitsSrc+bfoffBits,
(LPBITMAPINFO) mpBitmapInfo,DIB_RGB_COLORS);
// 建立位图
HDC hMemDC=::CreateCompatibleDC(dc.m_hDC);// 建立内存
HBITMAP hBitmapOld= SelectBitmap(hMemDC, hBitmap); // 选择对象
// 成员CRect mDispR用于指示图形显示区域的大小.
// 成员CPoint mPos用于指示图形显示起始位置坐标.
if( mPos.x > (mpBitmapInfo- >biWidth - mDispR.Width() ))
mPos.x= mpBitmapInfo->biWidth - mDispR.Width() ;
if( mPos.y > (mpBitmapInfo- >biHeight- mDispR.Height()))
mPos.y= mpBitmapInfo- >biHeight- mDispR.Height();
if( mPos.x < 0 ) mPos.x= 0;
if( mPos.y < 0 ) mPos.y= 0;
if( mFullViewTog == 0)
{
// 显示真彩位图
::BitBlt(dc.m_hDC,0,0, mDispR.Width(), mDispR.Height(),
hMemDC,mPos.x,mPos.y, SRCCOPY);
} else {
::StretchBlt(dc.m_hDC,0,0, mDispR.Width(), mDispR.Height(),
hMemDC,0,0, mpBitmapInfo- >biWidth, mpBitmapInfo-
>biHeight, SRCCOPY);
}
// 结束显示真彩位图
::DeleteObject(SelectObject(hMemDC,hBitmapOld));
// 删 除 位 图
} else {
// 使用视频函数显示位图
if( mPos.x > (mpBitmapInfo- >biWidth - mDispR.Width() ))
mPos.x= mpBitmapInfo- >biWidth - mDispR.Width() ;
if( mPos.y > (mpBitmapInfo- >biHeight- mDispR.Height()))
mPos.y= mpBitmapInfo- >biHeight- mDispR.Height();
if( mPos.x < 0 ) mPos.x= 0;
if( mPos.y < 0 ) mPos.y= 0;
// 显示真彩位图
DrawDibRealize( m_hDrawDib, dc.GetSafeHdc(), TRUE);
if( mFullViewTog == 0)
{
Wid.x= mDispR.Width();
Wid.y= mDispR.Height();
// 1:1 显示时, 不能大于图形大小
if( Wid.x > mpBitmapInfo- >biWidth )
Wid.x = mpBitmapInfo- >biWidth;
if( Wid.y > mpBitmapInfo- >biHeight)
Wid.y = mpBitmapInfo- >biHeight;
DrawDibDraw( m_hDrawDib, dc.GetSafeHdc()
, 0, 0, Wid.x, Wid.y,
mpBitmapInfo, (LPVOID) (mpBitsSrc+bfoffBits),
mPos.x, mPos.y, Wid.x, Wid.y, DDF_BACKGROUNDPAL);
} else {
DrawDibDraw( m_hDrawDib, dc.GetSafeHdc(),
0, 0, mDispR.Width(), mDispR.Height(),
mpBitmapInfo, (LPVOID) (mpBitsSrc+bfoffBits),
0, 0, mpBitmapInfo- >biWidth, mpBitmapInfo- >biHeight,
DDF_BACKGROUNDPAL);
}
}
return;
}
---- 五、使用CViewBimap类显示BMP位图
---- 1. 在Visual C++5.0中新建一个名称为mymap工程文件,类型为MFC AppWizard[exe]。在编译运行通过后,在WorkSpace(如被关闭,用Alt_0打开)点击ResourceView,点击Menu左侧的+符号展开Menu条目,双击IDR_MAINFRAME条目,进入菜单资源编辑,在'“查看(V)”下拉式菜单(英文版为View下拉式菜单)的尾部添加“ViewBitmap”条目,其ID为ID_VIEW_BITMAP。
---- 2. 在Visual C++5.0中点击下拉式菜单Project- >Add To project- >Files...,将Bitmap0.h和Bitmap0.cpp添加到工程文件中。
---- 3. 在Visual C++5.0中按Ctrl_W进入MFC ClassWizard,选择类名称为CMainFrame,ObjectIDs: ID_VIEW_BITMAP,Messa


From: Toni Martir
To: Earl F. Glynn
Subject: RE: How to extract a bitmap from an avi file
Date: Wednesday, January 20, 1999 4:32 AM
I have one example
pavi:PAVIFile;
pavis:PAVIStream;
pavisound:PAVIStream;
ob:PGetFrame;
pbmi:PBitmapInfoHeader;
Punter:PByte;
han,i:integer;
Desti:TCanvas;
microsperframe.:integer;
principio,fin:integer;
if 0<>AVIFIleOpen(pavi,Pchar(FFilename),OF_READ,nil) then
Raise Exception.Create('No se pudo abrir el archivo');
Desti:=Canvas;
if AVIERR_NODATA=AVIFILEGetStream(pavi,pavis,streamtypeVIDEO,0) then
Raise Exception.Create('Error no hay pista de audio');
principio:=AVIStreamStart(pavis);
fin:=AVIStreamENd(pavis);
ShowMessage(IntToStr(AVIStreamLength(pavis)));
ob:=AVIStreamGetFrameOpen(pavis,nil);
if nil=ob then
Raise Exception.Create('Error en Frameopen');
han:=DrawDIBOpen;
try
microsperframe.:=Trunc(1000000/(info.dwRate/info.dwScale));
DrawDIBStart(han,microsperframe);
DrawDIBStart(han,microsperframe);
i:=0;
if 0<>AVIStreamBeginStreaming(pavis,principio,fin,1000) then
Raise Exception.Create('Error n AVIBegin');
pbmi:=AVIStreamGetFrame(ob,i);
While pbmi<>Nil do
begin
Punter:=Pointer(Integer(pbmi)+pbmi^.biSize);
DRawDIBBegin(han,desti.handle,0,0,pbmi,pbmi^.biWidth,pbmi^.biheight,DDF_ANIM
ATE);
DrawDIBRealize(han,desti.handle,false);
DrawDIBDraw(han,desti.handle,0,0,pbmi^.biWidth,pbmi^.biheight,pbmi,Punter,0,
0,pbmi^.biwidth,pbmi^.biheight,0);
DrawDIBEnd(han);
inc(i);
pbmi:=AVIStreamGetFrame(ob,i);
end;
AVIStreamEndStreaming(pavis);
DrawDIBStop(han);
finally
DrawDIBClose(han);
end;
AVIStreamGetFrameClose(ob);
AVIStreamRelease(pavis);
end;
-----Mensaje original-----
De: Earl F. Glynn
Para: Toni Martir
Fecha: martes, 19 de enero de 1999 21:40
Asunto: Re: How to extract a bitmap from an avi file
>Toni:
>
>>You can email-me if do you want this file.
>
>
>Do you have any examples of using this file?
>
>efg
>_________________________________
>efg's Computer Lab: www.efg2.com/lab
>Delphi Books: www.efg2.com/lab/TechBooks/Delphi.htm
>
>Earl F. Glynn E-Mail: EarlGlynn@att.net
>Overland Park, KS USA


呵呵,高手,我受教了!


呵呵,出了200分,自己回答问题,CSDN让我失望啊!


呵呵,老大对windows编程很熟,
不过delphi已经在自己的画图类TCanvas里包装了一个,
你用一下TCanvas.StretchDraw试试结果怎么样,我觉得还不错,呵呵。


楼上的朋友,小弟搞了多年多媒体编程了,不过TCanvas.StretchDraw的原型就是对stretchblt的封装!


这个效率很低,而且好要设置压缩模式,更慢了!


呵呵,是呀,速度是不行。


你有好的办法吗?


这个贴子也是我帮他回答的,呵呵,一样的问题!
http://www.csdn.net/expert/topic/772/772425.xml?temp=.1789972


我是菜鸟,只能收藏


同意!


偶试了试
Bitblt 效率还可以吧, 没有时间感觉
StretchDraw 有点抖,但我是单缓冲
我是觉得用 Windows GUI 不可能再有高于 Bitblt 的效率了, 这个API纯粹就是内存的拷贝,跟踪了多次了,用 movsb 语句直接写入 Windows 显存缓冲区。在纯 GUI 下是不可能直接操作显存的...??
而 StretchDraw 的汇编让人无法理解,可能用到了高级语言写,最可能改进的也就只有 StretchDraw 的算法?


StretchDraw用的就是stretchblt的封装


fastblib里的方法不错,就是用的dib


这个是下载地址:http://www.delphibyte.com/download/softview.php?softid=471
作者: g-soft. FastLIB集合了一组用于图形的单元文件。包括:一个DIB类,其封装了所有的Windows图形API函数;一套图片处理函数库;以及用于存取各种图片文件格式的单元。经过3年的时间和无数程序员排错和优化使FastLIb成为了一套非常优秀的图形函数库。大家还可以的它的主页上去下载Demo,非常的cool哦。


高手啊!


Microsoft的针对与设备无关位图(DIB位图),在其WIN32 SDK的Multimedia中提供了一组绘制DIB位图的高性能函数组──DrawDib函数组。DrawDib函数组是一组不依赖于图形设备接口(GDI)函数,而直接操作显存的函数组。它们支持8位、16位、24位和32位图象深度的DIB。总的来说,DrawDib函数组类似于StretchDIBits函数,它们都提供了将图象拉伸和抖动的功能,然而,DrawDib函数组还支持图象的解压、数据流以及更多的显示适配器。在某些情况下,DrawDib函数组还具有更大的优越性。但是,在某些场合下,DrawDib函数组却不能取代StretchDIBits函数。下面就DrawDib函数组和StretchDIBits函数使用的场合加以区别和说明:
颜色信息表格式。DrawDib函数组只支持颜色信息表格式为DIB_RGB_COLORS格式的图象,如果要显示以DIB_PAL_COLORS或DIB_PAL_INDICES格式的图象,则必须用StretchDIBits函数。
光栅操作模式。DrawDib函数组只能使用SRCCOPY光栅操作模式,如果要求不仅仅使用SRCCOPY模式的话,只能用StretchDIBits函数。同样地,如果要使用其他光栅操作,例如XOR,只能用StretchDIBits函数。
视频及动画回放的质量。DrawDib函数组支持数据流应用,诸如视频片和动画序列,它比StretchDIBits函数提供了更高的图象质量以及对回放过程的改进。
显示适配器。DrawDib函数组比StretchDIBits函数支持更多的显示适配器。DrawDib函数组支持使用4位图象深度提供16色调色板的VGA适配器,使用8位图象深度提供256色调色板的SVGA适配器和使用16位、24位和32位图象深度提供成千上万种颜色的真彩色适配器。DrawDib函数组还使用了受限制的潜在能力提高了图象在显示适配器上的速度和质量。例如,当使用8位的显示适配器时,DrawDib函数组有效地将真彩色图象抖动为256色;同样的,使用4位的显示适配器时,它们也将8位深度的图象抖动成4位。
图象拉伸。正如StretchDIBits一样,DrawDib函数组用源矩形和目的矩形来控制一个图象显示的部分。可以通过改变源矩形和目的矩形的位置和大小来裁剪一幅图象不需要的部分和拉伸某部分。如果显示驱动不支持图象拉伸,那么DrawDib函数组提供了比StretchDIBits函数更有效的拉伸能力。
压缩图象。DrawDib函数组支持好几种压缩和解压方法,其中包括游程编码,JPEG,Cinepak,411YUV和Indeo?。
 
DrawDib的操作
通过使用DrawDibOpen函数初始化DrawDib函数组。DrawDibOpen负责装载动态连接库(DLL),申请内存资源,DrawDib设备环境(DC),并且维持初始化相关的设备环境计数。DrawDibOpen同时返回一个其它DrawDib函数所需要使用的新的DC句柄。
当使用完DrawDib DC后,可以用DrawDibClose函数释放它。DrawDibClose同时减少存取DLL的应用的计数。在应用程序中,DrawDibClose函数应是最后的DrawDib操作。
可以创建任意多的DrawDib DC,也可以同时使用多个DrawDib DC来绘制几幅位图。在应用程序中可以创建多个不同性质的DrawDib DC,这样就可以选择最合适的DC设置。例如,在同一应用程序中,创建两个不同的DrawDib DC,一个用来显示图象的正常分辨率,另一个用来显示图象的放大部分。 为了更有效地运行,DrawDib函数组需要知道显示适配器及其驱动的信息。显示配置信息是在第一次使用包含DrawDib函数组的DLL时,对显示适配器通过了一系列的测试之后得到的。DrawDib函数组的所有应用都要用到这个配置信息。可以通过调用DrawDibProfileDisplay函数来强制重新进行这些测试。
通常,取得和保存显示配置是一次性的事件。如果配置信息发现在这个系统中安装了另一个显示驱动时,DrawDib则重新进行测试。
 
图象再现
创建了DrawDib DC后,就可以用DrawDibDraw函数将DIB绘至屏幕。当在8位深度的显示适配器上显示真彩色图象时,DrawDib将自动地抖动图象。
DrawDib也透明地支持视频压缩器。当显示压缩位图时,可通过DrawDibGetBuffer函数得到包含了解压图象数据的缓冲区。如果位图是未压缩的,则DrawDibGetBuffer返回NULL。在应用程序中应自己区分位图是否压缩。
可用DrawDibUpdate宏来刷新一幅图象的整体或一部分的显示。
 
图象序列
当DrawDibDraw函数同DrawDibBegin函数一起运用时,可以显示相同尺寸和格式的位图序列。DrawDib通过DrawDibBegin准备绘图的DrawDib DC来提高DrawDibDraw的效率。如果,应用程序没有调用DrawDibBegin,那么DrawDibDraw会在绘图前隐含地执行DrawDibBegin。
DrawDibBegin给DrawDibDraw提供了DrawDib的DC,DC的句柄,BITMAPINFOHEADER结构的地址和源矩形及目的矩形的尺寸。当要显示一个位图序列时,DrawDibDraw要检查序列中的每幅图象的这些值。如果DrawDibDraw检测到这些值有任何变化,它将隐含地再次调用DrawDibBegin来调整DrawDib DC的设置。
当调用完DrawDibBegin后,就可以指定一个或多个适当的标志来调用DrawDibDraw绘制图象序列。只要DC句柄未改变,就可指定DDF_SAME_HDC标志;下列参数未改变,就可指定DDF_SAME_DRAW标志:BITMAPINFOHEADER结构的地址和源矩形及目的矩形的尺寸。
可以通过在DrawDibEnd后跟另一个DrawDibBegin调用来更新前一个DrawDibBegin设置的标志。DrawDibEnd清除了当前的DrawDib DC的标志和设置。后续的调用DrawDibBegin将重新初始化DrawDib DC,并重新设置适当的标志和设置。然而,只要至少改变了以下任一个当前的标志设置:BITMAPINFOHEADER结构的地址或是源矩形或目的矩形的尺寸,也可不使用DrawDibEnd而直接调用DrawDibBegin来更新一个DrawDib DC。
通过使用DrawDibStart和DrawDibStop函数,可以提高使用压缩图象的数据流操作(如回放一个视频片)的DrawDibDraw的效率。DrawDibStart通过发送一个消息告诉视频管理器(VCM)准备DrawDib DC来接受一个图象流。当流结束时,DrawDibStop发送一个消息给VCM来指示它释放申请的资源。
需要注意的是,在应用程序中必须确定源矩形和目的矩形的宽度和高度;然而却并不需要确定这些矩形的起点。应用程序可以重新DrawDibDraw中的起点坐标来使用图象的不同部分或更新显示的不同部分。
 
调色板
DrawDib函数组需要响应两条调色板消息:WM_QUERYNEWPALETTE和WM_PALETTECHANGED。如果应用程序未注意到调色板,就需要对这些消息都增加一个各自的消息处理。 通过使用DrawDibRealize函数可在当前DC中实现当前DrawDib的调色板。应当在响应WM_QUERYNEWPALETTE和WM_PALETTECHANGED消息时,或在用DrawDibDraw函数显示一个图象序列的准备过程中实现调色板。
可以用DrawDibSetPallette函数用另一个调色板的映射来绘一幅图象。DrawDibSetPallette强迫DrawDib DC使用指定的调色板,而这会影响到图象的质量。例如,一个注意调色板的应用程序,可能已经实现了一个调色板并需要阻止DrawDib实现它自己的调色板。应用程序可以通过DrawDibSetPalette来通知DrawDib调色板的使用。
通过使用DrawDibGetPallette函数可以获得当前前景调色板的一个句柄。如果应用程序使用了当前前景调色板,它并没有对调色板的完全使用权,另一个应用程序能够使这个调色板句柄无效。当使用完毕后,应用程序不应该释放调色板,那样会使另一个应用程序不能使用调色板。
通过使用DrawDibChangPallete函数可以为它的调色板DrawDib来接收新的颜色值。在紧跟DrawDibChangPallete的后面的代码里,可以为调色板颜色表指定新的值。当调用DrawDibChangPalette时,在DrawDib DC中未设置DDF_ANIMATE标志的话,可以通过使用DrawDibRealize来实现调色板和DrawDibDraw重绘图象来实现调色板的改变。如果DDF_ANIMATE标志在DrawDib DC中设置了,就可以通过DrawDibDraw或DrawDibRealize来实现调色板和显示着的位图颜色的动画。通过DrawDibEnd和DrawDibBegin可以DDF_ANIMATE标志。
如果释放了被选入DC的DrawDib调色板,DC使用调色板时会报告一个GDI错误。相反,应该使用DrawDibSetPalette改变DrawDib DC来使用省缺调色板后另一调色板。
由于以下函数会释放DrawDib调色板,所以,除非调色板不被DC选中不应使用:DrawDibEnd,DrawDibClose和DrawDibBegin。同样的,当使用了相同的DrawDib DC,但指定了不同的绘制参数(lpbi,dxDst,dyDst,dxSrc或dySrc)或不同格式时,DrawDibDraw也会释放调色板。
 
时间计算
作为调试应用程序的一部分,调用DrawDibTime函数可以得到一些关于完全重复特定次数DrawDib操作所需时间。DrawDibTime返回以下操作的时间:
绘制一幅位图
解压一幅位图
抖动一幅位图
拉伸一幅位图
使用BitBlt函数变换一幅位图
使用StrecthDIBits函数变换一幅位图
得到返回值后,DrawDibTime重新设置每项操作的计数和值。
注意,DrawDibTime只在DrawDib函数的调试版中可用。
 
DrawDib的使用
增加调色板消息处理
下面的例子说明了WM_PALETTECHANGED和WM_QUERYNEWPALETTE消息的处理。这个例子用了DrawDibRealize函数来进行WM_QUERYNEWPALETTE消息的处理。
应用程序应通过使目标窗口无效来让DrawDibDraw函数重绘图象来响应WM_QUERYNEWPALETTE消息。应用DrawDibRealize函数实现调色板来响应WM_PALETTECHANGED消息。
case WM_PALETTECHANGED:
if ((HWND) wParam == hwnd)
break;
case WM_QUERYNEWPALETTE:
hdc = GetDC(hwnd);
f = DrawDibRealize (hdd,hdc,FALSE) > 0;
ReleaseDC (hwnd,hdc);
if (f)
InvalidateRect ( hwnd,NULL,TRUE);
break;
显示设备绘制
下面例子用DrawDibrealize函数在显示一个位图序列之前准备DrawDib DC.
hdc = GetDC(hwnd);
DrawDibBegin(hdd,hdc,dxDest,dyDest,lpbi,dxSrc,dySrc,NULL);
DrawDibRealize(hdd,hdc,fBackground);
DrawDibDraw(hdd,hdc,xDst,yDst,dxDst,dyDst,lpbi,lpBits,
xSrc,ySrc,dxSrc,dySrc,DDF_SAME_DRAW|DDF_SAME_HDC);
DrawDibDraw(hdd,hdc,xDst,yDst,dxDst,dyDst,lpbi,lpBits,
xSrc,ySrc,dxSrc,dySrc,DDF_SAME_DRAW|DDF_SAME_HDC);
DrawDibDraw(hdd,hdc,xDst,yDst,dxDst


下面给出一个实例的关键片段加以说明:(在Visual C++ 4.2 下Windows95或Windows NT环境下通过。)
void CTestDrawDibView::OnDraw(CDC* pDC)
{
CTestDrawDibDoc* pDoc = GetDocument();//得到文档指针
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
m_DibMem = pDoc->m_Buf;//得到DIB的内存
if (m_DibMem == NULL)
{
//AfxMessageBox("Error in m_DibMem");
return;
}
UINT ffset = pDoc->m_Off; //得到DIB数据的偏移
int xDst,yDst,dxDst,dyDst,xSrc,ySrc,dxSrc,dySrc;
LPBITMAPINFOHEADER lpbi;
LPVOID lpDibMem;
LPVOID lpbits=NULL;
// get the Windows width & height 得到窗口的宽高
RECT rect;
GetClientRect(&rect);
xDst = yDst = 0;
dxDst = rect.right - rect.left;
dyDst = rect.bottom - rect.top;
// Get Dib info得到DIB的信息
xSrc = ySrc =0;
lpDibMem = GlobalLock(m_DibMem);//锁定内存得到指针 lpbi = (LPBITMAPINFOHEADER)lpDibMem;//得到DIB信息
dxSrc = lpbi->biWidth;
dySrc = lpbi->biHeight;
lpbits = (LPSTR)lpDibMem + offset - sizeof(BITMAPFILEHEADER);
// Draw Dib绘DIB
HDC hdc = NULL;
hdc = pDC->m_hDC;
/*
// Using SetDIBToDevice使用SetDIBToDevice函数为对照
int line = SetDIBitsToDevice(hdc,
xDst,
yDst,
dxSrc,
dySrc,
xSrc,
ySrc,
0,
dySrc,
lpdib,//lpbits,
(LPBITMAPINFO)lpbi,
DIB_RGB_COLORS);
if(0 == line)
{
AfxMessageBox("Error in SetDIBsToDevice");
}
*/
/*
// Using StretchDIBits使用StretchDIBits函数为对照
int line = StretchDIBits(hdc,
xDst,
yDst,
dxDst,
dyDst,
xSrc,
ySrc,
dxSrc,
dySrc,
lpbits,
(LPBITMAPINFO)lpbi,
DIB_RGB_COLORS,
SRCCOPY);
if(0 == line)
{
AfxMessageBox("Error in SetDIBsToDevice");
}
*/
// Using DrawDib使用DrawDib
// Set Dawing flag设置绘制标志
UINT wFlags;
//标志意义参见前面的函数参考,以下两个标志可绘出图象,
//其余标志在这种情况下绘不出图象。
wFlags = DDF_DONTDRAW;
//wFlags = DDF_NOTKEYFRAME;
HDRAWDIB hdd = DrawDibOpen();
if (hdd != NULL)
{
BOOL Suc = TRUE;
//具体参数请参见前面函数参考
Suc = DrawDibDraw(hdd,
hdc,
xDst,
yDst,
dxDst,
dyDst,
lpbi,
lpbits,
xSrc,
ySrc,
dxSrc,
dySrc,
wFlags);
if(Suc == FALSE) AfxMessageBox("DrawDib Failed");
/* //时间测试
DRAWDIBTIME time;
DrawDibTime(hdd ,&time);
char buf[256];
sprintf(buf,"Count %dDraw %dDecompress %d
Dither %dStretch %dBlt %d SetDIBits %d",
time.timeCount,time.timeDraw,
time.timeDecompress,time.timeDither,
time.timeStretch,time.timeBlt,
time.timeSetDIBits);
AfxMessageBox(buf);
*/
DrawDibClose(hdd);
}
else
AfxMessageBox("Error in DrawDibOpen");
GlobalUnlock(m_DibMem);//释放DIB句柄
}


附:函数参考:
DrawDibBegin
这个DrawDib函数改变一个DrawDib DC的参数或初始化一个新的DrawDib DC.
BOOL DrawDibBegin(
HDRAWDIB hdd,
HDC hdc,
int dxDest,
int dyDest,
LPBITMAPINFOHEADER lpbi,
int dxSrc,
int dySrc,
UINT wFlags
);
参数
hdd DrawDib DC的句柄
hdc 绘图DC的句柄。此参数为可选。
dxDst和dyDst 在MM_TEXT方式下目的矩形的宽度和高度。
lpbi 包含图象格式的BITMAPINFOHEADER结构的地址。DIB颜色表紧跟图象格式,并且biHeight成员必须为一正值。 dxSrc和dySrc 源矩形的宽度和高度(以象素为单位)。
wFlags 函数调用的可用标志。定义了以下的值:
DDF_ANIMATE 允许调色板动画。如果这个值被设置,通过在LOGPALETTE结构中设置palPalEntry成员PC_RESERVED标志,则DrawDib保存了尽可能多的入口,调用drawDibChangePalette函数就可实现调色板动画。如果应用程序用了DrawDibBegin函数协同DrawDibDraw函数,最好在DrawDibBegin中设置这个值而不在DrawDibDraw中。
DDF_BACKGROUNDPAL 实现作为背景的调色板,保留当前显示所使用的调色板不变。(这个值与DDF_SAME_HDC互斥。)
DDF_BUFFER 使DrawDib使用屏幕缓冲,这样DDF_UPDATE才可使用。这关闭了解压和直接绘屏。如果DrawDib不能创建一个脱屏缓冲,就解压或直接绘屏。
DDF_DONTDRAW 当前图象未绘,但已解压。DDF_UPDATE能够以后被用来绘图象。这个标志取代了DDF_PREROLL标志。
DDF_FULLSCREEN 不被支持。
DDF_HALFTONE 不管DIB的调色板如何而把DIB抖动成标准调色板。如果应用程序用DrawDibBegin协同DrawDibDraw,在DrawDibBegin中设置这个值而不在DrawDibDraw中。
DDF_JUSTDRAWIT 用GDI绘这图象。禁止DrawDib函数解压,拉伸或抖动图象。这实际上剥夺了DrawDib区别于StrechDIBits函数的能力。
DDF_SAME_DRAW 让DrawDibDraw使用当前的绘制参数。只有当从使用DrawDibDraw或DrawDibBegin起,lpbi、dxDext、dyDest、dxSrc和dySrc就未改变才用这个值。这个标志取代了DDF_SAME_DIB和DDF_SAME_SIZE标志。
DDF_SAME_HDC 使用当前DC句柄以及与当前句柄相关联的调色板。
DDF_UPDATE 最后缓存的图象需要绘制。如果用这个值绘制失败,则缓冲的图象不在有效,并且在显示被更新前,需要指定一幅新的图象。
返回值
成功返回TRUE,否则FALSE。
注 这个函数准备由lpbi指定要绘往DC的DIB。图象已经拉伸成由dxDest和dyDest所指定的大小。如果dxDest和dyDest被设置成-1,DIB则被按原比例绘制。
可通过重新使用DrawDibBegin,指定新的标志和改变至少一个以下的设置:dxDest、dyDest、lpbi、dxSrc或dySrc来更新DrawDib DC的标志。
如果DrawDibBegin的参数未被改变,再次调用这个函数将不起作用。
DrawDibChangePalette
这个函数设置绘DIB所用的调色板。
BOOL DrawDibChangePalette(
HDRAWDIB hdd,
int iStart,
int iLen,
LPPALETTEENTRY lppe
);
参数:
hdd DrawDib DC的句柄。
iStart 调色板开始数。
iLen 调色板的数目。
lppe 调色板阵列的地址。
返回值
成功返回TRUE,否则FALSE。
注 只有当当前DrawDib调色板是调用DrawDibRealize函数实现时,这个函数改变物理调色板。
如果颜色表没有改变,下次没有指定DDF_SAME_DRAW的DrawDibDraw函数将隐含地调用DrawDibBegin函数。
DrawDibClose
这个函数关闭一个DrawDib DC并释放DrawDib申请的资源。
BOOL DrawDibClose(
HDRAWDIB hdd
);
参数
hdd DrawDib DC的句柄。
返回值
成功返回TRUE,否则FALSE。
DrawDibDraw
这个函数将DIB绘至屏幕。
BOOL DrawDibDraw(
HDRAWDIB hdd,
HDC hdc,
int xDst,
int yDst,
int dxDst,
int dyDst,
LPBITMAPINFOHEADER lpbi,
LPVOID lpBits,
int xSrc,
int ySrc,
int dxSrc,
int dySrc,
UINT wFlags
);
参数
hdd DrawDib DC的句柄。
hdc DC的句柄。
xDst和yDst 在MM_TEXT坐标系,目标矩形左上角的x和y坐标。
dxDst和dyDst 在MM_TEXT坐标系下,目标矩形的宽度和高度。如果dxDst为-1,则使用位图的宽度;如果dyDst为-1,则使用位图的高度。
lpbi 包含图象格式的BITMAPINFOHEADER结构的地址。DIB的颜色表紧跟着格式后,并且biHeight成员必须为正值;DrawDibDraw不能绘制倒置的DIB。
lpbits 包含位图位的缓冲的地址。
xSrc和ySrc 以象素为单位,源矩形左上角的x和y坐标。坐标(0,0)是位图的左上角。
dxSrc和dySrc 以象素为单位,源矩形的宽度和高度。
wFlags 可用的绘图标志。如下值被定义:
DDF_BACKGROUNDPAL 实现作为背景的调色板,保留当前显示所使用的调色板不变。这个值只有当DDF_SAME_HDC未被设置时才有效。
DDF_DONTDRAW 当前图象已解压但未绘。这个标志取代了DDF_PREROLL标志。
DDF_FULLSCREEN 不被支持。
DDF_HALFTONE 不管DIB的调色板如何而把DIB抖动成标准调色板。如果应用程序使用了DrawDibBegin,在DrawDibBegin中设置而不在DrawDibDraw中。
DDF_HURRYUP 数据并不需要被绘(它可以被绘)并且DDF_UPDATE不用理会这个信息。DrawDib只有当需要去构建另一帧时才检查这个值;否则,这个值被忽略。
这个值通常用来同步视频和音频。当同步数据时,应用程序应当用这个值发送图象以防止驱动器需要缓冲帧来解压后续帧。
DDF_NOTKEYFRAME. DIB数据不是关键帧。
DDF_SAME_HDC 使用当前DC句柄以及与当前句柄相关联的调色板。
DDF_SAME_DRAW 让DrawDibDraw使用当前的绘制参数。只有当从使用DrawDibDraw或DrawDibBegin起,lpbi、dxDext、dyDest、dxSrc和dySrc就未改变才用这个值。DrawDibDraw经常检查这些参数,如果它们改变了,DrawDibBegin则准备绘图的DrawDib DC。这个标志取代了DDF_SAME_DIB和DDF_SAME_SIZE标志。
DDF_UPDATE 最后缓存的图象需要绘制。如果用这个值绘制失败,则缓冲的图象不在有效,并且在显示被更新前,需要指定一幅新的图象。 返回值
成功返回TRUE,否则FALSE。
注 DDF_DONTDRAW使DrawDibDraw解压但不显示一幅图象。一个调用DrawDibDraw的序列是指定DDF_UPDATE来显示图象。
如果DrawDib DC没有指定一个屏幕缓冲,指定DDF_DONTDRAW会造成这帧被立即绘到屏幕。序列调用DrawDibDraw指定DDF_UPDATE会失败。
尽管DDF_UPDAT和DDF_DONTDRAW可以在不同时间设置,它们可以一起用来创建脱屏图象。当脱屏图象完成后,可以调用DrawDibDraw来显示图象。
DrawDibEnd
这个函数清除由DrawDibBegin或DrawDibDraw函数设置的标志和DrawDib DC的其它设置。
BOOL DrawDibEnd(
HDRAWDIB hdd
);
参数
hdd 要释放的DrawDib DC的句柄。
返回值
成功返回TRUE,否则FALSE。
DrawDibGetBuffer
这个函数清除由DrawDib用来解压的缓冲的地址。
LPVOID DrawDibGetBuffer(
HDRAWDIB hdd,
LPBITMAPINFOHEADER lpbi,
DWORD dwSize,
DWORD dwFlags
);
参数
hdd 要释放的DrawDib DC的句柄。
lpbi BITMAPINFO结构的地址。这个结构由BITMAPINFOHEADER结构和位图使用的256色调色板所定义的颜色表。 dwSize 通过lpbi的BITMAPINFO结构所指的字节大小。
dwFlags 保留,必须为0。
返回值
返回缓冲的地址或者如果没有用到缓冲返回NULL。如果lpbi不为NULL,它填充了一个描绘缓冲的BITMAPINFO的结构。
DrawDibGetPalette
这个函数清除由DrawDib DC所使用的调色板。
HPALETTE DrawDibGetPalette(
HDRAWDIB hdd
);
参数
hdd 要释放的DrawDib DC的句柄。
返回值
成功返回一个调色板句柄,否则返回NULL。
注 这个函数假设DrawDib DC包含了一个有效的调色板,隐含着这样的一个条件:对这个函数的调用必须在DrawDibDraw或DrawDibBegin函数之后。
DrawDibOpen
这个函数打开DrawDib库为使用和创建一个绘图的DrawDib DC作准备。
HDRAWDIB DrawDibOpen(VOID);
参数
这个函数不需要参数。
返回值
成功返回一个DrawDib DC的句柄,否则为NULL。
注 当同时绘多个DIB时,为同时在屏的每个图象创建一个DrawDib DC。
DrawDibProfileDisplay
这个函数决定了当用DrawDib函数时显示系统的设置。
BOOL DrawDibProfileDisplay(
LPBITMAPINFOHEADER lpbi
);
参数
lpbi 包含位图信息的BITMAPINFOHEADER结构。可以通过指定NULL来确认配置信息是当前的。如果配置信息不是当前的,DrawDib会重新运行配置测试来得到当前设置信息。如果把这个参数设为NULL来调用DrawDibProfileDisplay返回值是没有意义的。
返回值
返回值指出了这个显示系统的最快绘制和拉伸能力。如果位图格式不被支持,这个值为0或一个或更多的下列值:
PD_CAN_DRAW_DIB DrawDib能用这种格式绘图象。拉伸可能被支持或不被支持。
PD_CAN_STRETCHDIB DrawDib能用这种格式拉伸或绘制图象。
PD_STRETCHDIB _1_1_OK StretchDIBits用这种格式绘未拉伸的图象快于另一种方式。
PD_STRETCHDIB _1_2_OK StretchDIBits用这种格式绘以1:2拉伸的图象快于另一种方式。
PD_STRETCHDIB _1_N_OK StretchDIBits用这种格式绘以1:N拉伸的图象快于另一种方式。
DrawDibRealize
这个函数为用指定DC实现DrawDib DC 的调色板。
UINT DrawDibRealize (
HDRAWDIB hdd ,
HDC hdc ,
BOOL fBackground
) ;
参数
hdd DrawDib DC hdd DrawDib DC的句柄。
hdc 包含调色板的DC的句柄。
fBackground 背景调色板标志。如果此值非零,此调色板为背景调色板。如果此值为零并且DC与另一个窗口相连,当窗口拥有输入焦点时逻辑调色板变为背景调色板。(当窗口风格是CS_OWNDC或当DC是用GetDC函数得到的时,一个DC就与一个窗口相连)。


使用过ScanLine没有,我用它可以达到30帧/秒的时时动态生成的画面。
procedure TForm1.Button1Click(Sender: TObject);
var
x,y : Integer;
BitMap : TBitMap;
P : PByteArray;
begin
BitMap := TBitMap.create;
try
BitMap.LoadFromFile('C:\Program Files\Common Files\Borland Shared\Images\Splash\256color\factory.bmp');
for y := 0 to BitMap.Height -1 do
begin
P := BitMap.ScanLine[y];
for x := 0 to BitMap.Width -1 do
P[x] := y;
end;
Canvas.Draw(0,0,BitMap);
finally
BitMap.Free;
end;
end;


试试先!


gz


up


up


没有人要分了,呵呵


unit DrawDib;
interface
uses
Windows;
// DrawDib flags
const
DDF_UPDATE = $0002; // re-draw the last DIB
DDF_SAME_HDC = $0004; // HDC same as last call (all setup)
DDF_SAME_DRAW = $0008; // draw params are the same
DDF_DONTDRAW = $0010; // dont draw frame, just decompress
DDF_ANIMATE = $0020; // allow palette animation
DDF_BUFFER = $0040; // always buffer image
DDF_JUSTDRAWIT = $0080; // just draw it with GDI
DDF_FULLSCREEN = $0100; // use DisplayDib
DDF_BACKGROUNDPAL = $0200; // Realize palette in background
DDF_NOTKEYFRAME. = $0400; // this is a partial frame. update, hint
DDF_HURRYUP = $0800; // hurry up please!
DDF_HALFTONE = $1000; // always halftone
DDF_PREROLL = DDF_DONTDRAW; // Builing up a non-keyframe
DDF_SAME_DIB = DDF_SAME_DRAW;
DDF_SAME_SIZE = DDF_SAME_DRAW;
// display profiling
PD_CAN_DRAW_DIB = $0001; // if you can draw at all
PD_CAN_STRETCHDIB = $0002; // basicly RC_STRETCHDIB
PD_STRETCHDIB_1_1_OK = $0004; // is it fast?
PD_STRETCHDIB_1_2_OK = $0008;
PD_STRETCHDIB_1_N_OK = $0010;
type
hDrawDib = THandle;
TDrawDibTime = record
timeCount: LongInt; // see below
timeDraw: LongInt; // time to draw bitmaps
timeDecompress: LongInt; // time to decompress bitmaps
timeDither: LongInt; // time to dither bitmaps
timeStretch: LongInt; // time to stretch bitmaps
timeBlt: LongInt; // time to transfer bitmaps (BitBlt)
timeSetDIBits: LongInt; // time to transfer bitmaps (SetDIBits)
end;
function DrawDibBegin(hdd: hDrawDib; hDC: THandle; dxDest, dyDest: Integer;
var lpbi: TBitmapInfoHeader; dxSrc, dySrc: Integer; wFlags: UInt): Boolean; stdcall;
function DrawDibChangePalette(hdd: hDrawDib; iStart, iLen: Integer;
var lppe: TPaletteEntry): Boolean; stdcall;
function DrawDibClose(hdd: hDrawDib): Boolean; stdcall;
function DrawDibDraw(hdd: hDrawDib; hDC: THandle; xDst, yDst, dxDst, dyDst: Integer;
var lpbi: TBitmapInfoHeader; Bits: Pointer; xSrc, ySrc, dxSrc, dySrc: Integer;
wFlags: UInt): Boolean; stdcall;
function DrawDibEnd(hdd: hDrawDib): Boolean; stdcall;
function DrawDibGetBuffer(hdd: hDrawDib; var lpbi: TBitmapInfoHeader;
dwSize, dwFlags: DWord): Pointer; stdcall;
function DrawDibGetPalette(hdd: hDrawDib): THandle; stdcall;
function DrawDibOpen: hDrawDib; stdcall;
function DrawDibProfileDisplay(var lpbi: TBitmapInfoHeader): Boolean; stdcall;
function DrawDibRealize(hdd: hDrawDib; hDC: THandle; fBackground: Bool): UInt; stdcall;
function DrawDibSetPalette(hdd: hDrawDib; hpal: THandle): Boolean; stdcall;
function DrawDibStart(hdd: hDrawDib; rate: LongInt): Boolean; stdcall;
function DrawDibStop(hdd: hDrawDib): Boolean; stdcall;
function DrawDibTime(hdd: hDrawDib; var lpddtime: TDrawDibTime): Boolean; stdcall;
implementation
const
DLL = 'MsVfW32.dll';
function DrawDibBegin; external DLL name 'DrawDibBegin';
function DrawDibChangePalette; external DLL name 'DrawDibChangePalette';
function DrawDibClose; external DLL name 'DrawDibClose';
function DrawDibDraw; external DLL name 'DrawDibDraw';
function DrawDibEnd; external DLL name 'DrawDibEnd';
function DrawDibGetBuffer; external DLL name 'DrawDibGetBuffer';
function DrawDibGetPalette; external DLL name 'DrawDibGetPalette';
function DrawDibOpen; external DLL name 'DrawDibOpen';
function DrawDibProfileDisplay; external DLL name 'DrawDibProfileDisplay';
function DrawDibRealize; external DLL name 'DrawDibRealize';
function DrawDibSetPalette; external DLL name 'DrawDibSetPalette';
function DrawDibStart; external DLL name 'DrawDibStart';
function DrawDibStop; external DLL name 'DrawDibStop';
function DrawDibTime; external DLL name 'DrawDibTime';
end.
--------------B04D41ED428BD1DFBB24A362--


var
hdd :THandle;
dc :HDC;
begin
hdd := DrawDibOpen; //打开Draw句柄
dc := GetDC(Form1.Handle); //读取显示句柄
if DrawDibDraw(hdd,
dc,
left, //原图像
top,
width,
height,
@bmih, //原图像头信息结构
@data, //原图像数据
left, //显示
top,
width,
height,
Flag //标志
);