Пытаюсь написать программу для работы с .bmp файлами, структуру брал с сайта майкрософта, она точно правильная)
Считать и записать InfoHeader и FileHeader у меня получается - все 1 в 1, а вот дальше - проблема.
Нужно считать данные RGB в динамический массив, и видимо я что-то делаю не так... Т.е я пробовал кучей способов, но работают(более или менее) пока только 2 - построчный(он почему-то только с lena.bmp работает, нравится ему девушка наверное..) и побайтовый. Но в результате размер выходного файла получается больше чем входного(почти в 3 раза), да и цвета все "ломаются" + куча шума.
Т.е он почему-то пишет что-то лишнее, и в начале явно что-то не так...
Я знаю что я вообще не в том порядке считываю - надо в BGR, но я же не изменяю ничего, просто считываю а потом записываю.
Вот в общем код, помогите пожалуйста, по-любому какая-то очевидная ошибка..
#include <iostream>
#include <stdio.h>
using namespace std;
typedef long DWORD;//4 байта
typedef short WORD;//2 байта
typedef unsigned char byte;//1 байт
#pragma pack(push,1)
struct BITMAPFILEHEADER
{
WORD Type; // ‘BM’ 0x4D42
DWORD Size; // Размер файла в байтах, BitCount*Height*Width+ OffsetBits
WORD Reserved1; // Зарезервирован; должен быть нуль
WORD Reserved2; // Зарезервирован; должен быть нуль
DWORD OffsetBits; // Смещение данных от начала файла в байтах// = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)
};
#pragma pack(pop)
struct BITMAPINFOHEADER
{
DWORD Size; // Число байтов необходимое для структуры = 40
DWORD Width; // Ширина точечного рисунка в пикселях
DWORD Height; // Высота точечного рисунка в пикселях
WORD Planes; // Число плоскостей целевого устройства = 1
WORD BitCount; // Глубина цвета, число бит на точку = 0,1,4,8,16,24,32
DWORD Compression; // Тип сжатия = 0 для несжатого изображения
DWORD SizeImage; // Размер изображения в байтах BitCount*Height*Width
DWORD XPelsPerMeter; // Разрешающая способность по горизонтали
DWORD YPelsPerMeter; // Разрешающая способность по вертикали
DWORD ColorUsed; // Число индексов используемых цветов. Если все цвета = 0
DWORD ColorImportant; // Число необходимых цветов = 0
};
struct RGBTRIPLE
{
byte Blue;
byte Green;
byte Red;
};
struct RGBQUAD
{
byte Blue;
byte Green;
byte Red;
byte Reserved;
};
class Image {
BITMAPINFOHEADER BMInfoHeader;
BITMAPFILEHEADER BMFileHeader;
RGBTRIPLE **Rgbtriple;
// данные могут храниться и в одномерном массиве RGBTRIPLE *Rgbtriple, при этом изменяется способ обращения к пикселу Rgbtriple[i*Width+j] вместо Rgbtriple[i][j]
RGBQUAD **Rgbquad;
char fileName[100];
public:
Image (char *fileName); // Конструктор объекта изображения из файла
Image(); // Конструктор без параметров, создает пустой контейнер под изображение
~Image (); // Деструктор
int loadimage(char *fileName); // метод загрузки изображения
void writeimage(char *fileName); // метод записи изображения в файл
void imageinfo();
};
Image::Image()
{
Rgbtriple=NULL;
Rgbquad=NULL;
char tpm[] = "";
strcpy_s(fileName,tpm);
}
Image::~Image()
{
if(Rgbtriple) delete(Rgbtriple);
if(Rgbquad) delete(Rgbquad);
}
int Image::loadimage(char *filename)
{
FILE *f;
int imageIdx=0; //image index counter
fopen_s(&f,filename,"rb");//открываем файл
if (f == NULL) return 0;//если не смогли открыть - возвращаем код ошибки - 0
fread(&BMFileHeader, sizeof(BMFileHeader),1,f);//считали заголовок
if (BMFileHeader.Type !=0x4D42)//проверили - точно ли формат .bmp
{
fclose(f);
return 0;
}
fread(&BMInfoHeader, sizeof(BMInfoHeader),1,f); //считали информацию об изображении
this->imageinfo();//вывели информацию
fseek(f, BMFileHeader.OffsetBits, SEEK_SET); //переместили указатель в нужное место OffsetBits = 54
Rgbtriple=new RGBTRIPLE*[BMInfoHeader.Height];
for (int i=0;i<BMInfoHeader.Height;i++)
Rgbtriple[i]=new RGBTRIPLE[BMInfoHeader.Width];
///*
for (int i=0;i<BMInfoHeader.Height;i++)//побайтово
for (int j=0;j<BMInfoHeader.Width;j++)
{
fread(&(Rgbtriple[i][j].Red),1,1,f);
fread(&(Rgbtriple[i][j].Green),1,1,f);
fread(&(Rgbtriple[i][j].Blue),1,1,f);
}
//*/
/*
for (int i = 0; i < BMInfoHeader.Width; i++)//построчно
{
fread(Rgbtriple[i], sizeof(RGBTRIPLE), BMInfoHeader.Width, f);
}
*/
if(Rgbtriple) cout<<"Изображение успешно загружено!"<<endl;
else return 0;
fclose(f);
return 1;
}
void Image::imageinfo()
{
BITMAPINFOHEADER *bmp = &BMInfoHeader;
cout<<"Число байтов необходимое для структуры: "<<bmp->Size<<endl;
cout<<"Ширина: "<<bmp->Width<<endl;
cout<<"Высота: "<<bmp->Height<<endl;
cout<<"Число плоскостей целевого устройства: "<<bmp->Planes<<endl;
cout<<"Глубина цвета:"<<bmp->BitCount<<endl;
cout<<"Тип сжатия: "<<bmp->Compression<<endl;
cout<<"Размер изображения в байтах: "<<bmp->SizeImage<<endl;
cout<<"Разрешающая способность по горизонтали: "<<bmp->XPelsPerMeter<<endl;
cout<<"Разрешающая способность по вертикали: "<<bmp->YPelsPerMeter<<endl;
cout<<"Число индексов используемых цветов: "<<bmp->ColorUsed<<endl;
cout<<"Число необходимых цветов: "<<bmp->ColorImportant<<endl;
return;
}
void Image::writeimage(char *fileName)
{
FILE *f;
fopen_s(&f,fileName,"wb");
if (f==NULL)
{
cout<<"\n\nОшибочка!\n"<<endl;
return;
}
fwrite(&BMFileHeader, sizeof(BMFileHeader),1,f);//40
fwrite(&BMInfoHeader, sizeof(BMInfoHeader),1,f);//14
///*
for (int i=0;i<BMInfoHeader.Height;i++)//побайтово
for (int j=0;j<BMInfoHeader.Width;j++)
{
fwrite(&(Rgbtriple[i][j].Red),1,1,f);
fwrite(&(Rgbtriple[i][j].Green),1,1,f);
fwrite(&(Rgbtriple[i][j].Blue),1,1,f);
}
//*/
/*
for (int i = 0; i < BMInfoHeader.Width; i++)//построчно
{
fwrite(Rgbtriple[i], sizeof(RGBTRIPLE), BMInfoHeader.Width, f);
}
*/
fclose(f);
return;
}
int main ()
{
setlocale(LC_ALL,"RUS");
cout<<"Открыли исходное изображение: "<<endl;
Image img;
img.loadimage("sails.bmp");
img.writeimage("out.bmp");
system("PAUSE");
return 0;
}