在 GTK+-2.2 中显示 RGB 图像

发布于 2024-10-01 10:44:11 字数 2501 浏览 8 评论 0原文

我正在编写一个类,它可以获取我自己的 RGB 图像并使用 GTK+-2.2 将它们显示到窗口。我的 Image 类将图像存储为打包的 24 位 RGB 字节,因此转换应该很简单。我正在使用 gdk_draw_rgb(...) 方法绘制到我的窗口,但根本没有绘制任何内容 - 窗口仅显示为灰色。

我确实使用 Cairo 实现了这一点,不幸的是 Cairo 只能以 32bpp 格式表示图像,并且转换速度太慢。

  class ImageDisplay
  {
    public:
      ImageDisplay();
      ~ImageDisplay();

      void showImage(Image img, std::string label="");

    private:
      std::thread _gtkThread;

      std::map<std::string, GtkWidget*> _windows;
  };

// ######################################################################
void gtkThreadMethod()
{
  g_thread_init(NULL);
  gdk_threads_init();
  gdk_threads_enter();

  int argc=1;
  char **argv = new char*;
  argv[0] = new char[8];
  sprintf(argv[0], "display");
  gtk_init(&argc, &argv);

  gdk_rgb_set_verbose(TRUE);

  gtk_main();

  gdk_threads_leave();
}

// ######################################################################
ImageDisplay::ImageDisplay()
{ 
  // Start gtk in its own thread
  _gtkThread = std::thread(gtkThreadMethod);
}

// ######################################################################
ImageDisplay::~ImageDisplay()
{  
  // Tell GTK that it's time to quit
  gdk_threads_enter();
  gtk_main_quit();
  gdk_threads_leave();

  // Wait for the thread to die
  _gtkThread.join();
}

// ######################################################################
void ImageDisplay::showImage(Image img, std::string label)
{
  gdk_threads_enter();

  // Create a new window if one doesn't yet exist
  if(_windows.find(label) == _windows.end())
  {
    GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), label.c_str());
    gtk_window_set_default_size(GTK_WINDOW(window), img.dims().w(), img.dims().h());
    gtk_widget_set_app_paintable(window, TRUE);
    gtk_window_set_resizable(GTK_WINDOW(window), true);
    GdkGeometry size_hints;
    size_hints.min_aspect = 1;
    size_hints.max_aspect = 1;
    gtk_window_set_geometry_hints(GTK_WINDOW(window), window,
        &size_hints, GDK_HINT_ASPECT);
    gtk_widget_show_all(window);
    _windows[label] = window;
  }

  GtkWidget* window = _windows[label];

  GdkGC *gc = gdk_gc_new(gtk_widget_get_root_window(window));
  gdk_draw_rgb_image(
      gtk_widget_get_root_window(window),
      gc,
      0, 0,
      img.dims().w(), img.dims().h(),
      GDK_RGB_DITHER_NORMAL, 
      (const unsigned char*)img.const_begin(), 
      img.dims().w()*3);

  gdk_threads_leave();
}

I'm writing a class that can take my own RGB images and display them to windows using GTK+-2.2. My Image class stores the images as packed 24-bit RGB bytes, so the conversion should be trivial. I'm using the gdk_draw_rgb(...) method to draw to my window, but nothing gets drawn at all - the window just shows up gray.

I did get this to work using Cairo, unfortunately Cairo can only represent images in 32bpp format, and doing that conversion was just too slow.

  class ImageDisplay
  {
    public:
      ImageDisplay();
      ~ImageDisplay();

      void showImage(Image img, std::string label="");

    private:
      std::thread _gtkThread;

      std::map<std::string, GtkWidget*> _windows;
  };

// ######################################################################
void gtkThreadMethod()
{
  g_thread_init(NULL);
  gdk_threads_init();
  gdk_threads_enter();

  int argc=1;
  char **argv = new char*;
  argv[0] = new char[8];
  sprintf(argv[0], "display");
  gtk_init(&argc, &argv);

  gdk_rgb_set_verbose(TRUE);

  gtk_main();

  gdk_threads_leave();
}

// ######################################################################
ImageDisplay::ImageDisplay()
{ 
  // Start gtk in its own thread
  _gtkThread = std::thread(gtkThreadMethod);
}

// ######################################################################
ImageDisplay::~ImageDisplay()
{  
  // Tell GTK that it's time to quit
  gdk_threads_enter();
  gtk_main_quit();
  gdk_threads_leave();

  // Wait for the thread to die
  _gtkThread.join();
}

// ######################################################################
void ImageDisplay::showImage(Image img, std::string label)
{
  gdk_threads_enter();

  // Create a new window if one doesn't yet exist
  if(_windows.find(label) == _windows.end())
  {
    GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), label.c_str());
    gtk_window_set_default_size(GTK_WINDOW(window), img.dims().w(), img.dims().h());
    gtk_widget_set_app_paintable(window, TRUE);
    gtk_window_set_resizable(GTK_WINDOW(window), true);
    GdkGeometry size_hints;
    size_hints.min_aspect = 1;
    size_hints.max_aspect = 1;
    gtk_window_set_geometry_hints(GTK_WINDOW(window), window,
        &size_hints, GDK_HINT_ASPECT);
    gtk_widget_show_all(window);
    _windows[label] = window;
  }

  GtkWidget* window = _windows[label];

  GdkGC *gc = gdk_gc_new(gtk_widget_get_root_window(window));
  gdk_draw_rgb_image(
      gtk_widget_get_root_window(window),
      gc,
      0, 0,
      img.dims().w(), img.dims().h(),
      GDK_RGB_DITHER_NORMAL, 
      (const unsigned char*)img.const_begin(), 
      img.dims().w()*3);

  gdk_threads_leave();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

煮茶煮酒煮时光 2024-10-08 10:44:11
gdk_draw_rgb_image(
  gtk_widget_get_root_window(window),

这就是你的问题。在 X 术语中(GTK+ 大量借用了 X 术语),“根窗口”指的是桌面背景。您需要 gtk_widget_get_window 来获取代表您的窗口的 GdkDrawable

但是......我还没有从上面的行走得很远,我不确定这段代码的调用者是什么样子,但你通常希望绘制一个“暴露事件”处理程序,而不是立即绘制调用 gtk_window_new 后。上次我编写此类代码时(我承认已经有一段时间了),我要做的是创建一个 GdkPixmap 来绘制,然后将其内容复制到用户可见的位置GdkWindow 暴露事件。 GtkDrawingArea 小部件在这里很有帮助,所以我会搜索使用它的示例。

gdk_draw_rgb_image(
  gtk_widget_get_root_window(window),

There's your problem. In X terminology (which GTK+ borrows from heavily), the "root window" refers to the desktop background. You want gtk_widget_get_window which will get you the GdkDrawable which represents your window.

However... I haven't walked very far up the stack from the line above, and I am not sure what the caller of this code looks like, but you generally want to draw in an "expose event" handler, rather than immediately after calling gtk_window_new. The last time I was writing this kind of code (it's been a while, I'll admit), what I would do is create a GdkPixmap to draw in and then copy its contents to the user-visible GdkWindow on the expose event. The GtkDrawingArea widget is helpful here, so I would search for examples using that.

最美不过初阳 2024-10-08 10:44:11

要显示(客户端)图像,我认为您应该考虑使用 GtkImage 小部件,而不是“重载”随机小部件来进行自定义绘制。

这将依次公开 GdkPixbuf 保存像素。

To display a (client-side) image, I think you should look into using the GtkImage widget, rather than "overloading" a random widget to do custom painting.

This will in turn expose a GdkPixbuf holding the pixels.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文