C# と P/Invoke を使用して GDK ライブラリにアクセスしています。私の目標は、一連の SVG ファイルをラスター イメージ (具体的には png) に変換することであり、GDK ライブラリを使用することが最も信頼性が高く正確なようです。
Gnome/Cairo のドキュメントを読んだ後、これを達成するための 2 つの基本的なアプローチを見つけました。これらのアプローチの 1 つは非推奨の関数を使用し、もう 1 つは使用しません。
最初のアプローチは推奨されていませんが、間違いなくより単純でわかりやすいもので、基本的には次のようになります。
bool result = false;
ptrPixbuf = rsvg_pixbuf_from_file_at_size(svgFilePath, width, height, out ptrError);
if (ptrError == UIntPtr.Zero && ptrPixbuf != UIntPtr.Zero)
{
bool isSaved = gdk_pixbuf_save(ptrPixbuf, outputFilePath, out ptrError, UIntPtr.Zero);
if (ptrError == UIntPtr.Zero && isSaved == true)
{
result = true;
}
}
return result;
非推奨ではない2 番目の方法では、Cairo サーフェスをセットアップしてレンダリングし、ファイルに保存します。基本的には次のようになります。
bool result = false;
ptrRsvgHandle = rsvg_handle_new_from_file(svgFilePath, out ptrError);
if (ptrError == UIntPtr.Zero)
{
ptrCairoSurface = cairo_image_surface_create(CairoFormat.CAIRO_FORMAT_ARGB32, width, height);
if ((cairo_surface_status(ptrCairoSurface) == CairoStatus.CAIRO_STATUS_SUCCESS)
{
ptrcairoContext = cairo_create(ptrCairoSurface);
if ((cairo_status(ptrCairoContext) == CairoStatus.CAIRO_STATUS_SUCCESS))
{
bool isRendered = rsvg_handle_render_cairo(ptrRsvgHandle, ptrCairoContext);
if (isRendered)
{
ptrPixbuf = rsvg_handle_get_pixbuf(ptrRsvgHandle);
if (ptrPixbuf != UIntPtr.Zero)
{
bool isSaved = gdk_pixbuf_save(ptrPixbuf, outputFilePath, out ptrError, UIntPtr.Zero);
if (ptrError == UIntPtr.Zero && isSaved == true)
{
result = true;
}
}
}
}
}
}
return result;
これらのアプローチはどちらも機能しているようです-正しいラスター画像出力を生成します(ただし、一連の操作を並行して実行しようとすると、「カイロの方法」にはいくつかのバグがあります-メモリが不足してしまいます)。
私の質問は次のとおりです。古い/非推奨の方法 ( rsvg_pixbuf_from_file_at_size
)が新しい/Cairo の方法よりも著しく速いのはなぜですか? 私のテストでは、最初のアプローチが全面的に高速であることが示されています (1 つのファイル/複数のファイル、標準の C# ForEach/Parallel.ForEach)。
たとえば、16 個の入力ファイル (出力サイズが 6000x4200) で並列処理がない場合、最初のアプローチは ~2:15.89 秒かかります。2 番目のアプローチでは、約 2:37.95 かかります。並列処理 (Parallel.Foreach が私の P/Invoke コードを呼び出します) でも、結果は似MaxDegreesOfParallelism
ています。デフォルトに設定すると、非推奨のアプローチで 30.7 秒、Cairo アプローチで 36.95 秒かかります。
Cairo もかなり多くのメモリを使用しているようです。さらに、Cairo は変換ごとにより多くのリソースを使用するだけでなく、RAM のすべてを使用しないようにする方法も知らないようです。たとえば、入力ファイルの数を (16 から) 720 に増やし、Parallel.ForEach ループを使用すると、空き RAM が 0 MB になり、システムが停止します (最終的に、デバッグ プロセスは終了します)。 、そして私のシステムは戻ってきます...しかし、それは1分ほどロックアップします)。
私の質問に対する簡単な答えは、非推奨のアプローチを使用することですが、なぜ非推奨なのですか? カイロのアプローチは、何らかの点で優れていますか?
誰かが私のコードをもっと見たい場合は、お知らせください。追加します。投稿したコードを関連するビット (実際の P/Invoke コードであり、それを呼び出す C# コードではありません) だけに切り詰めようとしました。