我正在尝试将云添加到 Xscreensaver。我喜欢“等 ionic ”云的外观,所以我试图在 Xscreensaver 的背景上绘制一个基于 perlin 噪声的云。我有创建一个数组的代码,该数组具有构成柏林噪声的颜色值。我所需要做的就是从该数组创建一个图像并将其设置为该 Xscreensaver 中的背景。
如何从这个数组生成图像?我研究过使用纯 Xlib,但这是一项艰巨的任务。因此,如果有一种方法可以使用 Cairo 从数组中生成图像,那就太好了。此外,数组中的值介于 0 和 1 之间。
最佳答案
Cairo 函数是 cairo_image_surface_create_for_data() , 但将数据放入适当的布局中以供 Cairo 读取可能有点令人生畏。内存图像格式的详细信息(描述 here )在 cairo.h
头文件本身(在注释中),而不是手册。
另一个陷阱是:确保使用cairo_format_stride_for_width()获取行的大小,因为可能存在您无法(不需要)自己计算的填充要求。
尝试 CAIRO_FORMAT_A8
或 CAIRO_FORMAT_A1
可能很诱人,因为这是一个 1 位深的图像;但我发现 1 位图像更容易使用 CAIRO_FORMAT_RGB24
并将红绿蓝值设置为 0 或 255。A* 格式影响 alpha channel ,而不是图像数据通道,因此使用它时,您仍然需要另一个 RGB 数据源。不透明 nothing 与透明 nothing 一样不可见。此外,位的排列取决于底层机器的字节顺序,因此直接使用 32 位值(如果你愿意,你可以使用 uint32_t
,但是你的 printf 格式说明符会变得很糟糕;所以我坚持使用 long
)。如果您要移动整个整数值,那么数据的字节序自然会反射(reflect)机器的字节序。
这是来自 cairo.h
的相关信息:
/**
* cairo_format_t:
* @CAIRO_FORMAT_INVALID: no such format exists or is supported.
* @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with
* alpha in the upper 8 bits, then red, then green, then blue.
* The 32-bit quantities are stored native-endian. Pre-multiplied
* alpha is used. (That is, 50% transparent red is 0x80800000,
* not 0x80ff0000.) (Since 1.0)
* @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with
* the upper 8 bits unused. Red, Green, and Blue are stored
* in the remaining 24 bits in that order. (Since 1.0)
* @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding
* an alpha value. (Since 1.0)
* @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding
* an alpha value. Pixels are packed together into 32-bit
* quantities. The ordering of the bits matches the
* endianess of the platform. On a big-endian machine, the
* first pixel is in the uppermost bit, on a little-endian
* machine the first pixel is in the least-significant bit. (Since 1.0)
* @CAIRO_FORMAT_RGB16_565: each pixel is a 16-bit quantity
* with red in the upper 5 bits, then green in the middle
* 6 bits, and blue in the lower 5 bits. (Since 1.2)
* @CAIRO_FORMAT_RGB30: like RGB24 but with 10bpc. (Since 1.12)
*
* #cairo_format_t is used to identify the memory format of
* image data.
*
* New entries may be added in future versions.
*
* Since: 1.0
**/
typedef enum _cairo_format {
CAIRO_FORMAT_INVALID = -1,
CAIRO_FORMAT_ARGB32 = 0,
CAIRO_FORMAT_RGB24 = 1,
CAIRO_FORMAT_A8 = 2,
CAIRO_FORMAT_A1 = 3,
CAIRO_FORMAT_RGB16_565 = 4,
CAIRO_FORMAT_RGB30 = 5
} cairo_format_t;
我的 example code在另一个答案中是一个非常糟糕的例子。但就是这样,因为我写的时候根本找不到任何例子,所以... ex nihilo nihil。它尝试使用已知为大端字节序的源数据来打包适当的数据数组,并且可能是 1 位、2 位、4 位或 8 位深。哎呀,它甚至还有无辜的小声明
run(st);
它递归地调用整个解释器,这对于将 longjmp
的 error
机制获取到解释器的正确 实例来说是 hell 。这是一个使用 cairo_image_surface_create_for_data()
的非常糟糕的例子。但是...有人给我看一个更好的。请!
这是一个更简单的示例的说明。我还没有测试过它,但我认为这是一种更简单的方法来满足您的需求。
#include <stdint.h> /* uint32_t */
uint32_t datasamp(double d) { // convert floating point to rgb-byte-field integer
uint32_t u;
u = d * 255; // [0.0 .. 1.0] -> [0 .. 255]
return u<<16 | u<<8 | u; // r = g = b = u 0x00rrggbb
}
// samp is a 2D double array
// double samp[hgt][wid];
uint32_t *imagedata(int wid, int hgt, double *samp){
int stride;
uint32_t *data;
int i,j;
stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, wid);
data = malloc(stride*hgt*sizeof(uint32_t)); //use stride instead of width
for (i=0; i < hgt; i++) {
for (j=0; j < wid; j++) {
data[i*stride + j] = // use stride for data row width
datasamp(samp[i*wid + j]); // use wid as normal for source array
}
}
return data;
}
返回的数据将适合传递给 cairo_image_surface_create_for_data
。重要的是使用 stride
作为行宽,即使源数据的排列方式不同(这里只有 wid
宽)。
哦,这是一种反向抛光的“应用程序匈牙利语”,我在这里将其用于命名约定。所以 imagedata
表示“图像 <-- 数据”。 datasamp
表示“数据 <-- samp”。
关于c - 使用 Xlib 生成 Perlin 噪声,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16313336/