JPEG概述和头分析(C源码)
原创文章,转载请注明:JPEG概述和头分析(C源码) By Lucio.Yang
部分内容来自:w285868925,JPEG压缩标准
1.JPEG概述
JPEG是一个压缩标准,又可分为标准 JPEG、渐进式JPEG及JPEG2000三种:
①标准JPEG:以24位颜色存储单个光栅图像,是与平台无关的格式,支持最高级
别的压缩,不过,这种压缩是有损耗的。此类型图片在网页下载时只能由上而下依序显 示图片,直到图片资料全部下载完毕,才能看到全貌。
②渐进式 JPEG:渐进式JPG为标准JPG的改良格式,支持交错,可以在网页下载时,先呈现出图片的粗略外观后,再慢慢地呈现出完整的内容,渐进式JPG的文件 比标准JPG的文件要来得小。
③JPEG2000:新一代的影像压缩法,压缩品质更好,其压缩率比标准JPEG高约30%左右,同时支持有损 和无损压缩。一个极其重要的特征在于它能实现渐进传输,即先传输图像的轮廓,然后逐步传输数据,让图像由朦胧到清晰显示。
2.压缩算法
必要性:大数据量的图象信息会给存储器的存储容量,通信干线信道的带宽,以及计算机的处理速度增加极大的压力。单纯靠增加存储器容量,提高信道带宽以及计算机的处理速度等方法来解决这个问题是不现实的,这时就要考虑压缩。
压缩可分为两大类:第一类压缩过程是可逆的,也就是说,从压缩后的图象能够完全恢复出原来的图象,信息没有任何丢失,称为无损压缩;第二类压缩过程是不可逆的,无法完全恢复出原图象,信息有一定的丢失,称为有损压缩。
压缩编码的方法有很多,主要分成以下四大类:(1)象素编码;(2)预测编码;(3)变换编码;(4)其它方法。
选择哪一类压缩,要折衷考虑,尽管我们希望能够无损压缩,但是通常有损压缩的压缩比(即原图象占的字节数与压缩后图象占的字节数之比,压缩比越大,说明压缩效率越高)比无损压缩的高。
JPEG专家组开发了两种基本的压缩算法,一种是采用以离散余弦变换(Discrete
Cosine Transform,DCT)为基础的有损压缩算法,另一种是采用以预测技术为基础的无损压缩算法。使用有损压缩算法时,在压缩比为25:1的情况下,压缩后还原得到的图像与原始图像相比较,非图像专家难于找出它们之间的区别,因此得到了广泛的应用。例如,在VCD和DVD-Video电视图像压缩技术中,就使用JPEG的有损压缩算法来取消空间方向上的冗余数据 为了在保证图像质量的前提下进一步提高压缩比,近年来JPEG专家组正在制定JPEG2000标准,这个标准中将采用小波变换(Wavelet)算法。
JPEG压缩是有损压缩,它利用了人的视角系统的特性,使用量化和无损压缩编码相结合来去掉视角的冗余信息和数据本身的冗余信息。
压缩编码大致分成三个步骤:
1、使用正向离散余弦变换(Forward
Discrete Cosine Transform,FDCT)把空间域表示的图变换成频率域表示的图。
2、使用加权函数对DCT系数进行量化,这个加权函数对于人的视觉系统是最佳的。
3、使用霍夫曼可变字长编码器对量化系数进行编码。
3.标记段简介
压缩后的JPEG文件大体上可以分成以下两个部分:标记码(Tag)加压缩数据。
下面简单介绍标记段。
标记段的结构一般为:
SOI
DQT
DRI
SOF0
DHT
SOS
…
EOI
标记码由两个字节组成,高字节为0XFF,每个标记码之前可以填上个数不限的填充字节0XFF。
下面介绍一些常用的标记码的结构及其含义。
(1)SOI(Start of Image)
标记结构 字节数
0XFF 1
0XD8 1
可作为JPEG格式的判据(JFIF还需要APP0的配合)
(2)APP0(Application)
标记结构 字节数 意义
0XFF 1
0XE0 1
Lp 2 APP0标记码长度,不包括前两个字节0XFF,0XE0
Identifier 5 JFIF识别码 0X4A,0X46,0X49,0X46,0X00
Version 2 JFIF版本号 可为0X0101或者0X0102
Units 1 单位,等于零时表示未指定,为1表示英寸,为2表示
厘米
Xdensity 2 水平分辨率
Ydensity 2 垂直分辨率
Xthumbnail 1 水平点数
Ythumbnail 1 垂直点数
RGB0 3 RGB的值
RGB1 3 RGB的值
…
RGBn 3 RGB的值,n=Xthumbnail*Ythumbnail
APP0是JPEG保留给Application所使用的标记码,而JFIF将文件的相关信息定义在此标记中。
(3)DQT(Define Quantization Table)
标记结构 字节数 意义
0XFF 1
0XDB 1
Lq 2 DQT标记码长度,不包括前两个字节0XFF,0XDB
(Pq,Tq) 1 高四位Pq为量化表的数据精确度,Pq=0时,Q0~Qn的
值为8位,Pq=1时,Qt的值为16位,Tq表示量化表的
编号,为0~3。在基本系统中,Pq=0,Tq=0~1,也就是
说最多有两个量化表。
Q0 1或2 量化表的值,Pq=0时;为一个字节,Pq=1时,为两个
字节
Q1 1或2 量化表的值,Pq=0时;为一个字节,Pq=1时,为两个
字节
…
Qn 1或2 量化表的值,Pq=0时,为一个字节;Pq=1时,为两个
字节。n的值为0~63,表示量化表中64个值(之字形排
列)
(4)DRI(Define Restart Interval)
标记结构 字节数 意义
0XFF 1
0XDD 1
Lr 2 DRI标记码长度,不包括前两个字节0XFF,0XDD
Ri 2 重入间隔的MCU个数,Ri必须是一MCU行中MCU
(5)SOF(Start of Frame) 在基本系统中,只处理SOF0
标记结构 字节数 意义
0XFF 1
0XC0 1
Lf 2 SOF标记码长度,不包括前两个字节0XFF,0XC0
P 1 基本系统中,为0X08
Y 2 图象高度
X 2 图象宽度
Nf 1 Frame中的成分个数,一般为1或3,1代表灰度图,3
代表真彩图
C1 1 成分编号1
(H1,V1) 1 第一个水平和垂直采样因子
Tq1 1 该量化表编号
C2 1 成分编号2
(H2,V2) 1 第二个水平和垂直采样因子
Tq2 1 该量化表编号
…
Cn 1 成分编号n
(Hn,Vn) 1 第n个水平和垂直采样因子
Tqn 1 该量化表编号
(6)DHT(Define Huffman Table)
标记结构 字节数 意义
0XFF 1
0XC4 1
Lh 2 DHT标记码长度,不包括前两个字节0XFF,0XC4
(Tc,Th) 1
L1 1
L2 1
…
L16 1
V1 1
V2 1
…
Vt 1
(7)SOS(Start of Scan)
标记结构 字节数 意义
0XFF 1
0XDA 1
Ls 2 DHT标记码长度,不包括前两个字节0XFF,0XDA
Ns 1
Cs1 1
(Td1,Ta1) 1
Cs2 1
(Td2,Ta2) 1
…
CsNs 1
(TdNs,TaNs) 1
Ss 1
Se 1
(8)EOI(End of Image) 结束标志
标记结构 字节数 意义
0XFF 1
0XD9 1
4.头信息分析实例
/*
* File Name: jpegDe.c
* Author: 576632108@qq.com lucio
* Date: 2014.11.5
* Description: analyze the head info of jpeg
*/
#include <stdio.h>
#include <stdlib.h> typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef long LONG; int main(int argc, char **argv){
FILE *fp;
WORD window;
WORD temp;
int i=,j=,k=;
int found_count=;
int mark_head=0xFF;
int mark_part[]={0xD8,0xE0,0xDB,0xDD,0xC0,0xC4,0xDA,0xD9};
char mark_str[][]={"SOI","APP0","DQT","DRI","SOF0","DHT","SOS","EOI"};
int head,part;
int temp_head,temp_part;
int done=;
fp=fopen("KD.jpg","rb");
if(fp==){
printf("Can not open the file to read.\n");
return -;
}
while( ){
fseek(fp,i,SEEK_SET);
if(fread(&window,,,fp)!=){
printf("Can not read the info of the info header.\n");
fclose(fp);
return -;
}
head=window-(window/0x100)*0x100;//靠前的部分是高位
part=window/0x100;//靠后的部分是低位
if( head==mark_head ){
for ( j=;j<;j++ ){
if( part==mark_part[j] ){
printf("%s: %X-%X\n",mark_str[j],head,part);
if( j== ){//APP0
//此处不需要fseek,因为读的过程中指针移动
//Lp
if(fread(&temp,,,fp)!=){
printf("Can not read the info of the info header.\n");
fclose(fp);
return -;
}
temp_head=temp-(temp/0x100)*0x100;
temp_part=temp/0x100;
temp=temp_head+temp_part;
printf(" Lp: %d\n",temp);
//Identifier
printf(" Identifier: ");
for( k=;k<;k++ ){
if(fread(&temp,,,fp)!=){
printf("Can not read the info of the info header.\n");
fclose(fp);
return -;
}
temp_head=temp-(temp/0x100)*0x100;
temp_part=temp/0x100;
if( k!= ) printf("%02X-%02X-",temp_head,temp_part);
else printf("%02X",temp_head);
}
printf("\n");
//Version
fseek(fp,-,SEEK_CUR);
if(fread(&temp,,,fp)!=){
printf("Can not read the info of the info header.\n");
fclose(fp);
return -;
}
temp_head=temp-(temp/0x100)*0x100;
temp_part=temp/0x100;
temp=temp_head+temp_part;
printf(" Version: %02X-%02X\n",temp_head,temp_part);
//Units
if(fread(&temp,,,fp)!=){
printf("Can not read the info of the info header.\n");
fclose(fp);
return -;
}
printf(" Units: %02X\n",temp);
//Xdensity
if(fread(&temp,,,fp)!=){
printf("Can not read the info of the info header.\n");
fclose(fp);
return -;
}
temp_head=temp-(temp/0x100)*0x100;
temp_part=temp/0x100;
temp=temp_head+temp_part;
printf(" Xdensity: %d\n",temp);
//Ydensity
if(fread(&temp,,,fp)!=){
printf("Can not read the info of the info header.\n");
fclose(fp);
return -;
}
temp_head=temp-(temp/0x100)*0x100;
temp_part=temp/0x100;
temp=temp_head+temp_part;
printf(" Ydensity: %d\n",temp);
//Xthumbnail
if(fread(&temp,,,fp)!=){
printf("Can not read the info of the info header.\n");
fclose(fp);
return -;
}
temp_head=temp-(temp/0x100)*0x100;
temp_part=temp/0x100;
printf(" Xthumbnail: %d\n",temp_head);
//Ythumbnail
printf(" Ythumbnail: %d\n",temp_part);
}
i+=;
if( j== ) done=;
break;
}//if
}//for
}//if
i++;
if( done== ) break;
}
fclose(fp);
system("pause");
return ;
}
JPEG概述和头分析(C源码)的更多相关文章
- k8s client-go源码分析 informer源码分析(2)-初始化与启动分析
k8s client-go源码分析 informer源码分析(2)-初始化与启动分析 前面一篇文章对k8s informer做了概要分析,本篇文章将对informer的初始化与启动进行分析. info ...
- JVM源码分析-JVM源码编译与调试
要分析JVM的源码,结合资料直接阅读是一种方式,但是遇到一些想不通的场景,必须要结合调试,查看执行路径以及参数具体的值,才能搞得明白.所以我们先来把JVM的源码进行编译,并能够使用GDB进行调试. 编 ...
- k8s client-go源码分析 informer源码分析(3)-Reflector源码分析
k8s client-go源码分析 informer源码分析(3)-Reflector源码分析 1.Reflector概述 Reflector从kube-apiserver中list&watc ...
- Android源码分析--CircleImageView 源码详解
源码地址为 https://github.com/hdodenhof/CircleImageView 实际上就是一个圆形的imageview 的自定义控件.代码写的很优雅,实现效果也很好, 特此分析. ...
- 一 分析easyswoole源码(启动服务)
分析easyswoole源码 1以启动为例 //检查是否已经安装 installCheck();//检查锁文件是否存在,不存在结束 //启动服务 serverStart showLogo();//显示 ...
- 分析jQuery源码时记录的一点感悟
分析jQuery源码时记录的一点感悟 1. 链式写法 这是jQuery语法上的最大特色,也许该改改POJO里的set方法,和其他的非get方法什么的,可以把多行代码合并,减去每次 ...
- Linux内核(2) - 分析内核源码如何入手(上)
透过现象看本质,兽兽们无非就是一些人体艺术展示.同样往本质里看过去,学习内核,就是学习内核的源代码,任何内核有关的书籍都是基于内核,而又不高于内核的. 既然要学习内核源码,就要经常对内核代码进行分析, ...
- STM32F103 ucLinux开发之一(BOOT分析及源码)
STM32F103 ucLinux开发BOOT STM3210E-EVAL官方开发板主芯片STM32F103ZET6: 片内512K Flash,地址0x0800 0000 ~ 0x0807 FFFF ...
- Activiti架构分析及源码详解
目录 Activiti架构分析及源码详解 引言 一.Activiti设计解析-架构&领域模型 1.1 架构 1.2 领域模型 二.Activiti设计解析-PVM执行树 2.1 核心理念 2. ...
随机推荐
- 派生类地址比基类地址少4(子类与基类指针强行转换的时候,值居然会发生变化,不知道Delphi BCB是不是也这样) good
大家对虚表并不陌生,都知道每个含有虚函数的类对象都有1个虚指针,但是在现实使用中,却总是因为这而调试半天,才发现原来是虚指针惹的祸.我这几天在调试代码时候也中招了,我的问题是这样的,如下图,CTree ...
- css vertical-align全解
CSS 的属性 vertical-align 指定了内联(inline)元素或表格单元格(table-cell)元素的垂直对齐方式. 要记住:vertical-align不影响块级元素中内容的对齐. ...
- Linux常用的系统监控shell脚本
http://www.linuxqd.com下面是我常用的几个Linux系统监控的脚本,大家可以根据自己的情况在进行修改,希望能给大家一点帮助.1.查看主机网卡流量 #!/bin/bash #netw ...
- HDU 5828 Rikka with Sequence(线段树)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5828 [题目大意] 给出一个数列,要求支持区间加法,区间开方和区间和查询操作. [题解] 考虑开方 ...
- 合作开发,导入MyEclipse项目报错问题
因工作原因,同事将他的java项目交接给了我.和平时的交接一样.他把他最新的源代码,打成压缩包,发给我.我解压后,使用myeclipse开发工具,通过导入,将项目导入到我的开发工具中,这个时候有一个问 ...
- 关于cvScalar的那些事
CvScalar 可存放在1-,2-,3-,4-TUPLE类型的捆绑数据的容器 该函数包含4个浮点成员,可以用来表示B(Blue),G(Green),R(Red),Alpha(表示图像的透明度) ty ...
- BingMap的GeocodeService进行地理位置正向和反向检索--后台实现
一.加入GeocodeService的Web服务引用 地理编码服务(GeocodeService)是以WCF技术公布的一个Web服务,地图编码服务提供了以一个有效的物理地址在地图上匹配其相应的地图地址 ...
- How draw a stem -and -leaf & box-plot display by R.or Python
参考: 使用R进行数据可视化套路之-茎叶图.盒形图 step by step R 读取数据 在网上下载的2013全国各省区GDP排名(exl文件) 先 另存为 data.txt(为了方便存到D盘文件夹 ...
- css--技巧整理(1-13)
(更新中) 1.取消浏览器form中默认样式 a.chrome下input和textarea的聚焦边框 input,button,select,textarea{outline:none} b.取消 ...
- iframe跨域通信方案
概述 JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象.但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦.这里把涉及到跨域的一些问题简单地整理一下: 首先什么 ...