getzola / zola

A fast static site generator in a single binary with everything built-in. https://www.getzola.org
https://www.getzola.org
MIT License
13.59k stars 949 forks source link

Feature request: allow base64 encoding images in templates #2254

Open ismay opened 1 year ago

ismay commented 1 year ago

I'm looking at implementing low-quality image placeholders (LQIP) with zola. The one feature missing from zola to implement this is allowing the user to base64 encode an image from disk, in a template.

LQIP are a nice way to show users a blurred preview of the image that will load. Plus it prevents layout shift as images load, which is jarring for the user. See here for more details:

Basically the idea is:

The way I could see this working in zola is:

{# template #}
{% for image in images %}
  {% set lqip_image = resize_image(path=image, width=10, height=10, op="fit") %}
  {% set meta = get_image_metadata(path=image) %}
  {% set base64 = image_base64_encode(path=lqip_image) %}

  <div class="Placeholder" style="background-image: url('data:image/jpeg;base64,{{ base64 }}')">
    <div class="Placeholder-ratio" style="padding-bottom: calc({{ meta.height }} / {{ meta.width }} * 100%);"></div>
    <img
      class="Placeholder-content"
      loading="lazy"
      src="{{ image }}"
    />
  </div>
{% endfor %}

with the following css:

.Placeholder {
  background-size: cover;
  display: block;
  overflow: hidden;
  position: relative;
}

.Placeholder-ratio {
  display: block;
  padding-bottom: 100%;
  width: 100%;
}

.Placeholder-content {
  bottom: 0;
  height: 100%;
  left: 0;
  position: absolute;
  top: 0;
  width: 100%;
}

Just adding the loading of an image and subsequent base64 encoding of the image data would allow this to work, everything else already works with zola.

ismay commented 1 year ago

In thinking about this I suppose there are several ways to tackle this. The basics are that:

That could be added as an all in one method (e.g. image_base64_encode). But since the base64_encode filter already exists, just the loading of the image data could be sufficient (e.g. add image loading to load_data). Whichever makes more sense from zola's perspective. Either would work I suppose.

donovanglover commented 11 months ago

Are you interested in working on this? I was going to automate this for myself but having blurry image placeholders in Zola would be pretty cool.

ismay commented 11 months ago

I don't have the time tbh. I moved to hugo, which already supports this:

{{ with .Resources.GetMatch "img.png" }}
  <img src="data:{{ .MediaType.Type }};base64,{{ .Content | base64Encode }}">
{{ end }}
Keats commented 11 months ago

We would need to add a function to Zola to load the binary data of an image (load_data assumes utf-8) and we already have b64_encode as function