stat.c

Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /*
00003   stat.c
00004   an heraia plugin to calculate some stats on the opened file
00005 
00006   (C) Copyright 2007 - 2010 Olivier Delhomme
00007   e-mail : heraia@delhomme.org
00008   URL    : http://heraia.tuxfamily.org
00009 
00010   This program is free software; you can redistribute it and/or modify
00011   it under the terms of the GNU General Public License as published by
00012   the Free Software Foundation; either version 2, or  (at your option)
00013   any later version.
00014 
00015   This program is distributed in the hope that it will be useful,
00016   but WITHOUT ANY WARRANTY;  without even the implied warranty of
00017   MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE.  See the
00018   GNU General Public License for more details.
00019 
00020   You should have received a copy of the GNU General Public License
00021   along with this program; if not, write to the Free Software
00022   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00023 */
00024 /**
00025  * @file stat.c
00026  * does some basic statistics on the file and displays them
00027  * in a numerical or graphical way (histograms : 1D and 2D)
00028  */
00029 #include "stat.h"
00030 
00031 /* The functions for the plugin's usage */
00032 static void stat_window_connect_signals(heraia_plugin_t *plugin);
00033 
00034 static void statw_close_clicked(GtkWidget *widget, gpointer data);
00035 static void destroy_stat_window(GtkWidget *widget, GdkEvent  *event, gpointer data);
00036 
00037 static void statw_save_as_clicked(GtkWidget *widget, gpointer data);
00038 static void statw_export_to_csv_clicked(GtkWidget *widget, gpointer data);
00039 static void statw_export_to_gnuplot_clicked(GtkWidget *widget, gpointer data);
00040 static void statw_export_to_pcv_clicked(GtkWidget *widget, gpointer data);
00041 
00042 static gchar *stat_select_file_to_save(gchar *window_text, stat_t *extra);
00043 static void histo_radiobutton_toggled(GtkWidget *widget, gpointer data);
00044 static gboolean delete_stat_window_event(GtkWidget *widget, GdkEvent  *event, gpointer data );
00045 static void realize_some_numerical_stat(heraia_struct_t *main_struct, heraia_plugin_t *plugin);
00046 static void init_stats_histos(heraia_plugin_t *plugin);
00047 static void set_statw_button_state(GtkBuilder *xml, gboolean sensitive);
00048 static void populate_stats_histos(heraia_struct_t *main_struct, heraia_plugin_t *plugin);
00049 static void calc_infos_histo_1D(stat_t *extra);
00050 static void calc_infos_histo_2D(stat_t *extra);
00051 static void init_stats_pixbufs(stat_t *extra);
00052 static void make_pixbufs_from_histos(stat_t *extra);
00053 static void plot_in_pixbuf(GdkPixbuf *pixbuf, gint64 x, gint64 y, guchar red, guchar green, guchar blue, guchar alpha);
00054 static void do_pixbuf_1D_from_histo1D(stat_t *extra);
00055 static void do_pixbuf_2D_from_histo2D(stat_t *extra, guint max_2D);
00056 
00057 
00058 /**
00059  *  Initialisation plugin function called when the plugin is loaded
00060  *  (some sort of pre-init)
00061  *  @param[in,out] plugin : plugin's structure
00062  *  @return returns the plugin structure
00063  */
00064 heraia_plugin_t *heraia_plugin_init(heraia_plugin_t *plugin)
00065 {
00066     stat_t *extra = NULL;            /**< extra structure specific to this plugin */
00067     window_prop_t *stat_prop = NULL; /**< window properties                       */
00068 
00069     plugin->state             = PLUGIN_STATE_INITIALIZING;
00070     plugin->xml = NULL;
00071 
00072     plugin->info->api_version = API_VERSION;
00073     plugin->info->type        = PLUGIN_TYPE;
00074     plugin->info->priority    = HERAIA_PRIORITY_DEFAULT;
00075     plugin->info->name        = PLUGIN_NAME;
00076     plugin->info->version     = PLUGIN_VERSION;
00077     plugin->info->summary     = PLUGIN_SUMMARY;
00078     plugin->info->description = PLUGIN_DESCRIPTION;
00079     plugin->info->author      = PLUGIN_AUTHOR;
00080     plugin->info->homepage    = PLUGIN_HOMEPAGE;
00081 
00082     plugin->init_proc    = init;
00083     plugin->quit_proc    = quit;
00084     plugin->run_proc     = run;
00085     plugin->refresh_proc = refresh;
00086 
00087     plugin->filter->extensions = NULL;
00088     plugin->filter->import     = NULL;
00089     plugin->filter->export     = NULL;
00090 
00091     /* add the extra struct to the plugin one */
00092     extra = (stat_t *) g_malloc0 (sizeof(stat_t));
00093     extra->infos_1D = (histo_infos_t *) g_malloc0 (sizeof(histo_infos_t));
00094     extra->infos_2D = (histo_infos_t *) g_malloc0 (sizeof(histo_infos_t));
00095     extra->dirname = NULL;
00096 
00097     /* window properties */
00098     stat_prop = (window_prop_t *) g_malloc0(sizeof(window_prop_t));
00099     stat_prop->displayed = FALSE; /* by default, it might be anything else */
00100     stat_prop->x = 0;
00101     stat_prop->y = 0;
00102 
00103     plugin->win_prop = stat_prop;
00104 
00105     plugin->extra = extra;
00106 
00107 
00108     return plugin;
00109 }
00110 
00111 
00112 /* the plugin interface functions */
00113 /**
00114  *  The real init function of the plugin (called at init time)
00115  * @param main_struct : main structure
00116  */
00117 void init(heraia_struct_t *main_struct)
00118 {
00119     heraia_plugin_t *plugin = NULL;
00120 
00121     log_message(main_struct, G_LOG_LEVEL_INFO, "Initializing plugin %s", PLUGIN_NAME);
00122     /* first, know who we are ! */
00123     plugin = find_plugin_by_name(main_struct->plugins_list, PLUGIN_NAME);
00124 
00125     if (plugin != NULL)
00126         {
00127             /* load the xml interface */
00128             log_message(main_struct, G_LOG_LEVEL_INFO, "Plugin from %s found !", plugin->info->author);
00129             if (load_plugin_xml(main_struct, plugin) == TRUE)
00130                 {
00131                     log_message(main_struct, G_LOG_LEVEL_INFO, "%s xml interface loaded.", plugin->info->name);
00132                 }
00133             else
00134                 {
00135                     log_message(main_struct, G_LOG_LEVEL_WARNING, "Unable to load %s xml interface.", plugin->info->name);
00136                 }
00137 
00138             /* greyed save as button and others */
00139             set_statw_button_state(plugin->xml, FALSE);
00140 
00141             /* shows or hide the interface (hides it at first as all windows shows up) */
00142             if (plugin->win_prop->displayed == FALSE)
00143                 {
00144                     gtk_widget_hide(GTK_WIDGET(heraia_get_widget(plugin->xml, "stat_window")));
00145                 }
00146             else
00147                 {
00148                     gtk_check_menu_item_set_active(plugin->cmi_entry, TRUE);
00149                 }
00150 
00151             /* connect some signals handlers */
00152             stat_window_connect_signals(plugin);
00153         }
00154 }
00155 
00156 
00157 /**
00158  *  Normaly this is called when the plugin is unloaded
00159  *  One may wait it's entire life for this to be called !! ;)
00160  */
00161 void quit(void)
00162 {
00163     g_print("Quitting %s\n", PLUGIN_NAME);
00164 }
00165 
00166 
00167 /**
00168  *  This function is called via a signal handler when the menu entry is toggled
00169  * @param widget : widget which called the function (unused)
00170  * @param data : user data for the plugin, here MUST be heraia_struct_t * main
00171  *        structure
00172  */
00173 void run(GtkWidget *widget, gpointer data)
00174 {
00175     heraia_struct_t *main_struct = (heraia_struct_t *) data; /* the signal send the pointer to this structure */
00176     heraia_plugin_t *plugin = NULL;
00177     gboolean menu_state = FALSE;
00178 
00179     /* first, know who we are ! */
00180     plugin = find_plugin_by_name(main_struct->plugins_list, PLUGIN_NAME);
00181 
00182     if (plugin != NULL)
00183         {
00184             menu_state = gtk_check_menu_item_get_active(plugin->cmi_entry);
00185 
00186             show_hide_widget(GTK_WIDGET(heraia_get_widget(plugin->xml, "stat_window")), menu_state, plugin->win_prop);
00187 
00188             if (menu_state == TRUE)
00189                 {
00190                     plugin->state = PLUGIN_STATE_RUNNING;
00191                     realize_some_numerical_stat(main_struct, plugin);
00192                 }
00193             else
00194                 {
00195                     plugin->state = PLUGIN_STATE_NONE;
00196                 }
00197         }
00198 }
00199 
00200 
00201 /**
00202  * Sets stat window's button's sensitive property
00203  * @param xml : The plugin's xml description
00204  * @param sensitive : whether the buttons are greyed (FALSE) or not (TRUE)
00205  */
00206 static void set_statw_button_state(GtkBuilder *xml, gboolean sensitive)
00207 {
00208     if (xml != NULL)
00209     {
00210         gtk_widget_set_sensitive(heraia_get_widget(xml, "statw_save_as"), sensitive);
00211         gtk_widget_set_sensitive(heraia_get_widget(xml, "statw_export_to_csv"), sensitive);
00212         gtk_widget_set_sensitive(heraia_get_widget(xml, "statw_export_to_gnuplot"), sensitive);
00213         gtk_widget_set_sensitive(heraia_get_widget(xml, "statw_export_to_pcv"), sensitive);
00214     }
00215 }
00216 
00217 /**
00218  *  The refresh function is called when a new file is loaded or when the cursor is moved
00219  *  Here we want to refresh the plugin only if a new file is loaded AND if the plugin
00220  *  is already displayed (running)
00221  * @param main_struct : main structure
00222  * @param data : user data (the plugin itself) MUST be heraia_plugin_t *plugin
00223  *               structure
00224  */
00225 void refresh(heraia_struct_t *main_struct, void *data)
00226 {
00227     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00228 
00229     if (main_struct != NULL && plugin != NULL)
00230         {
00231             if (main_struct->event == HERAIA_REFRESH_NEW_FILE || main_struct->event == HERAIA_REFRESH_TAB_CHANGED) /* && plugin->state == PLUGIN_STATE_RUNNING) */
00232                 {
00233                     set_statw_button_state(plugin->xml, TRUE);
00234                     plugin->run_proc(NULL, (gpointer) main_struct);
00235                 }
00236         }
00237 }
00238 /* end of the plugin interface functions */
00239 
00240 
00241 /**
00242  *  Usefull functions for the stat plugin
00243  *  those may be included in an another .c source file ?!
00244  */
00245 
00246 /**
00247  * Closes stat window
00248  * @param widget : the widget which called this function
00249  * @param event : the event that issued the signal (unused here)
00250  * @param data : user data, MUST be heraia_plugin_t *plugin
00251  * @return resturns always FALSE (does not propagate the signal)
00252  */
00253 static gboolean delete_stat_window_event(GtkWidget *widget, GdkEvent  *event, gpointer data)
00254 {
00255     statw_close_clicked(widget, data);
00256 
00257     return TRUE;
00258 }
00259 
00260 
00261 /**
00262 
00263  * Closes stat window
00264  * @param widget : the widget which called this function
00265  * @param event : the event that issued the signal (unused here)
00266  * @param data : user data, MUST be heraia_plugin_t *plugin
00267  */
00268 static void destroy_stat_window(GtkWidget *widget, GdkEvent  *event, gpointer data)
00269 {
00270     statw_close_clicked(widget, data);
00271 }
00272 
00273 
00274 /**
00275  *  What to do when the window is closed
00276  * @param widget : the widget which called this function (unused here)
00277  * @param data : user data, MUST be heraia_plugin_t *plugin
00278  */
00279 static void statw_close_clicked(GtkWidget *widget, gpointer data)
00280 {
00281     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00282 
00283     if (plugin != NULL)
00284         {
00285             show_hide_widget(GTK_WIDGET(heraia_get_widget(plugin->xml, "stat_window")), FALSE, plugin->win_prop);
00286             gtk_check_menu_item_set_active(plugin->cmi_entry, FALSE);
00287         }
00288 }
00289 
00290 
00291 /**
00292  *  What to do when the save as button is clicked
00293  * @param widget : the widget which called this function (unused here)
00294  * @param data : user data, MUST be heraia_plugin_t *plugin
00295  */
00296 static void statw_save_as_clicked(GtkWidget *widget, gpointer data)
00297 {
00298     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00299     stat_t *extra = NULL;
00300     GtkImage *image = NULL;
00301     GdkPixbuf *pixbuf = NULL;
00302     gchar *filename = NULL;
00303     GError **error = NULL;
00304 
00305     if (plugin != NULL)
00306         {
00307             extra = (stat_t *) plugin->extra;
00308 
00309             image = GTK_IMAGE(heraia_get_widget(plugin->xml, "histo_image"));
00310             pixbuf = gtk_image_get_pixbuf(image);
00311 
00312             filename = stat_select_file_to_save("Enter filename's to save the image to", extra);
00313             if (filename != NULL)
00314             {
00315                 gdk_pixbuf_save(pixbuf, filename, "png", error, "compression", "9", NULL);
00316                 g_free(filename);
00317             }
00318         }
00319 }
00320 
00321 
00322 /**
00323  *  Selecting the file filename where to save the file
00324  * @param window_text : text to be displayed in the selection window
00325  * @return returns the new filename where to save a file
00326  */
00327 static gchar *stat_select_file_to_save(gchar *window_text, stat_t *extra)
00328 {
00329     GtkFileChooser *file_chooser = NULL;
00330     gint response_id = 0;
00331     gchar *filename;
00332 
00333     file_chooser = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new(window_text, NULL,
00334                                                                 GTK_FILE_CHOOSER_ACTION_SAVE,
00335                                                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
00336                                                                 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
00337                                                                 NULL));
00338 
00339     /* for the moment we do not want to retrieve multiples selections */
00340     gtk_window_set_modal(GTK_WINDOW(file_chooser), TRUE);
00341     gtk_file_chooser_set_select_multiple(file_chooser, FALSE);
00342     gtk_file_chooser_set_do_overwrite_confirmation(file_chooser, TRUE);
00343 
00344     /* If it exists define a new directory name */
00345     if (extra != NULL && extra->dirname != NULL)
00346         {
00347             gtk_file_chooser_set_current_folder(file_chooser, extra->dirname);
00348         }
00349 
00350     response_id = gtk_dialog_run(GTK_DIALOG(file_chooser));
00351 
00352     switch (response_id)
00353         {
00354             case GTK_RESPONSE_OK:
00355                 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser));
00356 
00357                 /* Saving directory name in order to use it at a later call */
00358                 if (filename != NULL)
00359                     {
00360                         if (extra->dirname != NULL)
00361                             {
00362                                 g_free(extra->dirname);
00363                             }
00364                         extra->dirname = g_path_get_dirname(filename);
00365                     }
00366 
00367                 break;
00368             case GTK_RESPONSE_CANCEL:
00369             default:
00370                 filename = NULL;
00371                 break;
00372         }
00373 
00374     gtk_widget_destroy(GTK_WIDGET(file_chooser));
00375     return filename;
00376 }
00377 
00378 
00379 /**
00380  * What to do when "export to csv" button is clicked
00381  * @param widget : the widget which called this function
00382  * @param data : user data, MUST be heraia_plugin_t *plugin
00383  */
00384 static void statw_export_to_csv_clicked(GtkWidget *widget, gpointer data)
00385 {
00386     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00387     stat_t *extra = NULL;
00388     gchar *filename = NULL;
00389     FILE *fp = NULL;
00390     guint i = 0;
00391     guint j = 0;
00392 
00393     if (plugin != NULL)
00394         {
00395             extra = (stat_t *) plugin->extra;
00396 
00397             filename = stat_select_file_to_save("Enter filename to export data as CSV to", extra);
00398 
00399             if (filename != NULL)
00400                 {
00401                     fp = g_fopen(filename, "w+");
00402                 }
00403 
00404             if (fp != NULL && extra != NULL)
00405                 {
00406                     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_1D"))) == TRUE)
00407                         {
00408                             /* 1D display */
00409                             fprintf(fp, "\"Byte\";\"Count\"\n");
00410 
00411                             for (i=0; i<=255; i++)
00412                                 {
00413                                     fprintf(fp, "%d;%Ld\n", i, extra->histo1D[i]);
00414                                 }
00415 
00416                         }
00417                     else
00418                     {
00419                         /* 2D display */
00420                         fprintf(fp, "\"Byte/Byte\";");
00421                         for (j=0; j<255; j++)
00422                             {
00423                                 fprintf(fp, "\"%d\";", j);
00424                             }
00425                         fprintf(fp, "\"%d\"\n", 255);
00426 
00427                         for (i=0; i<=255; i++)
00428                             {
00429                                 fprintf(fp, "\"%d\";", i);
00430                                 for (j=0 ; j<255; j++)
00431                                     {
00432                                         fprintf(fp, "\"%Ld\";", extra->histo2D[i][j]);
00433                                     }
00434                                 fprintf(fp, "\"%Ld\"\n", extra->histo2D[i][255]);
00435                             }
00436                     }
00437                     fclose(fp);
00438                 }
00439 
00440             if (filename != NULL)
00441                 {
00442                     g_free(filename);
00443                 }
00444         }
00445 }
00446 
00447 
00448 /**
00449  * What to do when "export to gnuplot" button is clicked
00450  * @param widget : the widget which called this function
00451  * @param data : user data, MUST be heraia_plugin_t *plugin
00452  */
00453 static void statw_export_to_gnuplot_clicked(GtkWidget *widget, gpointer data)
00454 {
00455     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00456     stat_t *extra = NULL;
00457     gchar *filename = NULL;
00458     FILE *fp = NULL;
00459     guint i = 0;
00460     guint j = 0;
00461 
00462     if (plugin != NULL)
00463         {
00464             extra = (stat_t *) plugin->extra;
00465 
00466             filename = stat_select_file_to_save("Enter filename to export data as gnuplot to", extra);
00467 
00468             if (filename != NULL)
00469                 {
00470                     fp = g_fopen(filename, "w+");
00471                 }
00472 
00473             if (fp != NULL && extra != NULL)
00474                 {
00475                     /* common settings */
00476                     fprintf(fp, "set terminal png transparent nocrop enhanced small size 1280,960\n");
00477                     fprintf(fp, "set output '%s.png'\n", g_path_get_basename(filename));
00478                     fprintf(fp, "set xrange [-10:265]\n");
00479                     fprintf(fp, "set xlabel 'Bytes'\n");
00480 
00481                     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_1D"))) == TRUE)
00482                         {
00483                             /* 1D display */
00484                             fprintf(fp, "set title 'Classical histogram'\n");  /**< @todo we might add here the name of the file being edited */
00485                             fprintf(fp, "set ylabel 'Count'\n");
00486                             fprintf(fp, "plot '-' title 'Byte count' with impulses\n");
00487 
00488                             for (i=0; i<=255; i++)
00489                                 {
00490                                     fprintf(fp, "%Ld\n", extra->histo1D[i]);
00491                                 }
00492                             fprintf(fp, "e\n");
00493                         }
00494                     else
00495                         {
00496                             /* 2D display */
00497                             fprintf(fp, "set title 'Heatmap histogram'\n");  /**< @todo we might add here the name of the file being edited */
00498                             fprintf(fp, "set bar 1.000000\n");
00499                             fprintf(fp, "set style rectangle back fc lt -3 fillstyle solid 1.00 border -1\n");
00500                             fprintf(fp, "unset key\n");
00501                             fprintf(fp, "set view map\n");
00502                             fprintf(fp, "set yrange [-10:265]\n");
00503                             fprintf(fp, "set ylabel 'Bytes'\n");
00504                             fprintf(fp, "set palette rgbformulae 36, 13, 15\n");
00505                             fprintf(fp, "splot '-' matrix with image\n");
00506 
00507                             for (i=0; i<=255; i++)
00508                                 {
00509                                     for (j=0; j<=255; j++)
00510                                         {
00511                                             fprintf(fp, "%Ld ", extra->histo2D[i][j]);
00512                                         }
00513                                     fprintf(fp, "\n");
00514                                 }
00515 
00516                             fprintf(fp, "e\n");
00517                             fprintf(fp, "e\n");
00518                         }
00519                     fclose(fp);
00520                 }
00521 
00522             if (filename != NULL)
00523                 {
00524                     g_free(filename);
00525                 }
00526         }
00527 }
00528 
00529 /**
00530  * What to do when "export to pcv" button is clicked
00531  * @param widget : the widget which called this function
00532  * @param data : user data, MUST be heraia_plugin_t *plugin
00533  */
00534 static void statw_export_to_pcv_clicked(GtkWidget *widget, gpointer data)
00535 {
00536     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00537     stat_t *extra = NULL;
00538     gchar *filename = NULL;
00539     FILE *fp = NULL;
00540     guint i = 0;
00541     guint j = 0;
00542 
00543     if (plugin != NULL)
00544         {
00545             extra = (stat_t *) plugin->extra;
00546 
00547             filename = stat_select_file_to_save("Enter filename to export data as PCV to", extra);
00548 
00549             if (filename != NULL)
00550                 {
00551                     fp = g_fopen(filename, "w+");
00552                 }
00553 
00554             if (fp != NULL && extra != NULL)
00555                 {
00556                     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_1D"))) == TRUE)
00557                         {
00558                             /* 1D display */
00559                             fprintf(fp, "header {\n");
00560                             fprintf(fp, "\theight = \"960\";\n");
00561                             fprintf(fp, "\twidth = \"1280\";\n");
00562                             fprintf(fp, "\ttitle = \"Classical histogram\";\n");
00563                             fprintf(fp, "}\n");
00564                             fprintf(fp, "axes {\n");
00565                             fprintf(fp, "\tinteger b [label=\"Bytes\"];\n");
00566                             fprintf(fp, "\tinteger c [label=\"Byte count\"];\n");
00567                             fprintf(fp, "}\n");
00568                             fprintf(fp, "data {\n");
00569 
00570                             for (i=0; i<=255; i++)
00571                                 {
00572                                     fprintf(fp, "\tb=\"%d\", c=\"%Ld\";\n", i, extra->histo1D[i]);
00573                                 }
00574                             fprintf(fp, "}\n");
00575                         }
00576                     else
00577                         {
00578                             /* 2D display */
00579                             fprintf(fp, "header {\n");
00580                             fprintf(fp, "\theight = \"960\";\n");
00581                             fprintf(fp, "\twidth = \"1280\";\n");
00582                             fprintf(fp, "\ttitle = \"Classical histogram\";\n");
00583                             fprintf(fp, "}\n");
00584                             fprintf(fp, "axes {\n");
00585                             fprintf(fp, "\tchar a [label=\"Bytes\"];\n");
00586                             fprintf(fp, "\tport c [label=\"Byte count\"];\n");
00587                             fprintf(fp, "\tchar b [label=\"Bytes\"];\n");
00588                             fprintf(fp, "}\n");
00589                             fprintf(fp, "data {\n");
00590 
00591                             for (i=0; i<=255; i++)
00592                                 {
00593                                     for (j=0; j<=255; j++)
00594                                         {
00595                                             if (extra->histo2D[i][j] == extra->infos_2D->max)
00596                                                 {
00597                                                     fprintf(fp, "\ta=\"%d\", c=\"%Ld\", b=\"%d\" [color=\"red\"];\n", i, extra->histo2D[i][j], j);
00598                                                 }
00599                                             else
00600                                                 {
00601                                                     if (extra->histo2D[i][j] == extra->infos_2D->min)
00602                                                         {
00603                                                             fprintf(fp, "\ta=\"%d\", c=\"%Ld\", b=\"%d\" [color=\"green\"];\n", i, extra->histo2D[i][j], j);
00604                                                         }
00605                                                     else
00606                                                         {
00607                                                             fprintf(fp, "\ta=\"%d\", c=\"%Ld\", b=\"%d\";\n", i, extra->histo2D[i][j], j);
00608                                                         }
00609                                                 }
00610                                         }
00611                                 }
00612                             fprintf(fp, "}\n");
00613                         }
00614                     fclose(fp);
00615                 }
00616 
00617             if (filename != NULL)
00618                 {
00619                     g_free(filename);
00620                 }
00621         }
00622 }
00623 
00624 
00625 /**
00626  *  What to do when the user chooses a 1D or 2D histo
00627  * @param widget : the widget which called this function (unused here)
00628  * @param data : user data, MUST be heraia_plugin_t *plugin
00629  */
00630 static void histo_radiobutton_toggled(GtkWidget *widget, gpointer data)
00631 {
00632     heraia_plugin_t *plugin = (heraia_plugin_t *) data;
00633 
00634     if (plugin != NULL)
00635         {
00636             GtkImage *image = GTK_IMAGE(heraia_get_widget(plugin->xml, "histo_image"));
00637             stat_t *extra = (stat_t *) plugin->extra;
00638 
00639             if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_1D"))) == TRUE)
00640                 {
00641                     gtk_image_set_from_pixbuf(image, extra->pixbuf_1D);
00642                 }
00643             else
00644                 {
00645                     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_2D"))) == TRUE)
00646                         {
00647                             gtk_image_set_from_pixbuf(image, extra->pixbuf_2D);
00648                         }
00649                 }
00650         }
00651 }
00652 
00653 
00654 /**
00655  *  Connects all the signals to the correct functions
00656  * @param plugin : main plugin structure
00657  */
00658 static void stat_window_connect_signals(heraia_plugin_t *plugin)
00659 {
00660 
00661     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "stat_window")), "delete_event",
00662                      G_CALLBACK(delete_stat_window_event), plugin);
00663 
00664     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "stat_window")), "destroy",
00665                      G_CALLBACK(destroy_stat_window), plugin);
00666 
00667     /* Close Button */
00668     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "statw_close_b")), "clicked",
00669                      G_CALLBACK(statw_close_clicked), plugin);
00670 
00671     /* RadioButton */
00672     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "rb_1D")), "toggled",
00673                      G_CALLBACK(histo_radiobutton_toggled), plugin);
00674 
00675     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "rb_2D")), "toggled",
00676                      G_CALLBACK(histo_radiobutton_toggled), plugin);
00677 
00678     /* Save As Button */
00679     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "statw_save_as")), "clicked",
00680                      G_CALLBACK(statw_save_as_clicked), plugin);
00681 
00682     /* CVS button */
00683     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "statw_export_to_csv")), "clicked",
00684                      G_CALLBACK(statw_export_to_csv_clicked), plugin);
00685 
00686     /* Gnuplot button */
00687     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "statw_export_to_gnuplot")), "clicked",
00688                      G_CALLBACK(statw_export_to_gnuplot_clicked), plugin);
00689 
00690     /* PCV button */
00691     g_signal_connect(G_OBJECT(heraia_get_widget(plugin->xml, "statw_export_to_pcv")), "clicked",
00692                      G_CALLBACK(statw_export_to_pcv_clicked), plugin);
00693 
00694     /* the toogle button is already connected to the run_proc function ! */
00695 }
00696 
00697 
00698 /**
00699  * Do some stats on the selected file (entire file is used)
00700  * @param main_struct : main structure from heraia
00701  * @param plugin : main plugin structure (the plugin itself in fact)
00702  */
00703 static void realize_some_numerical_stat(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00704 {
00705     struct stat *stat_buf;
00706     gchar buf[42];           /**< used for date printing */
00707     gchar *filename = NULL;
00708     stat_t *extra = NULL;
00709     GtkTextView *textview = GTK_TEXT_VIEW(heraia_get_widget(plugin->xml, "statw_textview"));
00710 
00711     if (main_struct != NULL && main_struct->current_doc != NULL)
00712         {
00713             filename = doc_t_document_get_filename(main_struct->current_doc);
00714         }
00715 
00716     if (filename != NULL)
00717         {
00718             log_message(main_struct, G_LOG_LEVEL_INFO, "Calculating stats on %s",  filename);
00719 
00720             stat_buf = (struct stat *) g_malloc0 (sizeof(struct stat));
00721             g_lstat(filename, stat_buf);
00722             if (S_ISREG(stat_buf->st_mode))
00723                 {
00724                     kill_text_from_textview(textview);
00725                     add_text_to_textview(textview, "File size : %Ld bytes\n\n", stat_buf->st_size);
00726                     ctime_r(&(stat_buf->st_mtime), buf);
00727                     add_text_to_textview(textview, "Last intern modification : %s", buf);
00728                     ctime_r(&(stat_buf->st_atime), buf);
00729                     add_text_to_textview(textview, "Last acces to the file   : %s", buf);
00730                     ctime_r(&(stat_buf->st_ctime), buf);
00731                     add_text_to_textview(textview, "Last extern modification : %s", buf);
00732 
00733                     populate_stats_histos(main_struct, plugin);
00734 
00735                     extra = (stat_t *) plugin->extra;
00736 
00737                     add_text_to_textview(textview, "\n1D histogram statistics :\n");
00738                     add_text_to_textview(textview, "     . minimum          : %lld\n", extra->infos_1D->min);
00739                     add_text_to_textview(textview, "     . maximum          : %lld\n", extra->infos_1D->max);
00740                     add_text_to_textview(textview, "     . mean             : %lld\n", extra->infos_1D->mean);
00741                     add_text_to_textview(textview, "     . number of values : %lld\n", extra->infos_1D->nb_val);
00742                     add_text_to_textview(textview, "\n2D histogram statistics :\n");
00743                     add_text_to_textview(textview, "     . minimum          : %lld\n", extra->infos_2D->min);
00744                     add_text_to_textview(textview, "     . maximum          : %lld\n", extra->infos_2D->max);
00745                     add_text_to_textview(textview, "     . mean             : %lld\n", extra->infos_2D->mean);
00746                     add_text_to_textview(textview, "     . number of values : %lld\n", extra->infos_2D->nb_val);
00747                     log_message(main_struct, G_LOG_LEVEL_INFO, "Histos calculated !");
00748                 }
00749         }
00750 }
00751 
00752 
00753 /**
00754  *  Inits the histograms
00755  */
00756 static void init_stats_histos(heraia_plugin_t *plugin)
00757 {
00758     guint i = 0;
00759     guint j = 0;
00760     stat_t *extra = NULL;
00761 
00762     /* inits the structures */
00763     extra = (stat_t *) plugin->extra;
00764     for (i=0; i<=255; i++)
00765         {
00766             extra->histo1D[i] = 0 ;
00767             for (j=0; j<=255; j++)
00768                 extra->histo2D[i][j] = 0 ;
00769         }
00770 }
00771 
00772 
00773 /**
00774  *  Populates the histograms
00775  */
00776 static void populate_stats_histos(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00777 {
00778     Heraia_Hex *gh = GTK_HEX(main_struct->current_doc->hex_widget);
00779     guint64 i = 0;
00780     guint64 taille = ghex_file_size(gh);
00781     guchar c1, c2;
00782     stat_t *extra = (stat_t *) plugin->extra;
00783     GtkImage *image = GTK_IMAGE(heraia_get_widget(plugin->xml, "histo_image"));
00784     GtkToggleButton *rb_1D = GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_1D"));
00785     GtkToggleButton *rb_2D = GTK_TOGGLE_BUTTON(heraia_get_widget(plugin->xml, "rb_2D"));
00786 
00787     init_stats_histos(plugin);
00788 
00789     while (i < taille)
00790         {
00791             c1 = gtk_hex_get_byte(gh, i);
00792             extra->histo1D[c1]++;
00793             if (i+1 < taille)
00794                 {
00795                     i++;
00796                     c2 = gtk_hex_get_byte(gh, i);
00797                     extra->histo1D[c2]++;
00798                     extra->histo2D[c1][c2]++;
00799                 }
00800             i++;
00801         }
00802 
00803     make_pixbufs_from_histos(extra);
00804 
00805     if (gtk_toggle_button_get_active(rb_1D) == TRUE)
00806         {
00807             gtk_image_set_from_pixbuf(image, extra->pixbuf_1D);
00808         }
00809     else
00810         {
00811             if (gtk_toggle_button_get_active(rb_2D) == TRUE)
00812                 {
00813                     gtk_image_set_from_pixbuf(image, extra->pixbuf_2D);
00814                 }
00815         }
00816 }
00817 
00818 
00819 /**
00820  *  Seeks the histo1D struct to find the maximum value
00821  */
00822 static void calc_infos_histo_1D(stat_t *extra)
00823 {
00824     guint i = 0;
00825     gint64 n = 1;
00826     guint64 max = 0;
00827     guint64 min = G_MAXUINT64;
00828     gint64 mean = extra->histo1D[0];
00829     gint64 diff = 0;
00830 
00831     extra->infos_1D->nb_val = 0;
00832 
00833     for (i=0; i<=255; i++)
00834         {
00835             /* maximum value */
00836             if (extra->histo1D[i] > max)
00837                 max = extra->histo1D[i];
00838 
00839             /* minimum value */
00840             if (extra->histo1D[i] < min)
00841                 min = extra->histo1D[i];
00842 
00843             /* number of different values */
00844             if (extra->histo1D[i] > 0)
00845                 extra->infos_1D->nb_val++;
00846 
00847             /* mean calculation */
00848             diff = extra->histo1D[i] - mean;
00849             mean = mean + diff/n;
00850             n++;
00851         }
00852 
00853     extra->infos_1D->min = min;
00854     extra->infos_1D->max = max;
00855     extra->infos_1D->mean = (guint64) mean;
00856 }
00857 
00858 
00859 /**
00860  *  Seeks the histo2D struct to find the maximum value
00861  */
00862 static void calc_infos_histo_2D(stat_t *extra)
00863 {
00864     guint i = 0;
00865     guint j = 0;
00866     gint64 n = 1;
00867     guint64 max = 0;
00868     guint64 min = G_MAXUINT;
00869     gint64 mean = extra->histo2D[0][0];
00870     gint64 diff = 0;
00871 
00872     extra->infos_2D->nb_val = 0;
00873 
00874     for (i=0; i<=255; i++)
00875         {
00876             for (j=0; j<=255; j++)
00877                 {
00878                     /* maximum value */
00879                     if (extra->histo2D[i][j] > max)
00880                         max = extra->histo2D[i][j];
00881 
00882                     /* minimum value */
00883                     if (extra->histo2D[i][j] < min)
00884                         min = extra->histo2D[i][j];
00885 
00886                     /* number of different values */
00887                     if (extra->histo2D[i][j] > 0)
00888                         extra->infos_2D->nb_val++;
00889 
00890                     /* mean calculation */
00891                     diff = extra->histo2D[i][j] - mean;
00892                     mean = mean + diff/n;
00893                     n++;
00894                 }
00895         }
00896 
00897     extra->infos_2D->min = min;
00898     extra->infos_2D->max = max;
00899     extra->infos_2D->mean = (guint64) mean;
00900 }
00901 
00902 
00903 /**
00904  *  Inits the image buffers
00905  */
00906 static void init_stats_pixbufs(stat_t *extra)
00907 {
00908 
00909     extra->pixbuf_1D = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 255, 255);
00910     gdk_pixbuf_fill(extra->pixbuf_1D, 0xFFFFFF00);
00911     gdk_pixbuf_add_alpha(extra->pixbuf_1D, TRUE, (guchar) 255, (guchar) 255, (guchar) 255);
00912 
00913     extra->pixbuf_2D = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 255, 255);
00914     gdk_pixbuf_fill(extra->pixbuf_2D, 0xFFFFFF00);
00915     gdk_pixbuf_add_alpha(extra->pixbuf_2D, TRUE, (guchar) 255, (guchar) 255, (guchar) 255);
00916 
00917 }
00918 
00919 
00920 /**
00921  *  Makes the pixbufs from the histograms values
00922  */
00923 static void make_pixbufs_from_histos(stat_t *extra)
00924 {
00925     init_stats_pixbufs(extra);
00926     calc_infos_histo_1D(extra);
00927     calc_infos_histo_2D(extra);
00928 
00929     if (extra->infos_1D->max > 0)
00930         {
00931             do_pixbuf_1D_from_histo1D(extra);
00932         }
00933 
00934     if (extra->infos_2D->max > 0)
00935         {
00936             do_pixbuf_2D_from_histo2D(extra, extra->infos_2D->max);
00937         }
00938 }
00939 
00940 
00941 /**
00942  *  Prints a pixel in the corresponding pixbuf
00943  */
00944 static void plot_in_pixbuf(GdkPixbuf *pixbuf, gint64 x, gint64 y, guchar red, guchar green, guchar blue, guchar alpha)
00945 {
00946   guchar *pixels = NULL;
00947   guchar *p = NULL;
00948 
00949   pixels = gdk_pixbuf_get_pixels(pixbuf);
00950 
00951   p = pixels + y * gdk_pixbuf_get_rowstride(pixbuf) + x * gdk_pixbuf_get_n_channels(pixbuf);
00952 
00953   p[0] = red;
00954   p[1] = green;
00955   p[2] = blue;
00956   p[3] = alpha;
00957 
00958 }
00959 
00960 
00961 /**
00962  *  Prints a line of pixels in the corresponding pixbuf (1D histo)
00963  */
00964 static void line_in_pixbuf(GdkPixbuf *pixbuf, gint64 x, gint64 y)
00965 {
00966     guchar *pixels = NULL;
00967     guchar *p = NULL;
00968 
00969     if (pixbuf != NULL)
00970         {
00971 
00972             gint rowstride = gdk_pixbuf_get_rowstride(pixbuf);
00973             gint n_channels = gdk_pixbuf_get_n_channels(pixbuf);
00974 
00975             pixels = gdk_pixbuf_get_pixels(pixbuf);
00976 
00977             while (y<255)
00978                 {
00979                     p = pixels + y * rowstride + x * n_channels;
00980                     p[0] = (guchar) 255-(y/2);
00981                     p[1] = (guchar) 16;
00982                     p[2] = (guchar) y/2;
00983                     p[3] = (guchar) 255;
00984                     y++;
00985                 }
00986         }
00987 }
00988 
00989 
00990 /**
00991  *  Fills the pixbuf with the corresponding data from the
00992  *  histo1D struct
00993  */
00994 static void do_pixbuf_1D_from_histo1D(stat_t *extra)
00995 {
00996     guint i = 0;
00997     gint64 y = 0;
00998     gdouble inter = 0;
00999     gdouble y_norm = 0;
01000 
01001     for (i=0; i<=255; i++)
01002         {
01003             /* normalisation (here we know that max != 0 (cf make_pixbufs_from_histos) */
01004             y_norm = (gdouble) extra->infos_1D->max - (gdouble) extra->histo1D[i];
01005             inter = (gdouble) (y_norm*255) / (gdouble)(extra->infos_1D->max);
01006             y = (gint64) inter;
01007             line_in_pixbuf(extra->pixbuf_1D, i, y);
01008         }
01009 }
01010 
01011 
01012 /**
01013  *  Fills the pixbuf with the corresponding data from the
01014  *  histo2D struct
01015  *  It is really hard to make something very visible (to make colors
01016  *  look really different between to height values)
01017  */
01018 static void do_pixbuf_2D_from_histo2D(stat_t *extra, guint max_2D)
01019 {
01020     /* A sort of color 'normalization' */
01021     guint i = 0;
01022     guint j = 0;
01023     guchar red;
01024     guchar green;
01025     guchar blue;
01026     gdouble height = 0;
01027     gdouble max = 0;
01028     gdouble min = 0;
01029     gdouble mean = 0;
01030     gdouble threshold1 = 0;
01031     gdouble threshold2 = 0;
01032     guchar ceill;
01033     guchar floor;
01034 
01035     max = extra->infos_2D->max;
01036     min = extra->infos_2D->min;
01037     mean = extra->infos_2D->mean;
01038 
01039     threshold1 = min + (mean - min) / 2;
01040     threshold2 = mean + (max - mean) / 2;
01041 
01042     floor = (guchar) 50;
01043     ceill = (guchar) 200;
01044 
01045     for (i=0; i<=255; i++)
01046         {
01047             for (j=0; j<=255; j++)
01048                 {
01049                     height = extra->histo2D[i][j];  /* min .. max */
01050 
01051                     if (height > 0)
01052                         {
01053 
01054                             if (height >= min && height <= threshold1)
01055                                 {
01056                                     red = floor;
01057                                     green = floor;
01058                                     blue = (guchar) (height - min)*(ceill-floor) / threshold1;
01059                                     /*
01060                                      * height = (gdouble) (height*255) / (gdouble) extra->infos_2D->max;
01061                                      * red = (guchar)  height;
01062                                      * green = (guchar) 255 - (height);
01063                                      * blue = (guchar) height/2;
01064                                      */
01065                                     plot_in_pixbuf(extra->pixbuf_2D, i, 255-j, red, green, blue, (guchar) 255);
01066                                 }
01067                             else if (height > threshold1 && height <= threshold2)
01068                                 {
01069                                     red = (guchar) floor;
01070                                     green = (guchar) (height - threshold1)*(ceill-floor) / (threshold2 - threshold1);
01071                                     blue = (guchar) floor; /* ceill - green;*/
01072                                     plot_in_pixbuf(extra->pixbuf_2D, i, 255-j, red, green, blue, (guchar) 255);
01073                                 }
01074                             else if (height > threshold2 && height <= max)
01075                                 {
01076                                     red = (guchar) (height - threshold2)*(ceill-floor) / (max - threshold2);
01077                                     green = floor; /* ceill - red; */
01078                                     blue = floor;
01079                                     /*
01080                                      * height = (gdouble) height*255 / (gdouble) extra->infos_2D->max;
01081                                      * red = (guchar)  255 - (height);
01082                                      * green = (guchar) height/2;
01083                                      * blue = (guchar) height;
01084                                      */
01085                                     plot_in_pixbuf(extra->pixbuf_2D, i, 255-j, red, green, blue, (guchar) 255);
01086                                 }
01087                         }
01088                 }
01089         }
01090 }
01091 
01092 
Generated on Tue May 11 18:46:08 2010 for Heraia by  doxygen 1.6.3