generated from gopherdojo/template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathimgconv.go
181 lines (156 loc) · 4.71 KB
/
imgconv.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package imgconv
import (
"fmt"
"image"
"image/jpeg"
"image/png"
"io/ioutil"
"os"
"path"
"golang.org/x/xerrors"
)
var (
ReadDirError = xerrors.New("read dir error")
FileStatError = xerrors.New("file stat error")
OpenFileError = xerrors.New("open file error")
CloseFileError = xerrors.New("close file error")
NotImageError = xerrors.New("not image error")
ReadImageError = xerrors.New("read image error")
CreateDestinationFileError = xerrors.New("create destination file error")
EncodeImageError = xerrors.New("encode image error")
)
// NewIMGConverter - 新しい画像変換の生成
func NewIMGConverter() IMGConverter {
return &imgConverter{converter: NewConverter()} // converterを外からもらってもいいけど、使い方は決まってるので決め打ちで
}
// IMGConverter - 画像変換のユースケースのインターフェース
type IMGConverter interface {
Do(path, src, dest string) chan error
}
// imgConverter - 画像変換のユースケース
type imgConverter struct {
converter Converter
}
// Do - 指定されたディレクトリから再帰的にたどりながらファイルを変換する
func (c *imgConverter) Do(path, src, dest string) chan error {
ch := make(chan error)
go func() {
defer close(ch)
dirs, files, err := c.converter.DirFileList(path)
if err != nil {
ch <- err
return
}
// 非同期で再帰的にディレクトリをたどる
for _, dir := range dirs {
dch := c.Do(dir, src, dest)
for err := range dch {
ch <- err
}
}
// ファイルを変換する
for _, file := range files {
if err := c.converter.Convert(file, src, dest); err != nil {
ch <- err
}
}
}()
return ch
}
// NewConverter - 新しいConverterを生成する
func NewConverter() Converter {
return &converter{}
}
// converter - 変換処理とそれに付随する処理をもつサービスのインターフェース
type Converter interface {
IsDir(path string) (bool, error)
GetIMGType(path string) (_ string, err error)
DirFileList(filePath string) ([]string, []string, error)
Convert(filePath string, src string, dest string) (err error)
}
// converter - 変換処理とそれに付随する処理をもつサービス
type converter struct{}
// IsDir - pathがディレクトリかどうか
func (c converter) IsDir(path string) (bool, error) {
fi, err := os.Stat(path)
if err != nil {
return false, xerrors.Errorf("%+v: %w", err, FileStatError)
}
return fi.IsDir(), nil
}
// GetIMGType - 引数のファイルの画像フォーマットを取得する
func (c converter) GetIMGType(path string) (_ string, err error) {
f, err := os.Open(path)
if err != nil { // 開けない
return "", OpenFileError
}
defer func() {
if closeErr := f.Close(); closeErr != nil {
err = xerrors.Errorf("%+v: %w", closeErr, CloseFileError)
}
}()
_, format, err := image.DecodeConfig(f)
if err != nil { // 画像じゃない
return "", NotImageError
}
return format, nil
}
// DirFileList - 引数直下のディレクトリとファイルの配列を返す
func (c converter) DirFileList(filePath string) ([]string, []string, error) {
infos, err := ioutil.ReadDir(filePath)
if err != nil {
return nil, nil, xerrors.Errorf("%+v(filePath: %s): %w", err, filePath, ReadDirError)
}
dirs, files := make([]string, 0), make([]string, 0)
for _, info := range infos {
jp := path.Join(filePath, info.Name())
if info.IsDir() {
dirs = append(dirs, jp)
} else {
files = append(files, jp)
}
}
return dirs, files, nil
}
// Convert - 画像変換
func (c converter) Convert(filePath string, src string, dest string) (err error) {
if ft, err := c.GetIMGType(filePath); err != nil {
return err
} else if ft != src {
return nil
}
f, err := os.Open(filePath)
if err != nil { // 開けない
return xerrors.Errorf("%+v: %w", err, OpenFileError)
}
defer func() {
if closeErr := f.Close(); closeErr != nil {
err = xerrors.Errorf("%+v: %w", closeErr, CloseFileError)
}
}()
img, _, err := image.Decode(f)
if err != nil {
return xerrors.Errorf("%+v: %w", err, ReadImageError)
}
newFilePath := fmt.Sprintf("%s.%s.%s", filePath, "converted", dest)
o, err := os.Create(newFilePath)
if err != nil {
return xerrors.Errorf("%+v: %w", err, CreateDestinationFileError)
}
defer func() {
if closeErr := o.Close(); closeErr != nil {
err = xerrors.Errorf("%+v: %w", closeErr, CloseFileError)
}
}()
switch dest {
case "jpeg":
if err = jpeg.Encode(o, img, nil); err != nil {
return xerrors.Errorf("%+v: %w", err, EncodeImageError)
}
case "png":
if err = png.Encode(o, img); err != nil {
return xerrors.Errorf("%+v: %w", err, EncodeImageError)
}
}
return nil
}