Upload and Resize Image in PHP
How to resize uploaded image in php? In this post we will create an image class with different methods to resize uploaded images in php. We will use PHP GD library in this class.
We will walk through following steps to create different sizes of uploaded image in php:
- Upload an image via html form.
- Open an image class object and resize it to a desired size.
- Save the resized image and show 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.
In image class we declare following properties for use in different methods:
- $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;
}
}
}
index.php
<?php
include_once('image.php');
$upload = false;
// Check if uploaded file was uploaded without errors
if($_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>
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;
}