3

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

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

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

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

感谢您的任何回复。

4

5 回答 5

11

& 和 >> 是两个不同的位运算符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

我们也有我们的蓝色价值。

希望能解释清楚!

于 2012-07-19T22:56:10.670 回答
1

我猜第一次出现,>>16,将所有位向右移动,直到只剩下红色,然后用 &0xFF 切断数字的开头。虽然在那个例子中我不能告诉红色的位深度(我希望颜色是 3 个字节的倍数),但它有点像这样:

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

其他颜色也类似。

于 2012-07-19T22:40:38.997 回答
1

>>表示按位右移,因此这些位向右移动 n 个(分别为 16 和 8 个)位置:

R = 1 字节 = 8 位

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

逐位与操作&用于删除我们不希望在结果中出现的剩余内容,方法是使用除应保留的部分之外的所有地方都为零的掩码:

00RRGG & 0000FF = 0000GG 
于 2012-07-19T22:48:27.590 回答
1

我们试试看:

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

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

你只需要第三个、第二个和第一个字节,所以>>(移位)它们,你得到二进制

$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) ;)

于 2012-07-19T22:52:55.180 回答
0

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

在十六进制中,您的值为 0x94C7FE;通过将其右移 16 位,您会丢失最后四个半字节,并留下 0x94。“& 0xFF”取最后 8 位(因此是多余的)。

通常这种 shift'n'cut 是这样完成的:

$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.
于 2012-07-19T22:47:21.143 回答