【问题标题】:How to create a C-string containing binary raster-data of a ppm image如何创建包含 ppm 图像的二进制光栅数据的 C 字符串
【发布时间】:2014-10-18 14:19:33
【问题描述】:

我有一个关于 C 中字符串生成的小问题。 以下代码 sn-p 是用于生成图像(mandelbrot、渐变等)的 Python/Tkinter 应用程序的 C 扩展的一部分。在有人问之前:我不想为这么简单的任务打开 Photoshop 的电源 - 矫枉过正......

我遇到的问题是在最后一个 for 循环中的 sn-p 末尾。 此函数生成一个 PPM 图像文件以供进一步处理。主要目标是生成一个包含二进制格式栅格数据的字符串,并将该字符串传回 Python,然后传回 Tkinter 图像数据以预览结果。

目前我将文件写入磁盘非常慢。 迭代器函数返回一个指向 RGB 数组的指针。 如果我现在使用

将每个颜色值写入文件
fputc(col[0], outfile)

它有效(被淘汰的部分)。 为了更接近我的主要目标,我尝试将三个颜色值合并为一个字符串并将其写入文件中。 当我从我的 Python 应用程序运行该代码时,我最终得到一个仅包含标题的文件。

谁能指出我正确的方向?整个 C 类东西对我来说都很新 - 所以我几乎被困在这里......

static PyObject* py_mandelbrotppm(PyObject* self, PyObject* args)
{
    //get filename from argument
    char *filename;
    PyArg_ParseTuple(args, "s", &filename);
    //---------- open file for writing and create header
    FILE *outfile = NULL;
    outfile = fopen(filename, "w");

    //---------- create ppm header
    char header[17];
    sprintf(header,"P6\n%d %d\n255\n", dim_x, dim_y);
    fputs(header, outfile);
    //---------- end of header generation

    for(int y = 0;y<dim_y;y++)
    {
        for(int x = 0;x<dim_x;x++)
        {
            int *col = iterator(x,y);
            char pixel[3] = {col[0], col[1], col[2]};
            fputs(pixel, outfile);

            /*
            for(int i = 0;i<3;i++)
            {
                fputc(pixel[i], outfile);
            }
            */
        }
    }
    fclose(outfile);
    Py_RETURN_NONE;
}

【问题讨论】:

  • 我会先写一个纯 Python 版本:你可以使用 numpy 数组来操作数据(或 array.array,或手动生成二进制缓冲区),然后将它们转换为图像(枕头:@987654324 @, Image.fromstring) 并在 Tkinter (ImageTk.PhotoImage) 中显示它们。
  • 这就是我最初所做的,但图像计算在纯 python 中花费了大量时间。所以我决定使用 C 扩展,因为 C API 已经是 Python 的一部分,而且纯 C 代码非常快。这在计算图像时给了我巨大的减速...主要目标是将图像放在内存中而不是磁盘上。这就是为什么我想在点击保存按钮时使用带有栅格数据的大字符串进行进一步处理并写入磁盘...
  • 如果您的纯 Python 版本对您的需求来说速度很慢,那么您还可以询问如何加快速度,例如,在现有 Python 函数上精心放置类型声明可以使其运行速度提高 100 倍当使用Cython 编译或使用 Numba 进行编译时(您仍然需要了解 C 才能理解并有效地更改代码)。
  • 对于进程内数据交换,可以直接传递数组、图像(很容易双向转换)。
  • 我想你知道fputs() 和相当多的其他相关函数将在他们看到的第一个 0 字节处停止。例如,如果您的像素具有 0 值的 R 分量,则很有可能甚至不会写入 G 和 B 分量。这可能是……有问题的……在图像中可能经常在某处出现带有 0 字节的像素。你可能需要重新考虑你的设计,除非你能保证这永远不会发生......

标签: python c arrays string


【解决方案1】:

您的新代码存在一些问题。

pixel 缺少空终止符(及其空格)。像这样修复它:

char pixel[4] = {col[0], col[1], col[2], '\0'};

但我要告诉你一个小秘密。将一堆ints 放入chars 数组中会截断它们并做各种奇怪的、松散的事情。也许不适用于char-length 数字,但就一般风格而言,我不推荐它。考虑一下:

...
for(int x = 0;x<dim_x;x++){
     int *col = iterator(x,y);
     fprintf(outfile, "%d, %d, %d", col[0], col[1], col[2]);
}
...

另一方面,我有点困惑为什么iterator 在 RGB 值介于 0-255 之间时返回整数,而这正是 unsigned char 的范围:

unsigned char *col = iterator(x,y);
fprintf(outfile, "%u, %u, %u", col[0], col[1], col[2]);

【讨论】:

  • 好的,我明白了。但是,如果我将 'sprint()' 用于大小为 'x*y*3' 的字符串,然后写入该字符串 - 我会得到一个损坏的文件或崩溃。我正在尝试跳过文件写入......但到目前为止,这个解决方案就像一个魅力。谢谢!!!
  • @hegoe 等等,什么?如果它是 x*y*3 长,那么您将不得不使用不同的格式说明符字符串,因为 '%d, %d, %d' 的长度为 3 个整数。
  • @hegoe:它是如何工作的? ppm format 不允许在颜色样本之间使用任何分隔符(例如 ', ')。应该是fwrite(unsigned_char_pixel, 1, 3, outfile)
  • @Al.Sal 对不起,我应该更清楚地说明我想对文件使用二进制格式,它是 ppm 标准中的 P6。不知何故,这种格式在 Tkinter 上效果更好。在纯文本格式中,我遇到了一些无法重现的奇怪错误...
  • @Al.Sal:顺便说一句 - 使用我从你的回答中学到的实际代码是这样的:fprintf(outfile, "%c%c%c", col[0], col[1], col[0]);
猜你喜欢
  • 1970-01-01
  • 2020-07-03
  • 1970-01-01
  • 2016-03-23
  • 1970-01-01
  • 2019-06-18
  • 2015-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多