In Photoshop there is a feature called Auto Contrast.

It builds a histogram of the image and spreads out the values so the whole tonal-range is being used. This is very usefull for images that have been taken in bad lightning conditions or low-range cameras. Makes the images look a lot crispier.

PHPThumb has these two funktions:

    function HistogramAnalysis(&$gdimg, $calculateGray=false) {
        $ImageSX = ImageSX($gdimg);
        $ImageSY = ImageSY($gdimg);
        for ($x = 0; $x < $ImageSX; $x++) {
            for ($y = 0; $y < $ImageSY; $y++) {
                $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y);
                @$Analysis['red'][$OriginalPixel['red']]++;
                @$Analysis['green'][$OriginalPixel['green']]++;
                @$Analysis['blue'][$OriginalPixel['blue']]++;
                @$Analysis['alpha'][$OriginalPixel['alpha']]++;
                if ($calculateGray) {
                    $GrayPixel = phpthumb_functions::GrayscalePixel($OriginalPixel);
                    @$Analysis['gray'][$GrayPixel['red']]++;
                }
            }
        }
        $keys = array('red', 'green', 'blue', 'alpha');
        if ($calculateGray) {
            $keys[] = 'gray';
        }
        foreach ($keys as $dummy => $key) {
            ksort($Analysis[$key]);
        }
        return $Analysis;
    }

and

    function HistogramStretch(&$gdimg, $band='*', $method=0, $threshold=0.1) {
        // equivalent of "Auto Contrast" in Adobe Photoshop
        // method 0 stretches according to RGB colors. Gives a more conservative stretch.
        // method 1 band stretches according to grayscale which is color-biased (59% green, 30% red, 11% blue). May give a punchier / more aggressive stretch, possibly appearing over-saturated
        $Analysis = phpthumb_filters::HistogramAnalysis($gdimg, true);
        $keys = array('r'=>'red', 'g'=>'green', 'b'=>'blue', 'a'=>'alpha', '*'=>(($method == 0) ? 'all' : 'gray'));
        $band = substr($band, 0, 1);
        if (!isset($keys[$band])) {
            return false;
        }
        $key = $keys[$band];

        // If the absolute brightest and darkest pixels are used then one random
        // pixel in the image could throw off the whole system. Instead, count up/down
        // from the limit and allow <threshold> (default = 0.1%) of brightest/darkest
        // pixels to be clipped to min/max
        $threshold = floatval($threshold) / 100;
        $clip_threshold = ImageSX($gdimg) * ImageSX($gdimg) * $threshold;
        //if ($min >= 0) {
        //    $range_min = min($min, 255);
        //} else {
            $countsum = 0;
            for ($i = 0; $i <= 255; $i++) {
                if ($method == 0) {
                    $countsum = max(@$Analysis['red'][$i], @$Analysis['green'][$i], @$Analysis['blue'][$i]);
                } else {
                    $countsum += @$Analysis[$key][$i];
                }
                if ($countsum >= $clip_threshold) {
                    $range_min = $i - 1;
                    break;
                }
            }
            $range_min = max($range_min, 0);
        //}
        //if ($max > 0) {
        //    $range_max = max($max, 255);
        //} else {
            $countsum = 0;
            for ($i = 255; $i >= 0; $i--) {
                if ($method == 0) {
                    $countsum = max(@$Analysis['red'][$i], @$Analysis['green'][$i], @$Analysis['blue'][$i]);
                } else {
                    $countsum += @$Analysis[$key][$i];
                }
                if ($countsum >= $clip_threshold) {
                    $range_max = $i + 1;
                    break;
                }
            }
            $range_max = min($range_max, 255);
        //}
        $range_scale = (($range_max == $range_min) ? 1 : (255 / ($range_max - $range_min)));
        if (($range_min == 0) && ($range_max == 255)) {
            // no adjustment neccesary - don't waste CPU time!
            return true;
        }

        $ImageSX = ImageSX($gdimg);
        $ImageSY = ImageSY($gdimg);
        for ($x = 0; $x < $ImageSX; $x++) {
            for ($y = 0; $y < $ImageSY; $y++) {
                $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y);
                if ($band == '*') {
                    $new['red']   = min(255, max(0, ($OriginalPixel['red']   - $range_min) * $range_scale));
                    $new['green'] = min(255, max(0, ($OriginalPixel['green'] - $range_min) * $range_scale));
                    $new['blue']  = min(255, max(0, ($OriginalPixel['blue']  - $range_min) * $range_scale));
                    $new['alpha'] = min(255, max(0, ($OriginalPixel['alpha'] - $range_min) * $range_scale));
                } else {
                    $new = $OriginalPixel;
                    $new[$key] = min(255, max(0, ($OriginalPixel[$key] - $range_min) * $range_scale));
                }
                $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, $new['red'], $new['green'], $new['blue'], $new['alpha']);
                ImageSetPixel($gdimg, $x, $y, $newColor);
            }
        }

        return true;
    }

I'm a designer, so I can't make a module from that code. It seems though that it wouldn't be too hard to hard to do for someone who knows his/her way around.

Comments

dman’s picture

Thanks for the code, I can see how it would fit in.
maybe one day...

stefan81’s picture

Hy, any progress on this?
Would be cool!

chaps555’s picture

Hello ,

I am not able to understand this function
HistogramAnalysis.

How the analysis is carried out here.

Chaps

millenniumtree’s picture

If you're using imagemagick instead of GD, you can do the following:

Install imagecache_customactions module.
Add a custom action, and enter the following PHP code.

$image->ops[] = '-normalize';
return $image;

Cheers,
--tree

NoRandom’s picture

Hi, I've used Imagemagick in the past from commandline to alter images but this is my first time trying to use it from PHP. Where can I find information of the functions or methods available for $image?

Following the example from millenniumtree I've tried:

$image->ops[] = '-contrast';

...and it seems to work. But, when I want a harder contrast this doesn't work:

$image->ops[] = '-contrast 100';

By the way, in Drupal 7 you don't have to return the image at the end.

fietserwin’s picture

Version: 6.x-1.x-dev » 7.x-1.x-dev

1st: let's move requests to the D7 branch. Our D6 branch is in maintenance only now.

#5: According to the documentation -contrast has no parameter, though you can use it with -contrast and +contrast (more/less contrast) and you can repeat the command. See: http://www.imagemagick.org/script/command-line-options.php#contrast.