/* bsutil.c - Edouard.Thiel@lim.univ-mrs.fr - 15/05/2001 Gestion du type image BsMap, lecture/écriture fichier PGM, visu XImage */ #include #include "bsutil.h" /*---------------- G E S T I O N D U T Y P E B S M A P ----------------*/ /* * Création complète d'une image ysiz*xsiz avec bord. * Renvoie NULL et affiche un message en cas d'erreur. * * USAGE : * BsMap *bm; * bm = NewBsMap (ysiz, xsiz, bord); * if (bm == NULL) return; */ BsMap *NewBsMap (int ysiz, int xsiz, int bord) { BsMap *bm; int i; bm = malloc (sizeof(BsMap)); if (bm == NULL) { fprintf (stderr, "NewBsMap: malloc error"); return NULL; } /* Titre */ bm->title[0] = 0; /* Calcul des bornes */ bm->bord = bord; bm->xsiz = xsiz; bm->ysiz = ysiz; bm->xmax = xsiz+bord; bm->ymax = ysiz+bord; bm->xtot = xsiz+bord*2; bm->ytot = ysiz+bord*2; bm->xytot = bm->ytot * bm->xtot; /* Tableau des pixels, sous forme linéaire */ bm->vec = malloc (bm->xytot * sizeof(short)); if (bm->vec == NULL) { fprintf (stderr, "NewBsMap: malloc error"); free (bm); return NULL; } /* Colonne d'adresses des débuts des lignes */ bm->col = malloc (bm->ytot * sizeof(short*)); if (bm->col == NULL) { fprintf (stderr, "NewBsMap: malloc error"); free (bm->vec); free (bm); return NULL; } /* Calcul des adresses tab[y][x] des pixels avec le bord : * toute l'astuce consiste à décaler l'adresse de base du tableau * de 'bord' lignes et de 'bord' colonnes. */ bm->tab = bm->col + bord; for (i = 0; i < bm->ytot; i++) bm->col[i] = bm->vec + i*bm->xtot + bord; return bm; } /* * Libération complète d'une image avec bord. Silencieux. * * USAGE : * BsMap *bm; * ... * FreeBsMap(bm); bm = NULL; */ void FreeBsMap (BsMap *bm) { if (bm == NULL) return; free (bm->col); free (bm->vec); free (bm); } /* * Copie complète d'une image avec bord. * Renvoie NULL et affiche un message en cas d'erreur. * * USAGE : * BsMap *src, *dest; * ... * dest = CopyBsMap(src); * if (dest == NULL) return; */ BsMap *CopyBsMap (BsMap *bm) { BsMap *res; int t; if (bm == NULL) return NULL; res = NewBsMap (bm->ysiz, bm->xsiz, bm->bord); if (res == NULL) return NULL; for (t = 0; t < bm->xytot; t++) res->vec[t] = bm->vec[t]; return res; } /* * Mémorise un titre dans l'image */ void SetTitleBsMap (BsMap *bm, char *title) { if (bm == NULL) return; if (title == NULL) { bm->title[0] = 0; return; } strncpy(bm->title, title, BMAP_TITLE_MAX); bm->title[BMAP_TITLE_MAX-1] = 0; /* sécurité */ } /* * Change la taille du bord d'une image. * Le contenu de l'intérieur de l'image est préservé ; * le contenu de l'ancien extérieur de l'image est perdu ; * attention, les pixels du nouvel extérieur ne sont pas initialisés. * * En cas d'erreur : renvoie -1, affiche un message, et laisse inchangé * le contenu initial de l'image. Renvoie 0 pour succès. * * USAGE : * BsMap *bm; * ... * if (SetBorderBsMap(bm, bord) < 0) return; */ int SetBorderBsMap (BsMap *bm, int bord) { BsMap *tmp; int x, y; if (bm == NULL || bm->bord == bord) return 0; /* Création d'une image avec le nouveau bord */ tmp = NewBsMap (bm->ysiz, bm->xsiz, bord); if (tmp == NULL) { fprintf (stderr, "SetBorderBsMap: can't change border size"); return -1; } /* Copie du titre */ SetTitleBsMap (tmp, bm->title); /* Copie des pixels de l'intérieur de l'image */ for (y = 0; y < tmp->ysiz; y++) for (x = 0; x < tmp->xsiz; x++) tmp->tab[y][x] = bm->tab[y][x]; /* Libération des champs de bm */ free (bm->col); free (bm->vec); /* Recopie des champs de tmp dans bm */ memcpy (bm, tmp, sizeof(BsMap)); /* Libération de tmp */ free (tmp); return 0; } /* * Initialisation de tous les pixels de l'image à la couleur value. * * USAGE : * BsMap *bm; * ... * InitWholeBsMap (bm, 0); */ void InitWholeBsMap (BsMap *bm, short value) { int t; if (bm == NULL) return; for (t = 0; t < bm->xytot; t++) bm->vec[t] = value; } /* * Initialisation de tous les pixels de l'interieur de l'image (c'est-à-dire * des pixels qui ne sont pas dans le bord) à la couleur value. * * USAGE : * BsMap *bm; * ... * InitInterBsMap (bm, 0); */ void InitInterBsMap (BsMap *bm, short value) { int x, y; if (bm == NULL) return; for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) bm->tab[y][x] = value; } /* * Initialisation de tous les pixels de l'extérieur de l'image (c'est-à-dire * des pixels qui sont dans le bord) à la couleur value. * * USAGE : * BsMap *bm; * ... * InitExterBsMap (bm, 0); */ void InitExterBsMap (BsMap *bm, short value) { int x, y; if (bm == NULL || bm->bord == 0) return; for (y = -bm->bord; y < 0 ; y++) for (x = -bm->bord; x < bm->xmax; x++) bm->tab[y][x] = value; for (y = bm->ysiz; y < bm->ymax; y++) for (x = -bm->bord; x < bm->xmax; x++) bm->tab[y][x] = value; for (x = -bm->bord; x < 0 ; x++) for (y = 0 ; y < bm->ysiz; y++) bm->tab[y][x] = value; for (x = bm->xsiz; x < bm->xmax; x++) for (y = 0 ; y < bm->ysiz; y++) bm->tab[y][x] = value; } /*------- L E C T U R E / E C R I T U R E F I C H I E R P G M -------*/ #define MAXBUF 32000 /* * Lecture d'un fichier au format pgm binaire et création d'une image de type * BsMap. Renvoie NULL et affiche un message en cas d'erreur. * * USAGE : * BsMap *bm; * bm = ReadBsMapFromPGM ("toto.pgm", 0); * if (bm == NULL) return; * ... * FreeBsMap(bm); */ BsMap *ReadBsMapFromPGM (char *filename, int bord) { FILE *f; BsMap *bm; unsigned char buf[MAXBUF]; int p[3], n, x, y; /* Ouverture du fichier binaire */ f = fopen (filename, "rb"); if (f == NULL) { fprintf (stderr, "ReadBsMapFromPGM: erreur fopen(%s)\n", filename); return NULL; } /* Lecture MagicValue */ if (fread (buf, 1, 2, f) < 2 || buf[0] != 'P' || buf[1] != '5') { fprintf (stderr, "ReadBsMapFromPGM: MagicValue <> P5\n"); fclose (f); return NULL; } /* Lecture de 3 entiers (largeur hauteur maxgris) séparés éventuellement par des lignes de commentaires. */ n = 0; while (n < 3) { /* On saute une ligne de commentaire, définie par : * ' ' une suite de séparateurs (blanc, \n, \t) * '#' le caractère # * '%[^\n]' une suite de caractères différents de \n, stockée dans buf * '\n' le caractère \n */ if (fscanf (f, " #%[^\n]\n", buf) == 1) continue; /* On lit un entier */ if (fscanf (f, "%d", &p[n]) == 1) { n++; continue; } /* Erreur */ fprintf (stderr, "ReadBsMapFromPGM: mauvais en-tete\n"); fclose (f); return NULL; } /* On vérifie que maxgris est 255 */ if (p[2] != 255) { fprintf (stderr, "ReadBsMapFromPGM: maxgris != 255\n"); fclose (f); return NULL; } /* Après l'en-tête il y a exactement un caractère à lire avant de tomber sur les données binaires. Le '*' permet de jeter le caractère lu.*/ fscanf (f, "%*c"); /* Allocation Image (hauteur, largeur, bord) */ bm = NewBsMap (p[1], p[0], bord); if (bm == NULL) { fclose (f); return NULL; } /* Titre de l'image : nom du fichier par défaut */ SetTitleBsMap (bm, filename); /* Lecture image ligne par ligne (efficace et simple) */ for (y = 0; y < bm->ysiz; y++) { /* On lit une ligne de xsiz pixels */ n = fread (buf, bm->xsiz, 1, f); if (n != 1) { fprintf (stderr, "ReadBsMapFromPGM: erreur fread()\n"); FreeBsMap(bm); fclose (f); return NULL; } /* On copie la ligne dans bm */ for (x = 0; x < bm->xsiz; x++) bm->tab[y][x] = buf[x]; } fclose (f); return bm; } /* * Sauvegarde d'une image de type BsMap dans un fichier au format pgm binaire. * Renvoie -1 et affiche un message en cas d'erreur, renvoie 0 pour succès. * * USAGE : * BsMap *bm; * ... * if (WriteBsMapInPGM ("toto.pgm", bm) < 0) return; */ int WriteBsMapInPGM (char *filename, BsMap *bm) { FILE *f; unsigned char buf[MAXBUF]; int x, y, n; if (bm == NULL) { fprintf (stderr, "WriteBsMapInPGM: image NULL\n"); return -1; } /* Ouverture du fichier binaire */ f = fopen (filename, "wb"); if (f == NULL) { fprintf (stderr, "WriteBsMapInPGM: erreur fopen(%s)\n", filename); return -1; } /* Ecriture du header. * RQ: la norme PGM demande de terminer le header par exactement 1 caractère * après maxgris ; c'est ici le cas pour '\n' car le fichier est ouvert en * mode binaire "wb". */ fprintf (f, "P5\n"); fprintf (f, "# largeur hauteur\n"); fprintf (f, "%d %d\n", bm->xsiz, bm->ysiz); fprintf (f, "255\n"); /* Ecriture du tableau ligne par ligne */ for (y = 0; y < bm->ysiz; y++) { /* Préparation de la ligne */ for (x = 0; x < bm->xsiz; x++) buf[x] = bm->tab[y][x]; /* Écriture de la ligne */ n = fwrite (buf, bm->xsiz, 1, f); if (n != 1) { fprintf (stderr, "WriteBsMapInPGM: erreur fwrite()\n"); fclose (f); return -1; } } fclose (f); return 0; /* succès */ } /*----------------- V I S U A L I S A T I O N X I M A G E -----------------*/ /* * Table des couleurs vga */ struct { int r, g, b; } color_vga[] = { { 0, 0, 0 }, /* 0 : black */ { 20, 20, 190 }, /* 1 : blue */ { 30, 200, 30 }, /* 2 : green */ { 30, 200, 200 }, /* 3 : cyan */ { 200, 30, 30 }, /* 4 : red */ { 200, 30, 200 }, /* 5 : magenta */ { 200, 130, 50 }, /* 6 : brown */ { 200, 200, 200 }, /* 7 : light gray */ { 110, 110, 140 }, /* 8 : dark gray */ { 84, 130, 252 }, /* 9 : light blue */ { 84, 252, 84 }, /* 10 : light green */ { 84, 252, 252 }, /* 11 : light cyan */ { 252, 84, 84 }, /* 12 : light red */ { 252, 84, 252 }, /* 13 : light magenta */ { 252, 252, 84 }, /* 14 : yellow */ { 252, 252, 252 } }; /* 15 : white */ /* * Allocation dynamique d'un xi selon la taille de l'image bm, * et calcul pixel par pixel de xi à partir de l'image bm et d'une palette * de couleurs lut. * Renvoie NULL en cas d'erreur. * * USAGE : * XImage *xi; * xi = NewXImageFromBsMap(bm,LUT_GREY); * if (xi == NULL) return; * ... * FreeXImage(xi); */ XImage *NewXImageFromBsMap (BsMap *bm, int lut) { int x, y, t = 0, v; XImage *xi; if (bm == NULL) return NULL; xi = HeCreateXi (bm->xsiz, bm->ysiz); if (xi == NULL) return NULL; switch (lut) { case LUT_GREY : /* 256 niveaux de gris */ for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) { v = bm->tab[y][x] % 256; if (v < 0) v = 256 + v; HeSetXiPixel (xi, t++, v, v, v); } break; case LUT_VGA : /* 15 couleurs vga */ for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) { v = bm->tab[y][x]; if (v > 0) v = 1 + (v-1) % 15; else if (v < 0) v = 1 + (-v-1) % 15; HeSetXiPixel (xi, t++, color_vga[v].r, color_vga[v].g, color_vga[v].b); } break; case LUT_VGA_GREY : /* <0 : 15 couleurs, >=0 : 256 gris */ for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) { v = bm->tab[y][x]; if (v >= 0) { v = v % 256; HeSetXiPixel (xi, t++, v, v, v); } else { v = 1 + (-v-1) % 15; HeSetXiPixel (xi, t++, color_vga[v].r, color_vga[v].g, color_vga[v].b); } } break; case LUT_RED_GREEN : /* <0 : 256 rouges, >=0 : 256 verts */ for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) { v = bm->tab[y][x]; if (v < 0) HeSetXiPixel (xi, t++, -v % 256, 0, 0); else HeSetXiPixel (xi, t++, 0, v % 256, 0); } break; default : fprintf (stderr, "NewXImageFromBsMap: mauvaise lut"); } return xi; } /* Affichage instantanné de xi dans le Window win (en général le win * du canvas). Ne fait rien si xi est NULL. */ void PaintXImage (XImage *xi, Window win) { HePutXi (win, he_gc, xi, 0, 0); } /* * Libération mémoire de xi. Ne fait rien si xi est NULL. */ void FreeXImage (XImage *xi) { HeDestroyXi (xi); }