使用Xlib生成Perlin噪声

时间:2013-05-01 05:43:25

标签: c image xlib screensaver perlin-noise

我正在尝试将云添加到Xscreensaver。我喜欢“等离子”云的外观,所以我试图将基于perlin噪声的云绘制到Xscreensaver的背景中。我有一些代码,它创建一个数组,其中包含构成perlin噪音的颜色值。我需要做的就是从这个数组中创建一个图像,并将其设置为此Xscreensaver中的背景。

如何从此阵列生成图像?我已经研究过使用纯Xlib,但这是一项艰巨的任务。所以,如果有一种方法可以使用Cairo从数组生成图像,这将是很好的。此外,数组中的值介于0和1之间。

2 个答案:

答案 0 :(得分:1)

开罗的功能是cairo_image_surface_create_for_data(),但是将数据放入适当的布局以供开罗阅读它可能有点令人生畏。内存中图像格式的详细信息(描述为here)位于cairo.h头文件本身(在注释中),而不是手册中。

另一个 gotcha 是:确保使用cairo_format_stride_for_width()来获取行的大小,因为可能存在您不能(不需要)计算的填充要求你自己。

尝试CAIRO_FORMAT_A8CAIRO_FORMAT_A1可能很有吸引力,因为这是一个1位深的图像;但我发现1位图像更容易使用CAIRO_FORMAT_RGB24并将红色绿色和蓝色值设置为0或255. A *格式会影响 alpha 频道,而不是图像数据通道,所以使用它,你仍然需要另一个RGB数据源。不透明没有与Transparent nothing 一样不可见。位的排列也取决于底层机器的字节顺序,因此直接使用32位值(如果需要,可以使用uint32_t,但是你的printf格式说明符会变得很残忍;所以我坚持使用{{ 1}})。如果要移动整数值,则数据的字节顺序将自然地反映机器的字节顺序。

以下是long的相关信息:

cairo.h

另一个答案中我的example code是一个非常糟糕的例子。但就是这样,因为我写这篇文章时根本找不到任何例子,所以... ex nihilo nihil 。它尝试使用已知为big-endian的源数据打包相应的数据阵列,并且可以是1位,2位,4位或8位深。 Egad,它甚至有无辜的小声明

/**
 * 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;

以递归方式调用整个解释器,这使 run(st); 机制到error机制到正确的解释器实例。这是使用longjmp的一个非常可怕的例子。但是......有人告诉我一个更好的。请!


这是一个更简单的例子。我没有对它进行测试,但我认为这是一种更简单的方法来做你需要的事情。

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表示“图像&lt; - 数据”。 imagedata表示“data&lt; - samp”。

答案 1 :(得分:0)

在旧目录中捣乱,我找到了一个使用CAIRO_FORMAT_A1cairo_mask_surface的示例,它可能比其他示例更接近您想要的内容(并且掩盖了我上面的一些断言)。这一个是完整的。使用此makefile编译

CFLAGS=-I/usr/include/cairo #-Wa,-alh
LDLIBS=-lcairo

使用make mask

/* mask.c test program for cairo bit mask
   makes a big blue turkey from the Postscript manual */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include <cairo.h>
#include <X11/Xlib.h>
#include <cairo-xlib.h>
#include <unistd.h>

enum { little, big } endian = little;

unsigned char reversebits (unsigned char b) {
    return (b & 0x01? 0x80: 0)
        |  (b & 0x02? 0x40: 0)
        |  (b & 0x04? 0x20: 0)
        |  (b & 0x08? 0x10: 0)
        |  (b & 0x10? 0x08: 0)
        |  (b & 0x20? 0x04: 0)
        |  (b & 0x40? 0x02: 0)
        |  (b & 0x80? 0x01: 0)
        ;
}

void paintmask(cairo_t *cr, unsigned char *samp, int w, int h) {
    int span; /* width in bytes */
    int stride; /* width in words */
    cairo_surface_t *mask;
    unsigned char *data;
    int i,j,k;
    uint32_t u;

    stride = cairo_format_stride_for_width(CAIRO_FORMAT_A1, w);
    /* stride = (w/32) + (w%32 ? 1 : 0) */
    span = w/8 + (w%8? 1: 0);
    printf("stride = %d\n", stride);
    data = malloc(h * stride);

    /* convert bytes to 32bit quantities matching
       endianness of the machine */
    /* each row */
    for (i = 0; i < h; i++) {

        /* each 32bit int in row */
        for (j = 0; j < stride/4; j++) {
            u = 0; /* zero the word */

            /* each 8bit byte in 32bit int from samples */
            for (k = 0; k < 4; k++) {
                uint8_t b;

                u <<= 8;

                if (j*4+k < span) {

                    /* postscript input is always big-endian */
                    /* so grab most-significant byte */
                    b = samp[i*span + j*4 + k];

                    if (endian == little) {
                        //b = samp[i*span + j*4 + (4-1-k)];
                        b = reversebits(b);
                    }

                    u |= b;
                }
                //printf("%X\n", u);
            } /* k */

            printf("%08X\n", u);
            *((uint32_t *)(data + i*stride + j)) = u;

        } /* j */
    } /* i */

    mask = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_A1, w, h, stride);
    cairo_mask_surface(cr, mask, 0, 0);
}



int main (int argc, char *argv[])
{
    int width = 480;
    int height = 460;
    Display *dis;
    int scr;
    int depth;
    Visual *vis;
    XSetWindowAttributes attr;
    unsigned long attrmask;
    Window win;
    cairo_surface_t *surface;
    cairo_t *cr;

    dis = XOpenDisplay(NULL);
    scr = DefaultScreen(dis);
    depth = DefaultDepth(dis, scr);
    vis = DefaultVisual(dis, scr);
    attr.background_pixel = WhitePixel(dis, scr);
    attr.border_pixel = BlackPixel(dis, scr);
    attr.event_mask = ExposureMask | StructureNotifyMask | ButtonPressMask;
    attrmask = CWColormap | CWBackPixel | CWBorderPixel | CWEventMask;
    win = XCreateWindow(dis, RootWindow(dis, scr),
            200, 10, //pos
            width, height, 5, //width height border
            depth,
            InputOutput,
            vis,
            attrmask, &attr);
    XMapWindow(dis, win);
    surface = cairo_xlib_surface_create(dis, win, vis, width, height);
    cr = cairo_create(surface);
    cairo_scale(cr, 10, 10);

    cairo_set_source_rgb(cr, 0, 0, 1);

    {

        unsigned char samp[] = {
            0x00, 0x3B, 0x00,
            0x00, 0x27, 0x00,
            0x00, 0x24, 0x80,
            0x0E, 0x49, 0x40,
            0x11, 0x49, 0x20,

            0x14, 0xB2, 0x20,
            0x3C, 0xB6, 0x50,
            0x75, 0xFE, 0x88,
            0x17, 0xFF, 0x8C,
            0x17, 0x5F, 0x14,

            0x1C, 0x07, 0xE2,
            0x38, 0x03, 0xC4,
            0x70, 0x31, 0x82,
            0xF8, 0xED, 0xFC,
            0xB2, 0xBB, 0xC2,

            0xBB, 0x6F, 0x84,
            0x31, 0xBF, 0xC2,
            0x18, 0xEA, 0x3C,
            0x0E, 0x3E, 0x00,
            0x07, 0xFC, 0x00,

            0x03, 0xF8, 0x00,
            0x1E, 0x18, 0x00,
            0x1F, 0xF8, 0x00 };

/*
 */

        unsigned char samp2[] = {
            0x00, 0x3B, 0x00, 0x00, 0x3B, 0x00,
            0x00, 0x27, 0x00, 0x00, 0x27, 0x00,
            0x00, 0x24, 0x80, 0x00, 0x24, 0x80,
            0x0E, 0x49, 0x40, 0x0E, 0x49, 0x40,
            0x11, 0x49, 0x20, 0x11, 0x49, 0x20,

            0x14, 0xB2, 0x20, 0x14, 0xB2, 0x20,
            0x3C, 0xB6, 0x50, 0x3C, 0xB6, 0x50,
            0x75, 0xFE, 0x88, 0x75, 0xFE, 0x88,
            0x17, 0xFF, 0x8C, 0x17, 0xFF, 0x8C,
            0x17, 0x5F, 0x14, 0x17, 0x5F, 0x14,

            0x1C, 0x07, 0xE2, 0x1C, 0x07, 0xE2,
            0x38, 0x03, 0xC4, 0x38, 0x03, 0xC4,
            0x70, 0x31, 0x82, 0x70, 0x31, 0x82,
            0xF8, 0xED, 0xFC, 0xF8, 0xED, 0xFC,
            0xB2, 0xBB, 0xC2, 0xB2, 0xBB, 0xC2,

            0xBB, 0x6F, 0x84, 0xBB, 0x6F, 0x84,
            0x31, 0xBF, 0xC2, 0x31, 0xBF, 0xC2,
            0x18, 0xEA, 0x3C, 0x18, 0xEA, 0x3C,
            0x0E, 0x3E, 0x00, 0x0E, 0x3E, 0x00,
            0x07, 0xFC, 0x00, 0x07, 0xFC, 0x00,

            0x03, 0xF8, 0x00, 0x03, 0xF8, 0x00,
            0x1E, 0x18, 0x00, 0x1E, 0x18, 0x00,
            0x1F, 0xF8, 0x00, 0x1F, 0xF8, 0x00 };

        //paintmask(cr, samp, 24, 23);
        paintmask(cr, samp2, 48, 23);
        XFlush(dis);
    }
    sleep(20);

    cairo_destroy(cr);
    cairo_surface_destroy(surface);

    return 0;
}