PLATFORM NOTICE
This guide only applies for apps built to run on the Basalt platform
(Pebble Time watches).
最高の Pebble アプリの中には、Animation と Graphics Context を上手く活用して、標準的な Layer タイプだけで作成されたものよりも美しく目を引くユーザーインターフェースを作成しているものがあります。
優れたデザインをさらに一歩進めるには、Draw Commands API を使用してベクター アイコンと画像を読み込み、実行時にポイント単位でアニメーション化することが含まれる場合があります。Draw Commands API の追加機能として、複数のフレームを単一のリソースに組み込み、フレームごとに再生できるドローコマンドシーケンスがあります。
このチュートリアルでは、これらのタイプの画像ファイルをあなたのプロジェクトで使用するプロセスを説明します。
描画するすべてのピクセルのデータを含むビットマップとは異なり、ベクター ファイルには、画像に含まれるポイントとそれらを結ぶ線の描画方法に関する命令のみが含まれています。塗りつぶしの色、ストロークの色、ストロークの幅などの命令も含まれます。
Pebble のベクター画像は Draw Commands API を使用して実装されており、これらの命令のセットを含む PDC(Pebble Draw Command)画像とシーケンスを読み込んで表示します。例としては、天気タイムライン ピンで使用される天気アイコンがあります。このアイコンにベクター グラフィックスを使用する利点は、タイムライン ビューとピン詳細ビューの間を移動するときに、おなじみの方法で画像を引き伸ばすことができることです:

1 つのファイルに 2 つ以上のベクター画像を含めることで、アニメーションを作成して、高速で詳細なアニメーション シーケンスを再生できるようになります。例えば以下のアニメーションの例のように、アクションが完了したときなど、Pebble システム UI で確認できます:

シンプルな画像やアイコンでビットマップよりもベクターを使用する主な利点は次のとおりです:
リソースサイズが小さい - ポイントを結合するための命令は、ピクセルごとのビットマップ データよりもメモリ効率が高くなります。
柔軟なレンダリング - ベクター画像は意図したとおりにレンダリングすることも、実行時に個々のポイントを移動するように操作することもできます。これにより、アイコンは静的な PNG 画像よりも有機的で生き生きとして見えます。スケーリングと歪みも可能になります。
より長いアニメーション - スペースを取らないという副次的な利点は、アニメーションを長くできることです。
ただし、特定のケースでベクター画像を選択することには、いくつかの欠点もあります:
ベクター ファイルは、ビットマップよりも専門的なツールを作成する必要があるため、作成が困難です。
複雑なベクター ファイルは、描画実装によっては、ピクセル単位で単純に描画される場合よりもレンダリングに時間がかかる場合があります。
Pebble のベクター画像ファイルの形式は PDC(Pebble Draw Command)形式で、ベクターの描画を可能にするために必要なすべての命令が含まれています。これらのファイルは、svg2pdc ツールを使用して、互換性のある SVG(Scalar Vector Graphics)ファイルから作成されます。
SVG ファイルを同じ名前の PDC 画像に変換するには:
$ python svg2pdc.py image.svg
個々の SVG フレームから PDCS(Pebble Draw Command Sequence)を作成するには、svg2pdc を実行するときに --sequence フラグを使用してフレームを含むディレクトリを指定します:
$ ls frames/
1.svg 2.svg 3.svg
4.svg 5.svg
$ python svg2pdc.py --sequence frames/
上記の例では、完全なアニメーションのドロー コマンド データを含む frames.pdc という出力ファイルが frames ディレクトリに作成されます。
制限事項
svg2pdc ツールは現在、次の要素のみを使用する SVG ファイルをサポートしています:g、layer、path、rect、polyline、polygon、line、circle。
互換性のある SVG アイコンと画像を作成するには、Adobe Illustrator の使用をお勧めします。
簡単にするために、独自のプロジェクトで使用できる互換性のある画像ファイルとシーケンス ファイルが提供されます。
サンプル PDC 画像ファイルは、App Assets にリストされているアイコンで利用できます。これらは、通知アプリや天気アプリなど、多くの一般的なタイプのアプリでの使用に最適です。
pebble new-project を使用して新しいプロジェクトを開始し、以下の例のように空白の Window をプッシュするシンプルなアプリを作成します:
#include <pebble.h>
static Window *s_main_window;
static void main_window_load(Window *window) {
Layer *window_layer = window_get_root_layer(window);
GRect bounds = layer_get_bounds(window_layer);
}
static void main_window_unload(Window *window) {
}
static void init() {
s_main_window = window_create();
window_set_window_handlers(s_main_window, (WindowHandlers) {
.load = main_window_load,
.unload = main_window_unload,
});
window_stack_push(s_main_window, true);
}
static void deinit() {
window_destroy(s_main_window);
}
int main() {
init();
app_event_loop();
deinit();
}
このチュートリアルでは、提供されているサンプル weather_image.pdc ファイルを使用してください。
以下に示すように、PDC ファイルを package.json のプロジェクト リソースに追加します。name フィールドを WEATHER_IMAGE に、type フィールドを raw に設定します。ファイル名は weather_image.pdc と想定されています:
"media": [
{
"type": "raw",
"name": "WEATHER_IMAGE",
"file": "weather_image.pdc"
}
]
Pebble Draw Command 画像を描画することは、通常の PNG 画像をグラフィックス コンテキストに描画するのと同じくらい簡単で、1 回の描画呼び出しだけで済みます。まず、リソースから .pdc ファイルを読み込みます。たとえば、以下に示すように WEATHER_IMAGE として定義された name を使用します。
ファイルの先頭に GDrawCommandImage 型のポインターを宣言します:
static GDrawCommandImage *s_command_image;
window_stack_push() を呼び出す前に、init() で GDrawCommandImage を作成して割り当てます:
static void init() {
/* ... */
// Create the object from resource file
s_command_image = gdraw_command_image_create_with_resource(RESOURCE_ID_WEATHER_IMAGE);
/* ... */
}
次に、PDC 画像の描画に使用される LayerUpdateProc を定義します:
static void update_proc(Layer *layer, GContext *ctx) {
// Set the origin offset from the context for drawing the image
GPoint origin = GPoint(10, 20);
// Draw the GDrawCommandImage to the GContext
gdraw_command_image_draw(ctx, s_command_image, origin);
}
次に、画像を表示する Layer を作成します:
static Layer *s_canvas_layer;
次に、レンダリングを行う LayerUpdateProc を設定し、目的の Window に追加します:
static void main_window_load(Window *window) {
/* ... */
// Create the canvas Layer
s_canvas_layer = layer_create(GRect(30, 30, bounds.size.w, bounds.size.h));
// Set the LayerUpdateProc
layer_set_update_proc(s_canvas_layer, update_proc);
// Add to parent Window
layer_add_child(window_layer, s_canvas_layer);
}
最後に、main_window_unload() で Window のサブコンポーネントが使用するメモリを解放することを忘れないでください:
static void main_window_unload(Window *window) {
layer_destroy(s_canvas_layer);
gdraw_command_image_destroy(s_command_image);
}
実行すると、PDC 画像が読み込まれ、LayerUpdateProc でレンダリングされます。画像をコントラストにするために、最後に window_create() の後で Window の背景色を変更します:
window_set_background_color(s_main_window, GColorBlueMoon);
結果は、以下に示す例と同様になります。

GDrawCommandSequence API を使用すると、開発者はベクター グラフィックスを大規模なアニメーションの個々のフレームとして使用できます。GDrawCommandImage と同様に、各 GDrawCommandFrame は LayerUpdateProc でグラフィックス コンテキストに描画されます。
このチュートリアルでは、提供されているサンプル clock_sequence.pdc ファイルを使用してください。
上記で提供されたテンプレートを含む C ファイルで新しいアプリを開始します。
次に、PDC 画像と同じ方法で、ファイルを raw リソースとして追加します。たとえば、package.json で name フィールドを CLOCK_SEQUENCE として指定します。
"media": [
{
"type": "raw",
"name": "CLOCK_SEQUENCE",
"file": "clock_sequence.pdc"
}
]
最初に GDrawCommandSequence ポインターを宣言して、アプリで PDCS を読み込みます:
static GDrawCommandSequence *s_command_seq;
次に、window_stack_push() を呼び出す前に init() でオブジェクトを初期化します:
static void init() {
/* ... */
// Load the sequence
s_command_seq = gdraw_command_sequence_create_with_resource(RESOURCE_ID_CLOCK_SEQUENCE);
/* ... */
}
LayerUpdateProc で次のフレームを取得して描画します。次に、次のフレームを描画するタイマーを登録します:
// Milliseconds between frames
#define DELTA 13
static int s_index = 0;
/* ... */
static void next_frame_handler(void *context) {
// Draw the next frame
layer_mark_dirty(s_canvas_layer);
// Continue the sequence
app_timer_register(DELTA, next_frame_handler, NULL);
}
static void update_proc(Layer *layer, GContext *ctx) {
// Get the next frame
GDrawCommandFrame *frame = gdraw_command_sequence_get_frame_by_index(s_command_seq, s_index);
// If another frame was found, draw it
if (frame) {
gdraw_command_frame_draw(ctx, s_command_seq, frame, GPoint(0, 30));
}
// Advance to the next frame, wrapping if neccessary
int num_frames = gdraw_command_sequence_get_num_frames(s_command_seq);
s_index++;
if (s_index == num_frames) {
s_index = 0;
}
}
次に、LayerUpdateProc を利用する新しい Layer を作成し、目的の Window に追加します。
Window ポインターを作成します:
static Layer *s_canvas_layer;
次に、Layer を作成して新しいポインターに割り当てます。更新プロシージャを設定し、Window に追加します:
static void main_window_load(Window *window) {
// Get Window information
Layer *window_layer = window_get_root_layer(window);
GRect bounds = layer_get_bounds(window_layer);
// Create the canvas Layer
s_canvas_layer = layer_create(GRect(30, 30, bounds.size.w, bounds.size.h));
// Set the LayerUpdateProc
layer_set_update_proc(s_canvas_layer, update_proc);
// Add to parent Window
layer_add_child(window_layer, s_canvas_layer);
}
初期化の最後にタイマーを使用してアニメーション ループを開始します:
// Start the animation
app_timer_register(DELTA, next_frame_handler, NULL);
最後に、main_window_unload() で GDrawCommandSequence と Layer を破棄することを忘れないでください:
static void main_window_unload(Window *window) {
layer_destroy(s_canvas_layer);
gdraw_command_sequence_destroy(s_command_seq);
}
実行すると、アニメーションは DELTA によって指示されたフレームレートでタイマーによって再生され、以下に示す例と同様になります:

これで、アプリにベクター画像とアニメーションを追加する方法を学習しました。これらの API の完全な例は、pebble-examples GitHub organization で入手できます:
pdc-image - Pebble Draw Command Image の実装例。
pdc-sequence - Pebble Draw Command Sequence アニメーション アイコンの実装例。
より高度なチュートリアルは今後ここに追加される予定なので、定期的にチェックしてください!