Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从gtk窗口在draw调用时缩放cairo上下文花费的时间太长_C_Gtk_Cairo - Fatal编程技术网

从gtk窗口在draw调用时缩放cairo上下文花费的时间太长

从gtk窗口在draw调用时缩放cairo上下文花费的时间太长,c,gtk,cairo,C,Gtk,Cairo,我一直在开发gtk+/cairo应用程序,在这个应用程序中,我需要在绘图区域上显示一个图像,并在上面绘制一些文本和线条。我已经制作了将所有必要的图形绘制到cairo上下文中的函数,但是图像需要缩放以适应绘图区域(也为了避免更改窗口大小时出现缩放问题)。我计划只使用cairo_scale函数来完成此操作,但此选项似乎相当缓慢 以下是我目前如何扩展开罗环境: *** typedef struct diagram_properties_{ cairo_surface_t * surface;

我一直在开发gtk+/cairo应用程序,在这个应用程序中,我需要在绘图区域上显示一个图像,并在上面绘制一些文本和线条。我已经制作了将所有必要的图形绘制到cairo上下文中的函数,但是图像需要缩放以适应绘图区域(也为了避免更改窗口大小时出现缩放问题)。我计划只使用cairo_scale函数来完成此操作,但此选项似乎相当缓慢

以下是我目前如何扩展开罗环境:

***
typedef struct diagram_properties_{
    cairo_surface_t * surface;
    d_tank_ tanks[DIAGRAM_TANK_COUNT];
    d_valve_ valves[DIAGRAM_VALVE_COUNT];
    d_info_ infos[DIAGRAM_INFO_COUNT];
    int last_error_;
    double width, height;
    bool is_saved;
    GtkDrawingArea * drawing_area;
}diagram_properties_;
***
gboolean on_draw_diagram_event(GtkWidget *widget, cairo_t *cr, gpointer user_data){
    //Initialize diagram (d_properties)
    draw_diagram(cr, &d_properties);
    return FALSE;
}
***
void draw_diagram( cairo_t *cr, diagram_properties_ *diagram ){

    GtkWidget * da_widget = GTK_WIDGET(diagram->drawing_area);
    gtk_widget_queue_draw(da_widget);
    GtkAllocation allocation;
    gtk_widget_get_allocation(da_widget, &allocation);
    diagram->width = cairo_image_surface_get_width(diagram->surface);
    diagram->height = cairo_image_surface_get_height(diagram->surface);
    cairo_scale(cr, allocation.width / diagram->width, allocation.height /     diagram->height);
    cairo_set_source_surface(cr, diagram->surface, 0, 0);
    cairo_paint(cr);
    update_diagram_tanks( cr, diagram );
    update_diagram_valves( cr, diagram );
    update_diagram_info( cr, diagram );
}
***

带有图表的PNG文件用于在代码开头创建图表表面。所以我的问题是,有没有一种方法可以将cairo上下文保存在缓冲区中,并且只在窗口的维度发生变化时对其进行缩放?我已经在尝试缩放曲面本身,以及图形和文本的坐标,但如果有更好的方法,我宁愿避免这样做

您可以结合使用
cairo\u push\u group()
cairo\u get\u group\u target()
cairo\u pop\u group\u to\u source()
+
cairo\u paint()
来绘制缩放内容

伪代码:

static cairo_surface_t *cache_surface = NULL;
static double cache_width = -1, cache_height = -1;

// s must be an image surface and it must always be the same image surface (= content must not change)
void draw_at_size(cairo_t *cr, cairo_surface_t *s, double width, double height)
{
  double diagram_width = cairo_image_surface_get_width(s);
  double diagram_height = cairo_image_surface_get_height(s);
  cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
  if (width == cache_width && height == cache_height) {
    cairo_set_source_surface(cr, cache_surface, 0, 0);
    cairo_paint(cr);
  } else {
    cairo_push_group(cr);
    cairo_scale(cr, width / diagram_width, height / diagram_height);
    cairo_set_source_surface(cr, surface, 0, 0);
    cairo_paint(cr);

    cairo_surface_destroy(cache_surface);
    cache_surface = cairo_reference(cairo_get_group_target(cr));
    cache_width = width;
    cache_height = height;

    cairo_pop_group_to_source(cr);
    cairo_paint(cr);
  }
}
不知道这是否真的更快,但这意味着曲面只缩放一次。当然,您也可以通过在缩放曲面上绘制其他内容来扩展此功能


但是,这与您自己分配另一个曲面基本相同。唯一的区别是曲面分配是隐藏的,您可能会得到一个“更好”的曲面,例如,我猜您当前正在为临时曲面分配一个图像曲面,但cairo将在X11上使用X11曲面。

您可以结合使用
cairo\u push\u group()
cairo\u get\u group\u target()
cairo\u pop\u group\u to\u source()
+
cairo\u paint()
绘制缩放内容

伪代码:

static cairo_surface_t *cache_surface = NULL;
static double cache_width = -1, cache_height = -1;

// s must be an image surface and it must always be the same image surface (= content must not change)
void draw_at_size(cairo_t *cr, cairo_surface_t *s, double width, double height)
{
  double diagram_width = cairo_image_surface_get_width(s);
  double diagram_height = cairo_image_surface_get_height(s);
  cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
  if (width == cache_width && height == cache_height) {
    cairo_set_source_surface(cr, cache_surface, 0, 0);
    cairo_paint(cr);
  } else {
    cairo_push_group(cr);
    cairo_scale(cr, width / diagram_width, height / diagram_height);
    cairo_set_source_surface(cr, surface, 0, 0);
    cairo_paint(cr);

    cairo_surface_destroy(cache_surface);
    cache_surface = cairo_reference(cairo_get_group_target(cr));
    cache_width = width;
    cache_height = height;

    cairo_pop_group_to_source(cr);
    cairo_paint(cr);
  }
}
不知道这是否真的更快,但这意味着曲面只缩放一次。当然,您也可以通过在缩放曲面上绘制其他内容来扩展此功能


但是,这与您自己分配另一个曲面基本相同。唯一的区别是表面分配是隐藏的,您可能会得到一个“更好”的表面,例如,我猜您当前正在为临时表面分配一个图像表面,但cairo会在X11上使用X11表面。

我想我知道您在尝试做什么(我应该提到我在cairo方面只有大约3天的经验),但当我尝试这样做时,我得到一个断言“CAIRO\u REFERENCE\u COUNT\u HAS\u REFERENCE(&cr->ref\u COUNT)”失败。错误(我将行
cache\u surface=CAIRO\u REFERENCE(CAIRO\u get\u group\u target(cr))
更改为
cache\u surface=CAIRO\u get\u目标(CAIRO\u group\u target(cr)))
,再次尝试,但也没有成功),但今天晚些时候我将研究
cairo\u push\u group()、cairo\u get\u group\u target()
。我明天会发布更新(希望如此)。谢谢,顺便说一句!哎呀,对不起。它应该是
cairo\u surface\u reference
而不是
cairo\u reference
。编译器应该警告从
cairo\u-surface\u-t*
cairo\u-t*
的强制转换。该警告在这里是一个严重问题,并导致崩溃。因此,该行应该是
cairo\u surface\u reference(cairo\u get\u group\u target(cr))
。再次感谢您的回复!,我刚刚在一个函数中加入了绘图调用,该函数由一个g_timeout_add调用每秒执行10次,对于这个应用程序来说已经足够好了。不过,如果您不介意的话,我将在下一版本的应用程序上尝试您的解决方案,因此感谢您的帮助,很抱歉,在我再次看到此代码之前,我没有机会尝试它:这可能会泄漏表面
cache\u surface
在被覆盖之前应该不被引用(是的,
cairo\u surface\u destroy(NULL)
是安全的)。我想我知道你想做什么(我应该提到我只有3天的cairo经验),但当我尝试这样做时,我得到了一个
断言“cairo\u REFERENCE\u COUNT\u have\u REFERENCE”(&cr->ref_count)失败。
错误(我将行
缓存_surface=cairo_引用(cairo_get_group_target(cr));
更改为
缓存_surface=cairo_get_target(cairo_reference(cairo_get_group_target(cr));
,再次尝试,它也不起作用),但我将查看
cairo_推送_group(),cairo_get_group_target()
今天晚些时候。我将发布更新(希望如此)明天。谢谢。哎呀,对不起。应该是
cairo\u surface\u reference
而不是
cairo\u reference
。编译器应该警告从
cairo\u surface\u t*
转换到
cairo\u t*
。这个警告在这里是一个严重的问题,会导致崩溃。所以这行应该是
cairo\u surface\u reference(开罗获得集团目标(cr))
。再次感谢您的回复!我刚刚在一个函数中加入了绘图调用,该函数由g_timeout_add调用每秒执行10次,对于这个应用程序来说已经足够好了。但是,如果您不介意的话,我将在下一版本的应用程序上尝试您的解决方案,因此感谢您的帮助,很抱歉我没有机会尝试请在我再次看到此代码之前尝试一下:这可能会泄漏表面。
cache\u surface
应该在覆盖它之前取消引用(是的,
cairo\u surface\u destroy(NULL)
是安全的)。