我将
Cairo::ImageSurface
保存为二进制文件的一部分。从 surface->get_data()
写入像素效果很好,但与我使用 surface->write_to_png(std::string name)
写入时相比,它会生成更大的文件。所以我尝试使用 surface->write_to_png_stream(const SlotWriteFunc &write_func);
和 Cairo::ImageSurface::create_from_png_stream(const SlotReadFunc &read_func)
;
最初,Cairo::Surface::SlotWriteFunc回调对我来说很有意义,它在写入表面时被调用多次,并提供参数
const unsigned char*
作为数据和unsigned int
作为长度,但是Cairo::Surface: :SlotReadFunc 让我感到困惑,因为它还提供了一个 unsigned int
来确定它想要读取多少数据。为什么不是 unsigned int&
,以便我可以根据文件判断长度?这让我得出一个结论,我也不明白SlotWriteFunc
。
请解释如何使用
SlotWriteFunc
和SlotReadFunc
。
谢谢您的帮助。
以下示例可以正常写入文件,但在我调用
create_from_png_stream
: 时抛出错误
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted
#include <fstream>
#include <iostream>
#include <cairomm/cairomm.h>
class PNGStream {
public:
std::fstream *file;
Cairo::ErrorStatus write(const unsigned char *data, unsigned int length) {
std::cout << length << std::endl;
file->write(reinterpret_cast<char *>(&length), sizeof(length));
file->write(reinterpret_cast<const char*>(data), length);
return Cairo::ErrorStatus::CAIRO_STATUS_SUCCESS;
}
Cairo::ErrorStatus read(unsigned char *data, unsigned int length) {
std::cout << length << std::endl;
// I'm not sure, what comes here
return Cairo::ErrorStatus::CAIRO_STATUS_SUCCESS;
}
};
int main() {
std::fstream file;
PNGStream png_stream;
png_stream.file = &file;
auto surface = Cairo::ImageSurface::create(Cairo::Surface::Format::ARGB32, 1920, 1080);
auto cr = Cairo::Context::create(surface);
cr->set_source_rgb(0, 0, 0);
cr->paint();
file.open("test.png", std::ios::binary | std::ios::out);
surface->write_to_png_stream(sigc::mem_fun(png_stream, &PNGStream::write));
file.close();
file.open("test.png", std::ios::binary | std::ios::in);
auto surface2 = Cairo::ImageSurface::create_from_png_stream(sigc::mem_fun(png_stream, &PNGStream::read)); //error
file.close();
return 0;
}
PNG 文件具有已知的格式,它由块组成,每个块以其长度为前缀,cairo 可以逐块读取它,直到读取失败指示文件结尾。
对于您编写的代码,您应该只从流中读取
length
字节,然后如果读取不成功,则文件流将设置错误标志,这意味着它将评估为false
。
Cairo::ErrorStatus read(unsigned char *data, unsigned int length) {
std::cout << length << std::endl;
file->read(data, length);
if (!*file) // read failed
{
return Cairo::ErrorStatus::CAIRO_STATUS_READ_ERROR;
}
Cairo::ErrorStatus::CAIRO_STATUS_SUCCESS;
}
如果您有一个大小与 png 大小完全相同的文件流,那么这将起作用,但如果您在同一个文件中“打包”了其他任何内容,那么您需要计算读取了多少字节并手动限制读取的字节。