有没有办法以编程方式使给定 RGB 值的颜色变暗?

Posted

技术标签:

【中文标题】有没有办法以编程方式使给定 RGB 值的颜色变暗?【英文标题】:Is there a way to programmatically darken the color given RGB values? 【发布时间】:2015-07-25 00:44:32 【问题描述】:

假设我有这样的 RGB 值(例如在 R 中):

cols <- c("#CDE4F3","#E7F3D3","#F7F0C7","#EFCFE5","#D0D1E7")

有没有办法以编程方式派生另一组颜色,它是前者的暗色版本?

不一定是R。

【问题讨论】:

非 R 答案:***.com/questions/1787124/… 和 ***.com/questions/5560248/… 【参考方案1】:

这里有一些对我有用的简单方法,并以与原始格式相同的格式返回颜色:

library(colorspace)

cols <- c("#CDE4F3","#E7F3D3","#F7F0C7","#EFCFE5","#D0D1E7")    
rgb(hex2RGB(cols)@coords * 0.8)

【讨论】:

【参考方案2】:

您实际上可以使用colorRampPalette() 在基本图形中轻松完成此操作。

只需使用您的初始颜色和黑色制作渐变,渐变 100 并选择您想要的“深多少”(1=初始和 100=黑色)。

我在一个简洁的小函数中做了这个:

darker.col = function(color, how.much = 30)
  colorRampPalette(c(color, "black"))(100)[how.much]


plot(1:100, rep(1, 100), pch=16, cex=5, col=darker.col("royalblue", 1:100))

【讨论】:

【参考方案3】:

问题询问是否有任何方法以编程方式使颜色变暗。问题是有许多不同的方法,它们都会产生不同的结果。您获得的具体结果取决于所采用的具体算法和所使用的色彩空间。

R 包colorspace 现在通过darken() 函数提供了一个内置函数来加深颜色。此函数使用我们提出的新“组合”色彩空间,它是 HLS 和 HCL 的混合。 (简而言之,在 HCL 空间中调整 L,但通过 HLS 绕道调整 C,同时保持 H 不变。)

要使用该功能,需要安装当前开发版的colorspace:

install.packages("colorspace", repos = "http://R-Forge.R-project.org")

然后,尝试以下操作:

# original colors
cols <- c("#CDE4F3", "#E7F3D3", "#F7F0C7", "#EFCFE5", "#D0D1E7")

# darken 20%
cols_d2 <- darken(cols, 0.2)

# darken 40%
cols_d4 <- darken(cols, 0.4)

# plot
pal <- function(col, border = "light gray") 
  n <- length(col)
  plot(0, 0, type="n", xlim = c(0, 1), ylim = c(0, 1), axes = FALSE,
       xlab = "", ylab = "")
  rect(0:(n-1)/n, 0, 1:n/n, 1, col = col, border = border)


par(mfrow = c(3, 1), mar = c(1, 0, 2, 0))
pal(cols); mtext("original")
pal(cols_d2); mtext("20% darker")
pal(cols_d4); mtext("40% darker")

您可以尝试几种不同的色彩空间和其他调整选项,但默认值在大多数情况下应该可以工作。

要查看在不同颜色空间中变暗的效果,请考虑当我们在 HCL 或 HLS 中变暗相同颜色时会发生什么:

HCL 变暗的颜色看起来很灰,而 HLS 变暗的颜色显得过于明亮和多彩。但是,根据您的具体应用,您可能需要其中一种结果。

【讨论】:

【参考方案4】:

这不是很好的代码。 munsell 包可能更友好

library(colorspace)

cols <- c("#CDE4F3","#E7F3D3","#F7F0C7","#EFCFE5","#D0D1E7")

lab = as(hex2RGB(cols),"LAB")
lab@coords[,1] = lab@coords[,1] *0.3 # 
cols1 =  hex(as(lab,"RGB"))
cols1

【讨论】:

【参考方案5】:
library(colorspace)

cols <- c("#CDE4F3","#E7F3D3","#F7F0C7","#EFCFE5","#D0D1E7")

cols1 <- readhex(file = textConnection(paste(cols, collapse = "\n")),
                 class = "RGB")
#transform to hue/lightness/saturation colorspace
cols1 <- as(cols1, "HLS")
cols2 <- cols1
#additive decrease of lightness
cols1@coords[, "L"] <- pmax(0, cols1@coords[, "L"] - 0.3)
#multiplicative decrease of lightness
cols2@coords[, "L"] <- cols2@coords[, "L"] * 0.75
#going via rgb seems to work better  
cols1 <- as(cols1, "RGB")
cols1 <- hex(cols1)
cols2 <- as(cols2, "RGB")
cols2 <- hex(cols2)


plot(x = seq_along(cols), y = rep(1, length(cols)), 
     col = cols, pch = 15, ylim = c(0, 4.5), cex = 5,
     xlab = "", ylab = "")
points(x = seq_along(cols), y = rep(2, length(cols)), 
       col = cols1, pch = 16, cex = 5)
points(x = seq_along(cols), y = rep(3, length(cols)), 
       col = cols2, pch = 17, cex = 5)

legend("top",legend = c("original", "additive", "multipl."), 
       pch = 15:17, ncol = 3)

【讨论】:

@Gregor 或者更确切地说是pmax cols1 &lt;- hex2RGB(cols, TRUE) 是第三行的更简单版本。很好的答案 - 非常有用。 colorspace 包现在有一个内置函数 darken() 可以做到这一点(虽然目前不在 RGB 空间中)。看我的回答。【参考方案6】:

HSV值调整

这似乎比我第一次使用 Munsell 颜色(下图)要好得多。它仍然有点绕路(可能是因为我正在混合在行和列中指定颜色并采用矩阵或不采用矩阵的包),但它有效:

cols.hsv = rgb2hsv(cols.rgb)
# adjust the "value" down to 80% of it's previous level
cols.hsv["v", ] = cols.hsv["v", ] * 0.8

cols.darker = cols
for (i in seq_along(cols)) 
    cols.darker[i] = hsv(cols.hsv[1, i], cols.hsv[2, i], cols.hsv[3, i])


par(mfrow = c(1, 2))
scales::show_col(cols)
scales::show_col(cols.darker)

孟塞尔

我以前没有使用过 munsell 包,所以我可能会比它需要的更复杂,但它有一个函数 darker ,“将孟塞尔颜色的值减 1”。

困难的部分是转换。据我所知,我们需要将您的十六进制颜色转换为必须通过 RGB 进行的孟塞尔颜色。

cols <- c("#CDE4F3","#E7F3D3","#F7F0C7","#EFCFE5","#D0D1E7")
cols.rgb = col2rgb(cols)

library(munsell)
# munsell expects rgb colors in rows, not columns, and expects the
# values to be between 0 and 1, not 0 and 255
cols.m = rgb2mnsl(t(cols.rgb) / rowSums(t(cols.rgb)))

# make darker
darker.m = darker(cols.m)
# at least converting back to hex is one step!
darker.hex = mnsl2hex(darker.m)


# view the results
par(mfrow = c(2, 1))
scales::show_col(cols)
scales::show_col(darker.hex)

总的来说,我对这个解决方案并不满意。它使颜色大大变暗了,我看不到在 darker 函数中调整它的方法。

【讨论】:

刚刚尝试了您的munsell 解决方案,我现在可以看到为什么darker() 函数只将颜色降低了一步。第二步将是完全黑色的!在colorspace 中尝试新的darken() 功能(请参阅我的答案)。【参考方案7】:

是的。

您必须指定要变暗或变亮的程度。

这是一个用 javascript 完成的函数:https://css-tricks.com/snippets/javascript/lighten-darken-color/

function LightenDarkenColor(col, amt) 
    var usePound = false;
    if (col[0] == "#") 
        col = col.slice(1);
        usePound = true;
    
    var num = parseInt(col,16);
    var r = (num >> 16) + amt;
    if (r > 255) 
      r = 255;
    else if  (r < 0) 
      r = 0;
    
    var b = ((num >> 8) & 0x00FF) + amt;
    if (b > 255) 
      b = 255;
    else if  (b < 0) 
      b = 0;
    
    var g = (num & 0x0000FF) + amt;
    if (g > 255) 
      g = 255;
    else if (g < 0) 
      g = 0;
    
    return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);

希望对你有帮助, 干杯。

【讨论】:

请允许我建议对您的变暗算法进行细微的改进。与其将“amt”用作加法项,不如将其用作乘法项。想象一下原始颜色是橙色,例如#FF8800。由于它因添加变化而变暗,随着它越来越暗,它变成纯深红色(#880000)。如果进行乘法更改,则更改色调的趋势会更小,从而产生逐渐变深的橙色阴影。

以上是关于有没有办法以编程方式使给定 RGB 值的颜色变暗?的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式使飞镖中的十六进制颜色变亮或变暗

在matplotlib中使颜色变暗或变亮

以编程方式使视图变暗

Android M Light and Dark状态栏以编程方式 - 如何使其再次变暗?

创建修改先前值的地图值

SpriteKit Swift 使整个场景变暗,然后将其改回