How to Upload and Compress Images in Laravel

Do you want to compress(optimize) images in Laravel? Though there are several ways of compressing images, I recommend optimizing them at the time of uploading. This behavior will save time for later work. And you don’t have to worry about image optimization once the application is built. In this tutorial, I’ll explain how to upload and compress images in Laravel.

Why Need to Compress Images?

Images play an important role in your website. Images add better UX and an eye-catching experience for the visitors. But at the same time, it can also kill the site’s performance. Heavy images slow down the website. As a result, your site takes a long time to load. Users don’t like slow websites. If the site is taking more time to load, it is a high chance of losing your audience. The standard loading time for a website is 2 seconds. You should make sure your site is loading within 2 seconds.

There are several factors that need to be considered to improve the page speed, one of them is the use of optimized images. Compressing images reduces the size of your original image without losing its quality. Lower the file size, fast it will load on the web pages.

Apart from image optimization, you should also consider resizing images as per the container. Don’t try to fit large-dimension images in a small container. The purpose of this tutorial is to show you compress the original image, check out the linked article in order to resize the images.

Uploading Images in Laravel

Laravel provides an easy approach to uploading images. For getting started, you first need to create a directory where the images will be stored. Open your command prompt in the root directory and run the below command.

php artisan storage:link

This command creates a storage directory under the public folder. Inside this storage folder, we’ll store the images.

To see the flow in action, let’s create routes, a controller, and a view. Add the below routes to the routes/web.php file.

Route::get('upload', 'ImageController@index');
Route::post('store', 'ImageController@store');

Create the ImageController with the following command.

php artisan make:controller ImageController

Next, create the upload.blade and add the following lines to it.

@if(session('success'))
    <strong>{{ session('success') }}</strong>
@endif

@if (count($errors) > 0)
    @foreach ($errors->all() as $error)
        <strong>{{ $error }}</strong>
    @endforeach
@endif

@if(session('error'))
    <strong>{{ session('error') }}</strong>
@endif

<form action="{{ url('store') }}" method="post" enctype="multipart/form-data">
    @csrf
    Upload Image: <input type="file" name="profile_image" required />
    <p><button type="submit" name="submit">Submit</button></p>
</form>

In the above code, I have added a file input with the name ‘profile_image’. I also added a code to display success or error messages.

The form action is set to the store route which is mapped with the store() method. This store() method will have a code that uploads the image to the server. The view will be called from the index() method.

ImageController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ImageController extends Controller
{
    public function index()
    {
        return view('upload');
    }

    public function store(Request $request)
    {
        // validate image
        $this->validate($request, [
            'profile_image' => 'required|image|mimes:jpg,jpeg,png,gif,svg'
        ]);

        //get filename with extension
        $filenamewithextension = $request->file('profile_image')->getClientOriginalName();
 
        //get filename without extension
        $filename = pathinfo($filenamewithextension, PATHINFO_FILENAME);
 
        //get file extension
        $extension = $request->file('profile_image')->getClientOriginalExtension();
 
        //filename to store
        $filenametostore = $filename.'_'.time().'.'.$extension;
 
        //Upload File
        $request->file('profile_image')->storeAs('public/profile_images', $filenametostore);
 
        //Code for Compress Image
 
        return redirect('upload')->with('success', "Image uploaded successfully.");
    }
}

This code creates a unique filename and stores the file inside the profile_images directory. Laravel automatically generates this directory under public/storage if it does not exist.

As I said before, it’s a good practice to optimize the image at the time of upload. We are done with uploading an image. Now we need to compress it. For image compression, I am going to use 2 services – TinyPNG and reSmush.it. Both these services provide the APIs to compress images on the fly. Let’s see them one by one.

Compress Images using TinyPNG in Laravel

To compress images using TinyPNG you need to get your API key. The process is simple. Register your email address with them and they will send your developer key.

Once you get the API key, add it to the .env file.

TINIFY_API_KEY=

After this, install a TinyPNG package using the command:

composer require tinify/tinify

Upon package installation, we have to write a code that compresses the uploaded image using TinyPNG.

Write a compression code just below the line which uploads the image.

//Code for Compress Image
$filepath = public_path('storage/profile_images/'.$filenametostore);

try {
    \Tinify\setKey(env("TINIFY_API_KEY"));
    $source = \Tinify\fromFile($filepath);
    $source->toFile($filepath);
} catch(\Tinify\AccountException $e) {
    // Verify your API key and account limit.
    return redirect('upload')->with('error', $e->getMessage());
} catch(\Tinify\ClientException $e) {
    // Check your source image and request options.
    return redirect('upload')->with('error', $e->getMessage());
} catch(\Tinify\ServerException $e) {
    // Temporary issue with the Tinify API.
    return redirect('upload')->with('error', $e->getMessage());
} catch(\Tinify\ConnectionException $e) {
    // A network connection error occurred.
    return redirect('upload')->with('error', $e->getMessage());
} catch(Exception $e) {
    // Something else went wrong, unrelated to the Tinify API.
    return redirect('upload')->with('error', $e->getMessage());
}

Here we take an image from the uploaded directory, send it to the TinyPNG server for compression, and after receiving a response, store the compressed image in the same directory. In short, it replaces the original image with its optimized version.

This process runs in the background. You don’t need to worry about how the image is sent to the TinyPNG server, and how it receives the API response. TinyPNG library handles this task for you.

Try to upload the image and you should see your image get compressed.

Compress Images using reSmush.it in Laravel

TinyPNG works well but it has a limitation of optimizing 500 free images per month. To compress more than 500 images, you need to pay for them. You can use TinyPNG if you are willing to pay. Alternatively, users can pick a free service of reSmush.it for image compression. At the time of writing this article, they compressed more than 7 billion images. This is enough to say about the popularity of this service.

The below code compresses images using reSmush.it in Laravel. Add this code in place of the TinyPNG we have written before.

//Code for Compress Image
$filepath = public_path('storage/profile_images/'.$filenametostore);
$mime = mime_content_type($filepath);
$output = new \CURLFile($filepath, $mime, $filenametostore);
$data = ["files" => $output];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://api.resmush.it/?qlty=80');
curl_setopt($ch, CURLOPT_POST,1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$result = curl_exec($ch);
if (curl_errno($ch)) {
    $result = curl_error($ch);
}
curl_close ($ch);

$arr_result = json_decode($result);

// store the optimized version of the image
$ch = curl_init($arr_result->dest);
$fp = fopen($filepath, 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);

I have passed the quality value as 80 to the parameter ?qlty=80. You can play with passing different quality values. Give it a try and you will get the optimized version of your images.

I hope you understand how to upload and compress images in Laravel. I would like to hear your thoughts and suggestions in the comment section below.

Related Articles

If you liked this article, then please subscribe to our YouTube Channel for video tutorials.

5 thoughts on “How to Upload and Compress Images in Laravel

  1. Nice Tutorial but after uploading some images i’m getting error “Maximum execution time of 60 seconds exceeded”
    and when i remove Tinify code then it works fine but i want to use tinify to compress image size.

    try {
    \Tinify\setKey(env(“TINIFY_DEVELOPER_KEY”));
    $source = \Tinify\fromFile($realimagepath);
    $source->toFile($realimagepath);
    } catch(\Tinify\AccountException $e) {
    // Verify your API key and account limit.
    return redirect(‘admincontrol/create’)->with(‘error’, $e->getMessage());
    } catch(\Tinify\ClientException $e) {
    // Check your source image and request options.
    return redirect(‘admincontrol/create’)->with(‘error’, $e->getMessage());
    } catch(\Tinify\ServerException $e) {
    // Temporary issue with the Tinify API.
    return redirect(‘admincontrol/create’)->with(‘error’, $e->getMessage());
    } catch(\Tinify\ConnectionException $e) {
    // A network connection error occurred.
    return redirect(‘admincontrol/create’)->with(‘error’, $e->getMessage());
    } catch(Exception $e) {
    // Something else went wrong, unrelated to the Tinify API.
    return redirect(‘admincontrol/create’)->with(‘error’, $e->getMessage());
    }

    1. max_execution_time issue is related to your PHP configuration not with Laravel. You should change values of max_execution_time in your php.ini file. Set it to 300 like max_execution_time=300

Leave a Reply

Your email address will not be published. Required fields are marked *