diff --git a/kadai2/tanaka0325/README.md b/kadai2/tanaka0325/README.md
new file mode 100644
index 0000000..620b539
--- /dev/null
+++ b/kadai2/tanaka0325/README.md
@@ -0,0 +1,33 @@
+# 課題2
+
+## 【TRY】io.Readerとio.Writer
+
+```
+- io.Readerとio.Writerについて調べてみよう
+  - 標準パッケージでどのように使われているか
+  - io.Readerとio.Writerがあることでどういう利点があるのか具体例を挙げて考えてみる
+```
+
+### io.Readerとio.Writerについて調べてみよう
+
+#### 標準パッケージでどのように使われているか
+
+身近なものでいうと `fmt` の `Fprint` 系の関数は `io.Writer` を引数にとり、そこに対して書き込みを行っている。
+例えば `Println` は `io.Writer` として `os.Stdout` を `Fprintln` に渡して処理を行っている。
+
+標準バッケージでは上記のほかにも、画像やファイルやhttpのリクエスト/レスポンスなど「何か読み書きできるやつ」を抽象化して扱えるように `io.Reader`, `io.Writer` が使われている。
+
+#### io.Readerとio.Writerがあることでどういう利点があるのか具体例を挙げて考えてみる
+
+- 「読み書きできるやつ」と抽象化することができるので、例えば書き込みをする関数を1つ作れば複数の構造体に対応できる
+  - `io.Writer` がない場合、「ファイルに対して書き込みする関数」「画像に対して書き込みする関数」のように構造体ごとに関数を準備しなくてはならない
+- 抽象化することにより、具体的な構造体に依存しなくなるため、テスト時に差し替えることができモックなどでテストがしやくすなる
+  - 例えば画像を扱うテストをしたい時に、実際に画像を準備する必要がない
+
+
+## 感想
+
+- どういう構成にするのが良いのか考えながら何度もいじっていたらどんどん深みにハマり、何が良いのか全然わからなくなってしまった...
+- `main` パッケージにはテストを書くほどの処理は書かないで複雑な処理を書きたいなら別途パッケージを切るべきかな?と思ったので今回は `main` パッケージのテストを書いていないがそれで良いのかわからず
+  - 現状で `main` には受け取ったオプション、引数まわりの処理などをしているので、もしパッケージを作るなら `cli` みたいなパッケージを作ろうと思ってますが、今くらいの規模であれば作らなくてよいかなと思いました
+
diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go
new file mode 100644
index 0000000..66a6b02
--- /dev/null
+++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go
@@ -0,0 +1,146 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"path/filepath"
+
+	"github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv"
+)
+
+var (
+	args []string
+
+	from   string
+	to     string
+	dryRun bool
+)
+
+const (
+	fromUsageText   = "before extension"
+	toUsageText     = "after extension"
+	dryRunUsageText = "with dry-run"
+)
+
+var allowedExts = map[string]bool{
+	"png":  true,
+	"jpg":  true,
+	"jpeg": true,
+	"gif":  true,
+	"bmp":  true,
+	"tiff": true,
+	"tif":  true,
+}
+
+func init() {
+	flag.StringVar(&from, "from", "jpg", fromUsageText)
+	flag.StringVar(&from, "f", "jpg", fromUsageText+" (short)")
+	flag.StringVar(&to, "to", "png", toUsageText)
+	flag.StringVar(&to, "t", "png", toUsageText+" (short)")
+	flag.BoolVar(&dryRun, "dry-run", false, dryRunUsageText)
+	flag.BoolVar(&dryRun, "n", false, dryRunUsageText+" (short)")
+	flag.Parse()
+
+	args = flag.Args()
+}
+
+func main() {
+	// validate options
+	if ok := isAllowedFileType(from); !ok {
+		onExit(fmt.Errorf("%s is invalid filetype", from))
+	}
+	if ok := isAllowedFileType(to); !ok {
+		onExit(fmt.Errorf("%s is invalid filetype", to))
+	}
+
+	// validate arguments
+	dirnames := uniq(args)
+	for _, dirname := range dirnames {
+		ok, err := isDir(dirname)
+		if err != nil {
+			onExit(err)
+		}
+		if !ok {
+			onExit(fmt.Errorf("%s is not a directory", dirname))
+		}
+	}
+
+	paths, err := getTargetFilepaths(dirnames, from)
+	if err != nil {
+		onExit(err)
+	}
+
+	for _, path := range paths {
+		param := imgconv.ConvertParam{
+			Path:         path,
+			FileHandler:  imgconv.NewFile(),
+			BeforeFormat: imgconv.NewImage(from),
+			AfterFormat:  imgconv.NewImage(to),
+		}
+
+		if !dryRun {
+			if err := imgconv.Do(param); err != nil {
+				onExit(err)
+			}
+		} else {
+			e := len(param.Path) - len(from)
+			fmt.Printf("%s => %s%s\n", path, path[:e], to)
+		}
+	}
+}
+
+func isAllowedFileType(ft string) bool {
+	return allowedExts[ft]
+}
+
+func onExit(err error) {
+	fmt.Fprintln(os.Stderr, err)
+	os.Exit(1)
+}
+
+func uniq([]string) []string {
+	m := map[string]bool{}
+	u := []string{}
+
+	for _, v := range args {
+		if !m[v] {
+			m[v] = true
+
+			u = append(u, v)
+		}
+	}
+
+	return u
+}
+
+func isDir(path string) (bool, error) {
+	fi, err := os.Stat(path)
+	if err != nil {
+		return false, err
+	}
+
+	return fi.IsDir(), nil
+}
+
+func getTargetFilepaths(ds []string, ext string) ([]string, error) {
+	var names []string
+
+	for _, n := range ds {
+		if err := filepath.Walk(n, func(name string, info os.FileInfo, err error) error {
+			if err != nil {
+				return err
+			}
+
+			if filepath.Ext(name) == "."+ext {
+				names = append(names, name)
+			}
+
+			return nil
+		}); err != nil {
+			return nil, err
+		}
+	}
+
+	return names, nil
+}
diff --git a/kadai2/tanaka0325/imgconv/cover.html b/kadai2/tanaka0325/imgconv/cover.html
new file mode 100644
index 0000000..8758e79
--- /dev/null
+++ b/kadai2/tanaka0325/imgconv/cover.html
@@ -0,0 +1,271 @@
+
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+		<style>
+			body {
+				background: black;
+				color: rgb(80, 80, 80);
+			}
+			body, pre, #legend span {
+				font-family: Menlo, monospace;
+				font-weight: bold;
+			}
+			#topbar {
+				background: black;
+				position: fixed;
+				top: 0; left: 0; right: 0;
+				height: 42px;
+				border-bottom: 1px solid rgb(80, 80, 80);
+			}
+			#content {
+				margin-top: 50px;
+			}
+			#nav, #legend {
+				float: left;
+				margin-left: 10px;
+			}
+			#legend {
+				margin-top: 12px;
+			}
+			#nav {
+				margin-top: 10px;
+			}
+			#legend span {
+				margin: 0 5px;
+			}
+			.cov0 { color: rgb(192, 0, 0) }
+.cov1 { color: rgb(128, 128, 128) }
+.cov2 { color: rgb(116, 140, 131) }
+.cov3 { color: rgb(104, 152, 134) }
+.cov4 { color: rgb(92, 164, 137) }
+.cov5 { color: rgb(80, 176, 140) }
+.cov6 { color: rgb(68, 188, 143) }
+.cov7 { color: rgb(56, 200, 146) }
+.cov8 { color: rgb(44, 212, 149) }
+.cov9 { color: rgb(32, 224, 152) }
+.cov10 { color: rgb(20, 236, 155) }
+
+		</style>
+	</head>
+	<body>
+		<div id="topbar">
+			<div id="nav">
+				<select id="files">
+				
+				<option value="file0">github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/file.go (33.3%)</option>
+				
+				<option value="file1">github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go (54.5%)</option>
+				
+				<option value="file2">github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go (95.7%)</option>
+				
+				</select>
+			</div>
+			<div id="legend">
+				<span>not tracked</span>
+			
+				<span class="cov0">not covered</span>
+				<span class="cov8">covered</span>
+			
+			</div>
+		</div>
+		<div id="content">
+		
+		<pre class="file" id="file0" style="display: none">package imgconv
+
+import (
+        "io"
+        "os"
+)
+
+type FileHandler interface {
+        Open(string) (io.ReadCloser, error)
+        Create(string) (io.WriteCloser, error)
+}
+
+type File struct{}
+
+func (File) Open(n string) (io.ReadCloser, error)    <span class="cov0" title="0">{ return os.Open(n) }</span>
+func (File) Create(n string) (io.WriteCloser, error) <span class="cov0" title="0">{ return os.Create(n) }</span>
+
+func NewFile() File <span class="cov8" title="1">{
+        return File{}
+}</span>
+</pre>
+		
+		<pre class="file" id="file1" style="display: none">package imgconv
+
+import (
+        "image"
+        "image/gif"
+        "image/jpeg"
+        "image/png"
+        "io"
+
+        "golang.org/x/image/bmp"
+        "golang.org/x/image/tiff"
+)
+
+type Decoder interface {
+        Decode(io.Reader) (image.Image, error)
+}
+
+type Encoder interface {
+        Encode(io.Writer, image.Image) error
+}
+
+type ImageFormater interface {
+        Decoder
+        Encoder
+        GetExt() string
+}
+
+type ImageFormat struct {
+        Ext string
+}
+
+// ImagePng is type for png format.
+type PNG ImageFormat
+
+func (PNG) Decode(r io.Reader) (image.Image, error) <span class="cov0" title="0">{ return png.Decode(r) }</span>
+func (PNG) Encode(w io.Writer, i image.Image) error <span class="cov0" title="0">{ return png.Encode(w, i) }</span>
+func (p *PNG) GetExt() string                       <span class="cov8" title="1">{ return p.Ext }</span>
+
+// JPEG is type for jpeg format.
+type JPEG ImageFormat
+
+func (JPEG) Decode(r io.Reader) (image.Image, error) <span class="cov0" title="0">{ return jpeg.Decode(r) }</span>
+func (JPEG) Encode(w io.Writer, i image.Image) error <span class="cov0" title="0">{ return jpeg.Encode(w, i, nil) }</span>
+func (j *JPEG) GetExt() string                       <span class="cov8" title="1">{ return j.Ext }</span>
+
+// GIF is type for gif format.
+type GIF ImageFormat
+
+func (GIF) Decode(r io.Reader) (image.Image, error) <span class="cov0" title="0">{ return gif.Decode(r) }</span>
+func (GIF) Encode(w io.Writer, i image.Image) error <span class="cov0" title="0">{
+        return gif.Encode(w, i, &amp;gif.Options{NumColors: 256})
+}</span>
+func (g *GIF) GetExt() string <span class="cov8" title="1">{ return g.Ext }</span>
+
+// BMP is type for bmp format.
+type BMP ImageFormat
+
+func (BMP) Decode(r io.Reader) (image.Image, error) <span class="cov0" title="0">{ return bmp.Decode(r) }</span>
+func (BMP) Encode(w io.Writer, i image.Image) error <span class="cov0" title="0">{ return bmp.Encode(w, i) }</span>
+func (b *BMP) GetExt() string                       <span class="cov8" title="1">{ return b.Ext }</span>
+
+// TIFF is type for tiff format.
+type TIFF ImageFormat
+
+func (TIFF) Decode(r io.Reader) (image.Image, error) <span class="cov0" title="0">{ return tiff.Decode(r) }</span>
+func (TIFF) Encode(w io.Writer, i image.Image) error <span class="cov0" title="0">{ return tiff.Encode(w, i, nil) }</span>
+func (t *TIFF) GetExt() string                       <span class="cov8" title="1">{ return t.Ext }</span>
+
+func NewImageFormat(ext string) ImageFormater <span class="cov8" title="1">{
+        switch ext </span>{
+        case "png":<span class="cov8" title="1">
+                return &amp;PNG{Ext: ext}</span>
+        case "jpg", "jpeg":<span class="cov8" title="1">
+                return &amp;JPEG{Ext: ext}</span>
+        case "gif":<span class="cov8" title="1">
+                return &amp;GIF{Ext: ext}</span>
+        case "bmp":<span class="cov8" title="1">
+                return &amp;BMP{Ext: ext}</span>
+        case "tiff", "tif":<span class="cov8" title="1">
+                return &amp;TIFF{Ext: ext}</span>
+        }
+
+        <span class="cov8" title="1">return nil</span>
+}
+</pre>
+		
+		<pre class="file" id="file2" style="display: none">// Imgconv package is to convert images file format.
+package imgconv
+
+import "io"
+
+// ConvertParam is parameter to convert image format.
+type ConvertParam struct {
+        Path         string
+        FileHandler  FileHandler
+        BeforeFormat ImageFormater
+        AfterFormat  ImageFormater
+}
+
+// Do is func to convert image format.
+func Do(param ConvertParam) (rerr error) <span class="cov8" title="1">{
+        r, err := param.FileHandler.Open(param.Path)
+        if err != nil </span><span class="cov8" title="1">{
+                return err
+        }</span>
+        <span class="cov8" title="1">defer r.Close()
+
+        n := buildAfterPath(param.Path, param.BeforeFormat.GetExt(), param.AfterFormat.GetExt())
+        w, err := param.FileHandler.Create(n)
+        if err != nil </span><span class="cov8" title="1">{
+                return err
+        }</span>
+        <span class="cov8" title="1">defer func() </span><span class="cov8" title="1">{
+                err := w.Close()
+                if err != nil </span><span class="cov0" title="0">{
+                        rerr = err
+                }</span>
+        }()
+
+        <span class="cov8" title="1">if err := convert(r, param.BeforeFormat, w, param.AfterFormat); err != nil </span><span class="cov8" title="1">{
+                return err
+        }</span>
+
+        <span class="cov8" title="1">return nil</span>
+}
+
+func buildAfterPath(path, beforeExt, afterExt string) string <span class="cov8" title="1">{
+        e := len(path) - len(beforeExt)
+        return path[:e] + afterExt
+}</span>
+
+func convert(r io.Reader, d Decoder, w io.Writer, e Encoder) error <span class="cov8" title="1">{
+        img, err := d.Decode(r)
+        if err != nil </span><span class="cov8" title="1">{
+                return err
+        }</span>
+
+        <span class="cov8" title="1">if err := e.Encode(w, img); err != nil </span><span class="cov8" title="1">{
+                return err
+        }</span>
+
+        <span class="cov8" title="1">return nil</span>
+}
+</pre>
+		
+		</div>
+	</body>
+	<script>
+	(function() {
+		var files = document.getElementById('files');
+		var visible;
+		files.addEventListener('change', onChange, false);
+		function select(part) {
+			if (visible)
+				visible.style.display = 'none';
+			visible = document.getElementById(part);
+			if (!visible)
+				return;
+			files.value = part;
+			visible.style.display = 'block';
+			location.hash = part;
+		}
+		function onChange() {
+			select(files.value);
+			window.scrollTo(0, 0);
+		}
+		if (location.hash != "") {
+			select(location.hash.substr(1));
+		}
+		if (!visible) {
+			select("file0");
+		}
+	})();
+	</script>
+</html>
diff --git a/kadai2/tanaka0325/imgconv/cover.out b/kadai2/tanaka0325/imgconv/cover.out
new file mode 100644
index 0000000..187b117
--- /dev/null
+++ b/kadai2/tanaka0325/imgconv/cover.out
@@ -0,0 +1,42 @@
+mode: set
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/file.go:15.54,15.75 1 0
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/file.go:16.54,16.77 1 0
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/file.go:18.21,20.2 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:35.53,35.77 1 0
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:36.53,36.80 1 0
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:37.53,37.69 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:42.54,42.79 1 0
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:43.54,43.87 1 0
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:44.54,44.70 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:49.53,49.77 1 0
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:50.53,52.2 1 0
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:53.31,53.47 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:58.53,58.77 1 0
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:59.53,59.80 1 0
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:60.53,60.69 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:65.54,65.79 1 0
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:66.54,66.87 1 0
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:67.54,67.70 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:69.47,70.13 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:83.2,83.12 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:71.13,72.24 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:73.21,74.25 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:75.13,76.24 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:77.13,78.24 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:79.21,80.25 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:15.42,17.16 2 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:20.2,24.16 4 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:27.2,27.15 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:34.2,34.77 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:38.2,38.12 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:17.16,19.3 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:24.16,26.3 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:27.15,29.17 2 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:29.17,31.4 1 0
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:34.77,36.3 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:41.62,44.2 2 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:46.68,48.16 2 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:52.2,52.41 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:56.2,56.12 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:48.16,50.3 1 1
+github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:52.41,54.3 1 1
diff --git a/kadai2/tanaka0325/imgconv/export_test.go b/kadai2/tanaka0325/imgconv/export_test.go
new file mode 100644
index 0000000..91de432
--- /dev/null
+++ b/kadai2/tanaka0325/imgconv/export_test.go
@@ -0,0 +1,4 @@
+package imgconv
+
+var ConvertFunc = convert
+var BuildAfterPathFunc = buildAfterPath
diff --git a/kadai2/tanaka0325/imgconv/file.go b/kadai2/tanaka0325/imgconv/file.go
new file mode 100644
index 0000000..a92a39d
--- /dev/null
+++ b/kadai2/tanaka0325/imgconv/file.go
@@ -0,0 +1,20 @@
+package imgconv
+
+import (
+	"io"
+	"os"
+)
+
+type FileHandler interface {
+	Open(string) (io.ReadCloser, error)
+	Create(string) (io.WriteCloser, error)
+}
+
+type File struct{}
+
+func (File) Open(n string) (io.ReadCloser, error)    { return os.Open(n) }
+func (File) Create(n string) (io.WriteCloser, error) { return os.Create(n) }
+
+func NewFile() File {
+	return File{}
+}
diff --git a/kadai2/tanaka0325/imgconv/file_test.go b/kadai2/tanaka0325/imgconv/file_test.go
new file mode 100644
index 0000000..7fea260
--- /dev/null
+++ b/kadai2/tanaka0325/imgconv/file_test.go
@@ -0,0 +1,17 @@
+package imgconv_test
+
+import (
+	"testing"
+
+	"github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv"
+)
+
+func TestImgconvNewFile(t *testing.T) {
+	var f interface{}
+	f = imgconv.NewFile()
+
+	got, ok := f.(imgconv.File)
+	if !ok {
+		t.Errorf("expected type: File, but got %T", got)
+	}
+}
diff --git a/kadai2/tanaka0325/imgconv/format.go b/kadai2/tanaka0325/imgconv/format.go
new file mode 100644
index 0000000..352f440
--- /dev/null
+++ b/kadai2/tanaka0325/imgconv/format.go
@@ -0,0 +1,84 @@
+package imgconv
+
+import (
+	"image"
+	"image/gif"
+	"image/jpeg"
+	"image/png"
+	"io"
+
+	"golang.org/x/image/bmp"
+	"golang.org/x/image/tiff"
+)
+
+type Decoder interface {
+	Decode(io.Reader) (image.Image, error)
+}
+
+type Encoder interface {
+	Encode(io.Writer, image.Image) error
+}
+
+type ImageConverter interface {
+	Decoder
+	Encoder
+	GetExt() string
+}
+
+type Image struct {
+	Ext string
+}
+
+// ImagePng is type for png format.
+type PNG Image
+
+func (PNG) Decode(r io.Reader) (image.Image, error) { return png.Decode(r) }
+func (PNG) Encode(w io.Writer, i image.Image) error { return png.Encode(w, i) }
+func (p *PNG) GetExt() string                       { return p.Ext }
+
+// JPEG is type for jpeg format.
+type JPEG Image
+
+func (JPEG) Decode(r io.Reader) (image.Image, error) { return jpeg.Decode(r) }
+func (JPEG) Encode(w io.Writer, i image.Image) error { return jpeg.Encode(w, i, nil) }
+func (j *JPEG) GetExt() string                       { return j.Ext }
+
+// GIF is type for gif format.
+type GIF Image
+
+func (GIF) Decode(r io.Reader) (image.Image, error) { return gif.Decode(r) }
+func (GIF) Encode(w io.Writer, i image.Image) error {
+	return gif.Encode(w, i, &gif.Options{NumColors: 256})
+}
+func (g *GIF) GetExt() string { return g.Ext }
+
+// BMP is type for bmp format.
+type BMP Image
+
+func (BMP) Decode(r io.Reader) (image.Image, error) { return bmp.Decode(r) }
+func (BMP) Encode(w io.Writer, i image.Image) error { return bmp.Encode(w, i) }
+func (b *BMP) GetExt() string                       { return b.Ext }
+
+// TIFF is type for tiff format.
+type TIFF Image
+
+func (TIFF) Decode(r io.Reader) (image.Image, error) { return tiff.Decode(r) }
+func (TIFF) Encode(w io.Writer, i image.Image) error { return tiff.Encode(w, i, nil) }
+func (t *TIFF) GetExt() string                       { return t.Ext }
+
+func NewImage(ext string) ImageConverter {
+	switch ext {
+	case "png":
+		return &PNG{Ext: ext}
+	case "jpg", "jpeg":
+		return &JPEG{Ext: ext}
+	case "gif":
+		return &GIF{Ext: ext}
+	case "bmp":
+		return &BMP{Ext: ext}
+	case "tiff", "tif":
+		return &TIFF{Ext: ext}
+	}
+
+	return nil
+}
diff --git a/kadai2/tanaka0325/imgconv/format_test.go b/kadai2/tanaka0325/imgconv/format_test.go
new file mode 100644
index 0000000..a2fa0d9
--- /dev/null
+++ b/kadai2/tanaka0325/imgconv/format_test.go
@@ -0,0 +1,39 @@
+package imgconv_test
+
+import (
+	"testing"
+
+	"github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv"
+)
+
+func TestImgconvNewImage(t *testing.T) {
+	tests := []struct {
+		args     string
+		expected string
+	}{
+		{args: "png", expected: "png"},
+		{args: "jpg", expected: "jpg"},
+		{args: "jpeg", expected: "jpeg"},
+		{args: "gif", expected: "gif"},
+		{args: "bmp", expected: "bmp"},
+		{args: "tiff", expected: "tiff"},
+		{args: "tif", expected: "tif"},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.args, func(t *testing.T) {
+			f := imgconv.NewImage(tt.args)
+			got := f.GetExt()
+			if got != tt.expected {
+				t.Errorf("expected = %+v, but got = %+v", tt.expected, got)
+			}
+		})
+	}
+
+	t.Run("expected args", func(t *testing.T) {
+		got := imgconv.NewImage("pdf")
+		if got != nil {
+			t.Errorf("expected = nil, but got = %+v", got)
+		}
+	})
+}
diff --git a/kadai2/tanaka0325/imgconv/go.mod b/kadai2/tanaka0325/imgconv/go.mod
new file mode 100644
index 0000000..554fa07
--- /dev/null
+++ b/kadai2/tanaka0325/imgconv/go.mod
@@ -0,0 +1,5 @@
+module github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv
+
+go 1.14
+
+require golang.org/x/image v0.0.0-20200618115811-c13761719519
diff --git a/kadai2/tanaka0325/imgconv/go.sum b/kadai2/tanaka0325/imgconv/go.sum
new file mode 100644
index 0000000..83da957
--- /dev/null
+++ b/kadai2/tanaka0325/imgconv/go.sum
@@ -0,0 +1,4 @@
+github.com/gopherdojo/dojo8 v0.0.0-20200703052727-6a79d18126bf h1:lpYevjFQMxI5VNBc3WXV6Z5pDDrdppdDKwmeBoyt5BE=
+golang.org/x/image v0.0.0-20200618115811-c13761719519 h1:1e2ufUJNM3lCHEY5jIgac/7UTjd6cgJNdatjPdFWf34=
+golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/kadai2/tanaka0325/imgconv/imgconv.go b/kadai2/tanaka0325/imgconv/imgconv.go
new file mode 100644
index 0000000..18e56e8
--- /dev/null
+++ b/kadai2/tanaka0325/imgconv/imgconv.go
@@ -0,0 +1,57 @@
+// Imgconv package is to convert images file format.
+package imgconv
+
+import "io"
+
+// ConvertParam is parameter to convert image format.
+type ConvertParam struct {
+	Path         string
+	FileHandler  FileHandler
+	BeforeFormat ImageConverter
+	AfterFormat  ImageConverter
+}
+
+// Do is func to convert image format.
+func Do(param ConvertParam) (rerr error) {
+	r, err := param.FileHandler.Open(param.Path)
+	if err != nil {
+		return err
+	}
+	defer r.Close()
+
+	n := buildAfterPath(param.Path, param.BeforeFormat.GetExt(), param.AfterFormat.GetExt())
+	w, err := param.FileHandler.Create(n)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		err := w.Close()
+		if err != nil {
+			rerr = err
+		}
+	}()
+
+	if err := convert(r, param.BeforeFormat, w, param.AfterFormat); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func buildAfterPath(path, beforeExt, afterExt string) string {
+	e := len(path) - len(beforeExt)
+	return path[:e] + afterExt
+}
+
+func convert(r io.Reader, d Decoder, w io.Writer, e Encoder) error {
+	img, err := d.Decode(r)
+	if err != nil {
+		return err
+	}
+
+	if err := e.Encode(w, img); err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/kadai2/tanaka0325/imgconv/imgconv_test.go b/kadai2/tanaka0325/imgconv/imgconv_test.go
new file mode 100644
index 0000000..decdd0a
--- /dev/null
+++ b/kadai2/tanaka0325/imgconv/imgconv_test.go
@@ -0,0 +1,251 @@
+package imgconv_test
+
+import (
+	"fmt"
+	"image"
+	"io"
+	"os"
+	"testing"
+
+	"github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv"
+)
+
+func TestImgconvDo(t *testing.T) {
+	tests := []struct {
+		name  string
+		args  imgconv.ConvertParam
+		isErr bool
+	}{
+		{
+			name: "error: Open failed",
+			args: func() imgconv.ConvertParam {
+				mf := newMockFileHandler(
+					func(s string) (io.ReadCloser, error) { return nil, fmt.Errorf("err") },
+					nil,
+				)
+
+				return imgconv.ConvertParam{
+					Path:        "path",
+					FileHandler: mf,
+				}
+			}(),
+			isErr: true,
+		},
+		{
+			name: "error: Create failed",
+			args: func() imgconv.ConvertParam {
+				mf := newMockFileHandler(
+					func(s string) (io.ReadCloser, error) { return mockCloser{}, nil },
+					func(s string) (io.WriteCloser, error) { return nil, fmt.Errorf("err") },
+				)
+
+				mbi := newMockImage(
+					func(r io.Reader) (image.Image, error) { return mockStdImage{}, nil },
+					nil,
+					func() string { return "jpeg" },
+				)
+
+				mai := newMockImage(
+					nil,
+					func(w io.Writer, i image.Image) error { return nil },
+					func() string { return "png" },
+				)
+
+				return imgconv.ConvertParam{
+					Path:         "path",
+					FileHandler:  mf,
+					BeforeFormat: mbi,
+					AfterFormat:  mai,
+				}
+			}(),
+			isErr: true,
+		},
+		{
+			name: "error: convert failed",
+			args: func() imgconv.ConvertParam {
+				mf := newMockFileHandler(
+					func(s string) (io.ReadCloser, error) { return mockCloser{}, nil },
+					func(s string) (io.WriteCloser, error) { return mockCloser{}, nil },
+				)
+
+				mbi := newMockImage(
+					func(r io.Reader) (image.Image, error) { return mockStdImage{}, nil },
+					nil,
+					func() string { return "jpeg" },
+				)
+
+				mai := newMockImage(
+					nil,
+					func(w io.Writer, i image.Image) error { return fmt.Errorf("err") },
+					func() string { return "png" },
+				)
+
+				return imgconv.ConvertParam{
+					Path:         "path",
+					FileHandler:  mf,
+					BeforeFormat: mbi,
+					AfterFormat:  mai,
+				}
+			}(),
+			isErr: true,
+		},
+		{
+			name: "ok",
+			args: func() imgconv.ConvertParam {
+				mf := newMockFileHandler(
+					func(s string) (io.ReadCloser, error) { return mockCloser{}, nil },
+					func(s string) (io.WriteCloser, error) { return mockCloser{}, nil },
+				)
+
+				mbi := newMockImage(
+					func(r io.Reader) (image.Image, error) { return mockStdImage{}, nil },
+					nil,
+					func() string { return "jpeg" },
+				)
+				mai := newMockImage(
+					nil,
+					func(w io.Writer, i image.Image) error { return nil },
+					func() string { return "png" },
+				)
+
+				return imgconv.ConvertParam{
+					Path:         "path",
+					FileHandler:  mf,
+					BeforeFormat: mbi,
+					AfterFormat:  mai,
+				}
+			}(),
+			isErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			err := imgconv.Do(tt.args)
+			if (tt.isErr && err == nil) || (!tt.isErr && err != nil) {
+				t.Errorf("expected err = %+v, but got err = %+v", tt.isErr, err)
+			}
+		})
+	}
+}
+
+func TestImgconv_convert(t *testing.T) {
+	type args struct {
+		Reader  io.Reader
+		Decoder imgconv.Decoder
+		Writer  io.Writer
+		Encoder imgconv.Encoder
+	}
+
+	tests := []struct {
+		name  string
+		args  args
+		isErr bool
+	}{
+		{
+			name: "error: Decode failed",
+			args: func() args {
+				mi := newMockImage(
+					func(r io.Reader) (image.Image, error) { return nil, fmt.Errorf("err") },
+					nil,
+					nil,
+				)
+				return args{
+					os.Stdin,
+					mi,
+					nil,
+					nil,
+				}
+			}(),
+			isErr: true,
+		},
+		{
+			name: "error: Encode failed",
+			args: func() args {
+				me := newMockImage(
+					func(r io.Reader) (image.Image, error) { return mockImage{}, nil },
+					nil,
+					nil,
+				)
+
+				md := newMockImage(
+					nil,
+					func(w io.Writer, i image.Image) error { return fmt.Errorf("err") },
+					nil,
+				)
+				return args{
+					os.Stdin,
+					me,
+					os.Stdout,
+					md,
+				}
+			}(),
+			isErr: true,
+		},
+		{
+			name: "ok",
+			args: func() args {
+				me := newMockImage(
+					func(r io.Reader) (image.Image, error) { return mockImage{}, nil },
+					nil,
+					nil,
+				)
+
+				md := newMockImage(
+					nil,
+					func(w io.Writer, i image.Image) error { return nil },
+					nil,
+				)
+
+				return args{
+					os.Stdin,
+					me,
+					os.Stdout,
+					md,
+				}
+			}(),
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			err := imgconv.ConvertFunc(tt.args.Reader, tt.args.Decoder, tt.args.Writer, tt.args.Encoder)
+			if (tt.isErr && err == nil) || (!tt.isErr && err != nil) {
+				t.Errorf("expected err = %+v, but got err = %+v", tt.isErr, err)
+			}
+		})
+	}
+}
+
+func TestImgconv_buildAfterPath(t *testing.T) {
+	type args struct {
+		path      string
+		beforeExt string
+		afterExt  string
+	}
+
+	tests := []struct {
+		name     string
+		args     args
+		expected string
+	}{
+		{
+			name: "ok",
+			args: args{
+				path:      "test.gif",
+				beforeExt: "gif",
+				afterExt:  "png",
+			},
+			expected: "test.png",
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := imgconv.BuildAfterPathFunc(tt.args.path, tt.args.beforeExt, tt.args.afterExt)
+			if got != tt.expected {
+				t.Errorf("expected = %+v, but got = %+v", tt.expected, got)
+			}
+		})
+	}
+}
diff --git a/kadai2/tanaka0325/imgconv/mocks_test.go b/kadai2/tanaka0325/imgconv/mocks_test.go
new file mode 100644
index 0000000..0cab6ee
--- /dev/null
+++ b/kadai2/tanaka0325/imgconv/mocks_test.go
@@ -0,0 +1,61 @@
+package imgconv_test
+
+import (
+	"image"
+	"image/color"
+	"io"
+)
+
+type mockCloser struct{}
+
+func (mockCloser) Read(p []byte) (int, error)  { return 0, nil }
+func (mockCloser) Close() error                { return nil }
+func (mockCloser) Write(p []byte) (int, error) { return 0, nil }
+
+type openFunc func(string) (io.ReadCloser, error)
+type createFunc func(string) (io.WriteCloser, error)
+
+type mockFileHandler struct {
+	mockOpen   openFunc
+	mockCreate createFunc
+}
+
+func (m mockFileHandler) Open(s string) (io.ReadCloser, error)    { return m.mockOpen(s) }
+func (m mockFileHandler) Create(s string) (io.WriteCloser, error) { return m.mockCreate(s) }
+
+func newMockFileHandler(of openFunc, cf createFunc) mockFileHandler {
+	return mockFileHandler{
+		mockOpen:   of,
+		mockCreate: cf,
+	}
+}
+
+type decodeFunc func(io.Reader) (image.Image, error)
+type encodeFunc func(io.Writer, image.Image) error
+type getExtFunc func() string
+
+type mockImage struct {
+	mockDecode decodeFunc
+	mockEncode encodeFunc
+	mockGetExt getExtFunc
+}
+
+func (m mockImage) Decode(r io.Reader) (image.Image, error) { return m.mockDecode(r) }
+func (m mockImage) Encode(w io.Writer, i image.Image) error {
+	return m.mockEncode(w, i)
+}
+func (m mockImage) GetExt() string { return m.mockGetExt() }
+
+func newMockImage(df decodeFunc, ef encodeFunc, gf getExtFunc) mockImage {
+	return mockImage{
+		mockDecode: df,
+		mockEncode: ef,
+		mockGetExt: gf,
+	}
+}
+
+type mockStdImage struct{}
+
+func (mockStdImage) ColorModel() (c color.Model) { return }
+func (mockStdImage) Bounds() (r image.Rectangle) { return }
+func (mockStdImage) At(int, int) (c color.Color) { return }
diff --git a/kadai2/tanaka0325/imgconv/testdata/images/sample1.jpg b/kadai2/tanaka0325/imgconv/testdata/images/sample1.jpg
new file mode 100644
index 0000000..7a10881
Binary files /dev/null and b/kadai2/tanaka0325/imgconv/testdata/images/sample1.jpg differ
diff --git a/kadai2/tanaka0325/imgconv/testdata/images2/img/sample3.jpg b/kadai2/tanaka0325/imgconv/testdata/images2/img/sample3.jpg
new file mode 100644
index 0000000..7a10881
Binary files /dev/null and b/kadai2/tanaka0325/imgconv/testdata/images2/img/sample3.jpg differ
diff --git a/kadai2/tanaka0325/imgconv/testdata/images2/sample2.jpg b/kadai2/tanaka0325/imgconv/testdata/images2/sample2.jpg
new file mode 100644
index 0000000..7a10881
Binary files /dev/null and b/kadai2/tanaka0325/imgconv/testdata/images2/sample2.jpg differ