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

[課題1]画像変換コマンドを作る akhr77 #16

Open
wants to merge 7 commits 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
1 change: 1 addition & 0 deletions kadai1/akhr77/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/bin/
20 changes: 20 additions & 0 deletions kadai1/akhr77/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
GOCMD=go
GOFMT=$(GOCMD) fmt
GOVET=$(GOCMD) vet
GOLINT=golint
GOTEST=$(GOCMD) test
BINARYNAME=bin/imgconv

export GO111MODULE=off

.PHONY: build
build: ## go build
go build -o ${BINARYNAME} cmd/imgconv/main.go
fmt:
${GOFMT} ./...
${GOVET} ./...
${GOLINT} ./...

check:
${GOTEST} ./... -v
${GOTEST} ./... -cover
26 changes: 26 additions & 0 deletions kadai1/akhr77/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Gopher道場課題1

## 次の仕様を満たすコマンドを作って下さい
- ディレクトリを指定する
- 指定したディレクトリ以下のJPGファイルをPNGに変換(デフォルト)
- ディレクトリ以下は再帰的に処理する

## 以下を満たすように開発してください
- mainパッケージと分離する
- 自作パッケージと標準パッケージと準標準パッケージのみ使う
- ユーザ定義型を作ってみる
- GoDocを生成してみる

----------------------------------

## Installation

```bash
$ make
```

## Usage
```bash
$ cd bin
$ ./imgconv -s ../testdata -f jpg -t png
```
12 changes: 12 additions & 0 deletions kadai1/akhr77/cmd/imgconv/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import (
"os"

"github.com/akhr77/dojo7/kadai1/akhr77/pkg/imgconv"
)

func main() {
cli := &imgconv.CLI{OutStream: os.Stdout, ErrStream: os.Stderr}
os.Exit(cli.Run(os.Args))
}
134 changes: 134 additions & 0 deletions kadai1/akhr77/pkg/imgconv/imgconv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package imgconv

import (
"flag"
"fmt"
"image"
"image/gif"
"image/jpeg"
"image/png"
"io"
"log"
"os"
"path/filepath"
"strings"
)

// return Code
const (
ExitCodeOK = 0
ExitCodeError = 1
)

// CLI struct
type CLI struct {
OutStream, ErrStream io.Writer
}

var (
src string
from string
to string
)

// Run is implements function
func (c *CLI) Run(args []string) int {
log.Printf("\x1b[33m%s\x1b[0m\n", "[imgconv start]")
flags := flag.NewFlagSet(args[0], flag.ContinueOnError)
flags.SetOutput(c.ErrStream)
// ショートオプション
flags.StringVar(&src, "s", "", "変換したい画像のファイルパスを指定")
flags.StringVar(&from, "f", "jpg", "変換前の画像形式を指定")
flags.StringVar(&to, "t", "png", "変換後の画像形式を指定")
// ロングオプション
flags.StringVar(&src, "src", "", "変換したい画像のファイルパスを指定")
flags.StringVar(&from, "from", "jpg", "変換前の画像形式を指定")
flags.StringVar(&to, "to", "png", "変換後の画像形式を指定")

if err := flags.Parse(args[1:]); err != nil {
fmt.Fprintf(c.ErrStream, "解析処理でエラーになりました")
return ExitCodeError
}

if !supportFormat(from) {
fmt.Fprintf(c.ErrStream, "-fオポションで指定指定画像形式はサポートしていません")
}
if !supportFormat(to) {
fmt.Fprintf(c.ErrStream, "-tオポションで指定指定画像形式はサポートしていません")
}

err := walk(src, from, to)
if err != nil {
return ExitCodeError
}

log.Printf("\x1b[33m%s\x1b[0m\n", "[imgconv end]")
return ExitCodeOK
}

// walkは第一引数以下のディレクトリを再帰的に処理する
func walk(root, beforeExt, afterExt string) error {
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
n := info.Name()
if strings.HasSuffix(n, beforeExt) {
src, err := os.Open(path)
if err != nil {
return err
}
defer src.Close()

// extentionを含まないファイル名
n := filepath.Base(n[:len(n)-len(filepath.Ext(n))])
dir := filepath.Dir(path)
dest, err := os.Create(filepath.Join(dir, n+"."+afterExt))
if err != nil {
return err
}

log.Printf("\x1b[33m%s%s -> %s\x1b[0m\n", "[replace file]", path, afterExt)
err = convert(src, dest, afterExt)
if err != nil {
// 変換処理に失敗した場合、不要なファイルが作成されてしまうため、削除する
dest.Close()
e := os.Remove(filepath.Join(dir, n+"."+afterExt))
if e != nil {
return e
}
return err
}
}
return nil
})
if err != nil {
return err
}
return nil
}

func supportFormat(extention string) bool {
var supportedFormats = map[string]bool{"jpg": true, "jpeg": true, "png": true, "gif": true}
_, ok := supportedFormats[extention]
return ok
}

func convert(src io.Reader, dest io.Writer, extention string) error {
img, _, err := image.Decode(src)
if err != nil {
return err
}
switch extention {
case "jpg", "jpeg":
err = jpeg.Encode(dest, img, nil)
case "png":
err = png.Encode(dest, img)
case "gif":
err = gif.Encode(dest, img, nil)
}
if err != nil {
return err
}
return nil
}
Binary file added kadai1/akhr77/testdata/testdata_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 kadai1/akhr77/testdata/testdata_2.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/akhr77/testdata/testdata_3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.