Wednesday, September 17, 2014

Visual C++ 16비트 565 BMP 예제

bool loadBmpFile( LPCTSTR bmpFileName, int& outWidth, int& outHeight, int& outBpp, BYTE*& outBmpData )
{
    FILE *fp = fopen(bmpFileName, "rb");
    if(!fp)
        return false;

 BITMAPFILEHEADER bfh;
 BITMAPINFOHEADER bih;
 RGBQUAD rgb[3];

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

 // 16비트는 추가적으로 rgb가 12바이트 들어있다.
 if(bih.biBitCount == 16) {
  fread(rgb, sizeof(RGBQUAD), 3, fp);
 }

    LPBYTE buffer = new BYTE[bih.biSizeImage];
    fread(buffer, sizeof(BYTE), bih.biSizeImage, fp);
    fclose(fp);

 outWidth = bih.biWidth;
 outHeight = bih.biHeight;
 outBpp = bih.biBitCount;

 // height는 뒤집어 준다.
 if(outHeight < 0) {
  outHeight *= -1;
 }
 outBmpData = buffer;
 return true;
}

bool saveBmpFile( LPCTSTR bmpFileName, int width, int height, int bpp, BYTE* bmpData )
{
    PBITMAPINFO pbmi;

 if(height < 0)
  height *= -1;

 // 16비트는 추가적으로 rgb가 12바이트 들어있다.
 if (bpp == 16) {
        pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
        sizeof(BITMAPINFOHEADER) +
        sizeof(RGBQUAD) * 3);
 }
 else {// 24,32비트
        pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
        sizeof(BITMAPINFOHEADER));
 }

    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbmi->bmiHeader.biWidth = width;
    pbmi->bmiHeader.biHeight = height;
    pbmi->bmiHeader.biPlanes = 1;
    pbmi->bmiHeader.biBitCount = bpp;

 if (bpp == 16) {// 16비트 565일 경우의 bit mask를 채워준다. 그리고 rgb가 아니라 bitfields로 셋팅한다.
        pbmi->bmiHeader.biClrUsed = 3;
  pbmi->bmiHeader.biCompression = BI_BITFIELDS;
  memset(pbmi->bmiColors, 0, sizeof(RGBQUAD)*3);
  pbmi->bmiColors[0].rgbGreen = 248;
  pbmi->bmiColors[1].rgbBlue = 224;
  pbmi->bmiColors[1].rgbGreen = 7;
  pbmi->bmiColors[2].rgbBlue = 31;
 }
 else {
  pbmi->bmiHeader.biClrUsed = 0;
  pbmi->bmiHeader.biCompression = BI_RGB;
 }

    pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * bpp +31) & ~31) /8
        * pbmi->bmiHeader.biHeight;
    pbmi->bmiHeader.biClrImportant = 0;

 // height는 뒤집어 준다.
 if(pbmi->bmiHeader.biHeight > 0) {
  pbmi->bmiHeader.biHeight *= -1;
 }

    HANDLE hf;                 // file handle
    BITMAPFILEHEADER hdr;       // bitmap file-header
    DWORD dwTotal;              // total count of bytes
    DWORD cb;                   // incremental count of bytes
    BYTE *hp;                   // byte pointer
    DWORD dwTmp;

    // Create the .BMP file.
    hf = CreateFile(bmpFileName,
        GENERIC_READ | GENERIC_WRITE,
        (DWORD) 0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        (HANDLE) NULL);
    if (hf == INVALID_HANDLE_VALUE)
        return false;
    hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M"
    // Compute the size of the entire file.
    hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
        pbmi->bmiHeader.biSize + pbmi->bmiHeader.biClrUsed
        * sizeof(RGBQUAD) + pbmi->bmiHeader.biSizeImage);
    hdr.bfReserved1 = 0;
    hdr.bfReserved2 = 0;

    // Compute the offset to the array of color indices.
    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
        pbmi->bmiHeader.biSize + pbmi->bmiHeader.biClrUsed
        * sizeof (RGBQUAD);

    // Copy the BITMAPFILEHEADER into the .BMP file.
    if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),
        (LPDWORD) &dwTmp,  NULL))
    {
        return false;
    }

    // Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
    if (!WriteFile(hf, (LPVOID) &pbmi->bmiHeader, sizeof(BITMAPINFOHEADER)
        + pbmi->bmiHeader.biClrUsed * sizeof (RGBQUAD),
        (LPDWORD) &dwTmp, ( NULL)))
        return false;

    // Copy the array of color indices into the .BMP file.
    dwTotal = cb = pbmi->bmiHeader.biSizeImage;
    hp = bmpData;
    if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))
        return false;

    // Close the .BMP file.
    if (!CloseHandle(hf))
        return false;

 return true;
}

No comments:

Post a Comment