Commit 11324484 authored by Arnaud Blanchard's avatar Arnaud Blanchard
Browse files

Modern version of blc

parent 539bc0b8
......@@ -6,7 +6,6 @@ project(c_gtk_image)
#This is to be able to debug and recompile automatically the libs (shared_blc). It is slower, you can remove this line and use : ${BLAR_BUILD_DIR}/lib/libblc.dylib instead of shared_blc
find_package(blc REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
find_package(JPEG REQUIRED)
......
#include "blc.h"
#include "network_display.h"
#include <string>
#include "Display.hpp"
using namespace std;
Tcp4ClientDisplay::Tcp4ClientDisplay(string const &address, string const &port):blc_array_tcp4_client(address, port){
}
gboolean refresh_screen_callback(GtkWidget *widget, GdkFrameClock *frame_clock, Tcp4ClientDisplay* client){
char text[64];
int x, y, i, j;
double x_scale, y_scale;
if (blc_command_loop_start()){
client->recv_data();
client->display->update();
return G_SOURCE_CONTINUE;
}
else exit(EXIT_SUCCESS);
}
#ifndef NETWORK_DISPLAY_H
#define NETWORK_DISPLAY_H
#include <gtk/gtk.h>
#include <blc_array_network.h>
#include "Display.hpp"
class Tcp4ClientDisplay:public blc_array_tcp4_client{
public:
Tcp4ClientDisplay(std::string const &address, std::string const &port);
std::unique_ptr<Display> display;
};
#endif
......@@ -27,7 +27,6 @@ public:
/** set pointer position (i, j) in the window. return false if the pointer is not in the window. */
bool get_pointer_position(int &i, int &j);
/** Display the new image with the content array.*/
virtual void update()=0;
......
#ifndef COMMON_H
#define COMMON_H
#include <gtk/gtk.h>
#include <blc.h>
#include <image_display.h>
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 *window, *paned;
extern GdkDevice *pointer_device;
extern blc_array mouse_array;
extern char const *fullscreen_option;
void histogram_cb(GtkToolButton *toolbutton, gpointer pointer_statusbar );
GtkWidget *create_image_display(blc_array *array);
#endif
#include "common.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;
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;
}
}
#include "common.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
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;
int iterations=0;
int colors_initilized = 0;
int mouse_image_x, mouse_image_y;
cairo_surface_t *legend_surface, *image_surface;
gulong pointer_value_handler;
GtkWidget *paned;
static uint32_t *RGBA_from_YUYV = NULL;
static GtkWidget *vbox, *scrolled_window, *event_box, *toolbar, *general_statusbar;
static GtkWidget *zoom_button, *false_colors_button, *histogram_button;
GtkWidget *image;
static uchar *image_buffer;
static pthread_t init_table_thread;
double zoom_in_factor=2, zoom_out_factor=0.5;
static int width=0, height=0;
blc_array *array=NULL;
static int g_source_continue=G_SOURCE_CONTINUE;
#define SWAP_RGBA_TO_CAIRO_ARGB32(x) ((((x) & 0x000000FF) << 16) | (((x) & 0x00FF0000) >> 16) | ((x) & 0xFF00FF00) )
void* create_RGBA_from_YUYV()
{
int Y, Cb, Cr;
int i, j;
float G_tmp;
static uchar R[256], B;
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)
{
float gain;
int i, x, y, j;
double sx, sy;
uint32_t *values;
char text[64];
gain=1/(max_val-min_val);
if (blc_command_loop_start()){
values = (uint32_t*)image_buffer;
if (array->type=='UIN8')
FOR(i, array->size) values[i]=color_map[array->uchars[i]];
else if (array->type=='FL32')
FOR(i, array->total_length) values[i]=color_map[CLIP_UCHAR((array->floats[i]-min_val)*256*gain-0.5f)];
else EXIT_ON_ARRAY_ERROR(array, "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<width && j<height && i>=0 && j>=0){
if (array->type=='UIN8') SPRINTF(text, "%4d,%4d: Y:%3d", i,j, array->uchars[i+j*width]);
else if (array->type=='FL32') SPRINTF(text, "%4d,%4d: Y:%.3f", i,j, array->floats[i+j*width]);
gtk_statusbar_push(GTK_STATUSBAR(pointer_statusbar), 0, text);
}
iterations++;
blc_command_loop_end();
} else exit(EXIT_SUCCESS);
return G_SOURCE_CONTINUE;
}
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;
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!=array->size){
image_buffer[j++]=array->uchars[i+2];
image_buffer[j++]=array->uchars[i+1];
image_buffer[j++]=array->uchars[i];
j++;
i+=3;
}
i=x*sx;
j=y*sy;
if (i<width && j<height && i>=0 && j>=0){
if (mouse_array.dims!=nullptr)
{
mouse_array.uints32[0]=i;
mouse_array.uints32[1]=j;
gdk_device_get_state(pointer_device, gtk_widget_get_window(GTK_WIDGET(image)), NULL, (GdkModifierType*)(&mouse_array.uints32[2]));
}
R=array->uchars[i*4+j*width*3];
G=array->uchars[i*4+j*width*3+1];
B=array->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();
}
else exit (EXIT_SUCCESS);
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;
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);
FOR_INV(i, array->size/4) ((uint32_t*)image_buffer)[i]=SWAP_RGBA_TO_CAIRO_ARGB32(array->uints32[i]);
i=x*sx;
j=y*sy;
if (i<width && j<height && i>=0 && j>=0){
if (mouse_array.dims!=nullptr){
mouse_array.uints32[0]=i;
mouse_array.uints32[1]=j;
gdk_device_get_state(pointer_device, gtk_widget_get_window(GTK_WIDGET(image)), NULL, (GdkModifierType*)(&mouse_array.uints32[2]));
}
R=array->uchars[i*4+j*width*4];
G=array->uchars[i*4+j*width*4+1];
B=array->uchars[i*4+j*width*4+2];
A=array->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);
blc_command_loop_end();
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_array *array)
{
JSAMPROW row_pt[1];
GdkPixbuf *pixbuf;
int row_stride;
uchar *pixels;
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
(void) frame_clock;
if (blc_command_loop_start()==0) exit(0);
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*) array->data, array->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;