-
Notifications
You must be signed in to change notification settings - Fork 0
/
imgconv.go
189 lines (164 loc) · 3.87 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
182
183
184
185
186
187
188
189
package imgconv
import (
"image"
"image/jpeg"
"image/png"
"io"
"io/fs"
"os"
"path/filepath"
"strings"
"golang.org/x/image/tiff"
)
// Formatは画像形式を表す
type Format int
const (
Unknown Format = iota
PNG
JPEG
TIFF
)
// Stringは画像形式に対応する文字列を返す
func (f Format) String() string {
switch f {
case PNG:
return "png"
case JPEG:
return "jpeg"
case TIFF:
return "tiff"
}
return "unknown"
}
// Setは文字列形式から対応する画像形式を設定する
func (f *Format) Set(s string) error {
switch s {
case "png":
*f = PNG
case "jpg", "jpeg":
*f = JPEG
case "tiff":
*f = TIFF
}
return image.ErrFormat
}
// Extは画像形式に対応する拡張子を取得する
func (f Format) Ext() string {
switch f {
case PNG:
return ".png"
case JPEG:
return ".jpeg"
case TIFF:
return ".tiff"
}
return ""
}
// FormatFromPathは指定したパスの拡張子から画像形式を取得する
func FormatFromPath(path string) Format {
ext := filepath.Ext(path)
switch strings.ToLower(ext) {
case ".png":
return PNG
case ".jpeg", ".jpg":
return JPEG
case ".tiff":
return TIFF
}
return Unknown
}
// ReplaceExtは拡張子を指定した形式のものに書き換える
func ReplaceExt(path string, f Format) string {
if f == Unknown {
return path
}
ext := filepath.Ext(path)
i := len(path) - len(ext)
return path[:i] + f.Ext()
}
// Encodeは画像をio.Readerからデータを読み込みimage.Image型に変換する
// 変換する画像形式はfで指定する
func Encode(w io.Writer, img image.Image, f Format) error {
switch f {
case PNG:
return png.Encode(w, img)
case JPEG:
return jpeg.Encode(w, img, nil)
case TIFF:
return tiff.Encode(w, img, nil)
}
return image.ErrFormat
}
// Decodeはio.Readerからデータを読み込みimage.Image型に変換する
// 第2戻り値で画像の形式を返す
func Decode(r io.Reader) (image.Image, Format, error) {
img, format, err := image.Decode(r)
if err != nil {
return nil, Unknown, err
}
switch format {
case "png":
return img, PNG, nil
case "jpeg":
return img, JPEG, nil
case "tiff":
return img, TIFF, nil
}
return nil, Unknown, image.ErrFormat
}
// ConvertAllは指定したディレクトリ以下の画像ファイルの変換を行う
// 変換前の形式をfromで変換後の形式をtoで指定する
func ConvertAll(root string, to, from Format) error {
walkfunc := func(path string, info fs.FileInfo, err error) (rerr error) {
// エラーが発生した
if err != nil {
return err
}
// ディレクトリ
if info.IsDir() {
return nil
}
// フォーマットが一致しない
extFormat := FormatFromPath(path)
if extFormat != from {
return nil
}
// 変換前のファイルを開く
srcFile, err := os.Open(path)
if err != nil {
return err
}
// 関数終了時にファイルを閉じる
defer srcFile.Close()
// 画像を読み込む
img, format, err := Decode(srcFile)
if err != nil {
return err
}
// 拡張子だけ合ってて読み込んだ画像の形式が対象ではない
if format != from {
return nil
}
// 変換後に画像を保存するファイルを作成
dstPath := ReplaceExt(path, to)
dstFile, err := os.Create(dstPath)
if err != nil {
return err
}
// 関数終了時にファイルを閉じる
defer func() {
// 閉じる際にエラーが発生した場合にはその値を返す
// ただしすでにエラーが返されている場合(rerr != nil)は何もしない
if err := dstFile.Close(); rerr == nil && err != nil {
// 名前付き戻り値のrerrに代入することでwalkfuncの戻り値にする
rerr = err
}
}()
// フォーマットを指定して画像を保存する
if err := Encode(dstFile, img, to); err != nil {
return err
}
return nil
}
return filepath.Walk(root, walkfunc)
}