diff --git a/kadai1/tanaka0325/imgconv/args.go b/kadai1/tanaka0325/imgconv/args.go index c5cd6f6..4212901 100644 --- a/kadai1/tanaka0325/imgconv/args.go +++ b/kadai1/tanaka0325/imgconv/args.go @@ -10,6 +10,7 @@ func (args Args) uniq() []string { for _, v := range args { if !m[v] { m[v] = true + u = append(u, v) } } diff --git a/kadai1/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai1/tanaka0325/imgconv/cmd/imgconv/main.go index 10a5a56..875aefa 100644 --- a/kadai1/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai1/tanaka0325/imgconv/cmd/imgconv/main.go @@ -12,8 +12,8 @@ var options imgconv.Options var args imgconv.Args func init() { - options.From = flag.String("f", "jpg", "file extention before convert") - options.To = flag.String("t", "png", "file extention after convert") + options.From = flag.String("f", "jpg", "file extension before convert") + options.To = flag.String("t", "png", "file extension after convert") options.DryRun = flag.Bool("n", false, "dry run") flag.Parse() diff --git a/kadai1/tanaka0325/imgconv/cnv_image.go b/kadai1/tanaka0325/imgconv/cnv_image.go new file mode 100644 index 0000000..869a7d9 --- /dev/null +++ b/kadai1/tanaka0325/imgconv/cnv_image.go @@ -0,0 +1,81 @@ +package imgconv + +import ( + "image" + "image/gif" + "image/jpeg" + "image/png" + "io" + + "golang.org/x/image/bmp" + "golang.org/x/image/tiff" +) + +type Decoder interface { + Decode(io.Reader) (image.Image, error) +} + +type Encoder interface { + Encode(io.Writer, image.Image) error +} + +type DecodeEncoder interface { + Decoder + Encoder +} + +type CnvImage struct{} + +// CnvImagePng is type for png format. +type CnvImagePNG CnvImage + +func (ip CnvImagePNG) Decode(r io.Reader) (image.Image, error) { return png.Decode(r) } + +func (ip CnvImagePNG) Encode(w io.Writer, i image.Image) error { return png.Encode(w, i) } + +// CnvImageJPEG is type for jpeg format. +type CnvImageJPEG CnvImage + +func (ip CnvImageJPEG) Decode(r io.Reader) (image.Image, error) { return jpeg.Decode(r) } + +func (ip CnvImageJPEG) Encode(w io.Writer, i image.Image) error { return jpeg.Encode(w, i, nil) } + +// CnvImageGIF is type for gif format. +type CnvImageGIF CnvImage + +func (ip CnvImageGIF) Decode(r io.Reader) (image.Image, error) { return gif.Decode(r) } + +func (ip CnvImageGIF) Encode(w io.Writer, i image.Image) error { + return gif.Encode(w, i, &gif.Options{NumColors: 256}) +} + +// CnvImageBMP is type for bmp format. +type CnvImageBMP CnvImage + +func (ip CnvImageBMP) Decode(r io.Reader) (image.Image, error) { return bmp.Decode(r) } + +func (ip CnvImageBMP) Encode(w io.Writer, i image.Image) error { return bmp.Encode(w, i) } + +// CnvImageTIFF is type for tiff format. +type CnvImageTIFF CnvImage + +func (ip CnvImageTIFF) Decode(r io.Reader) (image.Image, error) { return tiff.Decode(r) } + +func (ip CnvImageTIFF) Encode(w io.Writer, i image.Image) error { return tiff.Encode(w, i, nil) } + +func newCnvImage(ext string) DecodeEncoder { + switch ext { + case "png": + return &CnvImagePNG{} + case "jpg", "jpeg": + return &CnvImageJPEG{} + case "gif": + return &CnvImageGIF{} + case "bmp": + return &CnvImageBMP{} + case "tiff", "tif": + return &CnvImageTIFF{} + } + + return nil +} diff --git a/kadai1/tanaka0325/imgconv/conv_image.go b/kadai1/tanaka0325/imgconv/conv_image.go deleted file mode 100644 index cb92ef3..0000000 --- a/kadai1/tanaka0325/imgconv/conv_image.go +++ /dev/null @@ -1,82 +0,0 @@ -package imgconv - -import ( - "fmt" - "image" - "image/gif" - "image/jpeg" - "image/png" - "io" - "os" - - "golang.org/x/image/bmp" - "golang.org/x/image/tiff" -) - -// convImage is type included infomation to convert file format. -type convImage struct { - filename string - fromExt string - toExt string - image image.Image -} - -func (i *convImage) decode() error { - r, err := os.Open(i.filename + "." + i.fromExt) - if err != nil { - return err - } - defer r.Close() - - img, err := decodeHelper(r, i.fromExt) - if err != nil { - return fmt.Errorf("decode error: %w", err) - } - - i.image = img - return nil -} - -func decodeHelper(r io.Reader, ext string) (image.Image, error) { - switch ext { - case "png": - return png.Decode(r) - case "jpg", "jpeg": - return jpeg.Decode(r) - case "gif": - return gif.Decode(r) - case "bmp": - return bmp.Decode(r) - case "tiff", "tif": - return tiff.Decode(r) - } - return nil, fmt.Errorf("%s is not allowed", ext) -} - -func (i *convImage) encode() error { - w, err := os.Create(i.filename + "." + i.toExt) - if err != nil { - return err - } - defer func() error { - if err := w.Close(); err != nil { - return err - } - return nil - }() - - switch i.toExt { - case "png": - return png.Encode(w, i.image) - case "jpg", "jpeg": - return jpeg.Encode(w, i.image, nil) - case "gif": - return gif.Encode(w, i.image, nil) - case "bmp": - return gif.Encode(w, i.image, nil) - case "tiff", "tif": - return gif.Encode(w, i.image, nil) - } - - return fmt.Errorf("cannot encode image") -} diff --git a/kadai1/tanaka0325/imgconv/go.mod.back b/kadai1/tanaka0325/imgconv/go.mod.back deleted file mode 100644 index ad64074..0000000 --- a/kadai1/tanaka0325/imgconv/go.mod.back +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/gopherdojo/dojo8/kadai1/tanaka0325/imgconv - -go 1.14 - -require golang.org/x/image v0.0.0-20200618115811-c13761719519 diff --git a/kadai1/tanaka0325/imgconv/imgconv.go b/kadai1/tanaka0325/imgconv/imgconv.go index 29db8da..e80c35c 100644 --- a/kadai1/tanaka0325/imgconv/imgconv.go +++ b/kadai1/tanaka0325/imgconv/imgconv.go @@ -9,47 +9,85 @@ import ( ) var allowedExts = []string{"png", "jpg", "jpeg", "gif", "bmp", "tiff", "tif"} +var fromExt string +var toExt string -// Run is to convert image file format +// Run is to convert image file format. func Run(options Options, args Args) error { - // validator + // // validator if err := options.validate(allowedExts); err != nil { return err } + fromExt = *options.From + toExt = *options.To + // get target image flepaths from args - paths, err := getTargetFilePaths(args, *options.From) + paths, err := getTargetFilePaths(args, fromExt) if err != nil { return err } // convert - imgs, err := createConvImages(paths, *options.From, *options.To) - if err != nil { - return err - } - for _, img := range imgs { - if err := img.decode(); err != nil { - return err - } + for _, path := range paths { + filename := strings.Replace(path, "."+fromExt, "", -1) + // ")) + f := newCnvImage(fromExt) + t := newCnvImage(toExt) if *options.DryRun { - fmt.Println(img.filename+"."+img.fromExt, "=>", img.filename+"."+img.toExt) - } else { - if err := img.encode(); err != nil { - return err - } + fmt.Printf("%s.%s => %s.%s \n", filename, fromExt, filename, toExt) + } else if err := convert(f, t, filename); err != nil { + return err } } return nil } +func convert(d Decoder, e Encoder, filename string) (err error) { + // open file + r, err := os.Open(filename + "." + fromExt) + if err != nil { + return + } + defer r.Close() + + // decode + img, err := d.Decode(r) + if err != nil { + return + } + + // create file + w, err := os.Create(filename + "." + toExt) + if err != nil { + return err + } + + defer func() { + err = w.Close() + }() + + // encode + if err := e.Encode(w, img); err != nil { + return err + } + + return +} + func getTargetFilePaths(args Args, from string) ([]string, error) { uns := args.uniq() - paths := []string{} + paths := []string{} for _, n := range uns { + if ok, err := isDir(n); err != nil { + return nil, err + } else if !ok { + return nil, fmt.Errorf("%s is not a directory", n) + } + if err := filepath.Walk(n, func(path string, info os.FileInfo, err error) error { if filepath.Ext(path) == "."+from { paths = append(paths, path) @@ -63,16 +101,16 @@ func getTargetFilePaths(args Args, from string) ([]string, error) { return paths, nil } -func createConvImages(paths []string, from, to string) ([]convImage, error) { - images := []convImage{} - for _, p := range paths { - i := convImage{ - filename: strings.Replace(p, "."+from, "", 1), - fromExt: strings.ToLower(from), - toExt: strings.ToLower(to), - } - images = append(images, i) +func isDir(path string) (bool, error) { + f, err := os.Open(path) + if err != nil { + return false, err + } + + fi, err := f.Stat() + if err != nil { + return false, err } - return images, nil + return fi.IsDir(), nil } diff --git a/kadai1/tanaka0325/imgconv/options.go b/kadai1/tanaka0325/imgconv/options.go index 3a31e15..1d91f04 100644 --- a/kadai1/tanaka0325/imgconv/options.go +++ b/kadai1/tanaka0325/imgconv/options.go @@ -13,13 +13,14 @@ type Options struct { DryRun *bool } -func (opt Options) validate(allow_list []string) error { +func (opt Options) validate(allowList []string) error { to := strings.ToLower(*opt.To) from := strings.ToLower(*opt.From) targetExts := []string{to, from} + for _, e := range targetExts { - if err := include(allow_list, e); err != nil { - return fmt.Errorf("%w. ext is only allowd in %s", err, allow_list) + if err := include(allowList, e); err != nil { + return fmt.Errorf("%w. ext is only allowd in %s", err, allowList) } }