diff --git a/kadai1/wataboru/.gitignore b/kadai1/wataboru/.gitignore new file mode 100644 index 0000000..090a1f0 --- /dev/null +++ b/kadai1/wataboru/.gitignore @@ -0,0 +1,2 @@ +.idea +.DS_Store diff --git a/kadai1/wataboru/README.md b/kadai1/wataboru/README.md new file mode 100644 index 0000000..012adcd --- /dev/null +++ b/kadai1/wataboru/README.md @@ -0,0 +1,52 @@ +# 課題 1 【TRY】画像変換コマンドを作ろう + +## 次の仕様を満たすコマンドを作って下さい + +- ディレクトリを指定する +- 指定したディレクトリ以下の JPG ファイルを PNG に変換(デフォルト) +- ディレクトリ以下は再帰的に処理する +- 変換前と変換後の画像形式を指定できる(オプション) + +## 以下を満たすように開発してください + +- main パッケージと分離する +- 自作パッケージと標準パッケージと準標準パッケージのみ使う +- 準標準パッケージ:golang.org/x 以下のパッケージ +- ユーザ定義型を作ってみる +- GoDoc を生成してみる +- Go Modules を使ってみる + +### 動作手順 + +``` +$ go build -o imgconv +$ ./imgconv -h +Usage of ./imgconv: + -a string + Input extension after conversion. (short) (default "png") + -after --after=jpg + Input extension after conversion. + ex) --after=jpg (default "png") + -b string + Input extension before conversion. (short) (default "jpg") + -before --before=png + Input extension before conversion. + ex) --before=png (default "jpg") + -d string + Input target Directory. (short) + -dir --dir=./convert_image + Input target Directory. + ex) --dir=./convert_image +$ ./imgconv -d ./testdate + or +$ ./imgconv -d ./testdate -b png -a gif + or +$ ./imgconv -d ./testdate -b jpeg -a tiff +``` + +### 感想等 + +- 前提として、@tenntennさんの公開されている[handsonプロジェクト](https://github.com/tenntenn/gohandson/tree/master/imgconv/ja)と似ている内容でして、以前やったことがありました。 + - そちらに無い部分として、tiff変換やbmp変換の追加などを行いました。 +- GoModulesを利用したく、`golang.org/x/image`を導入しました +- 様々なソースをみていると、変数名やコマンド名が自分は冗長かな?と感じています。Go話者の方は短く記載するものなのでしょうか。 diff --git a/kadai1/wataboru/commands/imageconverter/main.go b/kadai1/wataboru/commands/imageconverter/main.go new file mode 100644 index 0000000..a60490c --- /dev/null +++ b/kadai1/wataboru/commands/imageconverter/main.go @@ -0,0 +1,55 @@ +package main + +import ( + "github.com/gopherdojo/dojo8/kadai1/wataboru/imageconverter" + + "flag" + "fmt" + "os" +) + +const ( + // ExitCodeSuccess is the exit code on success + ExitCodeSuccess = 0 + // ExitCodeError is the exit code when failed + ExitCodeError = 1 + // ExitCodeError is the exit code when failed + ExitCodeInvalidDirectoryError = 2 +) + +var ( + args imageconverter.Args +) + +func init() { + flag.StringVar(&args.Directory, "dir", "", "Input target Directory.\n ex) `--dir=./convert_image`") + flag.StringVar(&args.Directory, "d", "", "Input target Directory. (short)") + flag.StringVar(&args.BeforeExtension, "before", "jpg", "Input extension before conversion.\n ex) `--before=png`") + flag.StringVar(&args.BeforeExtension, "b", "jpg", "Input extension before conversion. (short)") + flag.StringVar(&args.AfterExtension, "after", "png", "Input extension after conversion.\n ex) `--after=jpg`") + flag.StringVar(&args.AfterExtension, "a", "png", "Input extension after conversion. (short)") + flag.Parse() +} + +func run() int { + if args.Directory == "" { + fmt.Fprintln(os.Stderr, "Input target Directory.\n ex) `--dir=./convert_image`") + return ExitCodeInvalidDirectoryError + } + + if _, err := os.Stat(args.Directory); os.IsNotExist(err) { + fmt.Fprintln(os.Stderr, "Target directory is not found.") + return ExitCodeInvalidDirectoryError + } + + if err := imageconverter.Convert(args); err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + return ExitCodeError + } + + return ExitCodeSuccess +} + +func main() { + os.Exit(run()) +} diff --git a/kadai1/wataboru/go.mod b/kadai1/wataboru/go.mod new file mode 100644 index 0000000..f6891db --- /dev/null +++ b/kadai1/wataboru/go.mod @@ -0,0 +1,5 @@ +module github.com/gopherdojo/dojo8/kadai1/wataboru + +go 1.14 + +require golang.org/x/image v0.0.0-20200618115811-c13761719519 diff --git a/kadai1/wataboru/go.sum b/kadai1/wataboru/go.sum new file mode 100644 index 0000000..394251b --- /dev/null +++ b/kadai1/wataboru/go.sum @@ -0,0 +1,3 @@ +golang.org/x/image v0.0.0-20200618115811-c13761719519 h1:1e2ufUJNM3lCHEY5jIgac/7UTjd6cgJNdatjPdFWf34= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/kadai1/wataboru/imageconverter/ImageConverter.go b/kadai1/wataboru/imageconverter/ImageConverter.go new file mode 100644 index 0000000..9cb7132 --- /dev/null +++ b/kadai1/wataboru/imageconverter/ImageConverter.go @@ -0,0 +1,84 @@ +package imageconverter + +import ( + "fmt" + "image" + "image/gif" + "image/jpeg" + "image/png" + "os" + "path/filepath" + "strings" + + "golang.org/x/image/bmp" + "golang.org/x/image/tiff" +) + +type Args struct { + Directory string + BeforeExtension string + AfterExtension string +} + +func convertImage(source, dest string) (err error) { + sourceFile, err := os.Open(source) + if err != nil { + return fmt.Errorf("file could not be opened. target: %s", source) + } + defer sourceFile.Close() + + destFile, err := os.Create(dest) + if err != nil { + return fmt.Errorf("image file could not be created. target: %s", dest) + } + + defer func(returnErr error) { + if returnErr == nil { + err = destFile.Close() + } + }(err) + + img, _, err := image.Decode(sourceFile) + if err != nil { + return err + } + + switch strings.ToLower(filepath.Ext(dest)) { + case ".png": + err = png.Encode(destFile, img) + case ".jpg", ".jpeg": + err = jpeg.Encode(destFile, img, &jpeg.Options{Quality: jpeg.DefaultQuality}) + case ".gif": + err = gif.Encode(destFile, img, &gif.Options{256, nil, nil}) + case ".bmp": + err = bmp.Encode(destFile, img) + case ".tiff": + err = tiff.Encode(destFile, img, nil) + default: + err = fmt.Errorf("image file could not be created due to an unknown extension. target: %s", dest) + } + + return err +} + +// 指定したディレクトリ以下のJPGファイルをPNGに変換(デフォルト) +// ディレクトリ以下は再帰的に処理する +// 変換前と変換後の画像形式を指定できる(オプション) +func Convert(args Args) error { + return filepath.Walk(args.Directory, func(path string, info os.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("prevent panic by handling failure accessing a path %q: %v\n", path, err) + } + + ext := strings.ToLower(filepath.Ext(path)) + if "."+args.BeforeExtension != ext { + return nil + } + + return convertImage(path, replaceExt(info.Name(), "."+args.AfterExtension)) + }) +} + +func replaceExt(filePath, toExt string) string { + return filePath[:len(filePath)-len(filepath.Ext(filePath))] + toExt +} diff --git a/kadai1/wataboru/testdata/free-icon.jpg b/kadai1/wataboru/testdata/free-icon.jpg new file mode 100644 index 0000000..d49627e Binary files /dev/null and b/kadai1/wataboru/testdata/free-icon.jpg differ diff --git a/kadai1/wataboru/testdata/sub/free-icon.jpg b/kadai1/wataboru/testdata/sub/free-icon.jpg new file mode 100644 index 0000000..d49627e Binary files /dev/null and b/kadai1/wataboru/testdata/sub/free-icon.jpg differ