PHP Image cropping to square - php

I was using the following PHP script to create square thumbnails which I got here http://www.abeautifulsite.net/blog/2009/08/cropping-an-image-to-make-square-thumbnails-in-php/
I was able to integrate this into my image upload script, which uploads full sized image and after that takes the uploaded image and creates a thumbnail from that.
The problem is the author of the script said, it will crop landscape and portrait images without problem. It crops landscape images perfectly, but as it faces portrait image, the output thumbnail will not be cropped, but it appears scaled down to fit the given square thumbnail height and the emtpy space on the sides will be filled with black color.
I know there is a way to fix this, but as I am relatively new to PHP I am not able to solve it.
Can someome with real experience in PHP fix this?
Thank you in advance!
The script is here:
$
function square_crop($src_image, $dest_image, $thumb_size = 64, $jpg_quality = 90) {
// Get dimensions of existing image
$image = getimagesize($src_image);
// Check for valid dimensions
if( $image[0] <= 0 || $image[1] <= 0 ) return false;
// Determine format from MIME-Type
$image['format'] = strtolower(preg_replace('/^.*?\//', '', $image['mime']));
// Import image
switch( $image['format'] ) {
case 'jpg':
case 'jpeg':
$image_data = imagecreatefromjpeg($src_image);
break;
case 'png':
$image_data = imagecreatefrompng($src_image);
break;
case 'gif':
$image_data = imagecreatefromgif($src_image);
break;
default:
// Unsupported format
return false;
break;
}
// Verify import
if( $image_data == false ) return false;
// Calculate measurements
if( $image[0] & $image[1] ) {
// For landscape images
$x_offset = ($image[0] - $image[1]) / 2;
$y_offset = 0;
$square_size = $image[0] - ($x_offset * 2);
} else {
// For portrait and square images
$x_offset = 0;
$y_offset = ($image[1] - $image[0]) / 2;
$square_size = $image[1] - ($y_offset * 2);
}
// Resize and crop
$canvas = imagecreatetruecolor($thumb_size, $thumb_size);
if( imagecopyresampled(
$canvas,
$image_data,
0,
0,
$x_offset,
$y_offset,
$thumb_size,
$thumb_size,
$square_size,
$square_size
)) {
// Create thumbnail
switch( strtolower(preg_replace('/^.*\./', '', $dest_image)) ) {
case 'jpg':
case 'jpeg':
return imagejpeg($canvas, $dest_image, $jpg_quality);
break;
case 'png':
return imagepng($canvas, $dest_image);
break;
case 'gif':
return imagegif($canvas, $dest_image);
break;
default:
// Unsupported format
return false;
break;
}
} else {
return false;
}
}
?>
And I call it like this - square_crop('source_image', 'destination_image', 65);
You can see the result here http://imageshack.us/photo/my-images/717/imgfl.png/
It happens only with portrait images, landscape images are cropped in a way that it fills the whole square.

For cropping only, replace the imagecopyresampled() function with imagecopy().
The resampled performs an appropriate stretching or shrinking of the image if the source and destination coordinates and width and heights differ. imagecopy() doesn't.

you should add an image ration inside the if() statement, so it will understand if it's portrait or landscape.
change the line below
// Calculate measurements
if( $image[0] > $image[1] ) {

Related

Black bar on picture after resize, rotate and crop

On a PWA, full legacy/handmade PHP/JS (jquery), i'm trying to avoid all the bug and problems with picture.
I've solved the famous bug where picture are 90° rotate
I've dicreased the weight with the "quality" parameter in imagejpeg
And i'm trying to resize it with no less than 800px for width and no more less 600px for height. Like, 810x750 it's okay for me, 1500x620 too, but no 500x450.
1 and 2 work fine. The third point is bit complicated it "crop" my picture with false position and there is this famous black bar on right.
I've read a lot of articles on it with sometimes solutions, but they are always "isolated" scripts, intended for the black bar. I want to solve my problem by keeping this big function which makes resize/rotate/decrease weight.
I don't want a copy/thumbnail, just the original with correct size.
Here's my code
function compressImage($source, $destination, $quality) {
error_log('====================');
error_log('Source : '.$source);
error_log('Destination : '.$destination);
error_log('Qualité : '.$quality);
$imgInfo = getimagesize($source);
$mime = $imgInfo['mime'];
// EXTRACT INFO
$newPic = imagecreatefromstring(file_get_contents($source));
$exif = exif_read_data($source);
$rotation = 0;
if(!empty($exif['Orientation'])) {
error_log('Orientation : '.$exif['Orientation']);
// CHECK IF PHP DID WRONG ROTATION
switch($exif['Orientation']) {
case 8:
$newPic = imagerotate($newPic, 90, 0);
break;
case 3:
$newPic = imagerotate($newPic, 180, 0);
break;
case 6:
$newPic = imagerotate($newPic, -90 ,0);
break;
}
$rotation = 1;
time_nanosleep(0, 500000000);
}
$w = 800;
$h = 600;
list($width, $height) = $imgInfo;
error_log('Actual width : '.$width);
error_log('Actual height : '.$height);
$r = $width / $height;
if($w/$h > $r) {
$newWidth = $h*$r;
$newHeight = $h;
} else {
$newHeight = $w/$r;
$newWidth = $w;
}
// CALCULATE NEW SIZE (MAYBE HERE FOR MISTAKE ?)
error_log('New width : '.$newWidth);
error_log('New height : '.$newHeight);
$thumb = imagecreatetruecolor($newWidth, $newHeight);
if($rotation == 1) {
error_log('2nd MIME : '.$mime);
switch($mime) {
case 'jpg':
error_log('JPG');
$newPic = imagejpeg($image, $destination, $quality);
break;
case 'jpeg':
error_log('JPEG');
$newPic = imagejpeg($image, $destination, $quality);
break;
}
time_nanosleep(0, 500000000);
}
imagecopyresized($thumb, $newPic, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
$newPic = imagejpeg($thumb, $destination, $quality);
move_uploaded_file($newPic, $destination);
}
Here's a complete example :
Randomly wanted 9000x12000 to be 800x600 but for example if someone sends a picture of 1685x1235 (random) i want 819x600. (if we took the width as a reference in this specific case instead it would not be good because we would have 800x586 (and therefore 586 < 600)
Edit : after two weeks of tests i can't afford what i want, thanks to everyone who have solution to resize, prevent rotate bug and crop in one script.

How to get the orientation of an image in php

I am doing a project in core php. When i upload images which taken from mobile phone , it will display as inverted images. i am using exif_read_data function to get the orientation of image.and according to its value rotate the image. But i didn't get the orientation of all images.Is there any method to get the orientation of image?
This is the code
$exif_data = #exif_read_data($tmp_name);
if(!empty($exif_data['Orientation'])) {
switch($exif_data['Orientation']) {
case 8:
$image_p = imagerotate($image_p,90,0);
break;
case 3:
$image_p = imagerotate($image_p,180,0);
break;
case 6:
$image_p = imagerotate($image_p,-90,0);
break;
}
}
Well, you can check for the width and height of the image:
list($width, $height) = getimagesize('your-image.jpg'); // or other image ext
if ( $width > $height ) {
// Landscape image
}
elseif ( $width < $height ) {
// Portrait
}
else {
// Square
}
PS:
EXIF headers tend to be present in JPEG/TIFF images .. See here.
Resource for getimagesize() here.

Crop a png image with PHP, remove empty transparency

I'm currently trying to work with pictures and PHP, thanks to GD functions.
Now I would like to modify the size of PNG pictures. Here is an example of a PNG I'd like to resize :
The dotted line represent the border of the PNG, the background is transparent, and I only have a star lost on the middle of a large space. I'd like to crop this star, to get a simple square of the star (even if the new background becomes blank, It doesn't matter).
How could I do something like that efficiently ? I thought about doing a loop checking every pixel of the picture.. Trying to find where the image is, to finally crop with a little margin based on the minimum x / maximum X and minimum y / maximum y values, but If I start working with hundreds of pictures, It would be really long.
EDIT :
<?php
$file = "./crop.png";
$ext = pathinfo($file, PATHINFO_EXTENSION);
$image;
switch ($ext){
case 'png':
$image = imagecreatefrompng($file);
break;
case 'jpeg':
case 'jpg':
$image = imagecreatefromjpeg($file);
break;
case 'gif':
$image = imagecreatefromgif($file);
break;
}
$cropped = imagecropauto($image, IMG_CROP_DEFAULT);
if ($cropped !== false) { // in case a new image resource was returned
echo "=> Cropping needed\n";
imagedestroy($image); // we destroy the original image
$image = $cropped; // and assign the cropped image to $im
}
imagepng($image, "./cropped.png");
imagedestroy($image);
If you read and follow the php php-gd documentation, you'll find a function called imagecropauto which does exactly what you want, it crops the alpha channel of the image.
Crop an PNG image with alpha channel
$im = imagecreatefrompng("./star-with-alpha.png");
$cropped = imagecropauto($im, IMG_CROP_DEFAULT);
if ($cropped !== false) { // in case a new image resource was returned
imagedestroy($im); // we destroy the original image
$im = $cropped; // and assign the cropped image to $im
}
imagepng($im, "./star-with-alpha-crop.png");
imagedestroy($im);
You can try it dirrectly to a php page using this code:
<body>
<img src="star-with-alpha.png">
<?php
$im = imagecreatefrompng("./star-with-alpha.png");
$cropped = imagecropauto($im, IMG_CROP_DEFAULT);
if ($cropped !== false) { // in case a new image resource was returned
imagedestroy($im); // we destroy the original image
$im = $cropped; // and assign the cropped image to $im
}
imagepng($im, "./star-with-alpha-crop.png");
imagedestroy($im);
?>
<img src="star-with-alpha-crop.png">
</body>
The result
http://zikro.gr/dbg/php/crop-png/
[This is for ubuntu 12]
The only problem with the imagecropauto is that it works only on Mac & Windows.
And since most of the servers today use ubuntu/debain - this function is of no use.
Instead use Imagick() for this.
Here is a sample code I wrote which does exactly this:
//Add background transmparent
$background = 'none';
$image = new Imagick($path);
$image->trimImage(0);
//add transparent border
//border add start
/** Set border format **/
$borderWidth = 20;
$borderColor = 'none';
$borderPadding = 10;
$imageWidth = $image->getImageWidth() + ( 2 * ( $borderWidth +
$borderPadding ) );
$imageHeight = $image->getImageHeight() + ( 2 * ( $borderWidth +
$borderPadding ) );
Create Imagick object for final image with border
$imageWithBorder = new Imagick();
// Set image canvas
$imageWithBorder->newImage( $imageWidth, $imageHeight, new ImagickPixel(
'none' ));
// Create ImagickDraw object to draw border
$border = new ImagickDraw();
// Set fill color to transparent
$border->setFillColor( 'none' );
// Set border format
$border->setStrokeColor( new ImagickPixel( $borderColor ) );
$border->setStrokeWidth( $borderWidth );
$border->setStrokeAntialias( false );
Draw border
$border->rectangle(
$borderWidth / 2 - 1,
$borderWidth / 2 - 1,
$imageWidth - ( ($borderWidth / 2) ),
$imageHeight - ( ($borderWidth / 2) )
);
// Apply drawed border to final image
$imageWithBorder->drawImage( $border );
$imageWithBorder->setImageFormat('png');
Save Image
// Put source image to final image
$imageWithBorder->compositeImage(
$image, Imagick::COMPOSITE_DEFAULT,
$borderWidth + $borderPadding,
$borderWidth + $borderPadding
);
$imageWithBorder->writeImage($path);
Recenter and fit to original image height and width
$imageWithBorder->scaleImage(FINAL_WIDTH, FINAL_HEIGHT, true);
$imageWithBorder->setImageBackgroundColor($background);
$w = $imageWithBorder->getImageWidth();
$h = $imageWithBorder->getImageHeight();
$imageWithBorder->extentImage(FINAL_WIDTH, FINAL_HEIGHT, ($w -
FINAL_WIDTH) / 2, ($h - FINAL_HEIGHT)/ 2);
$imageWithBorder->writeImage($path);
Hope it helps.
Cheers!

image resize in my wordpress plugin using php

I am trying to resize an image in my wordpress plugin using php, But they don't work. How can I resize image as propotion wise using php?
anyone know if that's possible?
Thanks
You can use wordpress built-in resize function:
<?php image_resize( $file, $max_w, $max_h, $crop, $suffix, $dest_path, $jpeg_quality ); ?>
You can find more details in here: http://codex.wordpress.org/Function_Reference/image_resize
This function takes the imagePath as parameter and the size to which you want it to resize the image.This will resize image with proportion constraints
suppose size = 300
then there will be three scenarios
1) if image's height is greater than width then its height will be 300
2) if width is greater then its width will be 300
3) if image is of ratio 1:1 then both its height and width will be of size 300
function resizeImage($imagePath,$size)
{
$sizeData = getimagesize($imagePath);
$width = $sizeData[0];
$height = $sizeData[1];
# Loading image to memory according to type
switch ( $sizeData[2] ) {
case IMAGETYPE_GIF: $src = imagecreatefromgif($imagePath); break;
case IMAGETYPE_JPEG: $src = imagecreatefromjpeg($imagePath); break;
case IMAGETYPE_PNG: $src = imagecreatefrompng($imagePath); break;
default: return false;
}
if(!$src)
{
return false;
}
if($height >= $width)
{
$newheight = $size;
$newwidth = ($newheight*$width)/$height;
}
else
{
$newwidth = $size;
$newheight = ($height/$width)*$newwidth;
}
$tmp = imagecreatetruecolor($newwidth,$newheight);
imagecopyresampled($tmp,$src,0,0,0,0,$newwidth,$newheight,$width,$height);
# Writing image according to type to the output destination
switch ( $sizeData[2] ) {
case IMAGETYPE_GIF: imagegif($tmp, $imagePath); break;
case IMAGETYPE_JPEG: imagejpeg($tmp, $imagePath, 100); break;
case IMAGETYPE_PNG: imagepng($tmp, $imagePath, 9); break;
default: return false;
}
imagedestroy($src);
imagedestroy($tmp);
return true;
}

PHP watermarking

i am using this code to create watermark.
$image = '1.jpg';
$overlay = 'stamp.png';
$opacity = "20";
if (!file_exists($image)) {
die("Image does not exist.");
}
// Set offset from bottom-right corner
$w_offset = 0;
$h_offset = 100;
$extension = strtolower(substr($image, strrpos($image, ".") + 1));
// Load image from file
switch ($extension)
{
case 'jpg':
$background = imagecreatefromjpeg($image);
break;
case 'jpeg':
$background = imagecreatefromjpeg($image);
break;
case 'png':
$background = imagecreatefrompng($image);
break;
case 'gif':
$background = imagecreatefromgif($image);
break;
default:
die("Image is of unsupported type.");
}
// Find base image size
$swidth = imagesx($background);
$sheight = imagesy($background);
// Turn on alpha blending
imagealphablending($background, true);
// Create overlay image
$overlay = imagecreatefrompng($overlay);
// Get the size of overlay
$owidth = imagesx($overlay);
$oheight = imagesy($overlay);
// Overlay watermark
imagecopymerge($background, $overlay, $swidth - $owidth - $w_offset, $sheight - $oheight - $h_offset, 0, 0, $owidth, $oheight, $opacity);
imagejpeg($background,$image);
// Destroy the images
imagedestroy($background);
imagedestroy($overlay);
the png image contains a text with all other region as transparent.
but when i execute this code , it applys the png over jpg, but the transparecy is not maintained of the png. it shows in a box.
how can i acheive that . ie if a png contains transaparent part , it should show the below image in that part....?
replacing imagecopymerge with imagecopy solved the issue. here is the new code
function watermark($image){
$overlay = '../../../photos/photosets/stamp.png';
$opacity = "20";
if (!file_exists($image)) {
die("Image does not exist.");
}
// Set offset from bottom-right corner
$w_offset = 0;
$h_offset = 100;
$extension = strtolower(substr($image, strrpos($image, ".") + 1));
// Load image from file
switch ($extension)
{
case 'jpg':
$background = imagecreatefromjpeg($image);
break;
case 'jpeg':
$background = imagecreatefromjpeg($image);
break;
case 'png':
$background = imagecreatefrompng($image);
break;
case 'gif':
$background = imagecreatefromgif($image);
break;
default:
die("Image is of unsupported type.");
}
// Find base image size
$swidth = imagesx($background);
$sheight = imagesy($background);
// Turn on alpha blending
imagealphablending($background, true);
// Create overlay image
//$overlay = imagecreatefrompng($overlay);
// Get the size of overlay
$owidth = imagesx($overlay);
$oheight = imagesy($overlay);
$photo = imagecreatefromjpeg($image);
$watermark = imagecreatefrompng($overlay);
// This is the key. Without ImageAlphaBlending on, the PNG won't render correctly.
imagealphablending($photo, true);
// Copy the watermark onto the master, $offset px from the bottom right corner.
$offset = 10;
imagecopy($photo, $watermark, imagesx($photo) - imagesx($watermark) - $offset, imagesy($photo) - imagesy($watermark) - $offset, 0, 0, imagesx($watermark), imagesy($watermark));
// Output to the browser
header("Content-Type: image/jpeg");
imagejpeg($photo,$image);
// Overlay watermark
// Destroy the images
imagedestroy($background);
imagedestroy($overlay);
}
The jpg format doesn't support transparency, so conceptually you will have to:
grab the pixels from the larger image (the jpeg) and put them into a buffer
grab the non-transparent pixels from the smaller image (the watermark) and move them into that buffer, applying the alpha along the way
You probably want to let a library do this. I like ImageMagick, especially since it's built in to php... here's an example of how to use it for this purpose from PHP:
// Let's read the images.
$glasses = new Imagick();
if (FALSE === $glasses->readImage($dir . '/glasses.png'))
{
throw new Exception();
}
$face = new Imagick();
if (FALSE === $face->readImage($dir . '/face.jpg'))
{
throw new Exception();
}
// Let's put the glasses on (10 pixels from left, 20 pixels from top of face).
$face->compositeImage($glasses, Imagick::COMPOSITE_DEFAULT, 10, 20);
And here's the link to the PHP manual page for ImageMagick::compositeImage (from which the above example came).
Have you tried using imagecopyresampled()?
http://php.net/manual/en/function.imagecopyresampled.php

Categories