WEB开发网
开发学院软件开发Delphi 字符画软件的四个关键技术 阅读

字符画软件的四个关键技术

 2006-02-04 13:42:11 来源:WEB开发网   
核心提示: 字符画软件的四个关键技术第一个关键技术:汉字库读取技术使用汉字库技术可以做到和操作系统无关性,我们先了解一下点阵字库的基本原理如下所示,字符画软件的四个关键技术,下面是一个“字”的点阵图,在16点阵字库中一个汉字为16x16点,往往被转换的文本有多行,且每一行的长度不定,每一行使用两个字节表示,如下面示例第一行的十六
 

字符画软件的四个关键技术

第一个关键技术:汉字库读取技术

使用汉字库技术可以做到和操作系统无关性,我们先了解一下点阵字库的基本原理
如下所示,下面是一个“字”的点阵图,在16点阵字库中一个汉字为16x16点,每一行使用两个字节表示,如下面示例第一行的十六进制为:0x02和0x00,所以,一个汉字在16点阵字库中需要占用2x16个字节,24点阵字库需要3x24个字节,下面我们仅以16点阵字库为例,其他点阵类似。

██████ █████████
███████ ████████
██            ██
██ ██████████ ██
█ ██████████ ███
███        █████
█████████ ██████
████████ ███████
███████ █████ ██
               █
███████ ████████
███████ ████████
███████ ████████
███████ ████████
█████ █ ████████
██████ █████████

下面的函数返回指定字符串的字符画文本
function Get16(const AWord,AForeground,ABackground:string):string;
   function GetBit(const c,n:byte):integer;
   begin
     result:=(c shr n) and 1;
   end;
var
   iLen     :integer;
   iFileSize  :integer;
   s      :string;
   k,l,i,p   :integer;
   cw:array[0..31] of char;
   qu_ma,wei_ma:integer;
   File16    :file;
begin
   iLen:=length(AWord);
   AssignFile(File16,piprogramInfo.Path+'HZK16');
   FileMode := fmOpenRead;
   try
     Reset(File16,1);
   finally
     FileMode:=fmOpenReadWrite;
   end;
   iFileSize:=FileSize(File16);
   try
     for l:=1 to iLen div 2 do
     begin
       k:=l*2-1;
       // 如果不是汉字,往前进一位
       while k<=iLen do
       begin
         if ByteType(AWord,k)=mbLeadByte then break;
         inc(k);
       end;
       if k>iLen then break;
       if ((ord(AWord[k]) and $80)<>0) then
       begin
         qu_ma:=ord(AWord[k])-161;
         wei_ma:=ord(AWord[k+1])-161;
         if (94*qu_ma+wei_ma)*32+32>iFileSize then continue;
         try
           seek(File16,(94*qu_ma+wei_ma)*32);
         except
           myMessageBox('fseek call fail!');
           exit;
         end;
         BlockRead(File16,cw,32);

       for i:=0 to 15 do
         begin
           for p:=7 downto 0 do
           begin
             if GetBit(ord(cw[i*2]),p)=1 then s:=s+AForeground
             else               s:=s+ABackground;
           end;
           for p:=7 downto 0 do
           begin
             if GetBit(ord(cw[i*2+1]),p)=1 then s:=s+AForeground
             else                s:=s+ABackground;
           end;
           s:=s+#13#10;
         end;
       end;
     end;
   finally
     CloseFile(File16);
   end;

   result:=s;
end;

第二个关键技术:使用系统字库进行转换
  其实使用系统字库是极为自由的方式,因为这样我们完全不必关心字库的技术,这一切都交给系统好了,让我们充分利用系统资源。
  如果我们定义一个设备,然后设定好设备的各种属性,包括宽度、高度、字体、颜色等,然后在上面绘制文本就可以了,要转换为字符画,只需要把设备上的点阵信息转换为文本即可。
配合 CreateFontIndirect 函数,使用 DrawText 可以绘制丰富的文本效果。实现完整的字符画效果

下面是十二号宋体的转换结果
█████ ██████
█          █
  ████████ █
██       ███
██████ █████
█████ ██████
           █
█████ ██████
█████ ██████
█████ ██████
███   ██████
████████████

下面是九号@黑体的转换结果
████████████
██  ███ ████
██ ████ ████
██ █ ██ ████
██ █  █ ████
█  █       █
   █ ██ ██ █
██ █ ██ ██ █
██ █ ██ ████
██ ████ ████
██  ███ ████
████████████

第三个关键技术:图片转换为文本
  要把图像转换为文本,这其中有一个很大的困难,就是文本没有颜色,所以我们特别引进了一个概念:文本灰度,就是把不同字母在屏幕上显示的大小排序,得到一张灰度表,用这个灰度表来转换图片,可以达到比较好的效果。
下面的函数可以把一个位图转换成文本,ABit 是位图,AGray 是灰度
function ImageToText(ABit:TBitmap;const AGray:string):string;
var
   x,y     :integer;
   s      :string;
   pColor    :Longint;
   R,G,B    :byte;
   iGray    :integer;

   sGrayPer   :string;        
   iGrayLen   :integer;       
   iIndex    :integer;       
begin
   s:='';
   sGrayPer:=AGray;
   iGrayLen:=Length(sGrayPer);
   for y:=0 to ABit.Height-1 do
   begin
     for x:=0 to ABit.Width-1 do
     begin
       pColor:=ABit.Canvas.Pixels[x,y];
       R:=pColor and $FF;
       G:=(pColor shr 8) and $FF;
       B:=(pColor shr 16) and $FF;

     iGray:=HiByte(R*77+G*151+B*28);     
       iIndex:=(iGray*iGrayLen div 255);
       if iIndex<1 then iIndex:=1;
       if iIndex>iGrayLen then iIndex:=iGrayLen;
       s:=s+sGrayPer[iIndex];
     end;
     s:=s+Crlf;
   end;
   result:=s;
end;
这是一个常用且效果比较好的灰度:“MNHQ$OC?7>!":-';. ”


第四个关键技术:把文本转换为图像
  要把文本转换为图片,必须获取两个重要参数:转换后的宽和高,要取得这两个参数,我们可以使用 GetTextExtentPoint32 函数,该函数的定义如下:
function GetTextExtentPoint32(DC: HDC; Str: PChar; Count: Integer; var Size: TSize): BOOL;
DC 传入设备句柄
Str 为文本内容
Count 为文本的长度(字节)
Size 返回宽和高
在实际应用中,往往被转换的文本有多行,且每一行的长度不定,
所以我们还需要在生成图像前进行一遍预扫,以便获得完整的图像大小

下面演示了文本转换为图像的代码

////////////////////////////////////////////////////////////////////////////////
// 功能   : 把文本转换为位图
// AOwner  : 窗体参数
// AText   : 要转换的文本
// AFont   : 文本的字体
// ABitmap  : 转换后的位图对象
// 日期   : 2003.12.15
////////////////////////////////////////////////////////////////////////////////
PRocedure TextToBitmap(AOwner:TObject;const AText:TStrings;AFont:TFont;ABitmap:TBitmap);
var
   i        :integer;
   iWidth,iHeight  :integer;
   iCharHeight   :integer;
   s        :string;
   r        :TRect;
   size       :TSize;
   lblTemp     :TLabel;
begin
   iWidth:=0;
   iHeight:=0;

   lblTemp:=TLabel.Create(nil);
   r.Top:=0;
   try
     lblTemp.Visible:=false;
     lblTemp.Parent:=TWinControl(AOwner);
     lblTemp.Font.Assign(AFont);

   ABitmap.Canvas.Brush.Style:=bsClear;
     ABitmap.Canvas.Pen.Color:=rgb(0,0,0);
     ABitmap.Canvas.Brush.Color:=RGB(255,255,255);
     ABitmap.Canvas.Font.Assign(AFont);

   // 下面代码用户获得文本的最大宽度和高度
     for i:=0 to AText.Count-1 do
     begin
       s:=AText.Strings[i];
       if s='' then s:=' ';
       lblTemp.Caption:=s;

     GetTextExtentPoint32(lblTemp.Canvas.Handle,pchar(lblTemp.Caption),lblTemp.GetTextLen,size);
       if iWidth<size.cx then iWidth:=Size.cx;
       iHeight:=iHeight+Size.cy;
     end;

   // 获得一个字符的高度
     GetTextExtentPoint32(lblTemp.Canvas.Handle,pchar('  '),length('  '),size);
     iCharHeight:=size.cy;

   ABitmap.Width:=iWidth;
     ABitmap.Height:=iHeight;
     for i:=0 to AText.Count-1 do
     begin
       s:=AText.Strings[i];

     r.Left:=0;
       r.Right:=ABitmap.Width;
       r.Bottom:=r.Bottom+iCharHeight;

     DrawText(ABitmap.Canvas.Handle,PChar(s),length(s),r,0);
       r.Top:=r.Top+iCharHeight;
     end;
   finally
     lblTemp.Free;
   end;
end;

2003.12.15
凌丽软件工作室
http://wosens.com

Tags:字符 软件 四个

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接