rsvg_handle_new_from_gfile_sync always returns NULL on windows
For a while now I have been successfully converting SVG files to PDF using C++ code like this:
namespace fs = std::filesystem;
void ConvertSvgToPdf(const fs::path &svgPath, const fs::path &pdfPath)
{
auto rsvgHandle = rsvg_handle_new();
auto destroyRsvgHandle = gsl::finally([&rsvgHandle]()
{
GError *rsvgError = nullptr;
rsvg_handle_close(rsvgHandle, &rsvgError);
if (rsvgError)
g_error_free(rsvgError);
});
auto svgData = ReadFile(svgPath);
rsvg_handle_set_base_uri(rsvgHandle, svgPath.string().c_str());
GError *rsvgHandleWriteError = nullptr;
auto rsvgHandleResult = rsvg_handle_write(rsvgHandle, svgData.data(), svgData.size(), &rsvgHandleWriteError);
if (rsvgHandleResult != TRUE)
{
throw ImportError("Could not open SVG file");
}
if (rsvgHandleWriteError)
{
Logging::Get("svg")->error("Could not open SVG file: {}", rsvgHandleWriteError->message);
g_error_free(rsvgHandleWriteError);
throw ImportError("Could not open SVG file");
}
GError *rsvgHandleCloseError = nullptr;
auto rsvgHandleCloseResult = rsvg_handle_close(rsvgHandle, &rsvgHandleCloseError);
if (rsvgHandleCloseResult != TRUE)
{
throw ImportError("Could not close SVG file");
}
if (rsvgHandleCloseError)
{
Logging::Get("svg")->error("Could not close SVG file: {}", rsvgHandleCloseError->message);
g_error_free(rsvgHandleCloseError);
throw ImportError("Could not open SVG file");
}
RsvgDimensionData rsvgDimensions;
rsvg_handle_get_dimensions(rsvgHandle, &rsvgDimensions);
const auto width = rsvgDimensions.width;
const auto height = rsvgDimensions.height;
auto surface = cairo_pdf_surface_create(pdfPath.string().c_str(), width, height);
auto destroySurface = gsl::finally([&surface]() {cairo_surface_destroy(surface); });
auto cairo = cairo_create(surface);
auto destroyCairo = gsl::finally([&cairo]() {cairo_destroy(cairo); });
auto status = cairo_status(cairo);
auto renderResult = rsvg_handle_render_cairo(rsvgHandle, cairo);
status = cairo_status(cairo);
if (renderResult != TRUE || status)
throw ImportError(fmt::format("Could not translate SVG file to PDF. Status = {}", cairo_status_to_string(status)));
}
However, I have recently needed to start supporting SVG files with embedded base64-encoded images such as test.svg. The above code discards all of the embedded image data from that file.
I think -- but I am not sure -- that this is because I need to specify the RSVG_HANDLE_FLAG_UNLIMITED and/or the RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA flags. That option is not available to me if I use rsvg_handle_new. To accommodate that requirement, I have switched to using rsvg_handle_new_from_gfile_sync like this:
void ConvertSvgToPdf(const fs::path &svgPath, const fs::path &pdfPath)
{
std::string svgPathString = svgPath.string();
const char *svgPathPointer = svgPathString.c_str();
GFile *file = g_file_new_for_path(svgPathPointer);
// Just to see if the GFile is usable and points to a real file.
GError *queryInfoError = NULL;
auto queryInfo = g_file_query_info(file, "*", G_FILE_QUERY_INFO_NONE, NULL, &queryInfoError);
if (queryInfoError)
{
Logging::Get("svg")->error("Could not query file info: {}", queryInfoError->message);
}
GError *rsvgHandleNewError = NULL;
RsvgHandle *rsvgHandle = rsvg_handle_new_from_gfile_sync(
file,
(RsvgHandleFlags)(RSVG_HANDLE_FLAG_UNLIMITED | RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA),
NULL,
&rsvgHandleNewError);
if (!rsvgHandle)
{
if (rsvgHandleNewError)
{
Logging::Get("svg")->error("Could not open SVG file: {}", rsvgHandleNewError->message);
g_error_free(rsvgHandleNewError);
throw ImportError("Could not open SVG file");
}
else
{
Logging::Get("svg")->error("Could not open SVG file; reason unknown");
throw ImportError("Could not open SVG file");
}
}
// the rest the same as in the previous example
On a PC running Ubuntu 21.10 where I compiled this code using gcc11, this code works.
But on a Windows PC, where I compiled this code using Visual Studio 2022, linked to librsvg built using the gvsbuild project, rsvg_handle_new_from_gfile_sync always returns NULL, and the GError output parameter is also NULL. So I don't have much to work with to determine the cause of the problem.
From a debugger, if I step into the (Rust) implementation of rsvg_handle_new_from_gfile_sync, it appears to be returning immediately because of the is_gfile() check in the rsvg_return_val_if_fail! macro. This despite the fact that a previous call to g_file_query_info with the same GFile pointer worked just fine.
I assume there is something simple that I'm missing. I have been following the example from https://www.manpagez.com/html/rsvg-2.0/rsvg-2.0-2.52.1/ch01s03.php. Are there any better examples that would show me what I am doing wrong?