ПрограммированиеФорум2D графика и изометрия

WinApi из BMP в массив (С++) VS2008

#0
20:13, 7 авг 2011

Здравствуйте всем!

Необходимо из bmp извлечь пиксели (RGB) в массив (С++).

Уже весь день лазил по форумам, вот что получилось:  (чтобы упростить себе задачу решил считать хотябы первую линию bmp (1024 пикселя в картинке 1024х768))

void LoadBmpInMemory(LPCWSTR szFileName)  //name пока что не использую
{
  static HBITMAP hbitmap;
  BITMAP  BitMap;
  HANDLE hObj = LoadImage(NULL,L"Desert.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
  if ((HBITMAP)hObj == NULL) {
    ::MessageBox(NULL, __T("LoadImage Failed"), __T("Error"), MB_OK); //это сообщение не выбивается
    
  }
  HDC hdc = CreateCompatibleDC(NULL);
  SelectObject(hdc, (HBITMAP)hObj);
  GetObject((HBITMAP)hObj, sizeof(BITMAP), &BitMap);
  
  BITMAPINFO bInfo;
  WIDTH=BitMap.bmWidth;
  HEIGHT=BitMap.bmHeight;

    bInfo.bmiHeader.biSize =sizeof(bInfo.bmiHeader); //эта штука 40 байт
     bInfo.bmiHeader.biWidth = BitMap.bmWidth*4;  //это ширина в байтах изображения
     bInfo.bmiHeader.biHeight = BitMap.bmHeight*4;  //это высота в байтах
     bInfo.bmiHeader.biBitCount = 32;  //это количество бит на пиксель
     bInfo.bmiHeader.biPlanes = 1;
     bInfo.bmiHeader.biCompression = BI_RGB;
     bInfo.bmiHeader.biSizeImage = BitMap.bmHeight * BitMap.bmWidth * 4;  //это общий размер растра
 
   BYTE tempScanLine[1024*4]; //тут уже менял 3 на 4 тоже эффекта нету
   int LineCopy = GetDIBits(hdc, (HBITMAP)hObj, 0, 1, tempScanLine, &bInfo, DIB_RGB_COLORS);
  // delete [] tempScanLine;  //тут кстати крешится 
}

В итоге в tempScanLine одинаковые значения - видимо ничего и не присваивалось.

А GetDIBits возвратила 0 - то есть ошибка. =(

Кто хоть что-нибудь подскажет - буду очень признателен.  У меня windows 7 x 64

#1
20:44, 7 авг 2011

Вот когда то делал загрузку текстур из bmp файлов:

BOOL load_texture(char* filename,GLuint num_tex)
{  
  BITMAPFILEHEADER bfh; //Заголовок BMP файла
  BITMAPINFOHEADER bih; //Заголовок BMP файла
  GLubyte *TxBits,*buf; // массивы для цветов 
  DWORD nBytesRead;     // сколько данных прочтено с файла  
  HANDLE FileHandle; // хендл, открываемого для чтения, файла 
  int width,height;  // ширина и высота файла

  // открываем файл для чтения
  FileHandle=CreateFile(filename,          // имя файла 
                GENERIC_READ,        // открыт для чтения 
                0,                // совместного использования нет 
                NULL,              // защита по умолчанию 
                OPEN_EXISTING,        // только существующий файл 
                FILE_ATTRIBUTE_NORMAL,  // атрибуты обычного файла 
                NULL);                  // шаблона атрибутов нет 
      
  if (FileHandle == INVALID_HANDLE_VALUE) // если ошибка при открытии то сообщаем
  {
    MessageBox(NULL,"Файл отсутствует!","Ошибка",MB_OK | MB_ICONINFORMATION);
    return FALSE;
  }  
  ReadFile(FileHandle,&bfh,sizeof(bfh),&nBytesRead,NULL); //считываем первый заголовок, вообще то  он не нужен
  ReadFile(FileHandle,&bih,sizeof(bih),&nBytesRead,NULL); //считываем второй заголовок
  // записываем размер рисунка
  width=bih.biWidth; 
  height=bih.biHeight;
  buf = new GLubyte[width*height*3];    // выделяем память для исходного рисунка
  TxBits = new GLubyte[width*height*3];  // выделяем память для получаемого рисунка
  ReadFile(FileHandle,buf,(width*height*3),&nBytesRead,NULL); //считываем данные о цветах пикселей

  // в этом цикле  меняем структуру цвета, т.к. BMP файл имеет структуру BGR, а нам нужен RGB
  for (int i=0;i<(width*height*3);i+=3) 
  {
    //переписываем массив цветов
    TxBits[i]= buf[i+2];
    TxBits[i+1]= buf[i+1];
    TxBits[i+2]= buf[i];
  }

  // тут инициализируется текстура (это место стерто)

  // ...

  CloseHandle(FileHandle); // закрываем файл
  // освобождаем памяти 
  delete [] TxBits; 
  delete [] buf;  
  return TRUE; // возвражаем TRUE если все успешно
  }

В итоге получаем массив  цветов пикселей TxBits в формате [ R ] [ G ] [ B ] [ R ] [ G ] [ B ]... Красивее смотрелось бы со структурами, но для текстур нужен был такой формат.
Правда это работает только для 24-х битных bmp изображений без сжатия.
Посмотри, может чего и полезного вытянешь из этого кода

#2
21:24, 7 авг 2011

yamilramilev
Спасибо!
Если не решу первое - придется использовать это.)


По форумам полазил - проблема у многих. Именно с GetDIBits =(  Надеюсь найду в чем проблема...чувствую уже близко.

#3
21:58, 7 авг 2011

Порылся у себя, вот что нашел, может пригодится:

...
mM_Bitmap = (HBITMAP)LoadImage(NULL, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
...
GetObject(mM_Bitmap ,sizeof(BITMAP), &bmp);
....
mM_Width  = bmp.bmWidth;
mM_Height = bmp.bmHeight;
mM_Bits   = (BYTE*)bmp.bmBits;
...
BYTE* byte = mM_Bits + y*mM_Width*3;
byte += x*3; // кажется x это координата картинки
COLORREF color = (byte[0]) | (byte[1] << 8) | (byte[2] << 16); // RGB, это то что надо?
...

к сожалению код старый, не могу ничего ни вспомнить ни прокомментировать (может даже картинка читается сверху вниз или вообще черно-белая)
=)

#4
23:55, 7 авг 2011

Ну так у тебя в GetDIBits явно же указана одна строка. Почитай внимательно про этот метод

#5
23:56, 7 авг 2011

И высота должна быть не в байтах, а в пикселях

#6
1:57, 8 авг 2011

Sergio
rAmpArk
yamilramilev

 BITMAP  BitMap;
  
  HDC hdc = CreateCompatibleDC(NULL);
  SelectObject(hdc, hBitmap);
  GetObject(hBitmap, sizeof(BITMAP), &BitMap);
  
  BITMAPINFOHEADER bInfo;


    bInfo.biSize =sizeof(bInfo); //эта штука 40 байт
     bInfo.biWidth = BitMap.bmWidth;  
     bInfo.biHeight = BitMap.bmHeight; 
     bInfo.biBitCount = 32;  //это количество бит на пиксель
     bInfo.biPlanes = 1;
     bInfo.biCompression = BI_RGB;

   BYTE * tempScanLine=new BYTE[1024*768*4];
   int LineCopy = GetDIBits(hdc,hBitmap, 0,BitMap.bmHeight , tempScanLine,(LPBITMAPINFO) &bInfo, DIB_RGB_COLORS);

Всем спасибо! Вот так грузит. Ещё заметил, если в GetDIBits вместо hdc ставить NULL- не записывает.
На форумах очень по-разному заполняются параметры BITMAPINFO. В некоторых biHeight вообще отрицательное число, в некоторых пишут что это вообще величина в байтах растра. Непонятно.

Надеюсь кому-нибудь код поможет :)

#7
8:02, 8 авг 2011

2 LeeSwagger

Тут кагбэ

BYTE * tempScanLine=new BYTE[bInfo.biWidth*bInfo.biHeight*(bInfo.biBitCount/4)];
А ещё и delete [] tempScanLine; не забыть

За информацию о BITMAPINFO
читай MSDN от мелкософта по ссылям от Гоголя, думаю там подробно расписаны поля структуры.

#8
8:02, 8 авг 2011

LeeSwagger
> В некоторых biHeight вообще отрицательное число,
Это значит - изображение отражено по горизонтали, "перевернуто"

LeeSwagger
> в некоторых пишут что это вообще величина в байтах растра
Неверно. Это biSizeImage - размер в байтах, причем если изображение сжатое.

#9
15:21, 8 авг 2011

В уроках NeHe была функция, понимающая сразу jpg, bmp и gif. Тоже использует функции Windows.

ПрограммированиеФорум2D графика и изометрия

Тема в архиве.