Microsoft Windows GDI+提供了Image类用于进行光栅图像(位图)和矢量图像(图元文件)。Bitmap类和Metafile 类都是继承自Image类。Bitmap类通过提供加载、储存和管理光栅图像的其它方法,增强了Image类的功能。Metafile类别通过提供记录和检验矢量图像的其它方法,增强Image类别的功能。
位图是像素的矩形阵列,而每个像素都由位数组指定其颜色。单个像素的组成位数将决定指派给该像素的色彩数目。例如,如果每个像素都是由 4 个字节成,则可将16种不同的颜色指派给该像素 (2^4 = 16)。下表将显示一些范例,说明可指派给由指定位数所表示的像素的色彩数目。
Bits per pixel |
Number of colors that can be assigned to a pixel |
1 |
2^1 = 2 |
2 |
2^2 = 4 |
4 |
2^4 = 16 |
8 |
2^8 = 256 |
16 |
2^16 = 65,536 |
24 |
2^24 = 16, 777, 216 |
储存位图的磁盘文件通常都会包含一个或多个信息区块,其中存放每个像素位数、每行的像素数目和数组的行数等信息。这类文件可能也会包含颜色表(又称为调色板)。颜色表会将位图中的数字映射为特定色彩。下图显示一个放大的影像及其位图和色表。每个像素都是由 4 位数字来表示,因此色表中共有 2^4 = 16 个色彩。表格中的每一个色彩都是用 24 位数字来表示:8 位用来表示红色、8 位用来表示绿色,还有 8 位用来表示蓝色。这些数字是以十六进制格式显示:A = 10、B = 11、C = 12、D = 13、E = 14、F = 15。
请看图片的第 3 行第 5 列的像素。位图中对应的数字为 1。我们可由色表得知 1 代表红色,因此该像素为红色。位图顶端列的所有项目都是 3。我们可由色表得知 3 表示蓝色,因此影像顶端列的所有像素都是蓝色。
注意事项:有些位图是以由下到上的格式储存;位图首行的数目表示的是图片末行的像素
将索引储存至色彩表的位图称为索引色位图。有些位图并不需要色表。例如,如果位图使用每像素 24 位,则该位图可储存色彩本身,而非存入色表的索引。下图显示直接储存色彩的位图 (每像素 24 位),而不是使用色表。该图同时显示对应影像的放大画面。在位图中,FFFFFF 表示白色、FF0000 代表红色、00FF00 为绿色,而 0000FF 则为蓝色。
您可以使用许多标准格式将位图储存在磁盘文件中。GDI+ 支持以下各种图片文件格式。
位图是 Windows 用来储存设备无关和与应用程序无关的图片的标准格式。文件头决定了指定的位图文件的每个像素位数 (1、4、8、15、24、32 或 64)。常见的位图文件为每像素 24 位。通常 BMP 档不会被压缩,因此并不适合透过因特网传输。
GIF是Web网页上常见的图片格式。GIF非常适用于线条图形,具有实色块的图片和色彩之间具有明显界线的图片。GIF可被压缩而且不会在压缩过程中遗失任何信息;解压后的影像将和原始影像完全相同。GIF的色彩可指定为透明,这样一来影像则可以显示该影像的Web网页作为背景色彩。GIF影像的序列可储存在单一档案中,作为动画GIF。GIF最多储存为每像素8位,这样便将它们限制在256色彩。
JPEG是一种压缩结构,适用于自然景观图片,例如扫描的照片。有些信息可能会在压缩过程中丧失,但肉眼并无法看出变化。JPEG可储存每像素24位,因此它们可以显示超过1千6百万个色彩。JPEG不支持透明效果或动画。
您可以设定JPEG图片文件的压缩比,但压缩比越高 (档案越小),便会丢失更多信息。通常肉眼无法辨识以20:1的压缩比所产生的图片和源文件之间的差异。下图将显示BMP图片和两个从该BMP图片压缩而来的JPEG图片。第一个JPEG的压缩比率为4:1,第二个JPEG的压缩比率约为8:1。
JPEG 压缩不适用于线条图形、实色块和明显的界线。下图将显示一个BMP和两个JPEG及一个 GIF。这两个JPEG和GIF都是从BMP压缩而来的。GIF的压缩比率为4:1、较小的JPEG 为4:1,较大的JPEG为8:3。请注意,GIF中的线条间仍然出现明显边界,但JPEG中的边界似乎比较模糊。
JPEG 是一种压缩公式,而非文件格式。JPEG档案交换格式(JFIF)才是通常来储存和传送图片的文件格式,它们是根据JPEG公式进行压缩。Web浏览器显示的JFIF文件将使用.jpg扩展名。
EXIF 是用于数字相机所拍摄的相片文件格式。EXIF 文件包含一个根据 JPEG规范来压缩的图片。EXIF文件同时还包含了照片信息 (拍摄日期、快门速度、曝光时间等信息) 和相机信息 (制造商、型号等信息)。
PNG格式保留了许多GIF格式的优点,同时提供比GIF更强大的功能。PNG文件和GIF文件同样都不会在压缩过程中丧失任何信息。PNG文件可储存每像素8、24或48位的色彩,以及每像素1、2、4、8或16位的灰阶。相较之下,GIF档只能使用每像素1、2、4或8位。PNG文件还可储存每个像素的Alpha值,指定该像素与背景色彩混合的程度。
PNG改进了GIF渐进式显示影像的功能;当PNG收到透过网络联机传送的影像时,可以显示较佳的影像效果。PNG文件可包含Gamma修正和色彩修正信息,这样一来可将影像正确地对应到各种不同的显示装置。
TIFF 是一种灵活且可扩充的格式,各种平台和图片处理应用程序都支持这种格式。TIFF 文件可储存每像素任意位数的图片,并可使用各种压缩算法。单一、多页的TIFF文件可储存数个影像。影像相关信息 (扫描仪制作、主机计算机、压缩类型、方向、每像素范例等等)也可储存在档案中,并可使用标记进行排列。TIFF格式可按照需要(如情况允许而且必须增加新的标记)进行扩充。
Microsoft Windows GDI+提供Metafile类来记录和显示图元文件。图元文件又称为矢量图片,这种图片被储存为一种绘图命令和设定的序列。Metafile对象中所记录的命令和设定可储存于内存或储存至文件或数据流。
GDI+ 可显示储存为下列格式的图元文件:
Windows Metafile Format (WMF)
Enhanced Metafile (EMF)
EMF+
GDI+可记录EMF和EMF+格式的图元文件,但无法记录WMF格式的图元文件。
EMF+是EMF的功能扩充,可用来储存GDI+记录。EMF+格式有两种变化:EMF+ Only 和 EMF+ Dual。EMF+ Only图元文件仅包含GDI+记录。此类图元文件可由GDI+显示,但无法使用GDI显示。EMF+ Dual图元文件包含GDI+和GD记录。EMF+ Dual图元文件的每个GDI+数据录都会与替代GDI记录配对。此类图元文件可同时由GDI+或GDI显示。
下列范例将存储一个设置语句和一条绘图命令到一个磁盘文件中。注意这里构造一个Graphics对象,而且是通过在构造函数中传递一个MetaFile对象作为参数来构造的。
myMetafile = new Metafile(L"MyDiskFile.emf", hdc);
myGraphics = new Graphics(myMetafile);
myPen = new Pen(Color(255, 0, 0, 200));
myGraphics->SetSmoothingMode(SmoothingModeAntiAlias);
myGraphics->DrawLine(myPen, 0, 0, 60, 40);
delete myGraphics;
delete myPen;
delete myMetafile;
如上例所示,Graphics类是将指令和设置保存到Metafile对象的关键。任何对Graphics对象进行的方法调用均被记录到Metafile对象中。同样地,您可以设置任何Graphics对象的属性并将这个设置保存到Metafile对象中。在Graphics对象被删除或者超出作用域的时候,将停止记录。
下列范例显示先前储存为档案的图元文件。图元文件的左上角显示在 (100, 100)。
Graphics myGraphics(hdc);
Image myImage(L"MyDiskFile.emf");
myGraphics.DrawImage(&myImage, 100, 100);
下列范例记录多个属性设置(剪切区域、世界变换和平滑模式)到Metafile对象中。然后代码将记录多个绘图指令,然后将这些指令和设置都保存到一个磁盘文件中。
myMetafile = new Metafile(L"MyDiskFile2.emf", hdc);
myGraphics = new Graphics(myMetafile);
myGraphics->SetSmoothingMode(SmoothingModeAntiAlias);
myGraphics->RotateTransform(30);
// Create an elliptical clipping region.
GraphicsPath myPath;
myPath.AddEllipse(0, 0, 200, 100);
Region myRegion(&myPath);
myGraphics->SetClip(&myRegion);
Pen myPen(Color(255, 0, 0, 255));
myGraphics->DrawPath(&myPen, &myPath);
for(INT j = 0; j <= 300; j += 10)
{
myGraphics->DrawLine(&myPen, 0, 0, 300 - j, j);
}
delete myGraphics;
delete myMetafile;
下列范例显示先前储存为档案的图元文件。
myGraphics = new Graphics(hdc);
myMetafile = new Metafile(L"MyDiskFile.emf");
myGraphics->DrawImage(myMetafile, 10, 10);
下图显示了前面代码的执行结果。注意观察抗锯齿效果、椭圆形裁剪和30度角旋转。
您可以使用Image类来加载和显示点阵图片(位图)和矢量图片(图元文件)。若要显示图片,您需要一个Graphics对象和一个Image对象。Graphics对象提供DrawImage方法来接收Image对象作为它的一个参数。
下列代码示例会示范如何从Climber.jpg文件建立一个Image对象并显示此图片。图片左上角目标点 (10, 10) 是由第二个和第三个参数指定。
Image myImage(L"Climber.jpg");
myGraphics.DrawImage(&myImage, 10, 10);
上面的代码执行效果如图:
您可以使用下列各种图形文件格式来建构Image对象:BMP、GIF、JPEG、EXIF、PNG、TIFF 和 ICON。
下列代码示例会示范如何从各种文件类型建立Image对象,并显示该图片。
Image myBMP(L"SpaceCadet.bmp");
Image myEMF(L"Metafile1.emf");
Image myGIF(L"Soda.gif");
Image myJPEG(L"Mango.jpg");
Image myPNG(L"Flowers.png");
Image myTIFF(L"MS.tif");
myGraphics.DrawImage(&myBMP, 10, 10);
myGraphics.DrawImage(&myEMF, 220, 10);
myGraphics.DrawImage(&myGIF, 320, 10);
myGraphics.DrawImage(&myJPEG, 380, 10);
myGraphics.DrawImage(&myPNG, 150, 200);
myGraphics.DrawImage(&myTIFF, 300, 200);
Image类提供Clone方法,可用来制作现有Image、Metafile或者Bitmap对象的副本。Clone方法在Bitmap类中进行了重载,变体之一具有来源矩形参数,可指定您要复制的原始位图区域。下列程序代码范例会示范如何藉由复制现有Bitmap上半部来建立Bitmap。然后同时显示这两个图象。
Bitmap* originalBitmap = new Bitmap(L"Spiral.png");
RectF sourceRect(
0.0f,
0.0f,
(REAL)(originalBitmap->GetWidth()),
(REAL)(originalBitmap->GetHeight())/2.0f);
Bitmap* secondBitmap = originalBitmap->Clone(sourceRect, PixelFormatDontCare);
myGraphics.DrawImage(originalBitmap, 10, 10);
myGraphics.DrawImage(secondBitmap, 100, 10);
上面的代码执行效果如图:
您可以使用Graphics类的DrawImage方法来绘制并定位图像。DrawImage是一个重载方法,因此可使用许多种方法提供自变量给它。DrawImage方法的其中一个变体可接收Image对象的地址和Rectangle对象的引用。矩形可指定绘图操作的目标位置;也就是说,它可以指定绘制图片的位置。如果目的矩形的大小和原始图片大小并不相同,该图片将缩放至适合目的矩形的大小。下列程序代码范例会示范如何绘制三次相同的图片:一次不使用缩放、一次使用放大,还有一次使用缩小:
Bitmap myBitmap(L"Spiral.png");
Rect expansionRect(80, 10, 2 * myBitmap.GetWidth(), myBitmap.GetHeight());
Rect compressionRect(210, 10, myBitmap.GetWidth() / 2, myBitmap.GetHeight() / 2);
myGraphics.DrawImage(&myBitmap, 10, 10);
myGraphics.DrawImage(&myBitmap, expansionRect);
myGraphics.DrawImage(&myBitmap, compressionRect);
上面代码执行效果如图:
有些DrawImage方法的变体具有来源矩形参数和目的矩形参数。来源矩形参数指定要绘制的原始图片区域。目的矩形指定用来绘制该图片区域的位置。如果目的矩形大小和来源矩形大小并不相同,图片将缩放至适合目的矩形的大小。
下列程序代码范例会示范如何从Runner.jpg文档构造一个Bitmap对象。整个图片从 (0, 0) 开始绘制,且不进行缩放。接着图片中的一小部分会绘制两次:一次使用缩小,另一次使用放大。
Bitmap myBitmap(L"Runner.jpg");
// The rectangle (in myBitmap) with upper-left corner (80, 70),
// width 80, and height 45, encloses one of the runner's hands.
// Small destination rectangle for compressed hand.
Rect destRect1(200, 10, 20, 16);
// Large destination rectangle for expanded hand.
Rect destRect2(200, 40, 200, 160);
// Draw the original image at (0, 0).
myGraphics.DrawImage(&myBitmap, 0, 0);
// Draw the compressed hand.
myGraphics.DrawImage(&myBitmap, destRect1, 80, 70, 80, 45, UnitPixel);
// Draw the expanded hand.
myGraphics.DrawImage(&myBitmap, destRect2, 80, 70, 80, 45, UnitPixel);
下列图标将显示未缩放的影像,以及经过缩小和放大的影像部分。