LQIP in Rails using Thumbor and base64
Tags: ruby, selfhosting
Published: 2021-02-02 18:30:35

---
title: LQIP in Rails using Thumbor and base64
published: true
date: 2021-02-02 18:30:35 UTC
tags: ruby,selfhosting
canonical_url: https://www.mskog.com/posts/lqip-in-rails-using-thumbor-and-base64
---

There are [many](https://jmperezperez.com/svg-placeholders/) [ways](https://cloudinary.com/blog/low_quality_image_placeholders_lqip_explained) to do low quality image placeholders for applications. This is a simple way using Thumbor and Ruby to generate blurry base64 thumbnails. This way the image can be loaded in the first HTML load and there is no need for additional requests to fetch the  thumbnails while the original images are loading.

You will need [Thumbor](https://github.com/thumbor/thumbor) to use this method. If you're unfamiliar with Thumbor then I wrote an introduction [here](https://www.mskog.com/posts/self-hosted-tools-for-web-development).

The idea is to take the original image and then drop the quality as low we can and then make it small with a blur effect.

![Original image](https://thumbs.mskog.com/https://s3-eu-central-1.amazonaws.com/mskog-cms/2021/01/pexels-photo-5733127.jpeg)

Let's start by applying the quality filter and drop the quality to say 5

![](https://thumbs.mskog.com/https://s3-eu-central-1.amazonaws.com/mskog-cms/2021/01/quality-5.jpeg)

Next, we take the image size down to say 100 pixels wide and keep the aspect ratio.

![](https://thumbs.mskog.com/https://s3-eu-central-1.amazonaws.com/mskog-cms/2021/01/small.jpeg)

Now, if we blow this image up to a reasonable size it will look real bad. So what I like to do is play with the quality and size a bit and add a bit of blur. In this example I changed the size to 200 pixels wide, the quality to 25 and added 5 blur:

![](https://thumbs.mskog.com/https://s3-eu-central-1.amazonaws.com/mskog-cms/2021/01/final.jpeg)

The size is a bit larger now but I think the trade off is worth it. Here is the URL for the final image if you want to have a look at the settings:

https://thumbs.mskog.com/200x/filters:format:(jpeg):quality(25):blur(5)/https://images.pexels.com/photos/5733127/pexels-photo-5733127.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260

We can now use this excellent [Base64 Image Encoder](https://www.base64-image.de/) site to convert the image to base64. The final image will thus be about 3.26kB. Keep in mind that this is text and can be compressed. Gzip compression should be able to take this down to about 2kB once we add it to a website.

Ok, so now we have settings that we like. Next up we need to write some Ruby code to convert the image to base64. This is very easy to do:

```ruby
require "net/http"

url = "https://thumbs.mskog.com/200x/filters:format:(jpeg):quality(25):blur(5)/https://images.pexels.com/photos/5733127/pexels-photo-5733127.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260"

base64 = Base64.encode64(Net::HTTP.get(URI(url))).gsub("\n","")
```

That is all you need. We now have a base64 string representation of the image. I like to save this result to a database field on the model with the image. You can also use the Rails cache and generate these base64 images on the fly if you want. This will however be very slow and that is probably not what you want. Instead, just use [ActiveJob](https://guides.rubyonrails.org/active_job_basics.html) to create these in the background once the original image URL is saved. Then save them to the model. Another idea is to use [Active Storage](https://edgeguides.rubyonrails.org/active_storage_overview.html) and hook into the metadata analysis to add your base64 strings this way.

Right, time to put the base64 images to use. What you want to do is to use these as placeholders while the full image is loading. I usually use [vanilla-lazyload](https://github.com/verlok/vanilla-lazyload) for this. It is a simple and tiny project that gets the job done. Do mind that if you use Turbolinks you have to make sure that vanilla-lazyload does its thing after Turbolinks is done. If you use Webpacker it will look something like this in your application.js file:

```javascript
import LazyLoad from "vanilla-lazyload";
const lazyLoad = new LazyLoad();
document.addEventListener("turbolinks:load", function () {
  lazyLoad.update();
});
```

Now you can use this in your [HTML](https://en.wikipedia.org/wiki/Data_URI_scheme#Syntax)

And there we go. Lazy loaded base64 placeholders that will be replaced by the full image once it is done loading. If you want to see how this looks in practice then I made a [test site](https://upcomingvideogames.mskog.com/) for it