8位與24位圖像的相互轉換

原文鏈接:

http://hi.baidu.com/mayadong7349/blog/item/1b7e2b445f8e9e1c6a63e53a.html


#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

FILE *fpSrcBmpfile;
FILE *fpDestBmpfile;

void GetBmpHeader(PBITMAPFILEHEADER, PBITMAPINFOHEADER);
void ChangeBmpHeader(PBITMAPFILEHEADER, PBITMAPINFOHEADER, WORD);
void SetBmpHeader(const PBITMAPFILEHEADER, const PBITMAPINFOHEADER);
void SetRGBQUAD();
void RgbToGrade(); // 24位真彩色轉8位灰度
void GradeToRgb(); // 8位灰度位圖轉24位真彩色

int main(int argc, char *argv[])
{
    BITMAPFILEHEADER bfheader; // bmp文件頭
    BITMAPINFOHEADER biheader; // 位圖信息頭
    memset(&bfheader, 0, sizeof(BITMAPFILEHEADER));
    memset(&biheader, 0, sizeof(BITMAPINFOHEADER));
    if(argc != 2)
    {
        puts("\n\t***Error  : I need two parameters.");
        puts("\t   Example: RgbToQuad.exe D:\\flower.bmp");
        system("pause>nul");
        exit(EXIT_SUCCESS);
    }
    if((fpSrcBmpfile = fopen(argv[1], "rb")) == NULL) {
        perror("\t***Open file failed:(read)");
        system("pause>nul");
        exit(EXIT_FAILURE);
    }
    GetBmpHeader(&bfheader, &biheader);
    if(bfheader.bfType != 0x4D42) {
        puts("\t  *End: This file is not bitmap file.");
        system("pause>nul");
        exit(EXIT_SUCCESS);
    }

    if(biheader.biBitCount != 24 && biheader.biBitCount != 8) {
        puts("\n  *End: This bmp file is neither a 24bit nor a 8bit bitmap.");
        system("pause>nul");
        exit(EXIT_SUCCESS);
    }
    // 對於採用了遊程長度編碼方法進行壓縮的8位位圖 不能按照本算法轉爲24位位圖
    if(biheader.biBitCount == 8 && biheader.biCompression != BI_RGB) {
        puts("\n   *End: This 8bit bmp file is not BI_RGB type");
        system("pause>nul");
        exit(EXIT_SUCCESS);
    }
    if((fpDestBmpfile = fopen("D:\\_Done_.bmp", "wb")) == NULL) {
        perror("fopen failed :(write)");
        system("pause>nul");
        exit(EXIT_FAILURE);
    }
    switch(biheader.biBitCount) {
        case 8 : GradeToRgb(); break;
        case 24: RgbToGrade(); break;
        default: break;
    }
    fclose(fpDestBmpfile);
    fclose(fpSrcBmpfile);
    system("pause>nul");
    return 0;
}
void GetBmpHeader(PBITMAPFILEHEADER pbfheader, PBITMAPINFOHEADER pbiheader)
{
    fread(pbfheader, sizeof(BITMAPFILEHEADER), 1,fpSrcBmpfile);
    fread(pbiheader, sizeof(BITMAPINFOHEADER), 1,fpSrcBmpfile);
}

void ChangeBmpHeader(PBITMAPFILEHEADER pbfheader, PBITMAPINFOHEADER pbiheader, WORD wType)
{
    pbiheader->biBitCount  = wType; // 24 或者 8
    pbiheader->biClrUsed   = (wType == 24) ? 0 : 256;
    pbfheader->bfOffBits   = 54 + pbiheader->biClrUsed * sizeof(RGBQUAD);
    pbiheader->biSizeImage = ((((pbiheader->biWidth * pbiheader->biBitCount) + 31) & ~31) / 8) * pbiheader->biHeight;
    pbfheader->bfSize      = pbfheader->bfOffBits + pbiheader->biSizeImage;
}

void SetBmpHeader(const PBITMAPFILEHEADER pbfheader, const PBITMAPINFOHEADER pbiheader)
{
    fwrite(pbfheader, sizeof(BITMAPFILEHEADER), 1, fpDestBmpfile);
    fwrite(pbiheader, sizeof(BITMAPINFOHEADER), 1, fpDestBmpfile);
}

void SetRGBQUAD()
{
    int i;
    RGBQUAD rgbquad[256];
    for(i=0;i<256;i++) {
        rgbquad[i].rgbBlue     = i;
        rgbquad[i].rgbGreen    = i;
        rgbquad[i].rgbRed      = i;
        rgbquad[i].rgbReserved = 0;
    }
    fwrite(rgbquad, 256 * sizeof(RGBQUAD), 1, fpDestBmpfile);
}

void RgbToGrade() {
    LONG w, h;
    COLORREF rgb;
    BYTE r, g, b;
    BYTE gray;
    BYTE count24, count8;
    BYTE Bmpnul = 0;
    BITMAPFILEHEADER bfheader; // bmp文件頭
    BITMAPINFOHEADER biheader; // 位圖信息頭
    memset(&bfheader, 0, sizeof(BITMAPFILEHEADER));
    memset(&biheader, 0, sizeof(BITMAPINFOHEADER));
    rewind(fpSrcBmpfile);
    GetBmpHeader(&bfheader, &biheader);
    ChangeBmpHeader(&bfheader, &biheader, 8);
    SetBmpHeader(&bfheader, &biheader);
    SetRGBQUAD();
    count24 =  ( 4 - ( biheader.biWidth * 3 ) % 4 ) % 4;
    count8  =  ( 4 - ( biheader.biWidth     ) % 4 ) % 4;
    for(h=biheader.biHeight-1; h>=0; h--) {
        for(w=0; w<biheader.biWidth; w++) {
            fread(&rgb, 3, 1, fpSrcBmpfile);
            if(feof(fpSrcBmpfile)) {
                break;
            }
            // rgb: 0x00bbggrr
            r = GetBValue(rgb);
            g = GetGValue(rgb);
            b = GetRValue(rgb);
            // 參見: http://zhidao.baidu.com/question/152910968.html
            gray = (BYTE)( ( 77 * r + 151 * g + 28 * b) >> 8 ); // 24位轉8位核心算法
            fwrite(&gray, sizeof(gray), 1, fpDestBmpfile);
        } // for(w
        fseek(fpSrcBmpfile, count24, SEEK_CUR);
        fwrite(&Bmpnul, 1, count8, fpDestBmpfile);
    } // for(h=...
}
void GradeToRgb()
{
    LONG w, h;
    COLORREF rgb;
    BYTE gray;
    BYTE count24, count8; // 24位位圖、8位位圖每個掃描行需要填充的0的個數
    BYTE Bmpnul = 0;
    BITMAPFILEHEADER bfheader; // bmp文件頭
    BITMAPINFOHEADER biheader; // 位圖信息頭
    memset(&bfheader, 0, sizeof(BITMAPFILEHEADER));
    memset(&biheader, 0, sizeof(BITMAPINFOHEADER));
    rewind(fpSrcBmpfile);
    GetBmpHeader(&bfheader, &biheader);
    ChangeBmpHeader(&bfheader, &biheader, 24);
    SetBmpHeader(&bfheader, &biheader);
    fseek(fpSrcBmpfile, 256 * sizeof(RGBQUAD), SEEK_CUR); // 跳過顏色表部分 因爲24位位圖不需要顏色表
    count24 =  ( 4 - ( biheader.biWidth * 3 ) % 4 ) % 4;
    count8  =  ( 4 - ( biheader.biWidth     ) % 4 ) % 4;
    for(h=biheader.biHeight-1; h>=0; h--) {
        for(w=0; w<biheader.biWidth; w++) {
            fread(&gray, 1, 1, fpSrcBmpfile);
            if(feof(fpSrcBmpfile)) {
                break;
            }
            rgb = RGB(graygraygray); // 8位轉24位核心算法
            fwrite(&rgb, 3, 1, fpDestBmpfile);
        } // for(w
        fseek(fpSrcBmpfile, count8, SEEK_CUR);
        fwrite(&Bmpnul, 1, count24, fpDestBmpfile);
    } // for(h
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章