【Go】画像をリサイズして、dataサイズを圧縮する
はじめに
最近のケータイで撮った画像は高画質になった分、画像のデータサイズが大きくなり、
画像をたくさん表示するwebページが重くなる傾向にあります。
画像のリサイズをすると、データサイズが小さくなるので、速度を落とさずに済みます。
今回はそんなリサイズを試してみます。
今回使用するパッケージは
"github.com/nfnt/resize"
こちらです。
使用する理由は
画像の大きさを指定する際に、
通常はheightとwidthどちらも指定が必要ですが、
このパッケージは片方だけ指定すれば、それに合わせて、元サイズと同じ比率で小さくしてくれるのが良い!!
早速やってみます。
環境
macOS 11.4
go 1.16
今回リサイズしたい写真
- 桜の写真(jpg)
sakura.jpg
サイズ 3264 × 2448 で 3.4MBもあります。
- サメの写真(png)
shark.png
サイズ 3024 × 4032 なんと 8.2MB!?
この2つの写真をリサイズして画像データのサイズも小さくしようと思います。
ソースツリー
こんな感じで元データをimageフォルダに入れてます。
そして、サムネイル化出来たものをthumbnailフォルダに格納します。
ソースコード
package main
import (
"image"
"image/jpeg"
"image/png"
"log"
"os"
"github.com/nfnt/resize"
)
const imagePath = "image/"
const thumbnailPath = "thumbnail/"
const width = 256
const height = 0
// ここに元データのファイル名を書きます。
var imageName = "sakura.jpg"
// 変更後のファイル名を書きます。
var thumbnailName = "sakura-thumbnail"
func main() {
resizeImage()
}
func resizeImage() {
// 元の画像の読み込み
file := imagePath + imageName
fileData, err := os.Open(file)
if err != nil {
log.Fatal(err)
}
// 画像をimage.Image型にdecodeします
img, data, err := image.Decode(fileData)
if err != nil {
log.Fatal(err)
}
fileData.Close()
// ここでリサイズします
// 片方のサイズを0にするとアスペクト比固定してくれます
resizedImg := resize.Resize(width, height, img, resize.NearestNeighbor)
// 書き出すファイル名を指定します
createFilePath := thumbnailPath + thumbnailName + "." + data
output, err := os.Create(createFilePath)
if err != nil {
log.Fatal(err)
}
// 最後にファイルを閉じる
defer output.Close()
// 画像のエンコード(書き込み)
switch data {
case "png":
if err := png.Encode(output, resizedImg); err != nil {
log.Fatal(err)
}
case "jpeg", "jpg":
opts := &jpeg.Options{Quality: 100}
if err := jpeg.Encode(output, resizedImg, opts); err != nil {
log.Fatal(err)
}
default:
if err := png.Encode(output, resizedImg); err != nil {
log.Fatal(err)
}
}
}
こんな感じになりました。
下記で少しだけ解説しようと思います。
解説
1
const imagePath = "image/"
const thumbnailPath = "thumbnail/"
const width = 256
const height = 0
// ここに元データのファイル名を書きます。
var imageName = "sakura.jpg"
// 変更後のファイル名を書きます。
var thumbnailName = "sakura-thumbnail"
この部分は後で使う変数や定数を定義しています。
varの部分に元データや変更後のファイル名を書きます。
2
// 元の画像の読み込み
file := imagePath + imageName
fileData, err := os.Open(file)
if err != nil {
log.Fatal(err)
}
// 画像をimage.Image型にdecodeします
img, data, err := image.Decode(fileData)
if err != nil {
log.Fatal(err)
}
fileData.Close()
この部分は元の画像を読み込んでいます。
imageというフォルダにいる画像を取得するため、pathが
"image/sakura.jpg"
になるように、定数と変数を呼び出してます。
あとは、後のresizeで画像をimage.Image型にしておかないと使えないので、
image.Decodeでデコードしています。
その際に、dataという変数に画像の拡張子が返ってきます。
3
// ここでリサイズします
// 片方のサイズを0にするとアスペクト比固定してくれます
resizedImg := resize.Resize(width, height, img, resize.NearestNeighbor)
ここでresizeパッケージでリサイズされます。
引数に(横幅,高さ,画像data,補間フィルタ)を指定します。
私は定数でwidth=256,height=0と指定していますが、リテラルで直接数字を書く事も可能です。
横幅か高さのどちらかを 0 にすれば、指定した方に合わせてアスペクト比で小さくしてくれます。
(つまり同じ割合で、いい感じに小さくしてくれます)
最後の補間フィルタはよく分かりません。リサイズする時の方法みたいなのですが・・・
詳しく知りたい方は下記の記事を参考にされるといいと思います。
4
// 書き出すファイル名を指定します
createFilePath := thumbnailPath + thumbnailName + "." + data
output, err := os.Create(createFilePath)
if err != nil {
log.Fatal(err)
}
// 最後にファイルを閉じる
defer output.Close()
ここでサムネイル化した後のファイル名を指定しています。
これも上で変数にしています。
2.でお伝えしましたが、dataの中に拡張子が入ってますので、それを利用します。
5
// 画像のエンコード(書き込み)
switch data {
case "png":
if err := png.Encode(output, resizedImg); err != nil {
log.Fatal(err)
}
case "jpeg", "jpg":
opts := &jpeg.Options{Quality: 100}
if err := jpeg.Encode(output, resizedImg, opts); err != nil {
log.Fatal(err)
}
default:
if err := png.Encode(output, resizedImg); err != nil {
log.Fatal(err)
}
}
ここは拡張子によってswitchさせています。
decodeはimageパッケージでjpgでもpngでも対応出来ましたが、
encodeはjpgとpngで分けないと出来なかった為、switch文で切り分けしています。
実行
go run main.go
変数のファイル名はご自由に変更ください。
結果
桜のサムネイル写真
sakura-thumbnail.jpeg
サイズ 256 × 192 で 70KBに減りました。
サメのサムネイル写真
shark-thumbnail.png
サイズ 256 × 342 で 90KBに減りました。
とても小さくなりました。
サイズは色々指定できますので、遊んでみてください。
参考
注意
こちらのパッケージは2018年より更新されておりませんので、気になる方は別のパッケージをご利用ください。
Discussion