Thiemo Mättig

PHP imagesharpen()

The following example codes are for very small, 16 × 16 pixel images (favicons) and thumbnails mainly. It's not that difficult to adopt this code for larger images (basically replace all 16 with $height/$width in the for loops, see below). However, it's not a good idea to sharpen large images using these functions because they are horrible slow.

favicon_sharpen_fast() takes 0.0039 seconds for a 16 × 16 pixel image (on my machine, of course). It uses only two surrounding pixels for the calculations.

favicon_sharpen_precise() takes 0.0043 seconds. That's 15% slower but looks a little bit better. It uses all four surrounding pixels for the calculations.

These functions are based on code by Alex R. Austin found in the user notes at php.net but are faster (even imagesharpen_precise() is faster than the code at php.net, e.g. 8 instead of 9 seconds for a 800 × 600 pixel image).

Example script

<?php

$thumbnail = imagecreatefromjpeg("thumbnail.jpg");
$favicon = imagecreatetruecolor(16, 16);
imagecopyresampled($favicon, $thumbnail,
    0, 0, 0, 0,
    16, 16, imagesx($thumbnail), imagesy($thumbnail));
favicon_sharpen_precise($favicon);
header("Content-type: image/png");
imagepng($favicon);
imagedestroy($favicon);
imagedestroy($thumbnail);

Fast sharpen a 16 × 16 pixel image

<?php

function favicon_sharpen_fast($favicon)
{
    $rs = array();
    $gs = array();
    $bs = array();
    for ($y = 0; $y < 16; ++$y)
    {
        for ($x = 0; $x < 16; ++$x)
        {
            $rgb = imagecolorat($favicon, $x, $y);
            $rs[$y][$x] = $rgb >> 0x10;
            $gs[$y][$x] = $rgb >> 0x08 & 0xFF;
            $bs[$y][$x] = $rgb         & 0xFF;
        }
    }
    for ($y = 1; $y < 16; ++$y)
    {
        $rd = $rs[$y][0];
        $gd = $gs[$y][0];
        $bd = $bs[$y][0];
        $yd = $y - 1;
        for ($x = 1; $x < 16; ++$x)
        {
            $r = -($rs[$yd][$x] + $rd) / 2;
            $g = -($gs[$yd][$x] + $gd) / 2;
            $b = -($bs[$yd][$x] + $bd) / 2;
            $r += 2 * $rd = $rs[$y][$x];
            $g += 2 * $gd = $gs[$y][$x];
            $b += 2 * $bd = $bs[$y][$x];
            if ($r < 0) $r = 0;
            elseif ($r > 255) $r = 255;
            if ($g < 0) $g = 0;
            elseif ($g > 255) $g = 255;
            if ($b < 0) $b = 0;
            elseif ($b > 255) $b = 255;
            imagesetpixel($favicon, $x, $y, $r << 0x10 | $g << 0x08 | $b);
        }           
    }
}

Precise sharpen a 16 × 16 pixel image

<?php

function favicon_sharpen_precise($favicon)
{
    $rs = array();
    $gs = array();
    $bs = array();
    for ($y = 0; $y < 16; ++$y)
    {
        for ($x = 0; $x < 16; ++$x)
        {
            $rgb = imagecolorat($favicon, $x, $y);
            $rs[$y][$x] = $rgb >> 0x10;
            $gs[$y][$x] = $rgb >> 0x08 & 0xFF;
            $bs[$y][$x] = $rgb         & 0xFF;
        }
    }
    for ($y = 1; $y < 15; ++$y)
    {
        $rd = $rs[$y][0];
        $gd = $gs[$y][0];
        $bd = $bs[$y][0];
        $yd = $y - 1;
        $yi = $y + 1;
        for ($x = 1; $x < 15; ++$x)
        {
            $r = -($rs[$yd][$x] + $rs[$yi][$x] + $rd + $rs[$y][$x + 1]) / 4;
            $g = -($gs[$yd][$x] + $gs[$yi][$x] + $gd + $gs[$y][$x + 1]) / 4;
            $b = -($bs[$yd][$x] + $bs[$yi][$x] + $bd + $bs[$y][$x + 1]) / 4;
            $r += 2 * $rd = $rs[$y][$x];
            $g += 2 * $gd = $gs[$y][$x];
            $b += 2 * $bd = $bs[$y][$x];
            if ($r < 0) $r = 0;
            elseif ($r > 255) $r = 255;
            if ($g < 0) $g = 0;
            elseif ($g > 255) $g = 255;
            if ($b < 0) $b = 0;
            elseif ($b > 255) $b = 255;
            imagesetpixel($favicon, $x, $y, $r << 0x10 | $g << 0x08 | $b);
        }           
    }
}

Precise sharpen any image

<?php

function imagesharpen_precise($image)
{
    $height = imagesy($image);
    $width  = imagesx($image);
    $rs = array();
    $gs = array();
    $bs = array();
    for ($y = 0; $y < $height; ++$y)
    {
        for ($x = 0; $x < $width; ++$x)
        {
            $rgb = imagecolorat($image, $x, $y);
            $rs[$y][$x] = $rgb >> 0x10;
            $gs[$y][$x] = $rgb >> 0x08 & 0xFF;
            $bs[$y][$x] = $rgb         & 0xFF;
        }
    }
    $height--;
    $width--;
    for ($y = 1; $y < $height; ++$y)
    {
        $rd = $rs[$y][0];
        $gd = $gs[$y][0];
        $bd = $bs[$y][0];
        $yd = $y - 1;
        $yi = $y + 1;
        for ($x = 1; $x < $width; ++$x)
        {
            $r = -($rs[$yd][$x] + $rs[$yi][$x] + $rd + $rs[$y][$x + 1]) / 4;
            $g = -($gs[$yd][$x] + $gs[$yi][$x] + $gd + $gs[$y][$x + 1]) / 4;
            $b = -($bs[$yd][$x] + $bs[$yi][$x] + $bd + $bs[$y][$x + 1]) / 4;
            $r += 2 * $rd = $rs[$y][$x];
            $g += 2 * $gd = $gs[$y][$x];
            $b += 2 * $bd = $bs[$y][$x];
            if ($r < 0) $r = 0;
            elseif ($r > 255) $r = 255;
            if ($g < 0) $g = 0;
            elseif ($g > 255) $g = 255;
            if ($b < 0) $b = 0;
            elseif ($b > 255) $b = 255;
            imagesetpixel($image, $x, $y, $r << 0x10 | $g << 0x08 | $b);
        }           
    }
}