Monppm : un afficheur .ppm

Description

J'ai un logiciel qui calcule en .ppm des images.
Il y a une information sur les formats ppm
(Portable Pixel Map) à :
http://netpbm.sourceforge.net/doc/ppm.html
- J'ai donc eu l'envie de faire un afficheur de
fichiers *.ppm qui soit très facile à installer
et utiliser. Je souhaitais éviter les installeurs
et les logiciels complexes qu'il faut étudier
longtemps avant de s'en servir.
- Pour cela, j'ai développé MonPPM qui affiche
des fichiers *.ppm ayant le magic number : P6
et 256 niveaux pour les valeurs RGB des pixels.
Ce qui est un type assez courant.
- Il y a plusieurs façons de désigner le fichier image
à afficher : Fichier => Ouvrir, <ctrl>O, la touche : N
et le glisser-déposer du fichier dans la fenêtre adapté de :
http://www.gametutorials.com/gtstore/pc-335-9-drag-and-drop.aspx
- La touche F1 donne l'aide. Le source est commenté.
- La proportion largeur/hauteur de l'image est conservée
quand on modifie les dimensions de la fenêtre avec la souris,
et de même en cas d'utilisation du bouton : agrandir la fenêtre.
- Les tailles maximale et minimale de la fenêtre sont prises
en compte, y compris si l'image a plus de pixels que l'écran.
- Si on associe MonPPM et le type .ppm, on peut afficher l'image :
. soit par un glisser-déposer du fichier sur le nom de l'exécutable,
. soit par un double clic sur le nom du fichier.

Source / Exemple :


#include "main.h"

// variables communes :

char monprojet[] = "MonPPM v 0.7";
char nomModel[300]; // nom complet du fichier *.ppm à afficher
int larg;           // largeur de l'image
int haut;           // hauteur de l'image
int lsup=10;        // supplément de largeur entre la fenêtre et l'image ( 2 marges )
int hsup=74;        // supplément expérimental de hauteur entre la fenêtre et l'image
int hbet;           // hauteur de barre d'état
UCHAR *ucpBitsMem;  // les pixels BGRA de l'image
int cx,cy,xe,ye;    // largeur et hauteur de la fenêtre et de l'écran
int prem;           // prem : 1 pour le premier affichage et 0 ensuite
int zoom;           // zoom : 1 ( éch. 1 ) ou 2 ( éch. 1/2 ) ou 4 ( éch. 1/4 )
int nmax;           // nombre d'images qui se suivent en fenêtre maximisée
int faire;          // variable d'état pour readPPM : -1, 0, 1 ou 2 
char buf[600];      // un buffer de travail réutilisable

HINSTANCE hinst;
HWND hWnd,hEdit,hBe;
HDC hDC,hdcMem;
HBITMAP hBmpMem;

void rer(int n) {
char buf1[]="Problème n° ";
char buf2[]=" dans la lecture du fichier : \n\n";
char bb[3];
     strcpy(buf,buf1);      // on signale un problème 
     sprintf(bb,"%i",n);    // intervenu dans readPPM 
     strcat(buf,bb);        // pendant la lecture du fichier .ppm
     strcat(buf,buf2);      
     strcat(buf,nomModel);
     informer(buf);
     faire = -1;            // pour traiter l'erreur de lecture
     return;
}

void readPPM(char *szFileName, UCHAR **ucpBits, int *iWidth, int *iHeight) {
FILE *fi;          
unsigned int w, h, d;          // ici on lit le fichier *.ppm de l'image 
char *t,*ptr;
long fisize;
int r,n;
     fi = fopen(szFileName, "r");
     if ( fi == NULL ) {rer(1); return;}
     t = fgets(buf, 100, fi);
     if ( (t == NULL) || ( strncmp(buf, "P6", 2) != 0 ) ) {rer(2); return;}
     if(buf[2] == '\n') {
          t = fgets(buf, 100, fi);  // cas général : P6\n
          ptr=&buf[0];
     }
     else ptr=&buf[2];                     // si le '\n' est omis
     while(strncmp(ptr, "#", 1) == 0 ) {   // si commentaires
          t = fgets(buf, 100, fi);
          ptr=&buf[0];
     }
     while(strncmp(ptr, "\n", 1) == 0 ) {  // si ici : '\n' 
          t = fgets(buf, 100, fi);
          ptr=&buf[0];
     }
     d = 0;
     w = strtol(ptr, &ptr, 0);
     h = strtol(ptr, &ptr, 0);
     d = strtol(ptr, &ptr, 0);               // lecture de d : nb de niveaux
     if( d!= 255 ) {                
          t = fgets(buf, 100, fi);
          d = strtol(buf, &ptr, 0); //  si nécessaire, dans la ligne suivante
     }
     if ( d != 255 ) {rer(3); return;}         // on se restreint à d = 255 !
     n=3*w*h;                  //  n : nombre d'octets pour les pixels en RGB

  • ucpBits=(UCHAR *)malloc(n*sizeof(UCHAR)); // mémore des pixels en RGB
fseek(fi, 0, SEEK_END); fisize = ftell(fi); // nombre total d'octets du fichier fseek(fi, fisize-n, SEEK_SET); // on va lire les n derniers octets r=fread(*ucpBits, sizeof(UCHAR), n, fi); if(r == 0) {rer(4); return;} fclose(fi);
  • iWidth=(int)w; // largeur et
  • iHeight=(int)h; // hauteur de l'image
return; } void newModel() { // à chaque fois que l'on souhaite charger une nouvelle image UCHAR *pix=0; int i,j; if( openModel() ) { DeleteObject(hBmpMem); ReleaseDC(hWnd,hdcMem); free(ucpBitsMem); ucpBitsMem = 0; readPPM(nomModel, &pix, &larg, &haut); if(faire == -1) { free(pix); pix = 0; newModel(); // ça c'est osé ! mais ici ça marche ! return; } ucpBitsMem = (UCHAR*)malloc(4*larg*haut); for(i=0,j=0;i<larg*haut*3;i+=3,j+=4) { ucpBitsMem[j]=pix[i+2]; ucpBitsMem[j+1]=pix[i+1]; // rangement des données dans une ucpBitsMem[j+2]=pix[i]; // bonne structure : W*H*4 ( B G R A ) ucpBitsMem[j+3]=(UCHAR)0; } free(pix); pix = 0; hdcMem = CreateCompatibleDC(NULL); // création d'un bitmap hBmpMem = CreateBitmap(larg,haut,1,32,ucpBitsMem); SelectObject(hdcMem,hBmpMem); if(prem != 0) { prem = 0; // ici on prépare le cas particulier du i = mini(lmax(),lsup+larg/zoom); // premier affichage de la première image j = mini(hmax(),hsup+haut/zoom); SetWindowPos(hWnd,0,0,0,i,j,SWP_NOZORDER|SWP_NOMOVE); } else SetWindowPos(hWnd,0,0,0,lsup+larg/zoom,hsup+haut/zoom,SWP_NOZORDER|SWP_NOMOVE); guidage(); model(); faire=2; // ici la préparation de l'image s'est bien terminée } InvalidateRect(hWnd, NULL, TRUE); return; } // // Pour le reste du source voir dans le zip //

Conclusion :


On peut bien sûr l'étendre à d'autres types de fichiers d'images et/ou
développer des fonctionalités supplémentaires, ce n'était pas l'objectif
et de toutes façons, l'excellent et gratuit PhotoFiltre est bien mieux.
Toutes vos remarques sont les bienvenues. pgl10.

Codes Sources

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.