bitmap知识

 

GDI基本概念及思想

 

编写代码的一般步骤:先用CreateDC创建(或GetDC获取)device contentDC,然后用GetObject获取(或使用创建object的函数创建)需要的object,并用SelectObject将获取的object选入device content(DC),再使用object进行相应的画图操作,最后用SelectObject将原来的object重新选入DC,并deleterelease删除或释放前面创建或获取的DC

 

1.    关于device context (DC)设备内容:用来显示位图的地方.

 

四种设备内容:显示器设备内容、打印机设备内容、内存设备内容、Information设备内容,常用的有显示器DC和内存DC.

Device Context Types: There are four types of DCs: display, printer, memory (or compatible), and information.

 

Device context

Description

Display

Supports drawing operations on a video display.

Printer

Supports drawing operations on a printer or plotter.

Memory

Supports drawing operations on a bitmap.

Information

Supports the retrieval of device data.

 

其中需要注意的一种类型是: Memory Device Contexts,将在bitmap处理中详细介绍。

 

创建和获取DC的相关函数:

CreateDC,CreateCompatibleDC,GetDC,GetCurrentDC.

其中CreateCompatibleDC用于创建内存设备内容.

刷新、释放和删除DC的相关函数:

ResetDC,ReleaseDC,DeleteDC.前者当DC有变动时用来重置DC,后者用来释放使用万完的DC.

DeleteDCCreateDC对应使用
ReleaseDC
GetDC对应使用

 

2.关于graphical objectGDI objects):

包括:pen,brush,bitmap,palette,region,path.

 

获取、选择和删除object的相关函数:

GetObjectGetCurrentObjectSelectObjectDeleteObject

 

关于SelectObject需要注意的地方:在使用完object后需要将原来默认的object重新选入DC替换掉新的objectbitmap只可以选入"内存DC",一个bitmap不能同时选入多个DC.

This function returns the previously selected object of the specified type. An application should always replace a new object with the original, default object after it has finished drawing with the new object. An application cannot select a bitmap into more than one DC at a time.

 

如果object是创建的,则使用完后必须删除创建的object,创建object的一些函数如下:

 

Graphic object

Function

Bitmap

CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDiscardableBitmap, CreateDIBitmap

Brush

CreateBrushIndirect, CreateDIBPatternBrush, CreateDIBPatternBrushPt, CreateHatchBrush, CreatePatternBrush, CreateSolidBrush

Color Palette

CreatePalette

Font

CreateFont, CreateFontIndirect

Pen

CreatePen, CreatePenIndirect, ExtCreatePen

Region

CreateEllipticRgn, CreateEllipticRgnIndirect, CreatePolygonRgn, CreatePolyPolygonRgn, CreateRectRgn, CreateRectRgnIndirect, CreateRoundRectRgn

 

 

下面重点介绍GDI中关于bitmap的处理:

关于BitmapDevice Context:

 

1.关于bitmap的一些基本概念:

DIB:设备无关位图。

DDB:设备相关位图。

扫描顺序scan order:bottom-up DIBtop-down DIB

DDB总是top-down.

 

2.    关于drawing surface:

 

可以理解为绘制图象的区域,程序调用CreateDCGetDC后,系统在返回DC句柄(handle)前先将一个drawing surface(绘制区域)选入DC,再返回DC句柄,后面进行的绘制操作将限制在这个drawing surface(绘制区域)中。例如:如果使用CreateDC创建一个关于显示器的DCdevice content),那么绘制区域为显示器的整个屏幕,而如果使用GetDC获取一个对话框窗口或客户区的DC,那么绘制区域则为对话框窗口或客户区。

To creates a DC, call the CreateDC function; to retrieve a DC, call the GetDC function. Before returning a handle that identifies that DC, the system selects a drawing surface into the DC. If the application called the CreateDC function to create a device context for a VGA display, the dimensions of this drawing surface are 640-by-480 pixels. If the application called the GetDC function, the dimensions reflect the size of the client area.

 

3.关于内存设备内容。

 

因为与某个具体的device content相关,所以又叫作compatible device context.可以象操作其它device content一样操作它,效果相同,唯一的区别是它不会显示出来,必须用BitBlt之类的函数将它的内容COPY(复制)到它相关的具体device content中才能显示出来。它的主要目的是用来暂存图象数据。

 

It is an array of bits in memory that an application can use temporarily to store the color data for bitmaps created on a normal drawing surface. Because the bitmap is compatible with the device, a memory DC is also sometimes referred to as a compatible device context.

使用CreateCompatibleDC创建Memory Device Contexts

 

4.关于bitmap的创建。

一些关于bitmap创建的函数:

CreateBitmap, CreateBitmapIndirect两个基本相同,都创建DDBdevice-

dependent bitmap),只能使用selectobject将创建的bitmap选入相关的(具有相同格式)device

CreateCompatibleBitmapCreateDIBitmap也都创建DDB,但前者指定了一个相关的device,而后者是从一个DIB创建DDB.

CreateDIBSection才真正创建DIB.

 

BitBlt

Performs a bit-block transfer.

CreateBitmap

Creates a bitmap.

CreateBitmapIndirect

Creates a bitmap.

CreateCompatibleBitmap

Creates a bitmap compatible with a device.

CreateDIBitmap

Creates a device-dependent bitmap (DDB) from a DIB.

CreateDIBSection

Creates a DIB that applications can write to directly.

LoadBitmap

Loads a bitmap from a module's executable file.

StretchBlt

Copies a bitmap and stretches or compresses it.

StretchDIBits

Copies the color data in a DIB.

其中BitBltStretchBltStretchDIBvits用来真正显示bitmap,而

LoadBitmap则用来加载资源文件中的bitmap

 

5.关于bitmap的存储。

The established bitmap file format consists of a BITMAPFILEHEADER structure followed by a BITMAPINFOHEADER, BITMAPV4HEADER, or BITMAPV5HEADER structure. An array of RGBQUAD structures (also called a color table) follows the bitmap information header structure. The color table is followed by a second array of indexes into the color table (the actual bitmap data).

The bitmap file format is shown in the following illustration.

图一

可以看出bitmapBITMAPFILEHEADER+BITMAPINFOHEADER(或其它bitmap header结构)+颜色表+指向颜色表的实际图象数据组成。

 

下面主要来看一看bitmap的四个组成部分:

 

一、关于BITMAPFILEHEADER结构:

 

 

typedef struct tagBITMAPFILEHEADER { 
    
    
  WORD    bfType; 
    
    
  DWORD   bfSize; 
    
    
  WORD    bfReserved1; 
    
    
  WORD    bfReserved2; 
    
    
  DWORD   bfOffBits; 
    
    
} BITMAPFILEHEADER, *PBITMAPFILEHEADER; 
    
    

 

Members

bfType

指定文件类型,必须是0x424D,即字符串“BM”,也就是说所有.bmp文件的头两个字节都是“BM”。

Specifies the file type, must be BM.

bfSize

指定文件大小,包括这14个字节。单位:bytes

Specifies the size, in bytes, of the bitmap file.

bfReserved1

Reserved; must be zero.

bfReserved2

Reserved; must be zero.

bfOffBits

为从文件头到实际的位图数据的偏移字节数,即图中前三个部分的长度之和。

Specifies the offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits.

 

 

二、关于BITMAPINFOHEADER结构:

 

typedef struct tagBITMAPINFOHEADER{

  DWORD  biSize;

  LONG   biWidth;

  LONG   biHeight;

  WORD   biPlanes;

  WORD   biBitCount;

  DWORD  biCompression;

  DWORD  biSizeImage;

  LONG   biXPelsPerMeter;

  LONG   biYPelsPerMeter;

  DWORD  biClrUsed;

  DWORD  biClrImportant;

} BITMAPINFOHEADER, *PBITMAPINFOHEADER;

 

Members

biSize

此结构(BITMAPINFOHEADER)的大小,单位:byte

Specifies the number of bytes required by the structure.

biWidth

bitmap的宽,单位:pixel

Specifies the width of the bitmap, in pixels.

biHeight

bitmap的高,单位:pixel

Specifies the height of the bitmap, in pixels.

biPlanes

目标设备(即bitmap最终绘制的设备)平面的数目。一般为1,例如显示器和打印机都只有一个显示平面,对话框窗口和客户区也只有一个面,因此biPlanes的值必须设为1.

Specifies the number of planes for the target device. This value must be set to 1.

 

biBitCount

表示一个像素的颜色需要用到的位数,取决于bitmap的颜色数目(biBitCount bitmap颜色数目的关系:2^ biBitCount等于bitmap的颜色数目,很简单,因为二进制1 bit(位)只能表示2^1两个值,2位可以表示2^2个值……)。例如,如果是黑白二色图,则表示一个像素的颜色只需要1位,即biBitCount1,如果bitmap16色的话,则每一个像素需要4位才能表示其颜色。

常用的值为1(黑白二色图), 4(16色图), 8(256), 24(真彩色图)

单位:bits

biCompression

指定位图是否压缩,有效的值为BI_RGBBI_RLE8BI_RLE4BI_BITFIELDS(都是一些Windows定义好的常量)。要说明的是,Windows位图可以采用RLE4RLE8的压缩格式,但用的不多。一般bitmap为第一种不压缩的情况,即biCompressionBI_RGB的情况。

biSizeImage

指定实际的位图数据占用的字节数,如果biCompressionBI_RGB,则该项可能为零。因为BI_RGB为不压缩,所以biSizeImage其实也可以从以下的公式中计算出来:

biSizeImage=biWidth’ × biHeight

要注意的是:上述公式中的biWidth’必须是4的整倍数(所以不是biWidth,而是biWidth’,表示大于或等于biWidth的,最接近4的整倍数。举个例子,如果biWidth=240,则biWidth’=240;如果biWidth=241biWidth’=244)。如果biCompression为压缩值,则上面的等式不成立。

单位:bytes

biXPelsPerMeter

指定目标设备的水平分辨率,单位是每米的象素个数。

biYPelsPerMeter

指定目标设备的垂直分辨率,单位同上。

biClrUsed

指定本图象实际用到的颜色数,即颜色表(或调色板)中颜色的数目。如果该值为零,则用到的颜色数为2biBitCount

biClrImportant

指定本图象中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。

 

三、关于颜色表(即调色板palette

The RGBQUAD structure describes a color consisting of relative intensities of red, green, and blue.

RGBQUAD结构用来表示颜色,bitmap结构的第三部分是一个RGBQUAD数组,数组中元素的数目就是bitmap的颜色数,也就是说数组中每一个元素(每一个RGBQUAD)代表一种颜色。RGBQUAD结构的大小为4字节,所以bitmap第三部分调色板的大小等于bitmap的颜色数目乘以4.举个例子:如果是黑白二色图,则

Bitmap的调色板大小为8字节;如果是16色图,则bitmap的调色板大小为64字节。

typedef struct tagRGBQUAD {

  BYTE    rgbBlue;

  BYTE    rgbGreen;

  BYTE    rgbRed;

  BYTE    rgbReserved;

} RGBQUAD;

Members

rgbBlue

此颜色的蓝色分量,取值范围0255,刚好可以用一个BYTE表示,因此类型为BYTE.

Specifies the intensity of blue in the color.

rgbGreen

此颜色的绿色分量,同上。

Specifies the intensity of green in the color.

rgbRed

此颜色的红色分量,同上。

Specifies the intensity of red in the color.

rgbReserved

Reserved; must be zero.

 

注意:真彩色图(24位色图)没有第三部分,也就是说没有调色板。

 

 

四、关于实际位图数据(color-index array)部分:

 

The color-index array associates a color, in the form of an index to an RGBQUAD structure, with each pixel in a bitmap. Thus, the number of bits in the color-index array equals the number of pixels times the number of bits needed to index the RGBQUAD structures. For example, an 8x8 black-and-white bitmap has a color-index array of 8 * 8 * 1 = 64 bits, because one bit is needed to index two colors. The Redbrick.bmp, mentioned in About Bitmaps, is a 32x32 bitmap with 16 colors; its color-index array is 32 * 32 * 4 = 4096 bits because four bits index 16 colors.

 

位图中的每一个像素都是一个指向颜色表某一项的索引值,即实际的位图数据。颜色表即RGBQUAD数组中不同的项(或元素)代表不同的颜色,因此不同颜色的像素指向颜色表中不同的项,相同颜色的像素指向指向的项是相同的。

 

这一部分(即实际位图数据)的大小等于像素的数目乘以表示bitmap所有颜色(即颜色表中颜色的数目)所需要的位数(bits)。例如:一个32×32bitmap,如果调色板中的颜色数为16,即16色图,因为表示16色需要4bits,那么该位图的实际数据大小=32×32×4 = 4096 bits = 512 bytes

 

思考:

位图结构为什么要定义成这四个部分?这样有什么好处?BITMAPFILEHEADER

BITMAPINFOHEADER各定义了bitmap的哪些方面?为什么要引入调色板?

 

 

 

下面的内容摘录自《数字图象处理编程入门》

我们知道,普通的显示器屏幕是由许许多多点构成的,我们称之为象素。显示时采用扫描的方法:电子枪每次从左到右扫描一行,为每个象素着色,然后从上到下这样扫描若干行,就扫过了一屏。为了防止闪烁,每秒要重复上述过程几十次。例如我们常说的屏幕分辨率为640×480,刷新频率为70Hz,意思是说每行要扫描640个象素,一共有480行,每秒重复扫描屏幕70次。

我们称这种显示器为位映象设备。所谓位映象,就是指一个二维的象素矩阵,而位图就是采用位映象方法显示和存储的图象。举个例子,图1.1是一幅普通的黑白位图,图1.2是被放大后的图,图中每个方格代表了一个象素。我们可以看到:整个骷髅就是由这样一些黑点和白点组成的。

那么,彩色图是怎么回事呢?

我们先来说说三元色RGB概念。

我们知道,自然界中的所有颜色都可以由红、绿、蓝(RGB)组合而成。有的颜色含有红色成分多一些,如深红;有的含有红色成分少一些,如浅红。针对含有红色成分的多少,可以分成0255256个等级,0级表示不含红色成分;255级表示含有100%的红色成分。同样,绿色和蓝色也被分成256级。这种分级概念称为量化。

这样,根据红、绿、蓝各种不同的组合我们就能表示出256×256×256,约1600万种颜色。这么多颜色对于我们人眼来说已经足够丰富了。

1.1     常见颜色的RGB组合值

颜色

R

G

B

255

0

0

0

255

0

绿

0

0

255

255

255

0

255

0

255

0

255

255

255

255

255

0

0

0

128

128

128

你大概已经明白了,当一幅图中每个象素赋予不同的RGB值时,能呈现出五彩缤纷的颜色了,这样就形成了彩色图。的确是这样的,但实际上的做法还有些差别。

让我们来看看下面的例子。

有一个长宽各为200个象素,颜色数为16色的彩色图,每一个象素都用RGB三个分量表示。因为每个分量有256个级别,要用8(bit),即一个字节(byte)来表示,所以每个象素需要用3个字节。整个图象要用200×200×3,约120k字节,可不是一个小数目呀!如果我们用下面的方法,就能省的多。

因为是一个16色图,也就是说这幅图中最多只有16种颜色,我们可以用一个表:表中的每一行记录一种颜色的RGB值。这样当我们表示一个象素的颜色时,只需要指出该颜色是在第几行,即该颜色在表中的索引值。举个例子,如果表的第0行为25500(红色),那么当某个象素为红色时,只需要标明0即可。

让我们再来计算一下:16种状态可以用4(bit)表示,所以一个象素要用半个字节。整个图象要用200×200×0.5,约20k字节,再加上表占用的字节为3×16=48字节.整个占用的字节数约为前面的1/6,省很多吧?

这张RGB的表,就是我们常说的调色板(Palette),另一种叫法是颜色查找表LUT(Look Up Table),似乎更确切一些。Windows位图中便用到了调色板技术。其实不光是Windows位图,许多图象文件格式如pcxtifgif等都用到了。所以很好地掌握调色板的概念是十分有用的。

有一种图,它的颜色数高达256×256×256种,也就是说包含我们上述提到的RGB颜色表示方法中所有的颜色,这种图叫做真彩色图(true color)。真彩色图并不是说一幅图包含了所有的颜色,而是说它具有显示所有颜色的能力,即最多可以包含所有的颜色。表示真彩色图时,每个象素直接用RGB三个分量字节表示,而不采用调色板技术。原因很明显:如果用调色板,表示一个象素也要用24位,这是因为每种颜色的索引要用24(因为总共有224种颜色,即调色板有224),和直接用RGB三个分量表示用的字节数一样,不但没有任何便宜,还要加上一个256×256×256×3个字节的大调色板。所以真彩色图直接用RGB三个分量表示,它又叫做24位色图。

 

 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值