小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Delphi的圖形處理(一)

 塢絲別垎 2005-10-28
Delphi的圖形處理 之一 -- 圖像處理在可視化編程中的作用及其應(yīng)用價(jià)值 

作者:何詠     發(fā)布日期:(2005-4-12 21:07:49)

聲明:本文著作權(quán)屬于何詠,如要轉(zhuǎn)載請(qǐng)聲明作者及出處。

  第一章           圖像處理在可視化編程中的作用及其應(yīng)用價(jià)值

圖像處理,是可視化編程的基礎(chǔ)內(nèi)容。在Windows操作系統(tǒng)中,一切要輸出到屏幕上的東西都是通過(guò)圖形處理這部分的內(nèi)容來(lái)實(shí)現(xiàn)的。比如一個(gè)程序使用了標(biāo)簽控件,它看起來(lái)似乎并沒(méi)有用到什么圖形處理,但實(shí)際上標(biāo)簽控件就是通過(guò)使用GDI庫(kù)中的圖形處理函數(shù)來(lái)實(shí)現(xiàn)的??梢?jiàn)圖形處理在編程中的重要性。

圖像處理在實(shí)際的應(yīng)用中也極具價(jià)值。平面制作、動(dòng)畫(huà)制作等都離不開(kāi)它。這一部分的內(nèi)容十分繁多。我本次研究的內(nèi)容,只是其中最基礎(chǔ)的、最重要一部分。

探究Delphi的圖形處理 之二 -- 基本圖像處理函數(shù) 

作者:何詠     發(fā)布日期:(2005-4-12 21:06:29)

聲明:本文著作權(quán)屬于何詠,如要轉(zhuǎn)載請(qǐng)聲明作者及出處。

  第二章           圖像處理函數(shù)

2.1 為什么選擇Delphi

       所有的可視化編程語(yǔ)言都能夠進(jìn)行圖像處理。但由于這些語(yǔ)言的定位不同,它們?cè)谶M(jìn)行圖形處理的效率和便捷程度上也各不相同。實(shí)際上,Visual C 的圖像處理效率是最高的,這是由于GDI類(lèi)庫(kù)本身就是用C++寫(xiě)的。但是使用VC來(lái)編程并不是一件方便的事,因?yàn)檫@個(gè)語(yǔ)言本身就較為繁雜難懂,所以我沒(méi)有選擇它。Visual BasicVB)也是一個(gè)常用的語(yǔ)言,但它在圖形處理方面能力較差。首先是它的坐標(biāo)系統(tǒng)是以twip為單位的浮點(diǎn)坐標(biāo)系統(tǒng),在調(diào)用GDI類(lèi)庫(kù)時(shí),必須對(duì)坐標(biāo)系統(tǒng)進(jìn)行轉(zhuǎn)換,浪費(fèi)了大量的資源,編程起來(lái)較為麻煩。在多方面因素的影響下,我覺(jué)得Delphi是一個(gè)理想的語(yǔ)言。Delphi已經(jīng)把絕大多數(shù)GDI繪圖函數(shù)都封裝成可直接調(diào)用的類(lèi),使用它進(jìn)行圖形處理操作十分方便,而且Delphi Pascal演變而來(lái)的,Pascal具有嚴(yán)謹(jǐn)易讀的特點(diǎn),因此很容易上手。

2.2  Delphi中用于圖形處理的類(lèi)

Delphi為我們提供了許多圖形圖像方面的類(lèi),合理地使用這些類(lèi),我們可以方便地開(kāi)發(fā)出各種圖形處理程序。這些類(lèi)有TPicture、TBitmapTGraphic、TIcon、TJPEGImageTCanvas。其中,TCanvas類(lèi)用于繪圖,TPicture、TBitmap、TIconTJPEGImage是專(zhuān)門(mén)用來(lái)處理圖片的類(lèi),TGraphic是一個(gè)抽象類(lèi),一般不直接使用。TPicture類(lèi)可以載入所有支持的圖片,而TBitmap、TIconTJPEGImage分別用于處理各種類(lèi)型的圖片。在實(shí)際應(yīng)用中,我們一般用這些具體類(lèi)型的類(lèi)載入圖片,再將圖片轉(zhuǎn)為Bitmap格式來(lái)處理。TPicture、TIcon、TJPEGImage類(lèi)一般只用于輸入和輸出。例如,下面的代碼可以載入一幅任意支持格式的圖片(Delphi所支持的格式為bmp、jpg、dib、wmfemf)。

Var Pic:TPicture;

Begin

  Pic := TPicture.Create;

  Pic.LoadFromFile(FileName);

End;

TPicture類(lèi)來(lái)載入圖片時(shí),該類(lèi)會(huì)根據(jù)文件名的擴(kuò)展名來(lái)決定用何等方式來(lái)打開(kāi)圖片。這就出現(xiàn)了一個(gè)問(wèn)題,如果這個(gè)圖片的擴(kuò)展名被用戶(hù)非法修改,程序就會(huì)把這個(gè)圖片視為無(wú)效圖片。在真正編程中,我們要用TPictureTBitmap、TJPEGImage、TIcon依次嘗試去打開(kāi)圖片。

另外,Delphi本身是不支持GIF文件格式的。我們可以借用一個(gè)第三方的類(lèi)——GIFImage來(lái)讓Delphi支持它。這個(gè)類(lèi)在附帶的光盤(pán)中可以找到。最終我們用下面的代碼來(lái)完成載入圖片的操作。

Procedure ReadPicture(FileName: String; Bitmap: Graphics.TBitmap);

var pic:TPicture;Bit:Graphics.TBitmap;jpgPic:TJPEGImage;FGifPic:TGIFImage;

    icoPic:TIcon;

begin

   FGifPic := TGifImage.Create;

   Pic:=Tpicture.Create;

   bit:=Graphics.TBitmap.Create;

   jpgPic:=TJPEGImage.Create;

   icoPic:=TIcon.Create;

    try

        pic.LoadFromFile(FileName);

        if uppercase(ExtractFileExt(Filename)) = ‘.ICO‘ then begin

           Bitmap.Height:=pic.Height;

           Bitmap.Width:=Pic.Width;

           Bitmap.Canvas.Draw(0,0,Pic.Graphic);

        end

        else

        bitmap.Assign(pic.Graphic);

    except

         try

           bitmap.LoadFromFile(FileName);

         except

             try

               jpgPic.LoadFromFile(FileName);

               bitmap.Assign(jpgPic);

             except

                  try

                    icoPic.LoadFromFile(Filename);

                    bitmap.Free;

                    Bitmap:=TBitmap.Create;

                    bitmap.Height:=icoPic.Height;

                    bitmap.Width:=icoPic.Width;

                    bitmap.Canvas.Draw(0,0,icoPic);

                  except

                      try

                         FgifPic.LoadFromFile(FileName);

                         Bitmap.Assign(FGifPic.Bitmap);

                      except

                         bitmap.Height:=bitmap.Canvas.TextHeight(‘8‘);

                         bitmap.Width:=bitmap.Canvas.TextWidth(‘無(wú)效圖片‘);

                         BitMap.Canvas.TextOut(0,0,‘無(wú)效圖片‘);

                      end;{try}

                  end;

                end;{try}

             end;{try}

    end;{try}

   Pic.Free ;

   bit.Free;

   jpgPic.Free;

   icoPic.Free;

   FGifPic.Free;

end;

保存圖片的方法跟打開(kāi)圖片的方法類(lèi)似,我們可以使用不同類(lèi)型的圖片類(lèi)的SaveToFile方法保存文件。下面的代碼可以根據(jù)文件名中擴(kuò)展名的不同使用不同的類(lèi)來(lái)保存Bitmap。

Procedure SaveBitmap(FileName: String; PicB: TBitmap);

var pic:TPicture;  FileExt:String;picJPG:TJPEGImage;picGIF:TGIFImage;

begin

   pic:=TPicture.Create;

   picJPG:=TJPEGImage.Create;

   picGIF:=TGIFImage.Create;

   try

     pic.Assign(PicB);

     FileExt:= ExtractFileEXT(FileName);

     if (Uppercase(FileExt)=‘.JPG‘)or(Uppercase(FileExt)=‘.JPEG‘)

        or(Uppercase(FileExt)=‘.JPE‘) then

     begin

        picJPG.Assign(PicB);

        picJPG.SaveToFile(FileName);

     end

     else If (UpperCase(FileExt)=‘.BMP‘)OR(UpperCase(FileExt)=‘.DIB‘)THEN

     Begin

       PicB.SaveToFile(FileName);

     end

     else if (UpperCase(FileExt)=‘.GIF‘) then begin

       picGIF.Assign(PicB);

       PicGIF.SaveToFile(FileName);

     end

     else

       Pic.SaveToFile(FileName);

     {End If}

     ShowPicture(PictureIndex,False,TPicture(PicB));

   Finally

 pic.Free;

 picJPG.Free;

 PicGIF.Free;

end;

end;

探究Delphi的圖形處理 之三 -- GDI及Canvas類(lèi)簡(jiǎn)介 

作者:何詠     發(fā)布日期:(2005-4-12 21:05:11)

聲明:本文著作權(quán)屬于何詠,如要轉(zhuǎn)載請(qǐng)聲明作者及出處。

 

2.3 GDICanvas類(lèi)簡(jiǎn)介

GDI(Graphics Device Interface,圖形設(shè)備接口)Windows為我們提供的一個(gè)專(zhuān)門(mén)用于圖形繪制和屏幕輸出的類(lèi)庫(kù)。這個(gè)類(lèi)庫(kù)提供了許多繪圖函數(shù),使用這些函數(shù),我們幾乎可以開(kāi)發(fā)出所有的平面繪制、平面處理的程序。它同時(shí)也是Windows系統(tǒng)的核心,Windows系統(tǒng)中所有的繪圖任務(wù)都由這個(gè)庫(kù)來(lái)完成。在任何語(yǔ)言中,我們都可以調(diào)用這個(gè)庫(kù)來(lái)完成繪圖任務(wù)。

Delphi中,我們已經(jīng)有了一個(gè)已經(jīng)封裝了絕大多數(shù)GDI函數(shù)的類(lèi)。使用這個(gè)類(lèi)我們可以方便的完成各種圖像處理任務(wù)。這就是我們要研究的Canvas類(lèi)。

探究Delphi的圖形處理 之四 -- Canvas類(lèi)中的基本繪圖方法 

作者:何詠     發(fā)布日期:(2005-4-12 21:04:21)

聲明:本文著作權(quán)屬于何詠,如要轉(zhuǎn)載請(qǐng)聲明作者及出處。

 

Canvas類(lèi)中的基本繪圖方法

       Canvas就是“畫(huà)布”的意思,使用Canvas類(lèi)中的繪圖方法,我們可以在這塊畫(huà)布上繪制各種圖形。我們也可以通過(guò)設(shè)置每一個(gè)象素的顏色值來(lái)完成對(duì)圖像的處理。下面列出了Canvas類(lèi)中的一些常用繪圖方法。

       CopyRect(Dest:TRect;Canvas:TCanvas;Source:TRect);

       此方法用于把Canvas所指定的畫(huà)布的一部分(由Source指定)復(fù)制到當(dāng)前畫(huà)布中。Dest參數(shù)指定了復(fù)制后的圖像在當(dāng)前畫(huà)布中的位置。例如下面的語(yǔ)句:

       ThisCanvas.CopyRect(Rect(5,5,20,20),SourceCanvas,Rect(10,10,25,25));

可以把SourceCanvas中的(10,10,25,25)這一區(qū)域復(fù)制到ThisCanvas中的(5,5,20,20)區(qū)域中。

值得注意的是,TRect是一個(gè)Record類(lèi)型的變量,用Rect的構(gòu)造函數(shù)可以創(chuàng)建一個(gè)Rect變量。Rect類(lèi)型所指定的區(qū)域是一個(gè)長(zhǎng)方形,由(x1,y1,x2,y2)兩個(gè)點(diǎn)來(lái)確定。例如,Rect(10,10,25,25)所確定的就是下圖所示的區(qū)域:

       Draw(x,y:Integer;Graphic:TGraphic);

       此方法可以在當(dāng)前畫(huà)布中,以(x,y)為繪圖原點(diǎn)繪制由Graphic所指定的圖形或圖片。

       Ellips(x1,y1,x2,y2:Integer);

       此方法可以在當(dāng)前畫(huà)布中,以(x1,y1,(x2,y2)兩點(diǎn)所指定的矩形范圍內(nèi)繪制一個(gè)橢圓。并用畫(huà)筆中所指定的顏色作為線條顏色,筆刷的顏色作為填充顏色。

       MoveTo(x,y:Integer);

       把畫(huà)筆的位置移動(dòng)到點(diǎn)(x,y)

       LineTo(x,y:Integer);

       從畫(huà)筆當(dāng)前的位置繪制一條直線到點(diǎn)(x,y),并把畫(huà)筆的位置移動(dòng)到(x,y);

       Polygon(Points:array of TPoint);

       Points中的點(diǎn)為頂點(diǎn)繪制一個(gè)多邊形。并用畫(huà)筆中所指定的顏色作為線條顏色,筆刷的顏色作為填充顏色。

       StretchDraw(Const Rect:TRect;Graphic : TGraphic);

       此方法可以在由Rect所指定的區(qū)域中繪制圖片,圖片會(huì)根據(jù)Rect的大小自動(dòng)縮放。

       Rectangle(x1,y1,x2,y2);

       繪制由(x1,y1),(x2,y2)所確定的矩形。并用畫(huà)筆中所指定的顏色作為線條顏色,筆刷的顏色作為填充顏色。

       TextOut(x,y:Integer;Text:String);

       (x,y)為原點(diǎn)繪制參數(shù)Text所指定的文字。

       TextHeight(Text:String);

返回在當(dāng)前字體設(shè)置下,Text所指定的字符串的高度。

TextWidth(Text:String);

返回在當(dāng)前字體設(shè)置下,Text所指定的字符串的寬高度。

 

除了這些基本繪圖方法外,Canvas類(lèi)中還有一些重要的屬性,它們是:

       Pen(畫(huà)筆)

       這個(gè)屬性包含很多項(xiàng)目,其中Color指定了畫(huà)筆的顏色,Weight指定了畫(huà)筆的寬度,PenMode指定了畫(huà)筆繪圖的方式。

       Brush(筆刷)

這個(gè)屬性主要決定了圖形的填充方式。Color指定了填充顏色,BrushStyle決定了填充方式。

Font(字體)

它決定了在Canvas中,使用TestOut命令畫(huà)出的文字的字體和字號(hào)。

Pixels(象素?cái)?shù)組)

這個(gè)數(shù)組包含了Canvas中每一個(gè)象素的顏色值。

在一般的編程中,我們?cè)谛枰M(jìn)行象素級(jí)的圖像調(diào)整時(shí),一般不使用Pixels屬性。在Bitmap(位圖)類(lèi)中提供了一個(gè)ScanLine屬性,使用它我們可以快速地進(jìn)行象素讀取和設(shè)置。這在后面的章節(jié)中有詳細(xì)的說(shuō)明。

Canvas類(lèi)中所提供的繪圖方法遠(yuǎn)遠(yuǎn)不止上面提到的這些,本文檔所羅列的只是我認(rèn)為最常用的方法,更多的信息可以參考Delphi的幫助系統(tǒng)。

探究Delphi的圖形處理 之五 -- 使用Canvas類(lèi)繪圖 

作者:何詠     發(fā)布日期:(2005-4-12 21:03:21)

聲明:本文著作權(quán)屬于何詠,如要轉(zhuǎn)載請(qǐng)聲明作者及出處。

  使用Canvas類(lèi)繪圖

我們知道,在Canvas類(lèi)中可以完成各種繪圖操作。仔細(xì)觀察,會(huì)發(fā)現(xiàn)在Delphi提供的許多組件中,都有Canvas類(lèi)。這是因?yàn)檫@些組件都繼承自TGraphicControl基類(lèi),這個(gè)基類(lèi)就提供了Canvas類(lèi)。但我們并不滿(mǎn)足于直接使用它們的Canvas來(lái)繪圖,這是沒(méi)有效率的。因?yàn)?/SPAN>TGraphicControl是一個(gè)可視化控件,當(dāng)我們?cè)谶@些控件上繪圖時(shí),繪制的圖形會(huì)即時(shí)地翻印到前臺(tái)(即用戶(hù)的屏幕)上,而很多時(shí)候,我們希望在繪圖結(jié)束后才將圖像翻到前臺(tái),這樣可以大大提高工作效率。這里就使用到了一個(gè)緩沖的思想。即在內(nèi)存中開(kāi)一塊空間,在這塊空間上繪圖,繪圖完后,再將這塊空間中的圖像翻印到前臺(tái)。

這里,我們可以使用Delphi為我們提供的TBitmap(位圖)類(lèi)。這個(gè)類(lèi)也提供了Canvas類(lèi),我們同樣可以在這個(gè)Canvas類(lèi)上繪圖。繪制完后,我們用 控件名.Canvas.Draw(0,0,Bitmap)把這個(gè)位圖翻到前臺(tái)。

下面的例子可以在PaintBox上繪制一個(gè)漸變顏色的矩形。

程序2.1

unit Unit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls, ExtCtrls;

 

type

  TfrmMain = class(TForm)

    PaintBox1: TPaintBox;

    btnDraw: TButton;

    procedure btnDrawClick(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  frmMain: TfrmMain;

 

implementation

 

{$R *.dfm}

 

procedure TfrmMain.btnDrawClick(Sender: TObject);

var Bit:TBitmap;

    i:Integer;

begin

  Bit := TBitmap.Create;

  try

    Bit.Height := 300;

    Bit.Width := 387;

    For i := 0 to 200 do begin

       Bit.Canvas.MoveTo(50,i+50);

       Bit.Canvas.Pen.Color := RGB(0,0,Round((1-(i)/200) * 255));

       Bit.Canvas.LineTo(350,i+50);

    end;

    PaintBox1.Canvas.Draw(0,0,Bit);

  finally

    Bit.Free;

  end;

end;

 

end.

程序的運(yùn)行結(jié)果如下:

現(xiàn)在說(shuō)明一下上面的程序。首先我們用 Bit:=TBitmap.Create;語(yǔ)句在內(nèi)存中創(chuàng)建一個(gè)位圖對(duì)象。然后分別設(shè)置了位圖的高度和寬度。接下來(lái)使用了一個(gè)循環(huán)語(yǔ)句一行一行地畫(huà)出顏色不斷加深的線條。最后在PaintBoxCanvas中把這個(gè)位圖復(fù)制過(guò)去。

事實(shí)上,這個(gè)程序只使用了極少量的繪圖方法,并不需要?jiǎng)?chuàng)建位圖對(duì)象繪圖。本程序使用位圖只是為了說(shuō)明的方便。

探究Delphi的圖形處理 之六 -- 使用ScanLine屬性進(jìn)行高效的圖像處理 

作者:何詠     發(fā)布日期:(2005-4-12 21:02:19)

聲明:本文著作權(quán)屬于何詠,如要轉(zhuǎn)載請(qǐng)聲明作者及出處。

  使用ScanLine屬性進(jìn)行高效的圖像處理

在上一節(jié)的例子中,我們使用了Bitmap類(lèi)。Bitmap是一個(gè)處理位圖圖像的類(lèi)。這個(gè)類(lèi)允許你載入、創(chuàng)建和處理位圖圖像。Delphi的圖形處理,都是使用Bitmap類(lèi)來(lái)完成的。當(dāng)然,用Bitmap類(lèi)來(lái)處理圖片并不意味著Delphi只能處理位圖圖像,你可以用支持其他圖片格式的類(lèi)將這些圖片載入,然后把它們轉(zhuǎn)為Bitmap格式,再使用Bitmap類(lèi)進(jìn)行處理,最后在把Bitmap格式轉(zhuǎn)換為想要輸出的格式即可。這在后面的章節(jié)中會(huì)詳細(xì)地講解。

上一節(jié)中,我們提到了CanvasPixels屬性,該屬性可以讀取和更改位圖中每一像素的顏色值,這一功能在圖形處理非常有用。因?yàn)閳D像處理濾鏡就是通過(guò)讀取每一像素的顏色值決定當(dāng)前像素新的顏色值,通過(guò)改變這些顏色值來(lái)實(shí)現(xiàn)各種效果。但是,通過(guò)實(shí)驗(yàn)我發(fā)現(xiàn),對(duì)于一個(gè)較大的圖像,使用Pixels屬性是非常慢的。處理一幅800*600的圖像竟然需要幾秒中的時(shí)間。這是因?yàn)?/SPAN>Pixels屬性的Readwrite過(guò)程調(diào)用了GetPixelSetPixe這兩個(gè)GDI繪圖函數(shù)。每次執(zhí)行SetPixelsGetPixel,都進(jìn)行了大量的重復(fù)運(yùn)算,這樣只要圖像越大,處理時(shí)間會(huì)成倍增長(zhǎng)。使用Pixels屬性來(lái)處理圖片肯定不可行。然而我發(fā)現(xiàn)了一種新的東西來(lái)取代Pixels屬性,這就是Bitmap類(lèi)的ScanLine屬性。ScanLine屬性返回一個(gè)位圖中一行像素的顏色值。而且ScanLine屬性在讀取圖片的時(shí)候使用了DIB()處理方法,這種處理方法比通常的SetPixelGetPixel快得多。下面的實(shí)驗(yàn)就展示了使用Pixel屬性和使用ScanLine屬性的速度差異。

這個(gè)實(shí)驗(yàn)是分別使用Pixel屬性和ScanLine屬性把一個(gè)大小為600*450的圖片轉(zhuǎn)為灰度。把圖片轉(zhuǎn)為灰度的算法在后面的章節(jié)中有具體的介紹,這里不再解釋。以下是使用Pixel屬性完成任務(wù)的程序。

程序2.2

unit Unit1;

 

  {使用Pixels屬性將圖像轉(zhuǎn)為灰度}

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls, ExtCtrls;

 

type

  TForm1 = class(TForm)

    PaintBox1: TPaintBox;

    btnConvert: TButton;

    lblTime: TLabel;

    procedure FormCreate(Sender: TObject);

    procedure btnConvertClick(Sender: TObject);

    procedure FormDestroy(Sender: TObject);

    procedure PaintBox1Paint(Sender: TObject);

  private

    Procedure DecodeColor(Const Color : TColor; var R,G,B:Byte);

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

  Bit: TBitmap;

implementation

 

{$R *.dfm}

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  Bit:=TBitmap.Create;

  Bit.LoadFromFile(‘Test.bmp‘);

end;

 

procedure TForm1.btnConvertClick(Sender: TObject);

var i , j :Integer;NewColor:Byte; R,G,B:Byte; C:TColor; T:LongInt;

begin

  T:=GetTickCount;

  For i := 0 to bit.Width-1 do

  begin

    for j := 0 to bit.Height-1 do

    begin

      C:= Bit.Canvas.Pixels[i,j];

      DecodeColor(C,R,G,B);

      NewColor := (R+G+B) Div 3;

      Bit.Canvas.Pixels[i,j] := RGB(NewColor,NewColor,NewColor);

    end;

  end;

  T := GetTickCount -t;

  LblTime.Caption := ‘用時(shí):‘ + IntToStr(T) + ‘ms‘;

  PaintBox1.Canvas.StretchDraw(Rect(0,0,320,240),Bit);

end;

 

procedure TForm1.DecodeColor(const Color: TColor; var R, G, B: Byte);

begin

  R := Color mod 256;

  G := (color Div 256) mod 256;

  B := Color Div 65536;

end;

 

procedure TForm1.FormDestroy(Sender: TObject);

begin

  Bit.Free;

end;

 

procedure TForm1.PaintBox1Paint(Sender: TObject);

begin

  PaintBox1.Canvas.StretchDraw(Rect(0,0,320,240),Bit);

end;

 

end.

以下是使用ScanLine屬性的程序:

程序2.3

unit Unit1;

 

{使用ScanLine屬性完成任務(wù)}

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls, ExtCtrls;

 

type

  TForm1 = class(TForm)

    PaintBox1: TPaintBox;

    lblTime: TLabel;

    btnConvert: TButton;

    procedure FormCreate(Sender: TObject);

    procedure PaintBox1Paint(Sender: TObject);

    procedure btnConvertClick(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

  Bit : TBitmap;

implementation

 

{$R *.dfm}

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  Bit := TBitmap.Create;

  Bit.LoadFromFile(‘Test.Bmp‘);

  Bit.PixelFormat := pf24Bit;

  Bit.HandleType := bmDIB;

end;

 

procedure TForm1.PaintBox1Paint(Sender: TObject);

begin

  PaintBox1.Canvas.StretchDraw(Rect(0,0,320,240),Bit);

end;

 

procedure TForm1.btnConvertClick(Sender: TObject);

var CurLine : PByteArray;

    NewColor : Byte;

    i : Integer;

    j : Integer;

    m : Integer;

    t : LongInt;

begin

  t:=GetTickCount;

  For i  := 0 to Bit.Height-1 do

  begin

    CurLine := Bit.ScanLine[i];

    for j := 0 to Bit.Width-1 do begin

      m := j *3;

      NewColor := (curLine[m]+CurLine[m+1]+CurLine[m+2])Div 3;

      CurLine[m] := NewColor;

      CurLine[m+1] := NewColor;

      CurLine[m+2] := NewColor;

    end;

  end;

  t:=GetTickCount-t;

  PaintBox1.Canvas.StretchDraw(Rect(0,0,320,240),Bit);

  lblTime.Caption := ‘用時(shí):‘+IntToStr(t) + ‘ms‘;

end;

 

end.

下面就來(lái)比較一下它們的運(yùn)行結(jié)果:

使用Pixels屬性的運(yùn)行結(jié)果

使用ScanLine屬性的運(yùn)行結(jié)果

現(xiàn)在,我們來(lái)詳細(xì)分析ScanLine屬性的具體用法。

ScanLine屬性是一個(gè)只讀屬性,它返回一個(gè)數(shù)組指針,存放當(dāng)前Bitmapi行的像素顏色值。數(shù)組指針的類(lèi)型可以是PByteArray(字節(jié)數(shù)組指針)或者^array of TRGBTriple(像素顏色數(shù)組指針)。我覺(jué)得使用PByteArray類(lèi)型是最直接、最方便的,在本文中,我們都將使用PByteArray類(lèi)型。PByteArray類(lèi)型指向一個(gè)Byte類(lèi)型的一維數(shù)組。這個(gè)數(shù)組的第j*3個(gè)值表示當(dāng)前行第j個(gè)像素顏色值的B分值(藍(lán)色分值),第j*3+1個(gè)值表示當(dāng)前行第j個(gè)像素顏色值的G分值(綠藍(lán)色分值), j*3+2個(gè)值表示當(dāng)前行第j個(gè)像素顏色值的R分值(紅藍(lán)色分值)。其中j[0,圖像寬度-1]

ScanLine[i]表示當(dāng)前Bitmapi行的像素值。因此RGB(ScanLine[i][j*3+2],ScanLine[i][j*3+1], ScanLine[i][j*3])可以表示圖像中點(diǎn)(j,i)的顏色值。不過(guò)在程序中,這樣寫(xiě)是沒(méi)有效率的,我們?yōu)榱双@取一個(gè)像素就用了3ScanLine,浪費(fèi)了很多時(shí)間。下面的代碼可以用ScanLine讀取整個(gè)Bitmap的像素值:

程序2.4

Type TPixels = Array of Array of TRGBTriple;

 

Procedure ReadPixel(Pic: Tbitmap; var tPix: TPixels);

Var PixPtr:PbyteArray;i,j,m:Integer;

begin

  SetLength(tPix,Pic.Width,Pic.Height);

  Pic.PixelFormat := pf24bit;

  Pic.HandleType:=bmDIB;

  For i :=0 to pic.Height-1 do begin

      PixPtr:=Pic.ScanLine[i];

      for  j:= 0 to pic.Width-1 do begin

         m := j*3;

         tPix[j,i].rgbtBlue:=PixPtr[m];

         tPix[j,i].rgbtGreen := PixPtr[m+1];

         tPix[j,i].rgbtRed := PixPtr[m+2];

      end;

  end;

end;

       在此說(shuō)明一下上面的代碼。首先定義TPixels為一個(gè)二維動(dòng)態(tài)數(shù)組,類(lèi)型為TRGBTriple。TRGBTriple是一個(gè)記錄類(lèi)型,它可以保存一個(gè)像素值的R、G、B分值。下面是TRGBTriple的原形聲明:

TRGBTriple = tagRGBTRIPLE;

tagRGBTRIPLE = packed record

    rgbtBlue: Byte;

    rgbtGreen: Byte;

    rgbtRed: Byte;

  end; 

因此,TPixels類(lèi)型就可以表示Bitmap中所有像素的值。值得強(qiáng)調(diào)的是程序的第二行:

Pic.PixelFormat := pf24bit;

這行代碼的作用是把這個(gè)位圖轉(zhuǎn)為24位位圖格式。因?yàn)橹挥?/SPAN>24位的位圖格式才符合上面所說(shuō)的規(guī)則。如果沒(méi)有這行代碼,當(dāng)程序碰上非24位位圖的文件時(shí)就不能正常運(yùn)行。至于Pic.HandleType := bmDIB;這行代碼是為了強(qiáng)制把當(dāng)前Bitmap的操作方式轉(zhuǎn)化為DIB方式,這只是為了確保萬(wàn)無(wú)一失。

       那么,既然ScanLine屬性是只讀的,我們?nèi)绾胃淖冞@些顏色值呢?我們知道,ScanLine屬性返回的是一個(gè)指針。既然是指針,我們就可以改變指針?biāo)赶虻臄?shù)據(jù),通過(guò)這種方式就可以改變Bitmap中的顏色值了。下面的程序段演示了如何把一個(gè)TPixels變量寫(xiě)到Bitmap中去。

程序2.5

Procedure WritePixel(Pic: TBitmap; tPix: TPixels);

var PixPtr:PByteArray;i,j,m:Integer;

begin

  pic.PixelFormat := pf24bit;

  pic.HandleType:=bmDIB;

  Pic.Height := High(tPix[0])+1;

  Pic.Width:= High(tPix)+1;

  For i :=0 to pic.Height-1 do begin

      PixPtr:=Pic.ScanLine[i];

      for  j:= 0 to pic.Width-1 do begin

         m := j*3;

         PixPtr[M] := tPix[j,i].rgbtBlue;

         PixPtr[m+1] := tPix[j,i].rgbtGreen;

         PixPtr[m+2] := tPix[j,i].rgbtRed;

      end;

  end;

end;

這樣,我們?cè)趫D形處理時(shí),就可以先用ReadPixel過(guò)程把位圖讀到一個(gè)TPixels類(lèi)型的變量中去,然后處理這個(gè)TPixels變量,處理完后,用WritePixel過(guò)程把這個(gè)變量寫(xiě)到Bitmap中去,這就完成了修改過(guò)程。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多