Próbuję zapisać BMP, ale jakoś mi nie wychodzi, nie ma ktoś gdzieś pod ręką kodu zapisującego BMP z 32 bitów do 24 bitowego pliku, był bym wdzięczny [browar]
Na necie znalazłem dwie funkcje, ale jakoś działają jeszcze gorzej niż moja, źle zapisują już sam nagłówek...
Oto moje wypociny:
bool SaveBitmapForm32To24(HBITMAP hBmp,LPCSTR path)
{
//nagłówek
BYTE header[54];
header[0]=0x42;
header[1]=0x4D;
//ustalenie długości pliku
BITMAP bmp;
GetObject(hBmp,sizeof(BITMAP),&bmp);
UINT size_file=bmp.bmWidth*3;//ilość bajtów w linijce
UINT zero_line=0;
while(size_file%4!=0)//powiększamy linijkę do podzielności przez 4
{
size_file++;
zero_line++;
}
size_file*=bmp.bmHeight;//powiększamy o ilość linijek
size_file+=54;//powiększamy o nagłówek
header[2]=LOBYTE(LOWORD(size_file));
header[3]=HIBYTE(LOWORD(size_file));
header[4]=LOBYTE(HIWORD(size_file));
header[5]=HIBYTE(HIWORD(size_file));
for(int i=6;i<10;i++) header[i]=0;
header[10]=0x36;//offset początku obrazu
for(int i=11;i<14;i++) header[i]=0;
header[14]=0x28;//długość do końca nagłówka
for(int i=15;i<18;i++) header[i]=0;
header[18]=LOBYTE(LOWORD(bmp.bmWidth));
header[19]=HIBYTE(LOWORD(bmp.bmWidth));
header[20]=LOBYTE(HIWORD(bmp.bmWidth));
header[21]=HIBYTE(HIWORD(bmp.bmWidth));
header[22]=LOBYTE(LOWORD(bmp.bmHeight));
header[23]=HIBYTE(LOWORD(bmp.bmHeight));
header[24]=LOBYTE(HIWORD(bmp.bmHeight));
header[25]=HIBYTE(HIWORD(bmp.bmHeight));
header[26]=0x1;//ilość płatów
header[27]=0;
header[28]=0x18;//liczba bitów na piksel(24)
header[29]=0;
for(int i=30;i<54;i++) header[i]=0;
//obraz w pliku od 54 bajtu
LONG size_32bit=bmp.bmWidth*bmp.bmHeight*4;//wielkość pobranej 32 bitowej bitmapy w bajtach
LPBYTE bitmap32=new BYTE[size_32bit];//bitmapa 32 bitowa
LONG copied=GetBitmapBits(hBmp,size_32bit,bitmap32);
if(copied!=size_32bit)
{
MessageBox(0,0,0,0);//<======================================================================
delete[] bitmap32;
return 0;
}
LONG size_24bit=size_file-54;//wielkość bitmapy 24 bitowej w bajtach(bez nagłówka)
LPBYTE bitmap24=new BYTE[size_24bit];//bitmapa 24 bitowa
LONG long_line=size_24bit/bmp.bmHeight;//długość pojedynczej linii
UINT count_lines=size_24bit/long_line;//ilość linii w obrazie
LONG i_line,end_line,i32=0;
for(LONG i24=(count_lines-1)*long_line;i24>=0;i24-=long_line)//czytamy od końca linijki - c to numer pierwszego bajtu w każdej linijce
{
i_line=i24;
end_line=bmp.bmWidth*3+i24;
while(i_line<end_line)//jedziemy po koleji z bajtami w linijce
{
//zapis piksela w BGR z RGB
bitmap24[i_line]=bitmap32[i32+3];//zapis kanału B
bitmap24[i_line+1]=bitmap32[i32+2];//zapis kanału G
bitmap24[i_line+2]=bitmap32[i32+1];//zapis kanału R
//-------------
i32+=4;//przeskakujemy na kolejny piksel w bitmap32
i_line+=3;//przeskakujemy na kolejny piksel w bitmap24
}
for(UINT i=0;i<zero_line;i++)//dopisujemy zera na koniec linijki, aby dopełnić podzielności przez 4
{
bitmap24[i_line]=0;
i_line++;
}
}
delete[] bitmap32;
LPBYTE result_bitmap=new BYTE[size_24bit+54];
for(LONG i=0;i<54;i++) result_bitmap[i]=header[i];
LONG p=0;
for(LONG i=54;i<size_24bit+54;i++)
{
result_bitmap[i]=bitmap24[p];
p++;
}
delete[] bitmap24;
SECURITY_ATTRIBUTES sa;
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor=0;
sa.bInheritHandle=1;
HANDLE bfile=(HANDLE)CreateFile(path,FILE_ADD_FILE|FILE_WRITE_DATA,0,&sa,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
DWORD written;
WriteFile(bfile,result_bitmap,size_24bit+54,&written,0);
CloseHandle(bfile);
delete[] result_bitmap;
return 1;
}
Dodam, że przy większych bitmapach, takich już 50x50 sama funkcja GetBitmapBits zapisuje złą ilość bitów, tzn. to co zwraca !=wysokośćszerokość4, przy bmp 32 bitowej