-
Notifications
You must be signed in to change notification settings - Fork 2
Kadai2-hisamura #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Kadai2-hisamura #15
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module dojo6 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
|
||
### 標準パッケージでどのように使われているか | ||
|
||
fmt.Fprintでは以下のように記述されている。 | ||
``` | ||
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { | ||
p := newPrinter() | ||
p.doPrintf(format, a) | ||
n, err = w.Write(p.buf) | ||
p.free() | ||
return | ||
} | ||
``` | ||
同じファイル内のFprint内での呼び出しは以下。 | ||
|
||
``` | ||
Fprintf(os.Stdout, format, a...) | ||
``` | ||
|
||
io.writerのインターフェースはwriteをメソッドに持っている型なら引数に設定できるので、os.Stdoutを引数に指定し、呼び出している。 | ||
|
||
### io.Readerとio.Writerがあることでどういう利点があるのか具体例を挙げて考えてみる | ||
|
||
- コードが簡潔にできるために使用することができる。 | ||
- interfaceがないと、それぞれの型を引数に指定し、複数の関数を作らなくてはいけない。 | ||
- それがinterfaceを設定できることで、interfaceの関数は使用できることが約束される。 | ||
- io.Readerの型を満たしているということはReadメソッドが使用できることが約束されており、引数にio.Readerを指定することで関数内でその引数の型の違いを気にすることなく、Readメソッドを使うことができ、シンプルにコードを記述することができる。 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// Package convert is image conversion processing | ||
// | ||
// 画像変換処理。 | ||
// 変換前と変換後の拡張子を指定し、画像変換を行います。 | ||
// ディレクトリを選択し、再帰的にディレクトリ探索を行い変換します。 | ||
// 変換前のファイルを削除したい場合は、remove(-r)フラグを指定します。 | ||
package convert | ||
|
||
import ( | ||
"fmt" | ||
"image" | ||
"image/gif" | ||
"image/jpeg" | ||
"image/png" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
) | ||
|
||
// FlagOps is flag option | ||
type FlagOps struct { | ||
Dir string | ||
Src string | ||
Dest string | ||
Remove bool | ||
} | ||
|
||
// FileDetails have Extionsion and FileName info | ||
type FileDetails struct { | ||
Extension string | ||
FileName string | ||
} | ||
|
||
// Convert is image conversion processing | ||
func Convert(flagOps FlagOps) (string, error) { | ||
|
||
files := dirwalk(flagOps.Dir) | ||
var convertedName string | ||
|
||
for _, file := range files { | ||
fileDetails := FileDetails{ | ||
filepath.Ext(file), | ||
filepath.Clean(file), | ||
} | ||
|
||
if strings.HasSuffix(fileDetails.Extension, flagOps.Src) { | ||
|
||
decodeImg, err := decodeImage(fileDetails) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
if flagOps.Remove { | ||
defer os.Remove(fileDetails.FileName) | ||
} | ||
|
||
fileNameRemoveExt := strings.Replace(fileDetails.FileName, flagOps.Src, "", 1) | ||
dstFile, err := os.Create(fmt.Sprintf(fileNameRemoveExt + flagOps.Dest)) | ||
if err != nil { | ||
return "", err | ||
} | ||
convertedName = dstFile.Name() | ||
defer dstFile.Close() | ||
|
||
err = encodeImage(decodeImg, flagOps, dstFile) | ||
if err != nil { | ||
return "", err | ||
} | ||
} | ||
} | ||
return convertedName, nil | ||
|
||
} | ||
|
||
func decodeImage(fileDetails FileDetails) (image.Image, error) { | ||
srcFile, err := os.Open(fileDetails.FileName) | ||
|
||
defer srcFile.Close() | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
decodeImg, _, err := image.Decode(srcFile) | ||
return decodeImg, err | ||
} | ||
|
||
func encodeImage(decodeImg image.Image, flagOps FlagOps, dstFile *os.File) error { | ||
switch flagOps.Dest { | ||
case "jpeg", "jpg": | ||
err := jpeg.Encode(dstFile, decodeImg, nil) | ||
return err | ||
|
||
case "gif": | ||
err := gif.Encode(dstFile, decodeImg, nil) | ||
return err | ||
|
||
case "png": | ||
err := png.Encode(dstFile, decodeImg) | ||
return err | ||
|
||
default: | ||
return fmt.Errorf("Error: invalid extension") | ||
} | ||
} | ||
|
||
//指定したディレクトリ配下のファイルを取得 | ||
func dirwalk(dir string) []string { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
files, err := ioutil.ReadDir(dir) | ||
if err != nil { | ||
panic(err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
var paths []string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
for _, file := range files { | ||
if file.IsDir() { | ||
paths = append(paths, dirwalk(filepath.Join(dir, file.Name()))...) | ||
continue | ||
} | ||
paths = append(paths, filepath.Join(dir, file.Name())) | ||
} | ||
|
||
return paths | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package convert | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. パッケージを分ける( |
||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
type testImage struct { | ||
name string | ||
src string | ||
dest string | ||
expected string | ||
} | ||
|
||
func TestSuccess(t *testing.T) { | ||
|
||
cases := []testImage{ | ||
testImage{"jpgToGif", "jpg", "gif", "../testdata/test.gif"}, | ||
testImage{"jpgToGif", "jpg", "gif", "../testdata/test.gif"}, | ||
testImage{"jpgToPng", "jpg", "png", "../testdata/test.png"}, | ||
testImage{"gifToJpg", "gif", "jpg", "../testdata/test.jpg"}, | ||
testImage{"gifToPng", "gif", "png", "../testdata/test.png"}, | ||
testImage{"pngToGif", "png", "gif", "../testdata/test.gif"}, | ||
testImage{"pngToJpg", "gif", "png", "../testdata/test.png"}, | ||
} | ||
|
||
for _, c := range cases { | ||
t.Run(c.name, func(t *testing.T) { | ||
testSuccessConvert(t, c) | ||
}) | ||
} | ||
} | ||
|
||
func testSuccessConvert(t *testing.T, c testImage) { | ||
t.Helper() | ||
myflag := FlagOps{"../testdata", c.src, c.dest, false} | ||
convertedNmae, err := Convert(myflag) | ||
|
||
if convertedNmae != c.expected { | ||
t.Fatal("differnt name") | ||
} | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
func TestFail(t *testing.T) { | ||
cases := []testImage{ | ||
testImage{"jpgToGif", "jpg", "img", "../testdata/test.img"}, | ||
} | ||
|
||
for _, c := range cases { | ||
t.Run(c.name, func(t *testing.T) { | ||
testFailConvert(t, c) | ||
}) | ||
} | ||
|
||
} | ||
|
||
func testFailConvert(t *testing.T, c testImage) { | ||
t.Helper() | ||
myflag := FlagOps{"../testdata", c.src, c.dest, false} | ||
convertedNmae, err := Convert(myflag) | ||
|
||
if convertedNmae != "" { | ||
t.Fatal("not empty name") | ||
} | ||
if err == nil { | ||
t.Fatal("err nil") | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module dojo6/kadai2/hisamura |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package main | ||
|
||
import ( | ||
"dojo6/kadai2/hisamura/convert" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 標準パッケージ以外は空行を分けることが多い。 |
||
"flag" | ||
"fmt" | ||
) | ||
|
||
func main() { | ||
|
||
var ( | ||
dir = flag.String("dir", "./", "変換したいディレクトリ配下") | ||
src = flag.String("s", "png", "変換前の拡張子") | ||
dest = flag.String("d", "jpg", "変換後の拡張子") | ||
remove = flag.Bool("r", false, "変換前の拡張子ファイルを削除するかのflag") | ||
) | ||
|
||
flag.Parse() | ||
|
||
flagOps := convert.FlagOps{Dir: *dir, Src: *src, Dest: *dest, Remove: *remove} | ||
|
||
result := validation(flagOps) | ||
if result { | ||
fmt.Print("invalid extension") | ||
return | ||
} | ||
|
||
convertFile, err := convert.Convert(flagOps) | ||
|
||
if err != nil { | ||
fmt.Println(err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. エラーは |
||
} | ||
|
||
fmt.Printf("convert to %v", convertFile) | ||
} | ||
|
||
func validation(flagOps convert.FlagOps) bool { | ||
if flagOps.Dest != "png" && flagOps.Dest != "jpg" && flagOps.Dest != "jpeg" && flagOps.Dest != "gif" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
return true | ||
} | ||
return false | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defer
で指定した関数呼び出しは関数終了時に実行されるのでfor
の中で呼び出さない。関数に分けることで避けることができる。