diff --git a/kadai2/yasu/READWRITER.md b/kadai2/yasu/READWRITER.md new file mode 100644 index 0000000..29d5c72 --- /dev/null +++ b/kadai2/yasu/READWRITER.md @@ -0,0 +1,83 @@ +## io.Writerとio.Readerについて + +### io.Writer +#### どのように使われている? +io.Writerはfmtパッケージに置いて、FrintlnやFrintfなどに使われており、次のようになっています。 + +```print.go +func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + p := newPrinter() + p.doPrintln(a) + n, err = w.Write(p.buf) + p.free() + return +} +``` + +ここでは受け取ったinterface{}の配列をinterfaceの持つ情報の文字列に変換し、その文字列をbyte型のスライスにしたものをw(io.Writer)に書き込んでいます。 + +では、このio.Writerが何者かと言うと +Printlnの実装を見てみると + +```print.go +func Println(a ...interface{}) (n int, err error) { + return Fprintln(os.Stdout, a...) +} +``` + +os.Stdout、つまり標準出力が渡されています。 +os.StdoutにはWriteメソッドが存在しておりWriteを発火させる事によって標準出力に渡されたbyte配列を書き込んでいるのです。 +もちろん、Fprintlnにはos.Fileなどを渡すこともでき、io.Writerは書き込む先を抽象化するために使われてると言えます。 + +### io.Reader +#### どのように使われている? + +fmtパッケージのScanlnを例にとって考えてみると  + +```scan.go +func Fscan(r io.Reader, a ...interface{}) (n int, err error) { + s, old := newScanState(r, true, false) + n, err = s.doScan(a) + s.free(old) + return +} +``` + +io.Readerはここで使われています。 +こちらでのReaderの使い方はFprintlnとほぼ一緒で + +```scan.go +func Scan(a ...interface{}) (n int, err error) { + return Fscan(os.Stdin, a...) +} +``` + +```scan.go +func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) { + s = ssFree.Get().(*ss) + if rs, ok := r.(io.RuneScanner); ok { + s.rs = rs + } else { + s.rs = &readRune{reader: r, peekRune: -1} + } + s.nlIsSpace = nlIsSpace + s.nlIsEnd = nlIsEnd + s.atEOF = false + s.limit = hugeWid + s.argLimit = hugeWid + s.maxWid = hugeWid + s.validSave = true + s.count = 0 + return +} + +``` + +標準入力から受け取った文字列をssという構造体に書き込んでいます。 + +こちらもos.Stdinやos.Fileなどの構造体を抽象化するために用いられています。 + + +### 利点 +利点としては抽象化する事により実際に受け取っている値に依存する事なく関数を実装できる事だと思います。 +抽象化する事により受け取った具象系の変更の影響を受けないので変更にも強いです。 diff --git a/kadai2/yasu/converter/converter.go b/kadai2/yasu/converter/converter.go new file mode 100644 index 0000000..1fa54e6 --- /dev/null +++ b/kadai2/yasu/converter/converter.go @@ -0,0 +1,69 @@ +/* +Converter +Converterパッケージは画像の変換プログラムを提供します。 +*/ + +package converter + +import ( + "image" + "image/gif" + "image/jpeg" + "image/png" + "os" +) + +// ConvertImg は画像ファイルを指定したformatに変換します。 +func ConvertImg(file *os.File, directory string, afterFormat string) error { + img, _, err := image.Decode(file) + if err != nil { + return err + } + switch afterFormat { + case "png": + out, err := os.Create(file.Name() + ".png") + if err != nil { + return err + } + convertToPng(&img, out) + case "jpeg": + out, err := os.Create(file.Name() + ".jpg") + if err != nil { + return err + } + convertToJpeg(&img, out) + case "gif": + out, err := os.Create(file.Name() + ".gif") + if err != nil { + return err + } + convertToGif(&img, out) + } + return nil +} + +func convertToPng(img *image.Image, out *os.File) error { + err := png.Encode(out, *img) + if err != nil { + return err + } + return nil +} + +func convertToGif(img *image.Image, out *os.File) error { + opts := gif.Options{NumColors: 256} + err := gif.Encode(out, *img, &opts) + if err != nil { + return err + } + return nil +} + +func convertToJpeg(img *image.Image, out *os.File) error { + opts := jpeg.Options{Quality: 100} + err := jpeg.Encode(out, *img, &opts) + if err != nil { + return err + } + return nil +} diff --git a/kadai2/yasu/converter/converter_test.go b/kadai2/yasu/converter/converter_test.go new file mode 100644 index 0000000..e505667 --- /dev/null +++ b/kadai2/yasu/converter/converter_test.go @@ -0,0 +1,64 @@ +package converter + +import ( + "image" + "os" + "testing" +) + +func TestConvertImg(t *testing.T) { + file, err := os.Open("../sample_image/3d.jpg") + if err != nil { + t.Fatalf("failed test %#v", err) + } + directory := "sample_image" + err = ConvertImg(file, directory, "png") + if err != nil { + t.Fatalf("failed test %#v", err) + } +} + +func TestconvertToGif(t *testing.T) { + file, err := os.Open("../sample_image/3d.jpg") + if err != nil { + t.Fatalf("failed test %#v", err) + } + img, _, err := image.Decode(file) + if err != nil { + t.Fatalf("failed test %#v", err) + } + out, err := os.Create(file.Name() + ".gif") + if err := convertToGif(&img, out); err != nil { + t.Fatalf("failed test %#v", err) + } +} + +func TestconvertToPng(t *testing.T) { + file, err := os.Open("../sample_image/3d.jpg") + if err != nil { + t.Fatalf("failed test %#v", err) + } + img, _, err := image.Decode(file) + if err != nil { + t.Fatalf("failed test %#v", err) + } + out, err := os.Create(file.Name() + ".gif") + if err := convertToPng(&img, out); err != nil { + t.Fatalf("failed test %#v", err) + } +} + +func TestconvertToJpg(t *testing.T) { + file, err := os.Open("../sample_image/3d.jpg") + if err != nil { + t.Fatalf("failed test %#v", err) + } + img, _, err := image.Decode(file) + if err != nil { + t.Fatalf("failed test %#v", err) + } + out, err := os.Create(file.Name() + ".gif") + if err := convertToJpeg(&img, out); err != nil { + t.Fatalf("failed test %#v", err) + } +} diff --git a/kadai2/yasu/main.go b/kadai2/yasu/main.go new file mode 100644 index 0000000..06d5dd1 --- /dev/null +++ b/kadai2/yasu/main.go @@ -0,0 +1,67 @@ +/* +Overview +このコードはGopher道場1回目の課題のソースコードです。 +画像を変換するプログラムです。 +Usage +go buildをし、バイナリを実行してください。 +./yasu some_directory でsome_directoryに指定されたdirectory内の +全ての画像ファイルをpngファイルに変換します。 +Options +バイナリを実行する際にオプションを指定する事が可能です。 +to オプションを指定すると変換先の画像フォーマットを変更できます。 +次のように指定するとgifフォーマットへと変換します。 +./yasu -to gif some_directory +*/ + +package main + +import ( + "dojo4/kadai1/yasu/converter" + "flag" + "io/ioutil" + "os" + "sync" +) + +// オプション保持用変数 +var ( + //before_format string + afterFormat string // 変換先format +) + +var wg = sync.WaitGroup{} + +func main() { + bindFlags() + directory := os.Args[len(os.Args)-1] + if err = analyzeFiles(directory); err != nil { + log.Println(err) + } +} + +func bindFlags() { + //flag.StringVar(&before_format, "from", "jpeg", "File format") + flag.StringVar(&afterFormat, "to", "png", "Converted file format") + flag.Parse() +} + +func analyzeFiles(directory string) error { + files, err := ioutil.ReadDir(directory) // Get all file information in directory + if err != nil { + return err + } + for _, fileInfo := range files { + file, err := os.Open(directory + "/" + fileInfo.Name()) // Read file + if err != nil { + return err + } + wg.Add(1) + go func(file *os.File) { + if err := converter.ConvertImg(file, directory, afterFormat); err != nil { + return err + } + wg.Done() + }(file) + } + wg.Wait() +} diff --git a/kadai2/yasu/sample_image/3d.jpg b/kadai2/yasu/sample_image/3d.jpg new file mode 100644 index 0000000..a6365f1 Binary files /dev/null and b/kadai2/yasu/sample_image/3d.jpg differ diff --git a/kadai2/yasu/sample_image/hdri.jpg b/kadai2/yasu/sample_image/hdri.jpg new file mode 100644 index 0000000..1c0ccad Binary files /dev/null and b/kadai2/yasu/sample_image/hdri.jpg differ