2016-11-17 1 views
0

У меня самая странная проблема здесь ... Я использую тот же код (копипаст) из Linux в Windows, чтобы ЧИТАТЬ и WRITE и BMP образ. И по какой-то причине в Linux все работает отлично отлично, но когда я прихожу к Windows 10 от некоторых я не могу открыть эти изображения, и у меня появляется сообщение об ошибке, как говорится примерно так:C++: Написать BMP ошибка формата изображения на WINDOWS

«Похоже, мы не поддерживаем этот формат файла».

Вы знаете, что мне делать? Я поставлю код ниже.

EDIT:

Я решил проблему отступы и теперь это записать образы, но они полностью белый, любая идея, почему? Я также обновляю код.

struct BMP { 
    int width; 
    int height; 
    unsigned char header[54]; 
    unsigned char *pixels; 
    int size; 
    int row_padded; 
}; 

void writeBMP(string filename, BMP image) { 
    string fileName = "Output Files\\" + filename; 
    FILE *out = fopen(fileName.c_str(), "wb"); 
    fwrite(image.header, sizeof(unsigned char), 54, out); 

    unsigned char tmp; 
    for (int i = 0; i < image.height; i++) { 
     for (int j = 0; j < image.width * 3; j += 3) { 
      // Convert (B, G, R) to (R, G, B) 
      tmp = image.pixels[j]; 
      image.pixels[j] = image.pixels[j + 2]; 
      image.pixels[j + 2] = tmp; 
     } 
     fwrite(image.pixels, sizeof(unsigned char), image.row_padded, out); 
    } 
    fclose(out); 
} 

BMP readBMP(string filename) { 
    BMP image; 
    string fileName = "Input Files\\" + filename; 
    FILE *f = fopen(fileName.c_str(), "rb"); 

    if (f == NULL) 
     throw "Argument Exception"; 

    fread(image.header, sizeof(unsigned char), 54, f); // read the 54-byte header 

    // extract image height and width from header 
    image.width = *(int *) &image.header[18]; 
    image.height = *(int *) &image.header[22]; 

    image.row_padded = (image.width * 3 + 3) & (~3); 
    image.pixels = new unsigned char[image.row_padded]; 
    unsigned char tmp; 

    for (int i = 0; i < image.height; i++) { 
     fread(image.pixels, sizeof(unsigned char), image.row_padded, f); 
     for (int j = 0; j < image.width * 3; j += 3) { 
      // Convert (B, G, R) to (R, G, B) 
      tmp = image.pixels[j]; 
      image.pixels[j] = image.pixels[j + 2]; 
      image.pixels[j + 2] = tmp; 
     } 
    } 
    fclose(f); 
    return image; 

} 

С моей точки зрения, этот код должен быть кросс-платформенным ... Но это не ... почему?

Спасибо за помощь

+0

Вы можете использовать инструмент сравнения в таких окнах, как windiff, который поставляется вместе с Visual Studio для сравнения двух файлов. Или используйте отладчик, чтобы убедиться, что эти же данные заголовка изображения записаны. –

+0

Что сравнивать? Это точно такой же код ... – Mircea

+0

Я проверил этот код несколько раз, и он точно такой же ... – Mircea

ответ

1

Проверьте заголовок

header должен исходить из следующих двух signature байт: 0x42 0x4D. Если это что-то другое, стороннее приложение будет думать, что этот файл не содержит изображения bmp, несмотря на расширение файла .bmp.

Размер и способ сохранения пикселей также немного: more complex than what you expect: вы считаете, что количество бит на пиксели равно 24, и никакое сжатие не используется. Это не гарантируется. Если это не так, вы можете прочитать больше данных, чем доступно, и повредить файл при его записи.

Кроме того, размер заголовка зависит также от BMP version вы используете, которые you can detect using на 4 байтовое целое со смещением 14.

Улучшить код

При загрузке файла, проверка подпись, версия bmp, количество бит на пиксель и сжатие. Для отладки цели, рассмотреть демпинг заголовок, чтобы проверить его вручную:

for (int i=0; i<54; i++) 
    cout << hex << image.header[i] << " ";` 
cout <<endl; 

Кроме того, когда вы fread() проверить, что количество прочитанных байт соответствует размеру вы хотели прочитать, так, чтобы быть уверенным, что вы не работа с неинициализированными данными буфера.

Edit:

Проверив дамп, представляется, что этот формат, как и ожидалось.Но проверки проложенного размера в заголовке с подкладкой размером, что вы рассчитали кажется, что ошибка здесь:

image.row_padded = (image.width * 3 + 3) & (~3);  // ok size of a single row rounded up to multiple of 4 
image.pixels = new unsigned char[image.row_padded]; // oops ! A little short ? 

На самом деле вы читаете по строкам, но вы только сохранить последнюю в памяти! Это отличается от вашей первой версии, где вы читали полные пиксели изображения.

Аналогичным образом, вы пишете повторную высоту времени последней строки.

Пересмотрите свои прокладки, работая с общим мягким размером.

image.row_padded = (image.width * 3 + 3) & (~3);  // ok size of a single row rounded up to multiple of 4 
image.size_padded = image.row_padded * image.height; // padded full size 
image.pixels = new unsigned char[image.size_padded]; // yeah ! 
if (fread(image.pixels, sizeof(unsigned char), image.size_padded, f) != image.size_padded) { 
    cout << "Error: all bytes couldn't be read"<<endl; 
} 
else { 
    ... // process the pixels as expected 
} 
... 
+0

Я решаю часть своей проблемы, я редактирую свой вопрос, вы можете проверить его снова, пожалуйста? – Mircea

+0

@Mircea Я отредактировал свой ответ – Christophe

+0

ну ... входное изображение в порядке, я могу открыть его и посмотреть на него. Моя проблема - только выходное изображение. Я уже проверял кратность заголовка, и это идеально, или я не видел разницы. Я проверил даже с 'for (int i = 0; i <54; i ++) cout << hex << image.header [i] <<" ";' и это то же самое ... Теперь, если у меня есть право , в этот момент моя проблема не в заголовке, а в массиве пикселей. По какой-то причине я потерял все пиксели, которые я думаю каким-то образом ... Или я не пишу это правильно. Я думаю, что это моя проблема в этот момент. – Mircea

Смежные вопросы