Я использую cairomm версии 1.12.0 с cairo версии 1.14.6.
Я пытаюсь создать ImageSurface в cairo из png, который я сохранил в памяти как вектор байтов. В большинстве случаев это работает, но иногда Cairo передает моей функции чтения (лямбда) длину для чтения (параметр длины), превышающую то, что осталось в векторе. Когда я отлаживаю это в Visual Studio, конечно, я получаю ошибочное утверждение об отладке Expression: cannot seek vector iterator after end
Cairo::RefPtr<Cairo::ImageSurface> someFunc(const std::vector<BYTE>& src)
{
Cairo::RefPtr<Cairo::ImageSurface> ret;
if (src.size() > 0)
{
unsigned int read = 0;
ret = Cairo::ImageSurface::create_from_png_stream([&src, &read](unsigned char* data, unsigned int length) {
std::copy_n(src.begin() + read, length, data);
read += length;
return CAIRO_STATUS_SUCCESS;
});
}
return ret;
}
Если я попытаюсь изменить свою функцию чтения, чтобы скопировать минимум оставшихся данных и длину, которую Cairo запросил для чтения, я получаю CAIRO_STATUS_NO_MEMORY
, что вызывает исключение std::bad_alloc
.
Cairo::RefPtr<Cairo::ImageSurface> someFunc(const std::vector<BYTE>& src)
{
Cairo::RefPtr<Cairo::ImageSurface> ret;
if (src.size() > 0)
{
unsigned int read = 0;
ret = Cairo::ImageSurface::create_from_png_stream([&src, &read](unsigned char* data, unsigned int length) {
length = std::min((unsigned int)src.size() - read, length); // added
std::copy_n(src.begin() + read, length, data);
read += length;
return CAIRO_STATUS_SUCCESS;
});
}
return ret;
}
Я думаю, это как-то связано с вызовом _cairo_output_stream_write
в stream_read_func
в cairo-png.c, поскольку он передает тот же размер, что и мою функцию чтения, поэтому, вероятно, ожидается, что там будут какие-то данные.
...
status = png_closure->read_func (png_closure->closure, data, size);
...
_cairo_output_stream_write (png_closure->png_data, data, size);
Должен ли я писать null или что-то еще, чтобы заполнить разницу в байтах?
Если cairo запрашивает больше данных, чем у вас есть, ваш PNG неисправен. Cairo запрашивает столько байтов, сколько запрашивает libpng, и, предположительно, libpng знает, что делает (tm), и запрашивает нужное количество байтов. Если у вас недостаточно байтов, вы должны вернуть CAIRO_STATUS_READ_ERROR
из функции чтения.
Спасибо. Я выгрузил png в файл, проверил его в шестнадцатеричном редакторе и обнаружил, что его окончательный блок IDAT имеет длину 8192 байта, но на самом деле он составляет всего 7725 байт. Мне придется добавить некоторую обработку ошибок и посмотреть, почему данные были потеряны ранее в конвейере.