Colorimètre numérique linux

Soyez le premier à donner votre avis sur cette source.

Snippet vu 3 158 fois - Téléchargée 18 fois

Contenu du snippet

Emulation sous linux du colorimètre numérique MacOSX, en utilisant la librairie X11.
Codé en C et testé sur Ubuntu.

Dans mon cas, j'ai du ajouter dans le Makefile :
-L/usr/lib/i386-linux-gnu -lX11

Source / Exemple :


/*
Colorimètre numérique basé sur la librairie X11

3 sous fenetres composent cette application:
La 1ere est un zoom sur le voisinage du curseur. Le diaphragme y est représenté par un carré noir.
La 2eme est la couleur moyenne sur tous les pixels dans le diaphragme.
La 3eme liste les valeurs r, g, b, la taille du diaphragme et la position x, y du curseur.

Echap pour sortir. Les touches 'a' et 'z' permettent de réduire / agrandir le diaphragme.

  • /
#include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xatom.h> #include <X11/keysym.h> #include <X11/cursorfont.h> #include <stdlib.h> #include <stdio.h> #include <string.h> // NPIX et TPIX sont le nombre et la taille des pixels de la sous-fenetre zoom // HEIGHT, WIDTH les dimensions de la fenetre application; SUBWIDTH la largeur de chaque 'sous fenetres' #define NPIX 15 #define TPIX 8 #define HEIGHT 120 #define WIDTH 360 #define SUBWIDTH 120 Display *dpy; int black, white; double r, g, b; unsigned int dpy_width, dpy_height; Window w, wroot; XTextProperty *title; GC gc; unsigned int x, y, x_im, y_im; XImage *image; XColor *c; //Colormap cmap; char str[5][32]; unsigned int i, j; unsigned int diaphragme; XEvent e; // redessiner la fenetre de l'application void redraw(){ // x, y coords souris // (x_im, y_im) coords de l'angle haut-gauche de la fenetre de zoom x_im= x- (NPIX- 1)/ 2; if (x_im< (NPIX- 1)/ 2) x_im= (NPIX- 1)/ 2; if (x_im> dpy_width- NPIX) x_im= dpy_width- NPIX; y_im= y- (NPIX- 1)/ 2; if (y_im< (NPIX- 1)/ 2) y_im= (NPIX- 1)/ 2; if (y_im> dpy_height- NPIX) y_im= dpy_height- NPIX; // recuperer l'image de l'écran entre (x_im, y_im) et (x_im+ NPIX, y_im+ NPIX) image= XGetImage(dpy, wroot, x_im, y_im, NPIX, NPIX, XAllPlanes(), ZPixmap); // Partie gauche // Dessin d'un rectangle pour chaque pixel r= g= b= 0.; for (i=0; i<NPIX; i++) for (j=0; j<NPIX; j++) { c->pixel= XGetPixel(image, i, j); // XQueryColor très lent => décomposition en red, green, blue de pixel //XQueryColor(dpy, cmap, c); c->red= c->pixel>> 16; c->green= (c->pixel>> 8) & 0xFF; c->blue= c->pixel & 0xFF; // Dessin des pixels zoomés XSetForeground(dpy, gc, c->pixel); XFillRectangle(dpy, w, gc, TPIX* i, TPIX* j, TPIX* (i+ 1), TPIX* (j+ 1)); // Si le pixel est dans le diaphragme, on ajoute sa contribution à la valeur moyenne if ( (i>= (NPIX- 1)/2- diaphragme+ 1) && (i< NPIX- ((NPIX- 1)/2- diaphragme+ 1)) && (j>= (NPIX- 1)/2- diaphragme+ 1) && (j< NPIX- ((NPIX- 1)/2- diaphragme+ 1)) ){ r+= (double)(c->red)/ ((2* diaphragme- 1)* (2* diaphragme- 1)); g+= (double)(c->green)/ ((2* diaphragme- 1)* (2* diaphragme- 1)); b+= (double)(c->blue)/ ((2* diaphragme- 1)* (2* diaphragme- 1)); } } // Dessin carré du diaphragme XSetForeground(dpy, gc, black); XDrawRectangle(dpy, w, gc, ((NPIX- 1)/ 2- diaphragme+ 1)* TPIX, ((NPIX- 1)/ 2- diaphragme+ 1)* TPIX, TPIX* (2* diaphragme- 1), TPIX* (2* diaphragme- 1)); // Partie centrale c->red= (unsigned int)(r); c->green= (unsigned int)(g); c->blue= (unsigned int)(b); c->pixel= c->blue+ (c->green<< 8)+ (c->red<< 16); XSetForeground(dpy, gc, c->pixel); XFillRectangle(dpy, w, gc, SUBWIDTH, 0, 2* SUBWIDTH, HEIGHT); // Partie droite sprintf(str[0], "X: %i; Y: %i", x, y); sprintf(str[1], "red : %i", c->red); sprintf(str[2], "green : %i", c->green); sprintf(str[3], "blue : %i", c->blue); sprintf(str[4], "diaph : %i", diaphragme); XSetForeground(dpy, gc, black); XFillRectangle(dpy, w, gc, 2* SUBWIDTH, 0, WIDTH, HEIGHT); XSetForeground(dpy, gc, white); for (i=0; i<5; i++) XDrawString(dpy, w, gc, 5+ 2* SUBWIDTH, 20*(i+ 1), str[i], strlen(str[i])); // Dessiner tout ca dans la fenetre XFlush(dpy); } // Initialisation void init(){ dpy= XOpenDisplay(NULL); if (dpy== NULL){ printf("Pas de display\n"); exit(1); } dpy_width= DisplayWidth(dpy, DefaultScreen(dpy)); dpy_height= DisplayHeight(dpy, DefaultScreen(dpy)); black= BlackPixel(dpy, DefaultScreen(dpy)); white= WhitePixel(dpy, DefaultScreen(dpy)); wroot= DefaultRootWindow(dpy); // Création fenetre w= XCreateSimpleWindow(dpy, wroot, 0, 0, WIDTH, HEIGHT, 0, black, black); // Donner un titre à la fenetre title= malloc(sizeof(XTextProperty)); title->value= (unsigned char *) "Colorimetre numerique"; title->encoding= XA_STRING; title->format= 8; title->nitems= strlen((char *) title->value); XSetWMName(dpy, w, title); // Selectionner events que l'on veut capter XSelectInput(dpy, w, StructureNotifyMask | KeyPressMask | ExposureMask); // Afficher fenetre XMapWindow(dpy, w); // Creer un "Graphics Context" gc= XCreateGC(dpy, w, 0, NULL); // cmap Utile à XQueryColor : désactivé //cmap= DefaultColormap(dpy, DefaultScreen(dpy)); c= malloc(sizeof(XColor)); diaphragme= 1; // Attendre MapNotify event for(;;){ XNextEvent(dpy, &e); if (e.type == MapNotify) break; } XSync(dpy, False); // Grabber le curseur en lui assignant une forme (ici XC_cross) XGrabPointer(dpy, wroot, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, wroot, XCreateFontCursor(dpy, XC_cross), CurrentTime); // Déplacement du curseur au milieu de l'écran et 1er dessin x= dpy_width/ 2; y= dpy_height/ 2; XWarpPointer(dpy, None, wroot, 0, 0, 0, 0, x, y); redraw(); } // ----------------------------------------------------------- // Point entrée application // ----------------------------------------------------------- void main() { // Initialiser les variables init(); // Boucle principale for(;;){ XNextEvent(dpy, &e); // a : réduire diaphragme // z : augmenter diaphragme // esc : sortir du programme if (e.type== KeyPress){ if (XLookupKeysym(&e.xkey, 0)== XK_a){ diaphragme--; if (diaphragme< 1) diaphragme= 1; redraw(); } if (XLookupKeysym(&e.xkey, 0)== XK_z){ diaphragme++; if (2* diaphragme- 1> NPIX) diaphragme--; redraw(); } else if (XLookupKeysym(&e.xkey, 0)== XK_Escape){ break; } } // Mouvement curseur => redessiner fenetre else if (e.type== MotionNotify){ x= e.xmotion.x; y= e.xmotion.y; redraw(); } } // Libérer les resources XFree(image); XCloseDisplay(dpy); free(c); free(title); }

Conclusion :


Toutes les remarques sont les bienvenues.

A voir également

Ajouter un commentaire

Commentaires

alec078
Messages postés
2
Date d'inscription
mercredi 19 décembre 2007
Statut
Membre
Dernière intervention
30 janvier 2012
-
Pour la compilation, c'est bien lié au compilateur: par réflexe, ne faisant que rarement du C, j'avais le source mis dans un fichier d'extension cpp. Ce qui donne:
$ gcc -o color color.cpp -lX11
/tmp/ccZ6jt2n.o:(.eh_frame+0x12): undefined reference to `__gxx_personality_v0'
$ gcc -o color color.c -lX11
# OK
valchek
Messages postés
1
Date d'inscription
mercredi 1 septembre 2010
Statut
Membre
Dernière intervention
30 janvier 2012
-
Bonjour Alec078

Pour ce qui est des problèmes de compilation, je pense que c'est lié au binaire utilisé : g++ au lieu de gcc. Ce code est en C.
Sinon en ce qui concerne la remarque sur la non fonctionnalité du programme, je crois comprendre ce que tu dis; j'ai fais ce bout de code car j'avais besoin d'un programme équivalent à celui existant sur Mac, comme précisé dans la description; je m'en sers en peinture lorsque j'ai un modèle sur écran et que j'ai un doute sur la couleur d'une portion de l'image. Je n'ai donc pas l'utilité de récupérer ces valeurs dans un programme... Mais cela pourrait être une amélioration de ce code, assez simple à mettre en place je pense.

Bonne journée
alec078
Messages postés
2
Date d'inscription
mercredi 19 décembre 2007
Statut
Membre
Dernière intervention
30 janvier 2012
-
Voici les modifications que j'ai effectuées pour que cela compile:

$ uname -a
Linux lucid 2.6.32-34-generic #77-Ubuntu SMP Tue Sep 13 19:39:17 UTC 2011 x86_64 GNU/Linux

$ lsb_release -a
[...]
Description: Ubuntu 10.04.3 LTS

J'ai du caster ces 2 malloc:

$ g++ -o color color.cpp -lX11
color.cpp: In function ‘void init()’:
color.cpp:111: error: invalid conversion from ‘void*’ to ‘XTextProperty*’
color.cpp:125: error: invalid conversion from ‘void*’ to ‘XColor*’
color.cpp: At global scope:
color.cpp:144: error: ‘::main’ must return ‘int’

1/
title=(XTextProperty *) malloc(sizeof(XTextProperty));
2/
c= (XColor *) malloc(sizeof(XColor));

puis renvoyer un int plutôt que void dans le main, ce qui est plus dans la norme.

Le programme fonctionne comme prévu pour ce qui est de la colorimétrie.
Par contre changer le curseur en croix ne rend pas le pointage plus précis, c'est le rôle de la loupe.

Et surtout, et c'est ce qui rend le programme non fonctionnel, les événements X sont tous interceptés par l'application, ce qui rend son utilisation compliquée; quand on en arrive au point d'utiliser un colorimètre, c'est qu'on est en train de programmer, et qu'on a besoin de ces valeurs (bien souvent plusieurs en série si on veut les couleurs dans un dégrade). Et obliger l'utilisateur a quitter et relancer l'application, entre chaque valeur, sans compter qu'il doit compter sur sa mémoire entre deux.

Pourquoi ne pas juste dumper les valeurs aux points cliqués ?
g3g3
Messages postés
4
Date d'inscription
lundi 14 février 2005
Statut
Membre
Dernière intervention
9 janvier 2012
-
library = bibliothèque en français à moins que tu ne fasse payer tes fonctions ...

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.