将颜色通道字节打包成带符号的整数并正确显示为十六进制

Pack color channel bytes into a signed integer and display correctly as hex

我试图将颜色通道字节打包成一个带符号的整数,但生成的整数将无法正确显示为十六进制,因为它是带符号的。在 JavaScript 中有没有简单的方法可以做到这一点?不幸的是我不能声明一个无符号整数。

#-FFFF01 or -16776961

应该导致:

#FF0000FF or 4278190335

[
  [ 'rgba(255, 0, 0, 1.0)' ],
  [ 'rgb(34, 12, 64)' ],
  [ 'rgb(34, 12, 64, 0.6)' ],
  [ 'rgba(34, 12, 64, 0.6)' ],
  [ 'rgb(34 12 64 / 0.6)' ],
  [ 'rgba(34 12 64 / 0.3)' ],
  [ 'rgb(34.0 12 64 / 60%)' ],
  [ 'rgba(34.6 12 64 / 30%)' ],
  [  34, 12, 64, 0.3 ]
].forEach(analyze);

/*
 * @param {int|String} r [0, 255] or rgba?()
 * @param {int} g [0, 255]
 * @param {int} b [0, 255]
 * @param {Number} a [0, 1]
 */
function rgba2int(r, g, b, a) {
  if (typeof r === 'string' && arguments.length === 1) {
    const [r1, g1, b1, a1] = r
      .match(/^rgba?\((\d+\.?\d*)[,\s]*(\d+\.?\d*)[,\s]*(\d+\.?\d*)[,\s\/]*(.+)?\)$/)
      .slice(1);    
    [r, g, b] = [r1, g1, b1].map(v => parseFloat(v));
    a = a1
      ? a1.endsWith('%')
        ? parseInt(a1.substring(0, a1.length - 1), 10) / 100
        : parseFloat(a1)
      : null;
  }
  return a
    ? ((r & 0xFF) << 24) + ((g & 0xFF) << 16) + ((b & 0xFF) << 8) + (Math.floor(a * 0xFF) & 0xFF)
    : ((r & 0xFF) << 16) + ((g & 0xFF) << 8) + (b & 0xFF);
}

function analyze(input) {
  const res = rgba2int(...input);
  console.log([
    input.join(' ').padEnd(24, ' '),
    res.toString(10).padStart(10, ' '),
    ('#' + res.toString(16)).padStart(11, ' ')
  ].join(''));
}
.example { display: inline-block; width: 32px; height: 32px; }
.example-1 { background: rgba(255, 0, 0, 1.0); }
.example-2 { background: rgb(34, 12, 64); }
.example-3 { background: rgb(34, 12, 64, 0.6); }
.example-4 { background: rgba(34, 12, 64, 0.6); }
.example-5 { background: rgb(34 12 64 / 0.6); }
.example-6 { background: rgba(34 12 64 / 0.3); }
.example-7 { background: rgb(34.0 12 64 / 60%); }
.example-8 { background: rgba(34.6 12 64 / 30%); }
<!-- https://developer.mozilla.org/en-US/docs/Web/CSS/color#Syntax -->
<div class="example example-1"></div>
<div class="example example-2"></div>
<div class="example example-3"></div>
<div class="example example-4"></div>
<div class="example example-5"></div>
<div class="example example-6"></div>
<div class="example example-7"></div>
<div class="example example-8"></div>

  return a
    ? (((r & 0xFF) << 24) + ((g & 0xFF) << 16) + ((b & 0xFF) << 8) + (Math.floor(a * 0xFF) & 0xFF)) >>> 0
    : (((r & 0xFF) << 16) + ((g & 0xFF) << 8) + (b & 0xFF)) >>> 0;