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
- TinyPNG Compress Images Using PHP
- Image Optimization using artisansweb/image-optimizer Package
- Resize Image in PHP Using Intervention Image Library
If you liked this article, then please subscribe to our YouTube Channel for video tutorials.
i get error Call to a member function save() on array
Tinypng works well
Thanks so much
Please I’m getting this error Input file is empty (HTTP 400/InputMissing)
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());
}
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