字元畫軟體的四個關鍵技術 (轉)

amyz發表於2007-08-17
字元畫軟體的四個關鍵技術 (轉)[@more@]

字元畫的四個關鍵技術

第一個關鍵技術:漢字型檔讀取技術

  使用漢字型檔技術可以做到和操作無關性,我們先了解一下點陣字型檔的基本原理
如下所示,下面是一個“字”的點陣圖,在16點陣字型檔中一個漢字為16x16點,每一行使用兩個位元組表示,如下面示例第一行的十六進位制為:0x02和0x00,所以,一個漢字在16點陣字型檔中需要佔用2x16個位元組,24點陣字型檔需要3x24個位元組,下面我們僅以16點陣字型檔為例,其他點陣類似。

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

下面的返回指定字串的字元畫文字
function Get16(const A,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)=mbLeayte 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  : 轉換後的點陣圖
// 日期  : .12.15
////////////////////////////////////////////////////////////////////////////////
procedure TextToBitmap(AOwner:T;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  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
凌麗軟體工作室


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-963395/,如需轉載,請註明出處,否則將追究法律責任。

相關文章