Processing フォントのアウトライン情報を取得して文字をいじってみた

去年の今くらいに,輪郭追跡のアルゴリズムを使って,

文字をvertexを用いた図形にしていろいろ遊んでいました

turtley-fms.hatenablog.com


 その後,

「フォントの情報を使えば,輪郭追跡しなくても文字を図形にできるのでは?」

という意見をもらっていたので,今回はそれをやってみました


結果

下に調べた情報などを書いていますが,長いのでとりあえず結果です


いろいろやってみたところ,Fontの情報ではbezierVertex()を使用しているために,

輪郭に沿って点が等間隔に配置されているわけではないことがわかりました

したがって,等間隔な点列を作成するには曲線の補間をする手間があり,輪郭追跡とあまり手間が変わらないという気持ちになりました

しかし一方で,bezierVertex()として扱えるため,

やわらかく曲線的にいじるのはやりやすそうです


とりあえずいじってみた

youtu.be

曲線的にいじってみた

youtu.be

youtu.be


githubソースコードを公開しました

displayShape()内のパラメータを変更したコードはbranchで分けています)

github.com

Fontのアウトライン情報を取得し,

beginShape()endShape()vertex()bezierVertex()を使い分ける情報と,それぞれの座標情報をクラスに持たせ,

displayShape()でそれぞれの情報をもとに図形を作成,表示しました


実装方法の調査

先駆者 その1

まずは,こちらの記事のコードをお借りしました

qiita.com

実行してみたところ,以下のような感じになりました 


(左側:shape()で表示したP, 右側:vertex()で表示したP)

f:id:turtar_fms:20181210175707p:plain
font.getShape('P', 0)
 
f:id:turtar_fms:20181210175630p:plain
font.getShape('P', 1)

なんかいまいち挙動がわからない...


右側のvertex()で表示したものを見ると,輪郭の区別も関係なく全部一つとして繋がっているために変な線が残っています


また,

font.getShape('P', 0)の時は,左側はツルツル,右側はカックカクで,

font.getShape('P', 1)の時は,左側も右側も同様に少し粗い感じのPになっています


先駆者 その2

次に,こちらの記事のコードをお借りしました

wcs.hatenablog.com

こちらではjava.awt.Fontのアウトラインを読み取って利用しています

GlyphVectorを取得して,Outlineを取得していますね


(グリフとかアウトラインとかについては,こちらの情報が参考になりました 文字とコンピュータ その3 フォントとグリフ


また,

PathIteratorcurrendSegment()typeを取得,typeの値に応じて,

beginShape() endShape() vertex() quadraticVertex() bezierVertex()

を使い分けて文字を形作っています


こちらの記事は利用できそうなのですが,

実行してみると,図形の内側の輪郭に使用するcontourがないことに気がつきました

f:id:turtar_fms:20181210200805p:plain


PFontのソースコード

processing/PFont.java at master · processing/processing · GitHub


ProcessingのPFontのソースコードを読んでみると以下のように書かれていました

public PShape getShape(char ch, float detail) {
  
  ...

  // make everything into moveto and lineto
  PathIterator iter = (detail == 0) ?
    shp.getPathIterator(null) : // maintain curves
    shp.getPathIterator(null, detail); // convert to line segments

  ...

}

detailが0のときはカーブのまま,0でないときはラインでの分割に変換する」

と書いてありますね

どうやら,ツルツルした文字のまま使いたいならカーブを使わないといけないみたいです


また,その下には次のように書かれています

    int contours = 0;
    ...
    while (!iter.isDone()) {
      int type = iter.currentSegment(iterPoints);
      switch (type) {
      case PathIterator.SEG_MOVETO:   // 1 point (2 vars) in textPoints
        ...
        if (contours == 0) {
          s.beginShape();
        } else {
          s.beginContour();
        }
        contours++;
        s.vertex(iterPoints[0], iterPoints[1]);
        break;

      case PathIterator.SEG_LINETO:   // 1 point
        ...
        s.vertex(iterPoints[0], iterPoints[1]);
        break;

      case PathIterator.SEG_QUADTO:   // 2 points
        ...
        s.quadraticVertex(iterPoints[0], iterPoints[1],
                          iterPoints[2], iterPoints[3]);
        break;

      case PathIterator.SEG_CUBICTO:  // 3 points
        ...
        s.quadraticVertex(iterPoints[0], iterPoints[1],
                          iterPoints[2], iterPoints[3],
                          iterPoints[4], iterPoints[5]);
        break;

      case PathIterator.SEG_CLOSE:
        ...
        if (contours > 1) {
          ...
          s.endContour();
        }
        break;
      }
      ...
      iter.next();
    }
    s.endShape(CLOSE);
    return s;
  }

先駆者 その2の方のコードに似ていますね

こちらのコードではcontourについての実装がされています

ただ,よく読むとcotoursが0以上では,beginContour()を実行するようになっていますが,

contoursはその後インクリメントのみ実行され,初期化はされません

したがって,以下のような図形を描画するコードになる可能性があります

beginShape();
  beginContour();
  endContour();
endShape();

beginContour();
  beginContour();
  endContour();
endContour();

すなわち,contourの内側にcontourが作られる可能性があります

Processingの実装上はこれでいいのですかね??謎です


ちなみにこのコード,もう一つ謎な点があります

case PathIterator.SEG_CUBICTOでは,6つパラメータを持つquadraticVertex()が使用されています

これ,P3Dで使用するときの使い方なはずなんですよね

quadraticVertex() \ Language (API) \ Processing 3+

おそらく,bezierVertex()が正しいと思うのですがなぜこうなっているのか...

(先駆者 その2の方の記事ではbezierVertex()になっています)


調査のまとめ

  • PFontのgetShape('P', 0)で,vertexbezierVertex()を使い分けられるか要確認(できれば楽に実装可能になる)

  • getShape('P', 1)では,文字の見た目が粗いが曲線が補間されているので使えるかも

  • ProcessingのPFont.javaの実装に謎がある

    • contourの内側にcontourが作られて良いのか?

    • 6つのパラメータを持つquadraticVertex()はP3Dで使用されるものでPFontで使うのは誤りでは?

はてなサマーインターン2018で社長とCTOと完全新規サービスを開発してきた話

思いついたおもしろそうなものをプログラミングで作って見せるのが趣味の id:turtar_fms と申します

8/13~9/7までの4週間、はてなサマーインターン2018で最高の夏を過ごしてきました!

いろんな話は後にしてまずは、

インターンでの成果物です!

「特命!社長とWebサービス開発コース」(社長コース)にて、

2週間で以下の2つの完全新規サービスを作ってきました!


その1:「はてな匿名ダイアリーの『いい話』」

増田に投稿されるいい話をAlexaに話してもらえるSkillです!

はてなのいい話、ちょっと聞いてみませんか?

labo.hatenastaff.com

・システム構成 f:id:turtar_fms:20180913013536p:plain


その2:5分しか共有できない投稿サービス「無常はてな

普通ブログは、ネット上に投稿した記事は共有され広がっていきます

でも逆に、共有できない投稿サービスがあったら...それはそれでおもしろい!

「無常はてな」では、投稿の共有リンクが5分で無効になってしまいます


「無常はてな」は、

  • ほとんど共有できない一期一会感

  • だれにも読まれなくてもいい気軽さ

を楽しめる投稿サービスです

(現在は社内でのみリリースしています。インターン期間中に公開までは間に合いませんでした...)


・トップページ f:id:turtar_fms:20180913004743p:plain

・詳細ページ f:id:turtar_fms:20180913004205p:plain

・共有が無効になった無常なページ f:id:turtar_fms:20180913030211p:plain


おめでとう!!

www.openprocessing.org

はてなサマーインターンではリリースするとくす玉を割るのですが、

社長コースではくす玉を割る機会がなかったのでくす玉プログラムを作りました

(くす玉をクリックしてみてください)


さて、成果物の報告も終わったところで、

ここからは、この4週間のインターンで体験したことをお話ししたいと思います。


インターン


応募

インターンの応募では私はこんな感じ(かめ's portfolio)のポートフォリオを送りました

面接では、思いついたおもしろそうなことをプログラミングで作っている人間だということ、その中でいろんな言語や技術に触っていることなどをアピールしたつもりです

面接中はそれほど緊張もせず、楽しくお話ししていました

結果として何が決め手となったかはわかりませんが、

ありがたいことに参加させていただくことになりました


事前課題

事前課題では、A Tour of Goと、Documentation · TypeScriptのHandbookを一通り勉強しました

Go言語もTypeScriptも初めてだったのでなかなか時間がかかりました


インターン

当日の早朝に新幹線に乗り関東から京都へ


前半:講義パート

前半の2週間の講義では、主にWebサービスに関する技術とはてなの歴史について学びました

技術面ではGo言語, React, TypeScript, GraphQL, 機械学習, AWSなどを学びました


今年の講義は去年までの内容から大きく変更し、モダンな技術を多く扱うようにしたそうです

講義内容はすごく作り込まれており、スライドを後から読みかえしてもわかりやすかったです

このインターンに対してかなり力を入れて準備をしていると感じました

またそのため、id:hakobe932 さんのGraphQLの講義などでは、社員のみなさんも周りで聞いていたりしました


講義パートでは1,2時間程度の講義の終わりに課題が出され、

その日の午後はその課題に取り組んで行くという流れでした


私はWebサービス開発に関する知識はあまりなかったので毎回かなり苦戦していました

ただ、わからないときはメンターさんに気軽に質問できるので、

めちゃめちゃ質問しまくることでなんとかなりました

本当に他のインターン生の誰よりも質問していた自信があります

実際、私はわからないものはわからないから聞くのスタンスは正解だったと思っています

質問することで自分でなんとかするよりもずっと早くずっと多くの知識を盗...得られたと思います


id:onishi さんのはてなの歴史id:riko さんのユーザコミュニティの話は個人的にとても好きな講義でした

はてながサービスを提供する上での信念について知ることができたという気持ちです


後半:実践パート

後半の2週間では、実際にそれぞれのチームに配属され開発を行いました

私は id:E_ntyo さんと「特命!社長とWebサービス開発コース」(通称 社長コース)に配属され、

「プロダクト志向」「コラボレーション」「おもしろ」を軸にゼロからサービス開発を行いました


イデア出し

社長コースでは、 社長の id:chris4403 さんとCTOの id:motemen さんとチームとなり、

まずはブレインストーミングをして何を開発していくかを決めました

おもしろいものを作ろうと集まった人と話し合うと、次々におもしろいものが出てきて本当に楽しいですね

社長コースは私の期待通りの場所でした

また、 id:chris4403 さんたちの提案は、おもしろいだけではなく、

こういう機能にすれば、ユーザはこういう風に利用できるようになるのではないかといったように、

一つ一つにサービスとして提供することを想定した理由がありとても勉強になりました


結果としては、もともとAlexaを使って一つ何かを作りたいという話になっていたので、

一つはAlexaにはてな匿名ダイアリーのいい話を話してもらうスキルを作ることになりました


そしてもう一つ、社長コースでは最終的に二つのサービスを作ることになったのですが、、、

とある酔っ払いが午前4時のSlackに謎の言葉を残していました


f:id:turtar_fms:20180913014405p:plain


はい、私です、

社員さんも大勢見るインターンのSlackで謎の発言をしました(のちに遺言と呼ばれる)

しかしながら「絶対に後から見返せない無常はてな」を詳しく説明したところ、

社長コースの方々の心に刺さり、なんとまさか私のアイデアが採用されました!

はてな匿名ダイアリーの次のステップとして、ポジティブに受け取っていただけたようです

支離滅裂でも書いておくものですね


サービス開発

サービスは以下のようなシステムで開発しました


・「はてな匿名ダイアリーのいい話」 f:id:turtar_fms:20180913013536p:plain

・「無常はてなf:id:turtar_fms:20180913022004p:plain


社長コースでは新規サービスということもあり、

技術選定においては前半の講義で習った内容を多く採用させていただきました


開発では私は主に、

はてな匿名ダイアリーのいい話」ではAlexa Skillとのインタラクションを、

「無常はてな」では主にフロントエンドとデザイン周りを担当していました

id:E_ntyo さんがTypeScript強者なのでめちゃめちゃ質問しつつ、

id:motemen さんに助けていただきつつ、

2週間でガツガツ実装しました


また、デザインについては id:Hasesann にロゴとマスコット(食べヤギ)を描いていただき、

私は、できるだけその雰囲気に合うようにCSSでデザインしていました

トップページなど自分では気に入っているのですがどうでしょうか?


f:id:turtar_fms:20180913004743p:plain


デザインはほとんどの実装が終わった後に作りましたが、

デザインを当てるまではただ機能を持つプログラムというような感じだったのですが、

デザインを当てた途端「すごい!Webサービスだ!」となりました


やはりデザインは重要ですね

id:Hasesann さん、本当にありがとうございました!


最終成果発表会

インターンの最終日には各チームの成果発表会が行われました

どのチームもすごく良い成果をあげていてすごかったです

またひとえに成果と言っても、それぞれのチームごとに特色があっておもしろかったです


社長コースは、実は発表会のタイミングでは、

という状況でした

結果として、社長コースは5コース中4位であり、

公開できていれば...というところではありますが、

インターンの成果としては私は満足でした


現在は「はてな匿名ダイアリーのいい話」は公開できていますが、

どうにか「無常はてな」も公開したいところです


インターン中の出来事とか


インターン

最高でした!

みんな優秀だし優しいし素晴らしい人たちでした

今年は全員遠方からきたのでホテルに泊まっていたこともあって、

よくみんなで夕食を食べに行っていました(というかほとんど誰かしらと一緒に食べていた)

ホテルの部屋に集まって趣味全開な話をしたのも楽しかったですね


社員さん

最高でした!(天丼)

みんな優しいんですよね

社内自体がいい雰囲気というか、すごく活気がある感じで私はすごく好きでした

労働時間外である昼休みには社員さんと id:mizdra さんとSplatoon2で遊んだりもしていました

また、インターン前半の講義ではメンターさんにめちゃめちゃ質問しましたが、

すごく丁寧に答えてくださりとても感謝しています


ホテル

インターン中は4週間ずっとホテルに泊まっていたのですが、快適すぎて驚きました

ハートンホテル京都というところです

www.hearton.co.jp

インターンに行く前、私は一人暮らしの経験もなかったのでめちゃめちゃ不安でしたが、

いざ泊まってみれば全然問題ありませんでした

シャワーがある、タオルもある、歯ブラシもある、コップもある、冷蔵庫もある、朝食もある、毎日部屋を掃除してくれる、etc...

テレビもあってHDMI繋げられるからデュアルディスプレイもできました

いろいろ準備していたのですが、結局役立ったのは爪切りとかくらいですかね


おわりに

はてなサマーインターン2018での4週間はめちゃめちゃ楽しい日々でした

前半2週間は、濃密な講義を受けて知識を蓄え

後半2週間は、前半の知識を応用して実際のサービスを開発

社員さんや他のインターン生は良い人ばかり。

社長コースは「おもしろ」を考え、作るのが大好きな人間にとっては最高の環境でした


最高の夏でした!4週間ありがとうございました!


他のインターン生の記事

私の記事は写真がないので、そこは他の方に任せます

e-ntyo.hatenablog.com

blog.meteors.me

tomoyaf.hatenablog.com

yaamaa-memo.hatenablog.com

アカウントが新しくなりました

turtley-fms.hatenablog.com

こちらでブログを書いていた turtley_fms です

今回、turtar_fms として新しくアカウントを作成しました

 

今後ともよろしくお願いします

 

以下、過去記事になります

turtley-fms.hatenablog.com

turtley-fms.hatenablog.com

turtley-fms.hatenablog.com

turtley-fms.hatenablog.com

turtley-fms.hatenablog.com