TalkPHP
 
 
Account Login
Latest Articles
» The basic usage of PHPTAL, a XML/XHTML template library for PHP
» Vulnerable methods and the areas they are commonly trusted in.
» Simple way to protect a form from bot
» The Basics On: How Session Stealing Works
» How to keep your forms from double posting data
IRC Channel
IRC Speech Bubble Join the friendly bunch on IRC...
(#TalkPHP on Freenode)

...Also available via a web interface.

See this thread for information on the TalkPHP Free Hugs Initiative™. Subject to availability.
Associates
Associates
CSS Tutorials
Reply
 
LinkBack Thread Tools Search this Thread Display Modes
Old 11-17-2008, 05:10 AM   #1 (permalink)
The Frequenter
Zend Certified 
 
Join Date: Sep 2007
Location: Denmark
Posts: 352
Thanks: 8
Kalle is on a distinguished road
Default Pixelate algorithm using GD

Long time no script for here, so I decided that a function I was working on the other day might be useful for posting here.

Its an pixelate algorithm written in PHP using GD, it includes a basic algorithm that works by coloring the pixel block the first color found in a block. The advanced algorithm iterates through all pixels and finds the average color in a block and colors it like that, through meaning more execution time.

Source:
PHP Code:
<?php
    
/**
     * Pixelate Algorithm
     * ========================================================================
     *
     * @author    Kalle Sommer Nielsen <kalle@php.net>
     * @link    http://www.tuxxedo.net/
     * @copyright    2006+
     * @license    Microsoft Public License
     * 
     * ========================================================================
     */

    
function imagepixelate($im$blocksize$advanced false)
    {
        if(!
is_resource($im) || strtolower(get_resource_type($im)) != 'gd')
        {
            return;
        }

        
$blocksize     = (integer) $blocksize;

        
$sx        imagesx($im);
        
$sy        imagesy($im);

        if(
$blocksize <= 0)
        {
            return(
false);
        }
        elseif(
$blocksize == 1)
        {
            return(
true);
        }

        if(
$advanced)
        {
            for(
$x 0$x $sx$x += $blocksize)
            {
                for(
$y 0$y $sy$y += $blocksize)
                {
                    
$colors = Array(
                            
'alpha'        => 0
                            
'red'        => 0
                            
'green'        => 0
                            
'blue'        => 0
                            
'total'        => 0
                            
);

                    for(
$cx 0$cx $blocksize; ++$cx)
                    {
                        for(
$cy 0$cy $blocksize; ++$cy)
                        {
                            if(
$x $cx >= $sx || $y $cy >= $sy)
                            {
                                continue;
                            }

                            
$color imagecolorat($im$x $cx$y $cy);
                            
imagecolordeallocate($im$color);

                            
$colors['alpha']     += ($color >> 24) & 0xFF;
                            
$colors['red']        += ($color >> 16) & 0xFF;
                            
$colors['green']    += ($color >> 8) & 0xFF;
                            
$colors['blue']        += $color 0xFF;

                            ++
$colors['total'];
                        }
                    }

                    
$color imagecolorallocatealpha($im
                                        
$colors['red'] / $colors['total'], 
                                        
$colors['green'] / $colors['total'], 
                                        
$colors['blue'] / $colors['total'], 
                                        
$colors['alpha'] / $colors['total']
                                        );

                    if(!@
imagefilledrectangle($im$x$y, ($x $blocksize 1), ($y $blocksize 1), $color))
                    {
                        return(
false);
                    }
                }
            }
        }
        else
        {
            for(
$x 0$x $sx$x += $blocksize)
            {
                for(
$y 0$y $sy$y += $blocksize)
                {
                    if(!@
imagefilledrectangle($im$x$y, ($x $blocksize 1), ($y $blocksize 1), imagecolorat($im$x$y)))
                    {
                        return(
false);
                    }
                }
            }
        }

        return(
true);
    }
?>
(Note that GD 2.0.1 or greater is required for this to work, but the chances that you're using GD 2.0.1 or greater is very high)

The code is licensed under the Ms-Pl license which can be found at:
http://www.opensource.org/licenses/ms-pl.html

Prototype:
imagepixelate(resource $image, integer $blocksize [, boolean $advanced = false])

The $image parameter must be a resource valid resource, invalid resources NULL is returned.

The $blocksize parameter defines the blocksize in pixels. If a blocksize of 0 or lower is supplied the function will return false. Note that a blocksize of 1 wouldn't have any effect as each block already is one pixel so therefore the function just returns true.

The $advanced parameter is used to specify which algorithm to use, by default its using the simple algorithm, descriptions can be found above.

Return values, NULL on invalid resource specified, FALSE on error and TRUE on success.

Example code (basic):
PHP Code:
<?php
    header
('Content-type: image/jpeg');

    
$im imagecreatefromjpeg('./VistaLogo.jpg');

    
imagepixelate($im5);
    
imagejpeg($im''100);
?>
Example code (advanced):
PHP Code:
<?php
    header
('Content-type: image/jpeg');

    
$im imagecreatefromjpeg('./VistaLogo.jpg');

    
imagepixelate($im5true);
    
imagejpeg($im''100);
?>
Example output (basic):


Example output (advanced):


A clear difference is visable, enjoy! :)


C Version
I've made a version, also written for gd. So in order to get it to work you have to be a minor libgd hacker. The C code is as follows:

c Code:
int gdImagePixelate(gdImagePtr im, int blocksize, int advanced)
{
    int x, y;

    if (blocksize <= 0) {
        return 0;
    } else if (blocksize == 1) {
        return 1;
    }

    if (advanced) {
        int a, r, g, b, c;
        int total;
        int cx, cy;

        for (x = 0; x < im->sx; x += blocksize) {
            for (y = 0; y < im->sy; y += blocksize) {
                a = r = g = b = c = total = 0;

                for (cx = 0; cx < blocksize; cx++) {
                    for (cy = 0; cy < blocksize; cy++) {
                        if (gdImageBoundsSafe(im, (x + cx), (y + cy)) == 0) {
                            continue;
                        }

                        c = gdImageGetPixel(im, (x + cx), (y + cy));
                        gdImageColorDeallocate(im, c);

                        a += (c >> 24) & 0xFF;
                        r += (c >> 16) & 0xFF;
                        g += (c >> 8) & 0xFF;
                        b += c & 0xFF;

                        total++;
                    }
                }

                c = gdImageColorAllocateAlpha(im, r / total, g / total, b / total, a / total);
                gdImageFilledRectangle(im, x, y, (x + blocksize - 1), (y + blocksize - 1), c);
            }
        }

        return 1;
    }

    for (x = 0; x < im->sx; x += blocksize) {
        for(y = 0; y < im->sy; y += blocksize) {
            gdImageFilledRectangle(im, x, y, (x + blocksize - 1), (y + blocksize - 1), gdImageGetPixel(im, x, y));
        }
    }

    return 1;
}

Put that in the bottom of gd.c, and in the gd.h header after the other function prototypes then add the following:
c Code:
int gdImagePixelate(gdImagePtr im, int blocksize, int advanced);

Its usage are exactly the same as the php version, except for this is on C level and much faster ofcourse.

Furthermore for people who also hacks php a little you can alter the gd binding to support this function, I assume people who do this knows how the basic PHPAPI works so I'll only post the PHP_FUNCTION macro's body:
c Code:
/* {{{ proto bool imagepixelate(resource im, int blocksize [, bool advanced])
   Applies pixelation to the image */

PHP_FUNCTION(imagepixelate)
{
    zval *IM;
    gdImagePtr im;
    long blocksize;
    zend_bool advanced = 0;
    int retval;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|b", &IM, &blocksize, &advanced) == FAILURE) {
        return;
    }

    ZEND_FETCH_RESOURCE(im, gdImagePtr, &IM, -1, "Image", le_gd);

    retval = gdImagePixelate(im, (int) blocksize, advanced);

    if (retval) {
        RETURN_TRUE;
    } else {
        RETURN_FALSE;
    }
}
/* }}} */

I've submitted it as a feature request to GD itself and yet again, enjoy! :)
__________________

Last edited by Wildhoney : 11-23-2008 at 04:13 PM.
Send a message via MSN to Kalle Send a message via Skype™ to Kalle
Kalle is offline  
Reply With Quote
Old 11-17-2008, 09:02 AM   #2 (permalink)
The Acquainted
 
sjaq's Avatar
 
Join Date: Nov 2007
Location: Netherlands
Posts: 113
Thanks: 11
sjaq is on a distinguished road
Default

Nice script, but can't you just scale an image down and then scale it up to get the same effect?...
sjaq is offline  
Reply With Quote
Old 11-17-2008, 11:49 AM   #3 (permalink)
The Prestige
Upcoming Programmer Inquisitive 
 
Tanax's Avatar
 
Join Date: Sep 2007
Location: Sweden, Stockholm
Posts: 1,080
Thanks: 115
Tanax is on a distinguished road
Default

I'm sorry if this is a weird question, but I really don't understand what this is for :O
__________________
Tanax is offline  
Reply With Quote
Old 11-17-2008, 07:38 PM   #4 (permalink)
Moderateur
RegEx Guru PHP Guru Top Contributor Advanced Programmer 
 
Salathe's Avatar
 
Join Date: Apr 2007
Posts: 1,393
Thanks: 5
Salathe is on a distinguished road
Default

A similar technique using imagecopyresized/imagecopyresampled (with a block size of 5) would produce something like:

Original


Non-advanced (uses imagecopyresized)


Advanced (uses imagecopyresampled)


Good work with the function Kalle, did you first write it in 2006 (looking at the copyright).
Salathe is offline  
Reply With Quote
Old 11-17-2008, 09:13 PM   #5 (permalink)
The Frequenter
Zend Certified 
 
Join Date: Sep 2007
Location: Denmark
Posts: 352
Thanks: 8
Kalle is on a distinguished road
Default

I initially wrote the simple pixelate effect in late 2006 yea, but the advanced version was written a few weeks ago :)

@Tanax im an image effect, could for example be used to style an image dynamiclly, or maybe on an verification image to blur it.

@Sjaq in theory I think its possible yea, but I didn't really look at it.
__________________
Send a message via MSN to Kalle Send a message via Skype™ to Kalle
Kalle is offline  
Reply With Quote
Old 11-17-2008, 09:15 PM   #6 (permalink)
The Prestige
Upcoming Programmer Inquisitive 
 
Tanax's Avatar
 
Join Date: Sep 2007
Location: Sweden, Stockholm
Posts: 1,080
Thanks: 115
Tanax is on a distinguished road
Default

Okey, I understand now what it does.
Now I have a new question.

Why would you want to do this? I mean, the original image is better quality? :O
__________________
Tanax is offline  
Reply With Quote
Old 11-17-2008, 09:46 PM   #7 (permalink)
how quixotic are you?
 
ETbyrne's Avatar
 
Join Date: Dec 2007
Location: Lapeer, MI
Posts: 445
Thanks: 37
ETbyrne is on a distinguished road
Default

Quote:
Originally Posted by Tanax View Post
Okey, I understand now what it does.
Now I have a new question.

Why would you want to do this? I mean, the original image is better quality? :O
To make it look kool of coarse...
__________________
Dingo Web Systems > http://www.dingocode.com
My Website > http://www.evanbot.com
ETbyrne is offline  
Reply With Quote
Old 11-18-2008, 12:01 AM   #8 (permalink)
The Frequenter
Zend Certified 
 
Join Date: Sep 2007
Location: Denmark
Posts: 352
Thanks: 8
Kalle is on a distinguished road
Default

Quote:
Originally Posted by Tanax View Post
Okey, I understand now what it does.
Now I have a new question.

Why would you want to do this? I mean, the original image is better quality? :O
The point of the effect isn't the quality, its to do what you need. I've personally written a couple of smaller image editing programs in php which enables me to manipulate images. For example if you wanna use pixelization (pixelate censur), you can easily perform this dynamically with php by using the function.

Theres no exact usage for it, as people's need vary :)
__________________
Send a message via MSN to Kalle Send a message via Skype™ to Kalle
Kalle is offline  
Reply With Quote
Old 11-23-2008, 04:04 PM   #9 (permalink)
The Frequenter
Zend Certified 
 
Join Date: Sep 2007
Location: Denmark
Posts: 352
Thanks: 8
Kalle is on a distinguished road
Default

Updated the original post with a C version for use with GD, enjoy! :)
__________________
Send a message via MSN to Kalle Send a message via Skype™ to Kalle
Kalle is offline  
Reply With Quote
Old 06-27-2009, 12:36 AM   #10 (permalink)
The Frequenter
Zend Certified 
 
Join Date: Sep 2007
Location: Denmark
Posts: 352
Thanks: 8
Kalle is on a distinguished road
Default

As an update for this, since PHP 5.3.0 RC1, this pixelation algorithm have been apart of the GD binding for PHP, and its available as of GD 2.1.0.

For more information and documentation see:
http://php.net/imagefilter
__________________
Send a message via MSN to Kalle Send a message via Skype™ to Kalle
Kalle is offline  
Reply With Quote
Reply



Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On


All times are GMT. The time now is 08:33 AM.

 
     

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.1.0
Inactive Reminders By Icora Web Design