diff --git a/kadai1/.gitkeep b/kadai2/.gitkeep similarity index 100% rename from kadai1/.gitkeep rename to kadai2/.gitkeep diff --git a/kadai2/waytkheming/.gitignore b/kadai2/waytkheming/.gitignore new file mode 100644 index 0000000..fa18208 --- /dev/null +++ b/kadai2/waytkheming/.gitignore @@ -0,0 +1,17 @@ +.DS_Store + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out +# Dependency directories (remove the comment below to include it) +# vendor/ + diff --git a/kadai2/waytkheming/README.md b/kadai2/waytkheming/README.md new file mode 100644 index 0000000..0d59e69 --- /dev/null +++ b/kadai2/waytkheming/README.md @@ -0,0 +1,16 @@ +# 課題1 + +## 次の仕様を満たすコマンドを作って下さい + +- ディレクトリを指定する +- 指定したディレクトリ以下のJPGファイルをPNGに変換(デフォルト) +- ディレクトリ以下は再帰的に処理する +- 変換前と変換後の画像形式を指定できる(オプション) + +## 以下を満たすように開発してください + +- mainパッケージと分離する +- 自作パッケージと標準パッケージと準標準パッケージのみ使う +- 準標準パッケージ:golang.org/x以下のパッケージ +- ユーザ定義型を作ってみる +- GoDocを生成してみる diff --git a/kadai2/waytkheming/cli/cli.go b/kadai2/waytkheming/cli/cli.go new file mode 100644 index 0000000..0231f18 --- /dev/null +++ b/kadai2/waytkheming/cli/cli.go @@ -0,0 +1,77 @@ +/* +このパッケージはImageconvパッケージを起動するためのパッケージになります。 + +*/ + +package cli + +// Package cli is run Image convert function + +import ( + "flag" + "fmt" + "io" + "os" + "path/filepath" + "sync" + + "github.com/waytkheming/godojo/dojo7/kadai2/waytkheming/imageconv" +) + +var ( + from, to string + wg sync.WaitGroup +) + +// Exit code. +const ( + ExitCodeOK = 0 +) + +// CLI -> cli struct +type CLI struct { + outStream, errStream io.Writer +} + +// NewCLI -> Initialize CLI +func NewCLI(outStream, errStream io.Writer) *CLI { + return &CLI{outStream: outStream, errStream: errStream} +} + +// Run -> run cli +func (c *CLI) Run(args []string) int { + flags := flag.NewFlagSet("convert", flag.ContinueOnError) + flags.SetOutput(c.errStream) + flags.StringVar(&from, "from", "jpg", + "input file format (support: jpg/png/gif, default: jpg)") + flags.StringVar(&from, "f", "jpg", + "input file format (support: jpg/png/gif, default: jpg)") + flags.StringVar(&to, "to", "png", + "output file format (support: jpg/png/gif, default: png)") + flags.StringVar(&to, "t", "png", + "output file format (support: jpg/png/gif, default: png)") + flags.Parse(args[1:]) + path := flags.Arg(0) + + converter := imageconv.NewConverter(path, from, to) + fmt.Println(converter) + err := filepath.Walk(converter.Path, converter.CrawlFile) + + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + queue := make(chan imageconv.ImageFile) + for _, image := range converter.Images { + wg.Add(1) + go converter.GetImages(queue, &wg) + queue <- image + } + + close(queue) + wg.Wait() + + return ExitCodeOK + +} diff --git a/kadai2/waytkheming/cli/cli_test.go b/kadai2/waytkheming/cli/cli_test.go new file mode 100644 index 0000000..2e501df --- /dev/null +++ b/kadai2/waytkheming/cli/cli_test.go @@ -0,0 +1,24 @@ +package cli_test + +import ( + "bytes" + "strings" + "testing" + + "github.com/waytkheming/godojo/dojo7/kadai2/waytkheming/cli" +) + +func TestCLI_Run(t *testing.T) { + outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) + c := cli.NewCLI(outStream, errStream) + args := strings.Split("convert ./../testdata/earthmap1k.jpg", " ") + exitCode := c.Run(args) + + if exitCode != cli.ExitCodeOK { + t.Errorf("failed cli run, exit_code: %d", exitCode) + } + + if errStream.Len() > 0 { + t.Errorf("failed cli run, output: %q", errStream.String()) + } +} diff --git a/kadai2/waytkheming/imageconv/image.go b/kadai2/waytkheming/imageconv/image.go new file mode 100644 index 0000000..c6bca47 --- /dev/null +++ b/kadai2/waytkheming/imageconv/image.go @@ -0,0 +1,22 @@ +package imageconv + +import ( + "path/filepath" + "regexp" +) + +//ImageFile -> Image struct +type ImageFile struct { + Path string + Name string + Format string +} + +// NewImage -> Initialize ImageFile +func NewImage(path string) ImageFile { + format := filepath.Ext(path) + rep := regexp.MustCompile(format + "$") + name := filepath.Base(rep.ReplaceAllString(path, "")) + + return ImageFile{Path: path, Name: name, Format: format} +} diff --git a/kadai2/waytkheming/imageconv/imageconv.go b/kadai2/waytkheming/imageconv/imageconv.go new file mode 100644 index 0000000..5de9ff3 --- /dev/null +++ b/kadai2/waytkheming/imageconv/imageconv.go @@ -0,0 +1,124 @@ +/* +このパッケージは、画像ファイルをpng,jpg,gifからpng,jpg,gifへ変換する機能を持っています。 + +*/ +package imageconv + +import ( + "image" + "image/gif" + "image/jpeg" + "image/png" + "io" + "os" + "path/filepath" + "strings" + "sync" +) + +// Converter -> Converter struct +type Converter struct { + Path string + Images []ImageFile + From string + To string +} + +// NewConverter -> Initialize ImageConverter +func NewConverter(path string, from string, to string) Converter { + return Converter{Path: path, From: from, To: to} +} + +// GetImages is queuing imageFile +func (c *Converter) GetImages(q chan ImageFile, wg *sync.WaitGroup) { + for { + image, more := <-q + if more { + _ = c.Convert(image) + } else { + wg.Done() + return + } + } +} + +//Convert -> Convert Image FIl +func (c *Converter) Convert(i ImageFile) error { + file, err := os.Open(i.Path) + if err != nil { + return err + } + defer file.Close() + + image, err := c.decode(file) + if err != nil { + return err + } + outFile, err := os.Create(strings.TrimSuffix(c.Path, c.From) + c.To) + if err != nil { + return err + } + defer outFile.Close() + + err = c.encode(outFile, image) + + if err != nil { + return err + } + + return nil +} + +// CrawlFile -> found image file and append Converter.Files +func (c *Converter) CrawlFile(path string, info os.FileInfo, err error) error { + if checkExtension(filepath.Ext(path)) == ("." + c.From) { + if !info.IsDir() { + c.Images = append(c.Images, NewImage(path)) + } + } + return nil +} + +func checkExtension(path string) string { + if path == ".jpeg" { + return ".jpg" + } + return path +} + +func (c *Converter) decode(file io.Reader) (image.Image, error) { + var ( + img image.Image + err error + ) + switch c.From { + case "jpeg", "jpg", "JPG", "JPEG": + img, err = jpeg.Decode(file) + case "gif", "GIF": + img, err = gif.Decode(file) + case "png", "PNG": + img, err = png.Decode(file) + } + if err != nil { + return nil, err + } + + return img, nil +} + +func (c *Converter) encode(file io.Writer, img image.Image) error { + var err error + switch c.To { + case "jpeg", "jpg", "JPG", "JPEG": + err = jpeg.Encode(file, img, nil) + case "gif", "GIF": + err = gif.Encode(file, img, nil) + case "png", "PNG": + err = png.Encode(file, img) + } + if err != nil { + return err + } + + return nil +} diff --git a/kadai2/waytkheming/imageconv/imageconv_test.go b/kadai2/waytkheming/imageconv/imageconv_test.go new file mode 100644 index 0000000..8a57c3c --- /dev/null +++ b/kadai2/waytkheming/imageconv/imageconv_test.go @@ -0,0 +1,119 @@ +package imageconv_test + +import ( + "image/gif" + "image/jpeg" + "image/png" + "os" + "path/filepath" + "testing" + + "github.com/waytkheming/godojo/dojo7/kadai2/waytkheming/imageconv" +) + +type testCase struct { + title string + path string + from string + to string + output string +} + +func TestConvert(t *testing.T) { + var testFixtures = []testCase{ + { + title: "jpg to png", + path: "../testdata/earthmap1k.jpg", + from: "jpg", + to: "png", + output: "../testdata/earthmap1k.png", + }, + { + title: "png to jpg", + path: "../testdata/earthmap1k.png", + from: "png", + to: "jpg", + output: "../testdata/earthmap1k.jpg", + }, + { + title: "jpg to gif", + path: "../testdata/earthmap1k.jpg", + from: "jpg", + to: "gif", + output: "../testdata/earthmap1k.gif", + }, + { + title: "png to gif", + path: "../testdata/earthmap1k.png", + from: "png", + to: "gif", + output: "../testdata/earthmap1k.gif", + }, + { + title: "gif to jpg", + path: "../testdata/earthmap1k.gif", + from: "gif", + to: "jpg", + output: "../testdata/earthmap1k.jpg", + }, + { + title: "gif to png", + path: "../testdata/earthmap1k.gif", + from: "gif", + to: "png", + output: "../testdata/earthmap1k.png", + }, + } + for _, testFixture := range testFixtures { + c := imageconv.NewConverter(testFixture.path, testFixture.from, testFixture.to) + i := imageconv.NewImage(testFixture.path) + t.Run("Check walk", func(t *testing.T) { + checkWalk(t, c) + }) + t.Run("Check convert", func(t *testing.T) { + checkConvert(t, c, i) + }) + t.Run("Check format", func(t *testing.T) { + checkFormat(t, testFixture.output, testFixture.to) + }) + } +} + +func checkWalk(t *testing.T, c imageconv.Converter) { + t.Helper() + if err := filepath.Walk(c.Path, c.CrawlFile); err != nil { + t.Errorf("Error: %s", err) + } +} + +func checkConvert(t *testing.T, c imageconv.Converter, i imageconv.ImageFile) { + t.Helper() + if err := c.Convert(i); err != nil { + t.Errorf("Error: %s", err) + } +} + +func checkFormat(t *testing.T, path string, to string) { + t.Helper() + if _, err := os.Stat(path); os.IsNotExist(err) { + t.Errorf("Expected output file %s %s is not exist", path, err.Error()) + } + file, err := os.Open(path) + if err != nil { + t.Errorf("Couldn't open file path: %s, fileType: %s, error: %v", path, to, err) + } + defer file.Close() + + switch to { + case "jpg", "jpeg": + _, err = jpeg.Decode(file) + case "png": + _, err = png.Decode(file) + case "gif": + _, err = gif.Decode(file) + } + + if err != nil { + t.Errorf("Couldn't decode path: %s, fileType: %s, error: %v", path, to, err) + } +} diff --git a/kadai2/waytkheming/main.go b/kadai2/waytkheming/main.go new file mode 100644 index 0000000..4002934 --- /dev/null +++ b/kadai2/waytkheming/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "fmt" + "os" + + "github.com/waytkheming/godojo/dojo7/kadai2/waytkheming/cli" +) + +func main() { + fmt.Println("Start running CLI...") + cli := cli.NewCLI(os.Stdout, os.Stderr) + os.Exit(cli.Run(os.Args)) +} diff --git a/kadai2/waytkheming/screenshots/godoc-cli-pkg.png b/kadai2/waytkheming/screenshots/godoc-cli-pkg.png new file mode 100644 index 0000000..45ae222 Binary files /dev/null and b/kadai2/waytkheming/screenshots/godoc-cli-pkg.png differ diff --git a/kadai2/waytkheming/screenshots/godoc-imageconv-pkg.png b/kadai2/waytkheming/screenshots/godoc-imageconv-pkg.png new file mode 100644 index 0000000..03c8aa5 Binary files /dev/null and b/kadai2/waytkheming/screenshots/godoc-imageconv-pkg.png differ diff --git a/kadai2/waytkheming/testdata/earthmap1k.gif b/kadai2/waytkheming/testdata/earthmap1k.gif new file mode 100644 index 0000000..47f02d2 Binary files /dev/null and b/kadai2/waytkheming/testdata/earthmap1k.gif differ diff --git a/kadai2/waytkheming/testdata/earthmap1k.jpg b/kadai2/waytkheming/testdata/earthmap1k.jpg new file mode 100644 index 0000000..ea451d4 Binary files /dev/null and b/kadai2/waytkheming/testdata/earthmap1k.jpg differ diff --git a/kadai2/waytkheming/testdata/earthmap1k.png b/kadai2/waytkheming/testdata/earthmap1k.png new file mode 100644 index 0000000..6836eb5 Binary files /dev/null and b/kadai2/waytkheming/testdata/earthmap1k.png differ