✨
[Go] 画像の拡張子の変更をするCLIコマンドを作る
はじめに
このまえ、Gopher道場 の自習室とやらに参加させてもらい、前々から気になっていたGopher道場の課題をgithubにて探して、(やっていいのかな…?)演習しました。
その課題1ってのが画像の拡張子変更 でした。とりあえずアウトプットをしたいので、ここに色々書いていきます。また、使用したパッケージから、flag
,os
,path/filepath
,image
について、ちょっとだけ解説していきます。
環境
# go version
go version go1.15.2 linux/amd64
# tree
.
|- conversion
| |- conversion.go
|- go.mod
|- main.go
実際のコード
とりあえず、リポジトリはここです
main.go
package main
import (
"cvs/conversion"
"flag"
"fmt"
"os"
"path/filepath"
)
var (
extension string
imagepath string
dirpath string
)
func main() {
flag.StringVar(&extension, "e", "jpeg", "拡張子の指定")
flag.StringVar(&imagepath, "f", "", "変換するファイルのパスの指定")
flag.StringVar(&dirpath, "d", "", "変換後のファイル名の指定")
flag.Parse()
err := conversion.ExtensionCheck(extension)
if err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
err = conversion.FilepathCheck(imagepath)
if err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
err = conversion.DirpathCheck(dirpath)
if err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
f := filepath.Ext(imagepath)
err = conversion.FileExtCheck(f)
if err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
fmt.Println("変換中・・・")
err = conversion.FileExtension(extension, imagepath, dirpath)
if err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
}
conversion.go
/*
Conversion は 画像の拡張子の変更を行うためのパッケージです。
*/
package conversion
import (
"errors"
"fmt"
"image"
"image/gif"
"image/jpeg"
"image/png"
"os"
_ "image/gif"
_ "image/jpeg"
_ "image/png"
)
const (
JPEG = "jpeg"
JPG = "jpg"
GIF = "gif"
PNG = "png"
)
// -e で指定した拡張子が対応しているか、判断します。
func ExtensionCheck(ext string) error {
switch ext {
case JPEG, JPG, GIF, PNG:
return nil
default:
return errors.New("指定できない拡張子です" + ext)
}
}
// -f で指定したファイルが存在するか、判断します。
func FilepathCheck(imagepath string) error {
switch imagepath {
case "":
return errors.New("ファイルの指定がされてません")
default:
if f, err := os.Stat(imagepath); os.IsNotExist(err) || f.IsDir() {
return errors.New("ファイルが存在しません" + imagepath)
} else {
return nil
}
}
}
func DirpathCheck(dirpath string) error {
switch dirpath {
case "":
return errors.New("変換後のファイル名が指定されていません")
default:
return nil
}
}
func FileExtCheck(imagepath string) error {
switch imagepath {
case "." + JPEG, "." + JPG, "." + GIF, "." + PNG:
return nil
default:
return errors.New("指定したファイルが対応していません。:" + imagepath)
}
}
func FileExtension(extension string, imagepath string, dirpath string) error {
exFile, err := os.Open(imagepath)
defer exFile.Close()
if err != nil {
return errors.New("os.Create失敗")
}
output, err := os.Create(dirpath)
defer output.Close()
if err != nil {
return errors.New("output失敗")
}
img, _, Err := image.Decode(exFile)
if Err != nil {
return errors.New("Decode失敗")
}
switch extension {
case JPEG, JPG:
err = jpeg.Encode(output, img, nil)
if err != nil {
return errors.New("Encode失敗")
}
fmt.Println("変換成功")
return nil
case GIF:
err = gif.Encode(output, img, nil)
if err != nil {
return errors.New("Encode失敗")
}
fmt.Println("変換成功")
return nil
case PNG:
err = png.Encode(output, img)
if err != nil {
return errors.New("Encode失敗")
}
fmt.Println("変換成功")
return nil
}
return nil
}
go.mod
module cvs
go 1.15
とりあえず、エラーハンドリングとかは適当にしつつ、ちゃんと動作するようにしました。
コード解説
今回のコードのテーマとして、
-
go mod
を使う -
go doc
を使う - パッケージを分ける
というのを決めました。一応、理由としては、
-
go mod
により、パッケージの分割を使いやすくする -
go doc
により、ドキュメントを作成することにより、可用性をあげる
この2つがあります。が、今回はパス。
今回使用したパッケージについて、色々書いていきます。
画像の拡張子を変更するCLIコマンドのために使用したパッケージを上げると、
flag
os
path/filepath
image
があります。
それぞれ解説していきます。
flag
ドキュメント
コマンドラインからオプションとして、引数を取得するときに使う
実装したコード(main.go)
var (
extension string
imagepath string
dirpath string
)
func main() {
flag.StringVar(&extension, "e", "jpeg", "拡張子の指定")
// -e "文字列" で、文字列を取得する/デフォルトで"jpeg"が指定されている
flag.StringVar(&imagepath, "f", "", "変換するファイルのパスの指定")
flag.StringVar(&dirpath, "d", "", "変換後のファイル名の指定")
flag.Parse()
// Parseしないと、変数にパースされない
~~~省略
書き方
flag.StringVar(&変数名, "オプションの記号", "デフォルトの値","このオプションの説明")
文字列の取得以外も取得はできる(はず)
os
ドキュメント
今回は、指定した画像が本当に存在するのか、画像を保存したりに使用しました。
実装したコード(conversion.go)
func FilepathCheck(imagepath string) error {
switch imagepath {
case "":
return errors.New("ファイルの指定がされてません")
default:
if f, err := os.Stat(imagepath); os.IsNotExist(err) || f.IsDir() {
return errors.New("ファイルが存在しません" + imagepath)
} else {
return nil
}
}
}
//-fで指定したファイルが存在するかを判定している関数です
こいつは結構なんでもできる。
path/filepath
ドキュメント
先程紹介した関数の引数の取得してます。stringからファイルパスを取得してます。
実装したコード(main.go)
f := filepath.Ext(imagepath)
err = conversion.FileExtCheck(f)
//imagepathが本当にあるのか、をチェックする
image
ドキュメント
画像処理系はこいつでできる。
実装したコード(conversion.go)
img, _, Err := image.Decode(exFile)
if Err != nil {
return errors.New("Decode失敗")
}
//画像をデコードする処理
switch extension {
case JPEG, JPG:
err = jpeg.Encode(output, img, nil)
if err != nil {
return errors.New("Encode失敗")
}
fmt.Println("変換成功")
return nil
case GIF:
err = gif.Encode(output, img, nil)
if err != nil {
return errors.New("Encode失敗")
}
fmt.Println("変換成功")
return nil
case PNG:
err = png.Encode(output, img)
if err != nil {
return errors.New("Encode失敗")
}
fmt.Println("変換成功")
return nil
}
//変換後の拡張子に合わせてエンコードする
画像処理はほぼこいつだけでできるっぽい
まとめ
実際に実行してみると、、、
# go build -o cvs
# ./cvs -e png -f sample.jpeg -d sample.png
変換中・・・
変換成功
って感じで、変換できる。
ちなみに、-d のあとに.pngではなく、適当に書いても、拡張子としては、ちゃんと変換されています。
ブラウザで変換すると、へんなスクリプトを入れられるみたいなのもないし、安全。
やりごたえがあって、楽しかったから、またコマンド作ろうかしら。
では。
Discussion