如何使用 GTK 绘制像素图?

问题描述

使用 GTK3,我一直在尝试从内存缓冲区中绘制像素图。我刚刚创建了一个内存缓冲区,并用 32 位 RGBA 格式的颜色交替行填充它。我一直在尝试以下功能gdk_pixbuf_new_from_data(const guchar *data,GdkColorspace colorspace,gboolean has_alpha,int bits_per_sample,int width,int height,int rowstride,GdkPixbufDestroyNotify destroy_fn,gpointer destroy_fn_data)

使用它,我已经能够将内存缓冲区包装到 GdkPixbuf* 中,但是当我尝试将 pixbuf 绘制到开罗屏幕时,图像似乎扭曲了。

这是我一直在试验的测试程序:

#include <gtk/gtk.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>

const int WIDTH = 1080;
const int HEIGHT = 720;

GtkWidget* mainWindow;

int currentCol = 0;

uint32_t* framebuffer = NULL;
GdkPixbuf* pixbuf = NULL;


typedef struct _rgbColor {
    uint8_t red;
    uint8_t green;
    uint8_t blue;
    uint8_t alpha;
}rgbColor;


void onWindowDestroy (GtkWidget* object,gpointer user_data) {
    gtk_main_quit();
}

gboolean onTimerTick(gpointer user_data) {
    rgbColor c = {0,255};
    if (currentCol == 0) {
        c.red = 255;
    }
    if (currentCol == 1) {
        c.green = 255;
    }
    if (currentCol == 2) {
        c.blue = 255;
        currentCol = -1;
    }
    currentCoL++;
    fillWithColour(framebuffer,c);

    rgbColor c1 = {0,255,255};
    filLeveryInterval(framebuffer,c1,20);
    gtk_widget_queue_draw(mainWindow);
    return 1;
}

gboolean onDraw(GtkWidget* widget,cairo_t *cr,gpointer user_data) {
    gdk_cairo_set_source_pixbuf(cr,pixbuf,0);
    cairo_paint(cr);
    return 0;
}

void fillWithColour(uint32_t* fb,rgbColor c) {
    for (int y = 0; y < HEIGHT; y++) {
        for (int x = 0; x < WIDTH; x++) {
            encodePixel(fb,c,x,y);
        }
    }
}

void filLeveryInterval(uint32_t* fb,rgbColor c,int interval) {
    for (int y = 1; y < HEIGHT; y += interval) {
        for (int x = 0; x < WIDTH; x++) {
            encodePixel(fb,y);
        }
    }
}


void encodePixel(uint32_t* fb,int x,int y) {
    uint32_t r,g,b,a;

    r = c.red;
    g = c.green << 8;
    b = c.blue << 16;
    a = c.alpha << 24;
    
    *(fb + (sizeof(uint32_t)*y+x)) = b | g | r | a;
}

int main() {
    framebuffer = malloc(sizeof(uint32_t)*WIDTH*HEIGHT);
    rgbColor c = {255,255};
    fillWithColour(framebuffer,c);


    gtk_init(NULL,NULL);
    mainWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_default_size(GTK_WINDOW(mainWindow),WIDTH,HEIGHT);
    gtk_window_set_title(GTK_WINDOW(mainWindow),"Framebuffer test");

    GtkWidget* drawingArea = gtk_drawing_area_new();

    gtk_container_add(GTK_CONTAINER(mainWindow),drawingArea);

    g_signal_connect(GTK_WINDOW(mainWindow),"destroy",(GCallback)onWindowDestroy,NULL);
    g_signal_connect(GTK_DRAWING_AREA(drawingArea),"draw",(GCallback)onDraw,NULL);

    g_timeout_add(500,onTimerTick,NULL);

    gtk_widget_show_all(GTK_WINDOW(mainWindow));
    pixbuf = gdk_pixbuf_new_from_data(framebuffer,GDK_COLORSPACE_RGB,true,8,HEIGHT,WIDTH*4,NULL,NULL);
    gtk_main();
}

我似乎无法弄清楚是什么导致了这个问题,我已经尝试过消除 alpha 通道并将 RGB 值打包为 24 位,但是我也没有成功使用该方法。我认为这可能与 rowstride 有关,但是我无法找到纠正问题的值。我在这里是在正确的轨道上,还是有更好的方法来使用 GTK 将 RGB 缓冲区绘制到屏幕上?

解决方法

您只是将像素存储在错误的位置。在 encodePixel 中,更改此行:

*(fb + (sizeof(uint32_t)*y+x)) = b | g | r | a;`

到这里

fb[WIDTH*y+x] = b | g | r | a;

顺便说一句:你应该对编译器发出的许多警告做些什么。