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

# Wataru / boru 課題1 #2

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions kadai1/wataboru/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.idea
.DS_Store
go.sum
Copy link
Member

Choose a reason for hiding this comment

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

ignoreする必要はないですね

52 changes: 52 additions & 0 deletions kadai1/wataboru/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# 課題 1 【TRY】画像変換コマンドを作ろう

## 次の仕様を満たすコマンドを作って下さい

- ディレクトリを指定する
- 指定したディレクトリ以下の JPG ファイルを PNG に変換(デフォルト)
- ディレクトリ以下は再帰的に処理する
- 変換前と変換後の画像形式を指定できる(オプション)

## 以下を満たすように開発してください

- main パッケージと分離する
- 自作パッケージと標準パッケージと準標準パッケージのみ使う
- 準標準パッケージ:golang.org/x 以下のパッケージ
- ユーザ定義型を作ってみる
- GoDoc を生成してみる
- Go Modules を使ってみる

### 動作手順

```
$ go build -o imageconverter
$ ./imgconv -h
Usage of ./imgconv:
-a string
Input extension after conversion. (short) (default "png")
-after --after=jpg
Input extension after conversion.
ex) --after=jpg (default "png")
-b string
Input extension before conversion. (short) (default "jpg")
-before --before=png
Input extension before conversion.
ex) --before=png (default "jpg")
-d string
Input target Directory. (short)
-dir --dir=./convert_image
Input target Directory.
ex) --dir=./convert_image
$ ./imgconv -d ./image
or
$ ./imgconv -d ./image -b png -a gif
Copy link
Member

Choose a reason for hiding this comment

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

テスト用の画像は testdata というディレクトリを作ってその下に入れましょう。
testdata という名前のディレクトリはGoにパッケージとして認識されません。
同様に_で始まるディレクトリ(よく_exampleとして使用される)や.で始まるディレクトリも無視されます。

or
$ ./imgconv -d ./image -b jpeg -a tiff
```

### 感想等

- 前提として、@tenntennさんの公開されている[handsonプロジェクト](https://github.com/tenntenn/gohandson/tree/master/imgconv/ja)と似ている内容でして、以前やったことがありました。
- そちらに無い部分として、tiff変換やbmp変換の追加などを行いました。
- GoModulesを利用したく、`golang.org/x/image`を導入しました
Copy link
Member

Choose a reason for hiding this comment

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

👍

- 様々なソースをみていると、変数名やコマンド名が自分は冗長かな?と感じています。Go話者の方は短く記載するものなのでしょうか。
55 changes: 55 additions & 0 deletions kadai1/wataboru/commands/imageconverter/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package main

import (
"dojo8/kadai1/wataboru/imageconverter"
Copy link
Member

Choose a reason for hiding this comment

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

github.comからのパスの方が好ましいです。


"flag"
"fmt"
"os"
)

const (
// ExitCodeSuccess is the exit code on success
ExitCodeSuccess int = iota
Copy link
Member

Choose a reason for hiding this comment

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

終了コードは外部に伝えるものなので iota は使わない方が安全です。
iota を使う値は区別さえできればOKで値として意味がないものに限ります。
終了コードは0が成功、それ以外が失敗という値に意味を持っているので使わないほうがが良いです。
DBに入れる値なんかも同様です。

// ExitCodeError is the exit code when failed
ExitCodeError
// ExitCodeError is the exit code when failed
ExitCodeInvalidDirectoryError
)

var (
args imageconverter.Args
)

func init() {
flag.StringVar(&args.Directory, "dir", "", "Input target Directory.\n ex) `--dir=./convert_image`")
flag.StringVar(&args.Directory, "d", "", "Input target Directory. (short)")
flag.StringVar(&args.BeforeExtension, "before", "jpg", "Input extension before conversion.\n ex) `--before=png`")
flag.StringVar(&args.BeforeExtension, "b", "jpg", "Input extension before conversion. (short)")
flag.StringVar(&args.AfterExtension, "after", "png", "Input extension after conversion.\n ex) `--after=jpg`")
flag.StringVar(&args.AfterExtension, "a", "png", "Input extension after conversion. (short)")
flag.Parse()
}

func run() int {
if args.Directory == "" {
fmt.Fprintln(os.Stderr, "Input target Directory.\n ex) `--dir=./convert_image`")
return ExitCodeInvalidDirectoryError
}

if _, err := os.Stat(args.Directory); os.IsNotExist(err) {
fmt.Fprintln(os.Stderr, "Target directory is not found.")
return ExitCodeInvalidDirectoryError
}

if err := imageconverter.Convert(args); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
return ExitCodeError
}

return ExitCodeSuccess
}

func main() {
os.Exit(run())
}
5 changes: 5 additions & 0 deletions kadai1/wataboru/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module dojo8/kadai1/wataboru

go 1.14

require golang.org/x/image v0.0.0-20200618115811-c13761719519
Binary file added kadai1/wataboru/image/free-icon.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/wataboru/image/sub/free-icon.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
81 changes: 81 additions & 0 deletions kadai1/wataboru/imageconverter/ImageConverter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package imageconverter

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

"golang.org/x/image/tiff"

Copy link
Member

Choose a reason for hiding this comment

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

詰める

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

type Args struct {
Directory string
BeforeExtension string
AfterExtension string
}

func convertImage(source, dest string) error {
sourceFile, err := os.Open(source)
if err != nil {
return fmt.Errorf("file could not be opened. target: %s", source)
}
defer sourceFile.Close()

destFile, err := os.Create(dest)
if err != nil {
return fmt.Errorf("image file could not be created. target: %s", dest)
}
defer destFile.Close()
Copy link
Member

Choose a reason for hiding this comment

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

Create は書き込みの処理なので、Close する際にもエラー処理をする。


img, _, err := image.Decode(sourceFile)
if err != nil {
return err
}

switch strings.ToLower(filepath.Ext(dest)) {
case ".png":
return png.Encode(destFile, img)
case ".jpg", ".jpeg":
return jpeg.Encode(destFile, img, &jpeg.Options{Quality: jpeg.DefaultQuality})
case ".gif":
return gif.Encode(destFile, img, &gif.Options{256, nil, nil})
case ".bmp":
return bmp.Encode(destFile, img)
case ".tiff":
return tiff.Encode(destFile, img, nil)
default:
return fmt.Errorf("image file could not be created due to an unknown extension. target: %s", dest)
}

return nil
}

// 指定したディレクトリ以下のJPGファイルをPNGに変換(デフォルト)
// ディレクトリ以下は再帰的に処理する
// 変換前と変換後の画像形式を指定できる(オプション)
func Convert(args Args) error {
return filepath.Walk(args.Directory, func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Printf("prevent panic by handling failure accessing a path %q: %v\n", path, err)
Copy link
Member

Choose a reason for hiding this comment

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

エラーをreturnするならログを出さない。
ログを出すならエラーを返さない。
エラーログの出力もエラーハンドリングの1つでエラーハンドリングは1度だけにする。
出すとしても標準エラー出力の方が好ましそう。

return err
}

ext := strings.ToLower(filepath.Ext(path))
if "."+args.BeforeExtension != ext {
return nil
}

return convertImage(path, replaceExt(info.Name(), "."+args.AfterExtension))
})
}

func replaceExt(filePath, toExt string) string {
return filePath[:len(filePath)-len(filepath.Ext(filePath))] + toExt
}