读数据文件 生成BMP图像

 

读数据文件 生成BMP图像

该程序的功能是读取存有位图颜色数据的数据流,提取颜色数据并进行格式转换,再存为位图文件。即将16位颜色数据转换成24位后以位图文件存储。
数据文件是通过固定转换工具由转换而来的(其实是我的同事写的,所以数据文件的格式是按我的要求生成的),转换后的数据格式为16位565形式的数据,高位在后,低位在前。存在“.c”文件中(存成什么文件不重要)。

数据文件的格式:(可以是多个位图的数据)
/* Plane.bmp 300 197 24 */  ……文件名,宽,高,位数
const uint8 Plane_565[] =
0x5f,0xd7,0x3f,0xd7,……16进制颜色数据
}

/* Clock.bmp 346 170 24 */
const uint8 Clock_565[] =
0x5f,0xd7,0x3f,0xd7,……16进制颜色数据
}

程序的主要代码,注释的很详细
/*------------------------------------------------------------------------------
                              DEFINE DEFINITION
------------------------------------------------------------------------------*/
#define SINGLETRANS 0             /* 标识单图转换 */
#define BATCHTRANS 1              /* 标识批量转换 */
#define FILEEND 1                 /* 读取结束标志 */

/*------------------------------------------------------------------------------
                              GLOBAL DEFINITION
------------------------------------------------------------------------------*/
int iBmpWidth;                    /* 输入的宽度,以像素为单位 */
int iBmpHeight;                   /* 输入的高度,以像素为单位 */
int iRealWidth;                   /* 存储字对齐后的宽度,以字节为单位 */
int iBitcounts;                   /* 用于存储图像位数 */
int iTransformtype;               /* 标识转换类型 */
int fileend = 0;                  /* 标识文件读取结束 */

CString lpszPathnamein;           /* 输入文件路径 */
CString lpszPathnameout;          /* 输出文件路径 */
char Filename[_MAX_FNAME];        /* 数据文件中指定的文件名 */
BYTE * DATAarray;                 /* 存储读入的图像数据 */
FILE * pfin;                      /* 指向数据流 */


/*------------------------------------------------------------------------------
Function: OnButtoninputClick

Description: 打开通用对话框,选择输入文件

Input: none

Output:

Return:
------------------------------------------------------------------------------*/
void CFileToBmpbatchDlg::OnButbrowsein()
{
    CString spszFilename;
    CFileDialog dlg(TRUE,"*.c",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,\
  "The C Files (*.c)|*.c|",NULL);
    if (dlg.DoModal() != IDOK)
    {
 //CommDlgExtendedError();
        return;
    }
    lpszPathnamein = dlg.GetPathName();
    spszFilename = dlg.GetFileName();

    /* 显示输入路径和文件名 */
    m_ctr_edit_inpath.SetWindowText(lpszPathnamein);

    /* 为输出路径添加默认路径和文件名 */
    lpszPathnameout = lpszPathnamein.Left(lpszPathnamein.GetLength() \
  - spszFilename.GetLength());
    m_ctr_edit_outpath.SetWindowText(lpszPathnameout);
}

/*------------------------------------------------------------------------------
Function: OnButtonoutputClick

Description: 打开浏览对话框,选择输出路径

Input: none

Output:

Return:
------------------------------------------------------------------------------*/
void CFileToBmpbatchDlg::OnButbrowseout()
{
    BROWSEINFO   bi;                     /* BROWSEINFO结构体 */  

    TCHAR   Buffer[MAX_PATH] = "";  
    TCHAR   FullPath[MAX_PATH] = "";  

    bi.hwndOwner = m_hWnd;               /* m_hWnd程序主窗口 */ 
    bi.pidlRoot = NULL;  
    bi.pszDisplayName = Buffer;          /* 返回选择的目录名的缓冲区 */ 
    bi.lpszTitle = "输出文件的保存位置"; /* 弹出的窗口的文字提示 */

    /* 只返回目录 */
    bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_EDITBOX | BIF_BROWSEFORCOMPUTER;  
    bi.lpfn = NULL;
    bi.lParam = 0;  
    bi.iImage = 0;  

    ITEMIDLIST *pidl = ::SHBrowseForFolder(&bi); /* 显示弹出窗口 */
    /* 在ITEMIDLIST中得到目录名的整个路径 */
    if (::SHGetPathFromIDList(pidl,FullPath))  
      
        m_ctr_edit_outpath.SetWindowText(FullPath);
        lpszPathnameout = FullPath;
    }
}

/*------------------------------------------------------------------------------
Function: OnButtontransformClick

Description: 执行文件的转换

Input: none

Output:

Return:
------------------------------------------------------------------------------*/
void CFileToBmpbatchDlg::OnOK()
{
    TCHAR CheckPath_in[MAX_PATH];    
    CString Outputmsg;

    /* 检查是否有输入路径 */
    if (!(m_ctr_edit_inpath.GetWindowText(CheckPath_in, sizeof(CheckPath_in))))
    {
        Outputmsg = "请选择数据文件!!!";
        MessageBox(Outputmsg, "警告", MB_OK);  
        return;  
    }

    if((pfin = fopen(lpszPathnamein, "rb")) == NULL)
    {
        MessageBox("读文件错!!!", "警告", MB_OK | MB_ICONERROR);
    }
    fseek(pfin, 2L, SEEK_CUR); /* 保证正确读取文件名等信息 */

    /* 单图的转换 */ 
    if (iTransformtype == SINGLETRANS)
    {
        Outputmsg = "已保存为图像文件!!!";

        Readtext();  /* 读文件 */
        SaveBmp(lpszPathnameout+Filename);
        delete [] DATAarray; /* 释放内存 */

        fclose(pfin);
       
        MessageBox(Outputmsg, "提示", MB_OK);
    }
    /* 批量的转换 */
    /* 实际上不用区分这两种转换形式,只用下面这段代码就可以了,写上为了表示清楚 */
    else if (iTransformtype == BATCHTRANS)
    {
        Outputmsg = "所有图像文件已存储!!!";

        /* 这里别指望feof(),永远也到不了文件结尾;也别指望fseek()能移出文件范围,
         * 鸟知道怎么回事,所有图像都转完之后Readtext()里面第一个被调用的fscanf
         * 由于不能正确读取就会返回-1,就用这个判断全部转换完毕
         */
        while (TRUE)
         
            Readtext();  /* 读文件 */
            if (fileend == FILEEND)
            {
                fileend = 0; /* 要记得恢复状态标志,否则批量转换就只能用一次 */
                break;
            }
            SaveBmp(lpszPathnameout+Filename);
            delete [] DATAarray; /* 释放内存 */            
        }

        MessageBox(Outputmsg, "提示", MB_OK);
        fclose(pfin);     
    }
}

/*------------------------------------------------------------------------------
Function: Readtext

Description: 将颜色数据从文件中读出,并转换成24位的颜色数据

Input: none

Output:

Return: DATAarray -指向存有颜色数据的数组

Remark: 这部分是C写的,MFC用的不是很熟,谁知道哪个类的方法可以以16进制形式
        从文本文件中读取数据,嘿嘿!。
------------------------------------------------------------------------------*/
void CFileToBmpbatchDlg::Readtext()
{
    WORD low, high, pixel;   /* 读入数据的低字节位、高字节位,pixel表示一个像素 */
    RGBTRIPLE rgb;           /* 用于存储转换好的24位RGB格式数据 */

    char flags;
    int ifscanfstate;        /* fscanf的返回值 */
    int row;                 /* 标识行数 */
    int line = 0;            /* 标识列数 */
    int k;

    ifscanfstate = fscanf(pfin, "%s %d %d %d", \
  Filename, &iBmpWidth, &iBmpHeight, &iBitcounts);
    /* 就是这里,图像全部转换完毕的标志 */
    if (ifscanfstate == -1)
    {
        fileend = FILEEND;
        return;
    }
  
    /* 确保一扫描行字节数为4的整数倍 */
    iRealWidth = (iBmpWidth * 3 + 3) / 4 * 4;
    k = iRealWidth - iBmpWidth * 3; /* 应该补0的个数 */
    row = iBmpHeight;
 
    /* 滤去数组名等字符部分,从第一个颜色数据开始读取 */
    while (true)
    {
        fscanf(pfin, "%c", &flags);
        if (flags == '{')
        {
            break;
        }
    }

    DATAarray = new BYTE[iRealWidth * iBmpHeight];
   
    while (row > 0)
    {
        fscanf(pfin, "%x,%x,", &low, &high);
       
        /* 数据文件中2个字节表示一个像素,且高位在后,低位在前
         * 此处将像素数据正确提取
         */
        high = high << 8;
        pixel = low | high;
  
        /* 将565格式位图数据扩展成888格式 */
        rgb.rgbtRed = (BYTE)((pixel & 0xF800) >> 8);
        rgb.rgbtGreen = (BYTE)((pixel & 0x07E0) >> 3);
        rgb.rgbtBlue = (BYTE)((pixel & 0x001F) << 3);
  
        /* 保证按正确顺序显示 */
  
        DATAarray[(row - 1) * iRealWidth + line] = rgb.rgbtBlue; 
        line++;
        DATAarray[(row - 1) * iRealWidth + line] = rgb.rgbtGreen; 
        line++;
        DATAarray[(row - 1) * iRealWidth + line] = rgb.rgbtRed; 
        line++;

        if (line == iBmpWidth * 3)
        {
            /* 扫描行的字节数不能被4整除时要补0对齐 */
            if (k != 0)
            
                for (; k > 0; k--)
                {
                    DATAarray[(row - 1) * iRealWidth + line] = 0x00;
                    line++;
                }
                k = iRealWidth - iBmpWidth * 3; /* 千万别忘了将k的值复原,否则
                                                 * 只有第一个扫描行尾加零,图像是斜的
                                                 * 或者将k赋初值的语句放在while内
                                                 * 就不用这一句了
                                                 */
             }
        }

        if (line >= iRealWidth)
        {
            line = 0;
            row--;
        
    }

    fseek(pfin, 7L, SEEK_CUR);/* 确保正确读取下一个图像的文件名、宽、高和位数 */
 
    return; 
}

/*------------------------------------------------------------------------------
Function: SaveBmp

Description: 利用颜色数组中的数据生成BMP图像

Input: CString filename-要保存的文件名

Output: BMP文件

Return: none
------------------------------------------------------------------------------*/
void CFileToBmpbatchDlg::SaveBmp(CString filename)
{
    FILE * pfout;

    BITMAPFILEHEADER bmfh;
    BITMAPINFOHEADER bmih;
   
    /* BITMAPFILEHEADER结构填写 */
    bmfh.bfType = 0x4d42;
    bmfh.bfOffBits = 54;
    bmfh.bfSize = bmfh.bfOffBits + iRealWidth * iBmpHeight; /* 文件的实际大小 */
    bmfh.bfReserved1 = 0;
    bmfh.bfReserved2 = 0;
 
    /* BITMAPINFOHEADER结构填写 */
    bmih.biSize = 40;
    bmih.biWidth = iBmpWidth;
    bmih.biHeight = iBmpHeight;
    bmih.biPlanes = 1;
    bmih.biBitCount = iBitcounts;
    bmih.biCompression = BI_RGB;
    bmih.biSizeImage = 0;
    bmih.biXPelsPerMeter = 0;
    bmih.biYPelsPerMeter = 0;
    bmih.biClrUsed = 0;
    bmih.biClrImportant = 0;

    if((pfout = fopen(filename, "wb")) == NULL)
    {
        MessageBox("写文件错!!!", "警告", MB_OK | MB_ICONERROR);
    }
   
    /* 写入头部和像素数据 */
    fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, pfout);
    fwrite(&bmih, sizeof(BITMAPINFOHEADER), 1, pfout);
    fwrite(DATAarray, iRealWidth * iBmpHeight, 1, pfout);

    fclose(pfout);
}

关于补0的问题:
已存在的图像,即使一个扫描行所占的字节数不能被4整除,它也是已经补过0的了。而本程序所读取的数据文件中不包含这些补充的零。所以,在保存颜色数据时候,如果需要补齐,必须补上,否则生成的文件是不正确的,尽管用ACDSee可以看到图像,但用XP的图片查看器是打不开的。

 

如果我的叙述存在问题,敬请指教,不胜感激!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值