2012-08-05 4 views
2

J'écris actuellement une fonction de capture d'écran BMP pour un framework OpenGL et je suis confronté à un problème étrange d'écriture des données. Les données importées de glReadPixels avec les en-têtes BMP sont correctes, mais il semble que l'opération ofstream.write insère des valeurs non valables au hasard.Création BMP - Corruption C++ ofstream en sortie

Des extraits d'une image BMP correcte de l'image (créée par Paint) et de celle de ma fonction sont affichés, mettant en évidence les octets incorrects. La ligne correcte sera toujours la première.


Row 0x08C

3B 0D 4A 3A 0A 48 38 08 45 36 
3B 0D 4A 3A 0D 0A 48 38 08 45 
      ^^ 

Row 0x0DC (déjà éteint par une, à ce stade)

3E 2F 07 3D 2E 0A 3F 31 0E 44 
07 3E 2F 07 3D 2E 0D 0A 3F 31 
        ^^ 

Row 0x0E68 (très rangée suivante, et en dehors par deux)

35 13 48 3A 10 44 36 0A 3F 31 
0E 44 35 13 48 3A 10 44 36 0D 
          ^^ 

Donc, il semble un modèle où la valeur non valide est toujours 0x0D et il est inséré devant un 0x0A. Je n'ai aucune idée pourquoi cela pourrait se produire, car j'ai confirmé que les en-têtes et les données de glReadPixels sont tous corrects. Le code de la méthode suit.

bool captureScreen(const char* name, unsigned originX, unsigned originY, unsigned width, unsigned height) 
{ 

    //... 

    GLubyte* imageData = new GLubyte[ width * height * 3 ]; 
    glReadPixels(originX, originY, width, height, GL_BGR, GL_UNSIGNED_BYTE, imageData); 

    //... 

    captureAsBMP(imageData, width, height, path.c_str()); 

    //... 
} 

bool captureAsBMP(GLubyte* data, GLuint width, GLuint height, const char* path) 
{ 
    std::ofstream stream(path, std::ios_base::out); 

    if(!stream.is_open()) 
     return false; 

    unsigned char BMPHeader[ 14 ] = { /* cut for brevity */ }; 
    unsigned char DIBHeader[ 40 ] = { /* cut for brevity */ }; 
    unsigned char padding[ 4 ] = { 0x00, 0x00, 0x00, 0x00 }; 

    unsigned int paddingLength = 4 - ((width * 3) % 4); 
    paddingLength = (paddingLength == 4 ? 0 : paddingLength); 

    long fileSize = (width * height * 3) + (paddingLength * height) + 54; 
    long dataSize = fileSize - 54; 

    memcpy(&BMPHeader[ 2 ], &fileSize, sizeof(long)); 
    memcpy(&DIBHeader[ 4 ], &width, sizeof(unsigned int)); 
    memcpy(&DIBHeader[ 8 ], &height, sizeof(unsigned int)); 
    memcpy(&DIBHeader[ 20 ], &dataSize, sizeof(long)); 

    stream.write(reinterpret_cast< char* >(BMPHeader), 14); 
    stream.write(reinterpret_cast< char* >(DIBHeader), 40); 

    unsigned pos = 0; 

    // Write out one row at a time 
    for(int i = 0; i < height; i++) 
    { 
     stream.write(reinterpret_cast< char* >(&data[ pos ]), (width * 3)); 

     // Is there padding that needs to be added? 
     if(paddingLength != 0) 
      stream.write(reinterpret_cast< char* >(padding), paddingLength); 

     // Update where we are in data 
     pos += width * 3; 
    } 

    stream.close(); 

    return true; 
} 

A noter également, l'image en question est un 800x600 et si cette erreur se produit lors de la première écriture de flux des lignes, avant de rembourrage et pos incrémenter.

Enfin, comment il devrait apparaître: http://imgur.com/oziid

et comment il le: http://imgur.com/SrXgA (re-enregistré dans la peinture comme Imgur plaignit corrompu bien sûr)

Répondre

6

Vous devez ouvrir vos fichiers en binaire en ajoutant le drapeau std::ios::binary pour éviter CRLF conversion. Sous Windows, les retours à la ligne sont représentés par les deux octets 0x0D 0x0A (retour chariot + saut de ligne, ou CR LF): les runtimes C et C++ traduisent automatiquement les retours à la ligne en entrée et traduisent automatiquement les retours à la ligne '\n' en paires CRLF en sortie , lorsque les fichiers sont ouverts en mode texte, qui est la valeur par défaut.

Pour supprimer ces conversions de nouvelle ligne, vous devez indiquer à l'exécution de ne pas traduire. Avec iostream s de C++, cela est fait avec le drapeau std::ios::binary; avec les flux FILE* de C, ceci est fait avec le drapeau de mode "b", par ex. "rb" pour la lecture ou "wb" pour l'écriture.

+0

C'est toujours quelque chose de simple, n'est-ce pas? Merci pour l'aide. Je suppose que j'avais juste besoin d'une nouvelle paire d'yeux. – ssell