Erreur: undefined reference to `seek' (Modification fichier bmp)

Erreur: undefined reference to `seek' (Modification fichier bmp) - C - Programmation

Marsh Posté le 21-10-2007 à 10:09:36    

Bonjour à tous, j'ai récemment découvert que les fichiers bmp était facilement modifiables grâce à ce site: http://www.wotsit.org/ et notamment cette page http://www.fortunecity.com/skyscra [...] ffrmt.html
 
J'ai essayer avec un éditeur hexadécimal de voir si ça correspondait et effectivement oui (heureusement :D )
 
Du coup je me suis lancé avec fread et fwrite pour modifier des octets et ça a marché. Je me suis donc amusé à récupérer la taille, la résolution puis à modifier des pixels jusqu'a créer une fonction "négatif" qui inverse toutes les couleurs de l'image.
 
Mais seulement voilà, je découvre les erreurs de "linkage", je ne sais pas si le terme est juste. Apparemment le linker ne trouve pas un truc qui devrait se trouver là où il cherche.
 
Voilà ce que codeblocks me donne:
 
Switching to target: default
Linking console executable: E:\Documents\Programmes\avi\avi.exe
.objs\bmp.o:bmp.c:(.text+0xf5): undefined reference to `seek'
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 0 seconds)
0 errors, 0 warnings

 
Apparemment l'erreur vient du fichier bmp.c (logique elle est apparue après de modif dans des fonctions de ce fichier). Mais la compilation à l'air d'avoir été faite (bmp.o) mais c'est au moment de la création des liens que ça bloque. Il faudrait donc configurer le linker? Bizzare étant donné que je n'utilise rien de spécial comme bibliothèque.
 
J'ai 3 fichiers dans mon projet: main.c, bmp.h et bmp.c
J'ai inclu stdio.h et stdlib.h
 
 
 
Voilà mes fichiers:
 
main.c

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "bmp.h"
  4. int main(int argc, char *argv[])
  5. {
  6.    FILE *bmp;
  7.    bmp = fopen(argv[1],"r+" );
  8.    inverser_couleurs_bmp(bmp);
  9. return EXIT_SUCCESS;
  10. }


 
bmp.h

Code :
  1. #define ROUGE RVB(255,0,0)
  2. #define BLEU RVB(0,0,255)
  3. #define VERT RVB(0,255,0)
  4. #define NOIR RVB(0,0,0)
  5. #define BLANC RVB(255,255,255)
  6. #define GRIS RVB(128,128,128)
  7. #define OFFSET_DATA 54
  8. typedef struct{
  9.    int rouge;
  10.    int vert;
  11.    int bleu;
  12. }t_couleur;
  13. typedef struct{
  14.    int x;
  15.    int y;
  16. }t_pixel;
  17. long int taille_octet_bmp(FILE *bmp);
  18. long int largeur_pixel_bmp(FILE *bmp);
  19. long int hauteur_pixel_bmp(FILE *bmp);
  20. int offset_pixel_bmp(FILE *bmp,int x, int y);
  21. long int offset_donnees_bmp(FILE *bmp);
  22. t_couleur RVB(int r, int v, int b);
  23. void modifier_couleur_pixel(FILE *bmp, int x, int y, t_couleur *couleur);
  24. t_couleur couleur_pixel_bmp(FILE *bmp,int x, int y);
  25. void inverser_couleur_pixel(FILE *bmp, int x, int y,t_couleur *couleur_origine,t_couleur *couleur_inverse);
  26. void inverser_couleurs_bmp(FILE *bmp);


 
bmp.c

Code :
  1. #include <stdio.h>
  2. #include "bmp.h"
  3. //Renvoi la taille de l'image en octets
  4. long int taille_octet_bmp(FILE *bmp)
  5. {
  6.    long int taille;
  7.    fseek(bmp,2,SEEK_SET);
  8.    fread(&taille,4,1,bmp);
  9.    return taille;
  10. }
  11. //Renvoie lenombre de pixel en largeur
  12. long int largeur_pixel_bmp(FILE *bmp)
  13. {
  14.    long int largeur;
  15.    fseek(bmp,18,SEEK_SET);
  16.    fread(&largeur,4,1,bmp);
  17.    return largeur;
  18. }
  19. //Renvoie le nombre de pixel en hauteur
  20. long int hauteur_pixel_bmp(FILE *bmp)
  21. {
  22.    long int hauteur;
  23.    fseek(bmp,22,SEEK_SET);
  24.    fread(&hauteur,4,1,bmp);
  25.    return hauteur;
  26. }
  27. //Renvoie la position du 1er octet ds le bmp décrivant les donnees de l'image (54 pour bmp 24 bits)
  28. long int offset_donnees_bmp(FILE *bmp)
  29. {
  30.    long int offset;
  31.    seek(bmp,10,SEEK_SET);
  32.    fread(&offset,4,1,bmp);
  33.    return offset;
  34. }
  35. //Renvoie une couleur RVB dans une structure t_couleur
  36. t_couleur RVB(int r, int v, int b)
  37. {
  38.    t_couleur couleur;
  39.    couleur.rouge = r;
  40.    couleur.vert = v;
  41.    couleur.bleu = b;
  42.    return couleur;
  43. }
  44. //Renvoie la position du 1er des 3 octets ds le bmp décrivant un pixel de coordonnées (x,y)
  45. int offset_pixel_bmp(FILE *bmp,int x, int y)
  46. {
  47.    int nbre_octet_ligne = largeur_pixel_bmp(bmp);
  48.    //Si le nbre de pixel par ligne n'est pas multiple de 4 le nbre d'octet décrivant une ligne du bmp est le nbre multiple de 4 supérieur
  49.    nbre_octet_ligne += 4-nbre_octet_ligne%4;
  50.    return OFFSET_DATA+3*((y-1)*nbre_octet_ligne+(x-1));
  51. }
  52. //Modifie les 3 octets ds le bmp décrivant la couleur d'un pixel de coordonnees (x,y)
  53. void modifier_couleur_pixel(FILE *bmp, int x, int y, t_couleur *couleur)
  54. {
  55.       fseek(bmp,offset_pixel_bmp(bmp,x,y),SEEK_SET);
  56.       fwrite(&couleur->bleu,1,1,bmp);
  57.       fwrite(&couleur->vert,1,1,bmp);
  58.       fwrite(&couleur->rouge,1,1,bmp);
  59. }
  60. //Renvoie la couleur d'un pixel de coordonnees (x,y) sous un format t_couleur
  61. t_couleur couleur_pixel_bmp(FILE *bmp,int x, int y)
  62. {
  63.    t_couleur couleur_pixel;
  64.    int offset_pixel = offset_pixel_bmp(bmp,x,y);
  65.    fseek(bmp,offset_pixel,SEEK_SET);
  66.    if(offset_pixel!=-1)
  67.    {
  68.       fread(&couleur_pixel.bleu,1,1,bmp);
  69.       fread(&couleur_pixel.vert,1,1,bmp);
  70.       fread(&couleur_pixel.rouge,1,1,bmp);
  71.       return couleur_pixel;
  72.    }
  73. }
  74. //Effectue le complément des 3 octets décrivant la couleur d'un pixel de coordonnees (x,y) pour obtenir la couleur inverse
  75. void inverser_couleur_pixel(FILE *bmp, int x, int y,t_couleur *couleur_origine,t_couleur *couleur_inverse)
  76. {
  77.    *couleur_origine = couleur_pixel_bmp(bmp,x,y);
  78.    couleur_inverse->rouge = 255-couleur_origine->rouge;
  79.    couleur_inverse->vert = 255-couleur_origine->vert;
  80.    couleur_inverse->bleu = 255-couleur_origine->bleu;
  81.    modifier_couleur_pixel(bmp,x,y,couleur_inverse);
  82. }
  83. //Inverse la couleur de tous les pixel d'une image bmp
  84. void inverser_couleurs_bmp(FILE *bmp)
  85. {
  86.    int largeur = largeur_pixel_bmp(bmp);
  87.    int hauteur = hauteur_pixel_bmp(bmp);
  88.    t_couleur couleur_origine, couleur_inverse;
  89.    int x,y;
  90.    for(y=1;y<=largeur;y++)
  91.    {
  92.       printf("y=%d\n",y);
  93.       for(x=1;x<=largeur;x++)
  94.          inverser_couleur_pixel(bmp,x,y,&couleur_origine,&couleur_inverse);
  95.    }
  96. }


 
Merci pour votre aide, je continue à chercher...


Message édité par ngkreator le 22-10-2007 à 15:19:51
Reply

Marsh Posté le 21-10-2007 à 10:09:36   

Reply

Marsh Posté le 21-10-2007 à 10:34:28    

T'aurais pas simplement ecrit "seek" au lieu de "fseek" ... ?
edit pour l'explication: quand ton compilo tombe sur une fonction qu'il ne connait pas, alors il suppose qu'elle renvoie un int et que tous ses parametres sont des int. Dans ton .o, il y a donc des references vers cette fonction qui sont faites. Mais si la fonction n'existe pas (dans un autre .o ou dans une bibliotheque), alors les references ne vont pas pouvoir etre resolues, et ca va te donner des erreurs a l'edition de liens.

Message cité 1 fois
Message édité par Ace17 le 21-10-2007 à 10:36:42
Reply

Marsh Posté le 21-10-2007 à 10:41:01    

Ace17 a écrit :

T'aurais pas simplement ecrit "seek" au lieu de "fseek" ... ?
edit pour l'explication: quand ton compilo tombe sur une fonction qu'il ne connait pas, alors il suppose qu'elle renvoie un int et que tous ses parametres sont des int. Dans ton .o, il y a donc des references vers cette fonction qui sont faites. Mais si la fonction n'existe pas (dans un autre .o ou dans une bibliotheque), alors les references ne vont pas pouvoir etre resolues, et ca va te donner des erreurs a l'edition de liens.


[:tinostar] Je suis con et pas fier de l'air :pfff:  
 
Vraiment un grand merci  Ace17 pour m'avoir branché le cerveau en ce bon matin!
 
Edit: ok merci également pour les précisions ça m'aide beaucoup à comprendre. J'ai recompilé et ça marche! En plus j'arrive enfin à rendre une image négative dans un délai raisonnable. (d'ailleurs c'est dur de trouver un compromis vitesse/nbre de vérifications des erreurs)


Message édité par ngkreator le 21-10-2007 à 10:48:04
Reply

Marsh Posté le 21-10-2007 à 12:15:58    

Bon voilà ce que j'obtiens en 37sec (et là je me dit que je ne pesterai plus contre photoshop quand il rame alors que moi c'est pire :D ) sur un bmp de 900x513:
 
 http://img179.imagevenue.com/loc210/th_62107_205b_122_210lo.jpg =>  http://img193.imagevenue.com/loc383/th_62101_205_122_383lo.jpg
 
 
Comme vous pouvez le voir il y a des points bleu qui apparaissent c'est intéressant. Je vais voir pourquoi.
 
Je me demande quels algorithme ils utilisent dans les logiciels, c'est là que je me rends compte qu'ils sont très rapide.


Message édité par ngkreator le 21-10-2007 à 12:23:47
Reply

Marsh Posté le 21-10-2007 à 13:07:02    

Ton programme est lent parce qu'il passe son temps a faire des seek/fread/fwrite. Dans l'ideal on charge le bitmap completement en memoire (avec un seul fread), on le modifie, et on le reecrit sur le disque (avec un seul fwrite). Fais ca, et tu vas voir que tu vas enormement gagner en rapidite.

Reply

Marsh Posté le 21-10-2007 à 13:10:34    

Ace17 a écrit :

Ton programme est lent parce qu'il passe son temps a faire des seek/fread/fwrite. Dans l'ideal on charge le bitmap completement en memoire (avec un seul fread), on le modifie, et on le reecrit sur le disque (avec un seul fwrite). Fais ca, et tu vas voir que tu vas enormement gagner en rapidite.


Ah oui c'est vrai! Merci je vas faire ça.

Reply

Marsh Posté le 21-10-2007 à 13:20:49    

Attention, tu as oublié l'appel à fclose(). Vérifie également que tu as bien pu ouvrir le fichier comme tu le voulais.


---------------
You get so used to things the way they are. And I've always been alone. I guess that makes me lonely.
Reply

Marsh Posté le 21-10-2007 à 14:25:25    

Tu as raison merci.

Reply

Marsh Posté le 22-10-2007 à 15:34:32    

Ok merci pour la précision.
 
Sinon j'ai compris mon erreur, mais je ne comprends pas pourquoi ma fonction fonctionnait dans un cas mais pas dans l'autre:
 
Celle là ne fonctionnait pas:

Code :
  1. nouvo_type fonction(FILE* fichier)
  2. {
  3.     nouvo_type data;
  4.     int tmp;
  5.     printf("Avant: %d\n",tmp);
  6.     fread(&tmp,1,1,fichier);
  7.     printf("Après: %d\n",tmp);
  8.    
  9.     return data;
  10. }


 
Celle là si:

Code :
  1. void fonction(FILE* fichier)
  2. {
  3.     int tmp;
  4.     printf("Avant: %d\n",tmp);
  5.     fread(&tmp,1,1,fichier);
  6.     printf("Après: %d\n",tmp);
  7. }


 
Et dans le premier cas pourquoi ça ne marchais pas quand le nombre de pointeurs dans ma structure nouvo_type était supérieur à 2?


Message édité par ngkreator le 22-10-2007 à 17:22:54
Reply

Marsh Posté le 22-10-2007 à 15:52:28    

man fread.
Mauvaise utilisation de fread

Reply

Marsh Posté le 22-10-2007 à 15:52:28   

Reply

Marsh Posté le 22-10-2007 à 15:53:30    

Tu écrit un octet dans un entier... Il faut lire sizeof tmp, pas 1.
 
Edit : enfin puisque tu veux lire un octet, lit un octet, mais met-le dans une variable de type char, pas int.

Message cité 1 fois
Message édité par matafan le 22-10-2007 à 15:56:06
Reply

Marsh Posté le 22-10-2007 à 15:54:11    

Juste en passant ...
66 -> 0x42
4206595 -> 0x403003
4206658 -> 0x403042

Reply

Marsh Posté le 22-10-2007 à 15:54:35    

Taz a écrit :

man fread.
Mauvaise utilisation de fread


man quésaco?
 
A quel niveau je l'ai mal utilisé? Pour savoir vers où chercher.

Reply

Marsh Posté le 22-10-2007 à 15:55:49    

fread a des arguments, ils ont un sens. Ouvre ton manuel et corrige celui qui est défectueux.

Reply

Marsh Posté le 22-10-2007 à 15:58:44    

ngkreator a écrit :


man quésaco?


man = 'manual' (manuel)
 
Par exemple :  
 
http://man.developpez.com/
 
ou  

* man fonction


sous unixoïde ou Cygwin (Windows).

Message cité 1 fois
Message édité par Emmanuel Delahaye le 22-10-2007 à 16:00:58

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 22-10-2007 à 16:22:03    

matafan a écrit :

Tu écrit un octet dans un entier... Il faut lire sizeof tmp, pas 1.
 
Edit : enfin puisque tu veux lire un octet, lit un octet, mais met-le dans une variable de type char, pas int.

Je comprends, étant donné que char stocke un seul octet ça me parait logique au final. Mais ça porte pas à confusion le fait d'utiliser char pour une valeur numérique? Mais au moins ça ne gaspille pas le 2ème 'octet qui ne sert pas avec int ok.
 

Taz a écrit :

Juste en passant ...
66 -> 0x42
4206595 -> 0x403003
4206658 -> 0x403042

Ah oui d'accord. Donc apparemment il aurai ajouté la valeur tout simplement. Mais sinon je comprends pas pourquoi ça serait affiché en hexadécimal si dans mon printf j'ai mis %d?
 

Emmanuel Delahaye a écrit :


man = 'manual' (manuel)
 
Par exemple :  
 
http://man.developpez.com/
 
ou  

* man fonction


sous unixoïde ou Cygwin (Windows).

Ok, bien sur je suis allé voir à plusieurs endroits comme ici par ex: http://www.cplusplus.com/reference [...] fread.html
 
Il y a de très bon cours en pdf aussi, je les ai consultés.  
 
 
Pour l'instant je ne vois pas où je me trompé dans l'utilisation de fread mais je vais revoir les docs.

Message cité 1 fois
Message édité par ngkreator le 22-10-2007 à 16:24:01
Reply

Marsh Posté le 22-10-2007 à 16:25:40    

ngkreator a écrit :

Je comprends, étant donné que char stocke un seul octet ça me parait logique au final. Mais ça porte pas à confusion le fait d'utiliser char pour une valeur numérique? Mais au moins ça ne gaspille pas le 2ème 'octet qui ne sert pas avec int ok.
 

Si tu veux lire un char, utilise un char. Si tu utilises un int, lis un int.
 
Trop bien ton économie de 3 octets, tu devrais postuler à la NASA.
Un char est une sorte d'entier. Le seul truc c'est qu'a travailler en char, ça peut se réveler une contre-optimisation.

Reply

Marsh Posté le 22-10-2007 à 16:37:44    

Taz a écrit :

Si tu veux lire un char, utilise un char. Si tu utilises un int, lis un int.
 
Trop bien ton économie de 3 octets, tu devrais postuler à la NASA.
Un char est une sorte d'entier. Le seul truc c'est qu'a travailler en char, ça peut se réveler une contre-optimisation.

Le problème c'est que je veux lire 1 octet. Je le stocke dans un char ou un int ça marche pour les deux. Après je pensais juste que le type int portait moins à confusion, quand on lit le programme, que le type char pour stocker un octet.
 
Super ta remarque pour la NASA j'ai juste essayé de trouver une raison pour laquelle il me disait d'utiliser char au lieu de int.

Reply

Marsh Posté le 22-10-2007 à 16:43:05    

ngkreator a écrit :

Le problème c'est que je veux lire 1 octet. Je le stocke dans un char ou un int ça marche pour les deux.

Stockage != lecture. Même remarque que précédemment. man fread. Là tu lis un byte qui écrit partiellement un int. C'est mauvais. Si tu lis un char, utilise un char.

Reply

Marsh Posté le 22-10-2007 à 17:07:27    

Ca y est je viens de comprendre. C'est en utilisant char et en voyant que ça fonctionnait comme ça que j'ai compris. En fait fread modifie 1 seul octet à partir de l'adresse contenu dans le 1er argument.
 
En fait sur mon pc j'ai tmp qui est sur 2 octets:
 
Programme                             Valeur des octets dans tmp
 
int tmp;                                0x33 0x56 (valeurs quelconques)
fread(&tmp,1,1,fichier);           0x42 0x56 (1seul octet modifié)
 
Je pensais que le 2ème argument de fread (ici égal à 1) indiquait seulement le nbre d'octet à lire dans "fichier". La valeur contenue dans l'octet était alors assigné à l'élément pointé par le 1er argument (&tmp) quel que soit le nombre d'octet. Je croyais bètement qu'il devinait que tmp représentait 2 octets et qu'il inscrivait 66 en prenant en compte qu'il fallait qu'il modifie les deux octets.  
Alors que tout ce qu'il sait ici c'est l'adresse de l'emplacement où il doit modifier x octets.
 
Edit:

Taz a écrit :

Stockage != lecture. Même remarque que précédemment. man fread. Là tu lis un byte qui écrit partiellement un int. C'est mauvais. Si tu lis un char, utilise un char.


Ah voilà j'aurai vu ça avant j'aurais plus vite compris, merci. C'est justement ce que je disais je croyais que le 2ème argument indiquait seulement le nbre d'octet à lire et non pas à écrire.
 
Merci de votre aide :jap:

Message cité 1 fois
Message édité par ngkreator le 22-10-2007 à 17:16:45
Reply

Marsh Posté le 22-10-2007 à 17:11:56    

Il faut avouer que la doc que j'avais porte à confusion: http://www.cplusplus.com/reference [...] fread.html
 
Size in bytes of each element to be read.

Reply

Marsh Posté le 22-10-2007 à 17:12:05    

Bravo
 
Celà dit en général un int c'est 4 octets, pas 2.

Reply

Marsh Posté le 22-10-2007 à 17:14:11    

matafan a écrit :

Bravo
 
Celà dit en général un int c'est 4 octets, pas 2.


 
Dans une doc en pdf (pas de titre) ils disent que sur un PC c'est 16 bits comme le short.  
 
Ah mais PC ne veux pas obligatoirement dire Windows c'est vrai.
 
Edit: sizeof(int) me sort 4, donc tu as raison :jap:
 
C'est vraiment intéressant le c pour ça, on découvre des trucs.


Message édité par ngkreator le 22-10-2007 à 17:18:08
Reply

Marsh Posté le 22-10-2007 à 17:18:01    

En fait, la norme garantie juste que la taille minimum d'un int c'est 16 bits.  
Mais après, ça dépend du système. Et clairement en ce moment c'est plutôt 32 bits... quand ce n'est pas 64.

Reply

Marsh Posté le 22-10-2007 à 17:23:41    

ngkreator a écrit :

Je pensais que le 2ème argument de fread (ici égal à 1) indiquait seulement le nbre d'octet à lire dans "fichier".

Le truc c'est de ne pas penser, et se référer à la documentation.

The function fread() reads nmemb objects, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr.


 
Usage simple:

Code :
  1. T data[N];
  2. if (fread(data, sizeof data[0], N, input) != N) { ... probleme }

Reply

Marsh Posté le 22-10-2007 à 17:23:48    

Ok merci pour la précision.
 
Sinon j'ai compris mon erreur, mais je ne comprends pas pourquoi ma fonction fonctionnait dans un cas mais pas dans l'autre:
 
Celle là ne fonctionnait pas:

Code :
  1. nouvo_type fonction(FILE* fichier)
  2. {
  3.     nouvo_type data;
  4.     int tmp;
  5.     printf("Avant: %d\n",tmp);
  6.     fread(&tmp,1,1,fichier);
  7.     printf("Après: %d\n",tmp);
  8.    
  9.     return data;
  10. }


 
Celle là si:

Code :
  1. void fonction(FILE* fichier)
  2. {
  3.     int tmp;
  4.     printf("Avant: %d\n",tmp);
  5.     fread(&tmp,1,1,fichier);
  6.     printf("Après: %d\n",tmp);
  7. }


 
Et dans le premier cas pourquoi ça ne marchais pas quand le nombre de pointeurs dans ma structure nouvo_type était supérieur à 2?

Reply

Marsh Posté le 22-10-2007 à 17:28:32    

bah parce que tmp est pas initialisé, et si fread échoue ou ne lis pas le bon nombre de données (ton cas, tu lis 1 au lieu de sizeof(int)), et bah t'as de la soupe dans tmp, écrasée partiellement par tes données.

Reply

Marsh Posté le 22-10-2007 à 17:35:51    

Taz a écrit :

Le truc c'est de ne pas penser, et se référer à la documentation.

The function fread() reads nmemb objects, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr.


 
Usage simple:

Code :
  1. T data[N];
  2. if (fread(data, sizeof data[0], N, input) != N) { ... probleme }


Le nom de ta doc? J'ai suivi la mienne sans réfléchir etdu coup je l'ai cru bètement.  

Taz a écrit :

bah parce que tmp est pas initialisé, et si fread échoue ou ne lis pas le bon nombre de données (ton cas, tu lis 1 au lieu de sizeof(int)), et bah t'as de la soupe dans tmp, écrasée partiellement par tes données.

Oui en fait je me suis mal exprimé. J'ai compris pourquoi ça marchait pas, ok.  
 
Mais il y a deux fonctions: une qui ne marche pas, normal, mais il y en a une autre qui fonctionne alors qu'elle ne devrait pas.
2ème point, dans celle qui ne marche pas, il se trouve qu'elle fonctionne si le nombre de pointeur est infèrieur à 3.

Reply

Marsh Posté le 22-10-2007 à 17:42:14    

ngkreator a écrit :

Celle là ne fonctionnait pas:

Code :
  1. nouvo_type fonction(FILE* fichier)
  2. {
  3.     nouvo_type data;
  4.     int tmp;
  5.     printf("Avant: %d\n",tmp);
  6.     fread(&tmp,1,1,fichier);
  7.     printf("Après: %d\n",tmp);
  8.    
  9.     return data;
  10. }




 
Euh, tu as remarqué que tu lisais (mal) dans la variable tmp, mais que tu retournais la variable data (non initialisée) ?

Message cité 1 fois
Message édité par tpierron le 22-10-2007 à 17:42:42
Reply

Marsh Posté le 22-10-2007 à 17:47:27    

tpierron a écrit :


 
Euh, tu as remarqué que tu lisais (mal) dans la variable tmp, mais que tu retournais la variable data (non initialisée) ?

Oui, mais c'est une fonction fictive pour simplifier la présentation. J'allais pas vous noyer dans des trucs inutiles. Ma vraie fonction avait cette forme:
 

Code :
  1. t_bmp charger_image_bmp(FILE *fichier_bmp)
  2. {
  3.     t_bmp struct_bmp;
  4.     int nb_octet_ligne,i,tmp;
  5.     long int largeur,hauteur;
  6.     fseek(fichier_bmp,18,SEEK_SET);
  7.     fread(&largeur,4,1,fichier_bmp);
  8.     fseek(fichier_bmp,22,SEEK_SET);
  9.     fread(&hauteur,4,1,fichier_bmp);
  10.     if(3*largeur%4!=0)
  11.         nb_octet_ligne=3*largeur+4-largeur%4;
  12.     struct_bmp.header=malloc(sizeof(int)*10);
  13.     struct_bmp.info_header=malloc(sizeof(int)*40);
  14.     struct_bmp.ligne_data=malloc(sizeof(int*)*hauteur);
  15.     for(i=0;i<hauteur;i++)
  16.         struct_bmp.ligne_data[i]=malloc(sizeof(int)*nb_octet_ligne);
  17.     fseek(fichier_bmp,0,SEEK_SET);
  18.     for(i=0;i<10;i++)
  19.     {
  20.         fread(&tmp,1,1,fichier_bmp);
  21.         printf("%d \n",tmp);
  22.     }
  23.     return struct_bmp;
  24. }

On voit le printf qui m'a servit à voir que c'était à ce fread que j'avais fait une connerie.

Message cité 1 fois
Message édité par ngkreator le 22-10-2007 à 17:51:10
Reply

Marsh Posté le 22-10-2007 à 17:50:24    

tous ces fread/fseek/malloc sans controller le retour, ça peut faire boom sans que tu t'en rendes compte.
 
 
Et ces malloc(<taille fixe/statique/connu à la compilation> ) dégage-les (sauf si tu comptres faire du realloc ensuite).
 
header=malloc(sizeof(int)*10);
-> int header[10];
 
 
Halte au nombre magique. Utilise sizeof et pas 4. Tu veux donner du sens, et bien "sizeof(int)" voire "sizeof largueur" ça ça a du sens. 4 non.

Reply

Marsh Posté le 22-10-2007 à 17:58:35    

Taz a écrit :

tous ces fread/fseek/malloc sans controller le retour, ça peut faire boom sans que tu t'en rendes compte.
 
 
Et ces malloc(<taille fixe/statique/connu à la compilation> ) dégage-les (sauf si tu comptres faire du realloc ensuite).
 
header=malloc(sizeof(int)*10);
-> int header[10];
 
 
Halte au nombre magique. Utilise sizeof et pas 4. Tu veux donner du sens, et bien "sizeof(int)" voire "sizeof largueur" ça ça a du sens. 4 non.


Attention cette fonction est le résultats de moultes suppressions (nottamment les controles des fread/fseek/malloc) pour essayer d'alléger aux max la fonction. Cette fonction est pourrie et m'a juste servi à trouver l'erreur. La variable tmp n'a rien à faire là (juste pour simplifier les test), elle remplace un tableau qui devait me servir dans la structure. Et encore j'ai enlevé les commentaires qui m'avait permit d'isoler le fread.
 
Par contre je prends toutes tes remarques car dans ma vrai fonction j'avais utilisé des malloc pour rien aussi et les sizeof également.


Message édité par ngkreator le 22-10-2007 à 18:00:05
Reply

Marsh Posté le 22-10-2007 à 18:09:48    

ngkreator a écrit :


Code :
  1. t_bmp charger_image_bmp(FILE *fichier_bmp)
  2. {
  3.     t_bmp struct_bmp;
  4.     int nb_octet_ligne,i,tmp;
  5.     long int largeur,hauteur;
  6.     fseek(fichier_bmp,18,SEEK_SET);
  7.     fread(&largeur,4,1,fichier_bmp);



Ce code est horriblement pas portable... Tu fais l'hypothèse qu'un int fait 4 octets, ce qui est faux (la norme dit, en d'autres termes, 'au moins 2 octets'). De plus, il ne tient pas compte de l'endianess...
 
C'est pas comme ça qu'on fait. On lit octet par octet avec fgetc() et on charge comme ll faut les octets dans les variables à coup de décalage dans le bon sens. La convention réseau/fichiers est MSB en tête (sauf formats Microsoft à la gomme, genre BMP ou WAV).


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 22-10-2007 à 18:22:35    

Emmanuel Delahaye a écrit :


Ce code est horriblement pas portable... Tu fais l'hypothèse qu'un int fait 4 octets, ce qui est faux (la norme dit, en d'autres termes, 'au moins 2 octets'). De plus, il ne tient pas compte de l'endianess...
 
C'est pas comme ça qu'on fait. On lit octet par octet avec fgetc() et on charge comme ll faut les octets dans les variables à coup de décalage dans le bon sens. La convention réseau/fichiers est MSB en tête (sauf formats Microsoft à la gomme, genre BMP ou WAV).


Merci :jap:  
 
Je viens de découvrir ce qu'est l'endianess, je m'étais d'ailleur posé la question de où se situaient les octets de poids fort (si on peut appeler ça comme ça?) quand une donnée était inscrite sur plusieurs octet.  
 
Grâce à toutes ces remarques (posts précédents inclus) je vais pouvoir faire un truc déjà plus potable :jap:


Message édité par ngkreator le 22-10-2007 à 18:22:56
Reply

Marsh Posté le 22-10-2007 à 18:35:14    

En fait, dans ce cas, il a raison d'utiliser 4 et pas sizeof(int). Il lit un format de fichier complètement figé depuis 15 ans au moins et qui ne changera certainement plus (au risque de péter qqs milliers d'applications, ce que Microsoft ne prendra jamais le risque de faire). Je changerais plutôt les variables int en uint32_t (déclarés dans stdint.h).
 
Sinon GDI+, dispose de tout un tas de fonction pour lire des bitmaps direct en mémoire. Bon, il faut coder sous Windows.

Reply

Marsh Posté le 22-10-2007 à 18:43:40    

tpierron a écrit :

En fait, dans ce cas, il a raison d'utiliser 4 et pas sizeof(int). Il lit un format de fichier complètement figé depuis 15 ans au moins et qui ne changera certainement plus (au risque de péter qqs milliers d'applications, ce que Microsoft ne prendra jamais le risque de faire). Je changerais plutôt les variables int en uint32_t (déclarés dans stdint.h).
 
Sinon GDI+, dispose de tout un tas de fonction pour lire des bitmaps direct en mémoire. Bon, il faut coder sous Windows.

Ah mais le but c'est de m'amuser et d'arriver à modifier des bmp sans bibliothèques qui vont me fournir des fonctions déjà toutes faites.
Avant ce week end je savais pas que les images bmp était de simples fichiers binaires qu'on pouvait modifier octet par octet [:cupra] . Je veux vraiment partir de la base et voir comment ça fonctionne.
 
Un jour je m'essayerai au jpeg avec fourrier [:totoz]
 
En fait c'est parti du prof de méca en vibration qui nous explique fourrier, puis le fait qu'on l'utilise dans le jpeg et moi qui me dit mais ça doit être intéressant tout ça [:dawa]


Message édité par ngkreator le 22-10-2007 à 18:49:04
Reply

Marsh Posté le 24-10-2007 à 19:00:47    

J'ai avancé sur ma fonction me permettant de charger un fichier dans une structure. Elle prend un fichier en paramètre, renvoie un pointeur sur une structure.
 
J'ai initialisé une struture dans la fonction pour renvoyer son adresse par la suite. Je pensais que ça n'allais pas marcher puisque que tout variable interne à une fonction ou un bloc était invisible à l'extérieur. Invisible mais pas "détruit" apparemment puisqu'on peut y accéder par son adresse.  
L'avantage c'est que j'ai les tableaux qui contienne l'en tête du fichier bmp dans la structure ont déjà leur espace mémoire.
 
J'ai hésité pour la disposition des if,else et return en cas d'erreur. Ca pose problème de faire plusieurs return en plein milieu de la fonction? J'ai essayé de ne faire que 2 return (1 pour renvoyer la structure l'autre un pointeul NULL en cas d'erreur) avec une cascade if,else assez imbuvable.  
 
J'ai pas jugé utile de tester les fgets, en considérant que si la fin du fichier n'est pas atteinte (vérifié par feof) le programme devrait s'en sortir pour lire un octet.
 
La structure
 

Code :
  1. typedef struct
  2. {
  3.     unsigned char header[10];
  4.     unsigned char info_header[40];
  5.     unsigned char **data;
  6. }
  7. t_bmp;


 
La fonction
 

Code :
  1. t_bmp *charger_image_bmp(FILE *fichier_bmp)
  2. {
  3.     int largeur, hauteur;
  4.     int nb_ligne_data, nb_octet_ligne_data, nb_octet_data;
  5.     int i,j,resultat;
  6.     short int format;
  7.     t_bmp struct_bmp;
  8.     //Vérification du format bmp-------------------------
  9.     fseek(fichier_bmp,0,SEEK_SET);
  10.     resultat=fread(&format,sizeof(short int),1,fichier_bmp);
  11.     if(resultat!=1)
  12.     {
  13.         puts("Erreur de lecture dans le fichier bmp.1" );
  14.         return NULL;
  15.     }
  16.     if(format!=19778)
  17.     {
  18.         puts("Le fichier n'est pas une image bmp valide.2" );
  19.         return NULL;
  20.     }
  21.     fseek(fichier_bmp,0,SEEK_SET);
  22.     //Lecture de header----------------------------------
  23.     for(i=0;i<10&&!feof(fichier_bmp);i++)
  24.         struct_bmp.header[i]=fgetc(fichier_bmp);
  25.     if(i<10)
  26.     {
  27.         puts("Le fichier n'est pas une image bmp valide.3" );
  28.         return NULL;
  29.     }
  30.     //Lecture de info_header
  31.     for(i=0;i<40&&!feof(fichier_bmp);i++)
  32.         struct_bmp.info_header[i]=fgetc(fichier_bmp);
  33.     if(i<40)
  34.     {
  35.         puts("Le fichier n'est pas une image bmp valide.4" );
  36.         return NULL;
  37.     }
  38.     //Lecture de data (données pixels)--------------------
  39.     largeur = hauteur=0;
  40.     for(i=0;i<4;i++)//A remplacer par une fonction
  41.     {
  42.         largeur+=puiss2(8*i)*struct_bmp.info_header[i+4];
  43.         hauteur+=puiss2(8*i)*struct_bmp.info_header[i+8];
  44.     }
  45.     nb_ligne_data = hauteur;
  46.     nb_octet_ligne_data = 3*largeur;
  47.     if(nb_octet_ligne_data%4!=0)
  48.         nb_octet_ligne_data += 4-nb_octet_ligne_data%4;
  49.     nb_octet_data = nb_ligne_data*nb_octet_ligne_data;
  50.     struct_bmp.data=malloc(nb_ligne_data*sizeof(unsigned char*));
  51.     if(struct_bmp.data==NULL)
  52.         return NULL;
  53.     else
  54.     {
  55.         for(i=0;i<nb_ligne_data;i++)
  56.         {
  57.             struct_bmp.data[i]=malloc(nb_octet_ligne_data*sizeof(unsigned char));
  58.             if(struct_bmp.data[i]==NULL)
  59.             {
  60.                 puts("Erreur allocation memoire" );
  61.                 return NULL;
  62.             }
  63.         }
  64.     }
  65.     for(i=0;i<nb_ligne_data&&!feof(fichier_bmp);i++)
  66.     {
  67.         for(j=0;j<nb_octet_ligne_data&&!feof(fichier_bmp);j++)
  68.         {
  69.             struct_bmp.data[i][j]=fgetc(fichier_bmp);
  70.         }
  71.     }
  72.     if(i<nb_ligne_data||j<nb_octet_ligne_data)
  73.     {
  74.         puts("Le fichier n'est pas une image bmp valide.5" );
  75.         return NULL;
  76.     }
  77.     return &struct_bmp;
  78. }


 
Pour lire la valeur de plusieur octet dans le bon sens je vais remplacer le for suivant par une fonction:
 

Code :
  1. for(i=0;i<4;i++)//A remplacer par une fonction
  2.     {
  3.         largeur+=puiss2(8*i)*struct_bmp.info_header[i+4];
  4.         hauteur+=puiss2(8*i)*struct_bmp.info_header[i+8];
  5.     }


 
A remplacer par (en considérant que dans un bmp l'octet de poids faible est placé en 1er):
 

Code :
  1. int valeur(unsigned char *tab,int octet_depart, int nb_octet)
  2. {//Aperçu juste pour montrer l'esprit de la fonction
  3.        for(i=0;i<nb_octet;i++)
  4.     {
  5.         largeur+=puiss2(8*i)*tab[i];
  6.     }
  7. }


 
J'ai des problèmes avec cette fonction, mais c'est normal je trouverai le problème.
 

Reply

Marsh Posté le 24-10-2007 à 21:46:43    

Erreur, il ne faut jamais retourner une variable locale à une fonction, elle n'existe que dans la fonction et la mémoire est libérée à la sortie de la fonction. Si tu arrives à lire en passant par l'adresse, c'est que cette mémoire n'a pas encore été écrasée au moment où tu la lis.
 
Fais plutot un truc du style :

Code :
  1. t_bmp *struct_bmp;
  2. struct_bmp = malloc(sizeof(struct_bmp));
  3. ...
  4. ...
  5. return struct_bmp;

Reply

Marsh Posté le 24-10-2007 à 22:23:36    

xilebo a écrit :

Erreur, il ne faut jamais retourner une variable locale à une fonction, elle n'existe que dans la fonction et la mémoire est libérée à la sortie de la fonction. Si tu arrives à lire en passant par l'adresse, c'est que cette mémoire n'a pas encore été écrasée au moment où tu la lis.
 
Fais plutot un truc du style :

Code :
  1. t_bmp *struct_bmp;
  2. struct_bmp = malloc(sizeof(struct_bmp));
  3. ...
  4. ...
  5. return struct_bmp;



En fait à quoi correspond la taille de struct_bmp puisqu'elle n'a pas de taille définie? Il y a un pointeur de pointeur (**data) à l'intérieur.

Reply

Marsh Posté le 25-10-2007 à 09:01:25    

sa taille est parfaitement définie :  
 
unsigned char header[10] fait 10 octets.
unsigned char info_header[40] fait 40 octets.
unsigned char **data est un pointeur , il fait donc la taille d'une adresse sur ta machine (généralement 4 octets).

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed