Skip to content
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

kadai2-nejiyoshida #17

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions kadai2/nejiyoshida/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# 1.画像変換コマンドをつくろう

## 使い方
imgconv {-s source-extension} {-t target-extension} search-directory save-directory

## 説明
指定したディレクトリ配下を再帰的に探索し、指定形式の画像を変換します。
保存先を指定する必要があり、指定の保存先が存在しない場合、新たにディレクトリが作られます。
対応形式はjpg, png, bmp, gif の4種類です。
Binary file added kadai2/nejiyoshida/check/gopher2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added kadai2/nejiyoshida/check/gopher_favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 56 additions & 0 deletions kadai2/nejiyoshida/dircrawler/dircrawler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// dircrawler パッケージは指定のディレクトリ以下にある指定の形式のファイルのリストを再帰的に取得する機能を提供します
package dircrawler

import (
"io/ioutil"
"log"
"path/filepath"
)

// 指定ディレクトリ配下の特定形式のファイルパスリストを再帰的に取得します
func SearchSpecificFormatFiles(rootDir, format string) []string {

paths := searchFilePaths(rootDir)
files := selectFormat(paths, format)

return files

}

// 指定ディレクトリのファイルパスリストを再帰的に取得します
func searchFilePaths(rootDir string) []string {
files, err := ioutil.ReadDir(rootDir)
if err != nil {
log.Fatal(err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

エラー処理。log.Fatalは使わない。

}

var paths []string

for _, file := range files {
if file.IsDir() {
paths = append(paths, searchFilePaths(filepath.Join(rootDir, file.Name()))...)
continue
}

paths = append(paths, filepath.Join(rootDir, file.Name()))
}

return paths
}

//ファイルパスリストから特定のフォーマットのもののみ抜き出します
func selectFormat(paths []string, format string) []string {
var files []string
for _, path := range paths {
if isSpecifiedFormat(path, format) {
files = append(files, path)
}
}
return files
}

// ファイルパスが特定のフォーマットか確認します。
func isSpecifiedFormat(path, format string) bool {
ext := filepath.Ext(path)
return ext == format
}
74 changes: 74 additions & 0 deletions kadai2/nejiyoshida/dircrawler/dircrawler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package dircrawler

import (
"fmt"
"reflect"
"testing"
)

func ExampleisSpecifiedFormat() {

fmt.Println(isSpecifiedFormat("hoge.jpg", ".jpg"))
//Output:true
fmt.Println(isSpecifiedFormat("huga.jpg", ".png"))
//Output:false
fmt.Println(isSpecifiedFormat("foo.png", ".png"))
//Output:true
fmt.Println(isSpecifiedFormat("bar.png", ".png"))
//Output:false
}

func TestSelectFormat(t *testing.T) {
t.Helper()
cases := []struct {
ext string
files []string
ret []string
}{
{ext: ".jpg", files: []string{"a.txt", "b.jpg", "c.jpg", "d.html", "e.png"}, ret: []string{"b.jpg", "c.jpg"}},
{ext: ".exe", files: []string{"a.txt", "b.jpg", "c.jpg", "d.html", "e.png"}, ret: nil},
{ext: ".jpg", files: []string{"./hoge/a.txt", "./hoge/huga/b.jpg", "./.git/c.jpg", "./d.html", "./e.png"}, ret: []string{"./hoge/huga/b.jpg", "./.git/c.jpg"}},
}
for _, c := range cases {
if !reflect.DeepEqual(selectFormat(c.files, c.ext), c.ret) {
t.Errorf("test cases %v does not match\n", c)
}
}

}

func TestIsSpecifiedFormat(t *testing.T) {
t.Helper()
cases := []struct {
file string
ext string
ans bool
}{
{file: "a.jpg", ext: ".jpg", ans: true},
{file: "a.jpg", ext: ".txt", ans: false},
{file: "./hoge/huga/a.png", ext: ".png", ans: true},
{file: "./foo/bar/a.jpg", ext: ".png", ans: false},
}
for _, c := range cases {
if !isSpecifiedFormat("./hoge/huga.jpg", ".jpg") {
t.Errorf("test cases %v is not %v formt\n", c.file, c.ext)
}
}
}
func TestSearchFilePaths(t *testing.T) {
t.Helper()
cases := []struct {
rootDir string
ret []string
}{
{rootDir: "./test", ret: []string{"test\\TEST\\bar.txt", "test\\TEST\\gopher.jpg", "test\\foo.txt"}},
{rootDir: "./test/TEST", ret: []string{"test\\TEST\\bar.txt", "test\\TEST\\gopher.jpg"}},
}
for _, c := range cases {

if !reflect.DeepEqual(searchFilePaths(c.rootDir), c.ret) {
t.Errorf("test case %v does not match\n", c)
}

}
}
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
Binary file added kadai2/nejiyoshida/gopher.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added kadai2/nejiyoshida/gopher_favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions kadai2/nejiyoshida/imgconv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

import (
"flag"
"fmt"

"github.com/gopherdojo/dojo5/kadai1/nejiyoshida/dircrawler"
"github.com/gopherdojo/dojo5/kadai1/nejiyoshida/imgconverter"
)

func main() {

var (
s string
t string
)

flag.StringVar(&s, "s", ".jpg", "format of image before conversion")
flag.StringVar(&t, "t", ".png", "format of image after conversion")
flag.Parse()

args := flag.Args()
searchDir, saveDir := args[0], args[1]
files := dircrawler.SearchSpecificFormatFiles(searchDir, s)
c := imgconverter.New(t, saveDir, files)
c.Convert()
fmt.Println("finished")
}
115 changes: 115 additions & 0 deletions kadai2/nejiyoshida/imgconverter/imgconverter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// imgconverter パッケージは指定の画像ファイルを指定の形式に変換する機能を提供します
package imgconverter

import (
"fmt"
"image"
"image/gif"
"image/jpeg"
"image/png"
"os"
"path/filepath"
"strings"

"golang.org/x/image/bmp"
)

type Client struct {

// tgtExt:変換先のファイル形式
tgtExt string
// savePath:保存先ディレクトリ、存在しない場合新たに作成されます
savePath string
// 変換対象の画像リスト
images []string
}

func New(tgtExt, savePath string, images []string) *Client {
return &Client{

tgtExt: tgtExt,
savePath: savePath,
images: images,
}
}

func (c *Client) Convert() {

if _, err := os.Stat(c.savePath); os.IsNotExist(err) {
os.MkdirAll(c.savePath, 0755)
}

for _, image := range c.images {
err := convertImage(image, c.tgtExt, c.savePath)
if err != nil {
fmt.Println(err)
}
}

return
}

//一枚の画像を特定のフォーマットに変換し指定のディレクトリに保存します
func convertImage(imgPath, tgtExt, savePath string) (err error) {

if tgtExt == filepath.Ext(imgPath) {
err = fmt.Errorf("file \"%s\"'s extension is already %s, conversion skipped", imgPath, tgtExt)
}
if err == nil {
src, err := os.Open(imgPath)
if err == nil {
defer src.Close()
decoded, err := decode(src)

if err == nil {
name := imgPath[0 : len(imgPath)-len(filepath.Ext(imgPath))]
name = filepath.Base(name)

tgt, err := os.Create(savePath + "/" + name + tgtExt)
if err == nil {
defer tgt.Close()
err = encode(tgt, decoded)
}
}
}
}
return
}

//画像のデコードを行います
func decode(srcImg *os.File) (decodedImg image.Image, err error) {
name := srcImg.Name()
ext := filepath.Ext(name)
switch strings.ToLower(ext) {
case ".jpg", ".jpeg":
decodedImg, err = jpeg.Decode(srcImg)
case ".png":
decodedImg, err = png.Decode(srcImg)
case ".gif":
decodedImg, err = gif.Decode(srcImg)
case ".bmp":
decodedImg, err = bmp.Decode(srcImg)
}

return
}

//特定の形式へのエンコードを行います
func encode(tgt *os.File, decodedImg image.Image) (err error) {
name := tgt.Name()
ext := filepath.Ext(name)
switch strings.ToLower(ext) {
case ".jpg", ".jpeg":
opt := &jpeg.Options{Quality: 100}
err = jpeg.Encode(tgt, decodedImg, opt)
case ".png":
err = png.Encode(tgt, decodedImg)
case ".gif":
opt := &gif.Options{}
err = gif.Encode(tgt, decodedImg, opt)
case ".bmp":
err = bmp.Encode(tgt, decodedImg)
}

return
}
Binary file added kadai2/nejiyoshida/imgconverter/test/1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added kadai2/nejiyoshida/imgconverter/test/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.