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

Kadai1 Hiroya-W #81

Open
wants to merge 19 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
2 changes: 2 additions & 0 deletions kadai1/hiroya-w/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bin/
.DS_Store
31 changes: 31 additions & 0 deletions kadai1/hiroya-w/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
SRC := main.go imgconv/imgconv.go

.PHONY: build
build: bin/imgconv

bin/imgconv: $(SRC)
go build -o bin/imgconv .

.PHONY: run
run: build
./bin/imgconv -input-type=png -output-type=jpg testdata

.PHONY: test
test: build testdata-gen run

.PHONY: testdata-gen
testdata-gen:
cd testdata && ./init.sh

.PHONY: check
check:
errcheck ./...

.PHONY: doc
doc:
godoc -http=:8080

.PHONY: clean
clean:
-rm bin/imgconv
-rm testdata/*.jpg testdata/*jpeg testdata/*.png testdata/*.gif
55 changes: 55 additions & 0 deletions kadai1/hiroya-w/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# 課題1

## 画像変換コマンドを作成する

- 次の仕様を満たすコマンドを作って下さい
- ディレクトリを指定する
- 指定したディレクトリ以下のJPGファイルをPNGに変換(デフォルト)
- ディレクトリ以下は再帰的に処理する
- 変換前と変換後の画像形式を指定できる(オプション)
- 以下を満たすように開発してください
- mainパッケージと分離する
- 自作パッケージと標準パッケージと準標準パッケージのみ使う
- 準標準パッケージ:golang.org/x 以下のパッケージ
- ユーザ定義型を作ってみる
- GoDocを生成してみる
- Go Modulesを使ってみる

## usage

```
.bin/imgconv -h
Usage of .bin/imgconv:
-input-type string
input type[jpg|jpeg|png|gif] (default "jpg")
-output-type string
output type[jpg|jpeg|png|gif] (default "png")
```

基本的なコマンドは `Makefile` で利用できます。

### build

ビルドすると `bin` フォルダに `imgconv` のバイナリが生成されます。


```
make build
```

### run

`testdata` ディレクトリ内にあるPNG画像ファイルをJPG画像ファイルに変換します。

```
make run
```

### test

`testdata` にテスト用の画像を生成してから、 `make run` を実行します。
画像データを用いた実行を行うだけで、テストを行っているわけではありません。

```
make test
```
3 changes: 3 additions & 0 deletions kadai1/hiroya-w/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module imgconv

go 1.17
130 changes: 130 additions & 0 deletions kadai1/hiroya-w/imgconv/imgconv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
Package imgconv provides image converter functions.
JPG, PNG, and GIF are supported.
*/
package imgconv

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

// Converter converts the inputType format images in the directory to outputType format.
func Converter(directory, inputType, outputType string) error {
imgPaths, err := getFiles(directory, inputType)
if err != nil {
return err
}

for _, path := range imgPaths {
if err := convert(path, outputType); err != nil {
return err
}
}
return nil
}

// getFiles returns a list of file paths in a directory with the file extension specified by inputType.
func getFiles(directory, inputType string) ([]string, error) {
var imgPaths []string

if f, err := os.Stat(directory); err != nil {
return nil, err
} else if !f.IsDir() {
return nil, fmt.Errorf("%s is not a directory", directory)
}

err := filepath.Walk(directory, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if filepath.Ext(path) == "."+inputType {
imgPaths = append(imgPaths, path)
}
return nil
})

if err != nil {
return nil, err
}

return imgPaths, nil
}

// convert converts the image at filePath to the outputType format.
func convert(filePath, outputType string) error {
f, err := os.Open(filePath)
if err != nil {
return err
}
defer func() {
if err := f.Close(); err != nil {
log.Printf("Error closing file: %s\n", err)
}
}()

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

outputPath := renameExt(filePath, outputType)
output, err := os.Create(outputPath)
if err != nil {
return err
}
defer func() {
if err := output.Close(); err != nil {
log.Printf("Error closing file: %s\n", err)
}
}()

switch outputType {
case "jpg", "jpeg":
return convertJPG(img, output)
case "png":
return convertPNG(img, output)
case "gif":
return convertGIF(img, output)
default:
return fmt.Errorf("%s is not a supported output type", outputType)
}
}

// renameExt renames the file extension of the file at filePath to newExt.
func renameExt(filePath, newExt string) string {
return filePath[:len(filePath)-len(filepath.Ext(filePath))] + "." + newExt
}

// convertJPG converts the image to the JPEG format.
func convertJPG(img image.Image, output *os.File) error {
if err := jpeg.Encode(output, img, nil); err != nil {
return err
}
return nil
}

// convertJPG converts the image to the PNG format.
func convertPNG(img image.Image, output *os.File) error {
if err := png.Encode(output, img); err != nil {
return err
}
return nil
}

// convertJPG converts the image to the GIF format.
func convertGIF(img image.Image, output *os.File) error {
if err := gif.Encode(output, img, nil); err != nil {
return err
}
return nil
}
66 changes: 66 additions & 0 deletions kadai1/hiroya-w/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package main

import (
"flag"
"fmt"
"imgconv/imgconv"
"log"
)

type Options struct {
inputType string
outputType string
directory string
}

var opt Options

func init() {
flag.StringVar(&opt.inputType, "input-type", "jpg", "input type[jpg|jpeg|png|gif]")
flag.StringVar(&opt.outputType, "output-type", "png", "output type[jpg|jpeg|png|gif]")
}

// validateType validates the type of the image
func validateType(t string) error {
switch t {
case "jpg", "jpeg", "png", "gif":
return nil
default:
return fmt.Errorf("invalid type: %s", t)
}
}

// validateArgs validates the arguments
func validateArgs() error {
flag.Parse()

if opt.inputType == opt.outputType {
return fmt.Errorf("input and output type can't be the same")
}

if err := validateType(opt.inputType); err != nil {
return err
}

if err := validateType(opt.outputType); err != nil {
return err
}

if flag.Arg(0) == "" {
return fmt.Errorf("directory is required")
} else {
opt.directory = flag.Arg(0)
}

return nil
}

func main() {
if err := validateArgs(); err != nil {
log.Fatalln(err)
}

if err := imgconv.Converter(opt.directory, opt.inputType, opt.outputType); err != nil {
log.Fatalln(err)
}
}
4 changes: 4 additions & 0 deletions kadai1/hiroya-w/testdata/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.png
*.jpg
*.jpeg
*.gif
9 changes: 9 additions & 0 deletions kadai1/hiroya-w/testdata/init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh
curl https://avatars.githubusercontent.com/hiroya-w -o hiroya-w.png

for i in {1..10}
do
cp hiroya-w.png image$i.png
done

rm hiroya-w.png