はじめに
複数のWebPファイルを元にアニメーションWebP(Animated WebP)を作成するプログラムを実装しました。
WebPについて
- 米Googleが開発しているオープンな静止画像フォーマットです。
- ウェブサイトのトラフィック量軽減と表示速度短縮を目的に、JPEGやGIF、PNGの置き換えを意図する規格だそうです。
- 各種ブラウザも表示対応しています。(
Chrome
、Firefox
、Edge
、Safari
、Opera
) - アニメーション形式にも対応しています。
環境
WebPファイルのアニメーションを作成するために、libwebpを使用します。
WebPの静止画像を作成するだけなら、こちらで紹介した方法もあります。
- Windows 10
- dmd v2.098.0
- libwebp ver 1.2.2 windows x64版
ソースコード
以下に、実装したソースコードを紹介します。
/+ dub.sdl:
name "awebp"
dependency "libwebp-d" repository="git+https://github.com/devmynote/libwebp-d.git" version="3c927671d7fef977a793cf3da0850104dc865216"
lflags "/LIBPATH:./lib"
+/
// dub build --build=release --arch=x86_64 --single awebp.d
import std.stdio;
import std.string;
import core.stdc.stdio;
import webp.decode;
import webp.encode;
import webp.mux;
import webp.muxtypes;
import webp.types;
ubyte[] loadWebP(string ifile)
{
auto file = File(ifile, "rb");
scope(exit) file.close();
auto size = file.size();
ubyte[] buf = file.rawRead(new ubyte[size]);
return ( buf );
}
void saveWebP(string ifile, string ofile)
{
ubyte[] buf = loadWebP(ifile);
auto file = File(ofile, "wb");
scope(exit) file.close();
file.rawWrite(buf);
}
ubyte* getImageRGBA(string ifile, int* width, int* height)
{
ubyte[] buf = loadWebP(ifile);
return ( WebPDecodeRGBA(buf.ptr, buf.length, width, height) );
}
void saveAnimatedWebP(string[] ifiles, string ofile, uint loopCount, ushort delayTime)
{
WebPAnimEncoderOptions enc_options;
WebPAnimEncoderOptionsInit(&enc_options);
WebPConfig config = void;
WebPConfigInit(&config);
WebPAnimEncoder* enc;
foreach ( i, ifile; ifiles ){
int width, height;
ubyte* rgba = getImageRGBA(ifiles[i], &width, &height);
if ( i == 0 ){
enc = WebPAnimEncoderNew(width, height, &enc_options);
}
WebPPicture frame;
WebPPictureInit(&frame);
frame.use_argb = 1;
frame.width = width;
frame.height = height;
int stride = width * 4;
WebPPictureImportRGBA(&frame, rgba, stride);
WebPAnimEncoderAdd(enc, &frame, cast(int)i * delayTime, &config);
WebPFree(rgba);
}
WebPAnimEncoderAdd(enc, null, cast(int)ifiles.length * delayTime, null);
WebPData webp_data;
WebPAnimEncoderAssemble(enc, &webp_data);
scope(exit) WebPFree(cast(void*)webp_data.bytes);
WebPMux* mux = WebPMuxCreate(&webp_data, 1);
WebPMuxAnimParams anim_params;
anim_params.loop_count = loopCount;
WebPMuxSetAnimationParams(mux, &anim_params);
WebPMuxAssemble(mux, &webp_data);
FILE* fp = fopen(ofile.toStringz, "wb");
scope(exit) fclose(fp);
fwrite(webp_data.bytes, webp_data.size, ubyte.sizeof, fp);
WebPMuxDelete(mux);
WebPAnimEncoderDelete(enc);
}
void main(string[] args)
{
if ( args.length == 3 ){
saveWebP(args[1], args[2]);
} else {
uint loopCount = 0; // 0:infinite
ushort delayTime = 500; // delayTime * ms
saveAnimatedWebP(args[1 .. $-1], args[$-1], loopCount, delayTime);
}
}
ソースコード補足
loadWebP
入力WebPファイルifile
をメモリに読み込みます。
saveWebP
入力WebPファイルが1つの場合、アニメーションWebPファイルを作成せず静止画像WebPファイルofile
を作成します。
getImageRGBA
入力WebPファイルから画像データ(RGBA)を抽出します。
saveAnimatedWebP
アニメーションWebPファイル作成の本処理となります。
- 複数の入力WebPファイルから画像データを抽出して、出力用アニメーションWebPファイルにセットします。
- アニメーションWebPファイルの幅、高さは1つ目の入力WebPファイルの情報を使います。このため、すべての入力WebPファイルはフレームの幅、高さが同じであることが前提です。
-
loopCount
は、アニメーションの繰り返し回数です。0
をセットすると無制限に繰り返します。 -
delayTime
は、各画像の表示間隔です。単位はミリ秒です。
コンパイル
libwebpの入手
A new image format for the Webより、libwebp-1.2.2-windows-x64.zipをダウンロードします。
libwebp-1.2.2-windows-x64.zip
内のlib
を以下に配置します。
D:\Dev\AWebP> tree
フォルダー パスの一覧: ボリューム ****
ボリューム シリアル番号は ****-**** です
D:.
└─lib
D:\Dev\AWebP> dir lib
フォルダー パスの一覧: ボリューム ****
ボリューム シリアル番号は ****-**** です
D:\Dev\AWebP\lib のディレクトリ
2021/03/20 18:23 <DIR> .
2021/03/20 18:23 <DIR> ..
2021/01/21 12:53 1,658,226 libwebp.lib
2021/01/21 12:53 42,868 libwebpdemux.lib
2021/01/21 12:53 118,690 libwebpmux.lib
lib
が配置できたら、コンパイルを実行するだけです。
D:\Dev\AWebP> dub build --build=release --arch=x86_64 --single awebp.d
parsePackageRecipe dub.sdl
Performing "release" build using D:\App\Dev\dmd2\windows\bin64\dmd.exe for x86_64.
awebp ~master: building configuration "application"...
Linking...
実行、実行結果
コマンド実行例です。実行結果はこちら
D:\Dev\AWebP> awebp i1.webp i2.webp i3.webp i4.webp i5.webp ani.webp
おまけ1:静止画像ファイルの作成
副産物として、適当なWebP静止画像ファイルの作成例を紹介します。
/+ dub.sdl:
name "iwebp"
dependency "libwebp-d" repository="git+https://github.com/devmynote/libwebp-d.git" version="3c927671d7fef977a793cf3da0850104dc865216"
lflags "/LIBPATH:./lib"
+/
// dub build --build=release --arch=x86_64 --single iwebp.d
import std.string;
import core.stdc.stdio;
import webp.encode;
import webp.types;
void saveImageWebP(string ofile, ubyte[] rgba, int width, int height)
{
int stride = width * 4;
ubyte* output;
size_t size = WebPEncodeLosslessRGBA(rgba.ptr, width, height, stride, &output);
scope(exit) WebPFree(output);
FILE* fp = fopen(ofile.toStringz, "wb");
scope(exit) fclose(fp);
fwrite(output, size, ubyte.sizeof, fp);
}
void saveImageSample()
{
int width = 200;
int height = 100;
ubyte[] rgba = new ubyte[width * height * 4];
for ( int y = 0; y < height; y++ ){
for ( int x = 0; x < width; x++ ){
int ind = x * 4 + y * width * 4;
rgba[ind ] = 0;
rgba[ind + 1] = 64;
rgba[ind + 2] = 128;
rgba[ind + 3] = 255;
}
}
saveImageWebP("image.webp", rgba, width, height);
}
void main(string[] args)
{
saveImageSample();
}
おまけ2:dstepを使ってみた
今回、libwebp
のライブラリを使用するためのバインドファイル(パッケージ)を作成しました。
おまけとして、バインドファイルを作成した際のメモ書きをまとめました。
参考:C言語のヘッダーファイルをD言語用に変換する dstep の使い方
dstep使用時の環境
- Windows 10
- dmd v2.096.0
- clang version 9.0.0
- Visual C++ ビルドツール 2019
- libwebp-1.2.2-windows-x64.zip
- dstep version 1.0.2
dstepのビルド
私の開発環境の場合、clangのインストールフォルダが標準と異なるため、ライブラリlibclang.lib
が見つからないというエラーが発生しました。
LINK : fatal error LNK1181: 入力ファイル 'libclang.lib' を開けません。
Error: linker exited with status 1181
D:\Dev\dmd2\windows\bin\dmd.exe failed with exit code 1.
dstepのdub.json
の/LIBPATH
をlibclang.lib
があるフォルダに修正します。(修正箇所は2か所あります)
以下は、D:\Dev\LLVM\lib
フォルダを指定する場合の修正例です。
"lflags-windows-x86_64": [
"/LIBPATH:D:\\Dev\\LLVM\\lib",
"libclang.lib",
"Ole32.lib"
],
dstepの実行
libwebp-1.2.2-windows-x64.zip
のinclude
をD:\Dev\AWebP
に配置しました。
その後で、dub
コマンドを順番に実行しました。出力先フォルダとしてsource
を作成しています。
コマンド実行中にDeprecated
のメッセージが出ますが、特に対処不要です。問題なくファイルが変換されました。
大半の変換はうまくいったので、とても便利だと感じました。ただし、すべて自動変換というわけにはいかず、一部手を加えました。
完成したファイルはこちらにもあります。
D:\Dev\AWebP> dub run dstep -- include\webp\decode.h -o source/decode.d
D:\Dev\AWebP> dub run dstep -- include\webp\demux.h -o source/demux.d
D:\Dev\AWebP> dub run dstep -- include\webp\encode.h -o source/encode.d
D:\Dev\AWebP> dub run dstep -- include\webp\mux.h -o source/mux.d
D:\Dev\AWebP> dub run dstep -- include\webp\mux_types.h -o source/muxtypes.d
D:\Dev\AWebP> dub run dstep -- include\webp\types.h -o source/types.d
参考情報
A new image format for the Web
libwebp-1.2.2-windows-x64.zip
WebPAnimEncoder API
C++ (Cpp) WebPAnimEncoderAssemble Examples
C言語のヘッダーファイルをD言語用に変換する dstep の使い方
dub v1.23.0/Support dependencies as git url with exact commit
アニメーションWebPの作り方
更新履歴
2021.3.20 初回投稿
2022.1.26 バージョン1.2.2にあわせて更新