如何在 Google Apps 脚本中根据单元格的背景颜色反转字体颜色?

How to inverse font color based on cell's background Color in Google Apps Script?

我想知道如何根据背景颜色自动反转单元格值的字体颜色以使其可读。

我使用以下脚本在将十六进制颜色代码粘贴到给定单元格时自动设置背景颜色How do I change a cell to the color of the hexadecimal value of a cell in Google Spreadsheets?, with sample sheet here

function onEdit(e) {
  r = e.range;

  if(r.getSheet().getSheetName() == "colors"){ //the sheet I want to apply this to is called colors

    var rows = r.getNumRows();
    var columns = r.getNumColumns();
    var colors = [] //this is our 2 dimensional array of colors in case you copy and paste a large amount of colors

    for (var i = 1; i <= rows; i++) { //go down each row
      var row = [] //create a new row array to clear the old one when we go down a row
      for (var j = 1; j <= columns; j++) { //then go across each column
        row.push(r.getCell(i,j).getValue()) //put together the row of colors
      }
      colors.push(row); //insert our row of colors so we can go down the next row
    }
    r.setBackgrounds(colors) //batch update in case you update many colors in one copy and paste otherwise it will be very slow
  }
}

但剩下的问题是字体没有显示在深色背景单元格上。

我也找到了这个相关问题 How to decide font color in white or black depending on background color?。 还有那些 Javascript 带有函数的特定答案,但我无法让它们在 GAS 中使用上述脚本。

JavaScript code 1

JavaScript code 2

JavaScript code 3

JavaScript code 4

JavaScript code 5

JavaScript code 6

我还查看了 setFontColors(colors) 的文档,发现我们可以在上面的脚本中使用方法 r.setFontColors(colors)。 我尝试调用上面的 JavaScript 代码 1 到 6,但我没有成功。

比如我试过这种方式基于JavaScript code 3):

function onEdit(e) {
  r = e.range;

  if(r.getSheet().getSheetName() == "colors"){ //the sheet I want to apply this to is called colors

    var rows = r.getNumRows();
    var columns = r.getNumColumns();
    var colors =  [] //this is our 2 dimensional array of colors in case you copy and paste a large amount of colors

    for (var i = 1; i <= rows; i++) { //go down each row
      var row = [] //create a new row array to clear the old one when we go down a row
      for (var j = 1; j <= columns; j++) { //then go across each column
        row.push(r.getCell(i,j).getValue()) //put together the row of colors
      }
      colors.push(row); //insert our row of colors so we can go down the next row
    }
    r.setBackgrounds(colors) //batch update in case you update many colors in one copy and paste otherwise it will be very slow
    r.setFontColors(lum([111, 22, 255]));
  }
}

function lum(rgb) {
    var lrgb = [];
    rgb.forEach(function(c) {
        c = c / 255.0;
        if (c <= 0.03928) {
            c = c / 12.92;
        } else {
            c = Math.pow((c + 0.055) / 1.055, 2.4);
        }
        lrgb.push(c);
    });
    var lum = 0.2126 * lrgb[0] + 0.7152 * lrgb[1] + 0.0722 * lrgb[2];
    return (lum > 0.179) ? '#000000' : '#ffffff';
}

我错过了什么?

感谢您的见解!

setFontColors 的必需参数是一个二维数组

尝试将r.setFontColors(lum([111, 22, 255]));改成如下代码:

const fontColor = lum([111, 22, 255]);
const fontColorsRow = new Array(columns).fill(fontColor);
const fontColors = new Array(rows).fill(fontColorsRow);
r.setFontColors(fontColors);

参考:

setFontColors(colors)

我相信你的目标如下。

  • 将十六进制值放入单元格后,您想使用输入的十六进制值设置背景颜色。那时,你想根据背景颜色设置每个单元格的字体颜色。

修改点:

  • 在您的脚本中,我认为 colors 的值可以通过 r.getValues() 检索。在这种情况下,不需要使用for循环。

  • r.setFontColors(lum([111, 22, 255]));开始,当你想给范围设置相同的字体颜色时,可以修改如下。

    • 来自

        r.setFontColors(lum([111, 22, 255]));
      
    •   r.setFontColor(lum([111, 22, 255]));
      

但是,根据您的脚本,我认为您可能希望通过每种背景颜色来设置字体颜色。如果我的理解是正确的,下面的修改怎么样?

修改后的脚本:

// I modified this function.
function onEdit(e) {
  var r = e.range;
  if (r.getSheet().getSheetName() == "colors") {
    var colors = r.getValues();
    r.setBackgrounds(colors);
    var fonrColors = r.getBackgroundObjects().map(r => r.map(c => {
      var obj = c.asRgbColor();
      return lum([obj.getRed(), obj.getGreen(), obj.getBlue()]);
    }))
    r.setFontColors(fonrColors);
  }
}

// This is from your script.
function lum(rgb) {
  var lrgb = [];
  rgb.forEach(function (c) {
    c = c / 255.0;
    if (c <= 0.03928) {
      c = c / 12.92;
    } else {
      c = Math.pow((c + 0.055) / 1.055, 2.4);
    }
    lrgb.push(c);
  });
  var lum = 0.2126 * lrgb[0] + 0.7152 * lrgb[1] + 0.0722 * lrgb[2];
  return (lum > 0.179) ? '#000000' : '#ffffff';
}
  • 这次修改,为了把hex转成RGB,我用了getBackgroundObjects()的方法。当然,您可以使用 Javascript 进行转换。如果不想使用getBackgroundObjects(),请勾选this thread

  • 在此修改中,当您将十六进制值放入单元格时,使用十六进制值设置背景颜色,并使用函数 [= 根据背景颜色设置字体颜色18=] 你的脚本。

参考文献:

简答

要根据背景颜色在黑色或白色之间翻转文本颜色,需要将背景颜色转换为亮度,并选择特定的亮度值进行翻转,一般在0.42 Y左右即可。

更长的答案

现实情况是,有许多心理物理因素会影响从黑色或白色文本翻转的最佳点,而不仅仅是特定颜色。字体大小和粗细,以及周围的颜色,房间内的环境光线都会影响“理想翻转点”。

我在 another answer on overflow with simple code snippets. After that answer, I also created a CodePen with live examples 中讨论这个你可以玩。

“超简单又脏又脏”的是:

// First convert your sRGB values to luminance:

let sY = Math.pow(sR/255.0,2.2) * 0.2126 +
         Math.pow(sG/255.0,2.2) * 0.7152 +
         Math.pow(sB/255.0,2.2) * 0.0722; // Andy's Easy Luminance for sRGB. For Rec709 HDTV change the 2.2 to 2.4

// AND THEN SET THE TEXT COLOR PER:

  let textColor = (sY < 0.42) ? "#fff" : "#000"; // Low budget down and dirty text flipper.

这是应该易于移植的最少、最简单的代码。我不熟悉 Google 脚本,但基本上你只需要将每个 8 位颜色除以 255.0,然后应用 2.2 指数,然后乘以系数(红色为 0.2126,绿色为 0.7152,蓝色为 0.0722)并相加。

翻转大约为 0.4 - 可翻转范围大约为 0.36 到 0.43 左右,具体取决于。

如果您真的想深入了解文本对比的本质世界以提高可读性,请查看 APCA 和 SAPC — at the SAPC dev site 单击“研究模式”进行互动实验,展示概念。这些是确定自发光显示器对比度的新方法。