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;
    }
    
    신간 소식 구독하기
    뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.