The art to having a website with decent imagery is to allow the user/administrator to crop the images. Despite advancing web technologies, I still cannot trust a computer to scale, resize or crop an image without the resulting image being of someones foot.

There are certain ‘off-the-shelf’ products, mainly for ASP.net, with very little introduced into PHP, so I had to build my own using helpful libraries and plugins.

The Cropping

Writing a JavaScript cropping tool from scratch is no small challenge, getting a bug-free environment where all of the calculations are perfect can take weeks of hairless programming sessions and various mental breakdowns! And with my hair still in tact and mental capacity intact I implemented jCrop (I let someone else do the hard work). I am continuously reminding people that reinventing the wheel is both a waste of time, energy and sanity but the odds are against you. If a plugin is popular then the chances are that their solution will be 10 times better than yours as theirs have probably evolved over several months if not years!

Implementing jCrop

Once you have the package downloaded and have included both the JavaScript file and the CSS file it can be as simple as:

$.Jcrop('#cropthis');

I know this isn’t the usual jQuery syntax, the reason for this will become apparent very soon!

The code above is all well and good but it is no use to anyone unless they enjoy spending their time moving a crop box around an image that does absolutely nothing with the co-ordinates. So we need to catch the xy co-ords to pass to the PHP to process.

For which we need a form:

<form action="/path/to/my/crop/method" action="post">
     <input type="hidden" name="x" id="x" value="" />
     <input type="hidden" name="y" id="y" value="" />
     <input type="hidden" name="x2" id="x2" value="" />
     <input type="hidden" name="y2" id="y2" value="" />
     <input type="hidden" name="w" id="w" value="" />
     <input type="hidden" name="h" id="h" value="" />
     <!-- You will probably want to store the id or path to the image you are altering -->
     <img id="cropthis" src="path/to/original/image.extension" alt="Image to crop" />
</form>

So we have form values to submit, but we need a way to alter these values on a real time basis as the cropping area is resized and moved. Lickily the developers at DeepLiquid have also written something to do that for you aswell!

We need to define a function to gather the information, then pass it into the JCrop function as a json argument.

function setCoords(c) {
    jQuery('#x').val(c.x);
    jQuery('#y').val(c.y);
    jQuery('#x2').val(c.x2);
    jQuery('#y2').val(c.y2);
    jQuery('#w').val(c.w);
    jQuery('#h').val(c.h);
}

$.Jcrop('#cropthis', {
     onChange: setCoords,
     onSelect: setCoords
});

Finally if you are using huge original images to crop with, i.e. the original is 4kx2.5x px and you need to crop an 800×600 image, then Jcrop has a solution for this too. Jcrop helps you deal with large scale images by allowing you to scale down the image without losing the original ratios. So I can tell Jcrop to present the image to crop as 700px Wide and 850px high, the user can then crop (maintaining an aspect ratio defined by us) and the co-ordinates will be correct relative to the original image’s scale. Very clever!

To do this, modify the jQuery to:

$.Jcrop('#cropthis', {
    boxWidth:700,
    boxHeight: 850,
    aspectRatio: 2,
    onChange: setCoords,
    onSelect: setCoords
})

You can also do handy things such as set the minimum cropping size using minSize:[width,height].

This is the Cropping done, we just need to process the image!

To process the image, I am not going to use CodeIgniter’s built in imagemanipulation class as after hours of it failing silently I moved to use an external library. For this example I will use image manipulation by Talk in Code. To use this class, simply download it and drop it into the /System/Application/Libraries directory and it will then be available for $this->load();

Lets get down to the PHP:

$image = $this->load->library('imagemanipulation', '/path/to/original/image.jpg');

if($image->imageok) {
    $image->setJpegQuality('100');
    $image->setCrop($this->input->post('x'), $this->input->post('y'), $this->input->post('w'), $this->input->post('h'));
    $image->resize('width you want to resize it to');
    $image->save('/path/to/new/image.jpg');
} else {
   //Throw error as there was a problem loading the image
}

It took me a while to work out the best way to do things, but the resize allows the width to be input which will scale the image, keeping aspect with the aspects of the x y co-ordinates.

If you need to scale and resize multiple images, you can resize->save->resize->save with the same image which works like a dream!

Have a go, any suggestions are welcome!

Links

Deepliquid – Jcrop

Talk in code – Imagemanipulation