Binary Builderを使っていろいろ埋め込んでみた

# はじめに

**JUCE Advent Calendar 2017** 8日目 二回目の参加になります。 kawaです。
今回はJUCEライブラリにこっそりついてくる **BinaryBuilder** について調べてみました。
間違っている部分はコメント欄にてご教授いただけると嬉しいです。
( JUCE v5.11 でこの記事を書いています。)

# Binary Builderとは？

* 画像やフォント、リソースファイルをバイナリデータとしてC++ソースに出力するコンソールアプリ。

> リソースファイルをバイナリソースにする方法は **Projucer** アプリでも可能。

今回は **ProJucer** を使わずに **BinaryBuilder** を使用してみたいと思います。


# Binary Builder の準備

Binary BuilderのプロジェクトファイルはJUCEの **```extras```** フォルダにこっそり入っています。

![01_BinaryBuilder.png](https://qiita-image-store.s3.amazonaws.com/0/212250/2f7394f9-409a-6b21-f6a0-daf07b6b567e.png)


プロジェクトファイルを使ってコンパイルを終えたところ。

![02_BinaryBuilder_2.PNG](https://qiita-image-store.s3.amazonaws.com/0/212250/4e3bf933-c5e9-f545-4d2d-2b3a679f8e68.png)



# 使い方の説明

Binary Builder はコンソールアプリなので、
コマンドプロンプト、ターミナル の中で使用していきます。


```bash:
$binaryBuilder  sourceDirectory  destDirectory  (targetClassName)
```

> **第1引数** : バイナリにしたいファイルをまとめたフォルダのディレクトリ
> **第2引数** : 出力するディレクトリの場所 (ディレクトリが存在しない場合はエラーが出るようです。)
> **第3引数** : 出力するソースファイルの名前
>ヘルプは **```-help```** オプションで表示できるようです。

# Buinary Builderを使ってみた

テスト用として あらかじめ ```TestResource``` フォルダの中に猫画像を3枚 、そして出力先の　```OutPut``` フォルダを準備して実行してみました。

```bash:
$binaryBuilder  TestResource OutPut TestResource
```

> 第1引数 : **TestResource** : バイナリソースにしたいフォルダパス
> 第2引数 : **OutPut** : 出力先のフォルダパス
> 第3引数 : **TestResource** : 出力するソースの名前

[画像] OutPutフォルダの中身

<img src="https://qiita-image-store.s3.amazonaws.com/0/212250/4d5a2c5e-84ea-335f-5f46-a73aed1f8f7a.png">

```c++:TestResource.h
/* (Auto-generated binary data file). */

#pragma once

namespace TestResource
{
    extern const char*  img_koma_01_jpg;               // 1枚目の画像のデータ
    const int           img_koma_01_jpgSize = 87341;   // 1枚目の画像のデータのサイズ

    extern const char*  img_koma_02_jpg;               // 2枚目の画像のデータ
    const int           img_koma_02_jpgSize = 126548;  // 2枚目の画像のデータのサイズ

    extern const char*  img_koma_03_jpg;               // 3枚目の画像のデータ
    const int           img_koma_03_jpgSize = 87332;   // 3枚目の画像のデータのサイズ

}
```
無事にOutPutフォルダに出力できているようです。ソースの中身を見てみると3枚分の画像のデータが書き出されていました。
実際にJUCEの中で使ってみたいと思います。


# 実際にいろいろ使ってみた

### 1. 画像を埋め込んでみた

![Koma_2.PNG](https://qiita-image-store.s3.amazonaws.com/0/212250/28177d53-9310-c1fe-8054-4958b8d9c910.png)

```c++
// 1枚目 : Binary Builder を使って出力したソースと
// ImageCacheクラスを経由してImageクラスを作成
this->m_img1 = juce::ImageCache::getFromMemory( TestResource::img_koma_01_jpg         // データ(1枚目)
                                              , TestResource::img_koma_01_jpgSize  ); // サイズ(1枚目)
this->m_img1 = m_img1.rescaled( m_img1.getWidth()  * 0.2 
                              , m_img1.getHeight() * 0.2 ); // 画像が大きかったので縮小

// 2枚目
this->m_img2 = juce::ImageCache::getFromMemory( TestResource::img_koma_02_jpg         // データ(2枚目)
                                              , TestResource::img_koma_02_jpgSize  ); // サイズ(2枚目)
this->m_img2 = m_img2.rescaled( m_img2.getWidth()  * 0.2 
                              , m_img2.getHeight() * 0.2 ); // rescale

// 3枚目 省略 ... 

//=============================================================================
// 描画するとき
// g.drawImageAt( m_img1 , x ,y , false );
// x += m_img1.getWidth() + 5; //margin 5 2枚目の座標
// ....
```

### 2. フォントを埋め込んでみた

![06_BinaryBuilder_Font.PNG](https://qiita-image-store.s3.amazonaws.com/0/212250/1deb5d55-d764-42e1-fd2d-0180d024726f.png)

今度はフォントを BinaryBuilder でC++ソースにして、日本語を表示してみました。

```c++
//=========================================================================  
// ソースファイル自体をUTF-8(BOMありで保存しておく。) 
juce::String text = JUCE_T( "春はあけぼの\nやうやう白くなりゆく山ぎは\n少しあかりて" );
//=========================================================================  

// Binary Builder を使って出力したソースと
// TypeFaceクラスを経由してFontクラスを作成
this->m_font1 = juce::Font( juce::Typeface::createSystemTypefaceFor( TestResource::VLGothicRegular_ttf          // データ ( フォント)
                                                                   , TestResource::VLGothicRegular_ttfSize ) ); // サイズ ( フォント)
this->m_font1.setHeight( 40.0f ); //フォントのサイズ変更

//=========================================================================                                                                 
// 描画するとき
// g.setFont ( this->m_font1 ); 
// g.drawFittedText( text ...
```

> * 細かい部分は未検証ですが、もしも読み込んだフォントで表示できない場合は ```Regular``` 体 を含むフォントで試してみると解決するかもしれないです。 


使用したフォント

* VL Gothic フォント
https://osdn.net/projects/vlgothic/

* ロゴたいぷゴシック 
http://www.fontna.com/blog/1226/



### 3. zipファイルを埋め込んでみた

ふと、zipファイルも埋め込んで解凍できるかもしれない。と気になって試してみました。

```c++:
//=========================================================================
// あらかじめBinary Builder を使って出力したソースと
// MemoryInputStream を経由して ZipFileクラスを作成。
juce::MemoryInputStream stream ( TestResource::test_zip      // データ
                               , TestResource::test_zipSize  // サイズ
                               , false );                    
juce::ZipFile zip( stream ); // ZipFile クラスをInputStreamクラスから作成
//=========================================================================

const int totalEntryNum = zip.getNumEntries();//zipファイル内のすべてのエントリー数を取得
for ( int i = 0; i < totalEntryNum; ++i)
{
    const juce::ZipFile::ZipEntry* entry = zip.getEntry( i );
    DBG( entry->filename  ); // ファイル名をコンソールに出力。( デバッグ表示用
}
//=========================================================================
```

```bash:出力(デバッグ)
img_koma_01.jpg
img_koma_02.jpg
img_koma_03.jpg
makuranosousi.txt
VL-Gothic-Regular.ttf
```
無事に埋め込んだzipファイルを読み込んでいるようです。
( zipファイルの中に猫画像とフォント、サンプルテキストを入れてみました。)


### 4. zipファイルから画像を表示してみた


![07.PNG](https://qiita-image-store.s3.amazonaws.com/0/212250/c361c9e0-18bc-7aea-0a5c-47a4fa639376.png)

今度は、zipファイルの中にある画像の表示について調べてみました。

```c++
//=============================================================================
// MemoryInputStream を経由して ZipFileクラスを作成。
juce::MemoryInputStream stream ( TestResource::test_zip     // データ
                               , TestResource::test_zipSize // サイズ
                               , false);
juce::ZipFile zip( stream );
//=============================================================================

// zipファイルのインデックスを zip内のファイルパスから取得。
const int targetZipEntryIndex = zip.getIndexOfFileName( "img_koma_01.jpg" ); 
//=============================================================================
if( targetZipEntryIndex != -1) // ファイルが見つかった場合.
{
    // 画像 を InputStreamクラス、MemoryBlock クラスを経由して Imageクラス を作成
    juce::ScopedPointer<juce::InputStream> inputStream = zip.createStreamForEntry( targetZipEntryIndex );
    juce::MemoryBlock memoryBlock;
    inputStream->readIntoMemoryBlock( memoryBlock );
    this->m_img = juce::ImageCache::getFromMemory( memoryBlock.getData()    // データ
                                                 , memoryBlock.getSize() ); // サイズ
    //=========================================================================
    this->m_img = m_img.rescaled( m_img.getWidth() *0.2, m_img.getHeight() *0.2 );// rescale
}

//=============================================================================
// 描画する時
// g.drawImageAt( m_img, 10, 10, false );
```

### 5. zipファイルからフォントを使ってみた

![07.PNG](https://qiita-image-store.s3.amazonaws.com/0/212250/7f2dcf75-884b-854b-1113-b5687fb1c3dc.png)

画像が表示できるなら、きっとzipファイルの中にあるフォントも読み込めるはず、と調べてみました。

```c++
//=========================================================================
// MemoryInputStream クラスを作成して ZipFileクラスを作成。
juce::MemoryInputStream stream ( TestResource::test_zip      // データ
                               , TestResource::test_zipSize  // サイズ
                               , false);
juce::ZipFile zip( stream );
//=========================================================================

// 猫画像部分 省略
//=========================================================================
const int targetTextIndex = zip.getIndexOfFileName( "makuranosousi.txt" );     // テキストファイル 
const int targetFontIndex = zip.getIndexOfFileName( "VL-Gothic-Regular.ttf" ); // フォントファイル
//=========================================================================
if (  targetTextIndex != -1
   && targetFontIndex != -1 )
{
    // サンプルテキストとして InputStreamクラス、MemoryBlockクラスを経由して Stringクラス を作成
    //=====================================================================
    juce::ScopedPointer<juce::InputStream> inputStream_txt = zip.createStreamForEntry( targetTextIndex );
    juce::MemoryBlock memoryBlock_txt;
    inputStream_txt->readIntoMemoryBlock( memoryBlock_txt );
    this->m_drawText = memoryBlock_txt.toString();
    //=====================================================================

    // 日本語フォントを InputStreamクラス、MemoryBlock クラスを経由して Fontクラス を作成
    juce::ScopedPointer<juce::InputStream> inputStream_font = zip.createStreamForEntry( targetFontIndex );
    juce::MemoryBlock memoryBlock_font;
    inputStream_font->readIntoMemoryBlock( memoryBlock_font );
    this->m_font = juce::Font( juce::Typeface::createSystemTypefaceFor( memoryBlock_font.getData()
                                                                      , memoryBlock_font.getSize() ));
    this->m_font.setHeight( 30.f ); // フォントサイズ
    //=====================================================================
}

// 描画 するとき
//=========================================================================
// g.setColour( juce::Colours::black );
// g.setFont  ( m_font );
// g.drawFittedText( m_drawText , .... 
//=========================================================================
```


# 結び

もしも内容に間違いがありましたら、コメント欄にて教えていただけると嬉しいです。

JUCEライブラリを扱っていると、やっぱり「なるほど～」と納得する部分があります。
僕も見習いたいと思っています。

この投稿が公開される日は12月8日。そろそろ年賀状に取り掛かりたい、と思いつつ・・時間は過ぎていくのでした。
よい年末をお過ごしください。

それでは、明日の Astellon さんへバトンタッチ。
ありがとうございました！