однократная манипуляция с php GD

Сначала я имею в виду предыдущий вопрос. Изменение изображения на пиксель и сохранение в db

Я обнаружил, что холст html5 не подходит, потому что трудно сохранить секрет исходного изображения. Вот почему я пытаюсь достичь своей цели с помощью библиотеки PHP GD. Я никогда не работал с этой библиотекой, поэтому у меня были некоторые трудности. Я думаю, мне нужны следующие функции

  • imagecreatetruecolor для создания изображения в браузере
  • imagecolorallocate для возврата rgb из исходного изображения
  • imagesetpixel для рисования случайных пикселей

    $x = 200; //width of image $y = 200; //height of image $gd = imagecreatetruecolor ($x, $y); $color = imagecolorallocate($gd, $r, $g, $b) //not sure how to retrieve the rgb from the source image Then I need a function for drawing random pixels with imagesetpixel. imagesetpixel($gd, $posx,$posy, $color); // not sure how to retrieve the x and y position of each pixel. 

Я не звезда с PHP, поэтому мой поиск застрял с этими функциями GD. Надеюсь, вы можете дать мне стартап

Одной из «особенностей» случайной функции является то, что она псевдослучайна, т. Е. Всегда будет выводить одну и ту же последовательность с одним и тем же семенем.

Таким образом, вы можете хранить для каждого «изображения»:

 sourcefile - the name of the source image seed - integer, maybe the start time of this sequence position - number of pixels that need to be shown, or maybe % completion 

Так скажите, что вы хотите вывести образ $sourcefile с семенным $seed и $position процентом видимых пикселей. Вам даже не нужно использовать alpha:

 // Load image $src = imageCreateFromPNG($sourcefile); // Assume image is PNG // Create work image $new = imageCreateTrueColor(ImageSX($src), ImageSY($src)); // new image of same size mt_srand($seed); // Seed the Mersenne Twister generator // Number of pixels to set: $position = 0: NONE, $position = 100: ALL $pixels = round($position*imageSX($src)*imageSY($src)/100); // Now we have a problem: if we do $pixels attempts, mt_rand might sometimes // return the same pixel again. So we end up setting less than $pixels pixels. // So we do this the expensive way, saving an array of yet-to-be-used pixels. $max = ImageSX($src)*ImageSY($src); $pixelid = array(); for ($i = 0; $i < $max; $i++) $pixelid[] = $i; $W = ImageSX($src); while($pixels--) { // Extract one pixel $chosen = $pixelid[$idx = mt_rand(0, $pixels)]; array_splice ($pixelid, $idx, 1); // Remove extracted pixel from array $x = $chosen % $W; $y = ($chosen - $x)/ $W; $rgb = imagecolorat($src, $x, $y); $pix = imagecolorsforindex($src, $rgb); $rgb = imageColorAllocate($new, $pix['red'], $pix['green'], $pix['blue']); imageSetPixel($new, $x, $y, $rgb); } ImageDestroy($src); // $new has now exactly $pixels set to the same pixels of $src, // the rest are undefined (you can fill $new with white beforehand...) Header("Content-Type: image/png"); ImagePNG($new); в // Load image $src = imageCreateFromPNG($sourcefile); // Assume image is PNG // Create work image $new = imageCreateTrueColor(ImageSX($src), ImageSY($src)); // new image of same size mt_srand($seed); // Seed the Mersenne Twister generator // Number of pixels to set: $position = 0: NONE, $position = 100: ALL $pixels = round($position*imageSX($src)*imageSY($src)/100); // Now we have a problem: if we do $pixels attempts, mt_rand might sometimes // return the same pixel again. So we end up setting less than $pixels pixels. // So we do this the expensive way, saving an array of yet-to-be-used pixels. $max = ImageSX($src)*ImageSY($src); $pixelid = array(); for ($i = 0; $i < $max; $i++) $pixelid[] = $i; $W = ImageSX($src); while($pixels--) { // Extract one pixel $chosen = $pixelid[$idx = mt_rand(0, $pixels)]; array_splice ($pixelid, $idx, 1); // Remove extracted pixel from array $x = $chosen % $W; $y = ($chosen - $x)/ $W; $rgb = imagecolorat($src, $x, $y); $pix = imagecolorsforindex($src, $rgb); $rgb = imageColorAllocate($new, $pix['red'], $pix['green'], $pix['blue']); imageSetPixel($new, $x, $y, $rgb); } ImageDestroy($src); // $new has now exactly $pixels set to the same pixels of $src, // the rest are undefined (you can fill $new with white beforehand...) Header("Content-Type: image/png"); ImagePNG($new); 

вариации

Вместо сращивания массива вы можете вырезать «используемые» пиксели, даже если это не дает равномерного распределения:

 $cnt = count($pixelid); while($pixels--) { // Extract one pixel $idx = mt_rand(0, $cnt); // If the extracted pixel is null, find next pixel that is unextracted // and if there are none, restart from the beginning of the array. while (-1 == ($chosen = $pixelid[$idx])) if ($cnt == ++$idx) $idx = 0; $chosen = $pixelid[$idx]; $pixelid[$idx] = -1; в $cnt = count($pixelid); while($pixels--) { // Extract one pixel $idx = mt_rand(0, $cnt); // If the extracted pixel is null, find next pixel that is unextracted // and if there are none, restart from the beginning of the array. while (-1 == ($chosen = $pixelid[$idx])) if ($cnt == ++$idx) $idx = 0; $chosen = $pixelid[$idx]; $pixelid[$idx] = -1; 

Или вы могли бы просто … повторить попытку. Но это может быть дорого, когда изображение почти завершено.

 $cnt = count($pixelid); while($pixels--) { // Extract one pixel for ($idx = mt_rand(0, $cnt); $pixelid[$idx] != -1; $idx = mt_rand(0, $cnt)) ; $chosen = $pixelid[$idx]; $pixelid[$idx] = -1; в $cnt = count($pixelid); while($pixels--) { // Extract one pixel for ($idx = mt_rand(0, $cnt); $pixelid[$idx] != -1; $idx = mt_rand(0, $cnt)) ; $chosen = $pixelid[$idx]; $pixelid[$idx] = -1; 

Если вам все равно, что изображение перестраивается всегда разными способами, вы можете использовать array_shuffle() вместо mt_rand() , и на каждой итерации я извлекаю i-й пиксель из $pixelid .

Последний вариант – переопределить array_shuffle() используя mt_rand как подробно описано на странице руководства (см. Пример по tim на leethost dot com):

 function array_new_shuffle(&$items, $seed) { mt_srand($seed); for ($i = count($items) - 1; $i > 0; $i--) { $j = @mt_rand(0, $i); list($items[$i], $items[$j]) = array($items[$j], $items[$i]); } } 

Таким образом, вы вызываете array_new_shuffle() против $pixelid используя $seed , а затем извлекаете элементы из перетасованного массива последовательно:

 for ($idx = 0; $idx < $pixels; $idx++) { $chosen = $pixelid[$idx]; ... 

Большие изображения

Для больших изображений обработка массива слишком дорога, и вы теряете память. Таким образом, чтобы mt_rand() неоднократно ударял одни и те же пиксели (что может стать очень проблематичным, если изображение на 99% завершено, и поэтому вероятность случайного попадания в один из неподвижных 1% пикселей составляет, конечно, 1%), этот хак использует другое изображение в качестве индекса.

Это ограничивает «массив» до 2 ^ 24 записей, то есть изображение со стороной 2 ^ 12 или 4096 пикселей.

Экономия памяти огромна: каждый пиксель изображения стоит 16 байт, а не около 176 (это на моей 64-битной машине Linux). Это означает, что для изображения с разрешением 1024×1024 пикселей требуется только около 17M RAM.

В моей системе этот скрипт обрабатывает около 180 тыс. Пикселей в секунду (изображение 1024х1024 обрабатывалось на 100% за 7,4 секунды, из которых около 2 были необходимы для загрузки и настройки изображений).

 $seed = 0; $position = 2; $sourcefile = '/home/lserni/Lena19721024-filtered.png'; mt_srand($seed); // Seed the Mersenne Twister generator // Load image $src = ImageCreateTrueColor(512,512); // $src = imageCreateFromPNG($sourcefile); // Assume image is PNG $W = ImageSX($src); $H = ImageSY($src); // Total number of pixels $size = $W*$H; if (($W > 4095) || ($H > 4095)) die("Image too big"); // Create work image $new = imageCreateTrueColor($W, $H); // new image of same size /* if ($position > 50) { $position = 100-$position; $tmp = $src; $src = $new; $new = $tmp; } */ // Number of pixels to set: $position = 0: NONE, $position = 100: ALL $pixels = round($position*$size/100.0); // Create a temporary buffer image of the same size $fix = imageCreateTrueColor($W, $H); for ($i = 0; $i < $size; $i++) { $b = $i & 0xFF; $g = ($i >> 8) & 0xFF; $r = ($i >> 16) & 0xFF; imageSetPixel($fix, $i % $W, floor($i / $W), imageColorAllocate($fix, $r, $g, $b)); } while($pixels--) { // Recover one of the available pixel indexes $idx = mt_rand(0, $size--); // Recover index from image $y = floor($idx / $W); $x = $idx % $W; $idx = imageColorAt($fix, $x, $y); $lst = imageColorAt($fix, $size % $W, floor($size / $W)); $b = $lst & 0xff; $lst >>= 8; $g = $lst & 0xff; $lst >>= 8; $r = $lst & 0xff; imageSetPixel($fix, $x, $y, imageColorAllocate($fix, $r, $g, $b)); // Whew. Now recover true x and y from new $idx $y = floor($idx / $W); $x = $idx % $W; $rgb = imagecolorat($src, $x, $y); $pix = imagecolorsforindex($src, $rgb); $rgb = imageColorAllocate($new, $pix['red'], $pix['green'], $pix['blue']); imageSetPixel($new, $x, $y, $rgb); } ImageDestroy($src); // $new has now exactly $pixels set to the same pixels of $src, // the rest are undefined (you can fill $new with white beforehand...) // die("Memory: " . memory_get_peak_usage()); Header("Content-Type: image/png"); ImagePNG($new); в $seed = 0; $position = 2; $sourcefile = '/home/lserni/Lena19721024-filtered.png'; mt_srand($seed); // Seed the Mersenne Twister generator // Load image $src = ImageCreateTrueColor(512,512); // $src = imageCreateFromPNG($sourcefile); // Assume image is PNG $W = ImageSX($src); $H = ImageSY($src); // Total number of pixels $size = $W*$H; if (($W > 4095) || ($H > 4095)) die("Image too big"); // Create work image $new = imageCreateTrueColor($W, $H); // new image of same size /* if ($position > 50) { $position = 100-$position; $tmp = $src; $src = $new; $new = $tmp; } */ // Number of pixels to set: $position = 0: NONE, $position = 100: ALL $pixels = round($position*$size/100.0); // Create a temporary buffer image of the same size $fix = imageCreateTrueColor($W, $H); for ($i = 0; $i < $size; $i++) { $b = $i & 0xFF; $g = ($i >> 8) & 0xFF; $r = ($i >> 16) & 0xFF; imageSetPixel($fix, $i % $W, floor($i / $W), imageColorAllocate($fix, $r, $g, $b)); } while($pixels--) { // Recover one of the available pixel indexes $idx = mt_rand(0, $size--); // Recover index from image $y = floor($idx / $W); $x = $idx % $W; $idx = imageColorAt($fix, $x, $y); $lst = imageColorAt($fix, $size % $W, floor($size / $W)); $b = $lst & 0xff; $lst >>= 8; $g = $lst & 0xff; $lst >>= 8; $r = $lst & 0xff; imageSetPixel($fix, $x, $y, imageColorAllocate($fix, $r, $g, $b)); // Whew. Now recover true x and y from new $idx $y = floor($idx / $W); $x = $idx % $W; $rgb = imagecolorat($src, $x, $y); $pix = imagecolorsforindex($src, $rgb); $rgb = imageColorAllocate($new, $pix['red'], $pix['green'], $pix['blue']); imageSetPixel($new, $x, $y, $rgb); } ImageDestroy($src); // $new has now exactly $pixels set to the same pixels of $src, // the rest are undefined (you can fill $new with white beforehand...) // die("Memory: " . memory_get_peak_usage()); Header("Content-Type: image/png"); ImagePNG($new); 

оптимизация

Вы заметите комментарий в приведенном выше коде. Если так получится, что $position составляет более 50%, скажем, 70%, нет смысла создавать пустое изображение и копировать 70% пикселей с хорошего изображения на пустой образ. Имеет смысл копировать 30% пустых пикселей из пустого изображения в хорошее изображение, «черное» его. Это можно сделать, просто заменив $new и $src и изменив $position . Я не очень тщательно тестировал этот код; поэтому я оставил его комментарий. Но вы можете попробовать.

Реализация

Преимущество использования PRNG заключается в том, что вам не нужно сохранять какое-либо изображение , но только seed и position – обычно восемь байтов.

Если человек А получает позицию 1 и просит получить позиции до 5 (т. Е. 5% видимого изображения), и вы сохраните семя и это значение 5 и используйте его для человека B, тогда человек B увидит то же самое 5 % того человека, которого получил.

Все без сохранения или загрузки изображений, кроме оригинала.

Если вы можете передать семя и позицию в параметрах $ _GET, вы можете отобразить в браузере изображение на разных этапах (например, image.php?seed=12345678&position=5 будет отображать изображение с 5% пикселей. Также вы можете указать количество пикселей, а не их процент, конечно).

Это работает, пока пиксели выбраны случайным образом : если человек А выбирает точные пиксели, которые он или она хочет, тогда этот подход недействителен, и вам нужно сохранить отдельные позиции пикселей, что можно сделать несколькими способами: используя фиксированный файл, удерживающий пары (x, y) в двоичном формате, или сохранение всего изображения. Последний подход легче понять и требует хранения для одного целого изображения на каждом этапе, поэтому, если это игра, и вы хотите «воспроизвести» ее, вам может понадобиться огромное дисковое пространство. Первый подход может разумно потребовать шесть байтов на пиксель, то есть эквивалент изображения с одинаковой высотой и в два раза больше, чем оригинал, или всего четыре байта на пиксель.

замените RANDOM_COLOR на случайное значение цвета

это заменит все пиксели,

 for($i=0;$i < $x;$i++) { for($e = 0;$e < $y;$e++) { imagesetpixel($gd, $i,$e, $RANDOM_COLOR); } } 

если вы хотите установить только несколько случайных пикселей, убедитесь, что вы установили их в диапазоне 0 и ширину -1, 0 и высоту -1

например

 $i = rand(0,$width-1); $e = rand(0,$height - 1); imagesetpixel($gd, $i,$e, $RANDOM_COLOR); 

вы можете использовать его в цикле

С помощью огров я частично ее работал.

То, что я делаю, это манипулировать проигрывателем и после манипуляции, объединить его с функцией imagecopy с исходным изображением. Выход представляет собой изображение в формате jpg.

Управление этим проигрывателем осуществляется с помощью этого кода

 for ($y = 0; $y < imagesy($img); $y++) { for ($x = 0; $x < imagesx($img); $x++) { $img = imagecreatefrompng("thecover.png"); imagealphablending($img, false); // Turn off blending $white_color_transparent = imagecolorallocatealpha($img, 255, 255, 255, 127); $rgb = imagecolorat($img, $x, $y); $pixel_color = imagecolorsforindex($img, $rgb); if ($pixel_color['red'] == 255 && $pixel_color['green'] == 255 && $pixel_color['blue'] == 255){ for ($i = 0; $i < 200; $i++) { imagesetpixel($img, rand(0,300), rand(0,300), $white_color_transparent); } } } } 

Цвет проигрывателя белого цвета, RGB (0,0,0). Скрипт проверяет этот цвет и устанавливает на данный момент 200 случайных пикселей для прозрачности.

Он задает много пикселей для прозрачных, но не для 200.

Тот, кто может мне помочь.