r = ($r > 255) ? 255 : (($r < 0) ? 0 : (int)($r)); $this->g = ($g > 255) ? 255 : (($g < 0) ? 0 : (int)($g)); $this->b = ($b > 255) ? 255 : (($b < 0) ? 0 : (int)($b)); } } class Image_PixelOperations { function pixelOperation( $input_image, $output_image, $operation_callback, $factor = false ) { $image = imagecreatefrompng($input_image); $x_dimension = imagesx($image); $y_dimension = imagesy($image); $new_image = imagecreatetruecolor($x_dimension, $y_dimension); if ($operation_callback == 'contrast') { $average_luminance = $this->getAverageLuminance($image); } else { $average_luminance = false; } for ($x = 0; $x < $x_dimension; $x++) { for ($y = 0; $y < $y_dimension; $y++) { $rgb = imagecolorat($image, $x, $y); $r = ($rgb >> 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; $pixel = new Pixel($r, $g, $b); $pixel = call_user_func( $operation_callback, $pixel, $factor, $average_luminance ); $color = imagecolorallocate( $image, $pixel->r, $pixel->g, $pixel->b ); imagesetpixel($new_image, $x, $y, $color); } } imagepng($new_image, $output_image); } function addNoise($pixel, $factor) { $random = mt_rand(-$factor, $factor); return new Pixel( $pixel->r + $random, $pixel->g + $random, $pixel->b + $random ); } function adjustBrightness($pixel, $factor) { return new Pixel( $pixel->r + $factor, $pixel->g + $factor, $pixel->b + $factor ); } function swapColors($pixel, $factor) { switch ($factor) { case 'rbg': return new Pixel( $pixel->r, $pixel->b, $pixel->g ); break; case 'bgr': return new Pixel( $pixel->b, $pixel->g, $pixel->r ); break; case 'brg': return new Pixel( $pixel->b, $pixel->r, $pixel->g ); break; case 'gbr': return new Pixel( $pixel->g, $pixel->b, $pixel->r ); break; case 'grb': return new Pixel( $pixel->g, $pixel->r, $pixel->b ); break; default: return $pixel; } } function removeColor($pixel, $factor) { if ($factor == 'r' ) { $pixel->r = 0; } if ($factor == 'g' ) { $pixel->g = 0; } if ($factor == 'b' ) { $pixel->b = 0; } if ($factor == 'rb' || $factor == 'br') { $pixel->r = 0; $pixel->b = 0; } if ($factor == 'rg' || $factor == 'gr') { $pixel->r = 0; $pixel->g = 0; } if ($factor == 'bg' || $factor == 'gb') { $pixel->b = 0; $pixel->g = 0; } return $pixel; } function maxColor($pixel, $factor) { if ($factor == 'r' ) { $pixel->r = 255; } if ($factor == 'g' ) { $pixel->g = 255; } if ($factor == 'b' ) { $pixel->b = 255; } if ($factor == 'rb' || $factor == 'br') { $pixel->r = 255; $pixel->b = 255; } if ($factor == 'rg' || $factor == 'gr') { $pixel->r = 255; $pixel->g = 255; } if ($factor == 'bg' || $factor == 'gb') { $pixel->b = 255; $pixel->g = 255; } return $pixel; } function negative($pixel) { return new Pixel( 255 - $pixel->g, 255 - $pixel->r, 255 - $pixel->b ); } function greyscale($pixel) { $pixel_average = ($pixel->r + $pixel->g + $pixel->b) / 3; return new Pixel( $pixel_average, $pixel_average, $pixel_average ); } function blackAndWhite($pixel, $factor) { $pixel_total = ($pixel->r + $pixel->g + $pixel->b); if ($pixel_total > (((255 + $factor) / 2) * 3)) { // white $pixel->r = 255; $pixel->g = 255; $pixel->b = 255; } else { $pixel->r = 0; $pixel->g = 0; $pixel->b = 0; } return $pixel; } function clip($pixel, $factor) { if ($pixel->r > 255 - $factor) { $pixel->r = 255; } if ($pixel->r < $factor) { $pixel->r = 0; } if ($pixel->g > 255 - $factor) { $pixel->g = 255; } if ($pixel->g < $factor) { $pixel->g = 0; } if ($pixel->b > 255 - $factor) { $pixel->b = 255; } if ($pixel->b < $factor) { $pixel->b = 0; } return $pixel; } function getAverageLuminance($image) { $luminance_running_sum = 0; $x_dimension = imagesx($image); $y_dimension = imagesy($image); for ($x = 0; $x < $x_dimension; $x++) { for ($y = 0; $y < $y_dimension; $y++) { $rgb = imagecolorat($image, $x, $y); $r = ($rgb >> 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; $luminance_running_sum += (0.30 * $r) + (0.59 * $g) + (0.11 * $b); } } $total_pixels = $x_dimension * $y_dimension; return $luminance_running_sum / $total_pixels; } function contrast($pixel, $factor, $average_luminance) { return new Pixel( $pixel->r * $factor + (1 - $factor) * $average_luminance, $pixel->g * $factor + (1 - $factor) * $average_luminance, $pixel->b * $factor + (1 - $factor) * $average_luminance ); } function saltAndPepper($pixel, $factor) { $black = (int)($factor/2 + 1); $white = (int)($factor/2 - 1); $random = mt_rand(0, $factor); $new_channel = false; if ($random == $black) { $new_channel = 0; } if ($random == $white) { $new_channel = 255; } if (is_int($new_channel)) { return new Pixel($new_channel, $new_channel, $new_channel); } else { return $pixel; } } function gamma($pixel, $factor) { return new Pixel( pow($pixel->r / 255, $factor) * 255, pow($pixel->g / 255, $factor) * 255, pow($pixel->b / 255, $factor) * 255 ); } /** * @todo Revise the logic, there is something not quite right here * */ function snap($pixel, $factor) { $proximity = $factor[1]; $snap_to = $factor[0]; $close = (int)(255 * $proximity / 100); if ($pixel->r + $close >= 255 && $pixel->g + $close >= 255 && $pixel->b + $close >= 255) { return $pixel; //skip whitish } $rgb = array ('r', 'g', 'b'); foreach ($rgb AS $channel) { if ($pixel->{$channel} < $snap_to->{$channel} && ($pixel->{$channel} + $close) > $snap_to->{$channel}) { $pixel->{$channel} = $snap_to->{$channel}; } if ($pixel->{$channel} > $snap_to->{$channel} && ($pixel->{$channel} - $close) < $snap_to->{$channel}) { $pixel->{$channel} = $snap_to->{$channel}; } } return $pixel; } /** * * @todo finish this method */ function substitute($pixel, $factor) { $find_pixel = $factor[0]; $replace_with_pixel = $factor[1]; $proximity = $factor[2]; $close = (int)(255 * $proximity / 100); // to do return $pixel; } function randomizeOperation($pixel, $factor) { $operations = array( 'clip', 'blackAndWhite', 'greyscale', 'negative', 'maxColor', 'removeColor', 'swapColors', //'adjustBrightness', 'addNoise', //'contrast', //removed, too heavy for this purpose 'saltAndPepper', 'gamma', ); $key = array_rand($operations); $operation = $operations[$key]; switch ($operation) { case 'clip': $factor = mt_rand(0, 255); break; case 'maxColor': case 'removeColor': $factors = array('r', 'g', 'b', 'rg', 'rb', 'gb'); $factor = $factors[array_rand($factors)]; break; case 'swapColors': $factors = array('rbg', 'gbr', 'grb', 'bgr', 'brg'); $factor = $factors[array_rand($factors)]; break; case 'adjustBrightness': $factor = mt_rand(0, 255); break; case 'addNoise': $factor = mt_rand(0, 255); break; case 'saltAndPepper': $factor = mt_rand(0, 255); break; case 'gamma': $factor = mt_rand(0.5, 5); break; default: $factor = false; break; } return call_user_func(array($this, $operation), $pixel, $factor); } } if (!empty($_GET['image'])) { set_time_limit(60); $po =& new Image_PixelOperations(); echo 'Original:
'; echo '
'; // noise $noise = 500; $po->pixelOperation($_GET['image'], 'result_noise.png', array($po, 'addNoise'), $noise); echo '
Add noise (factor '. $noise .'):
'; echo '
'; // 2 brightness adjustments $brightness = 50; $po->pixelOperation($_GET['image'], 'result_bright.png', array($po, 'adjustBrightness'), $brightness); echo '
Brighten:
'; $brightness = -50; $po->pixelOperation($_GET['image'], 'result_dark.png', array($po, 'adjustBrightness'), $brightness); echo '
Darken:
'; echo '
'; // 5 color swaps $po->pixelOperation($_GET['image'], 'result_rbg.png', array($po, 'swapColors'), 'rbg'); echo '
RGB to RBG:
'; $po->pixelOperation($_GET['image'], 'result_bgr.png', array($po, 'swapColors'), 'bgr'); echo '
RGB to BGR:
'; $po->pixelOperation($_GET['image'], 'result_brg.png', array($po, 'swapColors'), 'brg'); echo '
RGB to BRG:
'; $po->pixelOperation($_GET['image'], 'result_gbr.png', array($po, 'swapColors'), 'gbr'); echo '
RGB to GBR:
'; $po->pixelOperation($_GET['image'], 'result_grb.png', array($po, 'swapColors'), 'grb'); echo '
RGB to GRB:
'; echo '
'; // 6 color removals $po->pixelOperation($_GET['image'], 'result_r.png', array($po, 'removeColor'), 'r'); echo '
Remove red:
'; $po->pixelOperation($_GET['image'], 'result_g.png', array($po, 'removeColor'), 'g'); echo '
Remove green:
'; $po->pixelOperation($_GET['image'], 'result_b.png', array($po, 'removeColor'), 'b'); echo '
Remove blue:
'; $po->pixelOperation($_GET['image'], 'result_rg.png', array($po, 'removeColor'), 'rg'); echo '
Remove red and green:
'; $po->pixelOperation($_GET['image'], 'result_gb.png', array($po, 'removeColor'), 'gb'); echo '
Remove green and blue:
'; $po->pixelOperation($_GET['image'], 'result_rb.png', array($po, 'removeColor'), 'rb'); echo '
Remove red and blue:
'; echo '
'; // 6 color maximizations $po->pixelOperation($_GET['image'], 'result_maxr.png', array($po, 'maxColor'), 'r'); echo '
Maximize red:
'; $po->pixelOperation($_GET['image'], 'result_maxg.png', array($po, 'maxColor'), 'g'); echo '
Maximize green:
'; $po->pixelOperation($_GET['image'], 'result_maxb.png', array($po, 'maxColor'), 'b'); echo '
Maximize blue:
'; $po->pixelOperation($_GET['image'], 'result_maxrg.png', array($po, 'maxColor'), 'rg'); echo '
Maximize red and green:
'; $po->pixelOperation($_GET['image'], 'result_maxgb.png', array($po, 'maxColor'), 'gb'); echo '
Maximize green and blue:
'; $po->pixelOperation($_GET['image'], 'result_maxrb.png', array($po, 'maxColor'), 'rb'); echo '
Maximize red and blue:
'; echo '
'; // negative $po->pixelOperation($_GET['image'], 'result_negative.png', array($po, 'negative')); echo '
Negative:
'; echo '
'; // greyscale $po->pixelOperation($_GET['image'], 'result_grey.png', array($po, 'greyscale')); echo '
Greyscale:
'; echo '
'; // B&W $bw = 20; $po->pixelOperation($_GET['image'], 'result_bw.png', array($po, 'blackAndWhite'), $bw); echo '
Black and white (' . $bw . '):
'; echo '
'; // clip $clip = 100; $po->pixelOperation($_GET['image'], 'result_clip.png', array($po, 'clip'), $clip); echo '
Clip (' . $clip . '):
'; echo '
'; // contrast $contrast = 0.5; $po->pixelOperation($_GET['image'], 'result_contrast1.png', array($po, 'contrast'), $contrast); echo '
Contrast (' . $contrast . '):
'; $contrast = 1.5; $po->pixelOperation($_GET['image'], 'result_contrast2.png', array($po, 'contrast'), $contrast); echo '
Contrast (' . $contrast . '):
'; echo '
'; // salt & pepper $probability = 20; $po->pixelOperation($_GET['image'], 'result_sandp.png', array($po, 'saltAndPepper'), $probability); echo '
Salt and Pepper (' . $probability . '):
'; echo '
'; // gamma $gamma = 2.2; $po->pixelOperation($_GET['image'], 'result_gamma.png', array($po, 'gamma'), $gamma); echo '
Gamma (' . $gamma . '):
'; echo '
'; // random effect $po->pixelOperation($_GET['image'], 'result_rand.png', array($po, 'randomizeOperation')); echo '
Random effect:
'; // snap $snap_to = new Pixel(208, 122, 8); // dark blue - (2, 41, 107) // some orange - (208, 122, 8) // red - (255, 91, 60) // light blue - (100, 208, 249) $proximity = 80; // in % $po->pixelOperation($_GET['image'], 'result_snap.png', array($po, 'snap'), array($snap_to, $proximity)); echo '
Snap to color:
'; echo '
'; } ?>