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
    评论
【图书描述】: GDI+是新一代的图形接口。如果要设计.NET Framework图形应用程序,就必须使用GDI+。本书是一本为.NET开发人员讲授如何编写Windows和Web图形应用程序的专著,书中全面介绍了GDI+和Windows图形程序设计的基本知识和GDI+图形程序设计的各个方面。 本书适合于开发GDI+图形应用程序的初、中级程序员阅读,书中给出了大量用C#语言编写的可重用示例代码,可以使读者更快地掌握书中所介绍的各种知识和概念。本书也可以作为大专院校相关课程的重要辅导教材。 【编辑推荐】: 《GDI+图形程序设计》是为.NET开发人员介绍如何编写Windows和Web图形应用程序的指南用书。通过大量详尽的实例,本书使有经验的程序员可以更深入地理解在.NET Framework类库中定义和整个GDI+API。   本书从介绍GDI+Windows图形程序设计的基本知识开始,其核心是对一些实际问题的指导,包括如何使用Windows Forms及如何优化GDI+的性能。本书通过一些例子来说明如何开发真实世界的工具,如GDI+Painter、GDI+Editro、ImageViewer和ImageAnimator等。另外,作者还给出了大量使用C#语言编写的可重用示例代码,读者可从网上下载完整的C#和Visual Basic.NET源代码,并可通过这些源代码查看书中各图的彩色效果 第1章 GDI+ ——下一代图形接口 1.1 理解GDI+ 1.2 探索GDI+ 的功能 1.3 从GDI的角度学习GDI+ 1.4 .NET中的GDI+ 名称空间和类 总结 第2章 第一个GDI+ 应用程序 2.1 绘制表面 2.2 坐标系统 2.3 指南——第一个GDI+ 应用程序 2.4 一些基本的GDI+ 对象 总结 第3章 Graphics类 3.1 Graphics类的属性 3.2 Graphics类的方法 3.3 GDI+ Painter应用程序 3.4 绘制饼图 总结 第4章 使用画笔和钢笔 4.1 理解和使用画笔 4.2 在GDI+ 中使用钢笔 4.3 使用钢笔进行变形 4.4 使用画笔进行变形 4.5 系统钢笔和系统画笔 4.6 一个真实世界的例子 ——在GDI+ Painter应用程序中添加颜色、钢笔和画笔 总结 第5章 颜色、字体和文本 5.1 访问Graphics对象 5.2 使用颜色 5.3 使用字体 5.4 使用文本和字符串 5.5 渲染文本的质量和性能 5.6 高级版式 5.7 一个简单的文本编辑器 5.8 文本变形 总结 第6章 矩形和区域 6.1 Rectangle结构体 6.2 Region类 6.3 区域和剪辑 6.4 剪辑区域示例 6.5 区域、非矩形窗体和控件 总结 第7章 图像处理 7.1 光栅图像和矢量图像 7.2 使用图像 7.3 操作图像 7.4 在GDI+ 中播放动画 7.5 使用位图 7.6 使用图标 7.7 扭曲图像 7.8 绘制透明的图形对象 7.9 查看多个图像 7.10 使用图片框查看图像 7.11 使用不同的大小保存图像 总结 第8章 高级图像处理 8.1 渲染位图的一部分 8.2 使用图元文件 8.3 使用颜色对象应用颜色映射 8.4 图像属性和ImageAttributes类 8.5 编码器参数与图像格式 总结 第9章 高级二维图形 9.1 线帽和线条样式 9.2 理解并使用图形路径 9.3 图形容器 9.4 读取图像的元数据 9.5 混合 9.6 Alpha混合 9.7 其他高级二维主题 总结 第10章 变形 10.1 坐标系统 10.2 变形的类型 10.3 Matrix类与变形 10.4 Graphics类与变形 10.5 全局变形、局部变形和复合变形 10.6 图像变形 10.7 颜色变形和颜色矩阵 10.8 图像处理中的矩阵操作 10.9 文本变形 10.10 变形顺序的重要性 总结 第11章 打印 11.1 简要地回顾使用Microsoft Windows进行打印的历史 11.2 打印过程概述 11.3 第一个打印应用程序 11.4 打印机的设置 11.5 PrintDocument和Print事件 11.6 打印文本 11.7 打印图形 11.8 打印对话框 11.9 自定义面设置 11.10 打印多个面 11.11 边打印——注意事项 11.12 进入细节——自定义控制和打印控制器 总结 第12章 开发GDI+ Web应用程序 12.1 创建第一个ASP.NET Web应用程序 12.2 第一个图形Web应用程序 12.3 绘制简单的图形 12.4 在Web上绘制图像 12.5 绘制曲线图 12.6 绘制饼图 总结 第13章 GDI+ 的最佳实践及性能技术 13.1 理解渲染过程 13.2 双缓存和无抖动绘图 13.3 理解SetStyle方法 13.4 绘图过程的质量与性能 总结 第14章 GDI互操作性 14.1 在受控环境中使用GDI 14.2 在受控代码中使用GDI的注意事项 总结 第15章 其他GDI+ 示例 15.1 设计交互式GUI应用程序 15.2 绘制具有形状的窗体和Windows控件 15.3 为绘制的图像添加版权信息 15.4 从流或数据库读取及写入图像 15.5 创建自绘制的列表控件 总结 附录A .NET中的异常处理

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值