【问题标题】:Fastest way to calculate colors for a gradient?计算渐变颜色的最快方法?
【发布时间】:2011-11-24 06:30:50
【问题描述】:

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

我已经在下面完成了大部分工作。除了,我有两个核心问题:

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

代码如下:

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 个可能的值。

【问题讨论】:

  • 字节怎么可能在 0..255 子范围之外?

标签: delphi graphics colors delphi-7 gradient


【解决方案1】:

听起来你想替换你的???与

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

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

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);

这在数组的两端给出了相同的行为。或者您可能希望同时包含ColorAColorB。然后你会使用:

X / (Count-1) * 100.0

但如果你这样做,请记住 Count 必须大于 1,否则你将被零除。这永远不会成功!


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


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

【讨论】:

  • 谢谢,现在假设我想将 Percent: Integer 转换为 Percent: Single 以获得更平滑的效果 - 我将更新问题以包含它。
  • 嗯,这是一个相当不同的问题。我现在更新了我的答案,去掉了所有的整数运算。
  • 对于确保范围,将其应用于百分比。
  • 乘以 (1/100) 而不是除以 100 以获得更好的性能(是的,除法仍然比乘法慢很多)
  • @Eric 这是真的。另一方面,我发现代码的可读性较差。我相信这个例程不会成为热点,那么为什么要牺牲可读性而没有实际收益呢?
【解决方案2】:

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

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;

【讨论】:

    猜你喜欢
    • 2010-09-24
    • 2014-08-21
    • 2014-05-01
    • 2018-07-18
    • 1970-01-01
    • 2020-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多