2022/07/15(金) [n年前の日記]
#1 [prog] FreeImageとDevILライブラリを試用
C/C++で、pngファイルを読み込んだり書き込んだりする処理をしてみたい。
画像処理用のライブラリとして、FreeImage、DevIL というライブラリがあるらしいと知ったので試用してみた。
_C/C++ にて 画像ファイルを読み込む - Qiita
動作確認環境は、Windows10 x64 21H2 + MSYS2 (MinGW64)。g++ 12.1.0。GNU Make 4.3。
画像処理用のライブラリとして、FreeImage、DevIL というライブラリがあるらしいと知ったので試用してみた。
_C/C++ にて 画像ファイルを読み込む - Qiita
動作確認環境は、Windows10 x64 21H2 + MSYS2 (MinGW64)。g++ 12.1.0。GNU Make 4.3。
◎ FreeImageライブラリ。 :
C/C++ から利用できる画像処理用ライブラリとして、FreeImage というライブラリがあるらしい。
_The FreeImage Project
ライセンスは、GPL、または FreeImage Public License (FIPL)。どちらかを選べる、ということなのだろう。たぶん。
_GNU General Public License | Open Source Initiative
_freeimage.sourceforge.net/freeimage-license.txt
MSYS2 なら、パッケージが既に用意されていた。pacman -Ss hoge でパッケージ検索。
インストールしてみる。pacman -S hoge でインストールできる。
以下を参考にしてサンプルを用意した。pngファイルを読み込んで、1ドットずつグレースケール変換して、out.png として保存する、という処理をしている。
_FreeImageで画像の読み込みと保存 - Qiita
_画像変換ツールを自作する - Qiita
_FreeImage 3.13.1 documentation - FreeImage3131.pdf
_01_load_png01.cpp
コンパイルは以下。
実行。
グレースケールになった out.png が得られた。
ただ、ldd 01_load_png01.exe と打って、使用している .dll を確認したところ、かなり多い。ここまで多いのでは、おそらく静的リンク(スタティックリンク)はできない予感がする。
_The FreeImage Project
ライセンスは、GPL、または FreeImage Public License (FIPL)。どちらかを選べる、ということなのだろう。たぶん。
_GNU General Public License | Open Source Initiative
_freeimage.sourceforge.net/freeimage-license.txt
MSYS2 なら、パッケージが既に用意されていた。pacman -Ss hoge でパッケージ検索。
$ pacman -Ss freeimage mingw32/mingw-w64-i686-freeimage 3.18.0-8 Library project for developers who would like to support popular graphics image formats (mingw-w64) mingw64/mingw-w64-x86_64-freeimage 3.18.0-8 Library project for developers who would like to support popular graphics image formats (mingw-w64) ucrt64/mingw-w64-ucrt-x86_64-freeimage 3.18.0-8 Library project for developers who would like to support popular graphics image formats (mingw-w64) clang32/mingw-w64-clang-i686-freeimage 3.18.0-8 Library project for developers who would like to support popular graphics image formats (mingw-w64) clang64/mingw-w64-clang-x86_64-freeimage 3.18.0-8 Library project for developers who would like to support popular graphics image formats (mingw-w64)
インストールしてみる。pacman -S hoge でインストールできる。
pacman -S mingw-w64-x86_64-freeimage pacman -S mingw-w64-i686-freeimage
以下を参考にしてサンプルを用意した。pngファイルを読み込んで、1ドットずつグレースケール変換して、out.png として保存する、という処理をしている。
_FreeImageで画像の読み込みと保存 - Qiita
_画像変換ツールを自作する - Qiita
_FreeImage 3.13.1 documentation - FreeImage3131.pdf
_01_load_png01.cpp
// load png image with freeimage. #include <stdio.h> #include <iostream> #include <FreeImage.h> const char *outfile = "out.png"; int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage:\n\t01_load_png01.exe IN.png\n"); return -1; } FreeImage_Initialise(FALSE); printf("FreeImage ver. %s\n", FreeImage_GetVersion()); printf("%s\n\n", FreeImage_GetCopyrightMessage()); try { auto filename = argv[1]; // get input image format FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; int flag = 0; fif = FreeImage_GetFileType(filename); if (fif == FIF_UNKNOWN) fif = FreeImage_GetFIFFromFilename(filename); if (fif == FIF_PNG) flag = PNG_DEFAULT; else if (fif == FIF_BMP) flag = BMP_DEFAULT; else if (fif == FIF_GIF) flag = GIF_DEFAULT; else if (fif == FIF_JPEG) flag = JPEG_DEFAULT; // load image FIBITMAP *image = FreeImage_Load(fif, filename, flag); if (image) printf("Load : %s\n", filename); else throw std::runtime_error("Load failed"); // convert to 24bit image FIBITMAP *image24 = FreeImage_ConvertTo24Bits(image); // convert greyscale int width = FreeImage_GetWidth(image24); int height = FreeImage_GetHeight(image24); FIBITMAP *newimg = FreeImage_Allocate(width, height, 24); RGBQUAD col; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { FreeImage_GetPixelColor(image24, x, y, &col); double ncol = 0.299 * col.rgbRed + 0.587 * col.rgbGreen + 0.114 * col.rgbBlue; if (ncol < 0) ncol = 0; if (ncol > 255) ncol = 255; col.rgbRed = int(ncol); col.rgbGreen = int(ncol); col.rgbBlue = int(ncol); FreeImage_SetPixelColor(newimg, x, y, &col); } } // save png image if (FreeImage_Save(FIF_PNG, newimg, outfile, PNG_DEFAULT)) printf("Save : %s\n", outfile); else throw std::runtime_error("Save failed"); FreeImage_Unload(image); FreeImage_Unload(newimg); } catch (std::exception &e) { std::cout << "exception!\n" << e.what() << std::endl; } FreeImage_DeInitialise(); return 0; }
コンパイルは以下。
g++ 01_load_png01.cpp -o 01_load_png01.exe -lfreeimage
実行。
./01_load_png01.exe in.png
グレースケールになった out.png が得られた。
ただ、ldd 01_load_png01.exe と打って、使用している .dll を確認したところ、かなり多い。ここまで多いのでは、おそらく静的リンク(スタティックリンク)はできない予感がする。
◎ DevILライブラリ。 :
C/C++から利用できる画像処理用ライブラリとして、DevILというライブラリがあるらしい。
_DevIL - A full featured cross-platform Image Library
_DevILを用いた画像ファイルの読み込み - 月とスカラベ
_How To Load and Display an Image with DevIL and OpenGL | Geeks3D
MSYS2では、FreeImage と同様にパッケージが用意されていた。
インストール。
あちこちからコピペしてサンプルを書いてみた。画像を読み込んで画像サイズを出力するだけのスクリプト。
_01_load_image_devil.cpp
以下でコンパイル。
一応動いたものの、ldd 01_load_image_devil.exe で使用DLLを確認したら、これまたかなりの .dllを利用すると分かった。
試しに -static をつけて静的リンクを試みたところ、-lIL -ILU が見つからないとエラーが出てしまった。ググった感じでは、静的リンクをするなら DevILライブラリ自体をビルドし直さないといけないらしい。
_DevIL - A full featured cross-platform Image Library
_DevILを用いた画像ファイルの読み込み - 月とスカラベ
_How To Load and Display an Image with DevIL and OpenGL | Geeks3D
MSYS2では、FreeImage と同様にパッケージが用意されていた。
$ pacman -Ss devil mingw32/mingw-w64-i686-devil 1.8.0-8 Library for reading several different image formats (mingw-w64) mingw64/mingw-w64-x86_64-devil 1.8.0-8 Library for reading several different image formats (mingw-w64) ucrt64/mingw-w64-ucrt-x86_64-devil 1.8.0-8 Library for reading several different image formats (mingw-w64) clang32/mingw-w64-clang-i686-devil 1.8.0-8 Library for reading several different image formats (mingw-w64) clang64/mingw-w64-clang-x86_64-devil 1.8.0-8 Library for reading several different image formats (mingw-w64)
インストール。
pacman -S mingw-w64-x86_64-devil pacman -S mingw-w64-i686-devil
あちこちからコピペしてサンプルを書いてみた。画像を読み込んで画像サイズを出力するだけのスクリプト。
_01_load_image_devil.cpp
// DevIL sample. #include <IL/ilu.h> #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #undef USE_WCHAR_T int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage:\n\thoge.exe IN.png\n"); return 0; } char *filename = argv[1]; ILuint img; int width, height; // DevIL init ilInit(); iluInit(); // generate image ID ilGenImages(1, &img); ilBindImage(img); #ifdef USE_WCHAR_T // char to wchar_t size_t newsize = strlen(filename) + 1; wchar_t *wcfilename = new wchar_t[newsize]; size_t convertedChars = 0; mbstowcs_s(&convertedChars, wcfilename, newsize, filename, _TRUNCATE); #endif ILboolean fg; if (1) { // not use ilLoadImage() ILubyte *lump; ILuint size; FILE *fp; fp = fopen(filename, "rb"); fseek(fp, 0, SEEK_END); size = ftell(fp); lump = (ILubyte *)malloc(size); fseek(fp, 0, SEEK_SET); fread(lump, 1, size, fp); fclose(fp); fg = ilLoadL(IL_PNG, lump, size); free(lump); } else { // use ilLoadImage() fg = ilLoadImage(filename); } if (fg) { // load success printf("Load : %s\n", filename); width = ilGetInteger(IL_IMAGE_WIDTH); height = ilGetInteger(IL_IMAGE_HEIGHT); printf("image size : %d x %d\n", width, height); if (ilGetInteger(IL_IMAGE_ORIGIN) != IL_ORIGIN_LOWER_LEFT) { iluFlipImage(); } } else { // load failure ILenum err = ilGetError(); std::cerr << iluErrorString(err) << std::endl; } ilDeleteImages(1, &img); #ifdef USE_WCHAR_T delete wcfilename; #endif return 0; }
以下でコンパイル。
g++ 01_load_image_devil.cpp -o 01_load_image_devil.exe -lIL -lILU
一応動いたものの、ldd 01_load_image_devil.exe で使用DLLを確認したら、これまたかなりの .dllを利用すると分かった。
試しに -static をつけて静的リンクを試みたところ、-lIL -ILU が見つからないとエラーが出てしまった。ググった感じでは、静的リンクをするなら DevILライブラリ自体をビルドし直さないといけないらしい。
◎ wchar_t と char の変換。 :
Visual Studio Code 上で、DevIL のサンプルを書いていた際、ilLoadImage() に char* を渡す書き方をしたところ、「この関数は wchar_t* を要求している」と警告が表示されてしまった。
色々ググって、char* を wchar_t* に変換するやり方を記述したのだけど…。MSYS2 + MinGW64 でビルドしてみたら、今度は「これは char* を要求する関数だぞ」と言われてエラーが出てしまった。
どうやら、Visual Studio Code 上の警告は無視して、そのまま char* を渡せば良かったらしい。
ちなみに、char* から wchar_t* に変換する処理は以下。wcfilename に wchar_t の文字列が入る。はず。また、使い終わったら delete で消去(解放)しておかないといけない。
さておき。前述の問題の解決策が分かった。#define _UNICODE を無効にすれば、wchar_t* ではなく char* が使われる状態になるらしい。そのあたり、以下の韓国語ページで解説されていた。
_c++ devil library char または wchar_t の問題
vscode(Visual Studio Code)上で、この定義、_UNICODE を無効にするためには、以下の解説に従って作業する。
_Visual Studio Code C++ remove 'define' in c_cpp_properties.json - Stack Overflow
まず、vscode-preinclude.h というファイルをワークスペースフォルダ内に作って、以下の一文を書いておく。
vscode上で、Ctrl + Shift + P → C/C++:構成の編集(UI) C/C++: Edit Configurations (UI)。設定画面が出てくるので下のほうまでスクロールして「詳細設定」をクリック。「強制インクルード」の欄に以下を記述。
これで、vscode に vscode-preinclude.h が読み込まれて、そこに _UNICODE の定義を削除する一文が書いてあるから、DevIL の各関数が、wchar_t* ではなく char* を要求するものとして vscode に認識されて、おかしな警告が表示されなくなる。
あるいは、以下で紹介されているように、C++ の標準機能でファイルを開いてメモリに格納してから、そのメモリ領域を ilLoadL() に渡すのもアリかもしれない。
_The Developer's Image Library (DevIL) Tutorials
色々ググって、char* を wchar_t* に変換するやり方を記述したのだけど…。MSYS2 + MinGW64 でビルドしてみたら、今度は「これは char* を要求する関数だぞ」と言われてエラーが出てしまった。
どうやら、Visual Studio Code 上の警告は無視して、そのまま char* を渡せば良かったらしい。
ちなみに、char* から wchar_t* に変換する処理は以下。wcfilename に wchar_t の文字列が入る。はず。また、使い終わったら delete で消去(解放)しておかないといけない。
// char to wchar_t size_t newsize = strlen(filename) + 1; wchar_t *wcfilename = new wchar_t[newsize]; size_t convertedChars = 0; mbstowcs_s(&convertedChars, wcfilename, newsize, filename, _TRUNCATE); ... delete wcfilename;
さておき。前述の問題の解決策が分かった。#define _UNICODE を無効にすれば、wchar_t* ではなく char* が使われる状態になるらしい。そのあたり、以下の韓国語ページで解説されていた。
_c++ devil library char または wchar_t の問題
vscode(Visual Studio Code)上で、この定義、_UNICODE を無効にするためには、以下の解説に従って作業する。
_Visual Studio Code C++ remove 'define' in c_cpp_properties.json - Stack Overflow
まず、vscode-preinclude.h というファイルをワークスペースフォルダ内に作って、以下の一文を書いておく。
#undef _UNICODE
vscode上で、Ctrl + Shift + P → C/C++:構成の編集(UI) C/C++: Edit Configurations (UI)。設定画面が出てくるので下のほうまでスクロールして「詳細設定」をクリック。「強制インクルード」の欄に以下を記述。
${workspaceFolder}/vscode-preinclude.h
これで、vscode に vscode-preinclude.h が読み込まれて、そこに _UNICODE の定義を削除する一文が書いてあるから、DevIL の各関数が、wchar_t* ではなく char* を要求するものとして vscode に認識されて、おかしな警告が表示されなくなる。
あるいは、以下で紹介されているように、C++ の標準機能でファイルを開いてメモリに格納してから、そのメモリ領域を ilLoadL() に渡すのもアリかもしれない。
_The Developer's Image Library (DevIL) Tutorials
[ ツッコむ ]
#2 [nitijyou] 体調が悪い
朝、妙な息苦しさを感じた。喉にも痛みが。なんだろうコレは…。
実のところ、昨日一昨日から息苦しさを感じる瞬間はあって。寝ようとして横になったら急に息苦しくなったりとか。
症状からして、もしやコロナだろうか…。外出、というか密になる場面はできるだけ少なくしてるつもりなのだけど…。 *1
実のところ、昨日一昨日から息苦しさを感じる瞬間はあって。寝ようとして横になったら急に息苦しくなったりとか。
症状からして、もしやコロナだろうか…。外出、というか密になる場面はできるだけ少なくしてるつもりなのだけど…。 *1
*1: 夜食を買いに、数日に1回、近所のスーパー(ザ・ビッグ)、もしくはドラッグストア(カワチ)に入るぐらいで。できるだけ素早く買い物して早く店から出るように心掛けてはいるつもり。
[ ツッコむ ]
以上、1 日分です。