2

Xscreensaver にクラウドを追加しようとしています。私は「プラズマ」雲の外観が好きなので、Xscreensaver の背景にパーリン ノイズ ベースの雲を描画しようとしています。パーリン ノイズを構成する色の値を持つ配列を作成するコードがあります。あとは、この配列から画像を作成し、この Xscreensaver の背景として設定するだけです。

この配列から画像を生成するにはどうすればよいですか? 私は純粋に Xlib を使用することを検討しましたが、それは困難な作業です。したがって、カイロを使用して配列から画像を生成する方法があれば、それは素晴らしいことです。また、配列内の値は 0 から 1 の間です。

4

2 に答える 2

1

このための Cairo 関数はcairo_image_surface_create_for_data()ですが、データを適切なレイアウトに配置して Cairo が読み取れるようにするのは、少し困難な場合があります。メモリ内の画像形式 (ここで説明)の詳細cairo.hは、マニュアルではなく、ヘッダー ファイル自体 (コメント内) にあります。

もう 1 つの問題は、行のサイズを取得するために必ず cairo_format_stride_for_width() を使用することですこれは、自分で計算できない (計算する必要がない) パディング要件がある可能性があるためです。

CAIRO_FORMAT_A8orを試してみたくなるかもしれませんCAIRO_FORMAT_A1。これは深さ 1 ビットの画像であるためです。しかし、1 ビット画像を使用CAIRO_FORMAT_RGB24して、赤、緑、青の値を 0 または 255 に設定する方が簡単であることがわかりました。A* 形式は、画像データ チャネルではなく、アルファチャネルに影響するため、それを使用するには、別のRGB データのソース。Opaque Nothingは、 Transparent Nothing と同じように見えませ。また、ビットの配置は基盤となるマシンのエンディアンに依存するため、32 ビット値を直接操作します (必要に応じて使用できますuint32_tが、printf 形式指定子がひどくなってしまうため、私はそのまま使用しますlong)。整数値全体を移動する場合、データのエンディアンは当然マシンのエンディアンを反映します。

からの関連情報は次の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;

他の回答の私のコード例は、本当に悪い例です。でも、書いたときに例が全然見つからなかったのでその通りなので、 ... ex nihilo nihil . ビッグ エンディアンであることがわかっているソース データを使用して、適切なデータ配列をパックしようとします。Egad、それは無邪気な小さな声明さえ持っています

         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幅のみ)、行幅に使用することです。

ああ、私がここで命名規則に使用しているのは、一種の逆研磨の「アプリ ハンガリー語」です。つまりimagedata、「画像 <-- データ」を意味します。datasamp「データ <-- サンプル」を意味します。

于 2013-05-01T05:49:33.257 に答える
0

古いディレクトリを調べてみるCAIRO_FORMAT_A1と、 andcairo_mask_surfaceを使用した例が見つかりました。これは、他の例よりもあなたが望むものに近いかもしれません (そして、上記の私の主張のいくつかに反しています)。で、これで完成です。このメイクファイルでコンパイル

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;
}
于 2013-05-15T06:04:42.400 に答える