Hugo: Resize รูปด้วย Image Processing

Armno's avatar image
Published on July 25th, 2019
By Armno P.

Hugo มาพร้อมกับฟีเจอร์ Image Processing ที่ช่วยย่อรูป/crop รูปเป็นขนาดต่างๆ ได้ จากรูปต้นฉบับที่เราเตรียมไว้รูปเดียว ผมได้ลองใช้แล้วพบว่าสะดวกดี จึงอยากจะบันทึกไว้ครับ

Update: พบปัญหาจากการใช้งาน image processing อยู่ 2 อย่าง อย่างแรกคือ ขนาดไฟล์อาจจะใหญ่ขึ้นกว่าเดิม อย่างที่สองคือ คุณภาพของรูปที่ผ่าน image processing ของ hugo นั้นค่อนข้างแย่ ภาพดูแตกอย่างชัดเจน ถึงแม้ตั้ง quality เป็น 100 แล้วก็ตาม ปัญหานี้ผมยังหาทางแก้ไม่ได้ จึงปิดฟีเจอร์ไว้ก่อนครับ

bigger file size after resized

Page Bundle

แต่ละหน้าใน Hugo จะถูกเก็บไว้ในโฟลเดอร์ content/

ตัวอย่าง content แบบ post จากโฟลเดอร์ content/post/fira-code/

content/      # โฟลเดอร์เก็บ content ทั้งหมด
├── post/       # โฟลเดอร์เก็บ content ประเภท post
│   ├── fira-code/  # 1 page bundle
│   │   ├── images/
│   │   │   ├── all_ligatures.png
│   │   │   ├── cover.png
│   │   │   ├── fira-code-in-vim.png
│   │   │   ├── fira-code.png
│   │   │   ├── iterm-preferences.png
│   │   │   └── roboto-mono.png
│   │   └── index.md

โฟลเดอร์ content/post/fira-code/ ถือเป็น 1 page bundle หรือ 1 ก้อน

นอกจากมีไฟล์สำคัญคือ index.md ที่เป็นเนื้อหาของโพสต์แล้ว ยังมีโฟลเดอร์ images/ ที่เอาไว้เก็บรูปประกอบต่างๆ หรืออาจจะมีไฟล์ประเภทอื่น หรือโฟลเดอร์อื่นรวมอยู่ด้วยก็ได้

ไฟล์ต่างๆ ที่อยู่ใน page bundle 1 ก้อน เรียกว่า page resources รูปในโฟลเดอร์ images/ ก็ถือเป็น page resource ชนิดหนึ่งเหมือนกัน เราสามารถเรียกใช้ page resources ผ่านทางตัวแปร {{ .Resources }} ของ Hugo และใช้งาน property/function ต่างๆ ของ Hugo ได้

เรียกใช้ Page Resources ใน template

สมมุติว่าเก็บไฟล์ที่จะใช้เป็น thumbnail ที่ images/thumbnail.png ใน template (.html) จะเขียนประมาณนี้

{{ $original :=  .Resources.GetMatch "thumbnail.png" }}

เราจะได้ $original ที่เป็น page resource object มี property ให้เลือกใช้

เช่น ใช้ property .RelPermalink สำหรับ attribute src ของแท็ก <img>

<img src="{{ $original.RelPermalink }}">

(property ทั้งหมดดูได้จาก document ได้เลย)

ใช้ page resource object กับ image processing

เมื่อได้ object $original แล้ว เราก็สามารถใช้ function Image Processing ของ Hugo ได้

เช่น ต้องการย่อรูปจาก $original ให้เป็นขนาด 400x400 pixel แล้วเก็บไว้ใน object $thumbnail

{{ $thumbnail := $original.Resize "400x400" }}

หรือบอกขนาดเฉพาะด้านใดด้านหนึ่ง โดยรักษาอัตราส่วนของรูปไว้ตามต้นฉบับ

<!-- กว้าง 400px สูงเท่าไหร่ก็ได้ -->
{{ $thumbnail := $original.Resize "400x" }}

<!-- สูง 400px กว้างเท่าไหร่ก็ได้ -->
{{ $thumbnail := $original.Resize "x400" }}

ถ้าเป็นรูป jpeg กำหนด quality และบีบอัดรูปให้เล็กลงได้ด้วยการส่ง parameter q เพิ่มเข้าไป

{{ $thumbnail := $original.Resize "400x q60" }}

$thumbnail ก็จะเป็นรูปขนาดที่ย่อแล้ว ทำให้เราใช้งานใน template ได้เหมือน object อื่นๆ

<img src="{{ $thumbnail.RelPermalink }}">

ตอนรัน local server หรือตอน build Hugo ก็จะสร้างรูปใหม่ และแก้ path ของรูปใน build output ให้ ตัวอย่าง

path ของรูปที่ Hugo generate ให้

ย่อรูปพร้อมกันทีละหลายๆ ขนาด

เราสามารถสร้างรูปหลายๆ ขนาดได้จากรูปต้นฉบับรูปเดียว

{{ $src := .Resources.GetMatch "thumbnail.png" }}

{{ $small := $src.Resize "500x q90" }}
{{ $medium := $src.Resize "800x q90" }}
{{ $large := $src.Resize "1400x q70" }}

จะได้รูปขนาดกว้าง 500, 800 และ 1400 pixel ตามลำดับ ในกรณีนี้ก็เราไปใช้กับ attribute srcset ของแท็ก <img> เพื่อทำ responsive image ให้ browser เลือกขนาดรูปที่เหมาะสมกับหน้าจอได้ (ตัดมาจาก shortcode image.html)

<img srcset='
  {{ with $small.RelPermalink }}{{.}} 500w{{ end }}
  {{ with $medium.RelPermalink }}, {{.}} 800w{{ end }}
  {{ with $medium2x.RelPermalink }}, {{.}} 1400w{{ end }}
'>

ถือเป็นการประหยัดเวลาในการเตรียมรูปประกอบ content ได้ดีครับ

ข้อควรระวังก็คือ ถ้าในโพสต์มีรูปที่ต้อง process เยอะ ก็จะยิ่งกินเวลา build time นานขึ้นด้วย บางทีทำให้เกิด timeout ตอน build ได้ครับ

Image Processing ยังมี option อื่นๆ อีก ตามอ่านได้ที่ Hugo Docs ได้เลย

Related posts