Skip to content

Latest commit

 

History

History
165 lines (115 loc) · 11.7 KB

readme.md

File metadata and controls

165 lines (115 loc) · 11.7 KB

Commodetto 用アニメーション GIF

Copyright 2021 Moddable Tech, Inc.
更新日: 2021年4月11日

はじめに

アニメーションGIF画像形式は人気があり、マイクロコントローラーでも実装可能です。Commodettoグラフィックスライブラリは、スムーズなアニメーションを提供する製品のために、マイクロコントローラー上で高品質、高性能なレンダリングを提供します。

ほとんどのマイクロコントローラー向けのGIF実装は、メモリ使用量を最小限に抑えるためにフレームバッファに直接デコードします。これは一部のアニメーションGIFには有効ですが、他のものではちらつきやブロックノイズを引き起こすことがあります。CommodettoのアニメーションGIFデコーダーは異なるアプローチを取ります: 完全にデコードされた画像のためのメモリバッファを必要とします。これにより、メモリが厳しい場合には適していません。しかし、動作するデバイスでは、正確で高性能、ちらつきのないアニメーションを提供することができます。デコーダーの出力がCommodettoビットマップであるため、Pocoレンダラーを使用して他のグラフィカル要素と合成することができます。

CommodettoのアニメーションGIFデコーダーには、多くのアニメーションGIFシーケンスをデコードするために必要なメモリ量を大幅に削減するためのいくつかの特別なデコードモードがあります。 メモリ要件が増加したため、CommodettoのアニメーションGIFデコーダーはすべてのマイクロコントローラーで実用的ではありません。ESP32(外部RAMなし)およびPico(RP2040)では、約200ピクセルの画像に対して非常にうまく機能します。

Examples

モジュールを使用するには、まずインポートします:

import ReadGIF from "commodetto/ReadGIF";

インスタンスの作成

モジュールはリソースからGIFデータを読み取ります。リソースをコンストラクタに渡します:

let reader = new ReadGIF(new Resource("moddable.gif"));

メモリ使用量

ReadGIFはデコード状態を保存するためのメモリと、デコードされた画像を保存するためのメモリを必要とします。メモリが不足している場合、ReadGIF は例外をスローします。

デコード状態はアプリケーションヒープにあります。アプリケーションヒープのデフォルト構成はこれには小さすぎるため、約48 KBに増やす必要があります。プロジェクトマニフェストでこれを行うことができます:

	"creation": {
		"static": 49152
	}

デコードされた画像はシステムメモリに保存されます。ReadGIF を呼び出すときにシステムメモリがどれだけ空いているかを確認するには、xsbugの計測タブを確認してください。

ファイルに関する情報

リーダーインスタンスの widthheight プロパティは、デコードされた画像のサイズを提供します。

duration プロパティはアニメーションの総長さをミリ秒単位で示します。frameCount はアニメーションの総フレーム数です。

フレームのデコード

画像をデコードするには、next を呼び出します。アニメーションフレームシーケンスの終わりに達すると、デコーダーは自動的に最初に戻ります。

reader.next();

next 関数はリーダーの状態を次のフレームに更新します。リーダー自体はデコードされた画像を含むビットマップとして使用できます。画像をレンダリングするために便利な他のプロパティも持っています。next によって最後にデコードされたフレームの番号は frameNumber プロパティから取得できます。

注意: リーダーインスタンスの ready プロパティは、少なくとも1フレームのGIFが描画可能である場合に true になります。画像をダウンロードする際には、reader.ready をチェックしてリーダーが最初のフレームを返す準備ができているかどうかを確認してください。

フレームの描画

next を呼び出すと、リーダーのビットマップが次のフレームに更新されます。通常通りにビットマップを描画するためにPocoを使用します。以下は、画面の左上隅に画像を描画します。

import Poco from "commodetto/Poco";

poco.begin(0, 0, reader.width, reader.height);
poco.drawBitmapWithKeyColor(reader, 0, 0);
poco.end();

描画の最適化

多くの場合、アニメーションはフレーム全体ではなく、ピクセルの一部のみを更新します。この場合、ディスプレイ上のすべてのピクセルを更新する必要はなく、より効率的です。リーダーはその frameXframeYframeWidth、および frameHeight プロパティで更新領域を提供します。

次の例では、更新領域を使用して描画を最小限に抑えながら、毎秒10フレームでアニメーションを連続的に実行します。

Timer.repeat(() => {
	reader.next();

	poco.begin(reader.frameX, reader.frameY, reader.frameWidth, reader.frameHeight);
	poco.drawBitmapWithKeyColor(reader, 0, 0);
	poco.end();
}, 100);

アニメーションのタイミング

アニメーションGIFの各フレームにはそれぞれの持続時間があります。デコードされたフレームの持続時間は、リーダーインスタンスの frameDuration プロパティでミリ秒単位で取得できます。

let frameDuration = reader.frameDuration;

まとめ

この例は、描画領域を最適化し、各フレームの持続時間を適用する典型的な描画ループを示しています。

const reader = new ReadGIF(new Resource("moddable.gif"));

Timer.repeat(id => {
	reader.next();
	Timer.schedule(id, reader.frameDuration, 1);

	poco.begin(reader.frameX, reader.frameY, reader.frameWidth, reader.frameHeight);
	poco.drawBitmapWithKeyColor(bitmap, 0, 0);
	poco.end();
}, 1);

透過性

一部のアニメーションGIF画像には、背景が透けて見えるように設計された透明な領域があります。これは、非矩形の形状を持つアニメーションに使用されます。透明性は二値的で、ピクセルは完全に不透明か完全に見えないかのどちらかです。アルファブレンディングはありません。

リーダーインスタンスの transparent プロパティは、画像に透明なピクセルが含まれているかどうかを示します。

真の透過性を実現するにはいくつかのステップが必要です。まず、アプリケーションは画像の背後にある背景ピクセルを塗りつぶす必要があります。以下の例では、背景を赤で塗りつぶしています。次に、drawBitmapWithKeyColor を使用して画像をレンダリングし、アニメーションGIFから透明色を提供します。drawBitmapWithKeyColor 関数は drawBitmap と似ていますが、指定されたキー色と一致するピクセルをスキップします。

const red = poco.makeColor(255, 0, 0);

poco.fillRectangle(red, 0, 0, reader.width, reader.height);
poco.drawBitmapWithKeyColor(reader, 0, 0, reader.transparentColor);

fillRectangle 呼び出しがアニメーションGIFの背後に描画されることに注意してください。コードは、パターンやロゴ、さらには別のアニメーションなど、GIFの背後に何でも描画できます。drawBitmapWithKeyColor を使用するのは安全です。

メモリ使用量の削減

GIF画像には2色から約1600万色まで含まれています。多くの色を持つ画像は、ピクセルあたり16ビットで保存する必要があり、かなりのメモリを使用します。Commodetto GIFデコーダーは、GIF画像を8ビット、4ビット、および1ビットピクセルにデコードすることもできます。デコーダーは、完全な色忠実度を維持しながら、最も少ないメモリを使用するフォーマットを自動的に決定します。使用されるビットマップフォーマットは常に poco.drawBitmapWithKeyColor を使用して描画できます。使用されるビットマップのフォーマットは、GIFリーダーインスタンスの pixelFormat プロパティから取得できます。

一部のアプリケーションでは、自動フォーマット検出を無効にして特定のフォーマットにデコードを強制することを希望する場合があります。これにより、正しくレンダリングされない画像が生成されることがありますが、クラッシュすることはありません。特定のフォーマットにデコードを強制するには、オプションの引数の一部としてピクセルフォーマットを ReadGIF コンストラクタに渡します。以下の例は、RGB565リトルエンディアンフォーマットでピクセルを要求する方法を示しています:

const reader = new ReadGIF(
	new Resource("moddable.gif"),
	{
		pixelFormat: Bitmap.RGB565LE
	}
);

1、4、および8ビットパーピクセルにデコードを強制するには、それぞれ Bitmap.MonochromeBitmap.Gray16、および Bitmap.CLUT256 を使用します。

リファレンス

以下の表は、GIFリーダーインスタンスで利用可能なプロパティを説明しています。GIFアニメーションはキャンバスに描画されます。アニメーションの各フレームには、キャンバスを更新する画像が含まれています。画像はキャンバス全体を更新する場合もあれば、その一部のみを更新する場合もあります。

プロパティ 説明
width アニメーションキャンバスの幅
height アニメーションキャンバスの高さ
duration アニメーションの総持続時間(ミリ秒)
frameBounds 現在のフレームの更新領域を含む矩形オブジェクト
frameCount アニメーションの総フレーム数
frameDuration 現在のフレームの持続時間(ミリ秒)
frameNumber 現在のフレームのインデックス番号
frameX 前のフレームから更新された領域のキャンバス内の水平オフセット
frameY 前のフレームから更新された領域のキャンバス内の垂直オフセット
frameWidth 現在のフレームで更新された領域の幅
frameHeight 現在のフレームで更新された領域の高さ
transparent キャンバスに透明な背景ピクセルが含まれている場合は true
transparentColor 透明な背景ピクセルを埋めるために使用されるピクセル値。画像が透明性を使用していない場合は未定義
ready アニメーションGIFリーダーが少なくとも1フレームを解析できる場合は true。GIF画像をダウンロードする際に最初のフレームが利用可能かどうかを検出するために使用されます

謝辞

コアのGIFデコーダーは、BitBank SoftwareLarry Bank による GIF Animator です。