📄 复件 jpegdoc.cpp
字号:
{
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 + -