From 5a2e5ae64bdace83f040262efdd45e1180509aeb Mon Sep 17 00:00:00 2001 From: moritakee Date: Sun, 19 Sep 2021 16:01:34 +0900 Subject: [PATCH 1/5] first commit --- kadai1/README.md | 16 ++++++ kadai1/cli/cli.go | 98 +++++++++++++++++++++++++++++++++++ kadai1/converter/converter.go | 91 ++++++++++++++++++++++++++++++++ kadai1/go.mod | 3 ++ kadai1/main.go | 15 ++++++ 5 files changed, 223 insertions(+) create mode 100644 kadai1/README.md create mode 100644 kadai1/cli/cli.go create mode 100644 kadai1/converter/converter.go create mode 100644 kadai1/go.mod create mode 100644 kadai1/main.go diff --git a/kadai1/README.md b/kadai1/README.md new file mode 100644 index 00000000..ad266275 --- /dev/null +++ b/kadai1/README.md @@ -0,0 +1,16 @@ +# 画像変換コマンド + +## 次の仕様を満たすコマンドを作ってください + +- ディレクトリを指定する +- 指定したディレクトリ以下の JPG ファイルを PNG に変換(デフォルト) +- ディレクトリ以下は再帰的に処理する +- 変換前と変換後の画像形式を指定できる(オプション) + +## 以下を満たすように開発してください + +- main パッケージと分離する +- 自作パッケージと標準パッケージと準標準パッケージのみ使う +- ユーザ定義型を作ってみる +- GoDoc を生成してみる +- Go Modules を使ってみる diff --git a/kadai1/cli/cli.go b/kadai1/cli/cli.go new file mode 100644 index 00000000..0f2ea26e --- /dev/null +++ b/kadai1/cli/cli.go @@ -0,0 +1,98 @@ +package cli + +import ( + "flag" + "fmt" + + "io" + "io/fs" + "path/filepath" + + "github.com/kynefuk/gopherdojo-studyroom/kadai1/converter" +) + +const ( + ExitOk = 0 + ExitErr = 1 +) + +type CLI struct { + OutStream io.Writer + ErrStream io.Writer +} + +func (c *CLI) Run(args []string) int { + var ( + targetDir string + fromExt string + toExt string + ) + + flags := flag.NewFlagSet("image-convert", flag.ContinueOnError) + flags.SetOutput(c.ErrStream) + flags.Usage = func() { + fmt.Fprintf(c.ErrStream, helpText) + } + + flags.StringVar(&targetDir, "d", "", "specify target directory") + flags.StringVar(&fromExt, "f", converter.ExtJPG, "specify \"fromExt\"") + flags.StringVar(&toExt, "t", converter.ExtPNG, "specify \"toExt\"") + + if err := flags.Parse(args[1:]); err != nil { + fmt.Printf("failed to parse flags: %v", err) + return ExitErr + } + + // 指定された拡張子が変換可能かチェック + if ok := converter.IsConvertible(fromExt); !ok { + fmt.Printf("fromExt format is not convertible: %v\n", fromExt) + return ExitErr + } + + if ok := converter.IsConvertible(toExt); !ok { + fmt.Printf("toExt format is not convertible: %v\n", toExt) + return ExitErr + } + + // 指定されたディレクトリをWalkして、fromExtの拡張子に該当する画像ファイルをスライスに入れる + var targetFiles []string + err := filepath.WalkDir(targetDir, func(path string, d fs.DirEntry, err error) error { + if err != nil { + fmt.Printf("prevent panic by handling failure accessing a path %q, error: %v\n", path, err) + return err + } + + if ext := filepath.Ext(path); ext == fromExt { + targetFiles = append(targetFiles, path) + return nil + } + return nil + }) + + if err != nil { + fmt.Printf("failed to walk dir: %v\n", err) + return ExitErr + } + + // スライスの中身を1つずつ変換する + for _, f := range targetFiles { + con := converter.Converter{FromExt: fromExt, ToExt: toExt, TargetFilePath: f} + + if err := con.Convert(); err != nil { + fmt.Printf("failed to convert: %v\n", err) + continue + } + } + return ExitOk +} + +var helpText = `Usage: image-convert [options...] +image-convert +Options: +-d + specify target dir in which images will be converted +-f + specify image ext which convert from +-t + specify image ext which convert to +` diff --git a/kadai1/converter/converter.go b/kadai1/converter/converter.go new file mode 100644 index 00000000..09898a92 --- /dev/null +++ b/kadai1/converter/converter.go @@ -0,0 +1,91 @@ +package converter + +import ( + "fmt" + "image" + "image/gif" + "image/jpeg" + "image/png" + "os" + "strings" +) + +// Ext codes represents convertible file ext. +const ( + ExtJPG = ".jpg" + ExtJPEG = ".jpeg" + ExtPNG = ".png" + ExtGIF = ".gif" +) + +// IsConvertible check ext is convertible. +func IsConvertible(ext string) bool { + switch ext { + case ExtJPG, ExtJPEG, ExtPNG, ExtGIF: + return true + default: + return false + } +} + +// Converter converts image ext. +type Converter struct { + FromExt string + ToExt string + TargetFilePath string +} + +// Convert is main funf of Convert +func (con *Converter) Convert() error { + var err error + reader, err := os.Open(con.TargetFilePath) + if err != nil { + fmt.Printf("failed to open file: %v. error: %v", con.TargetFilePath, err) + return err + } + defer reader.Close() + + // decode + var img image.Image + + switch con.FromExt { + case ExtJPG, ExtJPEG: + img, err = jpeg.Decode(reader) + case ExtPNG: + img, err = png.Decode(reader) + case ExtGIF: + img, err = gif.Decode(reader) + } + + if err != nil { + fmt.Printf("failed to decode: %v\n", err) + return err + } + + // create dist file + fileName := strings.Replace(con.TargetFilePath, con.FromExt, con.ToExt, 1) + dist, err := os.Create(fileName) + if err != nil { + return err + } + defer func() { + if err := dist.Close(); err != nil { + fmt.Printf("failed to close file: %v\n", err) + } + }() + + // encode + switch con.ToExt { + case ExtJPG, ExtJPEG: + err = jpeg.Encode(dist, img, &jpeg.Options{}) + case ExtPNG: + err = png.Encode(dist, img) + case ExtGIF: + err = gif.Encode(dist, img, &gif.Options{}) + } + + if err != nil { + return err + } + return nil +} diff --git a/kadai1/go.mod b/kadai1/go.mod new file mode 100644 index 00000000..0e6642be --- /dev/null +++ b/kadai1/go.mod @@ -0,0 +1,3 @@ +module github.com/kynefuk/gopherdojo-studyroom/kadai1 + +go 1.17 diff --git a/kadai1/main.go b/kadai1/main.go new file mode 100644 index 00000000..12f9b267 --- /dev/null +++ b/kadai1/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "os" + + "github.com/kynefuk/gopherdojo-studyroom/kadai1/cli" +) + +func main() { + cli := cli.CLI{ + OutStream: os.Stdout, + ErrStream: os.Stderr, + } + os.Exit(cli.Run(os.Args)) +} From 648cf3bf794b1cb67d4db2bd591ad88327f2f426 Mon Sep 17 00:00:00 2001 From: moritakee Date: Sun, 19 Sep 2021 16:14:48 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kadai1/cli/cli.go | 24 +++++++++++------------- kadai1/converter/converter.go | 21 +++++++++++---------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/kadai1/cli/cli.go b/kadai1/cli/cli.go index 0f2ea26e..52f519ee 100644 --- a/kadai1/cli/cli.go +++ b/kadai1/cli/cli.go @@ -11,16 +11,19 @@ import ( "github.com/kynefuk/gopherdojo-studyroom/kadai1/converter" ) +// Exit codes are values that represents an exit code const ( ExitOk = 0 ExitErr = 1 ) +// CLI is a struct of cli type CLI struct { OutStream io.Writer ErrStream io.Writer } +// Run is a main func of CLI func (c *CLI) Run(args []string) int { var ( targetDir string @@ -28,22 +31,17 @@ func (c *CLI) Run(args []string) int { toExt string ) - flags := flag.NewFlagSet("image-convert", flag.ContinueOnError) - flags.SetOutput(c.ErrStream) - flags.Usage = func() { + flag.CommandLine.SetOutput(c.ErrStream) + flag.Usage = func() { fmt.Fprintf(c.ErrStream, helpText) } - flags.StringVar(&targetDir, "d", "", "specify target directory") - flags.StringVar(&fromExt, "f", converter.ExtJPG, "specify \"fromExt\"") - flags.StringVar(&toExt, "t", converter.ExtPNG, "specify \"toExt\"") + flag.StringVar(&targetDir, "d", "", "specify target directory") + flag.StringVar(&fromExt, "f", converter.ExtJPG, "specify \"fromExt\"") + flag.StringVar(&toExt, "t", converter.ExtPNG, "specify \"toExt\"") - if err := flags.Parse(args[1:]); err != nil { - fmt.Printf("failed to parse flags: %v", err) - return ExitErr - } + flag.Parse() - // 指定された拡張子が変換可能かチェック if ok := converter.IsConvertible(fromExt); !ok { fmt.Printf("fromExt format is not convertible: %v\n", fromExt) return ExitErr @@ -54,7 +52,7 @@ func (c *CLI) Run(args []string) int { return ExitErr } - // 指定されたディレクトリをWalkして、fromExtの拡張子に該当する画像ファイルをスライスに入れる + // walking directory to collect target image files var targetFiles []string err := filepath.WalkDir(targetDir, func(path string, d fs.DirEntry, err error) error { if err != nil { @@ -74,7 +72,7 @@ func (c *CLI) Run(args []string) int { return ExitErr } - // スライスの中身を1つずつ変換する + // converting for _, f := range targetFiles { con := converter.Converter{FromExt: fromExt, ToExt: toExt, TargetFilePath: f} diff --git a/kadai1/converter/converter.go b/kadai1/converter/converter.go index 09898a92..80d645bf 100644 --- a/kadai1/converter/converter.go +++ b/kadai1/converter/converter.go @@ -10,7 +10,7 @@ import ( "strings" ) -// Ext codes represents convertible file ext. +// Ext codes represents convertible file ext const ( ExtJPG = ".jpg" ExtJPEG = ".jpeg" @@ -18,7 +18,7 @@ const ( ExtGIF = ".gif" ) -// IsConvertible check ext is convertible. +// IsConvertible check that specified ext is convertible func IsConvertible(ext string) bool { switch ext { case ExtJPG, ExtJPEG, ExtPNG, ExtGIF: @@ -28,19 +28,20 @@ func IsConvertible(ext string) bool { } } -// Converter converts image ext. +// Converter is ... type Converter struct { FromExt string ToExt string TargetFilePath string } -// Convert is main funf of Convert -func (con *Converter) Convert() error { +// Convert is a main func of image convert +func (c *Converter) Convert() error { var err error - reader, err := os.Open(con.TargetFilePath) + + reader, err := os.Open(c.TargetFilePath) if err != nil { - fmt.Printf("failed to open file: %v. error: %v", con.TargetFilePath, err) + fmt.Printf("failed to open file: %v. error: %v", c.TargetFilePath, err) return err } defer reader.Close() @@ -48,7 +49,7 @@ func (con *Converter) Convert() error { // decode var img image.Image - switch con.FromExt { + switch c.FromExt { case ExtJPG, ExtJPEG: img, err = jpeg.Decode(reader) case ExtPNG: @@ -63,7 +64,7 @@ func (con *Converter) Convert() error { } // create dist file - fileName := strings.Replace(con.TargetFilePath, con.FromExt, con.ToExt, 1) + fileName := strings.Replace(c.TargetFilePath, c.FromExt, c.ToExt, 1) dist, err := os.Create(fileName) if err != nil { return err @@ -75,7 +76,7 @@ func (con *Converter) Convert() error { }() // encode - switch con.ToExt { + switch c.ToExt { case ExtJPG, ExtJPEG: err = jpeg.Encode(dist, img, &jpeg.Options{}) case ExtPNG: From e343157cb26f618111e2d80ac639c7a1914056f1 Mon Sep 17 00:00:00 2001 From: moritakee Date: Sun, 19 Sep 2021 16:17:24 +0900 Subject: [PATCH 3/5] =?UTF-8?q?README=E3=82=92=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kadai1/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kadai1/README.md b/kadai1/README.md index ad266275..083aeea4 100644 --- a/kadai1/README.md +++ b/kadai1/README.md @@ -14,3 +14,9 @@ - ユーザ定義型を作ってみる - GoDoc を生成してみる - Go Modules を使ってみる + +## 使い方 + +``` +go run main.go -d [ディレクトリ] -f [変換前の拡張子] -t [変換後の拡張子] +``` From 9d63cd1909df3f59e8fda2f1e5299f261e7440a6 Mon Sep 17 00:00:00 2001 From: moritakee Date: Sun, 19 Sep 2021 16:26:52 +0900 Subject: [PATCH 4/5] =?UTF-8?q?README=E3=82=92=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kadai1/README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/kadai1/README.md b/kadai1/README.md index 083aeea4..b5cf9506 100644 --- a/kadai1/README.md +++ b/kadai1/README.md @@ -17,6 +17,28 @@ ## 使い方 +### ビルドして使う場合 + +- ビルド + +``` +go build -o image-converter +``` + +- 例 + +``` +image-converter -d sample -f .png -t .jpg +``` + +### ビルドしない場合 + ``` go run main.go -d [ディレクトリ] -f [変換前の拡張子] -t [変換後の拡張子] ``` + +- 例 + +``` +go run main.go -d sample -f .png -t .jpg +``` From 8d59178a9666065be3af6b9bcefdd8c7581c9b7e Mon Sep 17 00:00:00 2001 From: moritakee Date: Sat, 9 Oct 2021 19:08:04 +0900 Subject: [PATCH 5/5] =?UTF-8?q?.gitignore=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kadai1/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 kadai1/.gitignore diff --git a/kadai1/.gitignore b/kadai1/.gitignore new file mode 100644 index 00000000..808d8dca --- /dev/null +++ b/kadai1/.gitignore @@ -0,0 +1,2 @@ +image-converter +images/** \ No newline at end of file