我如何使用 GTK 绘制像素图?
How do I draw a Pixmap with 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 绘制到 Cairo 屏幕时,图像似乎失真了。
这是我一直在试验的测试程序:
#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, 0, 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, 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, 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, c, x, y);
}
}
}
void encodePixel(uint32_t* fb, rgbColor c, 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, 0, 0, 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, WIDTH, 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;
旁注:你应该对编译器发出的许多警告采取一些措施。
我一直在尝试使用 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 绘制到 Cairo 屏幕时,图像似乎失真了。
这是我一直在试验的测试程序:
#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, 0, 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, 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, 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, c, x, y);
}
}
}
void encodePixel(uint32_t* fb, rgbColor c, 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, 0, 0, 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, WIDTH, 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;
旁注:你应该对编译器发出的许多警告采取一些措施。