Jump to content

Ability to provide custom cropping center to the ImageSizer


u-nikos
 Share

Recommended Posts

Hey Ryan,

I saw your recent commits to the ImageSizer and was wondering if you could also add the ability to provide a custom center value (x, y) to the ImageSizer?

Like: setCropping(array('30%', '40%')) or setCropping(array('200px', '300px'))

Sometimes you know exactly what the most important part of a uploaded image is. And this could also come in handy when developing a InputFieldImage module where the user can click on a image in the page editor to define his own cropping center (or focus point). Most images have a certain point in a image that is most important (like a human face) and should always be visible in crops.

Greetings,

Niek

  • Like 2
Link to comment
Share on other sites

Ryan, I think it would be enough to add something like this below the cropping switch in ImageSizer if you want to implement this feature.


// setCropping(array(.3, .4)) // = centered at x=30% y=40% ;

if (is_array($this->cropping)) {
 $w1 = ($gdWidth - $targetWidth) * $this->cropping[0];
 $h1 = ($gdHeight - $targetHeight) * $this->cropping[1];
}

  • Like 1
Link to comment
Share on other sites

Thanks for the input interrobang, your solution works perfectly :)

Some code that is also needed:

ImageSizer.php line 533:

else if(is_array($cropping)) $cropping = array(round(min(1, max(0, $cropping[0])), 2), round(min(1, max(0, $cropping[1])), 2));
Pageimage.php line 198:

// crop name if custom center point is specified
if(is_array($crop)) $crop = 'c' . $crop[0] * 100 . '-' . $crop[1] * 100;

This will generate filenames like: "avontuur.704x165c30-40.jpg"

Link to comment
Share on other sites

Or maybe it's better to use numbers between 0 and 100 for consistency with the quality percentage option?

ImageSizer.php line 266:

if (is_array($this->cropping)) {
$w1 = ($gdWidth - $targetWidth) * ($this->cropping[0] / 100);
$h1 = ($gdHeight - $targetHeight) * ($this->cropping[1] / 100);
}
ImageSizer.php line 533:

else if(is_array($cropping)) $cropping = array(round(min(100, max(0, $cropping[0]))), round(min(100, max(0, $cropping[1]))));
Pageimage.php line 198:

// crop name if custom center point is specified
if(is_array($crop)) $crop = 'c' . $crop[0] . '-' . $crop[1];
Link to comment
Share on other sites

I've added the crop percentage stuff to the dev branch if you guys want to take a look and try it out. Admittedly, I don't totally understand all aspects of this or even how to accurately test it. I did also try to add crop by pixels support (which is more tangible to me) but am not getting the result I expect so kind of gave up on it. Let me know if you guys can figure out a way to make it work.

To crop by percentage, do it like this:

$img = $page->image->size(400, 300, "50%,30%"); 

To crop by pixels (not currently working quite right) do it like this:

$img = $page->image->size(400, 300, "100,100"); 

When doing testing or debugging, I recommend preceding your tests with a $page->image->removeVariations() call. I was testing with something like this:

$img = $page->image;
// remove any previously generated sizes, crops, etc.
$img->removeVariations(); 
// output original
echo "<p>$img->url<br /><img src='$img->url' /></p>";
// make crop
$img = $img->size(400, 300, "50%, 30%"); 
// test crop
echo "<p>$img->url<br /><img src='$img->url' /></p>";
Link to comment
Share on other sites

My extended Christmas holidays already started, so I can only test when I am back in the office in late January.

If noone else did it by then, I would be glad to help you to implement the pixel cropping.

EDIT:

I should note, that the current percentage cropping, is not really setting the center but its more like aligning the downscaled original into the target size:

0% 0% = NorthWest

50% 50% = center

100% 100% = SouthEast

I am not sure if this is the expected result. Should the cropping parameters represent the thumb center instead? What do you think?

  • Like 1
Link to comment
Share on other sites

Thanks Ryan! I've started working on a module to select the most important part in a image (with a draggable crosshair) and it's almost finished. Though I didn't get the expected result because (like interrobang is mentioning) the current percentage cropping is not setting the center.

The following code should fix that:


// @interrobang + @u-nikos
if (strpos($this->cropping[0], '%') === false) {
$pointX = (int) $this->cropping[0];
} else {
$pointX = $gdWidth * ((int) $this->cropping[0] / 100);
}

if (strpos($this->cropping[1], '%') === false) {
$pointY = (int) $this->cropping[1];
} else {
$pointY = $gdHeight * ((int) $this->cropping[1] / 100);
}

if ($pointX < $targetWidth / 2) {
$w1 = 0;
} else if ($pointX > ($gdWidth - $targetWidth / 2)) {
$w1 = $gdWidth - $targetWidth;
} else {
$w1 = $pointX - $targetWidth / 2;
}

if ($pointY < $targetHeight / 2) {
$h1 = 0;
} else if ($pointY > ($gdHeight - $targetHeight / 2)) {
$h1 = $gdHeight - $targetHeight;
} else {
$h1 = $pointY - $targetHeight / 2;
}

It seems like the module is working great with the above code :)

  • Like 1
Link to comment
Share on other sites

Yeah I've seen the Thumbnails module and I think it is great when u need to have full control over the crops. The module I'm developing works a little bit different:

When a user uploads an image, they can (optionally) select the most important part of the image. They only need to do it once per image, and after that, all generated crops will make sure the selected part is visible in the crop.

This saves time, because the user doesn't need to define (for example) 4 different crops per uploaded image. They just select the most important part of the image. And when you (as developer) need a new crop somewhere on the website, you wouldn't need to define a new crop for all existing images because it can be auto-generated according to the most important part.

I hope this clarify's the difference.

  • Like 2
Link to comment
Share on other sites

Thanks u-nikos, I have pushed these updates.

Do you have any idea how we might get the regular pixel cropping working (the non-percentage one)? Here's an example of how I was thinking it should work, and how it actually works.

Lets say I want a 120px square crop of the point indicated. I want 354px from the left and 87px from the top.

post-2-0-55023500-1356284067_thumb.jpg

So I use this API call:

$img = $img->size(120, 120, "354,87");

But the crop that I end up with is this:

post-2-0-08666800-1356284075.jpeg

What's happening is that it crops after the resize. And what we need is for it to crop without resize. I've fiddled with it quite a bit, moving the crop dimensions to the first imagecopyresampled call and such, but I'm far outside my area of expertise on this one. Probably need to move it to a whole new function in the class that just handles the crop, without resize. I will keep fiddling with it, but let me know if you have any thoughts or solutions here.

Link to comment
Share on other sites

In that case it would give you flat black for the overlapping area. But u-nikos added some code that keeps it in bounds, otherwise that thumbnail I posted would show black on the right side of it at least. The way I see it, percentages are useful for targeting an area when you don't necessarily know the dimensions of the image. Whereas specifying pixels is useful when you do know the dimensions of the original image.

Link to comment
Share on other sites

Ah the pixel coordinates were indeed not working correctly, the following code should fix that:


if(strpos($this->cropping[0], '%') === false) $pointX = $gdWidth * ((int) $this->cropping[0] / $this->image['width']);
else $pointX = $gdWidth * ((int) $this->cropping[0] / 100);

if(strpos($this->cropping[1], '%') === false) $pointY = $gdHeight * ((int) $this->cropping[1] / $this->image['height']);
else $pointY = $gdHeight * ((int) $this->cropping[1] / 100);

Though if you want to specify a crop without resizing, it should be a different function in the Pageimage class or an extra option for the size function ("resize" => false or something?).

I've created a GitHub repository for the FieldtypeFocusPoint module I'm developing. It's my first ProcessWire module so I hope I've done everything correctly.

Maybe u guys can take a look at it? All suggestions are welcome :)

https://github.com/u...FocusPointImage

Usage: $page->image->sizeWithFocusPointCropping(704, 165);

  • Like 4
Link to comment
Share on other sites

  • 10 months later...
  • 2 years later...

I hate bumping really old topics, but since I've recently been looking at responsive images with regard to a central focal point, and this was the only topic that came up in a search (that I could tell was directly related), I thought I'd chime in and mention that there's a jQuery resource for defining a focal point when using various dimension based images in a responsive image layout.

https://github.com/jonom/jquery-focuspoint

I haven't looked closely enough (yet) on how best to possibly integrate this without requiring custom code in the templates, but it looks like a similar solution to the PHP-based solution offered here (and possibly more efficient overall). Below is an example of the script in action:

http://jonom.github.io/jquery-focuspoint/demos/grid/lizard.html

My buddy, the developer behind Statamic, built this (but customized) in to his CMS' control panel and his demo of it was awesome. It made me jealous that PW didn't have it, so the first step I did was to figure out which script he based it off of. So far I've only completed Step 1. ;)

  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...