程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 一個畫漸變的方法

一個畫漸變的方法

編輯:Delphi
(*
    ———————————————原理:————————————————
    對於任何一種線性漸變(就是最常見的那種),在由起點和終點定義的漸變區
    內,像素的RGB分量對於X和Y坐標的偏導數都是常量。於是我們可以先用極小
    的代價來計算出這個二元方程的初始值,然後使用累加遞推的方法計算出所有
    的值。
    ———————————————注 1:————————————————
    漸變區:由分別經過起點和終點,並垂直於這兩點連線的平行直線和繪圖區域
    的邊界圍成的區域。在這個區域以外的像素不再有漸變。
    ———————————————注 2:————————————————
    為了簡化編程,我使用了浮點數來進行累加計算。實際上可以先用移位操作來
    “放大”顏色值以提高累加時的精度,寫入位圖時再用移位“縮小”來恢復實
    際的值。
    ———————————————測試:————————————————
    該方法在Delphi6下調試通過。在Duron800,1152 X 864下采取重回1000次取
    平均值的方法測試。
    100 X 100:平均為4ms;
    500 X 200:平均為18ms;
    (我同時還在聽MP3:P)
  *)
  
  function SSDrawGradIEnt(ACanvas: TCanvas; AClipRect: TRect;
    FromPoint, ToPoint: TPoint; FromColor, ToColor: TColor): Boolean;
  type
    TSSGradIEntDirection=(gdEast, gdWest, gdNorth, gdSouth, gdOther);
  var
    buf:TBitmap;
    w,h,y,x,XOffset,ir,ig,ib,pw,ph:Integer;
    c1, c2: TColor;
    r1,g1,b1,r2,g2,b2,br,bg,bb,rmax,rmin,gmax,gmin,bmax,bmin: Byte;
    kx,ky,kx0,ky0,rx0,gx0,bx0,r0,g0,b0,drx,dry,dgx,dgy,dbx,dby,dr,dg,db: Double;
    P : PByteArray;
  
    function GetStep(V1, V2, V3:Integer): Double;
    begin
      if V2=V1 then Result:=0
      else Result:=V3/(V2-V1);
    end;
  
  begin
    Result:=False;
    if (FromPoint.Y=ToPoint.Y)and(FromPoint.X=ToPoint.X) then Exit;
    buf:=TBitmap.Create;
    try
      //初始化緩沖區
      buf.PixelFormat:=pf24bit;
      w:=WidthOfRect(AClipRect);
      buf.Width:=w;
      h:=HeightOfRect(AClipRect);
      buf.Height:=h;
      //為了防止運算溢出而設的檢查
      if (w>Screen.Width)or(h>Screen.Height) then Exit;
  
      //讀取漸變起點和終點的RGB值
      c1:=ColorToRGB(FromColor);
      c2:=ColorToRGB(ToColor);
      r1:=GetRValue(c1);
      g1:=GetGValue(c1);
      b1:=GetBValue(c1);
      r2:=GetRValue(c2);
      g2:=GetGValue(c2);
      b2:=GetBValue(c2);
      if r1>r2 then begin rmin:=r2; rmax:=r1 end
      else begin rmin:=r1; rmax:=r2 end;
      if g1>g2 then begin gmin:=g2; gmax:=g1 end
      else begin gmin:=g1; gmax:=g2 end;
      if b1>b2 then begin bmin:=b2; bmax:=b1 end
      else begin bmin:=b1; bmax:=b2 end;
      pw:=Abs(ToPoint.X-FromPoint.X);
      ph:=Abs(ToPoint.Y-FromPoint.Y);
      kx:=pw/Sqrt(ph*ph+pw*pw);
      ky:=ph/Sqrt(ph*ph+pw*pw);
     
      //計算出RGB值相對於XY軸的線性變化系數
      drx:=GetStep(AClipRect.Left, AClipRect.Right, Round((r2-r1)*kx));
      dry:=GetStep(AClipRect.Top, AClipRect.Bottom, Round((r2-r1)*ky));
      dgx:=GetStep(AClipRect.Left, AClipRect.Right, Round((g2-g1)*kx));
      dgy:=GetStep(AClipRect.Top, AClipRect.Bottom, Round((g2-g1)*ky));
      dbx:=GetStep(AClipRect.Left, AClipRect.Right, Round((b2-b1)*kx));
      dby:=GetStep(AClipRect.Top, AClipRect.Bottom, Round((b2-b1)*ky));
  
      //計算出矩形左上角的RGB值,備用
      kx0:=GetStep(FromPoint.X, ToPoint.X, FromPoint.X);
      ky0:=GetStep(FromPoint.Y, ToPoint.Y, FromPoint.Y);
      r0:=r1+(kx0+ky0)*r2;
      g0:=g1+(kx0+ky0)*g2;
      b0:=b1+(kx0+ky0)*b2;
  
      //這三個變量是每個掃描線的第一個點的RGB值
      rx0:=r0;
      gx0:=g0;
      bx0:=b0;
      for y:=0 to h-1 do
      begin
        XOffset:=0;
        //dr意思是Double類型的紅色值,其他類推
        dr:=rx0;
        dg:=gx0;
        db:=bx0;
        P := buf.ScanLine[y];
        for x:=0 to w-1 do
        begin
          //ir的意思是整型的紅色值,其他類推
          //之所以要先轉成整型,是因為我覺得整型的比較也許會比浮點快一點
          //反正都要三次Round的,不如早做……
          ir:=Round(dr);
          ig:=Round(dg);
          ib:=Round(db);
          //br的意思是字節型的紅色值
          br:=Max(Min(rmax,ir),rmin);
          bg:=Max(Min(gmax,ig),gmin);
          bb:=Max(Min(bmax,ib),bmin);
          //按照偏移量設置RGB值
          P[XOffset]:=bb;
          P[XOffset+1]:=bg;
          P[XOffset+2]:=br;
  
          if FromPoint.X<>ToPoint.X then
          begin
            //下一個像素的RGB值分別按照一定的系數遞增
            dr:=dr+drx;
            dg:=dg+dgx;
            db:=db+dbx;
          end;
          //因為我定義的P是字節型的數組,所以這裡遞增“3”,避免使用乘法
          Inc(XOffset, 3);
        end;
        if FromPoint.Y<>ToPoint.Y then
        begin
          //按照RGB在Y軸方向上的變化規律計算下一行的第一個像素RGB值
          rx0:=rx0+dry;
          gx0:=gx0+dgy;
          bx0:=bx0+dby;
        end;
      end;
      //將緩沖區復制到目標上
      BitBlt(ACanvas.Handle, AClipRect.Left, AClipRect.Top, w, h,
        buf.Canvas.Handle, 0, 0, SRCCOPY);
      Result:=True;
    finally
      buf.Free;
    end;
  end;
  
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved