Skip to content

Kadai1 nejiyoshida #8

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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 kadai1/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 kadai1/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 kadai1/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 kadai1/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)
}

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
}
45 changes: 45 additions & 0 deletions kadai1/nejiyoshida/dircrawler/dircrawler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
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) {
testCase1 := []string{"a.txt",
"b.jpg",
"c.jpg",
"d.html"}
ret1 := []string{"b.jpg", "c.jpg"}
if !reflect.DeepEqual(selectFormat(testCase1, ".jpg"), ret1) {
t.Fatal("testCase1 does not match")
}

}

func TestIsSpecifiedFormat(t *testing.T) {

if !isSpecifiedFormat("./hoge/huga.jpg", ".jpg") {
t.Fatal("isSpecifiedFormat(\"./hoge/huga.jpg\" , \"jpg\") should be true, but false")
}
}
func TestSearchFilePaths(t *testing.T) {
ret := []string{"test\\TEST\\bar.txt", "test\\TEST\\gopher.jpg", "test\\foo.txt"}
if !reflect.DeepEqual(searchFilePaths("./test"), ret) {
t.Fatal("does not match")

}
}
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 kadai1/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 kadai1/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 kadai1/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")
}
122 changes: 122 additions & 0 deletions kadai1/nejiyoshida/imgconverter/imgconverter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// 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) error {

if tgtExt == filepath.Ext(imgPath) {
err := fmt.Errorf("file \"%s\"'s extension is already %s, conversion skipped", imgPath, tgtExt)
return err
}

src, err := os.Open(imgPath)
if err != nil {

return err
}
defer src.Close()

decoded, err := decode(src)
if err != nil {
return err
}

name := imgPath[0 : len(imgPath)-len(filepath.Ext(imgPath))]
name = filepath.Base(name)

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

err = encode(tgt, decoded)

return err
}

//画像のデコードを行います
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
}