/********************************************************************
Created: 2006/12/09 12:32
FileName: J.cpp
Author: Jar 包杰
Purpose: 将24位BMP二色图像文件压缩
Copyright By Jar 2006.12
*********************************************************************/
#include "stdafx.h"
#include "J.h"
// 声明串行化过程
IMPLEMENT_SERIAL(CJ, CObject, 0);
CJ::CJ()
{
JFileName = "";
m_pBMFH = NULL;
m_pBMIH = NULL;
m_pBits = NULL;
m_pJFH = NULL;
}
CJ::~CJ()
{
if (m_pBMFH != NULL)
{
delete m_pBMFH;
m_pBMFH = NULL;
}
if (m_pBMIH != NULL)
{
delete m_pBMIH;
m_pBMIH = NULL;
}
if(m_pBits != NULL)
{
m_pBits = NULL;
}
if(m_pJFH != NULL)
{
m_pJFH = NULL;
}
}
/*************************************************
Function: BMPRead
Description: 读取BMP图像
Input: CFile *pFile
Output:
Return: BOOL 成功返回TRUE,否则返回FALSE
Others: 读取BMP文件头、信息头和图像数据
创建J文件头
*************************************************/
BOOL CJ::BMPRead(CFile *pFile)
{
int nSize = sizeof(BITMAPFILEHEADER);
m_pBMFH = (LPBITMAPFILEHEADER) new BYTE[nSize];
//创建J文件头
nSize = sizeof(JFILEHEADER);
m_pJFH = (LPJFILEHEADER) new BYTE[nSize];
//读取文件头
pFile->Read(m_pBMFH, sizeof(BITMAPFILEHEADER));
// 判断是否是BMP格式的位图
if(m_pBMFH->bfType != BMP_HEADER_MARKER)
return FALSE;
nSize = sizeof(BITMAPINFOHEADER);
m_pBMIH = (LPBITMAPINFOHEADER) new BYTE[nSize];
//生成.J文件名
JFileName=pFile->GetFileName()+".j";
//读取信息头
pFile->Read(m_pBMIH, sizeof(BITMAPINFOHEADER));
//非24位图像打开失败
if (m_pBMIH->biBitCount != 24)
return FALSE;
//读取图象数据
m_pBits = (LPBYTE) new BYTE[m_pBMIH->biSizeImage];
pFile->Read(m_pBits, m_pBMIH->biSizeImage);
return TRUE;
}
/*************************************************
Function: JWrite
Description: 压缩BMP图像
Input: *pDC
Output:
Return: BOOL 成功返回TRUE,否则返回FALSE
Others: 第一次扫描将BMP图像转换成二值矩阵,只含'0''1'
第二次扫描,求跳变点的坐标差分值,写入文件
注意:差分值类型为WORD,最大为65536,故需要判断差分大小
但一般的图像不会造成这种情况
也可以通过二维求差分压缩法来解决,具体见论文
第三次扫描,显示图像
*************************************************/
BOOL CJ::JWrite(CDC *pDC)
{
int i = 0,j = 0,k = 0;
int nSize = m_pBMIH->biHeight * m_pBMIH->biWidth;
LPBYTE DivMatrix;
DivMatrix = new BYTE[nSize]; //二值矩阵
WORD FirstDis = 0; //定义第一次出现颜色跳变的偏移量
LPBYTE BitsH = m_pBits;
LPBYTE DivMatrixH = DivMatrix; //标记数据区开始,防止刷新时越界
CString s;
//写入.J文件头
m_pJFH->JType = J_HEADER_MARKER;
m_pJFH->JHeight = (WORD)m_pBMIH->biHeight;
m_pJFH->JWidth = (WORD)m_pBMIH->biWidth;
for (i = 0;i < 3;i++) //读取第一种颜色值
m_pJFH->FirstColor[i] = *(m_pBits+2-i);
//第一次扫描,转换成二值矩阵
for (i = 0;i < m_pBMIH->biHeight;i++)
{
for (j = 0;j < m_pBMIH->biWidth;j++)
{
BYTE tmpColor[3]; //临时存放颜色量
for (k = 0;k < 3;k++)
tmpColor[k] = *m_pBits++;
if ((tmpColor[0] != m_pJFH->FirstColor[2])
||(tmpColor[1] != m_pJFH->FirstColor[1])
||(tmpColor[2] != m_pJFH->FirstColor[0]))
{
for (k = 0;k m_pJFH->OpposeColor[k] = tmpColor[2-k];
*DivMatrix++ = 1;
}
else *DivMatrix++ = 0;
}
m_pBits = m_pBits + m_pBMIH->biWidth%4;
}
m_pBits = BitsH;
DivMatrix = DivMatrixH; //指针复位
//记录第一次颜色跳变的位置
do{
FirstDis++;
DivMatrix++;
}while (*DivMatrix != *(DivMatrix-1));
//创建文件,写入文件头信息
CFile JFile;
JFile.Open(JFileName,CFile::modeCreate|CFile::modeReadWrite);
JFile.Write(m_pJFH,sizeof(JFILEHEADER));
JFile.Write(&FirstDis,sizeof(WORD));
pDC->TextOut(0,0,"Completed ");
WORD tmpDis = FirstDis; //临时存放跳变点之间距离
BYTE tmpDivMatrix; //临时存放二值矩阵
//第二次扫描,记录跳变位置的差值,写入文件
for (i = FirstDis;i < nSize;i++)
{
tmpDivMatrix = *DivMatrix++;
if (*DivMatrix != tmpDivMatrix)
{
WORD Dis = i - tmpDis;
JFile.Write(&Dis,sizeof(WORD));
tmpDis = i;
}
s.Format("%d %%",i*100/nSize); //显示进度
pDC->TextOut(75,0,s);
}
JFile.Close();
//第三次扫描,显示图像
s.Format("Compressed to %s",JFileName);
pDC->TextOut(0,0,s);
s.Format("Height = %d pix",m_pJFH->JHeight);
pDC->TextOut(0,20,s);
s.Format("Width = %d pix",m_pJFH->JWidth);
pDC->TextOut(0,40,s);
s.Format("FirstColor = RGB(%d,%d,%d)",m_pJFH->FirstColor[0],m_pJFH->FirstColor[1],m_pJFH->FirstColor[2]);
pDC->TextOut(0,60,s);
s.Format("SecondColor = RGB(%d,%d,%d)",m_pJFH->OpposeColor[0],m_pJFH->OpposeColor[1],m_pJFH->OpposeColor[2]);
pDC->TextOut(0,80,s);
for (i = 0;i < m_pBMIH->biHeight;i++)
{
for (j = 0;j < m_pBMIH->biWidth;j++)
{
BYTE b = *m_pBits++;
BYTE g = *m_pBits++;
BYTE r = *m_pBits++;
pDC->SetPixel(j,m_pBMIH->biHeight-i+100,RGB(r,g,b));
}
m_pBits = m_pBits + m_pBMIH->biWidth%4;
}
m_pBits = BitsH; //指针复位
return TRUE;
}
//串行化
void CJ::Serialize(CArchive &ar)
{
BMPRead(ar.GetFile());
}
//获取文件头指针
LPJFILEHEADER CJ::GetJFH()
{
return m_pJFH;
}