我正在尝试在 Canvas 中绘制以下渐变图像,但右下 Angular 有问题。

想要的效果:

javascript - 绘制饱和度/亮度渐变-LMLPHP

电流输出:

javascript - 绘制饱和度/亮度渐变-LMLPHP

我可能在这里遗漏了一些非常简单的东西。

function color(r, g, b) {
  var args = Array.prototype.slice.call(arguments);
  if (args.length == 1) {
    args.push(args[0]);
    args.push(args[0]);
  } else if (args.length != 3 && args.length != 4) {
    return;
  }
  return "rgb(" + args.join() + ")";
}

function drawPixel(x, y, fill) {
  var fill = fill || "black";
  context.beginPath();
  context.rect(x, y, 1, 1);
  context.fillStyle = fill;
  context.fill();
  context.closePath();
}

var canvas = document.getElementById("primary");
var context = canvas.getContext("2d");

canvas.width = 256;
canvas.height = 256;

for (var x = 0; x < canvas.width; x++) {
  for (var y = 0; y < canvas.height; y++) {
    var r = 255 - y;
    var g = 255 - x - y;
    var b = 255 - x - y;
    drawPixel(x, y, color(r, g, b));
  }
}
#primary {
    display: block;
    border: 1px solid gray;
}
<canvas id="primary"></canvas>


JSFiddle

最佳答案

使用渐变。

您可以让 GPU 为您完成大部分处理。2D 复合操作 multiply 有效地将每个像素的两种颜色相乘。因此,对于每个 channel 和每个像素,colChanDest = Math.floor(colChanDest * (colChanSrc / 255)) 是通过 GPU 的大规模并行处理能力完成的,而不是在单个内核(JavaScript 执行上下文)上运行的低共享线程。

两个梯度

  • 一个是背景从上到下白到黑
    var gradB = ctx.createLinearGradient(0,0,0,255);gradB.addColorStop(0,"white");gradB.addColorStop(1,"black");
  • 另一个是从左到右从透明到不透明的Hue
    var swatchHuevar col = "rgba(0,0,0,0)"var gradC = ctx.createLinearGradient(0,0,255,0);gradC.addColorStop(0,``hsla(${hueValue},100%,50%,0)``);gradC.addColorStop(1,``hsla(${hueValue},100%,50%,1)``);

  • 注意 上面的字符串引用在 SO 上没有正确呈现,所以我只是将它们加倍以显示,使用演示片段中所做的单引号。

    渲染

    然后将两者分层,先是背景(灰度),然后用复合操作“相乘”
    ctx.fillStyle = gradB;
    ctx.fillRect(0,0,255,255);
    ctx.fillStyle = gradC;
    ctx.globalCompositeOperation = "multiply";
    ctx.fillRect(0,0,255,255);
    ctx.globalCompositeOperation = "source-over";
    

    仅适用于色调

    重要的是颜色(色调)是纯色值,不能使用随机的 rgb 值。如果您有选定的 rgb 值,则需要从 rgb 中提取色调值。

    以下函数将 RGB 值转换为 HSL 颜色
    function rgbToLSH(red, green, blue, result = {}){
        value hue, sat, lum, min, max, dif, r, g, b;
        r = red/255;
        g = green/255;
        b = blue/255;
        min = Math.min(r,g,b);
        max = Math.max(r,g,b);
        lum = (min+max)/2;
        if(min === max){
            hue = 0;
            sat = 0;
        }else{
            dif = max - min;
            sat = lum > 0.5 ? dif / (2 - max - min) : dif / (max + min);
            switch (max) {
            case r:
                hue = (g - b) / dif;
                break;
            case g:
                hue = 2 + ((b - r) / dif);
                break;
            case b:
                hue = 4 + ((r - g) / dif);
                break;
            }
            hue *= 60;
            if (hue < 0) {
                hue += 360;
            }
        }
        result.lum = lum * 255;
        result.sat = sat * 255;
        result.hue = hue;
        return result;
    }
    

    把它们放在一起

    该示例每 3 秒渲染一个随机红色、绿色、蓝色值的样本。

    请注意,此示例使用 Balel,以便它可以在 IE 上运行

    var canvas = document.createElement("canvas");
    canvas.width = canvas.height = 255;
    var ctx = canvas.getContext("2d");
    document.body.appendChild(canvas);
    
    function drawSwatch(r, g, b) {
      var col = rgbToLSH(r, g, b);
      var gradB = ctx.createLinearGradient(0, 0, 0, 255);
      gradB.addColorStop(0, "white");
      gradB.addColorStop(1, "black");
      var gradC = ctx.createLinearGradient(0, 0, 255, 0);
      gradC.addColorStop(0, `hsla(${Math.floor(col.hue)},100%,50%,0)`);
      gradC.addColorStop(1, `hsla(${Math.floor(col.hue)},100%,50%,1)`);
    
      ctx.fillStyle = gradB;
      ctx.fillRect(0, 0, 255, 255);
      ctx.fillStyle = gradC;
      ctx.globalCompositeOperation = "multiply";
      ctx.fillRect(0, 0, 255, 255);
      ctx.globalCompositeOperation = "source-over";
    }
    
    function rgbToLSH(red, green, blue, result = {}) {
      var hue, sat, lum, min, max, dif, r, g, b;
      r = red / 255;
      g = green / 255;
      b = blue / 255;
      min = Math.min(r, g, b);
      max = Math.max(r, g, b);
      lum = (min + max) / 2;
      if (min === max) {
        hue = 0;
        sat = 0;
      } else {
        dif = max - min;
        sat = lum > 0.5 ? dif / (2 - max - min) : dif / (max + min);
        switch (max) {
          case r:
            hue = (g - b) / dif;
            break;
          case g:
            hue = 2 + ((b - r) / dif);
            break;
          case b:
            hue = 4 + ((r - g) / dif);
            break;
        }
        hue *= 60;
        if (hue < 0) {
          hue += 360;
        }
      }
      result.lum = lum * 255;
      result.sat = sat * 255;
      result.hue = hue;
      return result;
    }
    
    function drawRandomSwatch() {
      drawSwatch(Math.random() * 255, Math.random() * 255, Math.random() * 255);
      setTimeout(drawRandomSwatch, 3000);
    }
    drawRandomSwatch();


    要从 x 和 y 坐标计算颜色,您需要计算色相,然后是饱和度和值以获得 hsv 颜色(注意 hsl 和 hsv 是不同的颜色模型)
    // saturation and value are clamped to prevent rounding errors creating wrong colour
    var rgbArray = hsv_to_rgb(
        hue, // as used to create the swatch
        Math.max(0, Math.min(1, x / 255)),
        Math.max(0, Math.min(1, 1 - y / 255))
    );
    

    获取 h,s,v 颜色的 r,g,b 值的函数。

    /* Function taken from datGUI.js
       Web site https://workshop.chromeexperiments.com/examples/gui/#1--Basic-Usage
       // h 0-360, s 0-1, and v 0-1
    */
    
    function hsv_to_rgb(h, s, v) {
      var hi = Math.floor(h / 60) % 6;
      var f = h / 60 - Math.floor(h / 60);
      var p = v * (1.0 - s);
      var q = v * (1.0 - f * s);
      var t = v * (1.0 - (1.0 - f) * s);
      var c = [
        [v, t, p],
        [q, v, p],
        [p, v, t],
        [p, q, v],
        [t, p, v],
        [v, p, q]
      ][hi];
      return {
        r: c[0] * 255,
        g: c[1] * 255,
        b: c[2] * 255
      };
    }

    关于javascript - 绘制饱和度/亮度渐变,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41524641/

    10-09 18:14
    查看更多