How to compress image in PHP

Previously, I wrote an article on how to compress images in Node JS. In this article, we will discuss how you can compress an image in PHP.

Let’s say you have an image named “image.png”. The following code will compress the file by half:

$source = "image.jpg";
$destination = "image-min.jpg";
$quality = 50;

$info = getimagesize($source);
$image = null;

if ($info["mime"] == 'image/jpeg')
{
    $image = imagecreatefromjpeg($source);
}

else if ($info["mime"] == 'image/gif')
{
    $image = imagecreatefromgif($source);
}

else if ($info["mime"] == 'image/png')
{
    $image = imagecreatefrompng($source);
}

if ($image != null)
{
    imagejpeg($image, $destination, $quality);
    echo "Image compressed";
}

Explanation:

  • Line [1-3]: Setting the source and destination path. Also, the quality of the compressed image. It will be between 0 and 100. 0 means fully compressed and 100 indicates the original quality (although the file size will be reduced a little even on 100).
  • [5, 6]: getimagesize will return the size and mime type of the image. We will be needing the mime type only.
  • [8-21]: Creates a new image object based on file mime type.
  • [23-27]: If any of the supported image types match, create a JPEG image from source to destination along with the quality of the new image. If the source and destination paths are the same, the original image will be replaced by the compressed image. That is why we are using a different name for the destination image.

Why use JPEG for compressed image

You might be wondering why while creating an image object, we are checking the mime type of image. But on compressing the image we are only using imagejpeg that creates a JPEG file. We use JPEG (Joint Photographic Experts Group) for image compression for the following reasons:

  1. Compression: JPEG decreases the file size a lot without losing the quality of the image. You won’t see much difference in quality from the original to the compressed image but the file size will be much less than the original one.
  2. Custom quality: You can set the quality of your choice from 0 to 100.
  3. User experience: When the user opens a JPEG file and if it is too large, it will first load the lower quality version of the image, which is usually a grayscaled image. Then it loads the image in its original colors. This is pretty useful on slow internet.

Laravel

If you are working in Laravel, you might be facing difficulty because Laravel uses separate “storage” folder for handling all user uploaded files. Also, it creates a symbolic link to the public folder. So it gets a little confusing for developers on how to read image from storage and save the compressed image on storage.

Just change your source and destination variables to the following:

$source = base_path("public/storage/image.jpg");
$destination = base_path("storage/app/public/image-min.jpg");

To get the mime type of an image in Laravel, you can use the following code:

$file = request()->file("image");

if ($file->getClientMimeType() == 'image/jpeg')
{
    //
}

Complete code for Laravel developers will be:

if (request()->file("image"))
{
    $file = request()->file("image");

    $file_path = "images/" . $file->getClientOriginalName();
    $file->storeAs("/public", $file_path);

    $source = base_path("public/storage/" . $file_path);
    $destination = base_path("storage/app/public/" . $file_path);
    $quality = 50;

    // $info = getimagesize($source);
    $image = null;

    if ($file->getClientMimeType() == 'image/jpeg')
    {
        $image = imagecreatefromjpeg($source);
    }

    else if ($file->getClientMimeType() == 'image/gif')
    {
        $image = imagecreatefromgif($source);
    }

    else if ($file->getClientMimeType() == 'image/png')
    {
        $image = imagecreatefrompng($source);
    }

    if ($image != null)
    {
        imagejpeg($image, $destination, $quality);
        return "Image compressed";
    }
}

Note: Only the source and destination paths are changed and the way image mime type is get.

With that said, this concludes my article on how to compress an image in PHP. If you face any problem in following this, kindly do let me know.

Compress image in Node JS

In this tutorial, we are going to teach you, how you can compress image in Node JS. You can download and install Node JS from their official site.

Video tutorial: Compress image in Node JS

First, create a new folder. Open CMD in it. And run the following commands:

> npm init
> npm install express http

Then, create a file named “server.js” and write the following code in it:

const express = require("express")
const app = express()
const http = require("http").createServer(app)

// [other modules]

const port = process.env.PORT || 3000

http.listen(port, function () {
	console.log("Server started running at port: " + port)

	// [post route goes here]

	// [get route goes here]
})

Then run the following commands in your terminal:

> npm install -g nodemon
> nodemon server.js

You will see a message saying the “Server started running at port: 3000”. You can access your server from the following URL:

http://localhost:3000

Now, we need to install the module for displaying views. And to get input from form fields. So, install the following modules:

> npm install ejs fs express-formidable

EJS module is used for displaying the HTML files. FS stands for File System, this module is used to handle files. And “express-formidable” is used for getting values from the input field. Make sure to run the “nodemon server.js” command again.

Install compress image module in Node JS

To install a module to compress image in Node JS, you need to run the following command in your terminal:

> npm install pngquant-bin@6.0.1 gifsicle@5.2.1 compress-images fs

Then, we need to include those modules in our project. So write the following lines in the [other modules] section:

const compressImages = require("compress-images")
const formidable = require("express-formidable")
app.use(formidable())

const fileSystem = require("fs")
app.set("view engine", "ejs")

Now, write the following lines in the [get route goes here] section:

app.get("/", function (request, result) {
	result.render("index")
})

After that, you need to create a folder named “views” at the root of your project. And in that folder, create a file named “index.ejs”. Following will be the code of “index.ejs”:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1" />
		<title>Compress image</title>
	</head>

	<body>
		<form method="POST" action="/compressImage" enctype="multipart/form-data">
			<input type="file" name="image" accept="image/*" required />
			<input type="submit" value="Compress image" />
		</form>
	</body>
</html>

It will display a simple HTML form with an input field and a submit button. Then, you need to create a POST route that will handle this request. The following code goes in the [post route goes here] section of the “server.js” file:

app.post("/compressImage", function (request, result) {
    const image = request.files.image
    if (image.size > 0) {

        if (image.type == "image/png" || image.type == "image/jpeg") {
            fileSystem.readFile(image.path, function (error, data) {
                if (error) throw error

                const filePath = "temp-uploads/" + (new Date().getTime()) + "-" + image.name
                const compressedFilePath = "uploads/"
                const compression = 60
                
                fileSystem.writeFile(filePath, data, async function (error) {
                    if (error) throw error
                    
                    compressImages(filePath, compressedFilePath, { compress_force: false, statistic: true, autoupdate: true }, false,
                        { jpg: { engine: "mozjpeg", command: ["-quality", compression] } },
                        { png: { engine: "pngquant", command: ["--quality=" + compression + "-" + compression, "-o"] } },
                        { svg: { engine: "svgo", command: "--multipass" } },
                        { gif: { engine: "gifsicle", command: ["--colors", "64", "--use-col=web"] } },
                        async function (error, completed, statistic) {
                            console.log("-------------")
                            console.log(error)
                            console.log(completed)
                            console.log(statistic)
                            console.log("-------------")

                            fileSystem.unlink(filePath, function (error) {
                                if (error) throw error
                            })
                        }
                    )

                    result.send("File has been compressed and saved.")
                })

                fileSystem.unlink(image.path, function (error) {
                    if (error) throw error
                })
            })
        } else {
            result.send("Please select an image")
        }
    } else {
        result.send("Please select an image")
    }
})

The last thing you need to do is to create two folders named “uploads” and “temp-uploads” at the root of your project. Here, all compressed images will be stored.

This will compress the image up to 60%. You can now try to select an image from the input file and hit “Compress image”. You will see a success message if everything goes right. And you will see your compressed image in the “uploads” folder.

Real-world example

We implemented this compression in one of our projects, so you can get the real-world example of image compression in Node JS.

So that’s how you can compress an image in Node JS. If you face any problems in following this, kindly do let us know.

Download source code

[wpdm_package id=’1704′]