请解释一下,两个不寻常的PHP运算符一起使用来获取图像像素颜色


Two unusual PHP operators used together to get image pixel color, please explain

PHP imagecolorat(( 函数可用于获取图像像素的 RGB 值,如文档所示:

$im = imagecreatefrompng("php.png");
$rgb = imagecolorat($im, 10, 15);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;

我完全不明白最后三行;我知道它们返回正确的值,但我无法弄清楚>>运算符和&运算符如何协同工作以做到这一点。有人可以解释一下吗?

作为参考,当$rgb = 9750526时,RGB 值结果为(148,199,254)

感谢您的任何回复。

和>>是两个不同的按位运算符(PHP中的按位运算符(。它们使用值的位表示,这为我们提供了一些有用(且快速!(的可能性。

>>是右移。如果右移一个值,则会在表示中将所有位向右移动。如果你有"11100",右移两位,你就剩下"111"(右端移出的位消失(。>>右侧的数字表示要移位的位数。

并且是按位和的。如果您有两个值表示为 111000 和 101011,并决定按位和它们,则最终将得到 101000(两个值中设置相同位的位将为 1,否则为 0(。

我们现在有了理解上述代码所需的内容。 $rgb包含一个整数值(该值不感兴趣,但位模式很有趣(,它表示 24 位(RGBA 为 32 位,但我们在这里忽略它(。该值由 8 位表示红色、8 位表示绿色和 8 位表示蓝色组成。然而,我们不感兴趣的是这24位代表的数字,而是单独的R,G和B值是什么。

我们的值表示颜色的以下位:

rrrrrrrr gggggggg bbbbbbbb 

如果我们用>> 16 移动这个位掩码,我们将得到:

                  rrrrrrrr

这就是>> 16所做的,只给我们留下代表红色的位。由于我们现在已经将位一直向下移动,该值表示 [0, 255] 中的一个数字。然后我们添加 & 255(这里用十六进制表示法写成0xFF(以删除我们感兴趣的 8 上面的任何杂散位。现在,当我们查看如何获得 G 值时,我们将了解这种情况是如何发生的:

我们的价值观仍然勇敢地代表了不同的颜色:

rrrrrrrr gggggggg bbbbbbbb 

如果我们用 8>>移动这个位掩码 8 位,我们将得到:

         rrrrrrrr gggggggg

但是等等!这不仅是表示 g 的位,还包括表示 r 的位!这不是我们所追求的值(因为我们只想要g(。在上一个示例中,我们很幸运,因为我们没有在 r 上方设置任何位,但这次我们真的为我们完成了工作。但是我们知道 &,现在是时候看到它实际上是它的东西了。

我们现在有:

         rrrrrrrr gggggggg

然后我们应用&255(代码中的0xFF(,它以位值表示为:

         00000000 11111111

由于 & 只保留在两个操作数中设置的位,我们最终只会得到 g 值:

                  gggggggg

在移位值中表示红色的位现在为 0,我们只剩下表示原始颜色的绿色的位。当它们被移入代表 [0, 255] 的相同 8 位时,我们再次获得了我们的价值。

最后一个值更容易,因为它已经位于我们想要的位置:在代表 [0, 255] 的位中。我们可以在这里做&操作,然后从另一边出去:

rrrrrrrr gggggggg bbbbbbbb & 
00000000 00000000 11111111

最终得到:

                  bbbbbbbb

我们也有蓝色值。

希望能解释它!

>>表示逐位右移,因此位向右移动n(分别为16和8(位置:

R = 1 字节 = 8 位

RRGGBB >> 16  =  0000RR
RRGGBB >> 8   =  00RRGG

按位 AND 运算 & 用于删除结果中我们不想要的剩余内容,方法是使用除应保留的部分外所有地方均为零的掩码:

00RRGG & 0000FF = 0000GG 

让我们试试:

$rgb = 9750526;
var_dump(sprintf('%032b', $rgb));

$rgb = 00000000100101001100011111111110//整数为 32 或 64 位 - b 部分为最后 8 位

您只需要第 3、2 和第 1 个字节,因此>>(移位(它们你得到二进制

$rgb >> 16 =  string(32) "00000000000000000000000010010100" //r part is last 8 bits
$rgb >> 8 =  string(32) "00000000000000001001010011000111" //g part is last 8 bits

0xFF 是和操作与11111111因此你得到

r = 10010100
g = 11000111
b = 11111110

我希望这些是(148,199,254(;)

我猜第一次出现,>>16,是将所有位向右移动,直到只剩下红色,然后用&0xFF切断数字的开头。虽然我无法分辨该示例中红色的位深度(我希望颜色是 3 字节的倍数(,但它有点像这样:

rrggbb = 125438 // input
>> 16 // shift right (might be 8 for this example)
0000rr = 000012 // result
& 0xFF // cut beginning
rr = 12

其他颜色也类似。

imageColorAt(( 返回一个包含红色、绿色和蓝色值的 24 位数字。红色值乘以 2^16,绿色乘以 2^8,蓝色保持"原样"。

在十六进制中,您的值是0x94C7FE;通过将其向右移动 16 位,您将丢失最后四个半字节,只剩下0x94。"& 0xFF"需要最后8位(因此它是多余的(。

通常这种转变是这样完成的:

$value = imageColorAt(...)   // Gets 94C7FE
$blue  = $value & 0xFF;       // Takes the last "FE" (254 in decimal)
$value >>= 8;                 // Shifts right, 94C7 remains
$green = $value & 0xFF;       // Takes "C7"
$value >>= 8;                 // Shifts right, 94 remains
$red   = $value;              // Takes "94" hex, which is 148 dec.