더북(TheBook)

지금까지 설명한 핵심 코드에 주석과 예외 사항 체크를 추가한 완전한 OnLButtonDown 함수를 소스 3-1에 나타내었다.

소스 3-1 OnLButtonDown 함수 전체 소스 내용(BmpShowView.cpp)
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')

void CBmpShowView::OnLButtonDown(UINT nFlags, CPoint point)
{
    FILE* fp = NULL;
    fopen_s(&fp, "lenna.bmp", "rb");
    if (!fp)
        return;

    BITMAPFILEHEADER bmfh;
    BITMAPINFOHEADER bmih;

    // BITMAPFILEHEADER 읽기
    if (fread(&bmfh, sizeof(BITMAPFILEHEADER), 1, fp) != 1) {
        fclose(fp);
        return;
    }

    // BMP 파일임을 나타내는 'BM' 마커가 있는지 확인
    if (bmfh.bfType != DIB_HEADER_MARKER) {
        fclose(fp);
        return;
    }

    // BITMAPINFOHEADER 읽기
    if (fread(&bmih, sizeof(BITMAPINFOHEADER), 1, fp) != 1) {
        fclose(fp);
        return;
    }

    LONG nWidth = bmih.biWidth;
    LONG nHeight = bmih.biHeight;
    WORD nBitCount = bmih.biBitCount;

    DWORD dwWidthStep = (DWORD)((nWidth * nBitCount / 8 + 3) & ~3);
    DWORD dwSizeImage = nHeight * dwWidthStep;

    // DIB 구조 전체 크기 계산 (BITMAPINFOHEADER + 색상 테이블 + 픽셀 데이터)
    DWORD dwDibSize;
    if (nBitCount = = 24)
        dwDibSize = sizeof(BITMAPINFOHEADER) + dwSizeImage;
    else
        dwDibSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << nBitCount) + dwSizeImage;

    // 파일로부터 DIB 구조를 읽어서 저장할 메모리 공간 할당
    BYTE* pDib = new BYTE[dwDibSize];

    if (pDib = = NULL)
    {
        fclose(fp);
        return;
    }

    // 파일로부터 Packed-DIB 크기만큼을 읽기
    fseek(fp, sizeof(BITMAPFILEHEADER), SEEK_SET);
    if (fread(pDib, sizeof(BYTE), dwDibSize, fp) != dwDibSize)
    {
        delete[] pDib;
        pDib = NULL;
        fclose(fp);
        return;
    }

    // 픽셀 데이터 시작 위치 계산
    LPVOID lpvBits;
    if (nBitCount = = 24)
        lpvBits = pDib + sizeof(BITMAPINFOHEADER);
    else
        lpvBits = pDib + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << nBitCount);

    // DIB 화면 출력
    CClientDC dc(this);
    ::SetDIBitsToDevice(dc.m_hDC, point.x, point.y, nWidth, nHeight, 0, 0, 0,
        nHeight, lpvBits, (BITMAPINFO*)pDib, DIB_RGB_COLORS);

    // 메모리 해제 및 파일 닫기
    delete[] pDib;
    fclose(fp);

    CView::OnLButtonDown(nFlags, point);
}
신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.