源码链接: 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 格式图片信息读取模块主要是读取 BMP 格式图片的信息,做相关的处理并存储。
JPEG 图片格式初始化并写入模块主要是填充 JPEG 图片的头部信息,并写入到相关的文件中。
综合处理与编码模块包括:将 RGB信息转换为 YUV信息、离散余弦变化、量化和 z型编码,再进行游程编码和霍夫曼编码,最后进行尾部填充。
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);
根据固定的值和相关的表的信息对 JPEG 头部内容进行赋值,然后写入到相关的文件中。
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。
填充并写入结尾标志:
if(bytepos > 0)
{
fillbit.length = bytepos;
fillbit.value = 0;
writefile(fillbit);
}
writeword(0xffd9); //EOI
压缩前后图片内容对比:
压缩前后图片大小对比:
从结果可以看出,压缩前后图片的内容几乎看不出变化,但是图片的大小差距非常大,大约缩小为原来的1/20,实现了压缩的功能。