Cropping Images

Howzit guys,

Any one know of a way to crop an image from the center of the image in php? What I want to achieve is to take an uploaded photo and create a thumbnail of a certain size from this. The problem is that a use can upload a image of any dimension.

I know it is possible to crop an image, but would like to get some comments on the approach.

Here is my idea.

  1. Determine the width and height
  2. From the width, determine the middle
  3. From the middle, subtract half the desired width. This will give me my x coordinate
  4. do the same for my height to get my y coordinate
  5. Crop from these coordinates.

Any body know of a better idea, as this seems a bit messy.

I’ve posted a class that pretty much does this on the forum, though it rescales the image first, then crops to get the proportions right.

Computationally cropping without resizing will not work most of the time. The computer has no way of knowing what the compositional elements of the photo are and is going to end up cutting through faces a lot of the time. By rescaling first you can avoid some of this problem, but the solution still isn’t as idea as having the user do the resize first in photoshop.

That said the class is small and touches on the basics of manipulating images using the built in imageMagick library, so it’s a good learning tool.

You may also want to look at which is a JQuery script allowing users to user select an area of the image to crop to. There’s also a tutorial on using GD to crop based on the users selection here which you could use as a starting point.

If you use WideImage, the code boils down to:

WideImage::load('upload_field')->crop('center', 'center', 300, 200)->saveToFile('thumb.png');

If you’re not going with 3rd party code, then your logic is fine and can’t be done any better. :slight_smile:

Thanks, I think, though that code is on the old side (3 years now). It solved the problem set before it.

OK, this might be overkill, but you could use something like the Fruml ImageTools (and before you ask, yes, I wrote them :slight_smile: ).

How it works is quite simple: you define a transformation to be applied to an image in an array, then pass that to ImageTools, which transforms the image and caches it.

include_once "class.imagetools.php";

$crop_transformation = array(
    array('crop', array('width' => 300, 'height' => 300)),

$image_tool= ImageTools::create();

$data = $image_tool->process(array(
    'source' => dirname(__FILE__) . '/example.jpg',
    'chain' => $crop_transformation

echo '<img src="'. $data['path'] . '" width="'. $data['width'] . '" height="'. $data['height'] . '" alt="" />';

Why use such a verbose tool for cropping an image? Well, if you later want to do more than just crop, you can easily add new transformations:

$grayscale_transformation = array(
    array('resize', array('width' => 400, 'keep_aspect' => true, 'shrink_only' => true)),
    array('grayscale', array()),
    array('margin', array('global' => 2, 'bgcolor' => 'ffffff')),
    array('border', array('width' => 1, 'color' => 'B0B2B4', 'enlarge' => true))

Documentation is severely lacking although if you want to give it a go, I’ll be glad to help out with any questions you may have.

I’ll stop plugging my project now :slight_smile:

Looks like a very usefull project. When calling process(), does the code alter the existing image, or does it create a new image with the new properies supplied?

It creates a new image, the original is left untouched.
That’s useful for generating multiple variations of a single image.

I have noticed that you do not specify a name for the new image, does this use a random string as a name and the returns the name as an key in the array returned.

Does it by any chance have functionality to stream the image, rather than save it? :slight_smile:

Yes, there’s an output() function which you can use instead of process() will output the image to the browser. I’m not exactly sure, but the image might still be saved to the cache (I’ll need to dive into the code to check that out).

    'source' => dirname(__FILE__) . '/example.jpg',
    'chain' => $crop_transformation

As for the name issue, now it uses an md5 string as name. Possibly I’ll add an option to specify the output name, although that might make it a little difficult to decide if the image should be processed again or served from the cache.