首页 | IT新闻 | 硬件 | 操作系统 | 开发 | 网络编程 | 数据库 | 热门框架 | 网络安全 | 组网 | 建站指南 | 网页制作 | 特效 | 实用技巧 | 服务器 | 办公 | QQ | 探索 | 社区

  • 技术部落
  • 部落首页 > 程序开发 > Delphi > 正文
  • GDI+在Delphi中的应用:多帧(页)图像的分解与合成
      2007-12-21  来源:maozefa  编辑:Jsbulo  热度:

    在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格式。