他の画像形式への対応について
furafura 2015/01/20(Tue) 19:35
実はこのような記事を知りました。
http://nilposoft.info/archives/579
現時点で信憑性は不明です。(他の記事等を観ると、エンコーダの事を表現している可能性もありそうなので)
Siv3Dで、WICによるPNGデコード処理を行ってみたい場合、現在提供の機能で、努力すれば可能かどうか教えて頂けますでしょうか?
Imageのデータが厳密にはどうなっているのか、分かりかねるので、手が出せない状態です。
CustomImageに目を付けているのですが、間違っているでしょうか?
また、WICのデコードが有用だった場合、将来的にSiv3Dで対応する可能性はありますでしょうか?
Reputeless 2015/01/23(Fri) 16:00
furafura 2015/01/23(Fri) 17:57
furafura 2015/01/25(Sun) 18:50
誰も喜ばないと思いますが、実験コードを出しておく事にしました。
http://tanayalog.blogspot.jp/2013/12/windows-2.html
https://msdn.microsoft.com/ja-jp/library/ee719797(en-us,VS.85).aspx
等を参考にさせていただきました。丸バクリ。
パラメータ等いじっておりますが、稼働上はおそらく問題ないとは思います。
試した結論としては、非力な低速環境では、体感上で厳密なものではありませんが、速くなった感じはないに等しいと思います。
画像判定+復号+変換をWICに依存し、Imageに放り込み、Texture化しております。
実際には使う場合にはTextureの表示を行う事でしょうが、実験コードという事で。
私の場合、PNGだけ対象ですが、WIC対応画像形式ならこれで表示可能と思われます。
中・高速環境ではほとんど試しておりません。
問題画像は1枚が4608*3456のRGBの背景用PNGでありまして、大きなものですと32MBにもなる超大物。可逆圧縮であるという条件からPNGを採用。
今回の実験結果から考えて、ファイルの読み込み速度の影響が最も大きいように思います。3-4秒ぐらいかかっております。
他の画像形式については、jp2とtiff以外このコードでは検証しておりません。
Siv3D対応の可逆圧縮では、PNGより小さくなるものだとjp2やwebpがあるのですが、問題画像ともなりますと、復号に大変な時間がかかります。
WICの導入は有用な場合もあるかも知れませんが、このコードで高速化の余地が無ければ私にはあまり意味がないです。
高速化目的以外ではもう少し遊べるとは思いますが、画質を落とす等の対処を検討します。
#include <wincodec.h> // Windows Imaging Component。windowscodecs.lib もリンクが必要。
HRESULT GetPixelsFromImageFileWithConversionTo32bppRGBA(LPCWSTR imageFileName)
{
IWICImagingFactory *pFactory = NULL; // ファクトリ。デコーダを生成。
IWICBitmapDecoder *pDecoder = NULL; // デコーダ。画像ファイルからのフレーム取得に使用。
IWICBitmapFrameDecode *pFrame = NULL; // フレーム。画像一枚を格納。
IWICFormatConverter *pConverter = NULL; // コンバータ。目的のフォーマットに変換。
UINT puiWidth, puiHeight;
HRESULT hr = S_OK;
if(SUCCEEDED(hr))
{
// ファクトリの生成。
hr = CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
(LPVOID*)&pFactory
);
}
if(SUCCEEDED(hr))
{
// デコーダの生成。ファイル名からデコーダを判別して生成。
hr = pFactory->CreateDecoderFromFilename(
imageFileName,
NULL,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
}
//System::Update();
if(SUCCEEDED(hr))
{
// 一枚目のフレームを取得。
hr = pDecoder->GetFrame(0, &pFrame);
}
if(SUCCEEDED(hr))
{
// コンバータの生成。ファイル名からデコーダを判別して生成。
hr = pFactory->CreateFormatConverter(&pConverter);
}
if(SUCCEEDED(hr))
{
// コンバータの初期化。
hr = pConverter->Initialize(
pFrame,
GUID_WICPixelFormat32bppRGBA, // フォーマット指定
WICBitmapDitherTypeNone, // ディザリング指定
NULL, // パレット指定
0.f, // α スレッショルド
WICBitmapPaletteTypeCustom//WICBitmapPaletteTypeMedianCut // パレットトランスレーション
);
}
if(SUCCEEDED(hr))
{
// 画像の幅、高さを取得。
hr = pConverter->GetSize(&puiWidth, &puiHeight);
}
if(SUCCEEDED(hr))
{
Image img(puiWidth, puiHeight);
// 画素を取得。
hr = pConverter->CopyPixels(NULL, (puiWidth * 4), (puiWidth * puiHeight * 4), (LPBYTE)img.data());
Texture tx(img);
if(tx) {
ScreenTexture = tx;
}
}
// ファクトリ、デコーダ、フレームの解放。
if(pFactory)
{
pFactory->Release();
}
if(pDecoder)
{
pDecoder->Release();
}
if(pFrame)
{
pFrame->Release();
}
if(pConverter)
{
pConverter->Release();
}
return hr;
}
furafura 2015/01/27(Tue) 01:08
今格闘中なのですが、そのコード、どうもメモリリーク起こす感じです。
繰り返し呼び出すと、プライベートワーキングセットが増えっぱなしになり、いずれImage内部でメモリ確保出来ずに例外が発生します。
理由は分かりませんが、imgかtxが何らかの原因で解放されないようです。
WICが絡むのか、デコーダプラグインの問題かどちらかでしょうが……。
http://homepage1.nifty.com/toro/slplugin.html
がより参考になるかも知れません。
Susieとかには興味はないのですが、利用者も多いのでより安全なコードかと考えております。
furafura 2015/01/28(Wed) 17:49
メモリリークしていた箇所、愚かなのですぐ分かりませんでした。
コンバータの初期化を行うとリークする事までは掴んでいたのですが、早い話がサンプルコード丸パクリが悪かったのです。元がpConvererの解放がされてなかったのでした。(上記コードは修正済み)
WICでのサポート画像対象をMSによるコーデック限定+カメラRAW無視とする場合、現行のSiv3Dとほぼ同等となり意味が乏しくなる可能性があります。
WICはサードパーティ製に上書きされて別のデコーダになりうるので、その辺りも考えると注意が必要なのかも知れません。
未確認ですがAMDがjpegデコードをGPUにやらせて高速化する話もあるらしく、WICは将来有用なものになるのかも知れません。