Cropping Images using DHTML (Prototype) and symfony

by Dave Dash 16Sep06

Processing the crop

Initially I was frustrated with the data that was being sent. I knew the center of the image in relation to this 200x200 pixel canvas and its width... but what could I do with that. Well I could just recreate what I saw in the GUI. I needed to create a 200x200 pixel image first, place my original avatar resized (and resampled) at the precise coordinates and then cut out the center most 80x80 pixels to become the final avatar image.

If you note in our template above for cropSuccess.php we submit our form back to the crop action. Let's look at the action:

public function executeCrop()
{
    if ($this->getRequestParameter('file')&&$this->getRequestParameter('width')) {          // we are saving our cropped image
        // Load the original avatar into a GD image so we can manipulate it with GD
        $o_filename = $this->getRequestParameter('file');  // we'll use this to find the file on our system
        $o_filename = sfConfig::get('sf_root_dir').'/web' . $o_filename;
        $o_im = @imagecreatetruecolor(80, 80) or die("Cannot Initialize new GD image stream");
        $o_imagetype = exif_imagetype($o_filename); // is this gif/jpeg/png

        // appropriately create the GD image
        switch ($o_imagetype) {
            case 1: // gif
                $o_im = imagecreatefromgif($o_filename);
                break;
            case 2: // jpeg
                $o_im = imagecreatefromjpeg($o_filename);   
                break;
            case 3: // png
                $o_im = imagecreatefrompng($o_filename);
                break;
        }

        // Let's create our canvas
        $im = @imagecreatetruecolor(200, 200) or die("Cannot Initialize new GD image stream");
        imagecolortransparent ( $im, 127 ); // set the transparency color to 127
        imagefilledrectangle( $im, 0, 0, 200, 200, 127 ); // fill the canvas with a transparent rectangle

        // let's get the new dimension for our image

        $new_width = $this->getRequestParameter('width');
        $o_width = imageSX($o_im);
        $o_height = imageSY($o_im);

        $new_height = $o_height/$o_width * $new_width;

        // we place the image at the xy coordinate and then shift it so that the image is now centered at the xy coordinate
        $x = $this->getRequestParameter('x') - $new_width/2;
        $y = $this->getRequestParameter('y') - $new_height/2;

        // copy the original image resized and resampled onto the canvas
        imagecopyresampled($im,$o_im,$x,$y,0,0,$new_width,$new_height,$o_width,$o_height); 
        imagedestroy($o_im);

        // $final will be our final image, we will chop $im and take out the 80x80 center
        $final = @imagecreatetruecolor(80, 80) or die("Cannot Initialize new GD image stream");
        imagecolortransparent ( $final, 127 ); // maintain transparency

        //copy the center of our original image and store it here
        imagecopyresampled ( $final, $im, 0, 0, 60, 60, 80, 80, 80, 80 );
        imagedestroy($im);

        //save our new user pic
        $p = new Userpic();
        $p->setUser($this->getUser()->getUser());
        $p->setGD2($final);
        $p->save();
        imagedestroy($final);
        $this->userpic = $p;
        return "Finished";
    }


    $this->getResponse()->addJavascript("dom-drag");
    $this->getResponse()->addJavascript('/sf/js/prototype/prototype');
    $this->getResponse()->addJavascript('/sf/js/prototype/effects');
    $this->image = '/images/userpics/originals/' . $this->getRequestParameter('file');
}

It's doing exactly what the paragraph above explains when the image dimensions are given. The code is well commented so it should be easy enough to follow.

[GD image functions in PHP][gd2php] are fairly robust and can help you do a lot of tricks with image data. Note the code to save the image, we'll cover it in detail soon.

The Model

$p = new Userpic();
$p->setUser($this->getUser()->getUser());
$p->setGD2($final);
$p->save();

First some clarification the second line. myUser::getUser() gets the User object associated with the currently logged in user. The third line, however, is where the magic happens. Before we look at it, let's have a quick look at our model:

userpic:
 _attributes: { phpName: Userpic }
 id:
 user_id:
 image: blob
 thumb: blob
 created_at:
 updated_at:

We have an image attribute and a thumb property to our Userpic object. This is where we store PNG versions of each icon and their 16x16 thumbnails respectively. We do this in Userpic::setGD2():

public function setGD2($gd2_image)
{
    //convert to PNG
    ob_start();
    imagepng($gd2_image);
    $png = ob_get_clean();
    //save 16x16
    $gd2_tn = @imagecreatetruecolor(16, 16) or die("Cannot Initialize new GD image stream");
    imagealphablending( $gd2_tn, true );
    imagecolortransparent ( $gd2_tn, 127 );

    imagecopyresampled ( $gd2_tn, $gd2_image, 0, 0, 0, 0, 16, 16, 80, 80 );
    ob_start();
    imagepng($gd2_tn);
    $tn = ob_get_clean();

    $this->setImage($png);
    $this->setThumb($tn);
}

We capture the output of the full size PNG, then we scale it again and capture the output of the thumbnail and set them.

Conclusion

When it comes to web apps, having a relatively simple GUI for people to resize images can go a long way in terms of adoption rate of avatars and custom user pictures by non technical users.

Enjoy, and if you found this useful (or better implemented it) let me know.

Pages: 1 2


Where am I?

This is a single entry in the weblog.

"Cropping Images using DHTML (Prototype) and symfony" is filed under css, programming, reviewsby.us, spindrop, symfony and usability. It was published in September 2006.

September 2006
M T W T F S S
« Aug   Oct »
 123
45678910
11121314151617
18192021222324
252627282930  

Tags

need more help

If you found our tutorials and articles to be useful, but are still looking for more hands on help, consider hiring us. Find out more about how Spindrop can help you.

 

26 Responses to “Cropping Images using DHTML (Prototype) and symfony”


  1. 1 kevin Posted November 10th, 2006 - 6:57 pm

    People who dont have exif turned on in PHP can use this:

                $o_imagetype = getImageSize($o_filename); // is this gif/jpeg/png
    
            // appropriately create the GD image
            switch ($o_imagetype['mime']) {
                case "image/gif": // gif
                    $o_im = imagecreatefromgif($o_filename);
                    break;
                case 'image/jpeg': // jpeg
                    $o_im = imagecreatefromjpeg($o_filename);   
                    break;
                case 'image/png': // png
                    $o_im = imagecreatefrompng($o_filename);
                    break;
            }
    
  2. 2 Helper Guy Posted March 9th, 2007 - 11:21 am

    Just a note,

    there is a small bug

    as things currently are, you must move the slider (even if you are just moving it to the zero position), otherwise the image will not be cropped at the correct correctly

    to fix this, add the following line into the SetupAva function

    ava_width.value = new_w;

    apart from that.. great code, very helpful! EXACTLY what i was looking for :)

  3. 3 Dave Dash Posted March 9th, 2007 - 11:44 am

    Helper Guy,

    Thanks for the help, I edited your original post to preserve underscores… this site uses markdown which likes to turn underscores into italics… I’ll need to make the editing form more clear.

    -d

  4. 4 Helper Guy Posted March 9th, 2007 - 1:36 pm

    Transparency doesn’t work properly, even with the default image you are using

    any idea how to fix that?

  5. 5 Dave Dash Posted March 9th, 2007 - 1:43 pm

    Are you using Firefox or IE?

    If you’re using Firefox, it should work.

    If you’re using IE then there is an issue with IE’s lack of support for alpha transparncies.

    Luckily there is a PNG transparency fix that’ll use some IE specific magic to make it work. Hope that helps.

  6. 6 Helper Guy Posted March 9th, 2007 - 2:22 pm

    I meant the PHP GD image stuff

    it creates an image with a black background, rather than transparent

  7. 7 Dave Dash Posted March 9th, 2007 - 2:29 pm

    Unfortunately my knowledge of GD is limited, when I’ve used this cropper in environments running PHP5 with GD2 my transparencies worked.

    Looking back at the code:

    $im = imagecreatetruecolor(200, 200) or die("Cannot Initialize new GD image stream");
    imagecolortransparent ( $im, 127 ); // set the transparency color to 127
    imagefilledrectangle( $im, 0, 0, 200, 200, 127 ); // fill the canvas with a transparent rectangle
    

    We already initialize the canvas with a 200×200 rectangle that has the same color as the transparent pixel. So the code does what I expect it to on my end, beyond that I’m not sure what to say.

  8. 8 Helper Guy Posted March 9th, 2007 - 2:36 pm

    alright thanks for your help, it behaves differently for me for some reason.. i’m looking into the imagecopypallete function

    if i get it working i’ll post the solution here

  9. 9 vince Posted March 26th, 2007 - 11:17 am

    Very Nice Job, I’ve been looking for something like this for a while. Though I can’t seem to get it to work fully, would anyone have a working version they could zip to me. It would be greatly appreciated.

    vjz@hotmail.com

  10. 10 Dave Dash Posted March 26th, 2007 - 11:40 am

    Hey Vince,

    Where are you getting stuck?

    Unfortunately I don’t have anything zippable (code that’s used in closed-source production projects) at the moment, but I’m sure it can be debugged.

  11. 11 Fred Posted April 30th, 2007 - 10:02 pm

    Hi,

    this is the very best at least the more elegant cropping solution I have ever seen on web. Far. Bravo !

    Unfortunatly my poor english and programming knowledge don’t give me the opportunity to make it working fine for my users.

    The link to dom-drag.js is dead but I could get it using Coogle search (dom-drag.js download).

    The only way I found to get mac design images was to copy them from demo. I think they are only two images (handle.png and slider_back.png), right ?

    If you could put on line a full “kit” to download with the differents files (php, JS, CSS) as someone already asked for I believe, it would be great.

    Best regards

  12. 12 Developerz Posted June 14th, 2007 - 1:10 am

    Hi Dave,

    Thanks so much for sharing this example. I just got done implementing it in C#. Let’s just say I’m pretty stoked for figure it all out.

    I did find one bug in the javascript “function setupAva”

    The problem occurs when a user uploads a landscape image (width is greater than height), and does not use the handle.onDrag . If they don’t the ava_width returns 80, which will throw off the proportion.

    So what I did to fix this bug was set the was to set: avawidth.value = neww;

    Here’s a portion of the function setupAva that shows where I’ve added “avawidth.value = neww;”

    var ratio = (starth / startw); var newh; var neww; if (ratio > 1) { neww = 80; newh = (80starth)/startw; } else { newh = 80; neww = (80startw)/starth; }

            // set the ava_width.value here in case the user does not use the handle.onDrag function, if you don't landscape images get cropped with a small height
            ava_width.value = new_w;
    
            // these need to be set after we init
            avatarImg.style.top = '100px';
            avatarImg.style.left = '100px';
            avatarImg.style.width = new_w   'px';
            avatarImg.style.height = new_h   'px';
    

    Anyway, thanks again and hopefully this helps someone.

  13. 13 dungpt Posted July 2nd, 2007 - 7:12 am

    omg, i’m crazing with it :(

    here’s my problem

    http://www.sitepoint.com/forums/showthread.php?t=475618

    i can’t create image ok with 48×48 pixels

  14. 14 Ignacio Posted August 7th, 2007 - 11:30 pm

    I passed 2 days trying to change this… I don’t want 80×80, I want 160×160, nothing happen… :(

  15. 15 Ignacio Posted August 8th, 2007 - 12:04 am

    I did it! imagecopyresampled ( $final, $im, 0, 0, 17, 17, 160, 160, 160, 160 ); 17 = Margin of the overlay, sure!

  16. 16 NP Posted August 20th, 2007 - 10:03 am

    Could you please make a archive with the full functional code? I’m really having a hard time setting this up.

  17. 17 léonie Posted August 30th, 2007 - 5:17 am

    Can you please upload the corresponding php file(s)? Or am I missing something? I really digg your script. There are a couple others around, but I like the idea of the interface.

    Just for others to be up to date of what is around and works in most browsers:

    http://199.199.212.26/demo/ http://mondaybynoon.com/examples/imagecropresize/

  18. 18 Aleksey Posted May 28th, 2008 - 6:30 pm

    Hi, thank you very much autor for this work. Very introsting. But this havn’t been working in IE6. :-( . Problem in transparency for “”. Maybe somebody solved this proble.

  19. 19 Aleksey Posted May 28th, 2008 - 6:31 pm

    Problem in transparency for “ava_overlay”

  20. 20 Steve Conley Posted June 14th, 2009 - 5:34 pm

    Because there’s some demand out there for a packaged version of this, I’ve made one! My package wraps this in a class that isn’t symfony dependent.

    http://www.tanabi.com/projects/cropper

Who's linking?

  1. 1 - aNieto2K Pingback on Sep 16th, 2006
    "[...] Hazle Crop a tus imagenes con Javascript [Demo] [...] "
  2. 2 PHPDeveloper.org Trackback on Sep 16th, 2006
    "SpinDrop.us: Cropping Images using DHTML (Prototype) and symfony... ... "
  3. 3 Ruido blanco Trackback on Sep 17th, 2006
    "De como ser vago te evita escribir dos páginas de tutorial... Desde que volví de vacaciones he estado a punto de ... "
  4. 4 香港 PHP 用家社區 | Hong Kong PHP Users Group Trackback on Sep 20th, 2006
    "教學文件:利用 DHTML 製作一個裁剪圖像的介面... 網上有很多圖像處理、相簿管理的網上應用系統,容許我們把大圖像裁剪為較小的圖像,但是用戶必須輸入裁剪框的座標和大小,對一般人來說顯然十分困難,Dave Dash 在 Spindrop 發表了一篇教... "
  5. 5 Kwerty Blog » Avatar cropper Pingback on Mar 9th, 2007
    "[...] The cropper is identical to digg.coms cropper, I found the source on some random website. [...] "
  6. 6 Simbiotica :: Cropping Images using DHTML (Prototype) and symfony at Spindrop Pingback on Oct 24th, 2007
    "[...] Read more :: http://spindrop.us/2006/09/16/cropping-images-using-dhtml-prototype-and-symfony/ [...] "
Comments are currently closed.

Further Help

If you require more hands on assistance, we do offer affordable hands on support.