#include "image_display.hpp" #include "blgtk.h" #include "o_gtk_image.hpp" #include // O_RDONLY ... #include #include #include #include //uint32_t #include #include #include //errno #include "blc_image.h" #include "blc_realtime.h" #include "blc_program.h" //blc_status uint32_t false_colors[256]; uint32_t gray_colors[256]; uint32_t u_colors[256]; uint32_t v_colors[256]; uint32_t r_colors[256]; uint32_t g_colors[256]; uint32_t b_colors[256]; uint32_t *color_map; uchar min=0; uchar max=255; int iterations=0; int colors_initilized = 0; int mouse_image_x, mouse_image_y; cairo_surface_t *legend_surface, *image_surface; guint histogram_tick_id; gulong pointer_value_handler; uint32_t *histogram_data=NULL; GtkWidget *histogram_image, *histogram, *histogram_scrolled_window; cairo_surface_t *histogram_surface; GtkWidget *paned; static uint32_t *RGBA_from_YUYV = NULL; static GtkWidget *vbox, *scrolled_window, *event_box, *toolbar, *general_statusbar; static GtkToggleToolButton *zoom_button, *false_colors_button, *histogram_button; static GtkWidget *image, *legend=NULL; static uchar *image_buffer; pthread_t init_table_thread; double zoom_in_factor=2, zoom_out_factor=0.5; static int width=0, height=0; static blc_channel *channel; static int g_source_continue=G_SOURCE_CONTINUE; static int g_source_remove_pt=G_SOURCE_REMOVE; #define SWAP_RGBA_TO_CAIRO_ARGB32(x) ((((x) & 0x000000FF) << 16) | (((x) & 0x00FF0000) >> 16) | ((x) & 0xFF00FF00) ) static void toggle_fullscreen(GtkWidget *widget, GdkEventWindowState *event, gpointer user_data){ if (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN ){ gtk_widget_hide(toolbar); gtk_widget_hide(general_statusbar); } else{ gtk_widget_show(toolbar); gtk_widget_show(general_statusbar); } } void* create_RGBA_from_YUYV(void *widget) { int Y, Cb, Cr; int i, j; float G_tmp; static uchar R[256], B; (void)widget; if (RGBA_from_YUYV == NULL) { RGBA_from_YUYV= MANY_ALLOCATIONS(256*256*256, uint32_t); FOR_INV(Y, 256) { FOR_INV(j,256) R[j]= CLIP_UCHAR(Y+1.13983*(j-128)); //It does not depend on Cb FOR_INV(Cb, 256) { B = CLIP_UCHAR(Y+2.03211*(Cb-128)); // It does not depend on Cr G_tmp = - 0.58060*(Cb-128); FOR_INV(Cr, 256) { i = Y + (Cb << 8) + (Cr << 16); // Version Wikipedia RGBA_from_YUYV[i] = (R[Cr]<<16) + (((uchar)CLIP_UCHAR(Y-0.39465*(Cr-128) + G_tmp))<< 8)+ B + (255<<24); } } } } return NULL; } void init_false_colors() { int i, val; int min; FOR_INV(i, 256) { min=(int)(i*6/256)*256/6; if ((i-min) > 256/6) min++; val=(i-min)*6; switch (i*6/256) { case 0:false_colors[i]=(val)+(255<<24); break; case 1:false_colors[i]=255+(val<<8)+(255<<24); break; case 2:false_colors[i]=(255-val)+(255<<8)+(255<<24); break; case 3:false_colors[i]=(255<<8)+(val<<16)+(255<<24); break; case 4:false_colors[i]=((255-val)<<8)+(255<<16)+(255<<24); break; case 5:false_colors[i]=(255<<16)+(val)+(val<<8)+(255<<24); break; } } } static void init_color_maps(){ int i; if (RGBA_from_YUYV==NULL) create_RGBA_from_YUYV(NULL); FOR_INV(i, 256){ gray_colors[i]= i+(i<<8)+(i<<16)+(255<<24); u_colors[i]= RGBA_from_YUYV[128+(i<<8)+(128<<16)]+(255<<24); v_colors[i]=RGBA_from_YUYV[127+(127<<8)+(i<<16)]; r_colors[i]= 128+(128<<8)+(i<<16)+(255<<24); g_colors[i]= 128+(i<<8)+(128<<16)+(255<<24); b_colors[i]= i+(128<<8)+(128<<16)+(255<<24); } init_false_colors(); } /** Gtk cannot display a black and white image, therefore we convert it before updating it*/ gboolean update_Y800_image(GtkImage *image, GdkFrameClock *, gpointer pointer_statusbar) { int i, x, y, j; double sx, sy; uint32_t *values; char text[64]; if (blc_command_loop_start()==0) exit(0); values = (uint32_t*)image_buffer; if (channel->type=='UIN8') FOR_INV(i, channel->size) values[i]=color_map[channel->uchars[i]]; else if (channel->type=='FL32') FOR_INV(i, channel->size/sizeof(float)) values[i]=color_map[CLIP_UCHAR(channel->floats[i]*256-0.5f)]; else EXIT_ON_ARRAY_ERROR(channel, "Type not managed"); gtk_image_set_from_surface(image, image_surface); gdk_window_get_device_position(gtk_widget_get_window(GTK_WIDGET(image)), pointer_device, &x, &y, NULL); cairo_surface_get_device_scale(image_surface, &sx, &sy); i=x*sx; j=y*sy; if (i=0 && j>=0) { if (channel->type=='UIN8') SPRINTF(text, "%4d,%4d: Y:%3d", i,j, channel->uchars[i+j*width]); else if (channel->type=='FL32') SPRINTF(text, "%4d,%4d: Y:%.3f", i,j, channel->floats[i+j*width]); gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text); } iterations++; blc_command_loop_end(); return blc_status; } gboolean update_RGB3_image(GtkImage *image, GdkFrameClock *, gpointer pointer_statusbar) { char text[NAME_MAX]; double sx, sy; int x, y, i=0, j=0; int R, G, B; gdk_window_get_device_position(gtk_widget_get_window(GTK_WIDGET(image)), pointer_device, &x, &y, NULL); cairo_surface_get_device_scale(image_surface, &sx, &sy); while(i!=channel->size) { image_buffer[j++]=channel->uchars[i+2]; image_buffer[j++]=channel->uchars[i+1]; image_buffer[j++]=channel->uchars[i]; j++; i+=3; } i=x*sx; j=y*sy; if (i=0 && j>=0) { if (mouse_channel.fd!=-1) { mouse_channel.uints32[0]=i; mouse_channel.uints32[1]=j; gdk_device_get_state(pointer_device, gtk_widget_get_window(GTK_WIDGET(image)), NULL, (GdkModifierType*)(&mouse_channel.uints32[2])); } R=channel->uchars[i*4+j*width*3]; G=channel->uchars[i*4+j*width*3+1]; B=channel->uchars[i*4+j*width*3+2]; SPRINTF(text, "%4d,%4d : R:%3d,G:%3d,B:%3d", i, j, R, G, B); gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text); } gtk_image_set_from_surface(image, image_surface); iterations++; return G_SOURCE_CONTINUE; } gboolean update_RGBA_image(GtkImage *image, GdkFrameClock *, gpointer pointer_statusbar) { double sx, sy; int x, y; int i, j=0; char text[NAME_MAX]; int R, G, B, A; gdk_window_get_device_position(gtk_widget_get_window(GTK_WIDGET(image)), pointer_device, &x, &y, NULL); cairo_surface_get_device_scale(image_surface, &sx, &sy); FOR_INV(i, channel->size/4) ((uint32_t*)image_buffer)[i]=SWAP_RGBA_TO_CAIRO_ARGB32(channel->uints32[i]); i=x*sx; j=y*sy; if (i=0 && j>=0) { if (mouse_channel.fd!=-1) { mouse_channel.uints32[0]=i; mouse_channel.uints32[1]=j; gdk_device_get_state(pointer_device, gtk_widget_get_window(GTK_WIDGET(image)), NULL, (GdkModifierType*)(&mouse_channel.uints32[2])); } R=channel->uchars[i*4+j*width*4]; G=channel->uchars[i*4+j*width*4+1]; B=channel->uchars[i*4+j*width*4+2]; A=channel->uchars[i*4+j*width*4+3]; SPRINTF(text, "%4d,%4d: R:%d G:%d B:%d A:%d", i, j, R, G, B, A); gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text); } gtk_image_set_from_surface(image, image_surface); iterations++; return G_SOURCE_CONTINUE; } // Soon we should the implementation of blc_image */ void jpeg_error(j_common_ptr cinfo, int msg_level) { (void) msg_level; cinfo->err->num_warnings++; } gboolean update_JPEG_image(GtkImage *image, GdkFrameClock *frame_clock, blc_channel *channel) { JSAMPROW row_pt[1]; GdkPixbuf *pixbuf; int row_stride; uchar *pixels; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; (void) frame_clock; pixbuf = gtk_image_get_pixbuf(image); pixels = gdk_pixbuf_get_pixels(pixbuf); cinfo.err = jpeg_std_error(&jerr); cinfo.err->emit_message = jpeg_error; jpeg_create_decompress(&cinfo); jpeg_mem_src(&cinfo, (uchar*) channel->data, channel->size); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); row_stride = cinfo.output_width * cinfo.output_components; row_pt[0] = pixels; while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines(&cinfo, row_pt, 1); row_pt[0] += row_stride; } if (cinfo.err->num_warnings != 0) { PRINT_WARNING("Drop image : %s", cinfo.err->jpeg_message_table[cinfo.err->last_jpeg_message]); cinfo.err->num_warnings = 0; } gtk_image_set_from_pixbuf(image, pixbuf); jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return G_SOURCE_CONTINUE; } // 4:2:2 gboolean update_YUYV_image(GtkImage *image, GdkFrameClock *frame_clock, void*) { int i, j; uchar *data = (uchar*) channel->data; uint32_t *pixels; int Y, Cb = 128, Cr = 128; (void) frame_clock; pixels = (uint32_t*)image_buffer; if (blc_command_loop_start()==0) exit(0); i = 0; while (i != (int) channel->size) { Y = data[i++]; Cb = data[i++]; j = Y + (Cb << 8) + (Cr << 16); pixels[0]=RGBA_from_YUYV[j]; Y = data[i++]; Cr = data[i++]; j = Y + (Cb << 8) + (Cr << 16); pixels[1]=RGBA_from_YUYV[j]; pixels+=2; } iterations++; blc_command_loop_end(); gtk_image_set_from_surface(image, image_surface); return G_SOURCE_CONTINUE; } // 4:2:2 gboolean update_yuv2_image(GtkImage *image, GdkFrameClock *, gpointer pointer_statusbar) { double sx, sy; int x, y; int i, j; uchar *data = (uchar*) channel->data; char text[NAME_MAX]; uint32_t *tmp_pixels; int Y, U = 128, V = 128; tmp_pixels = (uint32_t*)image_buffer; i = 0; while (i != (int) channel->size) { U = data[i++]; Y = data[i++]; j = Y + (U << 8) + (V << 16); tmp_pixels[0]=RGBA_from_YUYV[j]; V = data[i++]; Y = data[i++]; j = Y + (U << 8) + (V << 16); tmp_pixels[1]=RGBA_from_YUYV[j]; tmp_pixels+=2; } gdk_window_get_device_position(gtk_widget_get_window(GTK_WIDGET(image)), pointer_device, &x, &y, NULL); cairo_surface_get_device_scale(image_surface, &sx, &sy); i=x*sx; j=y*sy; if (i=0 && j>=0) { if (mouse_channel.fd!=-1) { mouse_channel.uints32[0]=i; mouse_channel.uints32[1]=j; gdk_device_get_state(pointer_device, gtk_widget_get_window(GTK_WIDGET(image)), NULL, (GdkModifierType*)(&mouse_channel.uints32[2])); } Y=channel->uchars[i*2+j*width*2+1]; U=channel->uchars[i*4+j*width*2]; V=channel->uchars[i*4+j*width*2+2]; SPRINTF(text, "%d,%d: Y:%d, U:%d, V:%d", i, j, Y, U, V); gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text); } gtk_image_set_from_surface(image, image_surface); iterations++; return G_SOURCE_CONTINUE; } static void draw_histogram(uint32_t *drawing, int height, int histogram[256], uint32_t color_map[256], int max) { int i, j, val; FOR_INV(i, 256) { val = height-histogram[i]*(height-1)/max; for(j=height; j!=val; j--) drawing[j*256+i]=color_map[i]; drawing[val*256+i]=255<<24; FOR_INV(j, val) drawing[j*256+i]=0; } } gboolean update_histogram_cb(GtkImage *image, GdkFrameClock *, gpointer pointer_statusbar){ int i, j, x, y; double sx, sy; int histogram[256]={0}, histogram1[256]={0}, histogram2[256]={0}, max=0, max1=0, max2=0; char text[64]; struct timeval timer; CLEAR(timer); gdk_window_get_device_position(gtk_widget_get_window(GTK_WIDGET(image)), pointer_device, &x, &y, NULL); cairo_surface_get_device_scale(histogram_surface, &sx, &sy); x*=sx; y*=sy; switch (channel->format){ case 'Y800': FOR_INV(i, channel->size) histogram[channel->uchars[i]]++; FOR_INV(i, 256) max=MAX(histogram[i], max); FOR_INV(i, 256) { FOR_INV(j, histogram[i]*255/max) histogram_data[(255-j)*256+i]=color_map[i]; histogram_data[(255-histogram[i]*255/max)*256+i]=255<<24; FOR_INV(j, 255-histogram[i]*255/max) histogram_data[j*256+i]=0; } if (y>=0 && y<256 && x >=0 && x<256) { SPRINTF(text, "Y[%d]=%f.2%%", x, histogram[x]*100/(float)channel->size); gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text); } break; case 'RGB3': FOR_INV(i, channel->size/3){ histogram[channel->uchars[i*3]]++; histogram1[channel->uchars[i*3+1]]++; histogram2[channel->uchars[i*3+2]]++; } FOR_INV(i, 256) { max=MAX(histogram[i], max); max1=MAX(histogram1[i], max1); max2=MAX(histogram2[i], max2); } draw_histogram(histogram_data, 85, histogram, r_colors, max); draw_histogram(histogram_data+256*85, 85, histogram1, g_colors, max1); draw_histogram(histogram_data+256*170, 85, histogram2, b_colors, max2); if (y>=0 && y<256 && x >=0 && x<256) { if (y<85) SPRINTF(text, "R[%d]=%f.2%%", x, histogram[x]*100*2/(float)channel->size); else if (y<170) SPRINTF(text, "G[%d]=%.2f%%", x, histogram1[x]*100*4/(float)channel->size); else SPRINTF(text, "B[%d]=%.2f%%", x, histogram2[x]*100*4/(float)channel->size); gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text); } break; case 'YUYV': for(i=channel->size-2;i!=-1;i-=2) histogram[channel->uchars[i]]++; for(i=channel->size-1;i!=-2;i-=4) histogram1[channel->uchars[i]]++; for(i=channel->size-3;i!=-4;i-=4) histogram2[channel->uchars[i]]++; FOR_INV(i, 256) { max=MAX(histogram[i], max); max1=MAX(histogram1[i], max1); max2=MAX(histogram2[i], max2); } draw_histogram(histogram_data, 127, histogram, gray_colors, max); draw_histogram(histogram_data+256*128, 63, histogram1, u_colors, max1); draw_histogram(histogram_data+256*192, 63, histogram2, v_colors, max2); if (y>=0 && y<256 && x >=0 && x<256) { if (y<128) SPRINTF(text, "Y[%d]=%f.2%%", x, histogram[x]*100*2/(float)channel->size); else if (y<192) SPRINTF(text, "U[%d]=%.2f%%", x, histogram1[x]*100*4/(float)channel->size); else SPRINTF(text, "V[%d]=%.2f%%", x, histogram2[x]*100*4/(float)channel->size); gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text); } break; case 'yuv2': for(i=channel->size-1;i!=-1;i-=2) histogram[channel->uchars[i]]++; for(i=channel->size-2;i!=-2;i-=4) histogram1[channel->uchars[i]]++; for(i=channel->size-4;i!=-4;i-=4) histogram2[channel->uchars[i]]++; FOR_INV(i, 256) { max=MAX(histogram[i], max); max1=MAX(histogram1[i], max1); max2=MAX(histogram2[i], max2); } draw_histogram(histogram_data, 127, histogram, gray_colors, max); draw_histogram(histogram_data+256*128, 63, histogram1, u_colors, max1); draw_histogram(histogram_data+256*192, 63, histogram2, v_colors, max2); if (y>=0 && y<256 && x >=0 && x<256) { if (y<128) SPRINTF(text, "Y[%d]=%f.2%%", x, histogram[x]*100*2/(float)channel->size); else if (y<192) SPRINTF(text, "U[%d]=%.2f%%", x, histogram1[x]*100*4/(float)channel->size); else SPRINTF(text, "V[%d]=%.2f%%", x, histogram2[x]*100*4/(float)channel->size); gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text); } break; default: gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, "No histogram for this format. Only Y800,RGB3 or yuv2."); } gtk_image_set_from_surface(image, histogram_surface); // fprintf(stderr, "Hist delai %ldµs\n", us_time_diff(&timer)); return G_SOURCE_CONTINUE; } static void gtk_image_resize_cb(GtkWidget *image, GdkRectangle *allocation, gpointer user_data) { (void) image; (void) user_data; if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(zoom_button))) cairo_surface_set_device_scale(image_surface, (double)width/(double)allocation->width, (double)height/(double)allocation->height); if (legend) cairo_surface_set_device_scale(legend_surface, 256/(double)allocation->width, 1/(double)allocation->height); } static void histogram_resize_cb(GtkWidget *widget, GdkRectangle *allocation, gpointer user_data) { (void) widget; (void) user_data; cairo_surface_set_device_scale(histogram_surface, (double)256/(double)allocation->width, (double)256/(double)allocation->height); } static void zoom_original_cb(GtkToolButton *, gpointer) { int image_height, window_height; image_height=gtk_widget_get_allocated_height(image); window_height = gtk_widget_get_allocated_height(window); cairo_surface_set_device_scale(image_surface, 1, 1); if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(zoom_button))) gtk_window_resize(GTK_WINDOW(window), width, window_height-image_height+height ); } static void zoom_cb(GtkToolButton *toolbutton, double *factor) { double sx, sy; (void)toolbutton; gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(zoom_button), FALSE); cairo_surface_get_device_scale(image_surface, &sx, &sy); cairo_surface_set_device_scale(image_surface, sx*(*factor), sy*(*factor)); } static void histogram_cb(GtkToolButton *toolbutton, gpointer pointer_statusbar ) { char text[NAME_MAX]; GtkWidget *legend_box, *label; if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(toolbutton))) { histogram_data=MANY_ALLOCATIONS(256*256, uint32_t); histogram_surface=cairo_image_surface_create_for_data ((uchar*)histogram_data, CAIRO_FORMAT_ARGB32, 256, 256, 256*4); histogram_image=gtk_image_new_from_surface(histogram_surface); histogram_scrolled_window=gtk_scrolled_window_new(NULL, NULL); histogram=gtk_box_new(GTK_ORIENTATION_VERTICAL, 1); legend_box=gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1); gtk_container_add(GTK_CONTAINER(histogram_scrolled_window), histogram_image); gtk_container_add(GTK_CONTAINER(histogram), histogram_scrolled_window); gtk_container_add(GTK_CONTAINER(histogram), legend_box); SPRINTF(text, "%d", min); label=gtk_label_new(text); gtk_box_pack_start(GTK_BOX(legend_box), label, FALSE, FALSE, 0); SPRINTF(text, "%d", max); label=gtk_label_new(text); gtk_box_pack_end(GTK_BOX(legend_box), label, FALSE, FALSE, 0); if (legend) { gtk_container_remove(GTK_CONTAINER(paned), legend); // gtk_widget_destroy(legend); legend=NULL; } gtk_paned_add2(GTK_PANED(paned), histogram); gtk_widget_set_vexpand(histogram_image, TRUE); gtk_paned_set_position(GTK_PANED(paned), gtk_widget_get_allocated_height(paned)-256); gtk_widget_show_all(paned); g_signal_connect(G_OBJECT(histogram_scrolled_window), "size-allocate", G_CALLBACK(histogram_resize_cb), NULL); histogram_tick_id = gtk_widget_add_tick_callback(GTK_WIDGET(histogram_image), (GtkTickCallback) update_histogram_cb, pointer_statusbar, NULL); } else { gtk_widget_remove_tick_callback(GTK_WIDGET(histogram_image), histogram_tick_id); gtk_container_remove(GTK_CONTAINER(paned), histogram); FREE(histogram_data); // gtk_widget_destroy(histogram); histogram=NULL; } } static void false_color_cb(GtkToolButton *toolbutton, struct update_cb *){ GtkWidget *label, *legend_box, *legend_image; char text[NAME_MAX+1]; int i; if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(toolbutton))){ color_map=false_colors; legend_surface=cairo_image_surface_create_for_data ((uchar*)false_colors, CAIRO_FORMAT_RGB24, 256, 1, 256*4); legend=gtk_box_new(GTK_ORIENTATION_VERTICAL, 1); legend_image = gtk_image_new_from_surface(legend_surface); legend_box=gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1); FOR(i, 7) { SPRINTF(text, "%d", (i+1)*256/8); label = gtk_label_new(text); gtk_box_pack_start(GTK_BOX(legend_box), label, TRUE, TRUE, 0); } gtk_container_add(GTK_CONTAINER(legend), legend_image); gtk_container_add(GTK_CONTAINER(legend), legend_box); gtk_paned_add2(GTK_PANED(paned),legend ); gtk_widget_show_all(legend); } else{ color_map=gray_colors; if (legend){ gtk_container_remove(GTK_CONTAINER(paned), legend); gtk_widget_destroy(legend); legend=NULL; } } } void *refresh_RGB3_cb(void *) { int ch=' '; while(ch!='q') { ch=fgetc(stdin); switch (ch){ case '\n': case '.': gtk_widget_add_tick_callback(GTK_WIDGET(image), (GtkTickCallback) update_RGB3_image, &g_source_remove_pt, NULL); break; case 'q': g_application_quit(G_APPLICATION(app)); break; default:fprintf(stderr, "Unknown command '%c' code '%d'.\n", ch, ch); } } return NULL; } void *refresh_yuv2_cb(void *user_data) { int ch=' '; (void)user_data; while(ch!='q') { ch=fgetc(stdin); switch (ch){ case '\n': case '.': gtk_widget_add_tick_callback(GTK_WIDGET(image), (GtkTickCallback) update_yuv2_image, &g_source_remove_pt, NULL); break; case 'q': g_application_quit(G_APPLICATION(app)); break; default:fprintf(stderr, "Unknown command '%c' code '%d'.\n", ch, ch); } } return NULL; } int frame_rate(gpointer data) { char text[64]; GtkWidget *framerate_statusbar=(GtkWidget*)data; SPRINTF(text, "%dHz", iterations); gtk_statusbar_push(GTK_STATUSBAR(framerate_statusbar), 0, text); iterations=0; return G_SOURCE_CONTINUE; } GtkWidget *create_image_display(blc_channel *tmp_channel) { GtkWidget *pointer_statusbar, *framerate_statusbar; char label_text[NAME_MAX + 1]; uint32_t type_string, format_string; channel=tmp_channel; toolbar = gtk_toolbar_new(); general_statusbar=gtk_statusbar_new(); framerate_statusbar=gtk_statusbar_new(); pointer_statusbar=gtk_statusbar_new(); switch (channel->format) { case 'Y800': width=channel->dims[0].length; height=channel->dims[1].length; image_buffer = MANY_ALLOCATIONS(width*height * 4, uchar); image_surface=cairo_image_surface_create_for_data(image_buffer, CAIRO_FORMAT_RGB24, width, height, width * 4); image=gtk_image_new_from_surface(image_surface); gtk_widget_add_tick_callback(image, (GtkTickCallback) update_Y800_image, pointer_statusbar, NULL); false_colors_button=blgtk_add_toggle_tool_button(toolbar, "false\ncolors", "applications-graphics", G_CALLBACK(false_color_cb), NULL); break; case 'BA81': EXIT_ON_ARRAY_ERROR(channel, "format, Not fully implemented"); width=channel->dims[1].length; height=channel->dims[2].length; image_buffer = MANY_ALLOCATIONS(width*height * 4, uchar); image_surface=cairo_image_surface_create_for_data(image_buffer, CAIRO_FORMAT_RGB24, width, height, width * 4); image=gtk_image_new_from_surface(image_surface); gtk_widget_add_tick_callback(GTK_WIDGET(image), (GtkTickCallback) update_RGB3_image, &g_source_continue, NULL); break; case 'RGB3': width=channel->dims[1].length; height=channel->dims[2].length; image_buffer = MANY_ALLOCATIONS(width*height * 4, uchar); image_surface=cairo_image_surface_create_for_data(image_buffer, CAIRO_FORMAT_RGB24, width, height, width * 4); image=gtk_image_new_from_surface(image_surface); gtk_widget_add_tick_callback(GTK_WIDGET(image), (GtkTickCallback) update_RGB3_image, pointer_statusbar, NULL); break; case 'RGBA': width=channel->dims[1].length; height=channel->dims[2].length; image_buffer = MANY_ALLOCATIONS(width*height * 4, uchar); image_surface=cairo_image_surface_create_for_data(image_buffer, CAIRO_FORMAT_ARGB32, width, height, width * 4); image=gtk_image_new_from_surface(image_surface); gtk_widget_add_tick_callback(GTK_WIDGET(image), (GtkTickCallback) update_RGBA_image, pointer_statusbar, NULL); break; /* case 'JPEG': width=channel->lengths[1]; height=channel->lengths[2]; image_buffer = MANY_ALLOCATIONS(width*height*3, uchar); pixbuf = gdk_pixbuf_new_from_data( image_buffer, GDK_COLORSPACE_RGB, 0, 8, width, height, width * 3, NULL, NULL); image = gtk_image_new_from_pixbuf(pixbuf); gtk_widget_add_tick_callback(image, (GtkTickCallback) update_JPEG_image, channel, NULL);*/ case 'YUYV': width=channel->dims[1].length; height=channel->dims[2].length; image_buffer = MANY_ALLOCATIONS(width*height * 4, uchar); //In order to be sure that the rowstride will be 'gui.width * 3' image_surface=cairo_image_surface_create_for_data(image_buffer, CAIRO_FORMAT_RGB24, width, height, width * 4); image=gtk_image_new_from_surface(image_surface); gtk_widget_add_tick_callback(GTK_WIDGET(image), (GtkTickCallback) update_YUYV_image, pointer_statusbar, NULL); break; case 'yuv2':case 'UYVY': pthread_create(&init_table_thread, NULL, create_RGBA_from_YUYV, image); width=channel->dims[1].length; height=channel->dims[2].length; image_buffer = MANY_ALLOCATIONS(width*height * 4, uchar); image_surface=cairo_image_surface_create_for_data(image_buffer, CAIRO_FORMAT_RGB24, width, height, width * 4); image=gtk_image_new_from_surface(image_surface); gtk_widget_add_tick_callback(GTK_WIDGET(image), (GtkTickCallback) update_yuv2_image, pointer_statusbar, NULL); break; default:return NULL; } channel=tmp_channel; vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 3); scrolled_window=gtk_scrolled_window_new(NULL, NULL); gtk_container_add(GTK_CONTAINER(general_statusbar), framerate_statusbar); gtk_container_add(GTK_CONTAINER(general_statusbar), pointer_statusbar); gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH); init_color_maps(); color_map=gray_colors; g_timeout_add(1000, frame_rate, (gpointer)framerate_statusbar); SPRINTF(label_text, "%.4s, %.4s, %dx%d", UINT32_TO_STRING(type_string, channel->type), UINT32_TO_STRING(format_string, channel->format), width, height); gtk_statusbar_push(GTK_STATUSBAR(general_statusbar), 0, label_text); gtk_widget_set_vexpand(scrolled_window, TRUE); gtk_widget_set_halign(image, GTK_ALIGN_START); gtk_widget_set_valign(image, GTK_ALIGN_START); blgtk_add_tool_button(toolbar, "zoom\n1:1", "zoom-original", G_CALLBACK(zoom_original_cb), NULL); blgtk_add_tool_button(toolbar, "zoom\nx0.5", "zoom-out", G_CALLBACK(zoom_cb), &zoom_in_factor); blgtk_add_tool_button(toolbar, "zoom\nx2", "zoom-in", G_CALLBACK(zoom_cb), &zoom_out_factor); zoom_button=blgtk_add_toggle_tool_button(toolbar, "zoom\nfit", "zoom-fit-best", NULL, NULL); // blgtk_add_toggle_tool_button(toolbar, "cursor\nvalues", "system-search", NULL, NULL);/ histogram_button=blgtk_add_toggle_tool_button(toolbar, "histogram", "x-office-presentation", G_CALLBACK(histogram_cb), pointer_statusbar); gtk_toggle_tool_button_set_active(zoom_button, TRUE); g_signal_connect(G_OBJECT(scrolled_window), "size-allocate", G_CALLBACK(gtk_image_resize_cb), NULL); event_box=gtk_event_box_new(); paned=gtk_paned_new(GTK_ORIENTATION_VERTICAL); // gtk_paned_set_wide_handle (GTK_PANED(paned), TRUE); gtk_container_add(GTK_CONTAINER(scrolled_window), event_box); gtk_paned_add1(GTK_PANED(paned), scrolled_window); gtk_container_add(GTK_CONTAINER(event_box), image); gtk_container_add(GTK_CONTAINER(vbox), toolbar); gtk_container_add(GTK_CONTAINER(vbox), paned); gtk_container_add(GTK_CONTAINER(vbox), general_statusbar); zoom_original_cb(NULL, NULL); g_signal_connect(window, "window-state-event", G_CALLBACK (toggle_fullscreen), NULL); if (fullscreen_option) gtk_window_fullscreen(GTK_WINDOW(window)); // g_signal_connect(G_OBJECT(vbox), "realize", G_CALLBACK(image_realize_cb), NULL); return vbox; }