为什么弃用的“rsvg_pixbuf_from_file_at_size”比未弃用的方法(开罗)更快/更有效?

时间:2013-11-27 20:25:59

标签: pinvoke cairo parallel.foreach librsvg gdkpixbuf

我正在使用C#和P / Invoke来访问GDK库。我的目标是将一组SVG文件转换为光栅图像(特别是png),并且使用GDK库似乎是最可靠/最准确的。

在阅读了Gnome / Cairo文档之后,我找到了两种基本方法来实现这一目标。其中一种方法使用已弃用的函数,另一种则不使用。

The first approach,已被弃用,但可以说更简单/更直接,看起来基本上是这样的:

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;

第二种方法,已弃用,涉及设置开罗表面,渲染它,然后将其保存到文件中。看起来基本上是这样的:

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;

这两种方法似乎都有效 - 它们会生成正确的光栅图像输出(但是,当我尝试并行执行大量操作时,“开罗方式”会有一些错误 - 我最终耗尽内存)。 / p>

我的问题是:为什么旧的/弃用的方式(rsvg_pixbuf_from_file_at_size比新的/开罗的方式明显更快?我的测试显示第一种方法更快(一个文件/多个文件,标准C#ForEach / Parallel.ForEach)。

例如,对于16个输入文件(输出尺寸为6000x4200)并且没有并行处理,第一种方法需要~2:15.89秒。第二种方法需要大约2:37.95。使用并行处理(Parallel.Foreach调用我的P / Invoke代码),结果是相似的 - 将MaxDegreesOfParallelism设置为默认值,使用不推荐的方法需要30.7秒,使用Cairo方法需要36.95秒。

开罗似乎也使用了更多的记忆。此外,除了为每次转换使用更多资源外,Cairo似乎也不知道如何避免使用我的RAM的所有。例如,如果我将输入文件的数量增加到720(从16),并使用Parallel.ForEach循环,我最终得到0 MB的空闲RAM,并且系统停止运行(最终,调试进程退出,我的系统又回来了......但它会锁定一分钟左右。)

我的问题的简单答案就是使用弃用的方法,但为什么不推荐使用?开罗方法在任何方面都有所改善吗?

如果有人想查看我的更多代码,请告诉我,我会添加它。我试图将我发布的代码减少到相关位(实际的P / Invoke代码,而不是调用它的C#代码)。

1 个答案:

答案 0 :(得分:1)

首先,由于您的代码存在内存泄漏,可能会发生内存不足错误。您的示例不会调用任何清理函数(如cairo_destroy(),cairo_surface_destroy(),gdk_pixbuf_unref(),g_object_unref(),可能会发生任何发生的GError)。

其次,你的第二个代码实际绘制了什么? 你创建了一个cairo表面和上下文,有rsvg绘制它,但是然后调用rsvg_handle_get_pixbuf(),它在内部创建一个新的cairo表面并再次绘制所有内容。 换句话说,你应该调用rsvg_handle_new_from_file(),rsvg_handle_get_pixbuf()和gdk_pixbuf_save()吗?