diff --git a/kadai1/saza/.gitignore b/kadai1/saza/.gitignore new file mode 100644 index 00000000..914da327 --- /dev/null +++ b/kadai1/saza/.gitignore @@ -0,0 +1,129 @@ +gibo 2.2.4 by Simon Whitaker +https://github.com/simonwhitaker/gibo +### https://raw.github.com/github/gitignore/218a941be92679ce67d0484547e3e142b2f5f6f0/Global/macOS.gitignore + +# General +.DS_Store +.AppleDouble +.LSOverride +bin/ +testdata/ + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + + +### https://raw.github.com/github/gitignore/218a941be92679ce67d0484547e3e142b2f5f6f0/Go.gitignore + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + + +### https://raw.github.com/github/gitignore/218a941be92679ce67d0484547e3e142b2f5f6f0/Global/JetBrains.gitignore + +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + + diff --git a/kadai1/saza/.idea/.gitignore b/kadai1/saza/.idea/.gitignore new file mode 100644 index 00000000..73f69e09 --- /dev/null +++ b/kadai1/saza/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/kadai1/saza/.idea/modules.xml b/kadai1/saza/.idea/modules.xml new file mode 100644 index 00000000..59d5b25a --- /dev/null +++ b/kadai1/saza/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/kadai1/saza/.idea/saza.iml b/kadai1/saza/.idea/saza.iml new file mode 100644 index 00000000..cb113615 --- /dev/null +++ b/kadai1/saza/.idea/saza.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/kadai1/saza/.idea/vcs.xml b/kadai1/saza/.idea/vcs.xml new file mode 100644 index 00000000..b2bdec2d --- /dev/null +++ b/kadai1/saza/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/kadai1/saza/.idea/watcherTasks.xml b/kadai1/saza/.idea/watcherTasks.xml new file mode 100644 index 00000000..272cee1c --- /dev/null +++ b/kadai1/saza/.idea/watcherTasks.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/kadai1/saza/Makefile b/kadai1/saza/Makefile new file mode 100644 index 00000000..ca50bc33 --- /dev/null +++ b/kadai1/saza/Makefile @@ -0,0 +1,11 @@ +.PHONY: build +build: + @go build -o bin/imgconv . + +.PHONY: run +run: ready build + @./bin/imgconv testdata + +.PHONY: ready +ready: + @./init.sh diff --git a/kadai1/saza/README.md b/kadai1/saza/README.md new file mode 100644 index 00000000..4be86824 --- /dev/null +++ b/kadai1/saza/README.md @@ -0,0 +1,30 @@ +# 課題 1: imgconv + +指定されたディレクトリ以下の画像ファイルを異なる形式に変換するコンソールアプリケーションです。 + +### Usage +``` +imgconv [-s ] [-d ] +``` + +`-s` で指定した形式の画像ファイルを、`-d` で指定した形式に変換します。 + +例えば、jpeg ファイルを png ファイルに変換すると、 +指定されたディレクトリ以下の jpeg ファイル、`hoge.jpeg` に対し、 +同じディレクトリにそれを png ファイルに変換した `hoge.png` が生成されます。 + +オプションの画像形式で指定できるものは以下の通りです。 + +- `jpg`: jpeg ファイル +- `png`: png ファイル +- `gif`: gif ファイル + +オプションを指定しない場合、jpeg ファイルを png ファイルに変換します。 + +### make コマンド + +#### ビルド +`make build` でビルドでき、 `bin/imgconv` が出力されます。 + +#### 実行 +また、`make run` で `testdata/` にサンプルデータを生成し、それをターゲットとして実行することができます。 diff --git a/kadai1/saza/go.mod b/kadai1/saza/go.mod new file mode 100644 index 00000000..acad1812 --- /dev/null +++ b/kadai1/saza/go.mod @@ -0,0 +1,3 @@ +module github.com/saza-ku/gopherdojo-studyroom/kadai1/saza + +go 1.17 diff --git a/kadai1/saza/imgconv/converter.go b/kadai1/saza/imgconv/converter.go new file mode 100644 index 00000000..beffc5d6 --- /dev/null +++ b/kadai1/saza/imgconv/converter.go @@ -0,0 +1,154 @@ +package imgconv + +import ( + "fmt" + "image" + "image/gif" + "image/jpeg" + "image/png" + "io" + "os" + "path/filepath" + "strings" +) + +type converter struct { + root string + src fileType + dest fileType +} + +// Converter provides a function that convert image file format. +type Converter interface { + Run() +} + +// NewConverter creates a new Converter object, +// specifying root directory, src image file format, and dest image file format. +func NewConverter(root string, src string, dest string) Converter { + return converter{ + root: root, + src: extToType(src), + dest: extToType(dest), + } +} + +type fileType int + +const ( + jpegType = iota + pngType + gifType + others +) + +func (ft fileType) String() string { + switch ft { + case jpegType: + return "jpg" + case pngType: + return "png" + case gifType: + return "gif" + case others: + return "other type" + default: + return "invalid fileType" + } +} + +func extToType(ext string) fileType { + switch ext { + case ".jpg", ".jpeg", "jpg", "jpeg": + return jpegType + case ".png", "png": + return pngType + case ".gif", "gif": + return gifType + default: + return others + } +} + +func (c converter) Run() { + err := filepath.Walk(c.root, func(path string, info os.FileInfo, err error) error { + if info.IsDir() { + return err + } + + ext := filepath.Ext(path) + ft := extToType(ext) + + if ft == c.src { + err = convert(path, c.src, c.dest) + if err != nil { + return err + } + } + + return err + }) + + if err != nil { + fmt.Println("Error: " + err.Error()) + } +} + +func convert(src string, srcType fileType, destType fileType) error { + file, err := os.Open(src) + if err != nil { + return err + } + defer closeFile(file) + + img, _, err := image.Decode(file) + if err != nil { + return err + } + + dest := changeExt(src, destType) + out, err := os.Create(dest) + if err != nil { + return err + } + defer closeFile(out) + + err = encode(out, img, destType) + + if err == nil { + fmt.Printf("converted %s image \"%s\" to %s image \"%s\"\n", + srcType, src, destType, dest) + } + + return err +} + +func changeExt(path string, destExt fileType) string { + path = strings.TrimSuffix(path, filepath.Ext(path)) + return path + "." + destExt.String() +} + +func encode(out io.Writer, img image.Image, dest fileType) error { + var err error + + switch dest { + case jpegType: + err = jpeg.Encode(out, img, &jpeg.Options{}) + case pngType: + err = png.Encode(out, img) + case gifType: + err = gif.Encode(out, img, &gif.Options{}) + default: + panic("unknown output file type") + } + + return err +} + +func closeFile(f *os.File) { + err := f.Close() + if err != nil { + fmt.Printf("failed to close file: %s\n", err) + panic(err) + } +} diff --git a/kadai1/saza/init.sh b/kadai1/saza/init.sh new file mode 100755 index 00000000..9193ae13 --- /dev/null +++ b/kadai1/saza/init.sh @@ -0,0 +1,14 @@ +#!/bin/sh +rm -rf testdata +mkdir testdata +mkdir testdata/fuga + +for i in {1..9} +do + cp sample/morpeco-sample.jpeg testdata/hoge"$i".jpg +done + +for i in {1..9} +do + cp sample/morpeco-sample.jpeg testdata/fuga/hoge"$i".jpeg +done diff --git a/kadai1/saza/main.go b/kadai1/saza/main.go new file mode 100644 index 00000000..d172e91d --- /dev/null +++ b/kadai1/saza/main.go @@ -0,0 +1,74 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/saza-ku/gopherdojo-studyroom/kadai1/saza/imgconv" +) + +var ( + root string + src string + dest string + + types = []string{"jpg", "png", "gif"} +) + +func init() { + flag.StringVar(&src, "s", "jpg", "source image type") + flag.StringVar(&dest, "d", "png", "destination image type") + flag.Parse() +} + +func main() { + if err := validateInput(); err != nil { + fmt.Println(err) + return + } + + root = flag.Args()[0] + c := imgconv.NewConverter(root, src, dest) + + c.Run() +} + +func validateInput() error { + // check argument + if len(flag.Args()) == 0 { + return fmt.Errorf("target directory is not provided") + } + if len(flag.Args()) > 1 { + return fmt.Errorf("too many arguments") + } + + // check whether root exists + r := flag.Args()[0] + if f, err := os.Stat(r); err != nil || !f.IsDir() { + return fmt.Errorf("directory %s doesn't exists", root) + } + + // check image types + valid := false + for _, t := range types { + if src == t { + valid = true + } + } + if !valid { + return fmt.Errorf("image type %s is invalid", src) + } + + valid = false + for _, t := range types { + if dest == t { + valid = true + } + } + if !valid { + return fmt.Errorf("image type %s is invalid", src) + } + + return nil +} diff --git a/kadai1/saza/sample/morpeco-sample.jpeg b/kadai1/saza/sample/morpeco-sample.jpeg new file mode 100644 index 00000000..ee7bce99 Binary files /dev/null and b/kadai1/saza/sample/morpeco-sample.jpeg differ