Zapis BMP

0

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

0
  while(size_file%4!=0)//powiększamy linijkę do podzielności przez 4
  {
    size_file++;
    zero_line++;
  }

A nie prościej tak?

size_file+= (size_file&3) ? 4-(size_file&3) : 0;

:>

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;

Użyj strumieni bo to to jakiś żart... chyba...

LONG long_line=size_24bit/bmp.bmHeight;//długość pojedynczej linii
UINT count_lines=size_24bit/long_line;//ilość linii w obrazie

Nie wiem po co liczysz count_lines jeżeli jest (zawsze) równy bmp.bmHeight?

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

A próbowałeś użyć GetDIBits???

Na razie tyle...

1 użytkowników online, w tym zalogowanych: 0, gości: 1