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

📄 jpegdoc.cpp

📁 图象压缩算法的实现,十分具有参考价值的,赫赫有名
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	time( &tBegin );	
	if(!file.Open(pszFilename,CFile::modeCreate|CFile::modeWrite))
		return(FALSE);
	unsigned short int filehead=0xd8ff;					//JPEG标识符FFD8(16bit)
	unsigned char app0[18]={0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46,0x00,0x01,0x01,0x00,0x00,0x01,0x00,0x01,0x00,0x00};
	unsigned char quant0[5]={0xFF,0xDB,0x00,0x43,0x00};	//量化表标记头的前几个字节,后接具体的量化表。
	unsigned char quant1[5]={0xFF,0xDB,0x00,0x43,0x01};
	unsigned char GreyFrame[13]={0xff,0xc0,0x00,0x0b,0x08,0,0,0,0,0x01,0x01,0x11,0x00};
	unsigned char ColorFrame[19]={0xff,0xc0,0x00,0x11,0x08,0,0,0,0,0x03,0x01,0x22,0x00,
								0x02,0x11,0x01,0x03,0x11,0x01 };	//真彩色帧开始的标识符
	unsigned char LumDchuffman[5]={0xff,0xc4,0x00,0x1f,0x00};
	unsigned char LumAchuffman[5]={0xff,0xc4,0x00,0xb5,0x10};
	unsigned char ChrDchuffman[5]={0xff,0xc4,0x00,0x1f,0x01};
	unsigned char ChrAchuffman[5]={0xff,0xc4,0x00,0xb5,0x11};
	unsigned char GreySos[10]={0xff,0xda,0x00,0x08,0x01,0x01,0x00,0x00,0x3f,0x00};//扫描开始(SOS)标记符
	unsigned char ColorSos[14]={0xff,0xda,0x00,0x0c,0x03,0x01,0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00};//扫描开始(SOS)标记符
	unsigned char eoi[2]={0xff,0xd9};					//文件结束标识符End of Image
	GreyFrame[5]=ColorFrame[5]=height/256;
	GreyFrame[6]=ColorFrame[6]=height%256;	//图像的高度
	GreyFrame[7]=ColorFrame[7]=width/256;
	GreyFrame[8]=ColorFrame[8]=width%256;	//图像的宽度	
/////////////////////////////////////////////////////////////////////////////////

	file.Write(&filehead,sizeof(unsigned short int));	//写JPEG标识符FF D8
	file.Write(app0,18);								//写app0
	file.Write(quant0,5);									//写量化表标记头前5个字节
	file.Write(LumQuantTable,64);						//写量化表的64个字节
	if(m_bit24==1)
	{
		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();


	file.Write(eoi,2);									//写JPEG文件结束标识符
	file.Close();

	time( &tEnd );
	double nCostTime = difftime( tEnd, tBegin );	
	CString strCostTime;
	strCostTime.Format("JPEG编码完成!\n共花%.0lf秒", nCostTime);
	AfxMessageBox(strCostTime);	
	WaitCursorEnd();									//结束等待光标
	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);
}

/*************************************************************************
 * 函数名称:   Pre_DCT()
 * 参数:
 * double * sourcedata	- 指向时域值的指针

 * 返回值:		无
 * 说明: 该函数用来实现8*8快速离散余弦变换。
 ************************************************************************/
void CDib::Pre_DCT(double * sourcedata)
{
	double const C1=0.9808;
	double const C2=0.9239;
	double const C3=0.8315;
	double const C4=0.7071;
	double const C5=0.5556;
	double const C6=0.3827;
	double const C7=0.1951;
	double S18,S27,S36,S45,S1845,S2736;
	double D18,D27,D36,D45,D1845,D2736;
	double * data;
	int i;
/*	for(i=0;i<64;i++)
	{
		sourcedata[i]=sourcedata[i]-128;//图象数据减去128
	}
*/
//  后面有专门的地方使亮度值减去128
//  行DCT变换
	data=sourcedata;
   for(i=0;i<8;i++)
   {
    S18=data[0]+data[7];
    S27=data[1]+data[6];
    S36=data[2]+data[5];
    S45=data[3]+data[4];
    S1845=S18+S45;
    S2736=S27+S36;

    D18=data[0]-data[7]; 
    D27=data[1]-data[6];
    D36=data[2]-data[5];
    D45=data[3]-data[4];
    D1845=S18-S45;
    D2736=S27-S36;

    data[0]=0.5*(C4*(S1845+S2736));
    data[1]=0.5*(C1*D18+C3*D27+C5*D36+C7*D45);
    data[2]=0.5*(C2*D1845+C6*D2736);
    data[3]=0.5*(C3*D18-C7*D27-C1*D36-C5*D45);
    data[4]=0.5*(C4*(S1845-S2736));
    data[5]=0.5*(C5*D18-C1*D27+C7*D36+C3*D45);
    data[6]=0.5*(C6*D1845-C2*D2736);
    data[7]=0.5*(C7*D18-C5*D27+C3*D36-C1*D45);
	data+=8;
   }

/////////////////////////////////////////////////////
//  列DCT变换
   data=sourcedata;
   for(i=0;i<8;i++)
   {
    S18=data[0*8]+data[7*8];
    S27=data[1*8]+data[6*8];
    S36=data[2*8]+data[5*8];
    S45=data[3*8]+data[4*8];
    S1845=S18+S45;
    S2736=S27+S36;

    D18=data[0*8]-data[7*8]; 
    D27=data[1*8]-data[6*8];
    D36=data[2*8]-data[5*8];
    D45=data[3*8]-data[4*8];
    D1845=S18-S45;
    D2736=S27-S36;

    data[0*8]=0.5*(C4*(S1845+S2736));
    data[1*8]=0.5*(C1*D18+C3*D27+C5*D36+C7*D45);
    data[2*8]=0.5*(C2*D1845+C6*D2736);
    data[3*8]=0.5*(C3*D18-C7*D27-C1*D36-C5*D45);
    data[4*8]=0.5*(C4*(S1845-S2736));
    data[5*8]=0.5*(C5*D18-C1*D27+C7*D36+C3*D45);
    data[6*8]=0.5*(C6*D1845-C2*D2736);
    data[7*8]=0.5*(C7*D18-C5*D27+C3*D36-C1*D45);
	data++;
   }
}

///////////////////////////////////////////////////////
//
//	对8*8的图像块进行DCT变换,量化之后进行Z型扫描
//
///////////////////////////////////////////////////////
BOOL CDib::DCT(double * x,int n,unsigned char * QuantTable)
{	

	double * Light=new double[64];

	int i;
	for(i=0;i<n;i++)
		Light[i]=x[i];

	Pre_DCT(Light);    //二维DCT变换

//	对DCT系数进行量化,此处可调整量化矩阵,以调整JPEG文件的压缩比
	int quant_val[64];
	for(i=0;i<64;i++)
	{
		if(Light[i]>=0)
			quant_val[i]=(int)(Light[i]/QuantTable[i]+0.5);
		else
			quant_val[i]=(int)(Light[i]/QuantTable[i]-0.5);
	}
//	对量化矩阵进行Z型扫描
	for(i=0;i<64;i++)
		table[zig[i]]=quant_val[i];
	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)                    //能否被16整除
	{
		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
			r_height=height+8-height%8;
	}

⌨️ 快捷键说明

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