GDI+ 在Delphi程序的应用 -- 多帧(页)图像的分解与合成
在GDI+支持的各种图像格式,gif格式和tiff格式图像可包含多帧(页)图片,GDI+可以很方便的分解和合成多帧(页)图片。
下面是个简单的多帧(页)图片分解与合成例子:
unit main1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1
=
class
(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses Gdiplus, GdipTypes, ActiveX;
{$R
*
.dfm}
//
把多帧图像分解为单图像保存到文件
procedure TForm1.Button1Click(Sender: TObject);
var
I, Count: Integer;
Clsid: TClsid;
Parameters: TEncoderParameters;
Quality: Integer;
Image: TGpImage;
GUID: TGUID;
begin
//
打开图像文件
Image :
=
TGpImage.Create(
'
hbmap108.gif
'
);
try
//
获取图像所有帧维度的GUID,这里我们只取第一个
Image.GetFrameDimensionsList(@GUID,
1
);
//
通过获取维度的GUID,取得图像的帧(页)数量
Count :
=
Image.GetFrameCount(GUID);
//
下面设置自定义的编码参数,这里为1个参数
Parameters.Count :
=
1
;
//
设置参数唯一标志的GUID,这里为编码品质
Parameters.Parameter[
0
].Guid :
=
EncoderQuality;
//
设置参数值的数据类型为长整型
Parameters.Parameter[
0
].ValueType :
=
EncoderParameterValueTypeLong;
Parameters.Parameter[
0
].NumberOfValues :
=
1
;
//
设置参数的值:品质等级,最高为100,图像文件大小与品质成正比
Quality :
=
100
;
Parameters.Parameter[
0
].Value :
=
@Quality;
//
获取图像格式JPEG编码器的ClsID
GetEncoderClsid(
'
image/jpeg
'
, Clsid);
//
选择图像的各个帧为当前帧,并依次保存为jpg文件
for
I :
=
0
to Count
-
1
do
begin
Image.SelectActiveFrame(GUID, I);
Image.Save(
'
Hb
'
+
IntToStr(I)
+
'
.jpg
'
, Clsid, @Parameters);
end;
finally
Image.Free;
end;
end;
//
将单个图像合并为多帧图像,GDI+不支持GIF合成,只能合并为tiff格式
procedure TForm1.Button2Click(Sender: TObject);
var
Parameters: TEncoderParameters;
Value: TEncoderValue;
Img, tmp: TGpImage;
I: Integer;
Clsid: TClsid;
begin
//
下面设置自定义的编码参数,这里为1个参数
Parameters.Count :
=
1
;
//
设置参数唯一标志的GUID,这里为保存标记
Parameters.Parameter[
0
].Guid :
=
EncoderSaveFlag;
Parameters.Parameter[
0
].NumberOfValues :
=
1
;
Parameters.Parameter[
0
].ValueType :
=
EncoderParameterValueTypeLong;
//
设置参数的值。这里只把Value地址赋给了参数值,Value在后面具体赋值
Parameters.Parameter[
0
].Value :
=
@Value;
//
打开第一个图像,这里的图像是前面代码分解后保存的jpg文件
Img :
=
TGpImage.Create(
'
Hb0.jpg
'
);
try
//
获取图像格式tiff编码器的ClsID
GetEncoderClsid(
'
image/tiff
'
, Clsid);
//
在保存第一帧图像时,编码参数值设置为多帧
Value :
=
EncoderValueMultiFrame;
//
保存第一帧图像
Img.Save(
'
Hb.tif
'
, Clsid, @Parameters);
//
保存随后的各帧图像时,编码参数值设置为维度页
Value :
=
EncoderValueFrameDimensionPage;
//
依次打开后面的图像,保存到Hb.tif文件,本例图片为24帧
for
I :
=
1
to
23
do
begin
tmp :
=
TGpImage.Create(
'
Hb
'
+
IntToStr(I)
+
'
.jpg
'
);
try
Img.SaveAdd(tmp, @Parameters);
finally
tmp.Free;
end;
end;
finally
Img.Free;
end;
end;
end.
例子中已经作了较详细的注释,就不再对代码讲解了。但是有必要对编码参数作点说明:
TEncoderParameters是个封装图像编码器参数TEncoderParameter的数组类型结构,成员包括TEncoderParameter类型数组和数组个数。而编码参数类型TEncoderParameter定义如下:
//
---------------------------------------------------------------------------
//
Encoder Parameter structure
//
---------------------------------------------------------------------------
TEncoderParameter
=
packed record
Guid: TGUID;
//
该参数全局唯一标识符 (GUID),
NumberOfValues: ULONG;
//
Value地址处包含的元素个数
ValueType: TEncoderParameterValueType;
//
Value所指值的数据类型
Value: Pointer;
//
值的地址,可以为单值或者数组,具体根据Guid而定
PEncoderParameter
=
^
TEncoderParameter;
编码参数结构的Guid已经在GDI+中作了如下定义:
//
---------------------------------------------------------------------------
//
Encoder parameter sets 图像编码器参数类别设置
//
---------------------------------------------------------------------------
EncoderCompression : TGUID
=
'
{e09d739d-ccd4-44ee-8eba-3fbf8be4fc58}
'
;
//
压缩
{$EXTERNALSYM EncoderCompression}
EncoderColorDepth : TGUID
=
'
{66087055-ad66-4c7c-9a18-38a2310b8337}
'
;
//
颜色深度
{$EXTERNALSYM EncoderColorDepth}
EncoderScanMethod : TGUID
=
'
{3a4e2661-3109-4e56-8536-42c156e7dcfa}
'
;
//
扫描方法
{$EXTERNALSYM EncoderScanMethod}
EncoderVersion : TGUID
=
'
{24d18c76-814a-41a4-bf53-1c219cccf797}
'
;
//
版本
{$EXTERNALSYM EncoderVersion}
EncoderRenderMethod : TGUID
=
'
{6d42c53a-229a-4825-8bb7-5c99e2b9a8b8}
'
;
//
呈现方法
{$EXTERNALSYM EncoderRenderMethod}
EncoderQuality : TGUID
=
'
{1d5be4b5-fa4a-452d-9cdd-5db35105e7eb}
'
;
//
质量
{$EXTERNALSYM EncoderQuality}
EncoderTransformation : TGUID
=
'
{8d0eb2d1-a58e-4ea8-aa14-108074b7b6f9}
'
;
//
转换
{$EXTERNALSYM EncoderTransformation}
EncoderLuminanceTable : TGUID
=
'
{edb33bce-0266-4a77-b904-27216099e717}
'
;
//
亮度表
{$EXTERNALSYM EncoderLuminanceTable}
EncoderChrominanceTable : TGUID
=
'
{f2e455dc-09b3-4316-8260-676ada32481c}
'
;
//
色度表
{$EXTERNALSYM EncoderChrominanceTable}
EncoderSaveFlag : TGUID
=
'
{292266fc-ac40-47bf-8cfc-a85b89a655de}
'
;
//
保存标志
{$EXTERNALSYM EncoderSaveFlag}
也就是说我们可以在保存图像的同时,设置上述编码参数来满足我们的要求,如上面例子中分解图片时设置了质量参数;合成图像的时候设置了保存标志。但是很遗憾,不是每种图像编码器都支持上面参数的,如质量和转换参数就只有jpeg格式图像编码器支持,所以,如要用GDI+压缩图像旧只有JPEG格式才行。
编码参数的数据类型也是有规定的,具体定义和说明如下:
//
---------------------------------------------------------------------------
//
Image encoder parameter related types
//
---------------------------------------------------------------------------
TEncoderParameterValueType
=
(
EncoderParameterValueTypeByte
=
1
,
//
数组中的每个值都是 8 位无符号整数
EncoderParameterValueTypeASCII
=
2
,
//
一个空终止的 ASCII 字符串,
//
NumberOfValues 包括 NULL 结束符在内的字符串长度
EncoderParameterValueTypeShort
=
3
,
//
数组中的每个值都是 16 位无符号整数
EncoderParameterValueTypeLong
=
4
,
//
数组中的每个值都是 32 位无符号整数
EncoderParameterValueTypeRational
=
5
,
//
数组中的每一个值都是一对 32 位无符号整数,
//
每一对都表示一个分数,
//
第一个整数是分子,第二个整数是分母.
EncoderParameterValueTypeLongRange
=
6
,
//
数组中的每一个值都是一对 32 位无符号整数,
//
每一对都表示一个数字区域.
EncoderParameterValueTypeUndefined
=
7
,
//
值的数组是没有定义数据类型的字节的数组
EncoderParameterValueTypeRationalRange
=
8
//
数组中的每一个值都是一组四个 32 位无符号整数,
//
前两个整数表示一个分数,后两个整数表示第二个分数,
//
这两个分数表示一个有理数区域,
//
第一个分数是该区域中最小的有理数,
//
第二个分数是该区域中最大的有理数.
);
从上面的类型说明可以看出,有些类型定义对参数值(Value)的规定很具体,你只有按要求给出才不会出错。有些参数我们可以给的值的范围较大,如例子中的品质参数,就可以在0 - 100之间;而还有些值则是规定好了的,如例子中的保存参数的值,下面也把这些值的枚举定义以及使用图像格式列在下面:
//
---------------------------------------------------------------------------
//
Image encoder value types
//
---------------------------------------------------------------------------
TEncoderValue
=
(
EncoderValueColorTypeCMYK,
EncoderValueColorTypeYCCK,
EncoderValueCompressionLZW,
//
LZW 压缩方案。可以作为属于压缩类别的参数传递到 TIFF 编码器。
EncoderValueCompressionCCITT3,
//
CCITT3 压缩方案。可以作为属于压缩类别的参数传递到 TIFF 编码器。
EncoderValueCompressionCCITT4,
//
CCITT4 压缩方案。可以作为属于压缩类别的参数传递到 TIFF 编码器。
EncoderValueCompressionRle,
//
RLE 压缩方案。可以作为属于压缩类别的参数传递到 TIFF 编码器。
EncoderValueCompressionNone,
//
不指定压缩。可以作为属于压缩类别的参数传递到 TIFF 编码器。
EncoderValueScanMethodInterlaced,
EncoderValueScanMethodNonInterlaced,
EncoderValueVersionGif87,
EncoderValueVersionGif89,
EncoderValueRenderProgressive,
EncoderValueRenderNonProgressive,
EncoderValueTransformRotate90,
//
图像将围绕其中心沿顺时针方向旋转 90 度。可以作为属于转换类别的参数传递到 JPEG 编码器
EncoderValueTransformRotate180,
//
图像围绕其中心旋转 180 度。可以作为属于转换类别的参数传递到 JPEG 编码器。
EncoderValueTransformRotate270,
//
图像围绕其中心沿顺时针方向旋转 270 度。可以作为属于转换类别的参数传递到 JPEG 编码器
EncoderValueTransformFlipHorizontal,
//
图像水平翻转。可以作为属于转换类别的参数传递到 JPEG 编码器。
EncoderValueTransformFlipVertical,
//
图像垂直翻转。可以作为属于转换类别的参数传递到 JPEG 编码器。
EncoderValueMultiFrame,
//
图像有多于 1 帧(页面)。可以作为属于保存标志类别的参数传递到 TIFF 编码器
EncoderValueLastFrame,
//
指定多帧图像中的最后一帧。可以作为属于保存标志类别的参数传递到 TIFF 编码器。
EncoderValueFlush,
//
应关闭一个多帧文件或流。可以作为属于保存标志类别的参数传递到 TIFF 编码器
EncoderValueFrameDimensionTime,
EncoderValueFrameDimensionResolution,
EncoderValueFrameDimensionPage
//
将一帧添加到图像的页面维度。可以作为属于保存标志类别的参数传递到 TIFF 编码器。
);
没做说明的枚举值在GDI+ 1.0中是不支持的,其它也只适用规定的图像格式,如EncoderValueMultiFrame和EncoderValueFrameDimensionPage只适用于TIFF格式编码器,而EncoderValueFrameDimensionTime等值由不支持,所以,前面例子只能合成TIFF格式的多帧图像,而不能合成GIF格式。
关于多帧(页)图像可以参见我的文章《GDI+ 在Delphi程序的应用 -- 多帧(页)图像动画播放》。
我用的GDI+版本与网上流通不太兼容,可适当修改例子代码后测试,如需我的GDI+版本,请参照《GDI+ for VCL基础 -- GDI+ 与 VCL》的下载地址和说明,特别要注意后面的后记部分中需要修改的地方。
如有错误或建议,请来信:[email protected],或者直接在文章中留言。
最后,例子中使用的GIF图像已经贴在了《GDI+ 在Delphi程序的应用 -- 多帧(页)图像动画播放》中,现做个图像地址连接: