Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Загрузка BMP


Автор: KAPJICOH 25.9.2007, 21:44
Не могу загрузить BMP файл. Вот код:

Код

FILE* file;
fopen_s(&file, "Load.bmp", "rb");
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;

fread(&bfh, sizeof(BITMAPFILEHEADER), 1, file);
fread(&bih, sizeof(BITMAPINFOHEADER), 1, file);

BYTE* arr = new BYTE[(bih.biWidth + bih.biWidth%4) * bih.biHeight * 3];
fpos_t pos = bfh.bfOffBits;
fsetpos(file, &pos);
for(int i=0;i<(bih.biWidth + bih.biWidth%4) * bih.biHeight * 3; i++)
    fread(&arr[i], sizeof(BYTE), 1, file);

HBITMAP hbm, hOldbm;
HDC hMemDC, hDC;
BITMAP bm;
POINT  ptSize, ptOrg;

hDC = GetWindowsDC(hWnd);
hMemDC = CreateCompatibleDC(hDC);
HBITMAP hBitmap = CreateBitmap(bih.biWidth, bih.biHeight, bih.biPlanes, bih.biBitCount, arr);

 // Выбираем изображение bitmap в контекст памяти
hOldbm = (HBITMAP)SelectObject(hMemDC, hBitmap);
//ОШИБКА:  hOldbm = NULL т.е битмап не присоединился к устройству

  // Если не было ошибок, продолжаем работу
  if (hOldbm)
  {
    // Для контекста памяти устанавливаем тот же
    // режим отображения, что используется в
    // контексте отображения
    SetMapMode(hMemDC, GetMapMode(hDC));

    // Определяем размеры изображения
    GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);

    ptSize.x = bm.bmWidth;   // ширина
    ptSize.y = bm.bmHeight;  // высота

    // Преобразуем координаты устройства в логические
    // для устройства вывода
    DPtoLP(hDC, &ptSize, 1);

    ptOrg.x = 0;
    ptOrg.y = 0;

    // Преобразуем координаты устройства в логические
    // для контекста памяти
    DPtoLP(hMemDC, &ptOrg, 1);

    // Рисуем изображение bitmap
    BitBlt(hDC, 0, 0, ptSize.x, ptSize.y,
           hMemDC, ptOrg.x, ptOrg.y, SRCCOPY);

    // Восстанавливаем контекст памяти
    SelectObject(hMemDC, hOldbm);
  }

  // Удаляем контекст памяти
  DeleteDC(hMemDC);


    fclose(file);
    delete[] arr;


Битмап загружается, но я не могу присоединить его к устройству. Может кто-нибудь сталкивался с этой проблемой? Спасибо.

Автор: Mihhail 26.9.2007, 09:19
Здесь дело в несоответствии цветовой палитры и глубины цвета, картинки и контекста. Необходимо преобразование:
Код
hDC = GetDC( hWnd );
hMemDC = CreateCompatibleDC( hDC );

//Создаём картинку совместимое с контекстом
HBITMAP hBitmap = CreateCompatibleBitmap( hDC, bih.biWidth, bih.biHeight );

// Выбираем изображение bitmap в контекст памяти
hOldbm = (HBITMAP)SelectObject( hMemDC, hBitmap );

BITMAPINFO bi;
memcpy( &bi.bmiHeader, &bih, sizeof(BITMAPINFOHEADER) );

//Устанавливаем пиксели картинки, используя цветные данные загруженой
SetDIBits( hMemDC, hBitmap, 0, (WORD)bih.biHeight, arr, &bi, DIB_RGB_COLORS );


Цитата(KAPJICOH @  26.9.2007,  01:44 Найти цитируемый пост)
for(int i=0;i<(bih.biWidth + bih.biWidth%4) * bih.biHeight * 3; i++)
    fread(&arr[i], sizeof(BYTE), 1, file);

Может проще так?
fread( arr, sizeof(BYTE), (bih.biWidth + bih.biWidth%4) * bih.biHeight * 3, file );
smile

Автор: Alexeis 26.9.2007, 09:32
  странный метод вычисления размера растра.

Правильно будет 
   LineSize = (bih.biWidth * 3 +3) / 4 * 4;

Мы же выравниваем на 4 байта. Например, если длинна строки 257 байт, то она выравнивается на 3 байта до 260 байт

Строчка bih.biWidth + bih.biWidth%4 никак не выравнивает строку на границу 4х байт. Кроме того сам размер тоже должен быть выравнен на границу 4х байт.
   BitsSize = ((bih.biWidth * 3 +3) / 4 * 4 * bih.biHeight + 3) / 4 * 4;

Автор: Earnest 26.9.2007, 11:13
Цитата(Mihhail @  26.9.2007,  10:19 Найти цитируемый пост)
Может проще так?

Не проще, так как в общем случае строки bmp-файла и битмапа имеют неодинаковую длину: первые выровнены на 4 байта, а вторые - на 2.

KAPJICOH
Здесь куча мест, где можно допустить ошибку. И на форуме такие темы обсуждались, и кода примеры были, работающего. Поищи... в сто двадцать пятый раз искать в чем кривизна загрузки битмапа ей богу лень. smile 

Автор: Mihhail 26.9.2007, 12:07
Цитата(Earnest @  26.9.2007,  15:13 Найти цитируемый пост)
Не проще, так как в общем случае строки bmp-файла и битмапа имеют неодинаковую длину: первые выровнены на 4 байта, а вторые - на 2.

В данном случае это ни как не проявляется. Идёт побайтная загрузка всего блока растровых данных. Выравнивание учитывается позже, при вызове функции SetDIBits.

Автор: KAPJICOH 26.9.2007, 13:37
Цитата(Earnest @ 26.9.2007,  11:13)
KAPJICOH
Здесь куча мест, где можно допустить ошибку. И на форуме такие темы обсуждались, и кода примеры были, работающего. Поищи... в сто двадцать пятый раз искать в чем кривизна загрузки битмапа ей богу лень. smile

Сколько не искал всегда натыкался на функцию LoadBitmap.

Битмап создается, но привязать его к устройству не получается, как проверить правильность загрузки битмапа?

Автор: KAPJICOH 26.9.2007, 14:07
Все основная задача - вывести на экран решена. Вот код кому интересно:
Код

FILE* file;
    fopen_s(&file, "Load.bmp", "rb");
    BITMAPFILEHEADER bfh;
    BITMAPINFOHEADER bih;

    fread(&bfh, sizeof(BITMAPFILEHEADER), 1, file);
    fread(&bih, sizeof(BITMAPINFOHEADER), 1, file);

    if(hWnd == NULL)
    {
        Create(hParent, bih.biWidth, bih.biHeight);
    }
    else
    {
        MoveWindow(hWnd, 55, 0, bih.biWidth, bih.biHeight, TRUE);
    }

    HDC hdc = GetWindowDC(hWnd);
    BITMAPINFO BMI;

    BMI.bmiHeader.biSize = sizeof(BMI.bmiHeader);
    BMI.bmiHeader.biBitCount = bih.biBitCount;
    BMI.bmiHeader.biCompression = BI_RGB;
    BMI.bmiHeader.biPlanes = 1;
    BMI.bmiHeader.biWidth = bih.biWidth;
    BMI.bmiHeader.biHeight = bih.biHeight;

    BYTE* arr = new BYTE[((bih.biWidth * 3 +3) / 4 * 4 * bih.biHeight + 3) / 4 * 4];
    fpos_t pos = bfh.bfOffBits;
    fsetpos(file, &pos);
    fread(arr, sizeof(BYTE), ((bih.biWidth * 3 +3) / 4 * 4 * bih.biHeight + 3) / 4 * 4, file);

    //Выводим... Если есть hBitmap, можно обойтись SetDIBits
    SetDIBitsToDevice(hdc, 0, 0, bih.biWidth, bih.biHeight, 0, 0, 0, bih.biHeight, arr, &BMI, DIB_RGB_COLORS);

    fclose(file);
    delete[] arr;


Всем спасибо!

Автор: Alexeis 26.9.2007, 15:44
Цитата(KAPJICOH @  26.9.2007,  13:37 Найти цитируемый пост)
Сколько не искал всегда натыкался на функцию LoadBitmap.

  А как же LoadImage()? Она как раз грузит битмап из файла и создает битмап.

Автор: KAPJICOH 26.9.2007, 18:41
Цитата(Alexeis @ 26.9.2007,  15:44)
  А как же LoadImage()? Она как раз грузит битмап из файла и создает битмап.

По условию надо все это делать самому. Наверное я само задание криво объяснил))

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)