Width and height of photos on Photos page?

In order to avoid yank when the page is loaded I would really like to avoid setting the image width/height with javascript. (And in my case I don’t think it would make much difference since I can fall back on the “auto” width and height of the image when it’s loaded)

But in order to be able to query for the width/height I would guess that the values need to be added to the front matter of each photo post.

---
layout: post
microblog: true
guid: http://kottkrig.micro.blog/2022/04/29/jag-ger-er.html
date: 2022-04-29T19:15:00+0200
type: post
images:
- https://www.johanl.se/uploads/2022/eff3af0c28.jpg
photos:
- https://www.johanl.se/uploads/2022/eff3af0c28.jpg
url: /2022/04/29/jag-ger-er.html
---
Jag ger er en styck sollapande kodapa. 

<img src="uploads/2022/eff3af0c28.jpg" width="600" height="400" alt="Johan, sittandes på ett trädäck, i solen, med en laptop." />

Yes, it’s possible, but maybe not in a very efficient way. :blush: In the best of worlds, one can get hold of a global resource in Hugo like this: {{ $image := resources.Get "images/sunset.jpg" }}. That assumes sunet.jpg is located here in the Hugo project:

assets/
└── images/
    └── sunset.jpg    <-- global resource

I don’t know if @manton exposes Micro.blog uploads like this during build time or if they are located somewhere else altogether.

There are also resources.GetRemote that can fetch any public available URL. So you could always do that, but it will be expensive. Every time your blog is rebuilt, every upload on your blog will be fetched over the internet.

Manton might not like it, but you could do something like this:

{{- $list := where .Site.Pages ".Params.photos" "!=" nil -}}
{{- $len := (len $list) -}}
{{ range $index, $value := $list }}
  <a href="{{ .Permalink }}">
    {{ range $imageURL := (first 1 .Params.photos) }}
      {{ $image := resources.GetRemote $imageURL }}

      {{ with $image }}
         <img src="{{ $imageURL }}" width="{{ .Width }}" height="{{ .Height }}" loading="lazy" />
      {{ end }}
    {{ end }}
  </a>
{{ end }}

More info over at the Hugo docs.

1 Like

You won’t be able to rely on resources.Get working consistently because Micro.blog does store the images separately from the Markdown. I think resources.GetRemote should work, but as pointed out there will be a performance cost to doing that. I would use that only in very limited cases and not for every post, otherwise I expect it would slow down just sending a basic post from Micro.blog.

1 Like

Thank you for your input. resources.GetRemote looks really intriguing but I’ll refrain from using it with respect for the resource usage.

In the future, would it be possible for Micro.blog to maybe expose the width/height properties as metadata in the post front matter? (Or expose these properties in some other way?)

And maybe also expose the Exif-data that Hugo can serve from a resource? It would be neat to be able to add some additional camera information to the photos.

1 Like

I’m open to suggestions about the width/height metadata and agree it would be useful. The convention for Hugo images is just to have a list of URLs, so I’m not sure there’s an obvious place to put other data for each image.

For EXIF, we’ve talked about having some kind of advanced setting for people who want to get at the data. For privacy, Micro.blog strips all EXIF data from JPEGs during upload, to get rid of location information especially.

Perhaps the easiest thing would be to have micro.blog name photos based on their size? I know there are endpoints to get specifically sized versions (which probably would meet @kottkrig’s needs but may not perform well… for posterities sake, something like <img src = "https://micro.blog/photos/300x/{{ .Get "src" }}" /> gets you a 300 pixel wide image).

Such an endpoint would be a nice addition. But unfortunately I don’t think it would help with my specific use case. What I would like to do is to use the original width/height of the image to set the correct aspect ratio of the <img> elements before any images have been downloaded.

I’m using a masonry-ish layout for my photos page. When width/height aren’t set on the <img> elements, the browser doesn’t know the aspect ratio of the images. Which, in this case, results in a yanky layout when the images have been downloaded. Since the browser needs to redraw the layout after each image load.

If I could set the correct width/height of the individual photos then the browser would know, even before loading any image data, if the image is landscape/portrait and how many images it could reliably fit on each row.

Would it be possible to add an additional array to the front matter? In my example below I’ve called this potential new array: photosWithMetadata. So that it might be expanded with additional data in the future.

---
layout: post
microblog: true
guid: http://kottkrig.micro.blog/2022/04/29/jag-ger-er.html
date: 2022-04-29T19:15:00+0200
type: post
images:
  - https://www.johanl.se/uploads/2022/eff3af0c28.jpg
photos:
  - https://www.johanl.se/uploads/2022/eff3af0c28.jpg
photosWithMetadata:
  - src: https://www.johanl.se/uploads/2022/eff3af0c28.jpg
    width: 2400
    height: 1600
url: /2022/04/29/jag-ger-er.html
---

We would then be able to query for these elements in Hugo. Along the same lines as we already do with photos:

{{- $list := where .Site.Pages ".Params.photosWithMetadata" "!=" nil -}}
{{- $len := (len $list) -}}
{{ range $index, $value := $list }}
  {{ range first 1 .Params.photosWithMetadata }}
    <img
      src="{{ .src }}"
      width="{{ .width }}"
      height="{{ .height }}"
      loading="lazy"
    />
  {{ end }}
{{ end }}

I don’t know about @manton’s underlying architecture. So, maybe this is hard to pull off, but just mounting the uploads directory and making it available under assets/uploads/ would be pretty nice.

That way, we could just work with images the same way as with any self-hosted Hugo blog.

Are you comfortable with regular expressions? :sweat_smile: If so, you could implement your own photosWithMetadata by extracting all image elements from the post’s HTML and fetching the width and height. Provided that the width and height attributes are set, of course.

Making the upload files available at the time Hugo is running isn’t possible right now. Sometimes the images are there, for example when you click the “Rebuild” button on the logs page it brings everything together including all images. But as an optimization, Micro.blog frequently recreates the Markdown files and runs with no images present, since they have already been uploaded to the static servers that host the blogs.

If anyone’s curious, I wrote a blog post last year about some of this: Manton Reece - How does Micro.blog even work?

It’s a little out of date (things are even better now!) but long story short, we currently run Hugo on 3 servers and randomly pick one, so there would be overhead to having all images on all servers at all times for all users. Mounting from a remote server would also potentially create another single point of failure which we try to avoid. This might be too much information, but maybe it helps explain why it currently works this way. :slightly_smiling_face:

Back to the real issue… When an image is uploaded, we do store the width/height in a separate database, so we have the data. The Micro.blog apps also usually include width/height attributes in HTML.

One thought I had is that I assume this data is most valuable for the “Photos” page, so perhaps more metadata could be made available to that page only, without affecting much else.

1 Like

No, not too much information at all, and it makes total sense. Thanks for the explanation.

1 Like

Can you share how you are doing this under the current setup?

Sure!

But it involves some knowledge of CSS and Flexbox. The code for the current version is available on GitHub. It’s a large flex container where the child element have a fixed height (in my case 40vh) and an “auto” width. Since we’re using flexbox we can allow these children to “grow” to fill all available space. And finally, we set the “object fit” property to “cover” so that the images gets cropped rather than stretched when the elements are resized.

And if you want to inspect the final result. You’re more than welcome to inspect the source code at my website: johanl.se.

Thanks a lot but I don’t think I know enough CSS and Flexbox to make sense of it but it looks really nice on your website. I was wondering how I could edit the default MB template (layouts/_default/list.photoshtml.html) to get that layout.

I’ve rolled out a change inspired by @kottkrig’s feedback. In the front matter, there is now a new “photos_with_metadata” with 3 fields: “url”, “width”, and “height”. I haven’t done much with this yet other than to confirm it’s working, but hopefully this opens up some more custom theme and plug-in possibilities.

Do you mean the plugin you had created works now?

No, the plug-in is still a work in progress, but it should be possible to do correctly now.

Huge thanks!

By using the new width and height properties I finally got rid of the jankiness during initial page load. And as a bonus, it also fixed a lingering Safari layout bug where the image sizes wouldn’t update properly in the flex layout.

Before the update:

After the update:

Excellent, that looks great! I’ll try to work something like into the Masonry plug-in I was experimenting with. If you want to share more about how you did this, I’m sure folks would be interested!