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 '
';
echo '
';
$brightness = -50;
$po->pixelOperation($_GET['image'], 'result_dark.png', array($po, 'adjustBrightness'), $brightness);
echo '
';
echo '
';
$po->pixelOperation($_GET['image'], 'result_bgr.png', array($po, 'swapColors'), 'bgr');
echo '
';
$po->pixelOperation($_GET['image'], 'result_brg.png', array($po, 'swapColors'), 'brg');
echo '
';
$po->pixelOperation($_GET['image'], 'result_gbr.png', array($po, 'swapColors'), 'gbr');
echo '
';
$po->pixelOperation($_GET['image'], 'result_grb.png', array($po, 'swapColors'), 'grb');
echo '
';
echo '
';
$po->pixelOperation($_GET['image'], 'result_g.png', array($po, 'removeColor'), 'g');
echo '
';
$po->pixelOperation($_GET['image'], 'result_b.png', array($po, 'removeColor'), 'b');
echo '
';
$po->pixelOperation($_GET['image'], 'result_rg.png', array($po, 'removeColor'), 'rg');
echo '
';
$po->pixelOperation($_GET['image'], 'result_gb.png', array($po, 'removeColor'), 'gb');
echo '
';
$po->pixelOperation($_GET['image'], 'result_rb.png', array($po, 'removeColor'), 'rb');
echo '
';
echo '
';
$po->pixelOperation($_GET['image'], 'result_maxg.png', array($po, 'maxColor'), 'g');
echo '
';
$po->pixelOperation($_GET['image'], 'result_maxb.png', array($po, 'maxColor'), 'b');
echo '
';
$po->pixelOperation($_GET['image'], 'result_maxrg.png', array($po, 'maxColor'), 'rg');
echo '
';
$po->pixelOperation($_GET['image'], 'result_maxgb.png', array($po, 'maxColor'), 'gb');
echo '
';
$po->pixelOperation($_GET['image'], 'result_maxrb.png', array($po, 'maxColor'), 'rb');
echo '
';
echo '
';
echo '
';
echo '
';
echo '
';
echo '
';
$contrast = 1.5;
$po->pixelOperation($_GET['image'], 'result_contrast2.png', array($po, 'contrast'), $contrast);
echo '
';
echo '
';
echo '
';
echo '
';
// 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 '
';
echo '