더북(TheBook)

IppDib 클래스의 파일 입출력 함수들의 실제 구현은 소스 4-4에 나타내었다. BMP 파일을 불러오는 방법은 3.4절 BmpShow 프로그램에서 자세히 설명하였으므로 여기서는 설명을 생략한다. LoadBMP 함수를 제대로 이해하면 SaveBMP 함수 또한 어렵지 않을 것이다.

소스 4-4 IppDib 클래스 - BMP 파일 입출력(IppDib.cpp)
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')

BOOL IppDib::Load(const char* filename)
{
    const char* ext = strrchr(filename, '.');
    if (!_strcmpi(ext, ".bmp"))
        return LoadBMP(filename);
    else
        return FALSE;
}

BOOL IppDib::Save(const char* filename)
{
    const char* ext = strrchr(filename, '.');
    if (!_strcmpi(ext, ".bmp"))
        return SaveBMP(filename);
    else
        return FALSE;
}

BOOL IppDib::LoadBMP(const char* filename)
{
    FILE* fp = NULL;
    fopen_s(&fp, filename, "rb");
    if (!fp)
        return false;

    BITMAPFILEHEADER bmfh;
    BITMAPINFOHEADER bmih;

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

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

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

    m_nWidth    = bmih.biWidth;
    m_nHeight   = bmih.biHeight;
    m_nBitCount = bmih.biBitCount;

    // 픽셀 데이터 공간 계산
    DWORD dwWidthStep = (DWORD)((m_nWidth * m_nBitCount / 8 + 3) & ~3);
    DWORD dwSizeImage = m_nHeight * dwWidthStep;

    if (m_nBitCount == 24)
        m_nDibSize = sizeof(BITMAPINFOHEADER) + dwSizeImage;
    else
        m_nDibSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << m_nBitCount) + dwSizeImage;

    // Packed-DIB 저장할 메모리 공간 동적 할당
    if (m_pDib)
        DestroyBitmap();

    m_pDib = new BYTE[m_nDibSize];
    if (m_pDib == NULL)
    {
        fclose(fp);
        return FALSE;
    }

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

    // 파일 닫기
    fclose(fp);

    return TRUE;
}

BOOL IppDib::SaveBMP(const char* filename)
{
    if (!IsValid())
        return FALSE;

    FILE* fp;
    fopen_s(&fp, filename, "wb");
    if (!fp)
        return FALSE;

    BITMAPFILEHEADER bmfh;
    bmfh.bfType      = DIB_HEADER_MARKER;
    bmfh.bfSize      = (DWORD)sizeof(BITMAPFILEHEADER) + m_nDibSize;
    bmfh.bfReserved1 = 0;
    bmfh.bfReserved2 = 0;
    bmfh.bfOffBits   = (DWORD)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
        + (sizeof(RGBQUAD) * GetPaletteNums()));

    fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, fp);
    fwrite(GetBitmapInfoAddr(), m_nDibSize, 1, fp);

    fclose(fp);

    return TRUE;
}
신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.