在 libjpeg c++ 中导出 jpeg 文件时的垂直线

Vertical lines when exporting jpeg file in libjpeg c++

提问人:Uomo Succo 提问时间:10/28/2023 最后编辑:Uomo Succo 更新时间:10/29/2023 访问量:74

问:

我不明白为什么当我导出为 jpeg 时,我每 1080 像素就会得到一条垂直线。我做错了什么?

完整回购 -> https://github.com/ElPettego/swg_bg

垂直线示例 -> https://github.com/ElPettego/swg_bg/blob/master/swg_test.jpg

void export_jpg(std::vector<std::vector<int>> grid) {
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);    

    FILE* outfile = fopen("swg_test.jpg", "wb");
    if (!outfile) {
        exit(1);
    }
    
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, outfile);

    cinfo.image_width = width;
    cinfo.image_height = height;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;

    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, 100, TRUE);

    jpeg_start_compress(&cinfo, TRUE);

    while (cinfo.next_scanline < cinfo.image_height) {
        JSAMPROW row_buffer = new JSAMPLE[cinfo.image_width * 3];

        for (int x = 0; x < width; x++) {
            row_buffer[x * 3] = 0;
            row_buffer[x * 3 + 2] = 0;
            row_buffer[x * 3 + 1] =  grid[cinfo.next_scanline][x] ? 255 : 0;

        }
        jpeg_write_scanlines(&cinfo, &row_buffer, 1);
        delete[] row_buffer;
    }
    jpeg_finish_compress(&cinfo);
    fclose(outfile);
    jpeg_destroy_compress(&cinfo);
}

我尝试修改new_generation函数中for循环的边界和导出质量,但错误仍然存在(https://github.com/ElPettego/swg_bg/blob/master/main.c%2B%2B)

C++ Conways-Game-of-Life libjpeg

评论

0赞 Mark Ransom 10/28/2023
您的输入数据是否有可能具有垂直线?
0赞 PaulMcKenzie 10/28/2023
题外话,但您应该通过引用而不是按值传递:.vectorvoid export_jpg(const std::vector<std::vector<int>>& grid)
0赞 Uomo Succo 10/28/2023
我不这么认为,我一开始是随机生成的。即使随机生成存在问题,在新一代中,线条也应该消失。我认为这是 libjpeg 的问题,但我无法弄清楚它是什么。@MarkRansom
0赞 Uomo Succo 10/28/2023
好的,谢谢,我会修改它@PaulMcKenzie
1赞 PaulMcKenzie 10/28/2023
另一件事是,使用 instead 会使循环运行效率更高。声明 outside the loop,然后使用 将消除调用和不断在循环中的需要。如果有数百甚至数千条扫描线,这将大大加快速度。std::vectornew[]whilestd::vector<JSAMPLE>vector.clear();new[]delete[]

答:

2赞 Mark Ransom 10/29/2023 #1

简单的未定义行为。

但是,通过查看此处问题中的代码,您永远不会知道这一点,您需要查看存储库中未包含的代码。

看看是如何创建的:grid

    std::vector<std::vector<int>> grid(width, std::vector<int>(height, 1));

请注意,这是在定义外部向量的大小,同时定义每个内部向量的大小。widthheight

现在看看你是如何访问网格的:

    row_buffer[x * 3 + 1] =  grid[cinfo.next_scanline][x] ? 255 : 0;

第一对括号取消引用外部向量,而第二对括号取消引用内部向量。这与定义向量的方式相反。由于宽度大于高度,因此您正在访问矢量的越界元素。

P.S. 该代码中还潜伏着其他越界访问,您应该给它一次。