⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 复件 jpegdoc.cpp

📁 图象压缩算法的实现,十分具有参考价值的,赫赫有名
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	{
		file.Write(quant1,5);
		file.Write(ChrQuantTable,64);
		file.Write(ColorFrame,19);							//写帧开始(SOF)的标识符
	}
	else if(m_bit24==0)
	{
		file.Write(GreyFrame,13);
	}
	file.Write(LumDchuffman,5);file.Write(LumDCHuffmanBit+1,16);/*从DCHuffmanBit数组的第二位开始写*/file.Write(LumDCHuffmanVal,12);
	file.Write(LumAchuffman,5);file.Write(LumACHuffmanBit+1,16);/*从ACHuffmanBit数组的第二位开始写*/file.Write(LumACHuffmanVal,162);
	if(m_bit24==1)
	{
		file.Write(ChrDchuffman,5);file.Write(ChrDCHuffmanBit+1,16);/*从DCHuffmanBit数组的第二位开始写*/file.Write(ChrDCHuffmanVal,12);
		file.Write(ChrAchuffman,5);file.Write(ChrACHuffmanBit+1,16);/*从ACHuffmanBit数组的第二位开始写*/file.Write(ChrACHuffmanVal,162);
	}
	if(m_bit24==1)
	{
		file.Write(ColorSos,14);						//写真彩色图像SOS标记符
	}
	else if(m_bit24==0)
	{
		file.Write(GreySos,10);							//写灰度图像SOS标记符
	}
	WriteHuffmanData();									//开始向JPEG文件中写入数据
	WriteSurplus();
	WaitCursorEnd();									//结束等待光标

	file.Write(eoi,2);									//写JPEG文件结束标识符
	file.Close();
	AfxMessageBox("BMP文件已成功压缩成JPEG文件!!!");
	return(TRUE);
}

//////////////////////////////////////////////////////
//
//
//
//////////////////////////////////////////////////////
BOOL CDib::Draw(CDC *pDC,int nX,int nY)
{
//	如果没有数据,不能显示
	if(m_pDib==NULL)
		return(FALSE);
//	得用StretchDIBits绘制位图
/*	函数原型为:
	int StretchDIBits
		(	HDC hdc,						//设备上下文的句柄
			int XDest,int YDest,			//目标矩形的左上角X和Y坐标值
			int nDestWidth,int nDestHeight,	//目标矩形的宽度和高度
			int XSrc,int YSrc,				//源矩形的左上角X和Y坐标值
			int nSrcWidth,int nSrcHeight,	//源矩形的宽度和高度
			CONST VOID *lpBits,				//address of bitmap bits
			CONST BITMAPINFO *lpBitsInfo,	//指向BITMAPINFO结构的指针
			UNIT iUsage,					//使用标志,用于指明颜色是采用RGB还是调色板的索引值
			DWORD dwRop);					//指定图像操作代码
最后一个参数dwRop有以下一些常用的代码:
BLACKNESS		输出黑色
DSTINVERT		反转目的位图
MERGECOPY		用与操作把图案(Pattern)与源位图融合起来
MERGEPAINT		用或操作把反转的源位图与目的位图融合起来
NOTSRCCOPY		把源位图反转然后拷贝目的地
NOTSRCERASE		用或操作融合源和目的位图,然后再反转
PATCOPY			把图案拷贝到目的位图中
PATINVERT		用异或操作把图案与目的位图相融合
PATPAINT		用或操作融合图案和反转的源位图,然后用或操作把结果与目的位图融合
SRCAND			用与操作融合源位图和目的位图
SRCCOPY			把源位图拷贝到目的位图
SRCERASE		先反转目的位图,再用与操作将其源位图融合
SRCINVERT		用异或操作融合源位图和目的位图
SRCPAINT		用或操作融合源位图和目的位图
WHITENESS		输出白色
	
*/
	StretchDIBits(pDC->m_hDC,nX,nY,m_pBIH->biWidth,m_pBIH->biHeight,0,0,
		m_pBIH->biWidth,m_pBIH->biHeight,m_pDibBits,
		(BITMAPINFO *)m_pBIH,BI_RGB,SRCCOPY);
	return(TRUE);
}

///////////////////////////////////////////////////////
//
//
//
///////////////////////////////////////////////////////
BOOL CDib::SetPalette(CDC *pDC)
{
//	如果没有数据,不能设置调色板
	if(m_pDib==NULL)
		return(FALSE);
//	检查是不有调色板句柄,大于8位的位图其句柄为NULL
	if(m_Palette.GetSafeHandle()==NULL)
		return(TRUE);
//	选择并实现调色板
	CPalette *pOldPalette;
	pOldPalette=pDC->SelectPalette(&m_Palette,FALSE);
	pDC->RealizePalette();
	pDC->SelectPalette(pOldPalette,FALSE);
	return(TRUE);
}

void CDib::Show(CDC *pDC,int nX,int nY)
{
/*SetDIBitsToDevice的函数据原型
	int SetDIBitsToDevice(
		HDC hdc,						//设备上下文的句柄
		int XDest,int YDest,			//目标矩形的左上角X和Y坐标
		DWORD dwWidth,DWORD dwHeight,	//源矩形的宽度和高度
		int XSrc,int YSrc,				//源矩形的左下角的X和Y坐标
		UINT uStartScan,				//矩阵中的第一个扫描线
		UINT cScanLines,				//扫描线的数目
		CONST VOID *lpvBits,			//指向DIB颜色数据的指针
		CONST BITMAPINFO *lpbmi,		//指向BITMAPINFO结构的指针
		UINT fuColorUse);				//用于指明颜色是用用RGB还是调色板的索引值
*/
//	CWnd test;
//	CRect cr;
//	test.GetClientRect(cr);
//	int xx=cr.right/2;//,yy=cr.bottom/2;
	for(LONG y=0;y<height;y++)
		SetDIBitsToDevice(pDC->GetSafeHdc(),nX,nY+y,width,
		1,0,0,0,1,data[y],(BITMAPINFO *)m_pBIH,DIB_RGB_COLORS);
}

/*************************************************************************
 *  函数名称:* FFT()
 *  参数:
 *  COMPLEX * TD	- 指向时域数组的指针
 *  COMPLEX * FD	- 指向频域数组的指针
 *  r				-2的幂数,即迭代次数
 *  返回值:   无
 *  说  明:   该函数用来实现快速付立叶变换。
 ************************************************************************/
void CDib::FFT(COMPLEX * TD,COMPLEX * FD,int r)
{
	LONG count;					// 付立叶变换点数
	int i,j,k;					// 循环变量
	int bfsize,p;				// 中间变量
	double angle;				// 角度
	COMPLEX *W,*X1,*X2,*X;
	count=1<<r;					// 计算付立叶变换点数
//  分配运算所需存储器
	W=new COMPLEX[count/2];
	X1=new COMPLEX[count];
	X2=new COMPLEX[count];

	for(i=0;i<count/2;i++)		// 计算加权系数
	{
		angle=-i*PI*2/count;
		W[i].re=cos(angle);
		W[i].im=sin(angle);
	}
	memcpy(X1,TD,sizeof(COMPLEX)*count);	// 将时域点写入X1
// 采用蝶形算法进行快速付立叶变换
	for(k=0;k<r;k++)
	{
		for(j=0;j<1<<k;j++)
		{
			bfsize=1<<(r-k);
			for(i=0;i<bfsize/2;i++)
			{
				p=j*bfsize;
				X2[i+p].re=X1[i+p].re+X1[i+p+bfsize/2].re;
				X2[i+p].im=X1[i+p].im+X1[i+p+bfsize/2].im;
				X2[i+p+bfsize/2].re=(X1[i+p].re-X1[i+p+bfsize/2].re)*W[i*(1<<k)].re-(X1[i+p].im-X1[i+p+bfsize/2].im)*W[i*(1<<k)].im;
				X2[i+p+bfsize/2].im=(X1[i+p].im-X1[i+p+bfsize/2].im)*W[i*(1<<k)].re+(X1[i+p].re-X1[i+p+bfsize/2].re)*W[i*(1<<k)].im;
			}
		}
		X=X1;
		X1=X2;
		X2=X;
	}
//  重新排序
	for(j=0;j<count;j++)		
	{
		p=0;
		for(i=0;i<r;i++)
		{
			if(j&(1<<i))
				p+=1<<(r-i-1);
		}
		FD[j]=X1[p];
	}
//  释放内存
	delete W;
	delete X1;
	delete X2;
}

/*************************************************************************
 * 函数名称:   Pre_DCT()
 * 参数:
 * double * f	- 指向时域值的指针
 * double * F	- 指向频域值的指针
 * r			-2的幂数
 * 返回值:		无
 * 说明: 该函数用来实现快速离散余弦变换。该函数利用2N点的快速付立叶变换,
 *		 来实现离散余弦变换。
 ************************************************************************/
void CDib::Pre_DCT(double *f,double *F,int r)
{
	LONG count;								// 离散余弦变换点数
	int i;									// 循环变量
	double dTemp;							// 中间变量
	COMPLEX *X;
	count=1<<r;								// 计算离散余弦变换点数
	X=new COMPLEX[count*2];					// 分配内存
	memset(X,0,sizeof(COMPLEX)*count*2);	//对X预赋值为0
	for(i=0;i<count;i++)					// 将时域点写入数组X
	{
		X[i].re=f[i];
		X[i].im=0;
	}
	FFT(X,X,r+1);							// 调用快速付立叶变换
	dTemp=1/sqrt(count);					// 调整系数
	F[0]=X[0].re*dTemp;						//求F[0],即直流DC的DCT系数值
	dTemp*=sqrt(2);
	for(i=1;i<count;i++)					// 求F[u],即交流AC的DCT系数值
	{
		F[i]=(X[i].re*cos(i*PI/(count*2))+X[i].im*sin(i*PI/(count*2)))*dTemp;
	}
	delete X;								// 释放内存
}

///////////////////////////////////////////////////////
//
//	对8*8的图像块进行DCT变换,量化之后进行Z型扫描
//
///////////////////////////////////////////////////////
BOOL CDib::DCT(double *x,int n,unsigned char *QuantTable)
{	
	double *light=new double[64];
	double *Light=new double[64];
//	double *light,*Light;
	int i,j;
	for(i=0;i<n;i++)
		light[i]=x[i];
	for(i=0;i<8;i++)
		Pre_DCT(&light[8*i],&Light[8*i],3);	//对行进行DCT变换
	for(i=0;i<8;i++)
	{
		for(j=0;j<8;j++)
			light[j*8+i]=Light[j+8*i];		//把已进行行变换的值赋给light数组,准备列变换
	}
	for(j=0;j<8;j++)
	{
		Pre_DCT(&light[j*8],&Light[j*8],3);	//对列进行DCT变换
	}
///把Light[]矩阵进行转置//////////////
	double aaa[64];
	for(i=0;i<8;i++)
	{
		for(j=0;j<8;j++)
			aaa[i*8+j]=Light[i+j*8];
	}
//	对DCT系数进行量化,此处可调整量化矩阵,以调整JPEG文件的压缩比//
	int quant_val[64];
	for(i=0;i<64;i++)
	{
		if(aaa[i]>=0)
			quant_val[i]=(int)(aaa[i]/QuantTable[i]+0.5);
		else
			quant_val[i]=(int)(aaa[i]/QuantTable[i]-0.5);
	}
//	对量化矩阵进行Z型扫描
	for(i=0;i<64;i++)
		table[zig[i]]=quant_val[i];
	delete light;
	delete Light;
////////////////////////////////
	return TRUE;
}

//////////////////////////////////////////////////////
//
//						游程编码子程序
//
//////////////////////////////////////////////////////
int CDib::RLEProg()
{
//	C_RLE  RLE[64];
///////初始化RLE编码数组///////////
	for(int i=0;i<64;i++)
	{
		RLE[i].zero_num=0;
		RLE[i].digit=0;
	}
///////开始RLE编码////////////////
	int j=0;				//零的个数
	int	k=0;				//8*8的数据块的游程长度
	int temp;				//由temp判断EOB的位置
	for(i=1;i<64;i++)		//去除Z型扫描之后的第一个元素,即DC的值
	{
		if(table[i]!=0)
			temp=i;			//此循环判断从哪一个元素开始以后的元素全为零
	}
	for(i=1;i<=temp;i++)
	{	
		if(table[i]==0)
		{
			if(j<16)		
				j++;
			else
			{
				RLE[k].zero_num=j-1;	//当连续零的个数为16时,存为(15,0)。此时j=16,因此要减去1
				RLE[k].digit=0;
				j=0;
				k++;
			}
		}
		else
		{	
			RLE[k].zero_num=j;
			RLE[k].digit=table[i];
			j=0;
			k++;
		}		
	}
	if(temp!=63)			//当游程数为63时,不能写结束标识符EOB,即(0,0)。temp=63说明最后一位不是零,而是非零数。
	{
		RLE[k].zero_num=0;
		RLE[k].digit=0;		//写RLE编码的结束标志EOB,即(0,0)
		k++;				//k为RLE的总个数
	}
	return k;				//K为游程的长度
}

////////////////////////////////////////////////////////////
//    此函数可得到哈夫曼码表和码长
//    val为JPEG文件中存储的哈夫曼码表
//    bit为JPEG文件中存储的哈夫曼码表长度
//    由这两个参数可得到实际使用的不等长的哈夫曼码表
//    此处使用的是固定的哈夫曼码
////////////////////////////////////////////////////////////
//	此处代码是参考的书上的程序流程图
BOOL CDib::HuffmanTable(unsigned char *bit,unsigned char*val)
{
	int k=0,i=1,j=1;
	int lastk;
	char huffsize[162];
/////////////////////////////
	int code=0,si,p;
	int huffcode[162];
/////////////////////////////
//	int ehufco[251],ehufsi[251];
	while(i<=16)			//
	{
		while(j<=bit[i])
		{
			huffsize[k]=i;
			k=k+1;
			j=j+1;
		}		
		i=i+1;
		j=1;
	}
	huffsize[k]=0;
	lastk=k;

	p=0;
	code=0;
	si=huffsize[0];

	while(huffsize[p])
	{
		while(((int)huffsize[p])==si)
		{
			huffcode[p]=code;
			p++;
			code++;
		}	
		code<<=1;
		si++;
	}
	for(p=0;p<lastk;p++)
	{
		ehufco[val[p]]=huffcode[p];		//ehufco是哈夫曼的码表
		ehufsi[val[p]]=huffsize[p];		//ehufsi是哈夫曼的码表长度
	}
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
//
//此函数功能是把一幅图像经DCT,量化之后的数据由哈夫曼编码后依次存入文件
//
//////////////////////////////////////////////////////////////////////

BOOL CDib::WriteHuffmanData()
{
	LONG r_width,r_height;
	int i,j;
	if(m_bit24==1)
	{
		if(width%16==0)
			r_width=width;
		else
			r_width=width+16-width%16;
		if(height%16==0)
			r_height=height;
		else
			r_height=height+16-height%16;
	}
	else if(m_bit24==0)
	{
		if(width%8==0)
			r_width=width;
		else
			r_width=width+8-width%8;
		if(height%8==0)
			r_height=height;
		else

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -