计算渐变颜色的最快方法?

时间:2011-11-24 06:30:50

标签: delphi graphics colors delphi-7 gradient

我正在制作与渐变相关的一小部分类型/功能,以备将来使用。我想确保至少有两个过程:ColorBetween和ColorsBetween。我可能想要在任意两种颜色(ColorsBetween)之间获得一个TColor数组,我可能只需要知道一种颜色值,两种颜色之间的百分比(ColorBetween)。

我已经在下面完成了它。除此之外,我有两个核心问题:

  1. 如何按给定百分比计算每个RGB通道的中间颜色? (见下面我有[???]
  2. 的地方
  3. 完成我正在做的事情的最快方法是什么(保留两个不同的功能)?

  4. 以下是代码:

    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
      StrUtils, StdCtrls, Math;
    
    type
      TColorArray = array of TColor;
    
    implementation
    
    function ColorsBetween(const ColorA, ColorB: TColor; const Count: Integer): TColorArray;
    var
      X: Integer; //Loop counter
    begin
      SetLength(Result, Count);
      for X:= 0 to Count - 1 do 
        Result[X]:= ColorBetween(ColorA, ColorB, Round((X / Count) * 100)); //Correct?
    end;
    
    function ColorBetween(const ColorA, ColorB: TColor; const Percent: Single): TColor;
    var
      R1, G1, B1: Byte;
      R2, G2, B2: Byte;
    begin
      R1:= GetRValue(ColorA);
      G1:= GetGValue(ColorA);
      B1:= GetBValue(ColorA);
      R2:= GetRValue(ColorB);
      G2:= GetGValue(ColorB);
      B2:= GetBValue(ColorB);
      Result:= RGB(
        EnsureRange(([???]), 0, 255),
        EnsureRange(([???]), 0, 255),
        EnsureRange(([???]), 0, 255)
      );
    end;
    

    编辑:将Percent: Integer更改为Percent: Single以获得更流畅的效果 - 不限于100个可能的值。

2 个答案:

答案 0 :(得分:7)

听起来你想要更换你的???与

Round((R1*Percent + R2*(100-Percent))/100.0)

代码中的EnsureRange不是必需的,因为如果Percent在0到100的范围内,此函数必须返回0到255范围内的值。我想我会应用{{ 1}}到EnsureRange(强制它进入范围0.0到100.0)然后使用以下代码:

Percent

您的第一个函数返回第一个颜色为Result := RGB( Round((R1*Percent + R2*(100-Percent))/100.0), Round((G1*Percent + G2*(100-Percent))/100.0), Round((B1*Percent + B2*(100-Percent))/100.0), ); 的数组。也许你会更好:

ColorA

这在数组的两端给出了相同的行为。或者您可能希望同时包含for X:= 0 to Count - 1 do Result[X]:= ColorBetween(ColorA, ColorB, (X+1) / (Count+1) * 100.0); ColorA。然后你会使用:

ColorB

但是如果你这样做,请记住Count必须大于1,否则你将除以零。那个蠢货就行了!!


不要担心性能。毫无疑问,代码可以稍快一点,但它肯定不会成为瓶颈。您将采用这些颜色并与它们一起绘制。与这些简单的例程相比,这将消耗更多的资源。


最后一点。 RGB空间中的插值对于人眼来说看起来不是特别平滑或线性的。使用浮点百分比无法回避这一事实。为了在查看时获得最佳效果,您需要在不同的色彩空间中进行插值。

答案 1 :(得分:4)

我不知道这是否是最快的方式,但它有效:

function ColorBetween(const ColorA, ColorB: TColor; const Percent: Integer): TColor;
var
  R1, G1, B1: Byte;
  R2, G2, B2: Byte;
begin
  R1:= GetRValue(ColorA);
  G1:= GetGValue(ColorA);
  B1:= GetBValue(ColorA);
  R2:= GetRValue(ColorB);
  G2:= GetGValue(ColorB);
  B2:= GetBValue(ColorB);

  Result:= RGB(
    Percent * (R2-R1) div 100 + R1,
    Percent * (G2-G1) div 100 + G1,
    Percent * (B2-B1) div 100 + B1
  );
end;

function ColorsBetween(const ColorA, ColorB: TColor; const Count: Integer): TColorArray;
var
  X : integer;
begin
  SetLength(Result, Count);
  for X := 0 to Count - 1 do
    Result[X] := ColorBetween(ColorA, ColorB, Round((X / (Count-1)) * 100));  //Note: Divide by count-1
end;