YAMAGUCHI::weblog

海水パンツとゴーグルで、巨万の富を築きました。カリブの怪物、フリーアルバイター瞳です。

GoのimageパッケージでGopherをぐるぐる回そう

はじめに

こんにちは、Go界のスタンリー・キューブリックです。このエントリはGo Advent Calendar 2013の22日目のエントリです。

2013年はGoカンファレンスも2回開催できましたし、私としてもかなりGoの広まりを実感出来た1年でした。来年はもっと多くの方にGoを使ってもらえたらと思いつつ、さらにプロダクション事例などを期待しています。

さて、Goなんですが、ネイティブにビルドされるとか、並列化が簡単にできるとか、そういうところがよく取り上げられますが、個人的にはimageパッケージを標準で持っているのが大きいと思っています。ということで、今回はimageパッケージを使ってアニメーションGIFを作ってみたいと思います。

imageパッケージとは

名前のとおり画像データを簡単に扱えるようにしたパッケージで、Go1.2の時点ではGIF、JPEG、PNGなどを簡単に読み込み・書き出し出来るようになっています。今回はPNG画像を読み込んで、アニメーションGIFにするということをやってみたいと思います。

まずこの可愛らしいGopherちゃんの画像を用意します。今回はサンプルということで、正方形の画像を用意しました。

f:id:ymotongpoo:20131222232717p:plain

クリスマスなので、このGopherちゃんがぐるぐると回転するアニメーションGIFができたらカワイイと思いませんか?思いますね!?じゃあ実際にぐるぐる回してみましょう!!

簡単に使い方解説

画像データの読み込み・書き込み

Goっぽく、まずはファイルを読み込んで(io.Readerを用意)して、そのあとDecoderに渡す、という流れです。

// Open source PNG file.
file, err := os.Open("image/gopher.png")
if err != nil {
    panic(err)
}
defer file.Close()

data, err := png.Decode(file)
if err != nil {
    panic(err)
}

逆に書き込みは画像データと書き込み先のio.Writerを用意しておいて、Encodeに渡すという流れ。

// Dump image data into file.
file, err = os.Create("image/rotate-gopher.gif")
if err != nil {
    panic(err)
}
defer file.Close()

err = gif.EncodeAll(file, &dst)
if err != nil {
    panic(err)
}

画像データの操作

読み込みと書き出しがわかったので、肝心の画像データの操作についてですが、扱う画像形式によって必要となる画像データ型が異なります。(image.Image、image.Palettedなど)ですが基本的には、領域を用意し(image.Rectangle)、色データを操作する(xxx.Setメソッド)という流れになります。

original := image.NewPaletted(r, palette.WebSafe)
for x := r.Min.X; x < r.Max.X; x++ {
    for y := r.Min.Y; y < r.Max.Y; y++ {
        original.Set(x, y, data.At(x, y))
    }
}
dst.Image = append(dst.Image, original)

たったこれだけで画像が扱えるんです。簡単!!ただし、現状では画像の入出力系の基本的な操作しか出来ないので、アフィン変換などは自分で実装する必要があります。では実際に作ってみた画像を見てください!

f:id:ymotongpoo:20131222234948g:plain

回っていますね!

これであなたもローリングGopherをいつでも作れます!今年のクリスマスはぜひローリングGopherちゃんと戯れてください!次はyanolabさんです。

サンプルコード全体

package main

import (
    "image"
    "image/color/palette"
    "image/gif"
    "image/png"
    "log"
    "os"
)

func main() {
    // Open source PNG file.
    file, err := os.Open("image/gopher.png")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    data, err := png.Decode(file)
    if err != nil {
        panic(err)
    }

    // Define destination boundary. Expecting original image is square.
    r := data.Bounds()

    // Prepare distination image buffer.
    dst := gif.GIF{
        Image: []*image.Paletted{},
    }

    // Rotate original image and store them into destination.
    original := image.NewPaletted(r, palette.WebSafe)
    for x := r.Min.X; x < r.Max.X; x++ {
        for y := r.Min.Y; y < r.Max.Y; y++ {
            original.Set(x, y, data.At(x, y))
        }
    }
    dst.Image = append(dst.Image, original)

    clockwise := image.NewPaletted(r, palette.WebSafe)
    for x := r.Min.X; x < r.Max.X; x++ {
        for y := r.Min.Y; y < r.Max.Y; y++ {
            clockwise.Set(x, y, data.At(-y+r.Max.Y, x))
        }
    }
    dst.Image = append(dst.Image, clockwise)

    upsidedown := image.NewPaletted(r, palette.WebSafe)
    for x := r.Min.X; x < r.Max.X; x++ {
        for y := r.Min.Y; y < r.Max.Y; y++ {
            upsidedown.Set(x, y, data.At(-y+r.Max.Y, -x+r.Max.X))
        }
    }
    dst.Image = append(dst.Image, upsidedown)

    counterclockwise := image.NewPaletted(r, palette.WebSafe)
    for x := r.Min.X; x < r.Max.X; x++ {
        for y := r.Min.Y; y < r.Max.Y; y++ {
            counterclockwise.Set(x, y, data.At(x, -y+r.Max.X))
        }
    }
    dst.Image = append(dst.Image, counterclockwise)

    // Post process
    dst.Delay = make([]int, len(dst.Image))
    dst.LoopCount = 100

    // Dump image data into file.
    file, err = os.Create("image/rotate-gopher.gif")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    err = gif.EncodeAll(file, &dst)
    if err != nil {
        panic(err)
    }
    log.Println("wrote out rotate-gopher.gif")
}

「果てなき渇望」読了

はじめに

こんにちは、Go界のドリアン・イエーツです。最近暇を見ては腕立て伏せをしているのですが、 @hiroki_niinuma の推薦図書を @shibukawa からプレゼントしてもらったので一気に読みきった。 このエントリは「果てなき渇望 Advent Calendar 2013」の2週目のエントリーです。まだアメリカ太平洋時間では土曜日なのでセーフです。

果てなき渇望―ボディビルに憑かれた人々 (草思社文庫)

果てなき渇望―ボディビルに憑かれた人々 (草思社文庫)

章立て

文庫371ページの割には章立てが少ない。インタビューとエッセイが3対7といったところ。

  • プロローグ 筋肉の呪縛
  • 第1章 コンテスト
  • 第2章 女子ビルダー
  • 第3章 禁止薬物
  • 終章 生涯をかけて

ボディビルディング」はスポーツか?

本書を読みながら常に考えていたことは「ボディビルディングはスポーツなのか」ということだった。本書の章立ては上にあるとおりだが、第1章、第2章、第3章と進むに連れて、ボディビルダーの倫理観の限界に触れる内容になっている。

本書の中でも触れているように、健康促進のための「広義のボディビルディング」に関しては私も大いに賛同する。社会人になってから運動する機会が減り、30歳を目前にしてようやく重い腰を上げ習慣的な運動を始めたわけだが、「習慣的な運動」という点においてはボディビルディングは優れている点が多いと思う。自分が目指す体型をきちんとイメージして、習慣的なトレーニングを行わなければ、目標が達成できないスポーツだからだ。

しかし「狭義のボディビルディング」はどうか。狭義のボディビルディングは、皆さんがご存知の通りのフィギュア形式の採点競技で、競技において勝つためには、筋肥大を行ったり、筋繊維を見せるための減量が必要となる。選手は理想の筋肉を作るために食事を含めたトレーニングを行っているわけだが、この一連のトレーニングは、果たして「スポーツ」の域に収まるものなのだろうか。

競技ボディビルディングの「男性」性

前提として本書は日本の競技ボディビルディング界に所属する複数の選手を中心として取材を行っている。日本の競技ボディビルディングと本場米国のそれの大きな違いはステロイドを始めとする薬物の使用度合いであり、日本においては非常に強い制限がかけられている。そもそもそれらの薬物を何のために摂取するのか。ここに競技ボディビルディングのスポーツ性が問われる。

競技ボディビルディングに於いて求められるものは、筋肥大とそれを綺麗に見せるための減量だ。(バルク、カット、ディフィニションという単語が用いられる)そしてまず必要となるのが筋肥大である。この筋肥大には男性ホルモンが大いに関係し、減量に関しては女性ホルモンが大いに関係する。 元来、筋肥大を促すテストステロンは女性にはあまり分泌されない。そもそもが競技自体が「男性」のそれなのだ。さらに筋肉を美しく見せるための減量も女性には不利だ。女性は生存のために元々が脂肪が付きやすく、かつ落ちにくくなっている。第2章にも出てくる女性ビルダーは「生理が止まるほどの減量を行ってから本当の減量が始まる」と述べている。これも明らかに男性性が強い側面である。

第1章、第2章だけを読んだ感想だけであれば、女性にとっては決して良いとは思えないが、競技ボディビルディングはある意味最高の男性像を追求するスポーツだととも言えるであろう。しかし、第3章でその認識を打ち砕かれる。

スポーツに求めるもの

なるほど確かに男性に向いたスポーツであることは確かであり、本書にも何度も登場する表現である「ギリシャ彫刻のような」肉体を得ることは男性にとっては理想に思える。しかし、現在の「競技ボディビルディング」が果たしてその「理想の男性」を目指しているのだろうか。第3章がその闇を描いている。

第3章では薬物規制が厳しくプロ制度がない日本のボディビルディング界を飛び出し、本場米国でプロボディビルダーを目指すある選手を追う。その選手は筋肥大のために複数の薬物を用いているわけだが、この危険な行為も彼は「バスケットボールと同じでバレなければファールではない」と語る。私には、もはや理想の男性の姿はそこにはなく、より大きな筋肉を果てなく求める、筋肉ジャンキーに映った。

私達がスポーツに求めるものはなにか。少なくとも私は、自然な食事のみを行ってトレーニングをし、人間が出せる最高の性能を発揮することである。自然な食事の定義は難しい。サプリメント類などは決して自然な形ではない。しかしながら、栄養素として食物から摂取できるため、ここでは自然な食事の中に含めても良いと考えている。一方で本場米国での競技ボディビルディングはその基準からは外れている。本書内でも一時期日本のように薬物使用の制限を厳しくしたことがあったが、おかげで選手のサイズがダウンし、客足が遠のいたために、基準を戻した、という記述があった。 私がスポーツに求める基準を敷いている日本の競技ボディビルディングは良いと思うが、世界的な基準が統一されていないために、「スポーツとして」日本選手が勝てないという悲しい現実があった。

ボディビルディングは自己破壊的アート

本書全体を通じて、「もはや競技ボディビルディングはスポーツではなく自己破壊的なアート活動」であるという感想を得た。決して自己の生命にとって安全ではない薬物を摂取してまで自らの肉体を理想の形に作り上げる行為は、ドラッグによる幻覚作用の中にアーティシズムを求めるアーティストのような印象を受ける。

終章で健康維持のためにボディビルディングを行っているという、シニアボディビルダーの話が描かれている。この章は、作者が競技ボディビルディングがもう一度「スポーツ」に回帰することを願って書いたものなのかもしれないと思いながら、本書を読み終えた。

iOS開発に際して調べたことの個人的メモ

はじめに

こんにちは、Go界のドン・チードルです。最近ちょこちょこiOS開発について調べ物したりちょろちょろいじってたので、忘れないうちにメモしておきます。ちなみに僕は最近になってiOS開発、Objective-Cを触り始めたような素人ですので、間違った理解をしているかもしれません。コメントなどいただければ幸い。

Getting Started

とりあえず公式ドキュメント読んどけばいいだろと思ったので、Appleの公式ドキュメントを読みながら手を動かしました。

これで「TODO listアプリをStoryboardとかを駆使してコードをほとんど書かずにできるよ、すごい!!」みたいなチュートリアルやったんですが、結局何がわかったのかがあいまいでわけわからなくなったので、とりあえずObjective-Cのコードを適当に書いてみることにしました。

Objective-C

最初のチュートリアルでObjective-Cがなんとなーくわかったので、今度はiOSプロジェクトではなく、普通のCLIプロジェクトを作ってみることにしました。 新規プロジェクト作成時に OS X > Application > Command Line Tool としてプロジェクトを作成すると main.m くらいしか無いプロジェクトが作成されてめちゃわかりやすい!!

とりあえず NSLog() で出力できればいいやってことで適当に色々書いて、最低限Objective-Cを書くために必要な文法だけ抑えた。

エントリポイント

  • main.m がエントリポイント
    • @autoreleasepool というプロパティでARC (Automatic Reference Counting) が呼ばれる。このブロックの中に書いておけば自動で参照カウント見て良きに計らってくれて助かる。

  • プリミティブに string やら int やらあるが、iOS開発の時はあんまり使わない風
  • NS*** といういかにもNext Step出身でございますよという拡張型が用意されている
    • NSString (文字列)、 NSInteger (整数)など
    • 拡張型は全部 NSObject というクラスの拡張なので、初期化とかがめっちゃだるい
      • eg. NSString *foo = [NSString stringWithCString:"だるい" encoding:NSUTF8StringEncoding];
    • でもだるすぎるので糖衣構文で @ を先頭につけると簡単に初期化出来て良い
      • eg. NSString *foo = @"だるい";
    • ArrayやDictionaryもある
      • eg1. NSArray *bar = @[ @"spam", @"egg", @"ham" ];
      • eg2. NSDictionary *buz = @{ @"Monty": @"Python", @"age": @100 };
    • Arrayはちゃんと初期化するときに、最後 nil 終わりにしないといけないのに注意
      • eg. NSArray *bar = [NSArray arrayWithObjects:@"spam", @"egg", @"ham", nil];
  • 基本はimmutableなので、mutableな型が欲しかったら NSMutable*** を使う。
  • ARC使うので大体ポインタ型で宣言する

クラス宣言・実装

  • クラスはヘッダファイル *.h と実装ファイル *.m で定義。ファイル名がクラス名。クラス名は大文字始まり。
    • ヘッダファイルの @interface から @end の間にクラスのメンバ等を定義
      • @property でメンバ変数の定義。いろいろなオプションある。
      • @property プロパティで宣言するとアクセサを勝手に定義してくれる。デフォルトはprotected。
      • メソッドの定義は - 始まりならインスタンスメソッド、 + 始まりならクラスメソッド。メソッド名は小文字始まり。
    • 実装は実装ファイルの @implementation から @end の間に
    • 実装ファイルの先頭で @interface クラス名() から @end と書かれてる部分はクラスエクステンション
      • クラスエクステンションの中でメンバを宣言するとprivate的な扱い
  • 継承はヘッダファイルでクラス名の後に : で宣言する。単一継承。
    • @interface ChildClass : ParentClass
  • protocolというJavaのInterface的なもの( @optional によって実装しないでも良いメソッドも定義できるのが異なる) を定義することでまとまった機能を継承できる
    • 宣言は @protocol プロパティ
    • 継承する時は親クラス名の後に <> 内に記述。複数継承する場合はカンマ区切り。
      • @interface ChildClass : ParentClass <FooProtocol, BarProtocol>

メソッド定義・呼び出し

Objective-Cで一番なれなかったのはメソッド呼び出し(メッセージ式)でした。メソッド見ても最初「なんのこっちゃ?」という感じだったので。

  • メソッド定義は次の通り
    • -/+ (戻り値型)メソッド名部分1:(引数1型)引数1 メソッド名部分2:(引数2型)引数2
    • メソッド名は引数を除いた部分を全部つなげたもの
      • メソッド名部分1:メソッド名部分2: がメソッド名(最後のコロンも入る)
      • へんてこりんに見えるけど、英語で書くとなんか自然言語っぽくなる
        • たいていメソッド名は verb:noun/adv/adj:noun/adv/adj... という感じで続く
    • eg1. - (NSInteger)count
      • NSInteger 型を返す count メソッド(引数が無い)
    • eg2. - (Image *)initWithFile:(NSString *)path Title:(NSString *)title Description:(NSString *)desc
      • Image * 型を返す initWithFile:Title:Decription: メソッド(引数は全部 NSString 型の引数 pathtitledesc
  • メソッド呼び出しは [ ... ] で行う(メッセージ式)
    • eg1. [someString count];
    • eg2. [[Image alloc] initWithFile:@"hoge.jpg" Title:@"great pic" Description:@"flower"];

UI作成

StoryboardやらInterface Builderやらを使えばポトペタで楽ちんなんだろうけど、いろいろ隠蔽されまくるので、最初はなるべくコードで書きながら理解した。このへんのドキュメントを読むとわりと理解できた。

ViewとかViewControllerとか

まあMVCやってますよという話

  • Viewはデータを表示する箱
    • ButtonもWebViewもCanvasも全部Viewです
    • Viewの上下関係に気をつけましょう
    • ViewをView Controllerの中にまとめて画面を構成する
  • View Contollerが画面を構成する単位
    • コンテンツを表示するContent View Controller
    • 画面の遷移情報を管理するNavigation Controller
    • データ情報を管理するContainer View Controller
  • iOSではTableを使ったUIが非常に多いのでTableViewControllerっていうのがあるよ
    • まあ普通にViewController定義してTableViewを持ってるのと変わらないけど、はじめからいろいろ定義してあって便利
  • コンポーネント間のやり取りはprotocolとdelegateを使って行う
    • eg1. ViewController内のView(ボタンとか)のコールバックを受け取るためにViewControllerが自分自身をdelegate
    • eg2. 遷移先のViewControllerからの結果を遷移元が受け取るために、遷移先のprotocolを遷移元が実装して、遷移元が自分自身をそのprotocolのdelegate先とする

全部コードで書く場合に意識すること

  • ViewControllerの loadViewviewDidLoad 内で初期化
  • initWithNibName とか用なしなので自分で init*** を書く
  • イベントはことごとく次のようなメソッドを定義して受け取る
    • - (IBAction)didSomething:(id)sender

snippet

  • initWith***
- (id)initWithTitle:(NSString *)title
{
    self = [super init];
    if (self) {
        self.title = title;
    }
    return self;
}
  • AppDelegate 初期化
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    Hoge *hoge = [[Hoge alloc] initWithString:@"hoge"];
    FooViewController *foo = [[FooViewController alloc] initWithHoge:hoge];
    UINavigationController *nav = [[UINavigationController alloc]
                                   initWithRootViewController:foo];
    self.window.rootViewController = nav;
    
    [self.window makeKeyAndVisible];
    return YES;
}

アプリケーションのルートとNavigation Controllerのルートは別だっていうのは、1回アプリ作っちゃえばわかるんだけど、最初はRootViewControllerって言葉が2回出てきてすごく混乱した。

ところで

はてなブログObjective-Cのsyntax highlight用キーワード調べるのに苦労した。 objc でいいんですね。

Goが4歳になりました

はじめに

こんにちは、Go界のヒュー・ジャックマンです。今日はGoのリリース4周年となる日です。

今日はリリース記念日ということで、上のエントリをなぞりながら、このすばらしい記念日を祝いましょう!

トレンド

先のエントリには "golang" というキーワードがどれくらい検索されてきたか、グローバルでの検索ボリュームを見ていて、2012年のversion 1.0リリースから急増したことが示されています。では日本国内に限ってはどうだったのかも見てみましょう。

面白いのは日本では各区切りの段階(初公開リリースと1.0のリリース)のタイミングでピークを迎えていて、それ以外は低空飛行をしている、という状況です。しかしながら、2012年3月の1.0リリース以降を見てみると、着実に検索ボリュームを伸ばしているのがわかります。

プロダクション投入

こちらに関しては日本国内においてはまだ表向きにはプロダクション環境でGoを利用しているという話はあまり出てきていません。(もしあればぜひご連絡ください!)

実際半年前の春の段階では「興味があります」というような内容が多かったですが、先日のGo Conference 2013 autumnでは「実際にプロダクションへ投入している」「導入を積極的に検討している」という声がちらほら聞こえ、いよいよ浸透してきたなあという実感を得ました。

半年後にまたGo Conferenceを開催したいな、と思っていますが、その時にはプロダクション環境での事例が1つでも聞けたら嬉しいなあと思います。

コミュニティ

国内のGoコミュニティは最近活発になってきています。

などなど。他にもあれば教えて下さい!

公式ブログのほうでも「Tokyoのコミュニティがあるよ」と紹介されていますが、東京に限らず各地域で勉強会が開催されています。ぜひ参加してみてください!また日本語情報などはGoogle+コミュニティ、Lingrなどで交換されていますので、ぜひ参加してみてください!

おわりに

リリース4周年おめでとうございます!次の4年がどうなっているか楽しみです!