2013-04-07 1 views
0

У меня есть проблема с чтением растровых файлов на C++. Мой код работает только тогда, когда заполнение строки равно 3 байтам. Любое другое дополнение делает странные вещи - иногда я не могу читать выходной файл, и иногда я могу его открыть, но он выглядит как мусор и имеет разную ширину и высоту.C++ чтение BMP-файл работает только тогда, когда заполнение строки равно 3 байтам

Вот моя функция считывания данных из растрового файла:

void read_bmp(ImageFile* Image, const char* filename){ 
FILE* pFile; 
unsigned char* buffer; 
unsigned int bufferSize, offset_bitmapData, counter_PixelCounter=0, offset_paddingSum=0; 

pFile = fopen(filename, "rb"); 
if(pFile==NULL) throw ERR_FILE_DOES_NOT_EXIST; 

fseek(pFile, 0, SEEK_SET); 
bufferSize = 54; 
buffer = new unsigned char[bufferSize]; 
if(fread(buffer, sizeof(char), bufferSize, pFile)!=bufferSize) throw ERR_FILE_READING_ERROR; 
if(readBytes_int(0, 2, buffer)!=0x4D42) throw ERR_NO_BMP_HEADER; 

offset_bitmapData = readBytes_int(0x0A, 4, buffer); 
Image->ImageWidth = readBytes_int(0x12, 4, buffer); 
Image->ImageHeight = readBytes_int(0x16, 4, buffer); 
Image->FileSize = readBytes_int(0x02, 4, buffer); 
Image->bbpInfo = readBytes_int(0x1C, 2,buffer); 
Image->Padding = (4 - (Image->ImageWidth*3)%4)%4; 
cout<<"width "<<Image->ImageWidth<<endl; 
cout<<"padding "<<(int)Image->Padding<<endl; 

if(readBytes_int(0x0E, 4, buffer)!=40) throw ERR_NO_BITMAPINFOHEADER; 

delete[] buffer; 
bufferSize = Image->ImageWidth * Image->ImageHeight * 3 + Image->ImageHeight * Image->Padding; 
buffer = new unsigned char[bufferSize]; 
if(buffer==NULL) throw ERR_BAD_ALLOC; 
fseek(pFile, offset_bitmapData, SEEK_SET); 

if(fread(buffer, sizeof(char), bufferSize, pFile)!=bufferSize) throw ERR_FILE_READING_ERROR; 
fclose(pFile); 

Image->PixelArray = new unsigned char**[Image->ImageHeight]; 
counter_PixelCounter = 0; 

for(int height = Image->ImageHeight-1; height >= 0; height--) 
{ 
    Image->PixelArray[height] = new unsigned char*[Image->ImageWidth]; 

    for(int width = 0; width < Image->ImageWidth; width++) 
    { 
     Image->PixelArray[height][width] = new unsigned char[3]; 

     Image->PixelArray[height][width][0] = (unsigned char)readBytes_int((counter_PixelCounter) * 3 + offset_paddingSum + 2, 1, buffer); 
     Image->PixelArray[height][width][1] = (unsigned char)readBytes_int((counter_PixelCounter) * 3 + offset_paddingSum + 1, 1, buffer); 
     Image->PixelArray[height][width][2] = (unsigned char)readBytes_int((counter_PixelCounter) * 3 + offset_paddingSum, 1, buffer); 

     counter_PixelCounter++; 

    } 
    offset_paddingSum += Image->Padding; 
} 
cout<<counter_PixelCounter<<endl; 
cout<<"File loaded successfully\n"; 
} 
+0

Казалось, работа для меня в файле с нулевым заполнением. Никаких очевидных ошибок при чтении кода тоже нет. Конечно, уродливый. – john

+0

Все эти магические числа делают код почти нечитаемым, может быть, вы перепутали его? Во всяком случае, есть также сжатое растровое изображение, которое вы не проверяете и не обрабатываете. Я не уверен, но, похоже, я помню, что BMP имеют отдельную ширину (пиксели) и шаг (байты на строку), которые вам тоже нужно учитывать. BTW, новый [] будет бросать неудачу, не нужно проверять и бросать макросы самостоятельно. –

ответ

4

The documentation says

DIB состоит из двух отдельных частей: структуры BITMAPINFO , описывающий размеры и цвета точечного рисунка, и массив из байтов, определяющий пиксели растрового изображения. Биты в массиве: , упакованные вместе, но каждая строка сканирования должна быть заполнена нулями до конца на границе LONG-типа данных.

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

+0

yea ... но каждый пиксель имеет 3 байта, поэтому я умножаю счетчик пикселей на 3, и это число моих байтов ... – VIPPER

0

В файле .BMP имеется четыре байта для описания размера заполнения в адресе 0x22 файла.

Вы можете прочитать и пропустить прокладку. См. Также этот вопрос и ответы: C++: .bmp to byte array in a file