🐈

Goのテンプレートエンジンを使用して、画像を一覧表示してみた。

2021/06/16に公開

はじめに

Go言語で画像アップロードする方法は分かっていても、それを画像一覧表示しようとして1週間以上詰まってしまったのでメモ。
検索しても特に記事が引っ掛からなかったので、残しておきたいと思います。

あなただれ

生まれて初めて記事を執筆しました。ご指摘ございましたらコメント下さると助かります。🙏
2021年1月から(約5ヶ月目)からプログラミングの勉強し開始しましたkinariと申します。
今は、自分の周りで未経験からGo言語を選択した人がいなくてえっちらおっちらしております。

執筆した背景

標準パッケージのみで画像を表示したいけど、どうすればいいか分からない。
→ 単体の画像は表示できることがわかった。
→ でも複数枚表示するにはどうしたらいいんだろう?(←今ここ)

環境

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.7
BuildVersion:   19H1217

$ go version
go version go1.16.2 darwin/amd64

ディレクトリ構成

$ tree
.
├── assets // ここに表示したい画像をおきます。
│   ├── levi.jpg
│   └── tanjiro.jpeg
├── main.go
└── templates
    └── index.html

やりたいこと

1ページに画像一覧表示をしてみたい!

やったこと

main.go
package main

import (
	"bytes"
	"encoding/base64"
	"github.com/nfnt/resize"
	"image"
	"image/jpeg"
	"log"
	"net/http"
	"os"
	"text/template"
)

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	dir, err := os.Open("assets/")
	defer dir.Close()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	allImageNames, err := dir.Readdirnames(-1) // それぞれの画像ファイルの名前を配列に格納します
	if err != nil {
		log.Fatalln("No files")
	}
	var decodeAllImages []image.Image
	for _, imageName := range allImageNames { // 全ての画像をデコード、リサイズしてdecodeAllImageseに格納します
		file, _ := os.Open("assets/" + imageName)
		defer file.Close()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		decodeImage, _, err := image.Decode(file)
		resizedDecodeImage := resize.Resize(300, 0, decodeImage, resize.Lanczos3) // サイズを揃えるために横幅を300に固定します
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		decodeAllImages = append(decodeAllImages, resizedDecodeImage)
	}
	writeImageWithTemplate(w, decodeAllImages)
}

// writeImageWithTemplateで画像をエンコードします。
func writeImageWithTemplate(w http.ResponseWriter, decodeAllImages []image.Image) {
	var encordImages []string
	for _, decodeImage := range decodeAllImages {
		buffer := new(bytes.Buffer)
		if err := jpeg.Encode(buffer, decodeImage, nil); err != nil {
			log.Fatalln("Unable to encode image.")
		}
		str := base64.StdEncoding.EncodeToString(buffer.Bytes())
		encordImages = append(encordImages, str)
	}
	data := map[string]interface{}{"Images": encordImages}
	renderTemplate(w, data)
}

// renderTemplateで渡された画像をテンプレートエンジンに渡します。
func renderTemplate(w http.ResponseWriter, data interface{}) {
	var templates = template.Must(template.ParseFiles("templates/index.html"))
	if err := templates.ExecuteTemplate(w, "index.html", data); err != nil {
		log.Fatalln("Unable to execute template.")
	}
}

func main() {
	http.HandleFunc("/", IndexHandler)
	http.ListenAndServe(":8080", nil)
}

index.htmlでテンプレートエンジンを使用して、複数枚の画像を表示します。(画像一覧表示)

index.html
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>画像一覧表示</title>
</head>

<body>
	<!-- Goのテンプレートエンジンの中でも、イテレータアクション(反復処理)を使用します。 -->
	<!-- ここに「"Images": encordImages」の複数枚の画像が一覧表示されていきます。 -->
	{{ range .Images }}
		<img src="data:image/jpg;base64,{{ . }}" /><br />
	{{ end }}
</body>

</html>

結果

無事、画像一覧表示がされました!

Github

Github にもコードをアップしました。

参考

Golangで画像をアップロードして表示するだけのアプリをつくってみた - 一から勉強させてください
Goプログラミング実践入門 標準ライブラリでゼロからWebアプリを作る - インプレスブックス

Discussion