if (headerChar != 'P' || (headerInt != '6' && headerInt != '3'))
{
cerr << "Error : bad file format, need 'P6' file" << endl;
exit (EXIT_FAILURE);
}
int width, height, maxIntensity;
input >> width >> height >> maxIntensity;
//input.getline(0x0, 10);
Image *image = new Image(width, height, maxIntensity);
// Pour lire le \n qui fait decaler les couleurs...
char toto;
input.read(&toto, 1);
// Case 'P6' image
if (headerInt == '6')
{
// Colors recording
for (int i = 0 ; i < height ; i++)
for (int j = 0 ; j < width ; j++)
{
unsigned char red, green, blue;
input.read(&red, 1);
input.read(&green, 1);
input.read(&blue, 1);
image->setColor(i, j,
(unsigned char) red,
(unsigned char) green,
(unsigned char) blue);
if (i == 0 && j == 0)
cout << (int) red << " " << (int) green << " " << (int) blue << endl;
}
input.close();
return image;</font></i></pre>
<pre><i><font color="#009900"></font></i></pre>
<pre><font color="#000000">Mais ce bout de code ne permet de lire que les images correspondant</font></pre>
<pre><font color="#000000">à la configuration :</font></pre>
<pre><font color="#000000">P6\n</font></pre>
<pre><font color="#000000">width\n</font></pre>
<pre><font color="#000000">height\n</font></pre>
<pre><font color="#000000">maxIntensity</font><font color="#FF0000">\n <- ce caractère devient <b>obligatoire</b> et <b>DOIT</b> etre le seul avant le flux binaire</font></pre>
<pre>flux binaire sans parasites (pas de \n ou \t ...)</pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre>Quelqu'un a-til une routine de lecture de fichier 'P6' en c++ ?</pre>
<pre>Sinon, comment lire mon fichier correctement a partir du code</pre>
Sinon, tu risques d'avoir des problèmes pour certaines valeurs binaires, dans certains contextes, selon la plateforme. (Sous Windows, par exemple, un 13 suivi d'un 10 sera supprimé. Sur un Mac, je crois qu'un 13 serait changé en 10. Et ainsi de suite -- chaque plateforme a ses propre règles.)
exit (EXIT_FAILURE); }
char headerChar; int headerInt;
input >> headerChar >> headerInt;
Je ne suis pas sûr ici. S'il s'agit réelement toujours d'exactement deux caractères, j'aurais plutôt une tendance à lire deux caractères, avec get(). Mais je ne connais pas le format réel ; c'est donc difficile à
- saute des blancs (espaces, tabs et fins de lignes), - lit le premier non blanc en headerChar, - saute de nouveau des blancs, et - lit un chiffre avec une signe optionnelle suivie d'un ou plus de chiffres dans headerInt.
Si le fichier commence par « P6 », pas de problème. Si le fichier commence par « P +006 » non plus. Si tu veux exactement « P6 », et rien d'autre, et les champs ci-dessus sont bien séparés par des fins de ligne, j'écrirais plutôt :
std::string header ; if ( ! std::getline( input, header ) || header != "P6" ) { // Erreur de formattage du fichier... }
Note en revanche que si tu ouvres le fichier en binaire, getline risque de ne pas marcher sur certains systèmes (p.e. Mac), et donner de mauvais résultat sur d'autres (Windows). Le mieux dans ce cas-ci, c'est probablement d'écrire ton propre getline(), qui reconnaît la façon qui sert à séparer les lignes dans ce type de fichier. Alternativement :
if ( input.get() != 'P' || input.get() != ´6' || ! skipNL( input ) ) { // Erreur de formattage du fichier... }
De toute façon, il faut que tu gères les fin de lignes exprès toi-même. (Et celui qui a mélangé du binaire et du texte orienté ligne dans le même fichier est un plutôt incompétent pour définir un format.) Ce que fait skipNL dépend du format, mais si les caractères en entrée correspond à une fin de ligne dans le format, il doit les extraire et revoyer true ; sinon, il renvoie false.
if (headerChar != 'P' || headerInt != 6) { cerr << "Error : bad file format, need 'P6' file" << endl; exit (EXIT_FAILURE); }
int width, height, maxIntensity;
input >> width >> height >> maxIntensity;
Ici aussi, c'est une simplification, qui pourrait cacher certaines erreurs de formattage. C'est peut-être acceptable, mais évidemment, il va accepter les trois nombres même s'ils sont sur la même ligne.
Note aussi qu'il a extrait les trois nombres, ainsi que des espaces blancs (y compris des fins de lignes) qui les précèdent chaque fois, mais que le ou les caractères de fin de lignes qui suivent le dernier nombre sont toujours là.
Image *image = new Image(width, height, maxIntensity);
// Colors recording for (int i = 0 ; i < height ; i++) for (int j = 0 ; j < width ; j++) { unsigned char red, green, blue; input >> red >> green >> blue;
Comme j'ai déjà dit, ça ne marche pas du tout pour des valeurs binaires. Tu peux l'oublier. L'opérateur >> interprète toujours un format texte : il commence par sauter des espaces blancs (c-à-d tout caractère pour lequel « isspace() » renvoie true dans le locale du fichier). Il saute donc la fin de ligne que tu n'as pas lu auparavent, mais il saute aussi toute octet qui a la valeur 9, 10, 11, 12, 13 ou 32 (en supposant locale "C" et un codage basé sur l'ASCII -- le locale "C" est le défaut, et tous les ordinateurs courant sauf les gros IBM utilise des codages basés sur ASCII).
Entre ça et l'absence de l'option binaire lors de l'ouverture, il n'y a aucune chance que ça marche. Ici, il faudrait encore quelque chose du genre :
if ( ! skipNL( input ) ) { // Erreur de formattage... } for ( int i = 0 ; i < height ; ++ i ) { for ( int j = 0 ; j < width ; ++ j ) { char red ; input.get( red ) ; char green ; input.get( green ) ; char blue ; input.get( blue ) ; if ( ! input ) { // Erreur de formattage... } image->setColor( i, j, red, green, blue ) ; } }
À vrai dire, vue qu'on peut estîmer que les erreurs de formattage sont assez exceptionnelles, je crois que j'écrirais une fonction :
unsigned char mustGet( std::istream& source ) { int result = source.get() ; if ( result == EOF ) { throw ErreurDeFormattage() ; } return result ; }
Le corps de la boucle deviendra alors :
unsigned char red = mustGet( input ) ; unsigned char green = mustGet( input ) ; unsigned char blue = mustGet( input ) ; image->setColor( i, j, red, green, blue ) ;
Si tu fais ça, il faudrait s'assurer que la reste du code réagit bien lors d'une exception. Par exemple, si tu as alloué l'image dyanmiquement (chose que je suppose), il faudrait plutôt utiliser std::auto_ptr pour le gérer.
Aussi, même avec cette solution, il faut absolument passer par des variables intermédiaires, et non écrire quelque chose comme :
Si l'interface est figée, et tu ne peux par renvoyer un auto_ptr, il faudrait faire :
return image.release() ;
ici.
}
En effet, sur la plupart des images, un décalage s'effectue dans la lecture des données : un saut d'une valeur decale les informations de couleurs car les valeurs de rouge passent au bleu, celle du vert passent au rouge et celle du bleu au vert... Un autre saut entraine d'autre decalages... C'est tres penible.
C'est normal. Tu as dit à la bibliothèque de faire un certain nombre de translations, et de sauter certains caractères. Il ne faut donc pas s'étonner à ce qu'elle le fasse.
Une alternative consiste a ecrire :
ifstream input (fileName.c_str (), ios::binary); if (!input) { cerr << "Error : bad file format" << endl; exit (EXIT_FAILURE); }
if (headerChar != 'P' || (headerInt != '6' && headerInt != '3')) { cerr << "Error : bad file format, need 'P6' file" << endl; exit (EXIT_FAILURE); }
int width, height, maxIntensity; input >> width >> height >> maxIntensity; //input.getline(0x0, 10); Image *image = new Image(width, height, maxIntensity);
// Pour lire le n qui fait decaler les couleurs... char toto; input.read(&toto, 1);
À ta place, je régarderais les variants de istream::get(). Dans tous les cas, il fait l'équivalent d'un read(..., 1), et il a souvent une interface plus commode en cas de la lecture d'un seul caractère.
// Case 'P6' image if (headerInt == '6') { // Colors recording for (int i = 0 ; i < height ; i++) for (int j = 0 ; j < width ; j++) { unsigned char red, green, blue; input.read(&red, 1); input.read(&green, 1); input.read(&blue, 1); image->setColor(i, j, (unsigned char) red, (unsigned char) green, (unsigned char) blue); if (i == 0 && j == 0) cout << (int) red << " " << (int) green << " " << (int) blue << endl;
}
input.close(); return image;
Mais ce bout de code ne permet de lire que les images correspondant
à la configuration :
P6n
widthn
heightn
maxIntensityn <- ce caractère devient obligatoire et DOIT etre le seul avant le flux binaire
flux binaire sans parasites (pas de n ou t ...)
Quelqu'un a-til une routine de lecture de fichier 'P6' en c++ ?
Sinon, comment lire mon fichier correctement a partir du code fournit?
Au fond, il faut savoir exactement ce qui est acceptable, et ce qui ne l'est pas. C'est toujours un problème en cas de melange de texte et de binaire. Quel est la convention qui sert pour séparer les lignes dans l'en-tête ? Si c'est la convention Windows (CRLF), il faut qu'il soit toujours la convention Windows, même sur une machine Unix, et vice versa. Si la fin de la ligne est suivie immédiatement du binaire, il ne peut pas être parfois CRLF, parfois simplement LF, et parfois simplement CR. (On pourrait dire que CRLF ou simplement LF soit acceptable.) Ensuite, il faut que tu écris toi-même du code pour la sauter ; si la convention accepte CRLF ou LF tout seul, on pourrait écrire quelque chose du genre :
Note, en revanche que tu ne peux pas faire qu'un CR tout seul soit accepté aussi ; si tu rencontre la séquence 13, 10, est-ce que c'est un CRLF, ou est-ce que c'est un CR tout seul, suivi d'un rouge dont la valeur est par hazard 10 ?
-- James Kanze GABI Software mailto: Conseils en informatique orientée objet/ http://www.gabi-soft.fr Beratung in objektorientierter Datenverarbeitung 11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
fanny Chevalier <chevalie@emi.u-bordeaux.fr> wrote in message
news:<40475437.5AB9AD46@emi.u-bordeaux.fr>...
Je croyais avoir resolu mon probleme quant a la lecture d'une image
ppm de type 'P6' dont la structure est
P6
12
12
255
//données en binaire
Mon problème est le suivant :
ce morceau de code est valable pour quelques images, mais pas toutes
ifstream input (fileName.c_str ());
if (!input)
{
cerr << "Error : bad file format" << endl;
Drôle de message d'erreur pour ce cas-ci. J'aurais imaginé quelque chose
plutôt du genre : « Cannot open file ».
Aussi, si le flux contient des données en binaire, il faut absolument
l'ouvrir en mode binaire. Donc :
Sinon, tu risques d'avoir des problèmes pour certaines valeurs binaires,
dans certains contextes, selon la plateforme. (Sous Windows, par
exemple, un 13 suivi d'un 10 sera supprimé. Sur un Mac, je crois qu'un
13 serait changé en 10. Et ainsi de suite -- chaque plateforme a ses
propre règles.)
exit (EXIT_FAILURE);
}
char headerChar;
int headerInt;
input >> headerChar >> headerInt;
Je ne suis pas sûr ici. S'il s'agit réelement toujours d'exactement deux
caractères, j'aurais plutôt une tendance à lire deux caractères, avec
get(). Mais je ne connais pas le format réel ; c'est donc difficile à
- saute des blancs (espaces, tabs et fins de lignes),
- lit le premier non blanc en headerChar,
- saute de nouveau des blancs, et
- lit un chiffre avec une signe optionnelle suivie d'un ou plus de
chiffres dans headerInt.
Si le fichier commence par « P6 », pas de problème. Si le fichier
commence par « P +006 » non plus. Si tu veux exactement « P6 », et
rien d'autre, et les champs ci-dessus sont bien séparés par des fins de
ligne, j'écrirais plutôt :
std::string header ;
if ( ! std::getline( input, header ) || header != "P6" ) {
// Erreur de formattage du fichier...
}
Note en revanche que si tu ouvres le fichier en binaire, getline risque
de ne pas marcher sur certains systèmes (p.e. Mac), et donner de mauvais
résultat sur d'autres (Windows). Le mieux dans ce cas-ci, c'est
probablement d'écrire ton propre getline(), qui reconnaît la façon qui
sert à séparer les lignes dans ce type de fichier. Alternativement :
if ( input.get() != 'P' || input.get() != ´6' || ! skipNL( input ) ) {
// Erreur de formattage du fichier...
}
De toute façon, il faut que tu gères les fin de lignes exprès toi-même.
(Et celui qui a mélangé du binaire et du texte orienté ligne dans le
même fichier est un plutôt incompétent pour définir un format.) Ce que
fait skipNL dépend du format, mais si les caractères en entrée
correspond à une fin de ligne dans le format, il doit les extraire et
revoyer true ; sinon, il renvoie false.
if (headerChar != 'P' || headerInt != 6)
{
cerr << "Error : bad file format, need 'P6' file" << endl;
exit (EXIT_FAILURE);
}
int width, height, maxIntensity;
input >> width >> height >> maxIntensity;
Ici aussi, c'est une simplification, qui pourrait cacher certaines
erreurs de formattage. C'est peut-être acceptable, mais évidemment, il
va accepter les trois nombres même s'ils sont sur la même ligne.
Note aussi qu'il a extrait les trois nombres, ainsi que des espaces
blancs (y compris des fins de lignes) qui les précèdent chaque fois,
mais que le ou les caractères de fin de lignes qui suivent le dernier
nombre sont toujours là.
Image *image = new Image(width, height, maxIntensity);
// Colors recording
for (int i = 0 ; i < height ; i++)
for (int j = 0 ; j < width ; j++)
{
unsigned char red, green, blue;
input >> red >> green >> blue;
Comme j'ai déjà dit, ça ne marche pas du tout pour des valeurs binaires.
Tu peux l'oublier. L'opérateur >> interprète toujours un format texte :
il commence par sauter des espaces blancs (c-à-d tout caractère pour
lequel « isspace() » renvoie true dans le locale du fichier). Il saute
donc la fin de ligne que tu n'as pas lu auparavent, mais il saute aussi
toute octet qui a la valeur 9, 10, 11, 12, 13 ou 32 (en supposant locale
"C" et un codage basé sur l'ASCII -- le locale "C" est le défaut, et
tous les ordinateurs courant sauf les gros IBM utilise des codages basés
sur ASCII).
Entre ça et l'absence de l'option binaire lors de l'ouverture, il n'y a
aucune chance que ça marche. Ici, il faudrait encore quelque chose du
genre :
if ( ! skipNL( input ) ) {
// Erreur de formattage...
}
for ( int i = 0 ; i < height ; ++ i ) {
for ( int j = 0 ; j < width ; ++ j ) {
char red ;
input.get( red ) ;
char green ;
input.get( green ) ;
char blue ;
input.get( blue ) ;
if ( ! input ) {
// Erreur de formattage...
}
image->setColor( i, j, red, green, blue ) ;
}
}
À vrai dire, vue qu'on peut estîmer que les erreurs de formattage sont
assez exceptionnelles, je crois que j'écrirais une fonction :
unsigned char
mustGet( std::istream& source )
{
int result = source.get() ;
if ( result == EOF ) {
throw ErreurDeFormattage() ;
}
return result ;
}
Le corps de la boucle deviendra alors :
unsigned char red = mustGet( input ) ;
unsigned char green = mustGet( input ) ;
unsigned char blue = mustGet( input ) ;
image->setColor( i, j, red, green, blue ) ;
Si tu fais ça, il faudrait s'assurer que la reste du code réagit bien
lors d'une exception. Par exemple, si tu as alloué l'image dyanmiquement
(chose que je suppose), il faudrait plutôt utiliser std::auto_ptr pour
le gérer.
Aussi, même avec cette solution, il faut absolument passer par des
variables intermédiaires, et non écrire quelque chose comme :
Si l'interface est figée, et tu ne peux par renvoyer un auto_ptr, il
faudrait faire :
return image.release() ;
ici.
}
En effet, sur la plupart des images, un décalage s'effectue dans la
lecture des données : un saut d'une valeur decale les informations de
couleurs car les valeurs de rouge passent au bleu, celle du vert
passent au rouge et celle du bleu au vert... Un autre saut entraine
d'autre decalages... C'est tres penible.
C'est normal. Tu as dit à la bibliothèque de faire un certain nombre de
translations, et de sauter certains caractères. Il ne faut donc pas
s'étonner à ce qu'elle le fasse.
Une alternative consiste a ecrire :
ifstream input (fileName.c_str (), ios::binary);
if (!input)
{
cerr << "Error : bad file format" << endl;
exit (EXIT_FAILURE);
}
if (headerChar != 'P' || (headerInt != '6' && headerInt != '3'))
{
cerr << "Error : bad file format, need 'P6' file" << endl;
exit (EXIT_FAILURE);
}
int width, height, maxIntensity;
input >> width >> height >> maxIntensity;
//input.getline(0x0, 10);
Image *image = new Image(width, height, maxIntensity);
// Pour lire le n qui fait decaler les couleurs...
char toto;
input.read(&toto, 1);
À ta place, je régarderais les variants de istream::get(). Dans tous les
cas, il fait l'équivalent d'un read(..., 1), et il a souvent une
interface plus commode en cas de la lecture d'un seul caractère.
// Case 'P6' image
if (headerInt == '6')
{
// Colors recording
for (int i = 0 ; i < height ; i++)
for (int j = 0 ; j < width ; j++)
{
unsigned char red, green, blue;
input.read(&red, 1);
input.read(&green, 1);
input.read(&blue, 1);
image->setColor(i, j,
(unsigned char) red,
(unsigned char) green,
(unsigned char) blue);
if (i == 0 && j == 0)
cout << (int) red << " " << (int) green << " " << (int) blue << endl;
}
input.close();
return image;
Mais ce bout de code ne permet de lire que les images correspondant
à la configuration :
P6n
widthn
heightn
maxIntensityn <- ce caractère devient obligatoire et DOIT etre le seul avant le flux binaire
flux binaire sans parasites (pas de n ou t ...)
Quelqu'un a-til une routine de lecture de fichier 'P6' en c++ ?
Sinon, comment lire mon fichier correctement a partir du code fournit?
Au fond, il faut savoir exactement ce qui est acceptable, et ce qui ne
l'est pas. C'est toujours un problème en cas de melange de texte et de
binaire. Quel est la convention qui sert pour séparer les lignes dans
l'en-tête ? Si c'est la convention Windows (CRLF), il faut qu'il soit
toujours la convention Windows, même sur une machine Unix, et vice
versa. Si la fin de la ligne est suivie immédiatement du binaire, il ne
peut pas être parfois CRLF, parfois simplement LF, et parfois simplement
CR. (On pourrait dire que CRLF ou simplement LF soit acceptable.)
Ensuite, il faut que tu écris toi-même du code pour la sauter ; si la
convention accepte CRLF ou LF tout seul, on pourrait écrire quelque
chose du genre :
Note, en revanche que tu ne peux pas faire qu'un CR tout seul soit
accepté aussi ; si tu rencontre la séquence 13, 10, est-ce que c'est un
CRLF, ou est-ce que c'est un CR tout seul, suivi d'un rouge dont la
valeur est par hazard 10 ?
--
James Kanze GABI Software mailto:kanze@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
Sinon, tu risques d'avoir des problèmes pour certaines valeurs binaires, dans certains contextes, selon la plateforme. (Sous Windows, par exemple, un 13 suivi d'un 10 sera supprimé. Sur un Mac, je crois qu'un 13 serait changé en 10. Et ainsi de suite -- chaque plateforme a ses propre règles.)
exit (EXIT_FAILURE); }
char headerChar; int headerInt;
input >> headerChar >> headerInt;
Je ne suis pas sûr ici. S'il s'agit réelement toujours d'exactement deux caractères, j'aurais plutôt une tendance à lire deux caractères, avec get(). Mais je ne connais pas le format réel ; c'est donc difficile à
- saute des blancs (espaces, tabs et fins de lignes), - lit le premier non blanc en headerChar, - saute de nouveau des blancs, et - lit un chiffre avec une signe optionnelle suivie d'un ou plus de chiffres dans headerInt.
Si le fichier commence par « P6 », pas de problème. Si le fichier commence par « P +006 » non plus. Si tu veux exactement « P6 », et rien d'autre, et les champs ci-dessus sont bien séparés par des fins de ligne, j'écrirais plutôt :
std::string header ; if ( ! std::getline( input, header ) || header != "P6" ) { // Erreur de formattage du fichier... }
Note en revanche que si tu ouvres le fichier en binaire, getline risque de ne pas marcher sur certains systèmes (p.e. Mac), et donner de mauvais résultat sur d'autres (Windows). Le mieux dans ce cas-ci, c'est probablement d'écrire ton propre getline(), qui reconnaît la façon qui sert à séparer les lignes dans ce type de fichier. Alternativement :
if ( input.get() != 'P' || input.get() != ´6' || ! skipNL( input ) ) { // Erreur de formattage du fichier... }
De toute façon, il faut que tu gères les fin de lignes exprès toi-même. (Et celui qui a mélangé du binaire et du texte orienté ligne dans le même fichier est un plutôt incompétent pour définir un format.) Ce que fait skipNL dépend du format, mais si les caractères en entrée correspond à une fin de ligne dans le format, il doit les extraire et revoyer true ; sinon, il renvoie false.
if (headerChar != 'P' || headerInt != 6) { cerr << "Error : bad file format, need 'P6' file" << endl; exit (EXIT_FAILURE); }
int width, height, maxIntensity;
input >> width >> height >> maxIntensity;
Ici aussi, c'est une simplification, qui pourrait cacher certaines erreurs de formattage. C'est peut-être acceptable, mais évidemment, il va accepter les trois nombres même s'ils sont sur la même ligne.
Note aussi qu'il a extrait les trois nombres, ainsi que des espaces blancs (y compris des fins de lignes) qui les précèdent chaque fois, mais que le ou les caractères de fin de lignes qui suivent le dernier nombre sont toujours là.
Image *image = new Image(width, height, maxIntensity);
// Colors recording for (int i = 0 ; i < height ; i++) for (int j = 0 ; j < width ; j++) { unsigned char red, green, blue; input >> red >> green >> blue;
Comme j'ai déjà dit, ça ne marche pas du tout pour des valeurs binaires. Tu peux l'oublier. L'opérateur >> interprète toujours un format texte : il commence par sauter des espaces blancs (c-à-d tout caractère pour lequel « isspace() » renvoie true dans le locale du fichier). Il saute donc la fin de ligne que tu n'as pas lu auparavent, mais il saute aussi toute octet qui a la valeur 9, 10, 11, 12, 13 ou 32 (en supposant locale "C" et un codage basé sur l'ASCII -- le locale "C" est le défaut, et tous les ordinateurs courant sauf les gros IBM utilise des codages basés sur ASCII).
Entre ça et l'absence de l'option binaire lors de l'ouverture, il n'y a aucune chance que ça marche. Ici, il faudrait encore quelque chose du genre :
if ( ! skipNL( input ) ) { // Erreur de formattage... } for ( int i = 0 ; i < height ; ++ i ) { for ( int j = 0 ; j < width ; ++ j ) { char red ; input.get( red ) ; char green ; input.get( green ) ; char blue ; input.get( blue ) ; if ( ! input ) { // Erreur de formattage... } image->setColor( i, j, red, green, blue ) ; } }
À vrai dire, vue qu'on peut estîmer que les erreurs de formattage sont assez exceptionnelles, je crois que j'écrirais une fonction :
unsigned char mustGet( std::istream& source ) { int result = source.get() ; if ( result == EOF ) { throw ErreurDeFormattage() ; } return result ; }
Le corps de la boucle deviendra alors :
unsigned char red = mustGet( input ) ; unsigned char green = mustGet( input ) ; unsigned char blue = mustGet( input ) ; image->setColor( i, j, red, green, blue ) ;
Si tu fais ça, il faudrait s'assurer que la reste du code réagit bien lors d'une exception. Par exemple, si tu as alloué l'image dyanmiquement (chose que je suppose), il faudrait plutôt utiliser std::auto_ptr pour le gérer.
Aussi, même avec cette solution, il faut absolument passer par des variables intermédiaires, et non écrire quelque chose comme :
Si l'interface est figée, et tu ne peux par renvoyer un auto_ptr, il faudrait faire :
return image.release() ;
ici.
}
En effet, sur la plupart des images, un décalage s'effectue dans la lecture des données : un saut d'une valeur decale les informations de couleurs car les valeurs de rouge passent au bleu, celle du vert passent au rouge et celle du bleu au vert... Un autre saut entraine d'autre decalages... C'est tres penible.
C'est normal. Tu as dit à la bibliothèque de faire un certain nombre de translations, et de sauter certains caractères. Il ne faut donc pas s'étonner à ce qu'elle le fasse.
Une alternative consiste a ecrire :
ifstream input (fileName.c_str (), ios::binary); if (!input) { cerr << "Error : bad file format" << endl; exit (EXIT_FAILURE); }
if (headerChar != 'P' || (headerInt != '6' && headerInt != '3')) { cerr << "Error : bad file format, need 'P6' file" << endl; exit (EXIT_FAILURE); }
int width, height, maxIntensity; input >> width >> height >> maxIntensity; //input.getline(0x0, 10); Image *image = new Image(width, height, maxIntensity);
// Pour lire le n qui fait decaler les couleurs... char toto; input.read(&toto, 1);
À ta place, je régarderais les variants de istream::get(). Dans tous les cas, il fait l'équivalent d'un read(..., 1), et il a souvent une interface plus commode en cas de la lecture d'un seul caractère.
// Case 'P6' image if (headerInt == '6') { // Colors recording for (int i = 0 ; i < height ; i++) for (int j = 0 ; j < width ; j++) { unsigned char red, green, blue; input.read(&red, 1); input.read(&green, 1); input.read(&blue, 1); image->setColor(i, j, (unsigned char) red, (unsigned char) green, (unsigned char) blue); if (i == 0 && j == 0) cout << (int) red << " " << (int) green << " " << (int) blue << endl;
}
input.close(); return image;
Mais ce bout de code ne permet de lire que les images correspondant
à la configuration :
P6n
widthn
heightn
maxIntensityn <- ce caractère devient obligatoire et DOIT etre le seul avant le flux binaire
flux binaire sans parasites (pas de n ou t ...)
Quelqu'un a-til une routine de lecture de fichier 'P6' en c++ ?
Sinon, comment lire mon fichier correctement a partir du code fournit?
Au fond, il faut savoir exactement ce qui est acceptable, et ce qui ne l'est pas. C'est toujours un problème en cas de melange de texte et de binaire. Quel est la convention qui sert pour séparer les lignes dans l'en-tête ? Si c'est la convention Windows (CRLF), il faut qu'il soit toujours la convention Windows, même sur une machine Unix, et vice versa. Si la fin de la ligne est suivie immédiatement du binaire, il ne peut pas être parfois CRLF, parfois simplement LF, et parfois simplement CR. (On pourrait dire que CRLF ou simplement LF soit acceptable.) Ensuite, il faut que tu écris toi-même du code pour la sauter ; si la convention accepte CRLF ou LF tout seul, on pourrait écrire quelque chose du genre :
Note, en revanche que tu ne peux pas faire qu'un CR tout seul soit accepté aussi ; si tu rencontre la séquence 13, 10, est-ce que c'est un CRLF, ou est-ce que c'est un CR tout seul, suivi d'un rouge dont la valeur est par hazard 10 ?
-- James Kanze GABI Software mailto: Conseils en informatique orientée objet/ http://www.gabi-soft.fr Beratung in objektorientierter Datenverarbeitung 11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16