Sunday, August 5, 2018

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.

Upload and Resize Image in PHP

We will walk through following steps to create different sizes of uploaded image in php:

  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 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 $image;
private $extension;
private $image_width;
private $image_height;
private $new_image;
private $new_width;
private $new_height;

function __construct($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;

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

public function resize_image($new_width, $new_height, $crop = false){
$ratio = [];

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

$this->new_image = imagecreatetruecolor($new_width, $new_height);

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

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

//-- Function to set transparent background
private function fill_transparent($image){
$color = imagecolorallocatealpha($image, 255, 255, 255, 127);
imagefill($image, 0, 0, $color);
imagesavealpha($image, true);
}

//-- Function to get ratio width of image
private function get_image_width_ratio($new_width,$new_height){
$ratio = $new_height / $new_height;
$width = ceil($ratio * $new_width);
return $width;
}

//-- Function to get ratio height of image
private function get_image_height_ratio($new_width,$new_height){
$ratio = $new_width / $new_width;
$height = ceil($ratio * $new_height);
return $height;
}

public function show_image(){
//-- Start output buffering in case headers were already sent.
ob_start();
header("content-type: image/*");
switch($this->extension){
case "jpeg":
case "jpg":
imagejpeg($this->new_image, NULL, 50);
break;

case "gif":
imagegif($this->new_image, NULL);
break;

case "png":
imagepng($this->new_image, NULL, 9);
break;
}
header("content-type: text/html");
$result = ob_get_clean();

return $result;
}

public function save_image($path, $quality = 50){

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);
$allowedExtentions = ["jpg","jpeg","png","gif"];
$name = time();

//-- Check if uploaded image either of jpg,gif and png
if(in_array(strtolower($extension),$allowedExtentions)){
$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</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<div class="main-container">
<div class="section">
<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-10">
<input type="file" name="image" />
</div>
<div class="col-2">
<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="section">
<div class="row">
<div class="col-4">
<h4>200x200</h4>
<img src="<?php echo $name?>-200x200.<?php echo $extension?>" />
</div>
<div class="col-3">
<h4>150x150</h4>
<img src="<?php echo $name?>-150x150.<?php echo $extension?>" />
</div>
<div class="col-3">
<h4>100x100</h4>
<img src="<?php echo $name?>-100x100.<?php echo $extension?>" />
</div>
</div>
</div>
<?php }
//-- If there was an error uploading the image show it here.
if(isset($error)){?>
<div class="section">
<div class="alert alert-red"><?php echo $error;?></div>
</div>
<?php
}
?>
</div>
</body>
</html>

style.css

*{
    box-sizing: border-box;
}
html,body{
    margin: 0px;
}
body{
    background: #f0f0f0;
    font: normal normal 14px Open Sans,Verdana, Arial;
}
.main-container {
    max-width: 1024px;
    margin: 0px auto;
}
.section{
    padding: 15px;
    background: #fff;
}
.alert{
    width: 100%;
    padding: 10px;
    margin-bottom: 10px;
    color: #fff;
    transition: opacity 0.5s;
}
.alert-blue{
    background: #3c8dbc;
    border: 1px solid #2b7cab;
}
.alert-red{
    background: #e65442;
    border: 1px solid #cc3a28;
}
.row{
    margin-left: -10px;
    margin-right: -10px;
    margin-bottom: 10px;
}
.row:before,
.form-row:before,
.row:after,
.form-row:after{
    content: "";
    display: table;
}
.row:after, .form-row:after{
    clear:both;
}
[class*="col-"] {
    float: left;
    padding: 0px 10px;
}
.col-2 {width: 16.66%;}
.col-3 {width: 25%;}
.col-4 {width: 33.33%;}
.col-10 {width: 83.33%;}
.btn-green {
    background: #00a65a;
    border: 1px solid #009549;
    color: #fff;
    text-decoration: none;
    display: inline-block;
    padding: 5px 10px;
    cursor: pointer;
    float: right;
}