/* editg-cor.c - Edouard.Thiel@lim.univ-mrs.fr - 23/10/2001 Compilation : cc bsutil.c editg-cor.c -o editg-cor \ `~/helium/helium-cfg --cflags --libs` Usage : editg-cor [image-in.pgm] [image-out.pgm] */ #include #include "bsutil.h" /* Variables globales */ He_node *princ, *panel, *text_load, *text_save, *text_haut, *text_larg, *b_quit, *tog_lut, *text_a, *text_b, *fen1_frame = NULL, *fen1_canvas, *fen1_panel, *fen1_mess; BsMap *gbm1 = NULL; int fen1_lut = LUT_GREY; XImage *fen1_xi = NULL; /*-------------------------- A L G O R I T H M E S --------------------------*/ void change_val (BsMap *bm, int a, int b) { int x, y; for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) if (bm->tab[y][x] == a) bm->tab[y][x] = b; } void echange_val (BsMap *bm, int a, int b) { int x, y; for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) if (bm->tab[y][x] == a) bm->tab[y][x] = b; else if (bm->tab[y][x] == b) bm->tab[y][x] = a; } void seuil_inf (BsMap *bm, int a, int b) { int x, y; for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) if (bm->tab[y][x] < a) bm->tab[y][x] = b; } void seuil_sup (BsMap *bm, int a, int b) { int x, y; for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) if (bm->tab[y][x] > a) bm->tab[y][x] = b; } void transfo_affine (BsMap *bm, double a, double b) { int x, y; for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) bm->tab[y][x] = bm->tab[y][x]*a +b; } void symetrie_V (BsMap *bm) { int x, y, m, tmp; m = bm->xsiz/2; for (y = 0; y < bm->ysiz; y++) for (x = 0; x < m; x++) { tmp = bm->tab[y][x]; bm->tab[y][x] = bm->tab[y][bm->xsiz-x-1]; bm->tab[y][bm->xsiz-x-1] = tmp; } } void symetrie_H (BsMap *bm) { int x, y, m, tmp; m = bm->ysiz/2; for (y = 0; y < m; y++) for (x = 0; x < bm->xsiz; x++) { tmp = bm->tab[y][x]; bm->tab[y][x] = bm->tab[bm->ysiz-y-1][x]; bm->tab[bm->ysiz-y-1][x] = tmp; } } void symetrie_D (BsMap *bm1, BsMap *bm2) { int x, y; for (y = 0; y < bm2->ysiz; y++) for (x = 0; x < bm2->xsiz; x++) bm2->tab[y][x] = bm1->tab[x][y]; } void rotation_90 (BsMap *bm1, BsMap *bm2) { int x, y; for (y = 0; y < bm2->ysiz; y++) for (x = 0; x < bm2->xsiz; x++) bm2->tab[y][x] = bm1->tab[x][bm2->ysiz-y-1]; } void contour4 (BsMap *bm, int coul_dessin, int coul_fond) { int x, y; /* Demande un bord extérieur d'épaisseur 1 et l'initialise à coul_fond */ if (bm->bord != 1) SetBorderBsMap (bm, 1); InitExterBsMap (bm, coul_fond); for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) if ( bm->tab[y][x] != coul_fond && ( bm->tab[y][x-1] == coul_fond || bm->tab[y][x+1] == coul_fond || bm->tab[y-1][x] == coul_fond || bm->tab[y+1][x] == coul_fond )) bm->tab[y][x] = coul_dessin; } #define MAXPILE 100000 void remplis4 (BsMap *bm, int x0, int y0, int coul_dessin, int coul_fond) { short px[MAXPILE], py[MAXPILE]; int x, y, p = 0; /* Demande un bord extérieur d'épaisseur 1 et l'initialise à une valeur * différente de coul_fond, pour ne pas avoir à tester si on sort de * l'image pendant la propagation. */ if (bm->bord != 1) SetBorderBsMap (bm, 1); InitExterBsMap (bm, coul_fond+1); px[0] = x0; py[0] = y0; p = 1; bm->tab[y0][x0] = coul_dessin; while (p > 0 && p < MAXPILE-10) { p--; x = px[p]; y = py[p]; if (bm->tab[y][x-1] == coul_fond) { px[p] = x-1; py[p] = y; p++; bm->tab[y][x-1] = coul_dessin; } if (bm->tab[y][x+1] == coul_fond) { px[p] = x+1; py[p] = y; p++; bm->tab[y][x+1] = coul_dessin; } if (bm->tab[y-1][x] == coul_fond) { px[p] = x; py[p] = y-1; p++; bm->tab[y-1][x] = coul_dessin; } if (bm->tab[y+1][x] == coul_fond) { px[p] = x; py[p] = y+1; p++; bm->tab[y+1][x] = coul_dessin; } } } void bresenham (BsMap *bm, int x1, int y1, int x2, int y2, int coul) { int x, y, dx, dy, px, py, e, pe, pente_inf_1, tmp; /* * Initialisations */ dx = x2 - x1; dy = y2 - y1; pente_inf_1 = (abs(dy) <= abs(dx)); if ((pente_inf_1 && dx < 0) || (!pente_inf_1 && dy < 0)) { tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; dx = -dx; dy = -dy; } x = x1; y = y1; bm->tab[y][x] = coul; /* * Trace de la droite */ if (pente_inf_1) { if (dy >= 0) py = 1; else { py = -1; dy = -dy; } pe = dy - dx; e = dx / 2 + pe; while (x < x2) { x++; if (e < 0) e += dy; else { e += pe; y += py; } bm->tab[y][x] = coul; } } else { if (dx >= 0) px = 1; else { px = -1; dx = -dx; } pe = dx - dy; e = dy / 2 + pe; while (y < y2) { y++; if (e < 0) e += dx; else { e += pe; x += px; } bm->tab[y][x] = coul; } } } /* Fonctions appelées par rosenfeld_ab */ int min4 (int p1, int p2, int p3, int p4) { int res = p1; if (res > p2) res = p2; if (res > p3) res = p3; if (res > p4) res = p4; return res; } int min5 (int p1, int p2, int p3, int p4, int p5) { int res = p1; if (res > p2) res = p2; if (res > p3) res = p3; if (res > p4) res = p4; if (res > p5) res = p5; return res; } /* Tester avec les couples a,b : 1,2 (d4) 1,1 (d8) 2,3 (d2-3) 3,4 (d3-4) */ void rosenfeld_ab (BsMap *bm, int a, int b) { int x, y; /* Demande un bord extérieur d'épaisseur 1 et l'initialise à 0. */ if (bm->bord != 1) SetBorderBsMap (bm, 1); InitExterBsMap (bm, 0); /* Balayage avant : de gauche à droite et de haut en bas */ for (y = 0; y < bm->ysiz; y++) for (x = 0; x < bm->xsiz; x++) if (bm->tab[y][x] > 0) bm->tab[y][x] = min4 ( bm->tab[y ][x-1] + a, bm->tab[y-1][x ] + a, bm->tab[y-1][x-1] + b, bm->tab[y-1][x+1] + b ); /* Balayage arriere : de droite à gauche et de bas en haut */ for (y = bm->ysiz-1; y >= 0 ; y--) for (x = bm->xsiz-1; x >= 0 ; x--) if (bm->tab[y][x] > 0) bm->tab[y][x] = min5 ( bm->tab[y][x], bm->tab[y ][x+1] + a, bm->tab[y+1][x ] + a, bm->tab[y+1][x-1] + b, bm->tab[y+1][x+1] + b ); } /*---------------------------- I N T E R F A C E ----------------------------*/ void fen1_repaint_proc (He_node *hn, Window win) { if (fen1_xi == NULL) return; PaintXImage (fen1_xi, win); } void afficher_fen1 (BsMap *bm, int lut, char *titre, char *legende, He_event_proc event_proc) { int k; if (bm == NULL) return; if (fen1_frame == NULL) { fen1_frame = HeCreateFrame (); fen1_canvas = HeCreateCanvas (fen1_frame); fen1_panel = HeCreatePanel (fen1_frame); fen1_mess = HeCreateMessage (fen1_panel); } HeSetShow (fen1_frame, TRUE); HeSetFrameLabel (fen1_frame, titre); HeSetMessageLabel (fen1_mess, legende); HeFit(fen1_panel); HeSetCanvasRepaintProc (fen1_canvas, fen1_repaint_proc); HeSetCanvasEventProc (fen1_canvas, event_proc); HeSetX (fen1_canvas, 0); HeSetWidth (fen1_canvas, bm->xsiz); HeSetHeight (fen1_canvas, bm->ysiz); HeJustify (fen1_panel, fen1_canvas, HE_TOP); HeFit (fen1_frame); k = HeGetWidth(fen1_frame) - HeGetExtWidth(fen1_canvas); if (k > 0) HeSetX (fen1_canvas, k/2); if (fen1_xi != NULL) FreeXImage (fen1_xi); fen1_xi = NewXImageFromBsMap (bm, lut); HePostRepaint(fen1_canvas); } void trans_abent_proc (He_node *hn) { char *nom = HeGetButtonLabel(hn); int a = atoi(HeGetTextValue(text_a)), b = atoi(HeGetTextValue(text_b)); if (gbm1 == NULL) return; if (strcmp (nom, "a -> b") == 0) change_val (gbm1, a, b); else if (strcmp (nom, "a <-> b") == 0) echange_val (gbm1, a, b); else if (strcmp (nom, " b") == 0) seuil_inf (gbm1, a, b); else if (strcmp (nom, ">a -> b") == 0) seuil_sup (gbm1, a, b); else if (strcmp (nom, "Contour4(a,b)") == 0) contour4 (gbm1, a, b); else if (strcmp (nom, "Rosenfeld(a,b)") == 0) rosenfeld_ab (gbm1, a, b); else return; afficher_fen1 (gbm1, fen1_lut, nom, "", NULL); } void trans_abdbl_proc (He_node *hn) { char *nom = HeGetButtonLabel(hn); double a = atof(HeGetTextValue(text_a)), b = atof(HeGetTextValue(text_b)); if (gbm1 == NULL) return; if (strcmp (nom, "*a +b") == 0) transfo_affine (gbm1, a, b); else return; afficher_fen1 (gbm1, fen1_lut, nom, "", NULL); } void trans_geom_proc (He_node *hn) { char *nom = HeGetButtonLabel(hn); if (gbm1 == NULL) return; if (strcmp (nom, "Sym V") == 0) symetrie_V (gbm1); else if (strcmp (nom, "Sym H") == 0) symetrie_H (gbm1); else if (strcmp (nom, "Sym D") == 0) { BsMap *tmp = NewBsMap (gbm1->xsiz, gbm1->ysiz, 0); if (tmp == NULL) return; symetrie_D (gbm1, tmp); FreeBsMap (gbm1); gbm1 = tmp; } else if (strcmp (nom, "Rot 90") == 0) { BsMap *tmp = NewBsMap (gbm1->xsiz, gbm1->ysiz, 0); if (tmp == NULL) return; rotation_90 (gbm1, tmp); FreeBsMap (gbm1); gbm1 = tmp; } else return; afficher_fen1 (gbm1, fen1_lut, nom, "", NULL); } void remplis_event_proc (He_node *hn, He_event *hev) { switch (hev->type) { case ButtonPress : { int a = atoi(HeGetTextValue(text_a)), b = atoi(HeGetTextValue(text_b)); if (gbm1 == NULL) return; remplis4 (gbm1, hev->sx, hev->sy, a, b); afficher_fen1 (gbm1, fen1_lut, "Remplis4(a,b)", "Clic pour remplir", remplis_event_proc); } break; } } static int bresen_x1, bresen_y1; void bresen_event_proc (He_node *hn, He_event *hev) { switch (hev->type) { case ButtonPress : { int a = atoi(HeGetTextValue(text_a)); if (gbm1 == NULL) return; if (bresen_x1 != -1) bresenham (gbm1, bresen_x1, bresen_y1, hev->sx, hev->sy, a); bresen_x1 = hev->sx; bresen_y1 = hev->sy; afficher_fen1 (gbm1, fen1_lut, "Bresenham(a)", "Clic sommet suivant", bresen_event_proc); } break; } } void trans_clic_proc (He_node *hn) { char *nom = HeGetButtonLabel(hn); if (gbm1 == NULL) return; if (strcmp (nom, "Remplis4(a,b)") == 0) { afficher_fen1 (gbm1, fen1_lut, nom, "Clic pour remplir", remplis_event_proc); } else if (strcmp (nom, "Bresenham(a)") == 0) { bresen_x1 = -1; /* Premier point */ afficher_fen1 (gbm1, fen1_lut, nom, "Clic premier sommet", bresen_event_proc); } } void tog_proc (He_node *hn) { char *nom = HeGetToggleLabel(hn); if (HeGetToggleValue(hn) == FALSE) return; if (strcmp(nom, "Gris") == 0) fen1_lut = LUT_GREY; else if (strcmp(nom, "Vga") == 0) fen1_lut = LUT_VGA; else if (strcmp(nom, "VgaGris") == 0) fen1_lut = LUT_VGA_GREY; else if (strcmp(nom, "RougeVert") == 0) fen1_lut = LUT_RED_GREEN; afficher_fen1 (gbm1, fen1_lut, nom, "", NULL); } void quit_proc (He_node *hn) { HeQuit(0); } void load_proc (He_node *hn) { char *nom = HeGetTextValue (text_load), bla[32]; FreeBsMap(gbm1); gbm1 = NULL; gbm1 = ReadBsMapFromPGM (nom, 0); if (gbm1 == NULL) { HeSimpleDialog ( HE_DIALOG_BELL, HE_DIALOG_TITLE, "Attention", HE_DIALOG_MESSAGE, "Erreur de lecture du fichier", HE_DIALOG_QUOTED, nom, HE_DIALOG_BUTTOK, "Ok", 0); return; } sprintf (bla, "%d", gbm1->ysiz); HeSetTextValue (text_haut, bla); sprintf (bla, "%d", gbm1->xsiz); HeSetTextValue (text_larg, bla); afficher_fen1 (gbm1, fen1_lut, gbm1->title, "", NULL); } void save_proc (He_node *hn) { char *nom = HeGetTextValue (text_save); if (gbm1 == NULL) { HeSimpleDialog ( HE_DIALOG_BELL, HE_DIALOG_TITLE, "Attention", HE_DIALOG_MESSAGE, "Image vide, rien à enregistrer", HE_DIALOG_BUTTOK, "Ok", 0); return; } if (WriteBsMapInPGM (nom, gbm1) < 0) { HeSimpleDialog ( HE_DIALOG_BELL, HE_DIALOG_TITLE, "Attention", HE_DIALOG_MESSAGE, "Erreur d'écriture du fichier", HE_DIALOG_QUOTED, nom, HE_DIALOG_BUTTOK, "Ok", 0); } } void new_proc (He_node *hn) { int haut = atoi(HeGetTextValue(text_haut)), larg = atoi(HeGetTextValue(text_larg)); if (haut < 1 || haut > 2048 || larg < 1 || larg > 2048) { HeSimpleDialog ( HE_DIALOG_BELL, HE_DIALOG_TITLE, "Attention", HE_DIALOG_MESSAGE, "Mauvaise taille d'image ; les limites sont", HE_DIALOG_MESSAGE, "1 <= Haut <= 2048, 1 <= Larg <= 2048", HE_DIALOG_BUTTOK, "Ok", 0); return; } FreeBsMap(gbm1); gbm1 = NewBsMap (haut, larg, 0); if (gbm1 == NULL) return; InitInterBsMap (gbm1, 0); afficher_fen1 (gbm1, fen1_lut, "Nouvelle image", "", NULL); } /*---------------------------- P R I N C I P A L ----------------------------*/ int main (int argc, char **argv) { int code_sortie; HeInit (&argc, &argv); princ = HeCreateFrame(); HeSetFrameLabel (princ, "Petit éditeur (cor)"); panel = HeCreatePanel (princ); text_load = HeCreateText (panel); HeSetTextVisibleLen (text_load, 38); HeSetTextCompletion (text_load, TRUE); HeSetTextNotifyProc (text_load, load_proc); HeCreateButtonP (panel, "Load", load_proc, NULL); HeSetPanelLayout (panel, HE_LINE_FEED); text_save = HeCreateText (panel); HeSetTextVisibleLen (text_save, 38); HeSetTextCompletion (text_save, TRUE); HeSetTextNotifyProc (text_save, save_proc); HeCreateButtonP (panel, "Save", save_proc, NULL); HeSetPanelLayout (panel, HE_LINE_FEED); HeCreateMessageP (panel, "Haut", TRUE); text_haut = HeCreateText (panel); HeSetTextVisibleLen (text_haut, 4); HeCreateMessageP (panel, "Larg", TRUE); text_larg = HeCreateText (panel); HeSetTextVisibleLen (text_larg, 4); HeCreateButtonP (panel, "New", new_proc, NULL); b_quit = HeCreateButtonP (panel, "Quit", quit_proc, NULL); HeSetPanelLayout (panel, HE_LINE_FEED); HeCreateMessageP (panel, "LUT", TRUE); tog_lut = HeCreateToggleRadioP (panel, "Gris", tog_proc, NULL); HeCreateToggleRadioP (panel, "Vga", tog_proc, tog_lut); HeCreateToggleRadioP (panel, "VgaGris", tog_proc, tog_lut); HeCreateToggleRadioP (panel, "RougeVert", tog_proc, tog_lut); HeSetPanelLayout (panel, HE_LINE_FEED); HeCreateButtonP (panel, "Sym V", trans_geom_proc, NULL); HeCreateButtonP (panel, "Sym H", trans_geom_proc, NULL); HeCreateButtonP (panel, "Sym D", trans_geom_proc, NULL); HeCreateButtonP (panel, "Rot 90", trans_geom_proc, NULL); HeSetPanelLayout (panel, HE_LINE_FEED); HeCreateMessageP (panel, "a =", TRUE); text_a = HeCreateText (panel); HeSetTextVisibleLen (text_a, 10); HeSetTextValue (text_a, "1"); HeCreateMessageP (panel, "b =", TRUE); text_b = HeCreateText (panel); HeSetTextVisibleLen (text_b, 10); HeSetTextValue (text_b, "0"); HeSetPanelLayout (panel, HE_LINE_FEED); HeCreateButtonP (panel, "a -> b", trans_abent_proc, NULL); HeCreateButtonP (panel, "a <-> b", trans_abent_proc, NULL); HeCreateButtonP (panel, " b", trans_abent_proc, NULL); HeCreateButtonP (panel, ">a -> b", trans_abent_proc, NULL); HeCreateButtonP (panel, "*a +b", trans_abdbl_proc, NULL); HeSetPanelLayout (panel, HE_LINE_FEED); HeCreateButtonP (panel, "Contour4(a,b)", trans_abent_proc, NULL); HeCreateButtonP (panel, "Rosenfeld(a,b)", trans_abent_proc, NULL); HeSetPanelLayout (panel, HE_LINE_FEED); HeCreateButtonP (panel, "Bresenham(a)", trans_clic_proc, NULL); HeCreateButtonP (panel, "Remplis4(a,b)", trans_clic_proc, NULL); HeSetPanelLayout (panel, HE_LINE_FEED); HeFit(panel); HeFit(princ); HeJustify (b_quit, NULL, HE_RIGHT); if (argc > 1) { HeSetTextValue (text_load, argv[1]); load_proc(text_load); } HeSetTextValue (text_save, argc > 2 ? argv[2] : "tmp1.pgm"); code_sortie = HeMainLoop (princ); FreeBsMap(gbm1); gbm1 = NULL; FreeXImage (fen1_xi); fen1_xi = NULL; return code_sortie; }