Два необычных PHP-оператора, используемых вместе, чтобы получить цвет пикселя изображения, пожалуйста, объясните

Функция 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 бита (32 бит для RGBA, но мы проигнорируем это здесь). Значение состоит из 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, и мы оставляем только биты, представляющие зеленый цвет исходного цвета. Поскольку они были сдвинуты в те же 8 бит, которые представляют [0, 255], мы снова получили нашу ценность.

Последнее значение проще, поскольку оно уже расположено там, где мы хотим: в битах, представляющих [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 бит (и, следовательно, является лишним).

Обычно этот 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.