Я играю с некоторым кодом в проекте;в частности, функция, которая берет изображения SVG и делает из них pngs.
У меня есть это:
typedef std::vector<uint8_t> BinaryBuffer;
BinaryBuffer readFile(fs::path const& path) {
BinaryBuffer ret;
fs::ifstream f(path, std::ios::binary);
f.seekg(0, std::ios::end);
ret.resize(f.tellg());
f.seekg(0);
f.read(reinterpret_cast<char*>(ret.data()), ret.size());
if (!f) throw std::runtime_error("File cannot be read: " + path.string());
return ret;
}
void loadSVG(Bitmap& bitmap, fs::path const& filename) {
double factor = config["graphic/svg_lod"].f();
// Try to load a cached PNG instead
if (cache::loadSVG(bitmap, filename, factor)) return;
std::clog << "image/debug: Loading SVG: " + filename.string() << std::endl;
// Open the SVG file in librsvg
#if !GLIB_CHECK_VERSION(2, 36, 0) // Avoid deprecation warnings
g_type_init();
#endif
GError* pError = nullptr;
std::shared_ptr<RsvgHandle> svgHandle(rsvg_handle_new_with_flags(RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA), g_object_unref);
rsvg_handle_set_base_uri(svgHandle.get(),filename.string().c_str());
BinaryBuffer data = readFile(filename);
std::clog << "svg/debug: svg data size is: " << data.size() << std::endl;
gboolean result = rsvg_handle_write(svgHandle.get(), data.data(), data.size(), &pError);
// rsvg_handle_new_from_file(filename.string().c_str(), &pError)
if (result != TRUE) {
g_error_free(pError);
throw std::runtime_error("Unable to load " + filename.string());
}
else {
std::clog << "svg/debug: SVG loaded succesfully." << std::endl;
}
// Get SVG dimensions
RsvgDimensionData svgDimension;
rsvg_handle_get_dimensions(svgHandle.get(), &svgDimension);
// Prepare the pixel buffer
std::clog << "svg/debug: svg width is: " << svgDimension.width << ", and height: " << svgDimension.height << std::endl;
bitmap.resize(svgDimension.width*factor, svgDimension.height*factor);
bitmap.fmt = pix::INT_ARGB;
bitmap.linearPremul = true;
// Raster with Cairo
std::shared_ptr<cairo_surface_t> surface(
cairo_image_surface_create_for_data(&bitmap.buf[0], CAIRO_FORMAT_ARGB32, bitmap.width, bitmap.height, bitmap.width * 4),
cairo_surface_destroy);
std::shared_ptr<cairo_t> dc(cairo_create(surface.get()), cairo_destroy);
cairo_scale(dc.get(), factor, factor);
gboolean renderRes = TRUE;
renderRes = rsvg_handle_render_cairo(svgHandle.get(), dc.get());
if (renderRes != TRUE) {
throw std::runtime_error("Unable to render " + filename.string());
}
// Change byte order from BGRA to RGBA
for (uint32_t *ptr = reinterpret_cast<uint32_t*>(&*bitmap.buf.begin()), *end = ptr + bitmap.buf.size() / 4; ptr < end; ++ptr) {
uint8_t* pixel = reinterpret_cast<uint8_t*>(ptr);
uint8_t r = pixel[2], g = pixel[1], b = pixel[0], a = pixel[3];
pixel[0] = r; pixel[1] = g; pixel[2] = b; pixel[3] = a;
}
bitmap.fmt = pix::CHAR_RGBA;
// Write to cache so that it can be loaded faster the next time
fs::path cache_filename = cache::constructSVGCacheFileName(filename, factor);
fs::create_directories(cache_filename.parent_path());
writePNG(cache_filename, bitmap);
}
Но это терпит неудачу в rsvg_handle_render_cairo
... Я не знаю почему.Предыдущая версия функции с использованием rsvg_handle_new_from_file (которая не использует структуру BinaryBuffer) работала нормально.Обратите внимание, что, по сути, одна и та же функция struct и readFile используется в другом месте без каких-либо проблем.И из отладочных сообщений, которые я туда зашёл, я вижу, что файл действительно читается.Я также получаю правильные размеры из моего файла SVG, и, кажется, нет никаких ошибок до вызова функции рендеринга (так что я бы предположил, что он проанализирован нормально), но, возможно, нет?