Upload and Resize Image in PHP

In this post we will create an image class with various methods to resize uploaded images in PHP using  PHP GD library in this class.

Upload and Resize Image in PHP

Resizing images in PHP can be helpful in terms of saving disk space and faster page load time. For example if you have a huge number of images all of unnecessarily in large sizes can take more disk space and may result in slower page load time. We will walk you through simple steps to understand image resize in PHP functionality using an image class and resize images in PHP to save multiple sizes of one image. This post demonstrates how to upload and resize an image in PHP with following simple steps:

  1. Upload an image via HTML form.
  2. Open an image class object and resize it to a desired size. 
  3. Save the resized image at the end.

To achieve this we will create following files:

  • image.php: An image class with different methods which will resize image and save it.
  • index.php: which will be used for HTML form to upload an image.
  • style.css: Contains all the CSS styles for HTML page and form.

Resize Image in PHP with Image Class

We create an image class to resize an image in PHP with required methods to resize and save image. This class will use PHP's GD Library function for image manipulations. The definition of image class is as below:

  • $image: Will hold the original image object.
  • $extension: The extension of original image.
  • $image_width: Width of original image.
  • $image_height: Height of original image.
  • $new_image: The new resized image object, initially its set to original image.
  • $new_width: Width of new/resized image.
  • $new_height: Height of new/resized image.

The main methods used in image class are its constructor, resize_image, save_image and show_image. Other methods are private methods used as supporting methods for above mentioned public methods.

  • __construct: Its the constructor method which called when the object is initialized. We first get the width and height of uploaded image, then its extension and assign them to relevant class properties.
  • resize_image: The method that resizes the uploaded image and assigns it to relevant class property. It accepts three parameters, $new_width,  $new_height, $cropped (if image should be cropped or not). We use a switch statement for conditional check. It checks if uploaded image width is greater than its height (Landscape image) then it keeps the new width and calculates the new height for image to maintain the aspect ratio.  If uploaded image height is greater than its width (Portrait image) then we keep the new height and calculate new width to maintain the aspect ratio. Default case is image is square then use new width and new height (No need to calculate width or height). Then we create new image of new width and new height, We use imagecopyresampled() to copy the original image to new image object.
  • save_image: This method saves the image assigned to $new_image property. It accepts two parameters, $path (where we save the new image) and $quality (the quality of new image).
  • show_image: This method will only print out the image without saving new image.
  • fill_transparent: This method will fill transparent background to given image.
  • get_image_width_ratio: Calculates image width maintaining the aspect ratio. Accept two parameters, $width and $height.
  • get_image_height_ratio: Calculates image height maintaining the aspect ratio. It accepts two parameters, $width and $height.

We used GD Library function in class methods, for detailed usage of these functions refer to GD and Image Functions

image.php

<?php
class image{

private GdImage $image;
private string $extension;
private int $image_width;
private int $image_height;
private GdImage $new_image;
private bool $is_transparent;

/**
* Constructs the current image class and sets local properties
* @param string $image
*/
function __construct(string $image)
{
list($width, $height, $type) = getimagesize($image);

$this->extension = image_type_to_extension($type, false);
$this->image = imagecreatefromstring(file_get_contents($image));

$this->image_width = $width;
$this->image_height = $height;

// Check transparency in constructor to avoid repeated loops
$this->is_transparent = $this->has_transparency($this->image);

// Initially set new image to received image
$this->new_image = $this->image;
$this->fill_transparent($this->new_image);
}

/**
* Resizes the current image for given width and height, Also crops image depending on passed parameter
* @param int $width
* @param int $height
* @param bool $crop
* @return void
*/
public function resize_image(int $width, int $height, bool $crop = false): void
{
switch(true){
// If uploaded image is landscape keep new width and calculate new height
case ($this->image_width > $this->image_height):
$new_width = $width;
$new_height = $this->get_image_height_ratio($width);
// If crop is true set height to new height and calculate width again.
if($new_height < $height && $crop){
$new_height = $height;
$new_width = $this->get_image_width_ratio($height);
}
break;
// If uploaded image is portrait keep new height and calculate new width
case ($this->image_height > $this->image_width):
$new_width = $this->get_image_width_ratio($height);
$new_height = $height;

// If crop is true set width to new width and calculate height again.
if($new_width < $width && $crop){
$new_width = $width;
$new_height = $this->get_image_height_ratio($width);
}
break;
// If uploaded image is square keep new width and new height. calculate nothing.
default:
$new_width = $width;
$new_height = $height;
break;
}

$this->new_image = imagecreatetruecolor($width, $height);

$this->fill_transparent($this->new_image);

$cropX = intval(($new_width - $width) / 2);
$cropY = intval(($new_height - $height) / 2);

imagecopyresampled($this->new_image, $this->image, -$cropX, -$cropY, 0, 0, $new_width, $new_height, $this->image_width, $this->image_height);
}

/**
* Checks if image should be filled with transparent color
* @param GdImage $image
* @return void
*/
private function fill_transparent(GdImage $image): void
{
if($this->is_transparent){
$color = imagecolorallocatealpha($image, 255, 255, 255, 127);
imagefill($image, 0, 0, $color);
imagesavealpha($image, true);
}
}


/**
* Checks if passed/given image has transparent pixels
* @param GdImage $image
* @return bool
*/
private function has_transparency(GdImage $image): bool
{
$rows = imagesx($image);
$cols = imagesy($image);

for($i = 0; $i < $rows; $i++) {
for($j = 0; $j < $cols; $j++) {
$rgba = imagecolorat($image, $i, $j);
if(($rgba & 0x7F000000) >> 24) {
return true;
}
}
}

return false;
}

/**
* Returns height ratio for given width
* @param int $width
* @return int
*/
private function get_image_height_ratio(int $width): int
{
$ratio = $width / $this->image_width;

return round($ratio * $this->image_height);
}

/**
* Returns width ratio for given height
* @param int $height
* @return int
*/
private function get_image_width_ratio(int $height): int
{
$ratio = $height / $this->image_height;

return round($ratio * $this->image_width);
}

/**
* @param string $path
* @param int $quality
* @return void
*/
public function save_image(string $path, int $quality = 50): void
{
switch($this->extension){
case 'jpeg':
case 'jpg':
imagejpeg($this->new_image, $path, $quality);
break;

case 'gif':
imagegif($this->new_image, $path);
break;

case 'png':
imagepng($this->new_image, $path, 9);
break;
}
}
}
 

Create an HTML Form to Upload and Resize an Image

Create an HTML page with form file input field to upload an image. Then resize uploaded image using the image class we created. Steps to upload image and resize it in PHP:

  • Check if files were uploaded without any error.
  • Declare a variable to store extension of uploaded.
  • Declare an array variable to store allowed extensions.
  • Declare a variable to store filename of resized image.
  • Check if uploaded file has the extension that exists in our allowed extensions array.
  • Instantiate image object of image class passing it the original image as parameter.
  • Resize the image passing values for width and height parameter.
  • Save resized image at the end passing it the name for new resized image.

index.php

<?php
include_once('image.php');
$upload = false;

// Check if uploaded file was uploaded without errors
if(!empty($_FILES) && $_FILES['image']['error'] === 0){
$extension = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION);
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif'];
$name = time();

// Check if uploaded image either of jpg,gif and png
if(in_array(strtolower($extension), $allowed_extensions)){
$new_image = new image($_FILES['image']['tmp_name']);

$new_image->resize_image(100, 100, true); // Resize image to 100x100
$new_image->save_image($name.'-100x100.'.$extension); // Save resized image

$new_image->resize_image(150, 150, true); // Resize image to 150x150
$new_image->save_image($name.'-150x150.'.$extension); // Save resized image

$new_image->resize_image(200, 200, true); // Resize image to 200x200
$new_image->save_image($name.'-200x200.'.$extension); // Save resized image
$upload = true;
}else{
// If uploaded file was not jpg,gif or png show an error
$error = 'Uploaded file was not an image. Please upload an image and try again.';
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Upload and Resize Image in PHP - Demo</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<div class="container">
<div class="mb-4">
<div class="alert alert-blue">Upload an image to resize. For demo purpose we will create <strong>200x200</strong>, <strong>150x150</strong> and <strong>100x100</strong> size images.</div>
<form class="form" method="POST" name="image-form" enctype="multipart/form-data">
<div class="row">
<div class="col-6">
<input type="file" name="image" />
</div>
<div class="col-6 text-right">
<input type="submit" value="Upload" class="btn btn-green"/>
</div>
</div>
</form>
</div>
<?php
// If image was uploaded show all resized images
if($upload){?>
<div class="mb-4">
<div class="row">
<div class="col-auto">
<h4>200x200</h4>
<img src="<?=$name?>-200x200.<?=$extension?>" />
</div>
<div class="col-auto">
<h4>150x150</h4>
<img src="<?=$name?>-150x150.<?=$extension?>" />
</div>
<div class="col-auto">
<h4>100x100</h4>
<img src="<?=$name?>-100x100.<?=$extension?>" />
</div>
</div>
</div>
<?php }

// If there was an error uploading the image show it here.
if(isset($error)){?>
<div class="alert alert-red"><?=$error;?></div>
<?php } ?>
</div>
</body>
</html>

Add CSS Styles

Add CSS styles for whole HTML page and form input field that is added for image upload.

style.css

*{
box-sizing: border-box;
}
html,body{
margin: 0px;
}
body{
background-color: #f6f6f6;
font-family: "Segoe UI", "Roboto", "Helvetica", sans-serif;
font-size: 15px;
font-weight: normal;
font-style: normal;
}
.container {
width: 100%;
margin-right: auto;
margin-left: auto;
padding-right: 15px;
padding-left: 15px;
max-width: 1140px;
}
.alert{
width: 100%;
padding: 10px;
margin-bottom: 10px;
color: #fff;
transition: opacity 0.5s;
}
.alert-blue{
background: #0369a1;
border: 1px solid #005D95;
}
.alert-red{
background: #e65442;
border: 1px solid #cc3a28;
}
.row{
margin-left: -10px;
margin-right: -10px;
margin-bottom: 10px;
}
.row {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-right: -15px;
margin-left: -15px;
}
.col-6, .col-auto{
width: 100%;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
}
.col-6 {
-webkit-box-flex: 0;
-ms-flex: 0 0 50%;
flex: 0 0 50%;
max-width: 50%;
}
.col-auto{
-webkit-box-flex: 0;
-ms-flex: 0 0 auto;
flex: 0 0 auto;
width: auto;
max-width: none;
}
.text-right{
text-align: right;
}
.btn-green {
display: inline-block;
padding: 5px 10px;
cursor: pointer;
font: inherit;
background: #00a65a;
border: 1px solid #009549;
color: #ffffff;
}