diff --git a/kadai1/edm20627/.gitignore b/kadai1/edm20627/.gitignore new file mode 100644 index 00000000..6ecd33cb --- /dev/null +++ b/kadai1/edm20627/.gitignore @@ -0,0 +1,17 @@ +# 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/ + +.DS_store diff --git a/kadai1/edm20627/README.md b/kadai1/edm20627/README.md new file mode 100644 index 00000000..789cb3e5 --- /dev/null +++ b/kadai1/edm20627/README.md @@ -0,0 +1,12 @@ +# 画像変換コマンド +指定ディレクトリ以下の画像ファイルを変換します。 + +## 使用方法 + +`cmd --from jpg --to png ディレクトリ` + +## オプション + +* `--from(-f)` 変換対象の画像形式(デフォルト: jpg) +* `--to(-t)` 変換後の画像形式(デフォルト: png) +* `--delete(-d)` 変換前の画像を削除(デフォルト: 無効) diff --git a/kadai1/edm20627/go.mod b/kadai1/edm20627/go.mod new file mode 100644 index 00000000..02e3b462 --- /dev/null +++ b/kadai1/edm20627/go.mod @@ -0,0 +1,3 @@ +module github.com/edm20627/gopherdojo-studyroom/kadai1/edm20627 + +go 1.15 diff --git a/kadai1/edm20627/imageconvert/imageconvert.go b/kadai1/edm20627/imageconvert/imageconvert.go new file mode 100644 index 00000000..f8817128 --- /dev/null +++ b/kadai1/edm20627/imageconvert/imageconvert.go @@ -0,0 +1,108 @@ +package imageconvert + +import ( + "errors" + "image" + "image/gif" + "image/jpeg" + "image/png" + "os" + "path/filepath" +) + +// Supported extensions. +var SupportedFormat = []string{"png", "jpg", "jpeg", "gif"} + +type ConvertImage struct { + filepaths []string + From, To string + DeleteOption bool +} + +// Get the target files for image conversion. +func (ci *ConvertImage) Get(dirs []string) error { + for _, dir := range dirs { + err := filepath.Walk(dir, + func(path string, info os.FileInfo, err error) error { + if info == nil { + return errors.New(path + " is not directory") + } + if info.IsDir() || filepath.Ext(path)[1:] != ci.From { + return nil + } + ci.filepaths = append(ci.filepaths, path) + return nil + }) + if err != nil { + return err + } + } + return nil +} + +// Perform image conversion. +func (ci *ConvertImage) Convert() error { + for _, path := range ci.filepaths { + err := convert(path, ci.To, ci.DeleteOption) + if err != nil { + return err + } + } + return nil +} + +// Check for supported extensions. +func (ci *ConvertImage) Valid() bool { + for _, v := range SupportedFormat { + if v == ci.From { + for _, v := range SupportedFormat { + if v == ci.To { + return true + } + } + } + } + return false +} + +func convert(path string, to string, deleteOption bool) error { + f, err := os.Open(path) + if err != nil { + return err + } + defer f.Close() + + img, _, err := image.Decode(f) + if err != nil { + return err + } + + out, err := os.Create(path[:len(path)-len(filepath.Ext(path))+1] + to) + if err != nil { + return err + } + defer out.Close() + + switch to { + case "png": + if err := png.Encode(out, img); err != nil { + return err + } + case "jpg", "jpeg": + if err := jpeg.Encode(out, img, nil); err != nil { + return err + } + case "gif": + if err := gif.Encode(out, img, nil); err != nil { + return err + } + } + + if deleteOption { + if err := os.Remove(path); err != nil { + return err + } + } + + return nil +} diff --git a/kadai1/edm20627/main.go b/kadai1/edm20627/main.go new file mode 100644 index 00000000..407d2409 --- /dev/null +++ b/kadai1/edm20627/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/edm20627/gopherdojo-studyroom/kadai1/edm20627/imageconvert" +) + +var ci = imageconvert.ConvertImage{} + +func init() { + flag.StringVar(&ci.From, "-from", "jpg", "Specify the image format before conversion") + flag.StringVar(&ci.From, "f", "jpg", "Specify the image format before conversion (short)") + flag.StringVar(&ci.To, "-to", "png", "Specify the converted image format") + flag.StringVar(&ci.To, "t", "png", "Specify the converted image format (short)") + flag.BoolVar(&ci.DeleteOption, "-delete", false, "Delete the image before conversion") + flag.BoolVar(&ci.DeleteOption, "d", false, "Delete the image before conversion (short)") +} + +func main() { + flag.Parse() + dirs := flag.Args() + + if !ci.Valid() { + fmt.Fprintln(os.Stderr, "supported formt is "+strings.Join(imageconvert.SupportedFormat, ", ")) + os.Exit(1) + } + + err := ci.Get(dirs) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + err = ci.Convert() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/kadai1/edm20627/sample_image/hoge/sample3.png b/kadai1/edm20627/sample_image/hoge/sample3.png new file mode 100644 index 00000000..02908b23 Binary files /dev/null and b/kadai1/edm20627/sample_image/hoge/sample3.png differ diff --git a/kadai1/edm20627/sample_image/hoge/sample4.png b/kadai1/edm20627/sample_image/hoge/sample4.png new file mode 100644 index 00000000..fc271cd8 Binary files /dev/null and b/kadai1/edm20627/sample_image/hoge/sample4.png differ diff --git a/kadai1/edm20627/sample_image/sample.jpg b/kadai1/edm20627/sample_image/sample.jpg new file mode 100644 index 00000000..dc98d757 Binary files /dev/null and b/kadai1/edm20627/sample_image/sample.jpg differ diff --git a/kadai1/edm20627/sample_image/sample2.jpg b/kadai1/edm20627/sample_image/sample2.jpg new file mode 100644 index 00000000..83932905 Binary files /dev/null and b/kadai1/edm20627/sample_image/sample2.jpg differ diff --git a/kadai2/edm20627/.gitignore b/kadai2/edm20627/.gitignore new file mode 100644 index 00000000..6ecd33cb --- /dev/null +++ b/kadai2/edm20627/.gitignore @@ -0,0 +1,17 @@ +# 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/ + +.DS_store diff --git a/kadai2/edm20627/README.md b/kadai2/edm20627/README.md new file mode 100644 index 00000000..789cb3e5 --- /dev/null +++ b/kadai2/edm20627/README.md @@ -0,0 +1,12 @@ +# 画像変換コマンド +指定ディレクトリ以下の画像ファイルを変換します。 + +## 使用方法 + +`cmd --from jpg --to png ディレクトリ` + +## オプション + +* `--from(-f)` 変換対象の画像形式(デフォルト: jpg) +* `--to(-t)` 変換後の画像形式(デフォルト: png) +* `--delete(-d)` 変換前の画像を削除(デフォルト: 無効) diff --git a/kadai2/edm20627/go.mod b/kadai2/edm20627/go.mod new file mode 100644 index 00000000..91235c33 --- /dev/null +++ b/kadai2/edm20627/go.mod @@ -0,0 +1,3 @@ +module github.com/edm20627/gopherdojo-studyroom/kadai2/edm20627 + +go 1.15 diff --git a/kadai2/edm20627/go.sum b/kadai2/edm20627/go.sum new file mode 100644 index 00000000..25c5d358 --- /dev/null +++ b/kadai2/edm20627/go.sum @@ -0,0 +1 @@ +github.com/edm20627/gopherdojo-studyroom v0.0.0-20200808023015-dd3cfe05cf7a h1:qrHQJOIqb8bC1Ulkv5H6eGp3DZgRA93eLUJr6XK/Gjk= diff --git a/kadai2/edm20627/imageconvert/imageconvert.go b/kadai2/edm20627/imageconvert/imageconvert.go new file mode 100644 index 00000000..775ccee3 --- /dev/null +++ b/kadai2/edm20627/imageconvert/imageconvert.go @@ -0,0 +1,117 @@ +package imageconvert + +import ( + "errors" + "image" + "image/gif" + "image/jpeg" + "image/png" + "os" + "path/filepath" +) + +// Supported extensions. +var SupportedFormat = []string{"png", "jpg", "jpeg", "gif"} + +var ( + ErrNotSpecified = errors.New("Need to specify directory or file") + ErrNotDirectory = errors.New("Specify directory or file is not directory") +) + +type ConvertImage struct { + Filepaths []string + From, To string + DeleteOption bool +} + +// Get the target files for image conversion. +func (ci *ConvertImage) Get(dirs []string) error { + if len(dirs) == 0 { + return ErrNotSpecified + } + + for _, dir := range dirs { + err := filepath.Walk(dir, + func(path string, info os.FileInfo, err error) error { + if info == nil { + return ErrNotDirectory + } + if info.IsDir() || filepath.Ext(path)[1:] != ci.From { + return nil + } + ci.Filepaths = append(ci.Filepaths, path) + return nil + }) + if err != nil { + return err + } + } + return nil +} + +// Perform image conversion. +func (ci *ConvertImage) Convert() error { + for _, path := range ci.Filepaths { + err := convert(path, ci.To, ci.DeleteOption) + if err != nil { + return err + } + } + return nil +} + +// Check for supported extensions. +func (ci *ConvertImage) Valid() bool { + var fromSupported, toSupported bool + for _, v := range SupportedFormat { + if v == ci.From { + fromSupported = true + } + if v == ci.To { + toSupported = true + } + } + return fromSupported && toSupported +} + +func convert(path string, to string, deleteOption bool) error { + f, err := os.Open(path) + if err != nil { + return err + } + defer f.Close() + + img, _, err := image.Decode(f) + if err != nil { + return err + } + + out, err := os.Create(path[:len(path)-len(filepath.Ext(path))+1] + to) + if err != nil { + return err + } + defer out.Close() + + switch to { + case "png": + if err := png.Encode(out, img); err != nil { + return err + } + case "jpg", "jpeg": + if err := jpeg.Encode(out, img, nil); err != nil { + return err + } + case "gif": + if err := gif.Encode(out, img, nil); err != nil { + return err + } + } + + if deleteOption { + if err := os.Remove(path); err != nil { + return err + } + } + + return nil +} diff --git a/kadai2/edm20627/imageconvert/imageconvert_test.go b/kadai2/edm20627/imageconvert/imageconvert_test.go new file mode 100644 index 00000000..c7ac1d2f --- /dev/null +++ b/kadai2/edm20627/imageconvert/imageconvert_test.go @@ -0,0 +1,215 @@ +package imageconvert_test + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "path" + "reflect" + "strings" + "testing" + + "github.com/edm20627/gopherdojo-studyroom/kadai2/edm20627/imageconvert" +) + +func TestGet(t *testing.T) { + success_cases := []struct { + name string + dirs []string + filepaths []string + from string + expected []string + }{ + {name: "get jpg", dirs: []string{"../testdata"}, from: "jpg", expected: []string{"../testdata/hoge/img_1.jpg", "../testdata/img_1.jpg"}}, + {name: "get png", dirs: []string{"../testdata"}, from: "png", expected: []string{"../testdata/hoge/img_2.png", "../testdata/img_2.png"}}, + {name: "get gif", dirs: []string{"../testdata"}, from: "gif", expected: []string{"../testdata/hoge/img_3.gif", "../testdata/img_3.gif"}}, + } + + for _, c := range success_cases { + t.Run(c.name, func(t *testing.T) { + ci := imageconvert.ConvertImage{From: c.from} + if err := ci.Get(c.dirs); err != nil { + t.Error(err) + } + if !reflect.DeepEqual(ci.Filepaths, c.expected) { + t.Errorf("want %v, got %v", c.expected, ci.Filepaths) + } + }) + } + + failure_cases := []struct { + name string + dirs []string + filepaths []string + from string + expected error + }{ + {name: "occurred ErrNotSpecified", dirs: []string{}, from: "jpg", expected: imageconvert.ErrNotSpecified}, + {name: "occurred ErrNotDirectory", dirs: []string{"../non_testdata"}, from: "jpg", expected: imageconvert.ErrNotDirectory}, + } + + for _, c := range failure_cases { + t.Run(c.name, func(t *testing.T) { + ci := imageconvert.ConvertImage{From: c.from} + if err := ci.Get(c.dirs); err != c.expected { + t.Errorf("want %v, got %v", c.expected, err) + } + }) + } +} + +func TestConvert(t *testing.T) { + // テスト実行ディレクトリを作成するためにtastdataをコピー + targetDir := "../test_execution_dir" + if err := testDirCopy(t, "../testdata", targetDir); err != nil { + t.Fatal("Failed to copy the test directory") + } + + cases := []struct { + name string + filepaths []string + from string + to string + deleteOption bool + }{ + {name: "jpg to png(deleteOption: false)", filepaths: []string{targetDir + "/img_1.jpg"}, from: "jpg", to: "png", deleteOption: false}, + {name: "png to gif(deleteOption: false)", filepaths: []string{targetDir + "/img_2.png"}, from: "png", to: "gif", deleteOption: false}, + {name: "gif to jpg(deleteOption: false)", filepaths: []string{targetDir + "/img_3.gif"}, from: "gif", to: "jpg", deleteOption: false}, + {name: "jpg to png(deleteOption: true)", filepaths: []string{targetDir + "/img_1.jpg"}, from: "jpg", to: "png", deleteOption: true}, + {name: "png to gif(deleteOption: true)", filepaths: []string{targetDir + "/img_2.png"}, from: "png", to: "gif", deleteOption: true}, + {name: "gif to jpg(deleteOption: true)", filepaths: []string{targetDir + "/img_3.gif"}, from: "gif", to: "jpg", deleteOption: true}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + + ci := imageconvert.ConvertImage{Filepaths: c.filepaths, To: c.to, DeleteOption: c.deleteOption} + if actual := ci.Convert(); actual != nil { + t.Error(actual) + } + + // ファイルのありなしを確認 + for _, fileName := range c.filepaths { + // 変換前ファイル + _, err := os.Stat(fileName) + if (err == nil) == c.deleteOption { + t.Fatal(err) + } + + // 変換後ファイル + targetFileName := strings.Replace(fileName, c.from, c.to, 1) + _, err = os.Stat(targetFileName) + if err != nil { + t.Fatal(err) + } + } + + for _, filepath := range c.filepaths { + targetFile := strings.Replace(filepath, c.from, c.to, 1) + if err := os.Remove(targetFile); err != nil { + t.Fatal(err) + } + } + }) + } + + // テスト実行ディレクトリを削除 + if err := os.RemoveAll(targetDir); err != nil { + fmt.Println(err) + } +} + +func TestValid(t *testing.T) { + cases := []struct { + name string + from string + to string + expected bool + }{ + {name: "jpg to png (true to true)", from: "jpg", to: "png", expected: true}, + {name: "png to jpg (true to true)", from: "png", to: "jpg", expected: true}, + {name: "jpeg to gif (true to true)", from: "jpeg", to: "gif", expected: true}, + {name: "gif to jpeg (true to true)", from: "gif", to: "jpeg", expected: true}, + {name: "jpg to fuga (true to false)", from: "jpg", to: "fuga", expected: false}, + {name: "hoge to jpg (false to true)", from: "hoge", to: "jpg", expected: false}, + {name: "hoge to fuga (false to false)", from: "hoge", to: "fuga", expected: false}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + ci := imageconvert.ConvertImage{From: c.from, To: c.to} + if actual := ci.Valid(); c.expected != actual { + t.Errorf("want %v, got %v", c.expected, actual) + } + }) + } +} + +func testDirCopy(t *testing.T, src string, dst string) error { + t.Helper() + var err error + var fds []os.FileInfo + var srcinfo os.FileInfo + + if srcinfo, err = os.Stat(src); err != nil { + t.Error(err) + } + + if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil { + t.Error(err) + + } + + if fds, err = ioutil.ReadDir(src); err != nil { + t.Error(err) + + } + + for _, fd := range fds { + srcfp := path.Join(src, fd.Name()) + dstfp := path.Join(dst, fd.Name()) + + if fd.IsDir() { + if err = testDirCopy(t, srcfp, dstfp); err != nil { + t.Error(err) + + } + } else { + if err = testFileCopy(t, srcfp, dstfp); err != nil { + t.Error(err) + + } + } + } + + return nil +} + +func testFileCopy(t *testing.T, src, dst string) error { + t.Helper() + var err error + var srcfd *os.File + var dstfd *os.File + var srcinfo os.FileInfo + + if srcfd, err = os.Open(src); err != nil { + t.Error(err) + } + defer srcfd.Close() + + if dstfd, err = os.Create(dst); err != nil { + t.Error(err) + } + defer dstfd.Close() + + if _, err = io.Copy(dstfd, srcfd); err != nil { + t.Error(err) + } + + if srcinfo, err = os.Stat(src); err != nil { + t.Error(err) + } + + return os.Chmod(dst, srcinfo.Mode()) +} diff --git a/kadai2/edm20627/main.go b/kadai2/edm20627/main.go new file mode 100644 index 00000000..1bdb38bb --- /dev/null +++ b/kadai2/edm20627/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/edm20627/gopherdojo-studyroom/kadai2/edm20627/imageconvert" +) + +var ci = imageconvert.ConvertImage{} + +func init() { + flag.StringVar(&ci.From, "-from", "jpg", "Specify the image format before conversion") + flag.StringVar(&ci.From, "f", "jpg", "Specify the image format before conversion (short)") + flag.StringVar(&ci.To, "-to", "png", "Specify the converted image format") + flag.StringVar(&ci.To, "t", "png", "Specify the converted image format (short)") + flag.BoolVar(&ci.DeleteOption, "-delete", false, "Delete the image before conversion") + flag.BoolVar(&ci.DeleteOption, "d", false, "Delete the image before conversion (short)") +} + +func main() { + flag.Parse() + dirs := flag.Args() + + if !ci.Valid() { + fmt.Fprintln(os.Stderr, "supported formt is "+strings.Join(imageconvert.SupportedFormat, ", ")) + os.Exit(1) + } + + err := ci.Get(dirs) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + err = ci.Convert() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/kadai2/edm20627/sample_image/hoge/sample3.png b/kadai2/edm20627/sample_image/hoge/sample3.png new file mode 100644 index 00000000..02908b23 Binary files /dev/null and b/kadai2/edm20627/sample_image/hoge/sample3.png differ diff --git a/kadai2/edm20627/sample_image/hoge/sample4.png b/kadai2/edm20627/sample_image/hoge/sample4.png new file mode 100644 index 00000000..fc271cd8 Binary files /dev/null and b/kadai2/edm20627/sample_image/hoge/sample4.png differ diff --git a/kadai2/edm20627/sample_image/sample.jpg b/kadai2/edm20627/sample_image/sample.jpg new file mode 100644 index 00000000..dc98d757 Binary files /dev/null and b/kadai2/edm20627/sample_image/sample.jpg differ diff --git a/kadai2/edm20627/sample_image/sample2.jpg b/kadai2/edm20627/sample_image/sample2.jpg new file mode 100644 index 00000000..83932905 Binary files /dev/null and b/kadai2/edm20627/sample_image/sample2.jpg differ diff --git a/kadai2/edm20627/testdata/hoge/img_1.jpg b/kadai2/edm20627/testdata/hoge/img_1.jpg new file mode 100644 index 00000000..15a20269 Binary files /dev/null and b/kadai2/edm20627/testdata/hoge/img_1.jpg differ diff --git a/kadai2/edm20627/testdata/hoge/img_2.png b/kadai2/edm20627/testdata/hoge/img_2.png new file mode 100644 index 00000000..6622c982 Binary files /dev/null and b/kadai2/edm20627/testdata/hoge/img_2.png differ diff --git a/kadai2/edm20627/testdata/hoge/img_3.gif b/kadai2/edm20627/testdata/hoge/img_3.gif new file mode 100644 index 00000000..e6f4a9bc Binary files /dev/null and b/kadai2/edm20627/testdata/hoge/img_3.gif differ diff --git a/kadai2/edm20627/testdata/img_1.jpg b/kadai2/edm20627/testdata/img_1.jpg new file mode 100644 index 00000000..4f49baba Binary files /dev/null and b/kadai2/edm20627/testdata/img_1.jpg differ diff --git a/kadai2/edm20627/testdata/img_2.png b/kadai2/edm20627/testdata/img_2.png new file mode 100644 index 00000000..7a38caec Binary files /dev/null and b/kadai2/edm20627/testdata/img_2.png differ diff --git a/kadai2/edm20627/testdata/img_3.gif b/kadai2/edm20627/testdata/img_3.gif new file mode 100644 index 00000000..4ad9940d Binary files /dev/null and b/kadai2/edm20627/testdata/img_3.gif differ