GROVER.
GROVER.

Reputation: 4378

Crop Uploaded Image To 1:1 Ratio PHP

I have my own PHP function allowing users to update their profile image.

It all works fine, however, I am having a problem where users can upload any size image they want; i.e: 564 x 346.

I do not want this to happen. I would like the image that they select to upload to be cropped to a 1:1 ratio and centred; i.e: it goes from 564 x 346 to 346 x 346 and centres to the middle of the image.

None of the scripts that I have found seem to work for my site (at least the way I want them to).

This is the code I am currently using to update their avatar. It consists of checking if they have a correct file extension & if the image is less than 256kb in size:

    $ext = array('jpg', 'jpeg', 'png');
    $file       = $_FILES['avatar']['name'];
    $fileext    = strtolower(end(explode('.', $file)));
    $filetmp    = $_FILES['avatar']['tmp_name'];

    if(!in_array($fileext, $ext)){
        $errors[] = 'Please select a valid file type. (JPG, JPEG or PNG)';  }
    if($_FILES['avatar']['size'] > 256000){
        $errors[] = 'Avatars cannot exceed a 256kb file size.';
    }

    if(empty($errors)){
        updateAvatar($conn, $username, $filetmp, $fileext);
    } else if(!empty($errors)){
        echo output_errors($errors);
    }
    if(isset($_SESSION['updateAvat'])){
        flash('You have successfully updated your avatar.');
        unset($_SESSION['updateAvat']);
    }

This is the updateAvatar() function that I have made and is called on line 13:

function updateAvatar($conn, $username, $filetmp, $fileext){
    $file = md5(microtime() . $filetmp) . '.' . $fileext;
    $filepth = './data/user_data/img/udid/prof/' . $file;
    move_uploaded_file($filetmp, $filepth);
    if(mysqli_query($conn, "UPDATE users SET profile = '$file' WHERE username = '$username'")){
        $_SESSION['updateAvat'] = md5(microtime() . $filetmp);
    } else {
        $errors[] = 'There was a problem updating your avatar. Please try again.';
    }
}

However, this is not enough and does not allow my users profile page to work or look the way it should, I am going for something along the lines of how Google or Twitter do their avatar's.

All help is appreciated. Cheers.

Upvotes: 0

Views: 2085

Answers (2)

NYG
NYG

Reputation: 1817

There is imagecrop() function in php:

$tmpfile = $_FILES['avatar']['tmp_name'];

switch ($fileext) {
 case 'jpg':
 case 'jpeg':
   $image = imagecreatefromjpeg($tmpfile);
   break;
 case 'png':
   $image = imagecreatefrompng($tmpfile);
   break;
 default:
   die("wtf is this extension??");
}

list($w, $h) = getimagesize($imgfile);
// get width $w and height $h for the image

if ($w < $h) // then keep the width and scale the height
 $image = imagecrop($image, array(
                              "x" => 0,
                              "y" => ($h - $w) / 2,
                              "width" => $w,
                              "height" => $w
                              ));
else if ($h < $w) // then keep the height and scale the width
 $image = imagecrop($image, array(
                              "x" => ($w - $h) / 2,
                              "y" => 0,
                              "width" => $h,
                              "height" => $h
                              ));

I haven't tried this code but I'm quite sure it's right. Try it and tell me if it doesn't work.

UPDATE: Then you can save the resource $image with imagejpeg() or imagepng() to save the images with the same extensions so you won't have problems with the database:

imagejpeg($image, "/path/to/your/image.jpg");

Upvotes: 4

Martin
Martin

Reputation: 22760

This is an explanation of how the process works, this is not a copy and paste code but a description of the logic processes you need to understand to resize images in PHP

You want to be using PHP imagecopyresampled to take the original image and then work out mathematically the margins to make it a square and then resize that square.

Process:

  • Uploaded image is checked is a genuine image and genuine filetype.

  • Using imagecreatefromjpeg (or similar ones for PNG etc.) you can import the uploaded image file resource.

  • Using getimagesize you can find the dimensions, you can then find the aspect ratio of the image.

  • If the aspect ratio is > 1 then width is larger than height so you then need to assume a square the same size as height (as it's the smaller value). For example:

.

 Width: 450
 Height: 300
 Ratio = 450/300 = 3/2 = 1.5 = >1
  • If the aspect ratio is <1 then the height is larger than the width.

  • So you want a square that is 300x300 so you need to cut off the excess 150 from the width. This is called the Margin, and to centre the image you need to cut off half of the margin from each side so:

.

$fullMargin = (width- height) 
$margin = $fullMargin/2 
  • Just before resizing and saving the new image, a new image resource should be generated:

.

$max_width = $max_height = 256;
$smallestDimensionValue = $originalHeight //(in this example);
$newImage = imagecreatetruecolor($max_width,$max_height);
$sourceHeight = $originalHeight;
$sourceWidth = $originalWidth - $fullMargin;
  • Finally, Image copy and resample and the output should be as intended:

.

 imagecopyresampled($nwImage, $sourceImage, 0,0,$margin,0,$max_width,$max_height,$sourceWidth,$sourceHeight); 

  • PHP scales the image in the imagecopyresampled automatically, but to understand it, Once you've established the Margin size for the full size image you then have to multiply the margin by the same value as the width and the height to scale the overall image to the appropriate size.

Say for example you want the avatar to have a maximum size of 256px then:

 maximum_allowed_width /  original_width = scale_factor. 

So for the example above this is:

256 / 450 = 0.56888888

This is the value the margin value defined above, as well as the height and width of the destination image, is multiplied by.

Upvotes: 0

Related Questions