【发布时间】:2021-06-07 12:38:25
【问题描述】:
我正在构建一个图形引擎,我需要将结果图像写入 .bmp 文件。我将像素存储在vector<Color> 中。同时还节省了图像的宽度和高度。目前我正在编写如下图像(我自己没有编写此代码):
std::ostream &img::operator<<(std::ostream &out, EasyImage const &image) {
//temporaryily enable exceptions on output stream
enable_exceptions(out, std::ios::badbit | std::ios::failbit);
//declare some struct-vars we're going to need:
bmpfile_magic magic;
bmpfile_header file_header;
bmp_header header;
uint8_t padding[] =
{0, 0, 0, 0};
//calculate the total size of the pixel data
unsigned int line_width = image.get_width() * 3; //3 bytes per pixel
unsigned int line_padding = 0;
if (line_width % 4 != 0) {
line_padding = 4 - (line_width % 4);
}
//lines must be aligned to a multiple of 4 bytes
line_width += line_padding;
unsigned int pixel_size = image.get_height() * line_width;
//start filling the headers
magic.magic[0] = 'B';
magic.magic[1] = 'M';
file_header.file_size = to_little_endian(pixel_size + sizeof(file_header) + sizeof(header) + sizeof(magic));
file_header.bmp_offset = to_little_endian(sizeof(file_header) + sizeof(header) + sizeof(magic));
file_header.reserved_1 = 0;
file_header.reserved_2 = 0;
header.header_size = to_little_endian(sizeof(header));
header.width = to_little_endian(image.get_width());
header.height = to_little_endian(image.get_height());
header.nplanes = to_little_endian(1);
header.bits_per_pixel = to_little_endian(24);//3bytes or 24 bits per pixel
header.compress_type = 0; //no compression
header.pixel_size = pixel_size;
header.hres = to_little_endian(11811); //11811 pixels/meter or 300dpi
header.vres = to_little_endian(11811); //11811 pixels/meter or 300dpi
header.ncolors = 0; //no color palette
header.nimpcolors = 0;//no important colors
//okay that should be all the header stuff: let's write it to the stream
out.write((char *) &magic, sizeof(magic));
out.write((char *) &file_header, sizeof(file_header));
out.write((char *) &header, sizeof(header));
//okay let's write the pixels themselves:
//they are arranged left->right, bottom->top, b,g,r
// this is the main bottleneck
for (unsigned int i = 0; i < image.get_height(); i++) {
//loop over all lines
for (unsigned int j = 0; j < image.get_width(); j++) {
//loop over all pixels in a line
//we cast &color to char*. since the color fields are ordered blue,green,red they should be written automatically
//in the right order
out.write((char *) &image(j, i), 3 * sizeof(uint8_t));
}
if (line_padding > 0)
out.write((char *) padding, line_padding);
}
//okay we should be done
return out;
}
如您所见,像素被一一写入。这很慢,我在我的程序中放了一些计时器,发现写作是我的主要瓶颈。
我试图写整个(水平)行,但我没有找到如何去做(我发现最好的是this。
其次,我想使用多线程写入文件(不确定是否需要使用线程或处理)。使用 openMP。但这意味着我需要指定写入哪个字节地址,我认为这是我无法解决的。
最后,我考虑在绘制对象时立即写入文件,但后来写入文件中的特定位置时遇到了同样的问题。
所以,我的问题是:解决这个问题的最佳(最快)方法是什么。 (为 windows 和 linux 编译这个)
【问题讨论】:
-
如果您将实际内存中的图像数据视为一个字节数组,如果使用 BMP 标头信息写入磁盘,它们的顺序是否正确?然后,您可以使用单个
write调用一次性编写它。不过要小心行填充之类的东西。因为当前代码处理了这个问题,而您的内存数据可能没有它。也许改为写行? -
多线程对计算很有用,但对磁盘 I/O 没有帮助。写入文件的最快方法是按顺序写入大块,例如 4 MB。
-
当我读取生成的 .bmp 文件的二进制数据并使用 python 打印时,我得到以下信息:´x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\.....´(图像大部分是黑色的)所以我可以尝试把它全部写一遍(像 rustyx 所说的那样,以 4 MB 的块为单位,或逐行写。如何我可以逐行写吗?
-
也许最简单的方法是只保留您当前拥有的代码,而是在不影响主事件或渲染线程的后台线程中运行整个函数?如果图像未在其他任何地方使用,只需像当前一样传递引用,否则创建它的内存副本(按值传递图像对象)。除非您需要保存应该足够好的每一帧。
-
如果您真的在寻找最快的写入性能,您可能希望使用操作系统特定的 API 调用,这些调用可以绕过操作系统完成的正常缓存并直接与磁盘硬件交互(但由于内存对齐限制而增加了复杂性)。
标签: c++ multithreading io multiprocessing c++14