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

📄 jpegdoc.cpp

📁 图象压缩算法的实现,十分具有参考价值的,赫赫有名
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	/////////////////////////////////////////////////////////////////////////////////////
	int LumDChufco[12],LumDChufsi[12];			//存储DC数据的哈夫曼码表和码长,四个字节
	int LumAChufco[251],LumAChufsi[251];		//存储AC数据的哈夫曼码表和码长,四个字节
	int ChrDChufco[12],ChrDChufsi[12];
	int ChrAChufco[251],ChrAChufsi[251];
	//*******************************
	HuffmanTable(LumDCHuffmanBit,LumDCHuffmanVal);//得到亮度DC的HUFFMAN的码表和码长
	for(i=0;i<12;i++)
	{
		LumDChufco[i]=ehufco[i];				//DChufco是亮度哈夫曼的码表
		LumDChufsi[i]=ehufsi[i];				//DChufsi是亮度哈夫曼的码长
	}
	//********************************
	HuffmanTable(LumACHuffmanBit,LumACHuffmanVal);//得到亮度AC的HUFFMAN的码表和码长
	for(i=0;i<251;i++)							//实际上用不完252个数,中间一些数没有用
	{
		LumAChufco[i]=ehufco[i];				//AChufco是亮度哈夫曼的码表
		LumAChufsi[i]=ehufsi[i];				//AChufsi是亮度哈夫曼的码长
	}
	//*******************************
	HuffmanTable(ChrDCHuffmanBit,ChrDCHuffmanVal);//得到色度DC的HUFFMAN的码表和码长
	for(i=0;i<12;i++)
	{
		ChrDChufco[i]=ehufco[i];				//DChufco是色度哈夫曼的码表
		ChrDChufsi[i]=ehufsi[i];				//DChufsi是色度哈夫曼的码长
	}
	//******************************
	HuffmanTable(ChrACHuffmanBit,ChrACHuffmanVal);//得到色度AC的HUFFMAN的码表和码长
	for(i=0;i<251;i++)
	{
		ChrAChufco[i]=ehufco[i];				//AChufco是色度哈夫曼的码表
		ChrAChufsi[i]=ehufsi[i];				//AChufsi是色度哈夫曼的码长
	}
	///////////////////////////////////////////////////////////////////////////
	double xx[64];
	int ii,jj;
	int LumPreDC=0,CrPreDC=0,CbPreDC=0;
	if(m_bit24==1)
	{
		char *Cr[800],*Cb[800],*Y[1600];//改用指针数组可以定义大的二维数组,可以克服上面的问题
		for(i=0;i<800;i++)
		{
			Cr[i]=new char[width>>1];	//记得清除内存
			Cb[i]=new char[width>>1];
		}
		for(i=0;i<1600;i++)
		{
			Y[i]=new char[width];
		}
		for(j=0;j<height;j++)
			for(i=0;i<width;i++)		//考虑用其它方法初始化,减少时间
			{
				Y[j][i]=0;
				Cr[j>>1][i>>1]=0;
				Cb[j>>1][i>>1]=0;
			}
		for(j=0;j<height;j++)
			for(i=0;i<width;i++)
			{
				Y[j][i]=(int)(0.114*data[j][i].Blue+0.587*data[j][i].Green+0.299*data[j][i].Red)-128;
			}	//使RGB值转换成亮度值,并减去128
		for(j=0;j<(height>>1);j++)			//height/2
			for(i=0;i<(width>>1);i++)		//width/2
			{
				Cr[j][i]=(int)(-0.0813*data[j<<1][i<<1].Blue-0.4187*data[j<<1][i<<1].Green+0.5*data[j<<1][i<<1].Red);
				Cb[j][i]=(int)(0.5*data[j<<1][i<<1].Blue-0.3313*data[j<<1][i<<1].Green-0.1687*data[j<<1][i<<1].Red);
			}
					
					
		for(ii=0;ii<(r_height>>4);ii++)		//r_height/16
			for(jj=0;jj<(r_width>>4);jj++)	//r_width/16
			{
		/////////       00             ///////////////////////
				for(i=0;i<8;i++)
					for(j=0;j<8;j++)
					{
						xx[(i<<3)+j]=Y[(ii<<4)+i][(jj<<4)+j];
					}
				DCT(xx,64,LumQuantTable);
				LumPreDC=WriteData(LumPreDC,LumDChufco,LumDChufsi,LumAChufco,LumAChufsi);
		/////////      01           ////////////////////////////
				for(i=0;i<8;i++)
					for(j=0;j<8;j++)
					{	
						xx[(i<<3)+j]=Y[(ii<<4)+i][(jj<<4)+8+j];
					}
				DCT(xx,64,LumQuantTable);
				LumPreDC=WriteData(LumPreDC,LumDChufco,LumDChufsi,LumAChufco,LumAChufsi);
		///////////    10           /////////////////////////////
				for(i=0;i<8;i++)
					for(j=0;j<8;j++)
					{	
						xx[(i<<3)+j]=Y[(ii<<4)+8+i][(jj<<4)+j];
					}
				DCT(xx,64,LumQuantTable);
				LumPreDC=WriteData(LumPreDC,LumDChufco,LumDChufsi,LumAChufco,LumAChufsi);
		/////////      11            /////////////////////////////
				for(i=0;i<8;i++)
					for(j=0;j<8;j++)
					{
						xx[(i<<3)+j]=Y[(ii<<4)+8+i][(jj<<4)+8+j];
					}
				DCT(xx,64,LumQuantTable);
				LumPreDC=WriteData(LumPreDC,LumDChufco,LumDChufsi,LumAChufco,LumAChufsi);
									
		//////////////////////     先蓝色后红色      ///////////////////////////////////////
				for(i=0;i<8;i++)
					for(j=0;j<8;j++)
					{
						xx[(i<<3)+j]=Cb[(ii<<3)+i][(jj<<3)+j];			//蓝色色差
					}
				DCT(xx,64,ChrQuantTable);
				CbPreDC=WriteData(CbPreDC,ChrDChufco,ChrDChufsi,ChrAChufco,ChrAChufsi);
										
												
				for(i=0;i<8;i++)
					for(j=0;j<8;j++)
					{
						xx[(i<<3)+j]=Cr[(ii<<3)+i][(jj<<3)+j];			//红色色差
					}
				DCT(xx,64,ChrQuantTable);
				CrPreDC=WriteData(CrPreDC,ChrDChufco,ChrDChufsi,ChrAChufco,ChrAChufsi);
			}
		for(i=0;i<800;i++)
		{
			delete [] Cr[i];
			delete [] Cb[i];
		}
		for(i=0;i<1600;i++)
		{
			delete [] Y[i];
		}
	}
	/////////////////////////////////////////////////////////////////////
	else if(m_bit24==0)			//灰度图像
	{
		for(ii=0;ii<(r_height>>3);ii++)
		{
			for(jj=0;jj<(r_width>>3);jj++)	
			{
				for(i=0;i<8;i++)
				{
					for(j=0;j<8;j++)
						xx[(i<<3)+j]=hdata[(ii<<3)+i][(jj<<3)+j]-128;	//灰度值减去128
				}
				DCT(xx,64,LumQuantTable);
				LumPreDC=WriteData(LumPreDC,LumDChufco,LumDChufsi,LumAChufco,LumAChufsi);
			}
		}
	}
	return TRUE;
}

////////////////////////////////////////////////////////////////////////////
//扩展为8的倍数的图像宽度和高度,不足的位全用零补齐,
//在定义数组用以存储BMP图像时,已对数组初始化为零,
//只支持高度小于等于1600的图像
////////////////////////////////////////////////////////////////
int CDib::WriteData(int preDC,int *DChufco,int *DChufsi,int *AChufco,int *AChufsi)
{

	int abs1;
	int i,j;
	unsigned char zero_num,power_num;		//8bit
	int digit,digitcode;					//32bit
	unsigned char huffmanval;				//8bit
//	int ii,jj;
	int power_dc;							//DC值的数据长度位数
	int dc_huffmancode,dc_huffmanbitnum;
	int nowDC;								//第一个DC值预先设为0,nowDC为实际编码所用的DC值
	int RLE_length;							//游程长度
	int ac_huffmancode,ac_huffmanbitnum;	//32bit

/////////////////////////////////////////////////////////////
////////////////		对DC分量进行编码		/////////////
/////////////////////////////////////////////////////////////
	nowDC=table[0]-preDC;			//对DC进行差分运算,初始值为0(即DC[0]=0)
	preDC=table[0];					//保留原DC的DCT值,以便下一步使用
	if(nowDC!=0)
	{
		for(i=0;i<16;i++)
		{	
			if(abs(nowDC)<pow(2,i+1)&&abs(nowDC)>=pow(2,i))		//计算nowDC的二进制位数(即分组值),i即为它的位数
				power_dc=i+1;
		}
	}
	else
	{	
		power_dc=0;									//DC值为零时分组为零
	}
	if(nowDC>0)										//对直流分量编码
	{
		dc_huffmancode=DChufco[power_dc];
		dc_huffmanbitnum=DChufsi[power_dc];
		ShiftWrite(dc_huffmanbitnum,dc_huffmancode);
		ShiftWrite(power_dc,nowDC);
	}
	else if(nowDC<0)								//
	{
		dc_huffmancode=DChufco[power_dc];
		dc_huffmanbitnum=DChufsi[power_dc];
		ShiftWrite(dc_huffmanbitnum,dc_huffmancode);//
		abs1=((int)pow(2,power_dc)-1)-abs(nowDC);	//DC为负,求绝对值后取其反码
		ShiftWrite(power_dc,abs1);					//由DC值的位长和码串决定如何移入数据缓冲区并写入文件
	}
	else
	{
		ShiftWrite(2,0);							//当nowDC=0时,其huffman码串为00,两位长,移入数据缓冲区
	}
	///////////////////////////////////////////////////
	////              对AC分量进行编码			///////
	///////////////////////////////////////////////////
	RLE_length=RLEProg();			//游程编码,返回值为游程的个数
	int digitTemp;
	
	for(i=0;i<RLE_length;i++)
	{
		zero_num=RLE[i].zero_num;	//得到第i个游程的零的个数
		digit=RLE[i].digit;			//得到第i个游程的数值
		//**///////////////////////////////////////////////////
		if(digit<0)
			digitTemp=abs(digit);
		else
			digitTemp=digit;		//可把这四句用abs()函数加到下面的的if语句中
		/////////....................................
		if(digit!=0)
		{
			for(j=0;j<=16;j++)   
			{
				if(digitTemp<pow(2,j+1)&&digitTemp>=pow(2,j))	//pow(2,j)为求2的J次幂,此处判断digit是哪一组的数
					power_num=j+1;								//最小为1,即最小分组为1
			}
		}
		else									//当digit=0,分组为0
		{
			power_num=0;
		}
		/////////....................................
		if(digit<0)
		{
			digitcode=(int)(pow(2,power_num)-1)-abs(digit);		//有效位取反码,使有效位以外的位为0
		}
		else 
		{
			digitcode=digit;
		}
		//**//////////////////////////////////////////////////
		huffmanval=(zero_num<<4)|power_num;		//使零的个数与该游程值所在的分组合为一个字节,以便用哈夫曼码表
		ac_huffmancode=AChufco[huffmanval];		//得到哈夫曼码表
		ac_huffmanbitnum=AChufsi[huffmanval];	//得到哈夫曼码表的位长度
		ShiftWrite(ac_huffmanbitnum,ac_huffmancode);
		if(digit!=0 || zero_num!=0)				//当是EOI(End of Image)时,不写数字位的0,否则要写数字位的0
		{
			ShiftWrite(power_num,digitcode);	//游程不为(0,0)时,写入数据
		}
	}
	return preDC;
}
	
	
////////////////  写最后数据缓冲区中已移到高位的码串,使其凑成整字节,不足字节位时后加1  ////////////
BOOL CDib::WriteSurplus()
{
	unsigned char spare[4];
	EncodeJpeg=EncodeJpeg|((int)pow(2,surplus)-1);	//使数据缓冲区中有效位以外的所有位为1
	if(surplus<32&&surplus>=24)						//剩余位大于等于24,只写一个字节到JPEG文件
	{
		spare[0]=(EncodeJpeg&0xff000000)>>24;
		file.Write(spare,1);
	}
	else if(surplus<24&&surplus>=16)				//剩余位大于等于16而小于24,写2个字节
	{
		spare[0]=(EncodeJpeg&0xff000000)>>24;
		spare[1]=(EncodeJpeg&0xff0000)>>16;
		file.Write(spare,2);
	}
	else if(surplus<16&&surplus>=8)					//剩余位大于等于8而小于16,写3个字节
	{
		spare[0]=(EncodeJpeg&0xff000000)>>24;
		spare[1]=(EncodeJpeg&0xff0000)>>16;
		spare[2]=(EncodeJpeg&0xff00)>>8;
		file.Write(spare,3);
	}
	else											//剩余位小于8,写4个字节
	{
		spare[0]=(EncodeJpeg&0xff000000)>>24;
		spare[1]=(EncodeJpeg&0xff0000)>>16;
		spare[2]=(EncodeJpeg&0xff00)>>8;
		spare[3]=EncodeJpeg&0xff;
		file.Write(spare,4);
	}
	EncodeJpeg=surplus=0;
////////////////////////////////////////////////////
	return TRUE;
}

////////////////////////////////////////////////////
//
//  把一个四字节的数由高字节到低字节的顺序写入文件
//
////////////////////////////////////////////////////
void CDib::Write32bit()
{
	unsigned char buf[4],insert=0x00;
	int i;
	buf[0]=(EncodeJpeg&0xff000000)>>24;		//把32位的JPEG编码整数由高位到低位存入buf数组中
	buf[1]=(EncodeJpeg&0xff0000)>>16;		//以便由高位到低位写入JPEG文件中,因直接写入,
	buf[2]=(EncodeJpeg&0xff00)>>8;			//将由低位到高位写入文件。
	buf[3]=EncodeJpeg&0xff;
	for(i=0;i<4;i++)						//EncodeJpeg的32位已满,写入文件
	{
		file.Write(buf+i,1);
		if(buf[i]==0xff)					//如果某一字节为0xFF,则需插入一个数0x00
			file.Write(&insert,1);			//已定义insert为0x00
	}
}

/////////////////////////////////////////////////
//
//
//
////////////////////////////////////////////////
void CDib::ShiftWrite(int huffmanbitnum,int huffmancode)
{
	int i,j,k;
	if(huffmanbitnum<surplus)				//需要编码的码串比数据缓冲区剩余的位少,可直接移入,不写入JPEG文件
	{
		EncodeJpeg=EncodeJpeg|(huffmancode<<(surplus-huffmanbitnum));//需要编码的码串移入数据缓冲区
		surplus=surplus-huffmanbitnum;		//当前数据缓冲区剩余的位数
	}
	else//需要编码的码串比数据缓冲区剩余的位多,截断码串分两次移入数据缓冲区,使EncodeJpeg=32之后写入文件
	{	
		i=huffmanbitnum-surplus;			//截断码串后第二次移入数据缓冲区的位长
		j=(int)pow(2,surplus)-1;			//得到从低位到高位surplus个1,即(000111...11)
		EncodeJpeg=EncodeJpeg|((huffmancode&(j<<i))>>i);
		Write32bit();						//32位数据缓冲区填满后写入JPEG文件
		EncodeJpeg=0;						//数据缓冲区清零
		k=(int)pow(2,i)-1;					//
		EncodeJpeg=(huffmancode&k)<<(32-i);	//使被截断后剩余的码串移到32位数据缓冲区的高位
		surplus=32-i;						//目前数据缓冲区剩余的位数
	}
}


BOOL CDib::ShangInvert()
{
	long x,y;
	if(m_bit24==1)
	{
	RGBData Tempdata;
	for(y=0;y<height/2;y++)
		for(x=0;x<width;x++)
		{
			Tempdata=data[y][x];
			data[y][x]=data[height-1-y][x];
			data[height-1-y][x]=Tempdata;
		}
	}
	else
	{
	BYTE temp;
	for(y=0;y<height/2;y++)
		for(x=0;x<width;x++)
		{
			temp=hdata[y][x];
			hdata[y][x]=hdata[height-1-y][x];
			hdata[height-1-y][x]=temp;
		}
	}
	return TRUE;
}

BOOL CDib::ZheInvert()
{
	long x,y;
	if(m_bit24==1)
	{
	RGBData Tempdata;
	for(y=0;y<height;y++)
		for(x=0;x<width/2;x++)
		{
			Tempdata=data[y][x];
			data[y][x]=data[y][width-1-x];
			data[y][width-1-x]=Tempdata;
		}
	}
	else if(m_bit24==0)
	{
	BYTE temp;
	for(y=0;y<height;y++)
		for(x=0;x<width/2;x++)
		{
			temp=hdata[y][x];
			hdata[y][x]=hdata[y][width-1-x];
			hdata[y][width-1-x]=temp;
		}
	}
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CJPEGDoc diagnostics

#ifdef _DEBUG
void CJPEGDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CJPEGDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CJPEGDoc commands

⌨️ 快捷键说明

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