我正在将 保存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
从流中读取字节,如果读取不成功,则文件流将设置错误标志。如果您有一个大小与 png 大小完全相同的文件流,那么这种方法将会起作用,但是如果您在同一个文件中“打包”了其他任何内容(例如嵌入的资源),那么您需要计算读取了多少字节并手动限制读取的字节数,即:如果请求更多字节,则会失败。
写入方应该只写入而不是读取