user2192094
user2192094

Reputation: 337

PHP - How do I convert a rectangle image to a square image?

How do I change a rectangular image to a square-shaped avatar in php, such that no matter what is the resolution of the uploaded image, it is able to resize to a centralized 42 x 42 pixel avatar. This is the php code I am using. Anyone can advise.

<?php 
//Name you want to save your file as
$save = 'myfile1.jpg';

$file = 'original1.jpg'; 
echo "Creating file: $save"; 
$size = 0.45; 
header('Content-type: image/jpeg') ; 
list($width, $height) = getimagesize($file) ; 
$modwidth = $width * $size; 
$modheight = $height * $size; 
$tn = imagecreatetruecolor($modwidth, $modheight) ; 
$image = imagecreatefromjpeg($file) ; 
imagecopyresampled($tn, $image, 0, 0, 0, 0, $modwidth, $modheight, $width, $height) ; 

// Here we are saving the .jpg, you can make this gif or png if you want
//the file name is set above, and the quality is set to 100%
imagejpeg($tn, $save, 100) ; 
?> 

Upvotes: 6

Views: 12574

Answers (3)

Alex Khimich
Alex Khimich

Reputation: 828

Here is working snippet from my animal adoption project that cuts the middle of the image (horizontal or vertical) and makes it square, without adding white fields to the destination image:

/**
 * Cuts a square image from the middle of rectangular image
 * Requires: mbstring, exif, gd built-in extensions uncommented in php.ini
 * Resamples rect img to square img and converts jpeg to wepp image
 *
 */
function squarify($src_file,$dst_file,$square_side=600,$quality=90) {

    // Deals only with jpeg
    if(exif_imagetype($src_file) != IMAGETYPE_JPEG) { return 'src_not_jpeg'; }
    
    // Convert old file into img
    $src_img=imagecreatefromjpeg($src_file);
    $src_side_x=imageSX($src_img);
    $src_side_y=imageSY($src_img);
    
    // Do not magnify image if its sides less than desired square side,
    // issue false if image size is too small
    // Remove, if you want src image be magnified
    // if($src_side_x < $square_side || $src_side_y < $square_side) { 
    //    return 'src_too_small'; 
    // }
    
    // Create new image
    $dst_image=imagecreatetruecolor($square_side,$square_side);
    
    // The image is square, just issue 
    // resampled image with adjusted square sides and image quality
    if($src_side_x==$src_side_y) {
        
        imagecopyresampled(
           $dst_image,
           $src_img,
           0,
           0,
           0,
           0,
           $square_side,
           $square_side,
           $src_side_x,
           $src_side_x
        );

    // The image is vertical, use x side as initial square side
    } elseif($src_side_x<$src_side_y) {
        
        $x1=0;
        $y1=round(($src_side_y-$src_side_x)/2);
        
         
        imagecopyresampled(
           $dst_image,
           $src_img,
           0,
           0,
           $x1,
           $y1,
           $square_side,
           $square_side,
           $src_side_x,
           $src_side_x
       );

    // The image is horizontal, use y side as initial square side
    } else {

        $x1=round(($src_side_x-$src_side_y)/2);
        $y1=0;
        
        imagecopyresampled(
           $dst_image,
           $src_img,
           0,
           0,
           $x1,
           $y1,
           $square_side,
           $square_side,
           $src_side_y,
           $src_side_y
        );
        
    }
    
    // Save it to the filesystem
    // imagewebp($dst_image,$dst_file,$quality);
    
    // Or show it in the browser, 
    // dont forget about header('Content-type: image/webp')
    imagewebp($dst_image,$dst_file,$quality);

}

And you can call this function on existing image:

if(!extension_loaded('mbstring')) { die('Err: mbstring extension not loaded.'); }
if(!extension_loaded('exif')) { die('Err: exif extension not loaded.'); }
if(!extension_loaded('gd')) { die('Err: gd extension not loaded.'); }

header('Content-type: image/webp');
squarify('images/src.jpg','images/res.webp',300,80);

Original image

After cutting the middle and resizing

Upvotes: 1

Edu
Edu

Reputation: 51

I don't know if someone was looking for this, but I needed to have a 600 x 600 squared image.

The source could be any rectangular image and I needed to mantain proportion of the original image and center the original rectangular image in a 600 x 600 squared white image.

Here it is

  • src_file: URL of Source Image
  • destination_file: Path where the destination file will be saved.
  • square_dimensions (pixels). I needed 600, but could be any value.
  • jpeg_quality: Quality (0, 100) . I used default 90

    function square_thumbnail_with_proportion($src_file,$destination_file,$square_dimensions,$jpeg_quality=90)
    {
        // Step one: Rezise with proportion the src_file *** I found this in many places.
    
        $src_img=imagecreatefromjpeg($src_file);
    
        $old_x=imageSX($src_img);
        $old_y=imageSY($src_img);
    
        $ratio1=$old_x/$square_dimensions;
        $ratio2=$old_y/$square_dimensions;
    
        if($ratio1>$ratio2)
        {
            $thumb_w=$square_dimensions;
            $thumb_h=$old_y/$ratio1;
        }
        else    
        {
            $thumb_h=$square_dimensions;
            $thumb_w=$old_x/$ratio2;
        }
    
        // we create a new image with the new dimmensions
        $smaller_image_with_proportions=ImageCreateTrueColor($thumb_w,$thumb_h);
    
        // resize the big image to the new created one
        imagecopyresampled($smaller_image_with_proportions,$src_img,0,0,0,0,$thumb_w,$thumb_h,$old_x,$old_y); 
    
        // *** End of Step one ***
    
        // Step Two (this is new): "Copy and Paste" the $smaller_image_with_proportions in the center of a white image of the desired square dimensions
    
        // Create image of $square_dimensions x $square_dimensions in white color (white background)
        $final_image = imagecreatetruecolor($square_dimensions, $square_dimensions);
        $bg = imagecolorallocate ( $final_image, 255, 255, 255 );
        imagefilledrectangle($final_image,0,0,$square_dimensions,$square_dimensions,$bg);
    
        // need to center the small image in the squared new white image
        if($thumb_w>$thumb_h)
        {
            // more width than height we have to center height
            $dst_x=0;
            $dst_y=($square_dimensions-$thumb_h)/2;
        }
        elseif($thumb_h>$thumb_w)
        {
            // more height than width we have to center width
            $dst_x=($square_dimensions-$thumb_w)/2;
            $dst_y=0;
    
        }
        else
        {
            $dst_x=0;
            $dst_y=0;
        }
    
        $src_x=0; // we copy the src image complete
        $src_y=0; // we copy the src image complete
    
        $src_w=$thumb_w; // we copy the src image complete
        $src_h=$thumb_h; // we copy the src image complete
    
        $pct=100; // 100% over the white color ... here you can use transparency. 100 is no transparency.
    
        imagecopymerge($final_image,$smaller_image_with_proportions,$dst_x,$dst_y,$src_x,$src_y,$src_w,$src_h,$pct);
    
        imagejpeg($final_image,$destination_file,$jpeg_quality);
    
        // destroy aux images (free memory)
        imagedestroy($src_img); 
        imagedestroy($smaller_image_with_proportions);
        imagedestroy($final_image);
    }
    

Upvotes: 5

Shomz
Shomz

Reputation: 37711

First you need to be tell where is the central square in a rectangle with dimensions $x and $y.

// horizontal rectangle
if ($x > $y) {
    $square = $y;              // $square: square side length
    $offsetX = ($x - $y) / 2;  // x offset based on the rectangle
    $offsetY = 0;              // y offset based on the rectangle
}
// vertical rectangle
elseif ($y > $x) {
    $square = $x;
    $offsetX = 0;
    $offsetY = ($y - $x) / 2;
}
// it's already a square
else {
    $square = $x;
    $offsetX = $offsetY = 0;
}

Now we can build a square from it, just need to resize it to 42x42. Something like this should work:

list($x, $y) = getimagesize($file);

// code snippet from above goes here
// so we get the square side and the offsets

$endSize = 42;
$tn = imagecreatetruecolor($endSize, $endSize);
imagecopyresampled($tn, $image, 0, 0, $offsetX, $offsetY, $endSize, $endSize, $square, $square);

So, if we have a rectangular image 100x80, the code will figure out that the big square size is 80, x offset is 10, y offset is 0. Roughly, it looks like this:

    100
-----------
|         |
|         | 80
|         |
-----------

     |
     V

    80
 ---------               42
 |       |             -----
 |       | 80   --->   |   | 42
 |       |             -----
 ---------

After we crop the big square from the original rectangle, we just shrink it to the end size, which is 42 in your case.


Just tested and works perfectly, make sure you remove the echo line if you plan to output the image into the browser (combined with the header).

Upvotes: 9

Related Questions