前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux C编程——为eog image viewer增加坐标和像素颜色显示功能

Linux C编程——为eog image viewer增加坐标和像素颜色显示功能

原创
作者头像
ExASIC
修改2020-07-15 14:37:07
1.4K0
修改2020-07-15 14:37:07
举报
文章被收录于专栏:ExASICExASIC

好用的看图工具对做图片相关的算法验证很有帮助。但常常工具并没有我们需要的功能。今天我就分享一个工作中遇到的例子。

eog(eye of gnome)是gnome桌面下常用的看图工具,放大时可以禁用插值平滑算法,眼睛看到的更为真实。但eog缺少一个功能,鼠标在图片上移动时希望在状态栏能够显示以下的信息:

1.    显示鼠标当前位置在图片中的行列值, 2.    显示鼠标所处像素的RGB颜色值。

第一步:下载源码:

ftp://ftp.gnome.org/mirror/gnome.org/desktop/2.28/2.28.2/sources/eog-2.28.2.tar.gz

第二步:研究分析源码,确定修改方案

我们主要修改两个地方:

  • 修改响应鼠标事件的函数:
    • 获取鼠标相对于eog图片显示窗口的坐标。
    • 根据图片的长宽、放大倍数、图片第一个点的偏移量等计算鼠标所处的行、列值。
    • 根据行、列值从GdkPixbuf里取当前像素。
    • 把行、列、红、绿、蓝分别保存到scroll_view中。
    • 发送更新状态栏的消息。
  • 修改更新状态栏的函数:
    • 从scroll_view中获得行、列、红、绿、蓝等信息。
    • 显示到状态栏。

第三步:修改源码

  1. 定义全局变量
代码语言:txt
复制
struct_EogScrollViewPrivate {
      //…
      int row, col;  //在scroll_view里增加全局变量,用来保存信息
      int r, g, b;
}
  1. 修改鼠标响应事件函数
代码语言:txt
复制
static gboolean

eog_scroll_view_motion_event (GtkWidget _widget, GdkEventMotion_ event, gpointer data)
{
      EogScrollView *view;
      EogScrollViewPrivate *priv;
      gintx, y;
      GdkModifierTypemods;

  //增加定义局部变量

      int scaled_width, scaled_height;
      int width, height;
      int ximage, yimage;
      int wimage, himage;
      int row, col;
      int r, g, b;
      row= 0;
      col= 0;
      r= 0;
      g= 0;
      b= 0;
      ximage= 0;
      yimage= 0;
      wimage= 0;
      himage= 0;

      view= EOG_SCROLL_VIEW (data);
      priv= view->priv;

      //获得鼠标在图片显示窗口中的坐标
      if(event->is_hint)
        gdk_window_get_pointer (GTK_WIDGET(priv->display)->window, &x, &y, &mods);
      else{
        x = event->x;
        y = event->y;
      }

      //非拖拽事件,即鼠标移动事件
      if(!priv->dragging){
        //计算图片缩放后的大小,单位像素
        compute_scaled_size (view, priv->zoom,&scaled_width, &scaled_height);

        //当前图片窗口的大小
        width = GTK_WIDGET(priv->display)->allocation.width;
        height = GTK_WIDGET(priv->display)->allocation.height;

        //图像本身的像素大小
        himage = gdk_pixbuf_get_height(priv->pixbuf);
        wimage = gdk_pixbuf_get_width(priv->pixbuf);

        //如果缩放后小于显示窗口,
        if(scaled_width < width &&scaled_height < height)
        {
          //图片左上角的坐标
          yimage = (height - scaled_height) / 2;
          ximage = (width - scaled_width) / 2;

          //计算鼠标位置的行和列
          row = (y - yimage) / priv->zoom;
          col = (x - ximage) / priv->zoom;

          //如果鼠标不在图片范围内,则显示0行0列
          if(y < yimage || y > (yimage +scaled_height) ||
             x < ximage || x > (ximage +scaled_width))
          {
            row = 0;
            col = 0;
          }
        }

        //水平缩放不超过显示窗口,但垂直缩放超过了显示窗口
        else if(scaled_width < width)
        {
          ximage = (width - scaled_width) / 2;
          yimage = 0 - priv->yofs;
          row = (y - yimage) / priv->zoom;
          col = (x - ximage) / priv->zoom;

          if(x < ximage || x >= (ximage +scaled_width))
          {
            row = 0;
            col = 0;
          }
        }

        //水平缩放超过显示窗口,垂直缩放不超过显示窗口

        else if(scaled_height < height)
        {
          yimage = (height - scaled_height) / 2;
          ximage = 0 - priv->xofs;
          row = (y - yimage) / priv->zoom;
          col = (x - ximage) / priv->zoom;
          if(y < yimage || y >= (yimage +scaled_height))
          {
            row = 0;
            col = 0;
          }
        }

       //水平和垂直缩放都超过显示窗口
        else
        {
          row = (y + priv->yofs) / priv->zoom;
          col = (x + priv->xofs) / priv->zoom;
        }      

        //获取图片像素指针:pixbuf
        if (row >=0 && row < himage&&
            col >=0 && col < wimage&&
            gdk_pixbuf_get_colorspace(priv->pixbuf) == GDK_COLORSPACE_RGB &&
            !gdk_pixbuf_get_has_alpha(priv->pixbuf) &&
            gdk_pixbuf_get_bits_per_sample(priv->pixbuf) == 8)
        {
          guchar *pixels;
          int rowstride, n_channels;
          rowstride = gdk_pixbuf_get_rowstride(priv->pixbuf);
          n_channels = gdk_pixbuf_get_n_channels(priv->pixbuf);

          //获取第row行col列的像素值
          pixels = (gdk_pixbuf_get_pixels(priv->pixbuf)
                 + row * rowstride
                 + col * n_channels);

          //获取r,g,b值
          r = pixels0;
          g = pixels1;
          b = pixels2;
        }

        if(scaled_width < width &&scaled_height < height)
        {
          //clear if the pointer is out of range
          if(y < yimage || y > (yimage +scaled_height) ||
             x < ximage || x > (ximage +scaled_width))
          {
            r = 0;
            g = 0;
            b = 0;
          }
        }

        else if(scaled_width < width)
        {
          if(x < ximage || x >= (ximage +scaled_width))
          {
            r = 0;
            g = 0;
            b = 0;
          }
        }

        else if(scaled_height < height)
        {
          if(y < yimage || y >= (yimage +scaled_height))
          {
            r = 0;
            g = 0;
            b = 0;
          }
        }

      //保存到scroll_view的全局变量里
      view->priv= row;
      view->priv= col;
      view->r= r;
      view->g= g;
      view->b= b;

      //触发更新状态栏的消息SIGNAL_ZOOM_CHANGED
  g_signal_emit (view, view_signalsSIGNAL_ZOOM_CHANGED, 0, priv->zoom);
        return TRUE;
      }

      //dragimage
      drag_to(view, x, y);
      returnTRUE;
}

3.修改更新状态栏函数

代码语言:txt
复制
static void
update_status_bar (EogWindow *window)
{
         EogWindowPrivate*priv;
         char*str = NULL;
         introw;
         intcol;
         intr;
         intg;
         intb;      

         g_return_if_fail(EOG_IS_WINDOW (window));
         eog_debug(DEBUG_WINDOW);
         priv= window->priv;

         if(priv->image != NULL &&
             eog_image_has_data (priv->image,EOG_IMAGE_DATA_ALL)) {
                   intzoom, width, height;
                   goffsetbytes = 0;
                   zoom= floor (100 * eog_scroll_view_get_zoom (EOG_SCROLL_VIEW (priv->view)) +0.5);
                   eog_image_get_size(priv->image, &width, &height);
                   bytes= eog_image_get_bytes (priv->image);
                   if((width > 0) && (height > 0)) {
                            char*size_string;
                            size_string= g_format_size_for_display (bytes);

                            //从scroll_view中取出row,col,r,g,b
                            row=  (EOG_SCROLL_VIEW (priv->view))->row;
                            col= (EOG_SCROLL_VIEW (priv->view))->col;
                            r= (EOG_SCROLL_VIEW (priv->view))->r;
                            g= (EOG_SCROLL_VIEW (priv->view))->g;
                            b= (EOG_SCROLL_VIEW (priv->view))->b; 

                            //格式化准备显示在状态栏的字符串
                            str= g_strdup_printf (ngettext("%i x %i pixel %s    %i%%    %i,%iRGB(%i,%i,%i)(%02x,%02x,%02x)",
                                                                 "%ix %i pixels  %s    %i%%   %i,%i RGB(%i,%i,%i)(%02x,%02x,%02x)", height),
                                                      width, height, size_string,zoom,
                                                      (height - row - 1), col, r, g, b, r, g,b
                                                      );

                            g_free(size_string);
                   }

                   update_image_pos(window);
         }

  gtk_statusbar_pop(GTK_STATUSBAR (priv->statusbar),
                               priv->image_info_message_cid); 

         //把str字符串显示到状态栏
  gtk_statusbar_push(GTK_STATUSBAR (priv->statusbar),
                                priv->image_info_message_cid, str ? str: "");
         g_free(str);
}

附件两张行列计算的关系图:

  1. 图片缩小的情况:
  1. 图片放大的情况:

第四步:最终显示效果

如图,当鼠标移动时,状态栏的行、列、红、绿、蓝等信息都实时更新。

总结:

本文的目的并不是想教会大家如何编写Linux C的软件,只是给大家提出一种解决问题的方法。数字验证工程师往往需要多方面的技能,如软件编程、数据库、FPGA、甚至是板级的原理图、PCB……

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一步:下载源码:
  • 第二步:研究分析源码,确定修改方案
  • 第三步:修改源码
  • 第四步:最终显示效果
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档