GDI+ 在Delphi程序的应用 -- 多帧(页)图像的分解与合成

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》的下载地址和说明,特别要注意后面的后记部分中需要修改的地方。

        如有错误或建议,请来信:maozefa@hotmail.com,或者直接在文章中留言。

       最后,例子中使用的GIF图像已经贴在了《GDI+ 在Delphi程序的应用 -- 多帧(页)图像动画播放》中,现做个图像地址连接:

       

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值