go言語で画像を作成(編集)する【imagemagick】
ImageMagick
画像編集するライブラリで超優秀なやつ
文字列の設定なども可能
フォントは微妙
インストール(Mac)
brew install ruby brew install ImageMagick brew install pkg-config go get gopkg.in/gographics/imagick.v3/imagick
※rubyは2.3以上
※imagickはimagemagickのインストールバージョンで切り替え
実装
sample2.go
package main import ( "gopkg.in/gographics/imagick.v3/imagick" // "fmt" ) func main() { var err error imagick.Initialize() defer imagick.Terminate() mw := imagick.NewMagickWand() dw := imagick.NewDrawingWand() pw := imagick.NewPixelWand() defer mw.Destroy() // 短形を作成 pw.SetColor("none") mw.NewImage(400, 300, pw) // フォント設定 pw.SetColor("RGB(255, 0, 125)") dw.SetFillColor(pw) dw.SetFontSize(60) pw.SetColor("RGB(255, 0, 125)") dw.SetStrokeColor(pw) // テキスト設定 dw.Annotation(25, 65, "Sample") // 短形の描画(塗りつぶしなし) pw.SetColor("RGB(100, 100, 100)") dw.SetStrokeColor(pw) dw.SetStrokeWidth(4) pw.SetColor("none") dw.SetFillColor(pw) dw.Rectangle(50, 150, 120, 250) dw.PushDrawingWand() // 描画 mw.DrawImage(dw) // 合成用 pw2 := imagick.NewPixelWand() mw2 := imagick.NewMagickWand() defer mw2.Destroy() pw2.SetColor("blue") mw2.NewImage(120, 100, pw2) // 指定の場所へ合成 err = mw.CompositeImage(mw2, mw2.GetImageCompose(), true, 100, 100) if err != nil { panic(err) } // 出力フォーマット err = mw.SetFormat("png") if err != nil { panic(err) } // ファイルへ出力 mw.WriteImage("text_shadow.png") }
↓
所感
文字列を挿入できました(^^)
まあ、あまり画像を使うことはないですがとりあえず覚えておこうかと思います。
go言語で超シンプルな画像作成
画像を作成
短形の画像を作成する。
実装
sample1.go
package main import ( "log" "image" "image/jpeg" "image/color" "os" ) var ( x = 0 y = 0 width = 400 height = 300 quality = 100 ) func main() { log.Println("start") // 短形を作成する img := image.NewRGBA(image.Rect(x, y, width, height)) // 短形に色を追加 for i := img.Rect.Min.Y; i<img.Rect.Max.Y;i++ { for j := img.Rect.Min.X; j<img.Rect.Max.X; j++ { img.Set(j, i, color.RGBA{255, 255, 0, 0}) } } // ファイルを作成し、終了時にクローズ file, _ := os.Create("sampleImage1.jpg") defer file.Close() err := jpeg.Encode(file, img, &jpeg.Options{quality}); if err != nil { log.Println(err) } log.Println("end") }
結果
所感
文字列が入力してみたいけどネットで探したけど見つからない…
探してもう少し探してみる
go言語でflagを使用したパラメータ指定を行う
とにかく実装
sample1.go
package main import ( "log" "flag" "os" ) // 引数取得エリア type ParamItem struct { Url string Count int User string Pass string } // 引数を指定して値を受け取る処理 func main() { // 処理開始 log.Println("start") param := new(ParamItem) // flagObj := flag.NewFlagSet(os.Args[0], flag.ExitOnError) // 引数を登録 flagObj.StringVar(¶m.Url, "url", "", "URLを設定してください。") flagObj.StringVar(¶m.User, "user", "", "ユーザ名を設定してください。") flagObj.StringVar(¶m.Pass, "pass", "", "パスワードを設定してください。") // パース処理 flagObj.Parse(os.Args[1:]) for 0 < flagObj.NArg() { flagObj.Parse(flagObj.Args()[1:]) } log.Println("url = " + param.Url) log.Println("user = " + param.User) log.Println("pass = " + param.Pass) // 処理終了 log.Println("end") }
↓
$ go run sample1.go -url http://hogehoge.com -user aaa -pass 1234 2017/10/28 17:29:07 start 2017/10/28 17:29:07 url = http://hogehoge.com 2017/10/28 17:29:07 user = aaa 2017/10/28 17:29:07 pass = 1234 2017/10/28 17:29:07 end $
ヘルプコマンドの場合
$ go run sample1.go -help 2017/10/28 17:29:46 start -pass string パスワードを設定してください。 -url string URLを設定してください。 -user string ユーザ名を設定してください。 exit status 2 $
順番ってキー名の昇順?
所感
項目名と連動するので引数で何が必要かなどの指定を用意しやすい。
設定ファイルでの読み込みと合わせて行えば役に立ちそう
go言語で設定ファイルを読み込み2(別パッケージにして扱う)
1つのファイルの場合
はメンテしづらいので分割する
ファイル構成
. ├── config │ └── appconfig.go ├── config.json └── sample2.go
こんな感じ
実装
config.json
{ "url": "http://hogehoge.com", "count": 100, "user": "hoge", "pass": "foo" }
config/appconfig.go
package config import ( "io/ioutil" "encoding/json" ) // 構造体定義 type Config struct { Url string `json:"url"` Count int `json:"count"` User string `json:"user"` Pass string `json:"pass"` } // configファイルを読み込み構造体へ割当 func Read(filename string) (*Config, error) { // 構造体を定義 c := new(Config) // 設定ファイルを読み込む jsonString, err := ioutil.ReadFile(filename) if err != nil { // エラー return c, err } // 設定 err = json.Unmarshal(jsonString, c) if err != nil { // エラー return c, err } // 正常 return c, nil }
sample2.go
package main import ( "log" "os" "strconv" "./config" ) // jsonの設定ファイルを読み込むサンプル func main() { // 処理開始 log.Println("start") // 構造体へconfigの結果を設定 c, err := config.Read("config.json") if err != nil { log.Println(err) os.Exit(1) } // 結果出力 log.Println("url = " + c.Url) log.Println("count = " + strconv.Itoa(c.Count)) log.Println("user = " + c.User) log.Println("pass = " + c.Pass) // 処理終了 log.Println("end") }
所感
うん、まあそれなりにスッキリした感じです。
構造体の場合は値渡しか参照渡しとなるかをきちんと考える必要がある
go言語でjson形式の設定ファイルを読み込む
実行する際の変数の外出
設定ファイルにして配置しておくとやりやすいので対応する。
前提
設定ファイルはjson
実装
config.json
{ "url": "http://hogehoge.com", "count": 100, "user": "hoge", "pass": "foo" }
sample1.go
package main import ( "log" "os" "io/ioutil" "encoding/json" "strconv" ) // jsonの設定ファイルを読み込むサンプル func main() { // 処理開始 log.Println("start") jsonString, err := ioutil.ReadFile("config.json") if err != nil { log.Println(err) os.Exit(1) } // config.jsonの中身を出力 // そのままだとbyteデータになるのでstringに変換 log.Println(string(jsonString)) // 構造体定義 type Config struct { Url string `json:"url"` Count int `json:"count"` User string `json:"user"` Pass string `json:"pass"` } // 設定変数用意 c := new(Config) // 設定 err = json.Unmarshal(jsonString, c) if err != nil { log.Println(err) os.Exit(2) } // 結果出力 log.Println("url = " + c.Url) log.Println("count = " + strconv.Itoa(c.Count)) log.Println("user = " + c.User) log.Println("pass = " + c.Pass) // 処理終了 log.Println("end") }
↓
$ go run sample1.go 2017/10/28 14:32:33 start 2017/10/28 14:32:33 { "url": "http://hogehoge.com", "count": 100, "user": "hoge", "pass": "foo" } 2017/10/28 14:32:33 url = http://hogehoge.com 2017/10/28 14:32:33 count = 100 2017/10/28 14:32:33 user = hoge 2017/10/28 14:32:33 pass = foo 2017/10/28 14:32:33 end $
注意点
構造体に設定する際はフィールドの項目は外部公開できるように1文字目を大文字にしておくこと
そうしないと構造体のデータに設定されてくれない
【C++】動的にデータを追加するvector、listを使う
実装
サンプル
//============================================================================ // Name : sample04.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> #include <vector> #include <list> #include <cstring> using namespace std; int main() { cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!! /** * vectorの場合 */ vector<string> strlist; strlist.push_back("aaaa1"); strlist.push_back("aaaa2"); strlist.push_back("aaaa3"); strlist.push_back("aaaa4"); // イテレータを使用して抽出 for (vector<string>::iterator it = strlist.begin(); it != strlist.end(); ++it) { cout << *it << endl; } vector<int> intlist; intlist.push_back(100); intlist.push_back(200); intlist.push_back(300); intlist.push_back(400); // 回数指定で抽出 for (int i=0;i<intlist.size();i++) { int a = intlist.operator[](i); cout << a << endl; } /** * listの場合 */ list<string> strlist2; strlist2.push_back("bbbb1"); strlist2.push_back("bbbb2"); strlist2.push_back("bbbb3"); strlist2.push_back("bbbb4"); // イテレータを使用して抽出 for (list<string>::iterator it = strlist2.begin(); it != strlist2.end(); ++it) { cout << *it << endl; } return 0; }
↓
!!!Hello World!!! aaaa1 aaaa2 aaaa3 aaaa4 100 200 300 400 bbbb1 bbbb2 bbbb3 bbbb4
vectorの場合
要素の途中の項目にもアクセスできます。listよりは少し遅いとのこと
listの場合
イテレータなどの処理以外で参照しかできない分処理は速いらしい
【C++】カレントディレクトリ配下のファイル一覧を抽出する
実装
sample03.cpp
//============================================================================ // Name : sample03.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> #include <windows.h> #include <cstring> #include <unistd.h> using namespace std; int main() { cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!! // カレントディレクトリを取得 char dir[512]; getcwd(dir, 512); cout << dir << endl; // 検索パス string str = ""; str.append(dir); str.append("/work/*.txt"); // 検索データ WIN32_FIND_DATA ffData; // 検索開始 HANDLE handle = FindFirstFile(str.c_str(), &ffData); if (handle == INVALID_HANDLE_VALUE) { cout << "取得失敗" << endl; } else { cout << "取得成功" << endl; do { // ファイル名を出力する string fileInfo = ""; SYSTEMTIME stFileTime; char strFileTime[256]; // 日付を変換 FileTimeToSystemTime(&ffData.ftLastWriteTime , &stFileTime); wsprintf(strFileTime , TEXT("%d年 %d月 %d日 %d時 %d分 %d秒") , stFileTime.wYear , stFileTime.wMonth , stFileTime.wDay , stFileTime.wHour , stFileTime.wMinute , stFileTime.wSecond); // 書式整形 fileInfo.append("file:"); fileInfo.append(ffData.cFileName); fileInfo.append(" "); fileInfo.append("最終更新日時:"); fileInfo.append(strFileTime); cout << fileInfo << endl; }while(FindNextFile(handle, &ffData));// 次のファイルを検索する // ファイルハンドルを閉じる FindClose(handle); } return 0; }
ディレクトリにサンプルファイルを準備
実行結果
!!!Hello World!!! C:\pleiades\pleiades-e4.5-cpp-jre_20160312\pleiades\workspace\sample03 取得成功 file:0001.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒 file:0002.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒 file:0003.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒 file:0004.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒 file:0005.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒 file:0006.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒 file:0007.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒 file:0008.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒 file:0009.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒 file:0010.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒 file:0011.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒