好用的看图工具对做图片相关的算法验证很有帮助。但常常工具并没有我们需要的功能。今天我就分享一个工作中遇到的例子。
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中获得行、列、红、绿、蓝等信息。
- 显示到状态栏。
第三步:修改源码
- 定义全局变量
struct_EogScrollViewPrivate {
//…
int row, col; //在scroll_view里增加全局变量,用来保存信息
int r, g, b;
}
- 修改鼠标响应事件函数
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)(x,x,x)",
"%ix %i pixels %s %i%% %i,%i RGB(%i,%i,%i)(x,x,x)", 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);
}
附件两张行列计算的关系图:
- 图片缩小的情况:
- 图片放大的情况:
第四步:最终显示效果
如图,当鼠标移动时,状态栏的行、列、红、绿、蓝等信息都实时更新。
总结:
本文的目的并不是想教会大家如何编写Linux C的软件,只是给大家提出一种解决问题的方法。数字验证工程师往往需要多方面的技能,如软件编程、数据库、FPGA、甚至是板级的原理图、PCB……