Sunday, August 5, 2018

Upload and Resize Image in PHP

In this post you will learn how you can upload an image and resize to different sizes maintaining aspect ratio in PHP. We will be using PHP GD library to achieve this.

Upload and Resize Image in PHP
First we will create an image class in php which will contain all resizing functions and image object, index.php which will be used at frontend to upload image call image function from image and style.css for styling our index.php.

image.php

<?php

class image{

    private $image;
    private $extension;
    private $image_width;
    private $image_height;
    private $new_width;
    private $new_height;
    private $new_image;
    private $is_transparent;

    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;

        // 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);
    }

    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){
        if($this->is_transparent){
            $color = imagecolorallocatealpha($image, 255, 255, 255, 127);
            imagefill($image, 0, 0, $color);
            imagesavealpha($image, true);
        }
    }

    // Function to check if given image contains a transparent pixel
    private function has_transparency($image){
        $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;
    }

    private function get_image_height_ratio($new_width,$new_height){
        $ratio = $new_width / $this->image_width;
        $height = ceil($ratio * $this->image_height);
        return $height;
    }

    private function get_image_width_ratio($new_width,$new_height){
        $ratio = $new_height / $this->image_height;
        $width = ceil($ratio * $this->image_width);
        return $width;
    }

    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 image show message 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;
}