将BMP 格式图片转换为 JPEG 格式【c语言】

源码链接: https://blog.csdn.net/qq_44394952/article/details/122587475?spm=1001.2014.3001.5502.

一、任务及目标

利用c语言,通过将 RGB 信息转换为 YCrCb 信息、离散余弦变化、量化和 z 型编码,再进行游程编码和霍夫曼编码,最后进行尾部填充的方式,将BMP 格式图片转换为 JPEG 格式。

二、原理及设计方案

c语言环境下,在主函数中输入 BMP 格式和 JPEG 格式图片的名称,然后调用 BMP 格式图片信息读取模块,再调用 JPEG 图片格式初始化并写入头信息模块,最后调用综合处理与编码模块填充 JPEG 图片。
将BMP 格式图片转换为 JPEG 格式【c语言】_第1张图片
BMP 格式图片信息读取模块主要是读取 BMP 格式图片的信息,做相关的处理并存储。
JPEG 图片格式初始化并写入模块主要是填充 JPEG 图片的头部信息,并写入到相关的文件中。
综合处理与编码模块包括:将 RGB信息转换为 YUV信息、离散余弦变化、量化和 z型编码,再进行游程编码和霍夫曼编码,最后进行尾部填充。

三、步骤及结果

3.1BMP格式信息处理

将BMP 格式图片转换为 JPEG 格式【c语言】_第2张图片
1)转换为 24 位:

for(unsigned long int n = 0; n < x8*yimage; ++n)
 	{
 		RGB_buf[n].B = RGBa_buf[n].B;
 		RGB_buf[n].G = RGBa_buf[n].G;
 		RGB_buf[n].R = RGBa_buf[n].R;
 }

2)逆序处理:

memcpy(tmpline, RGB_buf+line_up*ximage, ximage*3);
memcpy(RGB_buf+line_up*ximage,RGB_buf+line_down*ximage, ximage*3);
memcpy(RGB_buf+line_down*ximage, tmpline, ximage*3);

3.2JPEG 格式图片头部处理

根据固定的值和相关的表的信息对 JPEG 头部内容进行赋值,然后写入到相关的文件中。

3.3综合处理与编码模块

将BMP 格式图片转换为 JPEG 格式【c语言】_第3张图片
1)计算huffman编码表
在循环中进行如下操作:

HT[values[pos]].value = codevalue;  //编码值 
HT[values[pos]].length = k;  //长度
pos ++; 
codevalue++

并且在该长度的编码遍历完成后 codevalue 左移一位。

2)RGB转化为YUV: 根据原理部分相关的公式计算即可。

3)离散余弦变换:
在四重循环中进行如下操作:

tmp += data[i][j] * cos((2*i+1)*u*PI/(2.0 * 8)) * cos((2*j+1)*v*PI/(2.0 * 8)); 

在二重循环结束后乘以相关的系数并存储。
4)量化和 z 型编码:
离散余弦变化的值除以量化表并乘以相关的量化系数,然后再讲此值按四舍五入的规则变换为整数,得到量化后的值:

temp = output[i][j] / (float)((double)fdtbl[z[i*8+j]]); 
outdata[i*8+j] = (signed short int) ((signed short int)(temp + 16384.5)-16384); 

在量化完成后,根据z矩阵中的顺序,改变数据存储的顺序,目的是让矩阵右下角更多的0连续存储:

for (i = 0; i <= 63; i++) 
D2[z[i]] = D1[i]; 

5)直流编码:
单独对矩阵的左上角的第一个值进行处理,求出其与上一个矩阵的左上角的值的差值,然后用 huffman 编码表示此差值二进制编码的长度,并写入文件中,然后再写入该值的二进制编码。

6)交流编码:
首先求出尾部0的数量,若63个值全为0则写入0x00:

for(endpos = 63; (endpos > 0) && (D2[endpos] == 0); --endpos); 
if(endpos == 0) 
{ 
writefile(ACtable[0x00]); 
return ; 
} 

若不全为 0,则处理相应的内容:

startpos = i; 
for(; (D2[i] == 0) && (i <= endpos); ++i); 
nz = i - startpos;

若是连续0的数量超过15需要单独处理:

for(;nz >= 16; nz -= 16) 
writefile(ACtable[0xf0]); 

前4bit表示0的数量,后4bit表示后面二进制数的长度,进行huffman编码:

writefile(ACtable[nz*16+code_d[D2[i]].length]); 
writefile(code_d[D2[i]]); 
++i; 

最后,若尾部0的数量不是0,则在尾部写入0x00。

3.4 尾部信息处理

填充并写入结尾标志:

if(bytepos > 0) 
{ 
fillbit.length = bytepos; 
fillbit.value = 0; 
writefile(fillbit); 
} 
writeword(0xffd9);  //EOI

四、结果

将BMP 格式图片转换为 JPEG 格式【c语言】_第4张图片
压缩前后图片内容对比:
将BMP 格式图片转换为 JPEG 格式【c语言】_第5张图片
压缩前后图片大小对比:
将BMP 格式图片转换为 JPEG 格式【c语言】_第6张图片
从结果可以看出,压缩前后图片的内容几乎看不出变化,但是图片的大小差距非常大,大约缩小为原来的1/20,实现了压缩的功能。

你可能感兴趣的:(网络安全,通信,c语言,开发语言,后端)