From fd035a5492a1d7b6c9ab29802fb70086b27140dd Mon Sep 17 00:00:00 2001
From: Arnaud Blanchard <arnaud.blanchard@ensea.fr>
Date: Thu, 27 Jul 2017 15:34:02 +0200
Subject: [PATCH] - Add option min and max - Fix histogram for Y800 FL32 -
 Separate image code from histogram code

---
 check.sh                          |  19 --
 o_gtk_image/CMakeLists.txt        |   2 +-
 o_gtk_image/src/common.h          |  34 +++
 o_gtk_image/src/histogram.cpp     | 222 +++++++++++++++++++
 o_gtk_image/src/image_display.cpp | 351 +++++-------------------------
 o_gtk_image/src/image_display.hpp |  10 -
 o_gtk_image/src/o_gtk_image.cpp   |  57 +++--
 o_gtk_image/src/o_gtk_image.hpp   |  18 --
 8 files changed, 346 insertions(+), 367 deletions(-)
 delete mode 100755 check.sh
 create mode 100644 o_gtk_image/src/common.h
 create mode 100644 o_gtk_image/src/histogram.cpp
 delete mode 100644 o_gtk_image/src/image_display.hpp
 delete mode 100644 o_gtk_image/src/o_gtk_image.hpp

diff --git a/check.sh b/check.sh
deleted file mode 100755
index 7072e99..0000000
--- a/check.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright  ETIS — ENSEA, Université de Cergy-Pontoise, CNRS (2011 - 2016)
-# Author: Arnaud Blanchard (November 2016)
-# This software is governed by the CeCILL v2.1 license under French law and abiding by the rules of distribution of free software.
-# You can use, modify and/ or redistribute the software under the terms of the CeCILL v2.1 license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info".
-# As a counterpart to the access to the source code and  rights to copy, modify and redistribute granted by the license,
-# users are provided only with a limited warranty and the software's author, the holder of the economic rights,  and the successive licensors have only limited liability.
-# In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or developing or reproducing the software by the user in light of its specific status of free software,
-# that may mean  that it is complicated to manipulate, and that also therefore means that it is reserved for developers and experienced professionals having in-depth computer knowledge.
-# Users are therefore encouraged to load and test the software's suitability as regards their requirements in conditions enabling the security of their systems and/or data to be ensured  and, more generally, to use and operate it in the same conditions as regards security.
-# The fact that you are presently reading this means that you have had knowledge of the CeCILL v2.1 license and that you accept its terms.
-
-
-cd `dirname $0`
-echo
-echo "Checking `basename $PWD`"
-echo "===================="
-echo
-echo "No check for now"
-echo 
diff --git a/o_gtk_image/CMakeLists.txt b/o_gtk_image/CMakeLists.txt
index 0234672..f57f750 100644
--- a/o_gtk_image/CMakeLists.txt
+++ b/o_gtk_image/CMakeLists.txt
@@ -18,7 +18,7 @@ add_definitions(-Wall ${BL_DEFINITIONS} -Wno-deprecated-declarations) #device_ma
 include_directories(${GTK3_INCLUDE_DIRS} ${BL_INCLUDE_DIRS} ${JPEG_INCLUDE_DIR})
 link_directories(${GTK3_LIBRARY_DIRS})
 add_definitions(${GTK3_CFLAGS_OTHER})
-add_executable(o_gtk_image src/o_gtk_image.cpp src/image_display.cpp)
+add_executable(o_gtk_image src/o_gtk_image.cpp src/image_display.cpp src/histogram.cpp)
 target_link_libraries(o_gtk_image ${GTK3_LIBRARIES} ${BL_LIBRARIES} ${JPEG_LIBRARIES} )
 
 
diff --git a/o_gtk_image/src/common.h b/o_gtk_image/src/common.h
new file mode 100644
index 0000000..ae24106
--- /dev/null
+++ b/o_gtk_image/src/common.h
@@ -0,0 +1,34 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <gtk/gtk.h>
+#include <blc_channel.h>
+
+
+extern float min, max;
+
+extern blc_channel *channel;
+extern GtkWidget *legend;
+
+extern u_int32_t false_colors[256];
+extern uint32_t gray_colors[256];
+extern uint32_t u_colors[256];
+extern uint32_t v_colors[256];
+extern uint32_t r_colors[256];
+extern uint32_t g_colors[256];
+extern uint32_t b_colors[256];
+extern uint32_t *color_map;
+
+extern GtkWidget *paned;
+extern GdkDevice *pointer_device;
+extern blc_channel mouse_channel;
+
+extern char const *fullscreen_option;
+
+
+
+void histogram_cb(GtkToolButton *toolbutton, gpointer pointer_statusbar );
+GtkWidget *create_image_display(blc_channel *channel);
+
+#endif
+
diff --git a/o_gtk_image/src/histogram.cpp b/o_gtk_image/src/histogram.cpp
new file mode 100644
index 0000000..b1e496f
--- /dev/null
+++ b/o_gtk_image/src/histogram.cpp
@@ -0,0 +1,222 @@
+#include "common.h"
+
+#include "blgtk.h"
+
+#include <fcntl.h> // O_RDONLY ...
+#include <stdio.h>
+#include <gtk/gtk.h>
+#include <string.h>
+#include <stdint.h> //uint32_t
+#include <jpeglib.h>
+#include <sys/mman.h>
+#include <errno.h> //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;
+GtkWidget *histogram_image, *histogram, *histogram_scrolled_window;
+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 (channel->format){
+        case 'Y800':
+            switch (channel->type){
+                case 'UIN8':
+                    FOR(i, channel->size) histogram[channel->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)channel->size);
+                        gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text);
+                    }
+                    break;
+                case 'FL32':
+                    FOR(i, channel->total_length) histogram[(int)CLIP_UCHAR(((channel->floats[i]-min)/(max-min)*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-min-0.5)/256+min, histogram[x]*100/(float)channel->total_length);
+                        gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text);
+                    }
+                    break;
+                default: EXIT_ON_ARRAY_ERROR( channel, "Type not managed for format 'Y800'. Only 'UIN8' is");
+            }
+            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)
+        {
+            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)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)
+        {
+            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)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)
+        {
+            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)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);
+    return G_SOURCE_CONTINUE;
+}
+
+
+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);
+}
+
+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);
+        label=gtk_label_new(text);
+        gtk_box_pack_start(GTK_BOX(legend_box), label, FALSE, FALSE, 0);
+        SPRINTF(text, "%f", 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;
+    }
+}
diff --git a/o_gtk_image/src/image_display.cpp b/o_gtk_image/src/image_display.cpp
index 677338f..f06427b 100644
--- a/o_gtk_image/src/image_display.cpp
+++ b/o_gtk_image/src/image_display.cpp
@@ -1,7 +1,5 @@
-#include "image_display.hpp"
-
+#include "common.h"
 #include "blgtk.h"
-#include "o_gtk_image.hpp"
 
 #include <fcntl.h> // O_RDONLY ...
 #include <stdio.h>
@@ -22,10 +20,7 @@ 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;
@@ -33,28 +28,26 @@ 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;
+GtkWidget *image;
+
 static uchar *image_buffer;
 
-pthread_t init_table_thread;
+static pthread_t init_table_thread;
 double zoom_in_factor=2, zoom_out_factor=0.5;
 
+GtkWidget *legend=NULL;
+
 static int width=0, height=0;
-static blc_channel *channel;
+blc_channel *channel=NULL;
 
 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) )
 
@@ -70,7 +63,6 @@ static void toggle_fullscreen(GtkWidget *widget, GdkEventWindowState *event, gpo
     }
 }
 
-
 void* create_RGBA_from_YUYV(void *widget)
 {
     int Y, Cb, Cr;
@@ -79,11 +71,9 @@ void* create_RGBA_from_YUYV(void *widget)
     static uchar  R[256], B;
     (void)widget;
     
-    if (RGBA_from_YUYV == NULL)
-    {
+    if (RGBA_from_YUYV == NULL){
         RGBA_from_YUYV= MANY_ALLOCATIONS(256*256*256, uint32_t);
-        FOR_INV(Y, 256)
-        {
+        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)
             {
@@ -149,16 +139,20 @@ static void init_color_maps(){
 /** 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, ret=-1;
+    float gain;
+    int i, x, y, j;
     double sx, sy;
     uint32_t *values;
     char text[64];
     
-    if (blc_command_loop_start()){;
-        
+    gain=1/(max-min);
+    
+    if (blc_command_loop_start()){
         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)];
+        if (channel->type=='UIN8')
+            FOR(i, channel->size) values[i]=color_map[channel->uchars[i]];
+        else if (channel->type=='FL32')
+            FOR(i, channel->total_length) values[i]=color_map[CLIP_UCHAR((channel->floats[i]-min)*256*gain-0.5f)];
         else EXIT_ON_ARRAY_ERROR(channel, "Type not managed");
         gtk_image_set_from_surface(image, image_surface);
         
@@ -166,18 +160,15 @@ gboolean update_Y800_image(GtkImage *image, GdkFrameClock *, gpointer pointer_st
         cairo_surface_get_device_scale(image_surface, &sx, &sy);
         i=x*sx;
         j=y*sy;
-        if (i<width && j<height && i>=0 && j>=0)
-        {
+        if (i<width && j<height && 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 G_SOURCE_CONTINUE;
-        
     } else exit(EXIT_SUCCESS);
+    return G_SOURCE_CONTINUE;
 }
 
 gboolean update_RGB3_image(GtkImage *image, GdkFrameClock *, gpointer pointer_statusbar)
@@ -187,45 +178,43 @@ gboolean update_RGB3_image(GtkImage *image, GdkFrameClock *, gpointer pointer_st
     int x, y, i=0, j=0;
     int R, G, B;
     
-    if (blc_command_loop_start()==0) exit(0);
-    
-    
-    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<width && j<height && 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]));
+    if (blc_command_loop_start()){
+        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;
         }
         
-        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);
+        i=x*sx;
+        j=y*sy;
         
-        gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text);
+        if (i<width && j<height && 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++;
+        blc_command_loop_end();
     }
-    gtk_image_set_from_surface(image, image_surface);
-    iterations++;
-    blc_command_loop_end();
-    
+    else exit (EXIT_SUCCESS);
     return G_SOURCE_CONTINUE;
+    
 }
 
 gboolean update_RGBA_image(GtkImage *image, GdkFrameClock *, gpointer pointer_statusbar)
@@ -245,10 +234,8 @@ gboolean update_RGBA_image(GtkImage *image, GdkFrameClock *, gpointer pointer_st
     i=x*sx;
     j=y*sy;
     
-    if (i<width && j<height && i>=0 && j>=0)
-    {
-        if (mouse_channel.fd!=-1)
-        {
+    if (i<width && j<height && 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]));
@@ -425,141 +412,7 @@ gboolean update_yuv2_image(GtkImage *image, GdkFrameClock *, gpointer pointer_st
     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)
 {
@@ -570,12 +423,7 @@ static void gtk_image_resize_cb(GtkWidget *image,  GdkRectangle *allocation, gpo
     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)
 {
@@ -599,52 +447,6 @@ static void zoom_cb(GtkToolButton *toolbutton, double *factor)
     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;
@@ -679,47 +481,6 @@ static void false_color_cb(GtkToolButton *toolbutton, struct  update_cb *){
     }
 }
 
-
-
-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];
@@ -745,7 +506,7 @@ GtkWidget *create_image_display(blc_channel *tmp_channel)
     
     blc_loop_try_add_posting_semaphore(channel->sem_ack_data);
     blc_loop_try_add_waiting_semaphore(channel->sem_new_data);
-
+    
     blc_command_loop_init(0);
     switch (channel->format)
     {
diff --git a/o_gtk_image/src/image_display.hpp b/o_gtk_image/src/image_display.hpp
deleted file mode 100644
index e336842..0000000
--- a/o_gtk_image/src/image_display.hpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef BYTE_DISPLAY_H
-#define BYTE_DISPLAY_H
-
-#include <gtk/gtk.h>
-#include <blc_channel.h>
-
-
-GtkWidget *create_image_display(blc_channel *channel);
-
-#endif
\ No newline at end of file
diff --git a/o_gtk_image/src/o_gtk_image.cpp b/o_gtk_image/src/o_gtk_image.cpp
index fe2fb72..246c36a 100644
--- a/o_gtk_image/src/o_gtk_image.cpp
+++ b/o_gtk_image/src/o_gtk_image.cpp
@@ -1,4 +1,4 @@
-#include "o_gtk_image.hpp"
+#include "common.h"
 
 #include <fcntl.h> // O_RDONLY ...
 #include <stdio.h>
@@ -10,8 +10,7 @@
 #include <errno.h> //errno
 #include "blc_core.h"
 #include "blc_program.h"
-
-#include "image_display.hpp"
+float min, max;
 
 const char *channel_name, *fullscreen_option, *keyboard_mode;
 GtkWidget *window;
@@ -43,7 +42,7 @@ void ask_quit()
 }
 
 void on_key_press(GtkWidget	     *widget, GdkEventKey	     *event){
-
+    
     char key;
     
     if (event->type == GDK_KEY_PRESS){
@@ -53,10 +52,8 @@ void on_key_press(GtkWidget	     *widget, GdkEventKey	     *event){
     }
 }
 
-
 void activate_cb(GApplication *app)
 {
-    char tmp_title[NAME_MAX*2+1];
     GtkWidget *display=NULL;
     GtkWidget *grid;
     
@@ -65,19 +62,18 @@ void activate_cb(GApplication *app)
     pointer_device = gdk_device_manager_get_client_pointer (device_manager);
     
     window=gtk_application_window_new(GTK_APPLICATION(app));
-    SPRINTF(tmp_title, "%s", blc_program_name);
-    gtk_window_set_title(GTK_WINDOW(window), tmp_title);
+    gtk_window_set_title(GTK_WINDOW(window), input.name);
     
     grid=gtk_grid_new();
     
-  //  for(i=0; input_names[i]; i++){ This is for displaying multiple images
-      //  input=new blc_channel(/*input_names[i]*/ input_name, BLC_CHANNEL_READ);
-        display=create_image_display(&input);
-        if (display==NULL) EXIT_ON_CHANNEL_ERROR(&input, "Format not managed.");
-        gtk_widget_set_hexpand(display, 1);
-        gtk_widget_set_vexpand(display, 1);
-        gtk_container_add(GTK_CONTAINER(grid), display);
-  //  }
+    //  for(i=0; input_names[i]; i++){ This is for displaying multiple images
+    //  input=new blc_channel(/*input_names[i]*/ input_name, BLC_CHANNEL_READ);
+    display=create_image_display(&input);
+    if (display==NULL) EXIT_ON_CHANNEL_ERROR(&input, "Format not managed.");
+    gtk_widget_set_hexpand(display, 1);
+    gtk_widget_set_vexpand(display, 1);
+    gtk_container_add(GTK_CONTAINER(grid), display);
+    //  }
     gtk_container_add(GTK_CONTAINER(window), grid);
     gtk_widget_show_all(window);
     if (keyboard_mode) g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK (on_key_press), NULL);
@@ -90,24 +86,37 @@ void activate_cb(GApplication *app)
 int main(int argc, char *argv[])
 {
     int status=0;
-    char const *g_debug, *mouse_name;
+    char const *g_debug, *mouse_name, *min_str, *max_str;
     blc_channel channel_info;
     
     blc_program_set_description("Display the content of the blc_channel depending on its type on format");
     blc_program_add_option(&keyboard_mode, 'k', "keyboard", NULL, "Send keyboard input to stdout", NULL);
-    blc_program_add_option(&mouse_name, 'm', "mouse", "blc_channel-out", "return the mouse coordinates  and status in the channel", NULL);
+    blc_program_add_option(&min_str, 'm', "min", "FL32", "minimal value", NULL);
+    blc_program_add_option(&max_str, 'M', "max", "FL32", "maximal value", NULL);
+    //  blc_program_add_option(&mouse_name, 'm', "mouse", "blc_channel-out", "return the mouse coordinates  and status in the channel", NULL);
     blc_program_add_option(&fullscreen_option, 'F', "fullscreen", NULL, "Set the window in fullscreen", NULL);
     blc_program_add_option(&g_debug, ' ', "g-fatal-warnings", NULL, "Debug gtk.", NULL);
- // This function is not yer operaiotnal  blc_program_add_multiple_parameters(&input_names, "blc_channel", 1, "channel name you want to display");
+    // This function is not yer operaiotnal  blc_program_add_multiple_parameters(&input_names, "blc_channel", 1, "channel name you want to display");
     blc_program_add_parameter(&input_name, "blc_channel-in", 1, "channel name you want to display", NULL);
     
     blc_program_init(&argc, &argv, ask_quit);
     
     input.open(input_name, mode);
-   /*
-    while (sem_trywait(input.sem_ack_data)==0);
-    while (sem_trywait(input.sem_new_data)==0);
-*/
+    
+    min=0;
+    if (input.type=='UIN8') max=256;
+    if (input.type=='INT8'){
+        min=-128;
+        max=128;
+    }
+    
+    
+    if (input.type=='FL32' && input.format=='Y800'){
+        if (min_str) SSCANF(1, min_str, "%f", &min);
+        else min=0;
+        if (max_str) SSCANF(1, max_str, "%f", &max);
+        else max=1;
+    }else if (min_str || max_str) EXIT_ON_ARRAY_ERROR(&input, "Min (-m) and max (-M) have only effect for type FL32 format Y800");
     
     gtk_disable_setlocale();
     gtk_init(&argc, &argv);
@@ -116,6 +125,6 @@ int main(int argc, char *argv[])
     status = g_application_run(G_APPLICATION(app), 0, NULL);
     g_object_unref(app);
     
-    return (status);
+    return EXIT_SUCCESS;
 }
 
diff --git a/o_gtk_image/src/o_gtk_image.hpp b/o_gtk_image/src/o_gtk_image.hpp
deleted file mode 100644
index bd41e82..0000000
--- a/o_gtk_image/src/o_gtk_image.hpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef MAIN_HPP
-#define MAIN_HPP
-
-#include <gtk/gtk.h>
-#include <blc_channel.h>
-
-extern GtkWidget *window;
-extern GdkDisplay *main_display;
-extern GdkDevice *pointer_device;
-extern GtkApplication *app;
-extern blc_channel mouse_channel;
-
-extern int interactive_mode;
-extern uint32_t format;
-extern char const *fullscreen_option;
-
-void quit();
-#endif
\ No newline at end of file
-- 
GitLab