转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 软件开发 >> Delphi程序 >> 正文
Delphi中如何编写图像解析组件         ★★★★

Delphi中如何编写图像解析组件

作者:闵涛 文章来源:闵涛的学习笔记 点击数:1866 更新时间:2009/4/23 18:37:53

Delphi中如何编写图像解析组件

Delphi作为一个强大的RAD开发工具,在应用软件的开发方面一直有着它的独特优势。这种优势同样体现在图像相关软件的开发上。如果你要在桌面上放置一张图像,只需要简单的在桌面上放置一个Image控件,然后就可以通过其Image属性任意的加载BMP、WMF、EMF等格式的图像。如果还想增加对JPEG的支持,只需要添加一个JPEG单元即可。甚至在Image中加载一张JPEG后,Delphi会自动添加一个JPEG单元。一切做起来就是这么的简单。基本格式都已经封装在了VCL中,那么Delphi对类似JPEG这样图像格式的支持是如何实现的呢?

其实从TPicture中很容易看出其中的实现过程,它可以理解为所有图像对象的容器。

如JPEG.pas中有如下两句代码:

TPicture.RegisterFileFormat(''''jpeg'''', sJPEGImageFile, TJPEGImage);
TPicture.RegisterFileFormat(''''jpg'''', sJPEGImageFile, TJPEGImage);

(sJPEGImageFile = ''''JPEG Image File'''',见JConsts.pas)

什么意思呢?可以理解为将TJPEGImage注册为jpeg、jpg两种后缀图像文件的类。

其实质就是将后缀,图像描述,具体图像解析类等信息保存到了FileFormats。

具体见如下代码:

var FileFormats: TFileFormatsList = nil;

class procedure TPicture.RegisterFileFormat(const AExtension,
  ADescription: string; AGraphicClass: TGraphicClass);
begin
  GetFileFormats.Add(AExtension, ADescription, 0, AGraphicClass);
end;

function GetFileFormats: TFileFormatsList;
begin
  if FileFormats = nil then FileFormats := TFileFormatsList.Create;
  Result := FileFormats;
end;

而TPicture默认支持四种图像格式是因为TFileFormatsList的构造函数中已进行了添加。

constructor TFileFormatsList.Create;
begin
  inherited Create;
  Add(''''wmf'''', SVMetafiles, 0, TMetafile);
  Add(''''emf'''', SVEnhMetafiles, 0, TMetafile);
  Add(''''ico'''', SVIcons, 0, TIcon);
  Add(''''bmp'''', SVBitmaps, 0, TBitmap);
end;

也正是通过FileFormats中保存的信息,控件OpenPictureDialog中自动生成了所支持文件类型的列表。

那么该如何编写这些图像解析类呢?

TGraphic是TBitmap、TIcon、TMetafile对象的基类。同样这里的图像解析类也应该从TGraphic派生,利用很多VCL中已经封装了的代码,可以省去很多工作。

实现基本功能一般只需要重载三个成员:

TXXXImage = class(TGraphic)
protected
  procedure Draw(ACanvas: TCanvas; const Rect: TRect); override;//绘制图像到画布
public
  procedure LoadFromStream(Stream: TStream); override; //从流中获取图像数据
  procedure SaveToStream(Stream: TStream); override; //将图像数据写入流中
end;

因为TGraphic.LoadFromFile/TGraphic.SaveToFile中已经实现了由文件名读取数据到流的/将流中的数据写入到对应文件的功能,无特殊需要这里可以不用重载。而成员Draw自然就是用于实现将图像绘制到画布,由于TCanvas对GDI的完善封装,这里不需要考虑如何将图像利用GDI绘制到窗体的这个过程。剩下的就只是编写图像解析部分的代码啦。

下面就以RAS格式为例做进一步的探讨。

这里没有用TGraphic作为基类,而是用了TBitmap,这样进一步把Draw的实现过程都省了,只需要在LoadFromStream中实现转化为位图的过程就可以了。

type

TRASGraphic = class(TBitmap)
public
  procedure LoadFromStream(Stream: TStream); override;
  procedure SaveToStream(Stream: TStream); override;
end;

//定义描述RAS文件头的记录类型
TRASHeader = packed record
  Magic,               //标记
  Width,               //宽
  Height,              //高
  Depth,               //色深
  Length,              //图像数据长度,可能会等于0
  RasType,             //格式类型
  MapType,             //调色板类型
  MapLength: Cardinal; //调色板数据长度
end;

//定义一个用来描述RAS文件头的记录类型是非常必要的

const

//定义代表RAS所有类型的常量
  RT_OLD = 0;
  RT_STANDARD = 1;
  RT_BYTE_ENCODED = 2;
  RT_FORMAT_RGB = 3;
  RT_FORMAT_TIFF = 4;
  RT_FORMAT_IFF = 5;
  RT_EXPERIMENTAL = $FFFF;

//定义代表调色板类型的常量
  RMT_NONE = 0;//无调色板数据
  RMT_EQUAL_RGB = 1;
  RMT_RAW = 2;

{如果RAS的格式为RT_OLD,数据长度可能为0}


function SwapLong(const Value: Cardinal): Cardinal;
asm
  BSWAP EAX//调用字节交换指令
end;

//抛出异常,参数为具体的异常信息
procedure RasError(const ErrorString: String);
begin
  raise EInvalidGraphic.Create(ErrorString);
end;

{下面是实现部分的代码。}

procedure TRASGraphic.LoadFromStream(Stream: TStream);
var
  Header: TRASHeader;
  Row8: PByte;
  Row24: PRGBTriple;
  Row32: PRGBQuad;
  PMap: PByte;
  Y: Integer;
  I: Integer;
  MapReaded: Boolean;
  Pal: TMaxLogPalette;
  R,G,B:array[0..255] of Byte;
  ColorByte: Byte;
begin
with Stream do
begin
  ReadBuffer(Header, SizeOf(Header)); //将文件头数据读取到记录Header中
  with Header do
  begin
    Width := SwapLong(Width);
    Height := SwapLong(Height);
    Depth := SwapLong(Depth);
    Length := SwapLong(Length);
    RASType := SwapLong(RASType);
    MapType := SwapLong(MapType);
    MapLength := SwapLong(MapLength);
  end;
  //由于读取数据的顺序问题,这里需要调用上面的SwapLong改变顺序。
  if (Header.Magic = $956AA659) and
  (Header.Width<>0) and (Header.Height<>0) and
  (Header.Depth in [1,8,24,32]) and (Header.RasType in [RT_OLD,RT_STANDARD,RT_BYTE_ENCODED,RT_FORMAT_RGB]) then
  begin
    Width := Header.Width;
    Height := Header.Height;
    MapReaded := False;

    case Header.Depth of
      1:PixelFormat := pf1Bit;
      8:
      begin
        PixelFormat := pf8Bit;

        case Header.MapType of
          RMT_NONE:
          begin
            Pal.palVersion:=$300;
            Pal.palNumEntries:=256;
            for I := 0 to 255 do
            begin
              Pal.palPalEntry[I].peRed:=I;
              Pal.palPalEntry[I].peGreen:=I;
              Pal.palPalEntry[I].peBlue:=I;
              Pal.palPalEntry[I].peFlags:=0;
            end;
            Palette := CreatePalette(PLogPalette(@Pal)^);
            //当图像色深为8位,而又不存在调色板信息时,创建一个8位的灰度调色板
          end;
          RMT_EQUAL_RGB:
          begin
            if (Header.MapLength = 3*256) then
            begin
              Pal.palVersion:=$300;
              Pal.palNumEntries:=256;
              ReadBuffer(R,256);
              ReadBuffer(G,256);
              ReadBuffer(B,256);
              for I := 0 to 255 do
              begin
                Pal.palPalEntry[I].peRed:=R[I];
                Pal.palPalEntry[I].peGreen:=G[I];
                Pal.palPalEntry[I].peBlue:=B[I];
                Pal.palPalEntry[I].peFlags:=0;
              end;
              Palette := CreatePalette(PLogPalette(@Pal)^);
              //读取文件中的调色板信息
              //相关调色板操作的API请查询MSDN
            end
            else
              RasError(''''调色板长度错误!'''');
            MapReaded := True;
          end;
          RMT_RAW:
          begin
            RasError(''''不支持的文件格式!'''');
          end;
        end;
      end;
      24:PixelFormat := pf24Bit;
      32:
      begin
        PixelFormat := pf32Bit;
 

[1] [2] [3]  下一页


没有相关教程
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · C语言系列  · VB.NET程序
    · JAVA开发  · Delphi程序
    · 脚本语言
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台