测试: 
源24位位图: 无压缩, 高=20, 宽=108, 从中取出其中的左边宽18的部分(高度不变)下面的代码运行得到的位图,颜色不匹配(图像的大致轮廓是对的,但像右偏了一像素)
可能的问题: 
1、代码中将源图的头和描述仅修改了一部分即作为目标图的头和描述,是否还有其他需要修改?
2、位图需要行字节为4的倍数,是否补齐、访问像素索引出了问题?
请帮忙测试一下,可以用画图软件随便弄一个108*20的24位图,代码拷贝过去即可运行(请将nDestWidth设为18,这样测试用例保持一致):void ConvertBitmap24(const char* pszSrcFName, const char* pszDestFName, long nDestWidth)
{
    //= 从源24位位图提取指定的宽度(0~~nDestWidth),高度不变,生成目标24位位图文件
    //= 假定输入一定为24位位图文件名, 且文件操作都正确    BITMAPFILEHEADER srcBMPFileHeader;
    BITMAPINFO srcBMPInfo; FILE *fpBitmap = fopen(pszSrcFName, "rb");    //= 读取源位图头部: (位图标识: bmpFileHeader.bfType==0x4D42)
fread(&srcBMPFileHeader, sizeof(BITMAPFILEHEADER), 1, fpBitmap);    //= 读取源位图描述 (24位位图解析: bmpInfo.bmiHeader.biBitCount == 24)
fread(&srcBMPInfo.bmiHeader, sizeof(BITMAPINFOHEADER), 1, fpBitmap);    //= 申请源位图数据缓冲
    unsigned char* pbSrcBMPData = new unsigned char[srcBMPInfo.bmiHeader.biSizeImage];    //= 定位到源位图的数据部分
    fseek(fpBitmap, srcBMPFileHeader.bfOffBits, 0);
    //= 读取源位图的数据
    fread(pbSrcBMPData, srcBMPInfo.bmiHeader.biSizeImage, 1, fpBitmap);    //= 关闭源位图
    fclose(fpBitmap);    //= 源位图长宽(这里取绝对值, 不考虑颠倒的问题)
    long nSrcWidth  = abs(srcBMPInfo.bmiHeader.biWidth);
    long nSrcHeight = abs(srcBMPInfo.bmiHeader.biHeight);
    BITMAPFILEHEADER destBMPFileHeader;
    BITMAPINFO       destBMPInfo;    //= 源位图的行字节数
    int nSrcLineBytes  = ( (nSrcWidth *24/32) + (((nSrcWidth *24)%32)?1:0) ) * 4;    //= 目标位图的行字节数
    int nDestLineBytes = ( (nDestWidth*24/32) + (((nDestWidth*24)%32)?1:0) ) * 4;    //= 等同上面代码
    //nSrcLineBytes  = (nSrcWidth *24 + 31) / 32 * 4;
    //nDestLineBytes = (nDestWidth*24 + 31) / 32 * 4;    //= 将源位图头部的bfSize(文件大小)修改作为目标位图头部
    memcpy(&destBMPFileHeader, &srcBMPFileHeader, sizeof(BITMAPFILEHEADER));
    destBMPFileHeader.bfSize = srcBMPFileHeader.bfOffBits + nDestLineBytes*20;    //= 将源位图描述的长宽、图像大小修改作为目标位图描述
    memcpy(&destBMPInfo, &srcBMPInfo, sizeof(BITMAPINFO));
    destBMPInfo.bmiHeader.biWidth     = nDestWidth; // 指定宽度
    destBMPInfo.bmiHeader.biHeight    = nSrcHeight; // 高度不变
    destBMPInfo.bmiHeader.biSizeImage = nSrcHeight * nDestLineBytes;    //= 申请目标位图数据缓冲
    unsigned char* pbDestBMPData = new unsigned char[destBMPInfo.bmiHeader.biSizeImage];    //= 预制全白色
    memset(pbDestBMPData, 255, destBMPInfo.bmiHeader.biSizeImage); //= BGR三色
for (int nHeighLoop=0; nHeighLoop<nSrcHeight; nHeighLoop++)
{
for (int nWidthLoop=0; nWidthLoop<nDestWidth; nWidthLoop++)
{
            //= 从源位图提取指定宽度的BGR
            unsigned char b = pbSrcBMPData [ nSrcLineBytes*nHeighLoop + 3*nWidthLoop     ];
            unsigned char g = pbSrcBMPData [ nSrcLineBytes*nHeighLoop + 3*nWidthLoop + 1 ];
            unsigned char r = pbSrcBMPData [ nSrcLineBytes*nHeighLoop + 3*nWidthLoop + 2 ];            //= 设置目标位图BGR
            pbDestBMPData [ nDestLineBytes*nHeighLoop + 3*nWidthLoop     ] = b;
            pbDestBMPData [ nDestLineBytes*nHeighLoop + 3*nWidthLoop + 1 ] = g;
            pbDestBMPData [ nDestLineBytes*nHeighLoop + 3*nWidthLoop + 2 ] = r;
}
}    //= 释放源位图数据缓冲
    delete pbSrcBMPData;    //= 生成目标位图文件写入文件
    fpBitmap = fopen(pszDestFName, "wb");
    fwrite(&destBMPFileHeader, 1, sizeof(BITMAPFILEHEADER), fpBitmap);
    fwrite(&destBMPInfo, 1, sizeof(BITMAPINFO), fpBitmap);
    fwrite(pbDestBMPData, 1, destBMPInfo.bmiHeader.biSizeImage, fpBitmap);
    fclose(fpBitmap);    //= 释放目标位图数据缓冲
    delete pbDestBMPData;
}

解决方案 »

  1.   

    已解决fwrite(&destBMPInfo, 1, sizeof(BITMAPINFO), fpBitmap); 
    将BITMAPINFO中的RGBQUAD(颜色表)写入了文件,但是bfOffBits未增加该偏移,文件大小也未增加大小,导致数据整体偏移修改为:
         //= 生成目标位图文件写入文件 
         fpBitmap = fopen(pszDestFName, "wb"); 
        fwrite(&destBMPFileHeader, 1, sizeof(BITMAPFILEHEADER), fpBitmap); 
        fwrite(&destBMPInfo, 1, sizeof(BITMAPINFO), fpBitmap);
        fseek(fpBitmap, destBMPFileHeader.bfOffBits, 0);
        fwrite(pbDestBMPData, 1, destBMPInfo.bmiHeader.biSizeImage, fpBitmap); 
        fclose(fpBitmap); 
      

  2.   

    void ConvertBitmap24(const char* pszSrcFName, const char* pszDestFName, long nDestWidth) 

        //= 从源24位位图提取指定的宽度(0~~nDestWidth),高度不变,生成目标24位位图文件 
        //= 假定输入一定为24位位图文件名, 且文件操作都正确     BITMAPFILEHEADER srcBMPFileHeader; 
        BITMAPINFOHEADER srcBMPInfo;                  //该为BITMAPINFOHEADER     FILE *fpBitmap = fopen(pszSrcFName, "rb");     //= 读取源位图头部: (位图标识: bmpFileHeader.bfType==0x4D42) 
        fread(&srcBMPFileHeader, sizeof(BITMAPFILEHEADER), 1, fpBitmap);     //= 读取源位图描述 (24位位图解析: bmpInfo.bmiHeader.biBitCount == 24) 
        fread(&srcBMPInfo, sizeof(BITMAPINFOHEADER), 1, fpBitmap);     //= 申请源位图数据缓冲 
        unsigned char* pbSrcBMPData = new unsigned char[srcBMPInfo.biSizeImage];     //= 定位到源位图的数据部分 
        fseek(fpBitmap, srcBMPFileHeader.bfOffBits, 0); 
        //= 读取源位图的数据 
        fread(pbSrcBMPData, srcBMPInfo.biSizeImage, 1, fpBitmap);     //= 关闭源位图 
        fclose(fpBitmap);     //= 源位图长宽(这里取绝对值, 不考虑颠倒的问题) 
        long nSrcWidth  = abs(srcBMPInfo.biWidth); 
        long nSrcHeight = abs(srcBMPInfo.biHeight); 
        BITMAPFILEHEADER destBMPFileHeader; 
        BITMAPINFOHEADER      destBMPInfo;     //= 源位图的行字节数 
        int nSrcLineBytes  = ( (nSrcWidth *24/32) + (((nSrcWidth *24)%32)?1:0) ) * 4;     //= 目标位图的行字节数 
        int nDestLineBytes = ( (nDestWidth*24/32) + (((nDestWidth*24)%32)?1:0) ) * 4;     //= 等同上面代码 
        //nSrcLineBytes  = (nSrcWidth *24 + 31) / 32 * 4; 
        //nDestLineBytes = (nDestWidth*24 + 31) / 32 * 4;     //= 将源位图头部的bfSize(文件大小)修改作为目标位图头部 
        memcpy(&destBMPFileHeader, &srcBMPFileHeader, sizeof(BITMAPFILEHEADER)); 
        destBMPFileHeader.bfSize = srcBMPFileHeader.bfOffBits + nDestLineBytes*20;     //= 将源位图描述的长宽、图像大小修改作为目标位图描述 
        memcpy(&destBMPInfo, &srcBMPInfo, sizeof(BITMAPINFOHEADER)); 
        destBMPInfo.biWidth    = nDestWidth; // 指定宽度 
        destBMPInfo.biHeight    = nSrcHeight; // 高度不变 
        destBMPInfo.biSizeImage = nSrcHeight * nDestLineBytes;     //= 申请目标位图数据缓冲 
        unsigned char* pbDestBMPData = new unsigned char[destBMPInfo.biSizeImage];     //= 预制全白色 
        memset(pbDestBMPData, 255, destBMPInfo.biSizeImage); //= BGR三色 
    for (int nHeighLoop=0; nHeighLoop <nSrcHeight; nHeighLoop++) 

    for (int nWidthLoop=0; nWidthLoop <nDestWidth; nWidthLoop++) 

                //= 从源位图提取指定宽度的BGR 
                unsigned char b = pbSrcBMPData [ nSrcLineBytes*nHeighLoop + 3*nWidthLoop    ]; 
                unsigned char g = pbSrcBMPData [ nSrcLineBytes*nHeighLoop + 3*nWidthLoop + 1 ]; 
                unsigned char r = pbSrcBMPData [ nSrcLineBytes*nHeighLoop + 3*nWidthLoop + 2 ];             //= 设置目标位图BGR 
                pbDestBMPData [ nDestLineBytes*nHeighLoop + 3*nWidthLoop    ] = b; 
                pbDestBMPData [ nDestLineBytes*nHeighLoop + 3*nWidthLoop + 1 ] = g; 
                pbDestBMPData [ nDestLineBytes*nHeighLoop + 3*nWidthLoop + 2 ] = r; 

    }     //= 释放源位图数据缓冲 
        delete pbSrcBMPData;     //= 生成目标位图文件写入文件 
        fpBitmap = fopen(pszDestFName, "wb"); 
        fwrite(&destBMPFileHeader, 1, sizeof(BITMAPFILEHEADER), fpBitmap); 
        fwrite(&destBMPInfo, 1, sizeof(BITMAPINFOHEADER), fpBitmap); 
        fwrite(pbDestBMPData, 1, destBMPInfo.biSizeImage, fpBitmap); 
        fclose(fpBitmap);     //= 释放目标位图数据缓冲 
        delete pbDestBMPData; 
    }
      

  3.   

    BITMAPINFO srcBMPInfo; 
    ---------------------
    定义的时候直接定义为BITMAPINFOHEADER就可以了
      

  4.   


    这么处理也可以,这样就不会将BITMAPINFO中的RGBQUAD(颜色表)写入位图中,而只写入了等同BITMAPINFO的成员bmiHeader(BITMAPINFOHEADER)
    不用fseek到偏移位置了