Функция 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.