I introduced why I migrate my blog to github and Hugo here. Most of articles have been moved to here in 30 days. Next, I just want to talk about something about posts’ images management, versioning, theme customization/something about SEO.
Before start
All images will be compressed before I upload them for the post. Many tools that could do this, such as tinypng, UPNG. My choice is Tinypng because it supports variety formats and its API.
Tinypng’s APIs can be called by Python-Requests in this way:
import os
from os import path
import requests
from requests.auth import HTTPBasicAuth
def picopt(root_path, apikey):
for f in os.listdir(root_path):
fullurl = os.sep.join([root_path, f])
if path.isdir(fullurl):
picopt(fullurl, apikey)
else:
if fullurl.endswith(('.DS_Store', '-opt.png', '-opt.jpg', '-opt.jpeg')):
print('ignore ' + fullurl)
continue
print('processing ' + fullurl)
with open(fullurl, 'rb') as imgf:
content = imgf.read()
res = requests.post(
auth=HTTPBasicAuth("api:%s" %(apikey), ''), url='https://api.tinify.com/shrink', data=content)
print(res.json())
optimgurl = res.json()['output']['url']
# print(optimgurl)
res = requests.get(
auth=HTTPBasicAuth("api:%s" %(apikey), ''), url=optimgurl)
filename, filetypestr = fullurl.rsplit('.', 1)
optfullurl = '-opt.'.join([filename, filetypestr])
with open(optfullurl, 'wb') as fd:
for chunk in res.iter_content(chunk_size=128):
fd.write(chunk)
print('optimized img file: ' + fullurl)
if __name__ == "__main__":
devkey = ''
postimgsfolder = ''
picopt(postimgsfolder, devkey)
Manage the image in post with markdown
Refer to this Guide, it’s the easiest way:
Save the image file to folder static/img
Link image in post file with the markdown:
For image without link:
![Minion](/img/home-psb-bg.jpeg "alt wording")
For image with link:
[![Minion](/img/home-psb-bg.jpeg "alt wording")](/img/home-psb-bg.jpeg)
Yes, it’s /img/ in the link which was mentioned in here:
This union filesystem will be served from your site root. So a file
/static/me.png will be accessible as <MY_BASEURL>/me.png Load images from the post folder is possible in Hugo future version.
From my understanding, as the guide described, extra work should be needed for images resize with HTTP parameters, I didn’t dig deeper on this.
Manage the image in post with HTML code
For image without link:
<img src="/img/home-psb-bg.jpeg" alt="alt wording" style="height:200px;">
For images with link:
<a href="/img/home-psb-bg.jpeg"> <img src="/img/home-psb-bg.jpeg" alt="alt wording" style="height:200px;"> </a>
Manage the image with shortcode
Hugo provides a figure shortcode with sample:
{{< figure src="/media/spf13.jpg" title="Steve Francia" >}}
Note:
A sample about show shortcode on Hugo post.
The thing is Shortcode and Image Processing module enable Hugo to create responsive images:
- Customize the behavior and style to view the image
- Resize and crop the image to the proper size and quality for a different view
Make a long story short, shared my customization as an example
- Image defination with shortcode in the markdown file:
...
postWithImg: true
...
{{< imgproc imgPath="2018/12/5-opt.png" alt="XCode-Export Apple Developer Profile-3" max-height="250" >}}
Post images related settings in site configuration file:
... [params] postimgfoler = "/img/postimgs" #full url: assertsDir + /img/postimgs ...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
{{ $img := resources.Get (printf "%s/%s" ( .Site.Params.postimgfoler ) (.Get "imgPath")) }} {{ $imgpath := (printf "%s/%s/%s" ( "assets" ) (.Site.Params.postimgfoler ) (.Get "imgPath")) }} {{ $pagehgt := (printf "x%s q20" (.Get "max-height")) }} {{ .Scratch.Set "image" ($img.Resize $pagehgt) }} {{ $pageimage := .Scratch.Get "image" }} {{ $imgData := imageConfig $imgpath }} {{ $fanhgt := string ( $imgData.Height ) }} {{ if gt $imgData.Height 550 }} {{ $fanhgt = "550" }} {{ end }} {{ $fanhgt := (printf "x%s q20" ($fanhgt)) }} {{ .Scratch.Set "image" ($img.Resize $fanhgt) }} {{ $fanimage := .Scratch.Get "image" }} <div align="center"> <figure style="padding: 0.8rem; margin: 2rem 0; border: thin #c0c0c0 solid; border-radius: 10px; width: {{$pageimage.Width}}px; max-width: 88%"> <a href="{{ $fanimage.RelPermalink }}" data-fancybox data-caption={{ .Get "alt" }} > <img src="{{ $pageimage.RelPermalink }}" class="img-responsive" alt={{ .Get "alt" }} style="display: block;margin: 0.5rem;"/> </a> <figcaption class="text-capitalize"> <small>{{ .Get "alt" }}</small> </figcaption> </figure> </div>
- Line1: Different to markdown and html part, the images were saved to /assets/ folder so that resources.Get function could load the image file by path. The printf function joins two parameters to one string for resources.Get function.
- Line 3: Initial the full url of the image for imageConfig function (Line 9)
- Line 5-7: Generate an image from the original image by the max-height value which was defined in the markdown file, quality to 20
- Line 9-10: Get the hight info of the original image file with imageConfig
- Line 11-17: Check the height of the original image file, and generate a new file with quality value: 20. The height of the new image will be 550px if the value of the original is larger than 550px.
- Line 21-23: Call fancybox and bootstrap for image (Refer to layouts/partials/head.html for jQuery and fancybox files)
Note:
For the post with multiple images, failure might happen because of Hugo timeout mechanism. Changing timeout in global configuration (config.toml) could be the resolution:
timeout = 30000
The shortcode is also an example of Hugo - Creating a resource from a string
A live demo.
Lazy load images
Update @ Mar-09-2019
This part was referred to Lazy load images with zero Javascript
Add the class
img-lazyload
in Hugo shortcode for lazy load<img data-src="{{ $pageimage.RelPermalink }}" class="img-responsive img-lazyload" alt={{ .Get "alt" }} style="height: {{$pageimage.Height}}px;"/>
JS code
Added following code in footer.html
{{ if .Params.postWithImg }} <script> let lazyImages = [...document.querySelectorAll('.img-lazyload')] let inAdvance = 20 function lazyLoad() { lazyImages.forEach(image => { if ((image.offsetTop < window.innerHeight + window.pageYOffset + inAdvance) && ! image.classList.contains('img-lazyload-loaded') ) { image.src = image.dataset.src image.onload = () => { image.classList.add('img-lazyload-loaded'); image.style.height=""; } } }) // if all loaded removeEventListener } lazyLoad() window.addEventListener('scroll', _.throttle(lazyLoad, 8)) window.addEventListener('resize', _.throttle(lazyLoad, 8)) </script> {{end}}
Link
lodash
Add the link in head.html, otherwise, it will run into the error:
ReferenceError: _ is not defined
<!-- JS/CSS for postimg --> {{ if .Params.postWithImg }} <link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.6/jquery.fancybox.min.css"> <script src="//cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.6/jquery.fancybox.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/0.10.0/lodash.min.js"></script> {{end}}
Demo
**To Do:** With shortcodes and img process module, I'd like to try and process the post images like this: [Responsive images | MDN](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images).
Scan the QR code using WeChat