はじめに
画像変換ツールを自作したい方に向けて、実装例を紹介します。
FreeImageというライブラリを使うことで、PNG
、JPEG
、WebP
、GIF
、BMP
、TIFF
など、多様なファイル形式に相互変換可能です。
開発環境の情報
- Windows 10
- DMD v2.096.0
- FreeImage 3.18.0
画像変換ツールの実装例
画像ファイルを読み込んでからの画像変換処理を実装しました。
convFreeImage.d
/+ dub.sdl:
name "convFreeImage"
dependency "bindbc-freeimage" version=">=0.3.0"
versions "FI_318"
+/
// dub build --build=release --single convFreeImage.d
import std.conv;
import std.stdio;
import std.string;
import std.windows.charset;
import bindbc.freeimage;
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;
}
FREE_IMAGE_FORMAT format = FreeImage_GetFIFFromFilename(ofile.toStringz);
switch ( format ){
case FIF_GIF:
if ( FreeImage_GetBPP(dib) > 8 ){
FIBITMAP *dibold = dib;
dib = FreeImage_ColorQuantize(dibold, FIQ_WUQUANT);
FreeImage_Unload(dibold);
}
break;
case FIF_JPEG:
if ( FreeImage_GetBPP(dib) > 24 ){
FIBITMAP *dibold = dib;
dib = FreeImage_ConvertTo24Bits(dibold);
FreeImage_Unload(dibold);
}
break;
default:
}
FreeImage_Save(format, dib, ofile.toStringz);
}
FreeImageを使う際の注意点
GIF
形式への変換
GIF
形式へ変換を行う場合は、入力データを256色(8ビット)以下に減色する必要があります。
FreeImage_ColorQuantize
を使って減色処理を行っています。
JPEG
形式への変換
JPEG
形式へ変換を行う場合は、入力データの24ビットカラー(RGB)以下に変換する必要があります。
入力データのピクセル情報が24ビットを超える場合は、FreeImage_ConvertTo24Bits
を使って24ビットカラー(RGB)に変換してます。
コンパイル実行例
コマンドプロンプト
D:\Dev> dub build --build=release --single convFreeImage.d
Performing "release" build using D:\Dev\dmd2\windows\bin\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.
convFreeImage ~master: building configuration "application"...
Linking...
To force a rebuild of up-to-date targets, run again with --force.
モジュール実行例
コンパイルしたモジュールconvFreeImage.exe
を実行するには、FreeImage.dll
が必要です。
ダウンロードページより、入手してください。
コマンドプロンプト
D:\Dev> convFreeImage a.jpg b.webp
おまけ:メモリ上の画像データ変換
メモリ上の画像データを読み込むことや、メモリに画像データを書き込むことができます。
-
loadMemory
がubyte
配列からFreeImage
が管理するメモリFIMEMORY
への読み込み -
saveMemory
がメモリFIMEMORY
からubyte
配列への画像データを書き込み -
convert
が画像形式変換処理
の実装例となります。
convFreeImage2.d
/+ dub.sdl:
name "convFreeImage2"
dependency "bindbc-freeimage" version=">=0.3.0"
versions "FI_318"
+/
// dub build --build=release --single convFreeImage2.d
import std.conv;
import std.stdio;
import std.string;
import std.windows.charset;
import bindbc.freeimage;
ubyte[] loadFile(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 saveFile(ubyte[] buf, string ofile)
{
auto file = File(ofile, "wb");
scope(exit) file.close();
file.rawWrite(buf);
}
FIMEMORY* loadMemory(ubyte[] buf)
{
FIMEMORY* hmem = FreeImage_OpenMemory(buf.ptr, cast(uint)buf.length);
return ( hmem );
}
ubyte[] saveMemory(FIMEMORY* hmem)
{
ubyte* mem;
uint bufsize;
FreeImage_AcquireMemory(hmem, &mem, &bufsize);
FreeImage_SeekMemory(hmem, 0, 0/* = SEEK_SET */);
ubyte[] buf = new ubyte[bufsize];
FreeImage_ReadMemory(buf.ptr, 1, cast(uint)buf.length, hmem);
return ( buf );
}
FIMEMORY* convert(FIMEMORY* himem, FREE_IMAGE_FORMAT format)
{
FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory(himem);
FIBITMAP* dib = FreeImage_LoadFromMemory(fif, himem);
switch ( format ){
case FIF_GIF:
if ( FreeImage_GetBPP(dib) > 8 ){
FIBITMAP *dibold = dib;
dib = FreeImage_ColorQuantize(dibold, FIQ_WUQUANT);
FreeImage_Unload(dibold);
}
break;
case FIF_JPEG:
if ( FreeImage_GetBPP(dib) > 24 ){
FIBITMAP *dibold = dib;
dib = FreeImage_ConvertTo24Bits(dibold);
FreeImage_Unload(dibold);
}
break;
default:
}
FIMEMORY* homem = FreeImage_OpenMemory();
FreeImage_SaveToMemory(format, dib, homem);
return ( homem );
}
void main(string[] args)
{
// Argument check
if ( args.length < 3 ){
writeln("Argument required : input output");
return;
}
// Load FreeImage
FISupport fis = loadFreeImage();
if ( fis != fiSupport ){
if ( fis == FISupport.noLibrary ){
writeln("FISupport.noLibrary");
} else if ( FISupport.badLibrary ){
writeln("FISupport.badLibrary");
}
return;
}
ubyte[] buf = loadFile(args[1]);
FIMEMORY* himem = loadMemory(buf);
scope(exit) FreeImage_CloseMemory(himem);
FREE_IMAGE_FORMAT format = FreeImage_GetFIFFromFilename(args[2].toMBSz);
FIMEMORY* homem = convert(himem, format);
scope(exit) FreeImage_CloseMemory(homem);
buf = saveMemory(homem);
saveFile(buf, args[2]);
}
その他、画像ファイル作成のための参考情報
画像ファイル変換処理を自作する(AVIF
、HEIC
形式)
アニメーションファイルを自作する
画像ビューアを自作する
サムネイル画像を自作する