#include "common.h" #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 //cairo_surface_t *legend_surface; guint histogram_tick_id; uint32_t *histogram_data=NULL; cairo_surface_t *histogram_surface; 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; } } static 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}, hist_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 (array->format){ case 'Y800': switch (array->type){ case 'UIN8': FOR(i, array->size) histogram[array->uchars[i]]++; FOR(i, 256) hist_max=MAX(histogram[i], hist_max); FOR(i, 256) { FOR_INV(j, histogram[i]*255/hist_max) histogram_data[(255-j)*256+i]=color_map[i]; histogram_data[(255-histogram[i]*255/hist_max)*256+i]=255<<24; FOR_INV(j, 255-histogram[i]*255/hist_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)array->size); gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text); } break; case 'FL32': FOR(i, array->total_length) histogram[(int)CLIP_UCHAR(((array->floats[i]-min_val)/(max_val-min_val)*256+0.5))]++; FOR(i, 256) hist_max=MAX(histogram[i], hist_max); FOR(i, 256) { FOR_INV(j, histogram[i]*255/hist_max) histogram_data[(255-j)*256+i]=color_map[i]; histogram_data[(255-histogram[i]*255/hist_max)*256+i]=255<<24; FOR_INV(j, 255-histogram[i]*255/hist_max) histogram_data[j*256+i]=0; } if (y>=0 && y<256 && x >=0 && x<256) { SPRINTF(text, "Y[%f]=%f.2%%", x*(max_val-min_val-0.5)/256+min_val, histogram[x]*100/(float)array->total_length); gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text); } break; default: EXIT_ON_ARRAY_ERROR( array, "Type not managed for format 'Y800'. Only 'UIN8' is"); } break; case 'RGB3': FOR_INV(i, array->size/3){ histogram[array->uchars[i*3]]++; histogram1[array->uchars[i*3+1]]++; histogram2[array->uchars[i*3+2]]++; } FOR_INV(i, 256) { hist_max=MAX(histogram[i], hist_max); max1=MAX(histogram1[i], max1); max2=MAX(histogram2[i], max2); } draw_histogram(histogram_data, 85, histogram, r_colors, hist_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)array->size); else if (y<170) SPRINTF(text, "G[%d]=%.2f%%", x, histogram1[x]*100*4/(float)array->size); else SPRINTF(text, "B[%d]=%.2f%%", x, histogram2[x]*100*4/(float)array->size); gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text); } break; case 'YUYV': for(i=array->size-2;i!=-1;i-=2) histogram[array->uchars[i]]++; for(i=array->size-1;i!=-2;i-=4) histogram1[array->uchars[i]]++; for(i=array->size-3;i!=-4;i-=4) histogram2[array->uchars[i]]++; FOR_INV(i, 256) { hist_max=MAX(histogram[i], hist_max); max1=MAX(histogram1[i], max1); max2=MAX(histogram2[i], max2); } draw_histogram(histogram_data, 127, histogram, gray_colors, hist_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)array->size); else if (y<192) SPRINTF(text, "U[%d]=%.2f%%", x, histogram1[x]*100*4/(float)array->size); else SPRINTF(text, "V[%d]=%.2f%%", x, histogram2[x]*100*4/(float)array->size); gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text); } break; case 'yuv2': for(i=array->size-1;i!=-1;i-=2) histogram[array->uchars[i]]++; for(i=array->size-2;i!=-2;i-=4) histogram1[array->uchars[i]]++; for(i=array->size-4;i!=-4;i-=4) histogram2[array->uchars[i]]++; FOR_INV(i, 256) { hist_max=MAX(histogram[i], hist_max); max1=MAX(histogram1[i], max1); max2=MAX(histogram2[i], max2); } draw_histogram(histogram_data, 127, histogram, gray_colors, hist_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)array->size); else if (y<192) SPRINTF(text, "U[%d]=%.2f%%", x, histogram1[x]*100*4/(float)array->size); else SPRINTF(text, "V[%d]=%.2f%%", x, histogram2[x]*100*4/(float)array->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); return G_SOURCE_CONTINUE; } 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, "%f", min_val); label=gtk_label_new(text); gtk_box_pack_start(GTK_BOX(legend_box), label, FALSE, FALSE, 0); SPRINTF(text, "%f", max_val); 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); 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; } }