はじめに
HEIF(HEIC)形式のファイルについて、読み書きの処理を実装しました。
その際のまとめ記事になります。
-
libheif
のビルド - HEIF(HEIC)ファイルの作成
- HEIF(HEIC)ファイルの読込
HEIF(HEIC)とは
HEIF(HEIC)とは、High Efficiency Image File Format
のことで、Moving Picture Experts Group (MPEG)
によって開発された画像ファイルフォーマットです。(Wikipediaより)
同程度の画質のJPEG
形式と比べて、ファイルサイズを半分ほどに抑えられるとのことです。
画像形式の対応状況(英語)によると、macOS Sierra
やiOS 11
、ブラウザではSafari
が対応しているようです。
開発環境
Windows
でHEIF
ファイルを取り扱うには、HEIF 画像拡張機能(無料)、HEVC ビデオ拡張機能(有料)が必要のようです。
有料の拡張機能を使わずに、D言語でHEIF
ファイルの読み書き処理を実装しました。
- Windows 10 (バージョン 2004)
- Git (version 2.24.1.windows.2)
- CMake (version 3.15.19101501-MSVC_2)
- Visual C++ ビルドツール 2019 → インストール手順
- DMD v2.096.0
- libheif (release 1.12.0)
- libde265 (v1.0.8)
- libx265 (releasetag 3.4)
libheifのダウンロード
今回Windows10
向けにビルドしたライブラリとDLL
ファイルをGitHubに公開しました。
libheif_v1.12.0.zip
ビルドしたい方のために、以下にビルド方法を書きます。
libheifのビルド
libheifからソースコードを入手できます。
Windows
版であれば、Vcpkgから入手できるとのことで、試してみました。
しかし、途中でVisual Studio
英語版のインストールが必要とのエラーが出たため、中断して、cmake
から作成しました。
libheif
をビルドするには、libde265
、libx265
が必要なため、先にこれらをビルドします。
VS2019用 x64 Native Tools
コマンドプロンプトを起動します。
libde265のビルド
まずは、libde265
です。
以下の順序でコマンドを実行します。
d:\Dev> mkdir heif
d:\Dev> cd heif
d:\Dev\heif> git clone https://github.com/strukturag/libde265
d:\Dev\heif> cd libde265
d:\Dev\heif\libde265> cmake .
d:\Dev\heif\libde265> msbuild ALL_BUILD.vcxproj -p:Configuration=Release
d:\Dev\heif\libde265> cd ..
libx265のビルド
次に、libx265
です。
以下の順序でコマンドを実行します。
d:\Dev\heif> git clone https://github.com/videolan/x265
d:\Dev\heif> cd x265\source
d:\Dev\heif\x265\source> cmake .
d:\Dev\heif\x265\source> msbuild ALL_BUILD.vcxproj -p:Configuration=Release
d:\Dev\heif\x265\source> cd ../..
libde265
、libx265
のビルドが終わったところで、libheif
です。
以下の順序でコマンドを実行します。
d:\Dev\heif> git clone https://github.com/strukturag/libheif
d:\Dev\heif> cd libheif
d:\Dev\heif\libheif> cmake -D LIBDE265_INCLUDE_DIR=D:\Dev\heif\libde265 -D LIBDE265_LIBRARY=D:\Dev\heif\libde265\libde265\Release\libde265.lib -D X265_INCLUDE_DIR=D:\Dev\heif\x265\source -D X265_LIBRARY=D:\Dev\heif\x265\source\Release\libx265.lib .
d:\Dev\heif\libheif> msbuild ALL_BUILD.vcxproj -p:Configuration=Release
d:\Dev\heif\libheif> cd ..
lib、DLLファイルの配置
ビルドに成功したら、D:\Dev\heif\libheif\libheif\Release
にheif.lib
が作成されます。
heif.lib
をD:\Dev\heif\lib
に、各DLL
ファイルをD:\Dev\heif
にコピーします。
d:\Dev\heif> copy D:\Dev\heif\libheif\libheif\Release\heif.lib lib
d:\Dev\heif> copy D:\Dev\heif\libheif\libheif\Release\heif.dll .
d:\Dev\heif> copy D:\Dev\heif\libde265\libde265\Release\libde265.dll .
d:\Dev\heif> copy D:\Dev\heif\x265\source\Release\libx265.dll .
HEIF(HEIC)ファイルの作成
JPEG
やPNG
ファイル等FreeImage
で読み込み可能な画像形式ファイルから、HEIF
ファイルを作成するための実装例です。
ソースコード
/+ dub.sdl:
name "encode_sample"
dependency "bindbc-freeimage" version=">=0.3.0"
versions "FI_318"
dependency "libheif-d" repository="git+https://github.com/devmynote/libheif-d.git" version="92392885c81d9e3f5240acf82a8871b441ec9ab9"
+/
// dub build --build=release --single encode1.d
import std.conv;
import std.stdio;
import std.string;
import std.windows.charset;
import bindbc.freeimage;
import heif.heif;
pragma(lib, "lib/heif.lib");
void main(string[] args)
{
// Argument check
if ( args.length < 3 ){
writeln("Argument required : input output");
return;
}
string ifile = args[1].toMBSz.to!string;
string ofile = args[2].toMBSz.to!string;
// Load FreeImage
FISupport fis = loadFreeImage();
if ( fis != fiSupport ){
if ( fis == FISupport.noLibrary ){
writeln("FISupport.noLibrary");
} else if ( FISupport.badLibrary ){
writeln("FISupport.badLibrary");
}
return;
}
// Load Image
FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(ifile.toStringz);
FIBITMAP *dib = FreeImage_Load(fif, ifile.toStringz);
scope(exit) FreeImage_Unload(dib);
if ( dib == null ){
writeln("FreeImage_Load error");
return;
}
if ( FreeImage_GetBPP(dib) != 32 ){
FIBITMAP *dibold = dib;
dib = FreeImage_ConvertTo32Bits(dibold);
FreeImage_Unload(dibold);
}
int width = FreeImage_GetWidth(dib);
int height = FreeImage_GetHeight(dib);
ubyte* bits = FreeImage_GetBits(dib);
// Encode HEIF Image
heif_image* img;
heif_image_create(width, height, heif_colorspace.heif_colorspace_RGB, heif_chroma.heif_chroma_interleaved_RGBA, &img);
scope(exit) heif_image_release(img);
heif_image_add_plane(img, heif_channel.heif_channel_interleaved, width, height, 8);
int stride;
ubyte* data = heif_image_get_plane(img, heif_channel.heif_channel_interleaved, &stride);
for ( int y = 0; y < height; y++ ){
for ( int x = 0; x < width; x++ ){
int ind1 = x * 4 + y * stride;
int ind2 = x * 4 + (height - 1 - y) * width * 4;
*(data + ind1 ) = *(bits + ind2 + 2); // R
*(data + ind1 + 1) = *(bits + ind2 + 1); // G
*(data + ind1 + 2) = *(bits + ind2 ); // B
*(data + ind1 + 3) = *(bits + ind2 + 3); // A
}
}
// Get the default encoder
heif_context* ctx = heif_context_alloc();
scope(exit) heif_context_free(ctx);
heif_encoder* encoder;
heif_context_get_encoder_for_format(ctx, heif_compression_format.heif_compression_HEVC, &encoder);
scope(exit) heif_encoder_release(encoder);
// Set the encoder parameters
heif_encoder_set_lossy_quality(encoder, 100);
// Encode the image
heif_context_encode_image(ctx, img, encoder, null, null);
heif_context_write_to_file(ctx, ofile.toStringz);
}
コンパイル、実行
実行時にはFreeImage.dll
が必要です。
ダウンロードページにあるDownload FreeImage 3.18.0 [WIN32/WIN64]
から入手します。
できあがったHEIF
ファイルは、libheif decoder demoのサイトで内容確認できます。
D:\Dev\heif> dub build --build=release --single encode1.d
Performing "release" build using D:\Dev\dmd2\windows\bin64\dmd.exe for x86_64.
bindbc-loader 0.3.2: target for configuration "noBC" is up to date.
bindbc-freeimage 0.5.0: target for configuration "dynamic" is up to date.
encode_sample ~master: building configuration "application"...
Linking...
To force a rebuild of up-to-date targets, run again with --force.
D:\Dev\heif> encode_sample.exe abc.png abc.heic
HEIF(HEIC)ファイルの読み込み
HEIF
ファイルから、PNG
ファイルを作成するための実装例です。
ソースコード
/+ dub.sdl:
name "decode_sample"
dependency "bindbc-freeimage" version=">=0.3.0"
versions "FI_318"
dependency "libheif-d" repository="git+https://github.com/devmynote/libheif-d.git" version="92392885c81d9e3f5240acf82a8871b441ec9ab9"
+/
// dub build --build=release --single decode1.d
import std.conv;
import std.stdio;
import std.string;
import std.windows.charset;
import bindbc.freeimage;
import heif.heif;
pragma(lib, "lib/heif.lib");
void main(string[] args)
{
// Argument check
if ( args.length < 3 ){
writeln("Argument required : input output");
return;
}
string ifile = args[1].toMBSz.to!string;
string ofile = args[2].toMBSz.to!string;
// Load FreeImage
FISupport fis = loadFreeImage();
if ( fis != fiSupport ){
if ( fis == FISupport.noLibrary ){
writeln("FISupport.noLibrary");
} else if ( FISupport.badLibrary ){
writeln("FISupport.badLibrary");
}
return;
}
// Decode HEIF Image
heif_context* ctx = heif_context_alloc();
scope(exit) heif_context_free(ctx);
heif_context_read_from_file(ctx, ifile.toStringz, null);
int num = heif_context_get_number_of_top_level_images(ctx);
heif_item_id[] id = new heif_item_id[num];
heif_context_get_list_of_top_level_image_IDs(ctx, id.ptr, num);
for ( int i = 0; i < num; i++ ){
heif_image_handle* handle;
heif_context_get_image_handle(ctx, id[i], &handle);
scope(exit) heif_image_handle_release(handle);
int width = heif_image_handle_get_width(handle);
int height = heif_image_handle_get_height(handle);
heif_image* img;
heif_decode_image(handle, &img, heif_colorspace.heif_colorspace_RGB, heif_chroma.heif_chroma_interleaved_RGBA, null);
scope(exit) heif_image_release(img);
int stride;
const ubyte* data = heif_image_get_plane_readonly(img, heif_channel.heif_channel_interleaved, &stride);
FIBITMAP* dib = FreeImage_Allocate(width, height, 32);
scope(exit) FreeImage_Unload(dib);
ubyte* bits = FreeImage_GetBits(dib);
for ( int y = 0; y < height; y++ ){
for ( int x = 0; x < width; x++ ){
int ind1 = x * 4 + (height - 1 - y) * width * 4 ;
int ind2 = x * 4 + y * stride;
*(bits + ind1 ) = *(data + ind2 + 2); // B
*(bits + ind1 + 1) = *(data + ind2 + 1); // G
*(bits + ind1 + 2) = *(data + ind2 ); // R
*(bits + ind1 + 3) = *(data + ind2 + 3); // A
}
}
FreeImage_Save(FIF_PNG, dib, (ofile ~ i.to!string ~ ".png").toStringz);
}
}
コンパイル、実行
HEIF(HEIC)ファイルは、複数の画像データを格納可能です。
example.heicにも2つの画像データが含まれます。
その他、nokiatechのgithubにも画像サンプルがあります。
D:\Dev\heif> dub build --build=release --single decode1.d
Performing "release" build using D:\Dev\dmd2\windows\bin64\dmd.exe for x86_64.
bindbc-loader 0.3.2: target for configuration "noBC" is up to date.
bindbc-freeimage 0.5.0: target for configuration "dynamic" is up to date.
decode_sample ~master: building configuration "application"...
Linking...
To force a rebuild of up-to-date targets, run again with --force.
D:\Dev\heif> decode_sample.exe example.heic result
実行の結果、result0.png
とresult1.png
の2ファイルが作成されました。
libheif decoder demoで紹介されている画像と同じ結果になりました。
result0.png
result1.png
参考情報
High Efficiency Image File Format
【iOS】HEIF(HEIC)をさらっとおさらい
HEIF 画像拡張機能(無料)
HEVC ビデオ拡張機能(有料)
libheif
libde265
libx265
libheif decoder demo
nokiatechの画像サンプル
その他、画像処理の記事
これまでに書いた画像処理関連の記事です。相互に関連しあっているので、参考までに紹介します。