Skip to content

Commit e6d67ac

Browse files
committed
Implements imgconv
1 parent 6a79d18 commit e6d67ac

File tree

10 files changed

+273
-0
lines changed

10 files changed

+273
-0
lines changed

kadai1/tanaka0325/README.md

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Image Converter
2+
3+
## Spec
4+
5+
```
6+
## 次の仕様を満たすコマンドを作って下さい
7+
8+
- ディレクトリを指定する
9+
- 指定したディレクトリ以下のJPGファイルをPNGに変換(デフォルト)
10+
- ディレクトリ以下は再帰的に処理する
11+
- 変換前と変換後の画像形式を指定できる(オプション)
12+
13+
## 以下を満たすように開発してください
14+
15+
- mainパッケージと分離する
16+
- 自作パッケージと標準パッケージと準標準パッケージのみ使う
17+
- 準標準パッケージ:golang.org/x以下のパッケージ
18+
- ユーザ定義型を作ってみる
19+
- GoDocを生成してみる
20+
- Go Modulesを使ってみる
21+
```
22+
23+
## Usage
24+
25+
```zsh
26+
# build
27+
$ go build -o ./imgconv
28+
29+
# display help
30+
$ ./imgconv -h
31+
Usage of ./imgconv:
32+
-f string
33+
file extention before convert (default "jpg")
34+
-n dry run
35+
-t string
36+
file extention after convert (default "png")
37+
38+
# single directory
39+
$ ./imgconv images
40+
41+
# multi directories
42+
$ ./imgconv images images2
43+
44+
# customize ext
45+
$ ./imgconv -f png -t gif images
46+
47+
# dry run
48+
$ ./imgconv -n images
49+
images/sample1.jpg => images/sample1.png
50+
images2/img/sample3.jpg => images2/img/sample3.png
51+
images2/sample2.jpg => images2/sample2.png
52+
```
53+
54+
## 感想
55+
56+
- long option(?) はどうやってやれば良いのだろうか
57+
- そもそも作りとしてこれで良いのだろうか・・・めっちゃ悩みました
58+
+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package converter
2+
3+
import (
4+
"fmt"
5+
"image"
6+
"image/gif"
7+
"image/jpeg"
8+
"image/png"
9+
"io"
10+
"os"
11+
12+
"golang.org/x/image/bmp"
13+
"golang.org/x/image/tiff"
14+
)
15+
16+
type convImage struct {
17+
filename string
18+
fromExt string
19+
toExt string
20+
image image.Image
21+
}
22+
23+
func (i *convImage) decode() error {
24+
r, err := os.Open(i.filename + "." + i.fromExt)
25+
if err != nil {
26+
return err
27+
}
28+
defer r.Close()
29+
30+
img, err := decodeHelper(r, i.fromExt)
31+
if err != nil {
32+
return fmt.Errorf("decode error: %w", err)
33+
}
34+
35+
i.image = img
36+
return nil
37+
}
38+
39+
func decodeHelper(r io.Reader, ext string) (image.Image, error) {
40+
switch ext {
41+
case "png":
42+
return png.Decode(r)
43+
case "jpg", "jpeg":
44+
return jpeg.Decode(r)
45+
case "gif":
46+
return gif.Decode(r)
47+
case "bmp":
48+
return bmp.Decode(r)
49+
case "tiff", "tif":
50+
return tiff.Decode(r)
51+
}
52+
return nil, fmt.Errorf("%s is not allowed", ext)
53+
}
54+
55+
func (i *convImage) encode() error {
56+
w, err := os.Create(i.filename + "." + i.toExt)
57+
if err != nil {
58+
return err
59+
}
60+
defer func() error {
61+
if err := w.Close(); err != nil {
62+
return err
63+
}
64+
return nil
65+
}()
66+
67+
switch i.toExt {
68+
case "png":
69+
return png.Encode(w, i.image)
70+
case "jpg", "jpeg":
71+
return jpeg.Encode(w, i.image, nil)
72+
case "gif":
73+
return gif.Encode(w, i.image, nil)
74+
case "bmp":
75+
return gif.Encode(w, i.image, nil)
76+
case "tiff", "tif":
77+
return gif.Encode(w, i.image, nil)
78+
}
79+
80+
return fmt.Errorf("cannot encode image")
81+
}
+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package converter
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"log"
7+
"os"
8+
"path/filepath"
9+
"strings"
10+
)
11+
12+
// flags
13+
var (
14+
allowedExts = exts{"png", "jpg", "jpeg", "gif", "bmp", "tiff", "tif"}
15+
f = flag.String("f", "jpg", "file extention before convert")
16+
t = flag.String("t", "png", "file extention after convert")
17+
dryRun = flag.Bool("n", false, "dry run")
18+
)
19+
20+
// Convert is to convert image file format
21+
func Convert() {
22+
// check options ext
23+
flag.Parse()
24+
to := strings.ToLower(*t)
25+
from := strings.ToLower(*f)
26+
targetExts := []string{to, from}
27+
for _, e := range targetExts {
28+
if err := allowedExts.include(e); err != nil {
29+
log.Fatal(fmt.Errorf("%w. ext is only allowd in %s", err, allowedExts))
30+
}
31+
}
32+
33+
// get target image paths from args
34+
dns := flag.Args()
35+
udns := uniq(dns)
36+
paths, err := getPaths(udns, from)
37+
if err != nil {
38+
log.Fatal(err)
39+
}
40+
41+
// convert
42+
imgs, err := createConvImages(paths, from, to)
43+
if err != nil {
44+
log.Fatal(err)
45+
}
46+
for _, img := range imgs {
47+
if err := img.decode(); err != nil {
48+
log.Fatal(err)
49+
}
50+
51+
if *dryRun {
52+
fmt.Println(img.filename+"."+img.fromExt, "=>", img.filename+"."+img.toExt)
53+
} else {
54+
if err := img.encode(); err != nil {
55+
log.Fatal(err)
56+
}
57+
}
58+
}
59+
}
60+
61+
func uniq(s []string) []string {
62+
m := map[string]bool{}
63+
u := []string{}
64+
65+
for _, v := range s {
66+
if !m[v] {
67+
m[v] = true
68+
u = append(u, v)
69+
}
70+
}
71+
72+
return u
73+
}
74+
75+
func getPaths(dns []string, from string) ([]string, error) {
76+
paths := []string{}
77+
78+
for _, dn := range dns {
79+
if err := filepath.Walk(dn, func(path string, info os.FileInfo, err error) error {
80+
if filepath.Ext(path) == "."+from {
81+
paths = append(paths, path)
82+
}
83+
return nil
84+
}); err != nil {
85+
return nil, err
86+
}
87+
}
88+
89+
return paths, nil
90+
}
91+
92+
func createConvImages(paths []string, from, to string) ([]convImage, error) {
93+
images := []convImage{}
94+
for _, p := range paths {
95+
i := convImage{
96+
filename: strings.Replace(p, "."+from, "", 1),
97+
fromExt: strings.ToLower(from),
98+
toExt: strings.ToLower(to),
99+
}
100+
images = append(images, i)
101+
}
102+
103+
return images, nil
104+
}

kadai1/tanaka0325/converter/exts.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package converter
2+
3+
import "errors"
4+
5+
type exts []string
6+
7+
func (es exts) include(w string) error {
8+
for _, e := range es {
9+
if e == w {
10+
return nil
11+
}
12+
}
13+
return errors.New(w + " is not allowed")
14+
}

kadai1/tanaka0325/go.mod

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module github.com/gopherdojo/dojo8/kadai1/tanaka0325
2+
3+
go 1.14
4+
5+
require golang.org/x/image v0.0.0-20200618115811-c13761719519

kadai1/tanaka0325/go.sum

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
github.com/gopherdojo/dojo8 v0.0.0-20200703052727-6a79d18126bf h1:lpYevjFQMxI5VNBc3WXV6Z5pDDrdppdDKwmeBoyt5BE=
2+
golang.org/x/image v0.0.0-20200618115811-c13761719519 h1:1e2ufUJNM3lCHEY5jIgac/7UTjd6cgJNdatjPdFWf34=
3+
golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
4+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

kadai1/tanaka0325/images/sample1.jpg

10.7 KB
Loading
10.7 KB
Loading

kadai1/tanaka0325/images2/sample2.jpg

10.7 KB
Loading

kadai1/tanaka0325/imgconv.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package main
2+
3+
import "github.com/gopherdojo/dojo8/kadai1/tanaka0325/converter"
4+
5+
func main() {
6+
converter.Convert()
7+
}

0 commit comments

Comments
 (0)