c语言数据溢出解决解决一个问题

您所在的位置: &
解决问题--究竟C语言还有用吗
解决问题--究竟C语言还有用吗
电子工业出版社
《荡胸生层云:C语言开发修行实录》第1章学C语言还有用吗,本章通过对C语言的学习和了解,使我们能够深入地理解操作系统的运作方式,以及编程思想的核心理念。本节为大家介绍解决问题--究竟C语言还有用吗。
1.7& 解决问题--究竟C语言还有用吗
9月9日,17:00,多云
KNOWALL:"返回本章开始,看本章开始你提出的问题:C语言还有用吗?有用没用先不下结论,先看年这两年的统计:",如图1-24所示。
从上述统计表中可以一目了然地看出,C语言是当今使用最多的一门语言。
1.百家争鸣的语言之争
当前编程语言技术,犹如春秋时期的百家争鸣,各种最新技术、新思想、新名词层出不穷,令人眼花缭乱。新与旧混杂在一起,让人晕晕乎乎,各种技术领域越来越分化,程序员距离计算机底层实现越来越远,不懂的领域越来越多,也越来越感到焦虑,他们已经由计算机的主人变成了计算机的奴隶。
无论是初学者还是高级程序员,都在心底埋藏着一个问题:C语言会不会只是人们学习程序设计的基石,而没有了实际的使用价值?答案当然不是,笔者在此建议读者要牢记:越基础的语言,它能实现的功能也就越强大。比如现在许多的语言都是由C语言开发出来的。在真正高深的编程领域,许多好的软件、系统都是由汇编语言和C语言等编写出来的。所以它不光是基石,而且将会有强大的生命力。
2.C语言的江湖地位
C语言就如武学中的内功心法,是学习其他武功的根基。C语言是目前世界上流行、使用非常广泛的高级程序设计语言。它具有绘图能力强,可移植性,并具备很强的数据处理能力,因此适于编写系统软件、三维、二维图形和动画,它是数值计算的高级语言。
3.中肯的看C语言的地位
C语言比较贴近操作系统,纯C语言在Windows平台上主要用于系统底层驱动的开发(一般会辅以汇编)。特别是在Linux或UNIX上,C语言一直到现在都还是主流,C语言编写的命令程序可以很方便与其他程序在shell上配合。C脚本和shell构建了一整套UNIX/Linux哲学,与C语言相提并论的一般是C++,因为与Java、Python、Visual Basic这些语言明显不是一个领域。C语言相对C++来说比较简单,C++则编程语言中最复杂的一个。
在此可以简单地总结一下C语言特点。
(1)C语言语法简单,是学习其他语言的基础;
(2)C语言符合Unix/Linux哲学,它适合和其他程序以进程方式组合来构建大型的应用,也是因为这个原因,Linux直到2.5才把线程提到考虑范围中;
(3)Linux特别重视进程的开销,而相比Windows,Linux的进程开销也相对较小。
【责任编辑: TEL:(010)】&&&&&&
关于&&&&的更多文章
Java领域最有影响力和价值的著作之一,由拥有20多年教学与研究经
本书描述了黑客用默默无闻的行动为数字世界照亮了一条道路的故事。
本书通过对目前中国企业在风险管理和内部控制工作中的
解释ASP.NET MVC框架与"文件页"Web框架的不同之处
本书以Android 4.X进行开发示范,通过大量图示与step
去年11月至今年8月间,香港学生组织大学师生监察无良企业行动(以下简称SACOM)通过调查发现,戴尔公司位于东莞的三家代工厂严重
51CTO旗下网站共有 1838 人关注过本帖
标题:c语言
为什么写出现了一个问题,导致程序停止工作
来 自:西南石油大学
等 级:新手上路
帖 子:15
结帖率:50%
&&已结贴√
&&问题点数:10&&回复次数:22&&&
为什么写出现了一个问题,导致程序停止工作
#include&stdio.h&
int main()
&&& float m,
&&& scanf(&%f&,m);
&&& if(m&200)
&&&&&&&&tax=0;
&&& if(m&=200&&m&400)
&&&&&&&&tax=m*0.03;
&&& if(m&=400&&m&5000)
&&&&&&&&tax=m*0.04;
&&& if(m&=5000)
&&&&&&&&tax=m*0.05;
&&& printf(&%f&,tax);
&&& return 0;
我找了很久&&&就是没找出错&&&只能求帮助了
搜索更多相关主题的帖子:
等 级:贵宾
威 望:304
帖 子:25793
专家分:48814
看看別人的帖子會看到解答
授人以渔,不授人以鱼。
来 自:湖南
等 级:贵宾
威 望:64
帖 子:1190
专家分:4789
回复 2楼 TonyDeng
终于知道你为啥用繁体了
等 级:贵宾
威 望:304
帖 子:25793
专家分:48814
以下是引用林月儿在 21:55:07的发言:
终于知道你为啥用繁体了
授人以渔,不授人以鱼。
来 自:西南石油大学
等 级:新手上路
帖 子:15
来 自:西南石油大学
等 级:新手上路
帖 子:15
没找到&&& 给我讲一下嘛&&&我还有好多程序没编完
等 级:贵宾
威 望:304
帖 子:25793
专家分:48814
本版今天對答最多的帖子,沒幾個,去看看。
授人以渔,不授人以鱼。
来 自:西南石油大学
等 级:新手上路
帖 子:15
嗯嗯&&& 好吧&&&谢谢
来 自:湖南
等 级:贵宾
威 望:64
帖 子:1190
专家分:4789
&&& scanf(&%f&,&m);
&&& 不告诉你T板
来 自:西南石油大学
等 级:新手上路
帖 子:15
什么意思&&& 怎么改
版权所有,并保留所有权利。
Powered by , Processed in 0.030967 second(s), 8 queries.
Copyright&, BCCN.NET, All Rights Reserved查看:15290|回复:18
怎样用C语言实现简单的图像处理?bmp和JPEG格式
请问如下思路是否正确:
先用二进制方式打开图像文件,从文件头后面的位置开始读取。如果要想改变图像的颜色,就检查每一个像素的RGB值是否符合要求,如果符合就改为新的RGB值,不符合就继续查找下一个,直到文件结尾。
另外JPEG格式的图像是不是还需要编解码?
如何区分灰度图像?
BMP文件结构
位图文件可看成由4个部分组成:位图文件头(bitmap-file header)、位图信息头( bitmap-information header )、彩色表(color table)和定义位图的字节阵列,它具有如下所示的形式。
位图文件的组成
位图文件头(bitmap-file header)
BITMAPFILEHEADER
位图信息头(bitmap-information header)
BITMAPINFOHEADER
彩色表(color table)
图象数据阵列字节
aBitmapBits[]
1. 位图文件头
位图文件头包含有关于文件类型、文件大小、存放位置等信息,在Windows 3.0以上版本的位图文件中用BITMAPFILEHEADER结构来定义:
typedef struct tagBITMAPFILEHEADER { /* bmfh */
UINT bfReserved1;
UINT bfReserved2;
DWORD bfOffB
} BITMAPFILEHEADER;
bfType说明文件的类型.(该值必需是0x4D42,也就是字符'BM'。我们不需要判断OS/2的位图标识,这么做现在来看似乎已经没有什么意义了,而且如果要支持OS/2的位图,程序将变得很繁琐。所以,在此只建议你检察'BM'标识)
bfSize说明文件的大小,用字节为单位bfReserved1保留,必须设置为0bfReserved2保留,必须设置为0bfOffBits说明从文件头开始到实际的图象数据之间的字节的偏移量。这个参数是非常有用的,因为位图信息头和调色板的长度会根据不同情况而变化,所以你可以用这个偏移值迅速的从文件中读取到位数据。
2. 位图信息头
位图信息用BITMAPINFO结构来定义,它由位图信息头(bitmap-information header)和彩色表(color table)组成,前者用BITMAPINFOHEADER结构定义,后者用RGBQUAD结构定义。BITMAPINFO结构具有如下形式:
typedef struct tagBITMAPINFO { /* bmi */
BITMAPINFOHEADER bmiH
RGBQUAD bmiColors[1];
} BITMAPINFO;&&
bmiHeader说明BITMAPINFOHEADER结构,其中包含了有关位图的尺寸及位格式等信息bmiColors说明彩色表RGBQUAD结构的阵列,其中包含索引图像的真实RGB值。BITMAPINFOHEADER
包含有位图文件的大小、压缩类型和颜色格式,其结构定义为:
typedef struct tagBITMAPINFOHEADER { /* bmih */
WORD biBitC
DWORD biSizeI
LONG biXPelsPerM
LONG biYPelsPerM
DWORD biClrU
DWORD biClrI
} BITMAPINFOHEADER;
biSize说明BITMAPINFOHEADER结构所需要的字数。注:这个值并不一定是BITMAPINFOHEADER结构的尺寸,它也可能是sizeof(BITMAPV4HEADER)的值,或是sizeof(BITMAPV5HEADER)的值。这要根据该位图文件的格式版本来决定,不过,就现在的情况来看,绝大多数的BMP图像都是BITMAPINFOHEADER结构的(可能是后两者太新的缘故吧:-)。biWidth说明图象的宽度,以象素为单位biHeight说明图象的高度,以象素为单位。注:这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图。如果该值是一个正数,说明图像是倒向的,如果该值是一个负数,则说明图像是正向的。大多数的BMP文件都是倒向的位图,也就是时,高度值是一个正数。(注:当高度值是一个负数时(正向图像),图像将不能被压缩(也就是说biCompression成员将不能是BI_RLE8或BI_RLE4)。biPlanes为目标设备说明位面数,其值将总是被设为1biBitCount说明比特数/象素,其值为1、4、8、16、24、或32biCompression说明图象数据压缩的类型。其值可以是下述值之一:
BI_RGB:没有压缩;
BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引);
BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成
BI_BITFIELDS:每个象素的比特由指定的掩码决定。biSizeImage说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0biXPelsPerMeter说明水平分辨率,用象素/米表示biYPelsPerMeter说明垂直分辨率,用象素/米表示biClrUsed说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项)biClrImportant说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。
彩色表的定位
应用程序可使用存储在biSize成员中的信息来查找在BITMAPINFO结构中的彩色表,如下所示:
pColor = ((LPSTR) pBitmapInfo + (WORD) (pBitmapInfo-&bmiHeader.biSize))
(2) biBitCount
biBitCount=1 表示位图最多有两种颜色,缺省情况下是黑色和白色,你也可以自己定义这两种颜色。图像信息头装调色板中将有两个调色板项,称为索引0和索引1。图象数据阵列中的每一位表示一个象素。如果一个位是0,显示时就使用索引0的RGB值,如果位是1,则使用索引1的RGB值。
biBitCount=4 表示位图最多有16种颜色。每个象素用4位表示,并用这4位作为彩色表的表项来查找该象素的颜色。例如,如果位图中的第一个字节为0x1F,它表示有两个象素,第一象素的颜色就在彩色表的第2表项中查找,而第二个象素的颜色就在彩色表的第16表项中查找。此时,调色板中缺省情况下会有16个RGB项。对应于索引0到索引15。
biBitCount=8 表示位图最多有256种颜色。每个象素用8位表示,并用这8位作为彩色表的表项来查找该象素的颜色。例如,如果位图中的第一个字节为0x1F,这个象素的颜色就在彩色表的第32表项中查找。此时,缺省情况下,调色板中会有256个RGB项,对应于索引0到索引255。
biBitCount=16 表示位图最多有216种颜色。每个色素用16位(2个字节)表示。这种格式叫作高彩色,或叫增强型16位色,或64K色。它的情况比较复杂,当biCompression成员的值是BI_RGB时,它没有调色板。16位中,最低的5位表示蓝色分量,中间的5位表示绿色分量,高的5位表示红色分量,一共占用了15位,最高的一位保留,设为0。这种格式也被称作555 16位位图。如果biCompression成员的值是BI_BITFIELDS,那么情况就复杂了,首先是原来调色板的位置被三个DWORD变量占据,称为红、绿、蓝掩码。分别用于描述红、绿、蓝分量在16位中所占的位置。在Windows 95(或98)中,系统可接受两种格式的位域:555和565,在555格式下,红、绿、蓝的掩码分别是:0x7C00、0x03E0、0x001F,而在565格式下,它们则分别为:0xF800、0x07E0、0x001F。你在读取一个像素之后,可以分别用掩码“与”上像素值,从而提取出想要的颜色分量(当然还要再经过适当的左右移操作)。在NT系统中,则没有格式限制,只不过要求掩码之间不能有重叠。(注:这种格式的图像使用起来是比较麻烦的,不过因为它的显示效果接近于真彩,而图像数据又比真彩图像小的多,所以,它更多的被用于游戏软件)。
biBitCount=24 表示位图最多有224种颜色。这种位图没有调色板(bmiColors成员尺寸为0),在位数组中,每3个字节代表一个象素,分别对应于颜色R、G、B。
biBitCount=32 表示位图最多有232种颜色。这种位图的结构与16位位图结构非常类似,当biCompression成员的值是BI_RGB时,它也没有调色板,32位中有24位用于存放RGB值,顺序是:最高位—保留,红8位、绿8位、蓝8位。这种格式也被成为888 32位图。如果 biCompression成员的值是BI_BITFIELDS时,原来调色板的位置将被三个DWORD变量占据,成为红、绿、蓝掩码,分别用于描述红、绿、蓝分量在32位中所占的位置。在Windows 95(or 98)中,系统只接受888格式,也就是说三个掩码的值将只能是:0xFF0000、0xFF00、0xFF。而在NT系统中,你只要注意使掩码之间不产生重叠就行。(注:这种图像格式比较规整,因为它是DWORD对齐的,所以在内存中进行图像处理时可进行汇编级的代码优化(简单))。
(3) ClrUsed
BITMAPINFOHEADER结构中的成员ClrUsed指定实际使用的颜色数目。如果ClrUsed设置成0,位图使用的颜色数目就等于biBitCount成员中的数目。请注意,如果ClrUsed的值不是可用颜色的最大值或不是0,则在编程时应该注意调色板尺寸的计算,比如在4位位图中,调色板的缺省尺寸应该是16*sizeof(RGBQUAD),但是,如果ClrUsed的值不是16或者不是0,那么调色板的尺寸就应该是ClrUsed*sizeof(RGBQUAD)。
图象数据压缩
① BI_RLE8
每个象素为8比特的RLE压缩编码,可使用编码方式和绝对方式中的任何一种进行压缩,这两种方式可在同一幅图中的任何地方使用。
编码方式:由2个字节组成,第一个字节指定使用相同颜色的象素数目,第二个字节指定使用的颜色索引。此外,这个字节对中的第一个字节可设置为0,联合使用第二个字节的值表示:
第二个字节的值为0:行的结束。
第二个字节的值为1:图象结束。
第二个字节的值为2:其后的两个字节表示下一个象素从当前开始的水平和垂直位置的偏移量。
绝对方式:第一个字节设置为0,而第二个字节设置为0x03~0xFF之间的一个值。在这种方式中,第二个字节表示跟在这个字节后面的字节数,每个字节包含单个象素的颜色索引。压缩数据格式需要字边界(word boundary)对齐。下面的例子是用16进制表示的8-位压缩
图象数据:
03 04 05 06 00 03 45 56 67 00 02 78 00 02 05 01 02 78 00 00 09 1E 00 01
这些压缩数据可解释为
压缩数据&&扩展数据 03 04
06 06 06 06 06
00 03 45 56 67 00
00 02 05 01
从当前位置右移5个位置后向下移一行
1E 1E 1E 1E 1E 1E 1E 1E 1E
RLE编码图象结束
② BI_RLE4
编码方式:由2个字节组成,第一个字节指定象素数目,第二个字节包含两种颜色索引,一个在高4位,另一个在低4位。第一个象素使用高4位的颜色索引,第二个使用低4位的颜色索引,第3个使用高4位的颜色索引,依此类推。
绝对方式:这个字节对中的第一个字节设置为0,第二个字节包含有颜色索引数,其后续字节包含有颜色索引,颜色索引存放在该字节的高、低4位中,一个颜色索引对应一个象素。此外,BI_RLE4也同样联合使用第二个字节中的值表示:
第二个字节的值为0:行的结束。
第二个字节的值为1:图象结束。
第二个字节的值为2:其后的两个字节表示下一个象素从当前开始的水平和垂直位置的偏移量。
下面的例子是用16进制数表示的4-位压缩图象数据:
03 04 05 06 00 06 45 56 67 00 04 78 00 02 05 01 04 78 00 00 09 1E 00 01
这些压缩数据可解释为
压缩数据 扩展数据 03 04
00 06 45 56 67 00
4 5 5 6 6 7
00 02 05 01
从当前位置右移5个位置后向下移一行
1 E 1 E 1 E 1 E 1
RLE图象结束
彩色表包含的元素与位图所具有的颜色数相同,象素的颜色用RGBQUAD结构来定义。对于24-位真彩色图象就不使用彩色表(同样也包括16位、和32位位图),因为位图中的RGB值就代表了每个象素的颜色。彩色表中的颜色按颜色的重要性排序,这可以辅助显示驱动程序为不能显示足够多颜色数的显示设备显示彩色图象。RGBQUAD结构描述由R、G、B相对强度组成的颜色,定义如下:
typedef struct tagRGBQUAD { /* rgbq */
} RGBQUAD;
指定蓝色强度
指定绿色强度
指定红色强度
rgbReserved
保留,设置为0
紧跟在彩色表之后的是图象数据字节阵列。图象的每一扫描行由表示图象象素的连续的字节组成,每一行的字节数取决于图象的颜色数目和用象素表示的图象宽度。扫描行是由底向上存储的,这就是说,阵列中的第一个字节表示位图左下角的象素,而最后一个字节表示位图右上角的象素。(只针对与倒向DIB,如果是正向DIB,则扫描行是由顶向下存储的),倒向DIB的原点在图像的左下角,而正向DIB的原点在图像的左上角。同时,每一扫描行的字节数必需是4的整倍数,也就是DWORD对齐的。如果你想确保图像的扫描行DWORD对齐,可使用下面的代码:
& && && && && && && & (((width*biBitCount)+31)&&5)&&2
程序设计,算法为王。
提出问题;分析问题;确定算法;画出流程图;编辑程序;调试程序;建立文档资料。
大家在开发板块贴代码的时候,请使用“插入代码”的功能。
[code]int main(){return 0;}[/code]
JPEG 简易文档 V2.15
------------------------------
& && &&&初稿写于
& && &&&最后修订
& && && && && &&&
& && &&&作者: 云风
& && &&&Email: cloudwu (a)
& && &&&Homepage:
1. 为什么写这个文档?
& & 云风想对 JPEG/MPEG 有一个系统的研究, 但是苦于找到好的资料. 而英文水平又
& & 不怎样, 所以在学习的过程, 将已经了解了的东西记录下来. 方便自己在编写
& & 代码的时候查阅. 而且正式的 JPEG 文档非常复杂, 打印出来也有厚厚一本, 就
& & 是英文底子比较好的朋友, 看起来也会头痛. 英文文档可以在网上 google 到一篇
& & CRYX's note about the JPEG decoding algorithm . 本文结构照搬之. 内容在
& & 动笔之初只想做粗略翻译,后在自己实现 decode 程序时,又查阅了许多其他资料,
& & 便在文中增加了自己的诸多理解. 这是一份对 JPEG Baseline 编码的解码算法解说
& & 的精简版本. 需要深入研究 JPEG 的朋友请自己再去找书和资料. 现有电子工业出版社
& & 出版的《JPEG 2000 图象压缩基础、标准和实践》可供研读。希望 inet 上中文资料
& & 越来越丰富.
2. 通过阅读这份文档期望达到的目的.
& & 能够对 JPEG 图形压缩有一定感性的认识, 但其数学原理不需要搞清. 能够通过这,
& & 开始写自己的编码/解码程序. 或者看懂以有的代码. 对有损图形压缩有进一步了解.
& & 自己能够改良 JPEG, 比如增加透明色的支持, 加快 JPEG 的解码速度.
3. 为什么用文本格式写, 而不用 HTML?
& & 个人喜好. 不喜欢有格式编排的电子文档. 纯文本能够更广泛的使用, 而不需要
& & HTML 浏览器.
4. 读者需要为这个文档付出什么吗?
& & 您可以自由使用它. 但是由于您是无偿使用, 所以作者不对可能出现的错误和问
& & 题担负任何责任. 关于相关问题,可以来 email 探讨, 但由于精力有限, 不保证
& & 回信. 如果你对这有不满意的地方, 云风不接受任何无理批评.
5. 能够转载这篇文档吗?
& & 欢迎您随意转载, 但不得用它赢利. 而且转载请保留其内容完整. 如果您为它
& & 制作了诸如 HTML 等别的格式的版本, 也必须同时保留一份纯文本版在一起.
6. 如何得到文档的最新版本?
& & 你看到的这份文档很可能不是最新版本, 几年来云风总是能收到文档的读者对其中
& & 一些章节的质疑, 询问. 所以每隔一段时间, 一些被发现的 bug, 一些没有写清楚
& & 的细节会被修正和补充. 所以在有疑问时可以先
& & 最新版本.
本文档文字组织比较简陋, 大体上分成 3 个部分.
压缩算法简介
& & 1. 色彩模型
& & 2. DCT (离散余弦变换)
& & 3. 重排列 DCT 结果
& & 4. 量化
& & 5. 0 RLE 编码
& & 6. 范式 Huffman 编码
& & 7. DC 的编码
解码过程简述
& & 8. 一个数据单元 Y 的解码
& & 9. JPG 文件(Byte 级)里怎样组织图片信息
& & 10. 关于标记
& & 11. JPG 文件中 Haffman 表的储存
& & 12. 采样系数
& & 13. JPG 文件的解码简述
JPEG 文件格式
-------------
JPEG 压缩简介
-------------
1. 色彩模型
& & JPEG 的图片使用的是 YCrCb 颜色模型, 而不是计算机上最常用的 RGB. 关于色
彩模型, 这里不多阐述. 只是说明, YCrCb 模型更适合图形压缩. 因为人眼对图片上
的亮度 Y 的变化远比色度 C 的变化敏感. 我们完全可以每个点保存一个 8bit 的亮
度值, 每 2x2 个点保存一个 Cr Cb 值, 而图象在肉眼中的感觉不会起太大的变化.
所以, 原来用 RGB 模型, 4 个点需要 4x3=12 字节. 而现在仅需要 4+2=6 字节; 平
均每个点占 12bit. 当然 JPEG 格式里允许每个点的 C 值都记录下来; 不过 MPEG 里
都是按 12bit 一个点来存放的, 我们简写为 YUV12.
[R G B] -& [Y Cb Cr] 转换
-------------------------
(R,G,B 都是 8bit unsigned)
& && &&&| Y&&|& &&&|&&0.299& && & 0.587& && & 0.114 |& &| R |& &&&| 0 |
& && &&&| Cb |&&=&&|- 0.1687& & - 0.3313& && &0.5& &| * | G |& &+ |128|
& && &&&| Cr |& &&&|&&0.5& && & - 0.4187& & - 0.0813|& &| B |& &&&|128|
Y = 0.299*R + 0.587*G + 0.114*B&&(亮度)
Cb =&&- 0.1687*R - 0.3313*G + 0.5& &*B + 128
Cr =& & 0.5& &*R - 0.4187*G - 0.0813*B + 128
[Y,Cb,Cr] -& [R,G,B] 转换
-------------------------
R = Y& && && && && && &&&+ 1.402&&*(Cr-128)
G = Y - 0.34414*(Cb-128) - 0.71414*(Cr-128)
B = Y + 1.772&&*(Cb-128)
& & 一般, C 值 (包括 Cb Cr) 应该是一个有符号的数字, 但这里被处理过了, 方法
是加上了 128. JPEG 里的数据都是无符号 8bit 的.
2. DCT (离散余弦变换)
& & JPEG 里, 要对数据压缩, 先要做一次 DCT 变换. DCT 变换的原理, 涉及到数学
知识, 这里我们不必深究. 反正和傅立叶变换(学过高数的都知道) 是差不多了. 经过
这个变换, 就把图片里点和点间的规律呈现出来了, 更方便压缩.JPEG 里是对每 8x8
个点为一个单位处理的. 所以如果原始图片的长宽不是 8 的倍数, 都需要先补成 8
的倍数, 好一块块的处理. 另外, 记得刚才我说的 Cr Cb 都是 2x2 记录一次吗? 所
以大多数情况, 是要补成 16x16 的整数块.按从左到右, 从上到下的次序排列 (和我
们写字的次序一样). JPEG 里是对 Y Cr Cb 分别做 DCT 变换的. 这里进行 DCT 变换
的 Y, Cr, Cb 值的范围都是 -128~127. (Y 被减去 128)
& & JPEG 编码时使用的是 Forward DCT (FDCT) 解码时使用的 Inverse DCT (IDCT)
下面给出公式:
& && && && && && && && && &&&7& &7& && && && && &&&2*x+1& && && && && & 2*y+1
F(u,v) = alpha(u)*alpha(v)* sum sum f(x,y) * cos (------- *u*PI)* cos (------ *v*PI)
& && && && && && && && && & x=0 y=0& && && && && &&&16& && && && && && & 16
u,v = 0,1,...,7
& && && &&&{ 1/sqrt(8)&&(u==0)
alpha(u) = {
& && && &&&{ 1/2& && &&&(u!=0)
& && && & 7& &7& && && && && && && && && && && &2*x+1& && && && && & 2*y+1
f(x,y) = sum sum alpha(u)*alpha(v)*F(u,v)*cos (------- *u*PI)* cos (------ *v*PI)
& && && &u=0 v=0& && && && && && && && && && && &16& && && && && && & 16
x,y=0,1...7
& & 这个步骤很花时间, 另外有种 AA&N 优化算法, 大家可以去 inet 自己找一下.
在 Intel 主页上可以找到 AA&N IDCT 的 MMX 优化代码. ( Intel 主页上的代码,
输入数据为 12.4 的定点数, 输入矩阵需要转置 90 度)
3. 重排列 DCT 结果
& &&&DCT 将一个 8x8 的数组变换成另一个 8x8 的数组. 但是内存里所有数据都是线
形存放的, 如果我们一行行的存放这 64 个数字, 每行的结尾的点和下行开始的点就
没有什么关系, 所以 JPEG 规定按如下次序整理 64 个数字.
& && && && && && &0, 1, 5, 6,14,15,27,28,
& && && && && && &2, 4, 7,13,16,26,29,42,
& && && && && && &3, 8,12,17,25,30,41,43,
& && && && && && &9,11,18,24,31,40,44,53,
& && && && && &&&10,19,23,32,39,45,52,54,
& && && && && &&&20,22,33,38,46,51,55,60,
& && && && && &&&21,34,37,47,50,56,59,61,
& && && && && &&&35,36,48,49,57,58,62,63
& & 这样数列里的相邻点在图片上也是相邻的了.
& &&&对于前面得到的 64 个空间频率振幅值, 我们将对它们作幅度分层量化操作.方
法就是分别除以量化表里对应值并四舍五入.
for (i = 0 ; i&=63; i++ )
& &vector = (int) (vector / quantization_table + 0.5)
& & 下面有张 JPEG 标准量化表. (按上面同样的弯曲次序排列)
& & 16 11 10 16 24&&40&&51&&61
& & 12 12 14 19 26&&58&&60&&55
& & 14 13 16 24 40&&57&&69&&56
& & 14 17 22 29 51&&87&&80&&62
& & 18 22 37 56 68&&109 103 77
& & 24 35 55 64 81&&104 113 92
& & 49 64 78 87 103 121 120 101
& & 72 92 95 98 112 100 103 99
& & 这张表依据心理视觉阀制作, 对 8bit 的亮度和色度的图象的处理效果不错.
当然我们可以使用任意的量化表. 量化表是定义在 jpeg 的 DQT 标记后. 一般
为 Y 值定义一个, 为 C 值定义一个.
& & 量化表是控制 JPEG 压缩比的关键. 这个步骤除掉了一些高频量, 损失了很高
细节. 但事实上人眼对高空间频率远没有低频敏感.所以处理后的视觉损失很小.
另一个重要原因是所有的图片的点与点之间会有一个色彩过渡的过程. 大量的图象
信息被包含在低空间频率中. 经过量化处理后, 在高空间频率段, 将出现大量连续
& & 注意, 量化后的数据有可能超过 2 byte 有符号整数的处理范围.
5. 0 RLE 编码
& & 现在我们矢量中有许多连续的 0. 我们可以使用 RLE 来压缩掉这些 0. 这里我们
将跳过第一个矢量 (后面将解释为什么) 因为它的编码比较特别. 假设有一组矢量
(64 个的后 63 个) 是
& & 57,45,0,0,0,0,23,0,-30,-16,0,0,1,0,0,0, 0 , 0 ,0 , 0,..,0
经过 RLE 压缩后就是
& & (0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-16) ; (2,1) ; EOB
EOB 是一个结束标记, 表示后面都是 0 了. 实际上, 我们用 (0,0) 表示 EOB
但是, 如果这组数字不以 0 结束,&&那么就不需要 EOB.
& & 另外需要注意的是, 由于后面 huffman 编码的要求, 每组数字前一个表示 0 的
数量的必须是 4 bit, 就是说, 只能是 0~15, 所以, 如果有这么一组数字:
& & 57, 十八个0, 3, 0, 0, 0, 0, 2, 三十三个0, 895, EOB
我们实际这样编码:
& & (0,57) ; (15,0) (2,3) ; (4,2) ; (15,0) (15,0) (1,895) , (0,0)
注意 (15,0) 表示了 16 个连续的 0.
6. 范式 Huffman 编码
& & 为了提高储存效率, JPEG 里并不直接保存数值, 而是将数值按位数分成 16 组:
& && && && && &数值& && && && && &&&组& && && && &&&实际保存值
& && && && && & 0& && && && && && & 0& && && && && && & -
& && && && &&&-1,1& && && && && && &1& && && && && && &0,1
& && && &&&-3,-2,2,3& && && && && & 2& && && && &&&00,01,10,11
& &&&-7,-6,-5,-4,4,5,6,7& && && && &3& & 000,001,010,011,100,101,110,111
& && & -15,..,-8,8,..,15& && && && &4& && & 0000,..,,..,1111
& && &-31,..,-16,16,..,31& && && &&&5& &&&00000,..,,..,11111
& && &-63,..,-32,32,..,63& && && &&&6& && && && && && & .
& &&&-127,..,-64,64,..,127& && && & 7& && && && && && & .
& & -255,..,-128,128,..,255& && && &8& && && && && && & .
& & -511,..,-256,256,..,511& && && &9& && && && && && & .
& &-1023,..,-512,512,..,1023& && & 10& && && && && && & .
&&-2047,..,-,..,2047& && &11& && && && && && & .
&&-4095,..,-,..,4095& && &12& && && && && && & .
&&-8191,..,-,..,8191& && &13& && && && && && & .
-16383,..,-,..,16383& &&&14& && && && && && & .
-32767,..,-,..,32767& & 15& && && && && && & .
还是来看前面的例子:
& & (0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-8) ; (2,1) ; (0,0)
只处理每对数右边的那个:
& & 57 是第 6 组的, 实际保存值为 111001 , 所以被编码为 (6,111001)
& & 45 , 同样的操作, 编码为 (6,101101)
& & 23&&-&&&(5,10111)
& &-30&&-&&&(5,00001)
& & -8&&-&&&(4,0111)
& &&&1&&-&&&(1,1)
前面的那串数字就变成了:
& &(0,6), 111001 ; (0,6), 101101 ; (4,5), 10111; (1,5), 00001; (0,4) , 0111 ;
& && & (2,1), 1 ; (0,0)
括号里的数值正好合成一个字节. 后面被编码的数字表示范围是&&-3.
合成的字节里, 高 4 位是前续 0 的个数, 低 4 位描述了后面数字的位数.
继续刚才的例子, 如果 06 的 huffman 编码为 111000 ( 06 对应 111000 为查表所得.
jpeg 文件里保存了压缩时所产生的 huffman 表, 将 0~255 这 256 个 8 bits 定长数字,
对应成 1~16 bits 的不定长数值. 出现频率高的数字小于 8bits, 频率低的大于8bits,
从而使整个的数据长度降低, jpeg 实际使用的是范式 Huffman 编码(Canonical Huffman Code)
关于范式 huffman 编码的详细介绍, 请查阅相关资料 )
& && && && & 69 = (4,5)& & --- 1001&&( 注: 69=4*16+5=0x45 )
& && && && & 21 = (1,5)& & ---&&
& && && && & 4&&= (0,4)& & ---&&1011
& && && && & 33 = (2,1)& & ---&&11011
& && && && &&&0 = EOB = (0,0) ---&&1010
那么最后对于前面的例子表示的 63 个系数 (记得我们将第一个跳过了吗?) 按位流
写入 JPG 文件中就是这样的:
001&&101&&& & 00001
& &11011 1& &1010
7. DC 的编码
-----------
记得刚才我们跳过了每组 64 个数据的第一个吧, DC 就是指的这个数字 (后面 63
个简称 AC) 代入前面的 FDCT 公式可以得到
& && && && && & c(0,0)& &&&7& &7& && && && && && && && &&&
DC = F(0,0) = --------- * sum sum f(x,y) * cos 0 * cos 0 其中 c(0,0) = 1/2
& && && && && && &4& && & x=0 y=0& && && && && && && &&&
& && & 1& &&&7& &7& && && &
& &=&&--- * sum sum f(x,y)
& && & 8& & x=0 y=0& && &&&
即一块图象样本的平均值. 就是说, 它包含了原始 8x8 图象块里的很多能量. (通常
会得到一个很大的数值)
JPEG 的作者指出连续块的 DC 率之间有很紧密的联系,&&因此他们决定对 8x8 块的
DC 值的差别进行编码. (Y, Cb, Cr 分别有自己的 DC)
Diff = DC(i)&&- DC(i-1)
所以这一块的 DC(i) 就是:&&DC(i)&&= DC(i-1)&&+ Diff
JPG 从 0 开始对 DC 编码, 所以 DC(0)=0. 然后再将当前 Diff 值加在上一个值上得
下面再来看看上面那个例子: (记住我们保存的 DC 是和上一块 DC 的差值 Diff)
例如上面例子中, Diff 是 -511, 就编码成
& && && && && && &&&(9, )
如果 9 的 Huffman 编码是 1111110 (在 JPG 文件中, 一般有两个 Huffman 表, 一
个是 DC 用, 一个是 AC 用) 那么在 JPG 文件中, DC 的 2 进制表示为
& && && && && &000000
它将放在 63 个 AC 的前面, 上面上个例子的最终 BIT 流如下:
0111& &11011 1& &1010
解码过程简述
-------------
8. 一个数据单元 Y 的解码 (其余类同)
--------------------------------
在整个图片解码的开始, 你需要先初始化 DC 值为 0.
1) 先解码 DC:
& && && &a) 取得一个 Huffman 码 (使用 Huffman DC 表)
& && && &b) Huffman解码, 看看后面的数据位数 N
& && && &c) 取得 N 位, 计算 Diff 值
& && && &d) DC + = Diff
& && && &e) 写入 DC 值:& && && vector[0]=DC &
2) 解码 63 个 AC:
------- 循环处理每个 AC 直到 EOB 或者处理到 64 个 AC
& && & a) 取得一个 Huffman 码 (使用 Huffman AC 表)
& && & b) Huffman 解码, 得到 (前面 0 数量, 组号)
[记住: 如果是(0,0) 就是 EOB 了]
& && & c) 取得 N 位(组号) 计算 AC
& && & d) 写入相应数量的 0
& && & e) 接下来写入 AC
-----------------
下一步的解码
------------
上一步我们得到了 64 个矢量. 下面我们还需要做一些解码工作:
1) 反量化 64 个矢量 : &for (i=0;i&=63;i++) vector*=quant& (注意防止溢出)
2) 重排列 64 个矢量到 8x8 的块中
3) 对 8x8 的块作 IDCT
对 8x8 块的 (Y,Cb,Cr) 重复上面的操作 [Huffman 解码, 步骤 1), 2), 3)]
4) 将所有的 8bit 数加上 128
5) 转换 YCbCr 到 RGB
9. JPG 文件(Byte 级)里怎样组织图片信息
-----------------------------------
注意 JPEG/JFIF 文件格式使用 Motorola 格式, 而不是 Intel 格式, 就是说, 如果
是一个字的话, 高字节在前, 低字节在后.
JPG 文件是由一个个段 (segments) 构成的. 每个段长度 &=65535. 每个段从一个标
记字开始. 标记字都是 0xff 打头的, 以非 0 字节和 0xFF 结束. 例如 'FFDA' ,
'FFC4', 'FFC0'. 每个标记有它特定意义, 这是由第2字节指明的. 例如, SOS (Start
Of Scan = 'FFDA') 指明了你应该开始解码. 另一个标记 DQT (Define Quantization
Table = 0xFFDB) 就是说它后面有 64 字节的 quantization 表
在处理 JPG 文件时, 如果你碰到一个 0xFF, 而它后面的字节不是 0, 并且这个字节
没有意义. 那么你遇到的 0xFF 字节必须被忽略. (一些 JPG 里, 常用用 0xFF 做某
些填充用途) 如果你在做 huffman 编码时碰巧产生了一个 0xFF, 那么就用 0xFF
0x00 代替. 就是说在 jpeg 图形解码时碰到 FF00 就把它当作 FF 处理.
另外在 huffman 编码区域结束时, 碰到几个 bit 没有用的时候, 应该用 1 去填充.
然后后面跟 FF.
下面是几个重要的标记
--------------------
SOI = Start Of Image = 'FFD8'
这个标记只在文件开始出现一次
EOI = End Of Image = 'FFD9'
JPG 文件都以 FFD9 结束
RSTi = FFDi ( i =&&0..7)&&[ RST0 = FFD0, RST7=FFD7]
& &&&= 复位标记
通常穿插在数据流里, 我想是担心 JPG 解码出问题吧(应该配合 DRI 使用). RST 将
Huffman 的解码数据流复位. DC 也重新从 0 开始计
(SOS --- RST0 --- RST1 -- RST2 --...
...-- RST6 --- RST7 -- RST0 --...)
下面是必须处理的标记
SOF0 = Start Of Frame 0 = FFC0
SOS&&= Start Of Scan& & = FFDA
APP0 = it's the marker used to identify a JPG file which uses the JFIF
& & specification& && & = FFE0
COM&&= Comment& && && & = FFFE
DNL&&= Define Number of Lines& & = FFDC
DRI&&= Define Restart Interval& &= FFDD
DQT&&= Define Quantization Table = FFDB
DHT&&= Define Huffman Table& && &= FFC4
11. JPG 文件中 Haffman 表的储存
-----------------------------
JPEG 里定义了一张表来描述 Haffman 树. 定义在 DHT 标记后面. 注意: Haffman
代码的长度限制在 16bit 内.
一般一个 JPG 文件里会有 2 类 Haffman 表: 一个用于 DC 一个用于 AC (实际有 4
个表, 亮度的 DC,AC 两个, 色度的 DC,AC 两个)
这张表是这样保存的:
1) 16 字节:
第 i 字节表示了 i 位长的 Huffman 代码的个数 (i= 1 到 16)
& && && && && && && && && && && && && &&&
2) 这表的长度 (字节数) = 这 16 个数字之和
现在你可以想象这张表怎么存放的吧? 对应字节就是对应 Haffman 代码等价数字. 我
不多解释, 这需要你先了解 Canonical Huffman Code. 这里只举一个例子:
Haffman 表的表头是 0,2,3,1,1,1,0,1,0,0,0,0,0,0,0,0
就是说长度为 1 的代码没有
长度为 2 的代码为 00
& && && && && &&&01
长度为 3 的代码是 100
& && && && && &&&101
& && && && && &&&110
长度为 4 的代码是 1110
长度为 5 的代码是 11110
长度为 6 的代码是 111110
长度为 7 的代码没有 (如果有一个的话应该是 1111110)
长度为 8 的代码是
& && && &.....
后面都没有了.
如果表下面的数据是
& & 45 57 29 17 23 25 34 28
& & 45 = 00
& & 57 = 01
& & 29 = 100
& & 17 = 101
& & 23 = 110
使用 Canonical Huffman Code 的好处在于可以很简洁的重建对应关系表.
12. 采样系数
-----------
下面讲解的都是真彩 JPG 的解码, 灰度 JPG 的解码很简单, 因为图形中只有亮度信
息. 而彩色图形由 (Y, Cr, Cb) 构成, 前面提到过, Y 通常是每点采样一次, 而 Cr,
Cb 一般是 2x2 点采样一次, 当然也有的 JPG 是逐点采样, 或者每两点采样 (横向
两点, 纵向一点) 采样系数均被定义成对比最高采样系数的相对值.
一般情况 (即: Y 逐点采样, Cr Cb 每 2x2 点一次) 下: Y 有最高的采样率, 横向采
样系数HY=2 纵向采样系数 VY=2; Cb 的横向采样系数 HCb=1, 纵向采样系数 VCb=1;
同样 HCr=1, VCr=1
在 Jpeg 里, 8x8 个原始数据, 经过 RLE, Huffman 编码后的一串数据流称为一个
Data Unit (DU) JPG 里按 DU 为单位的编码次序如下:
& &&&1)& && &for&&(counter_y=1;counter_y&=VY;counter_y++)
& && && && && && &for (counter_x=1;counter_x&=HY;counter_x++)
& && && && && && && &{&&对 Y 的 Data Unit 编码 }
& &&&2)& && &for&&(counter_y=1;counter_y&=VCcounter_y++)
& && && && && && &for (counter_x=1;counter_x&=HCb;counter_x++)
& && && && && && && &{&&对 Cb 的 Data Unit 编码 }
& &&&3)& && &for&&(counter_y=1;counter_y&=VCr;counter_y++)
& && && && && && &for (counter_x=1;counter_x&=HCr;counter_x++)
& && && && && && && &{&&对 Cr 的 Data Unit 编码 }
按我上面的例子: (HY=2, VY=2 ; HCb=VCb =1, HCr,VCr=1) 就是这样一个次序
& & YDU,YDU,YDU,YDU,CbDU,CrDU
这些就描述了一块 16x16 的图形. 16x16 = (Hmax*8 x Vmax*8) 这里 Hmax=HY=2
一个 (Hmax*8,Vmax*8) 的块被称作 MCU (Minimun Coded Unix) 前面例子中一个
MCU = YDU,YDU,YDU,YDU,CbDU,CrDU
如果&&HY =1, VY=1
& && &HCb=1, VCb=1
& && &HCr=1, VCr=1
这样 (Hmax=1,Vmax=1), MCU 只有 8x8 大, MCU = YDU,CbDU,CrDU
对于灰度 JPG, MCU 只有一个 DU (MCU = YDU)
JPG 文件里, 图象的每个组成部分的采样系数定义在 SOF0 (FFC0) 标记后
13. 简单说一下 JPG 文件的解码
-------------------------
解码程序先从 JPG 文件中读出采样系数, 这样就知道了 MCU 的大小, 算出整个图象
有几个 MCU. 解码程序再循环逐个对 MCU 解码, 一直到检查到 EOI 标记. 对于每个
MCU, 按正规的次序解出每个 DU, 然后组合, 转换成 (R,G,B) 就 OK 了
附:JPEG 文件格式
~~~~~~~~~~~~~~~~
&&- 文件头 (2 bytes):&&$ff, $d8 (SOI) (JPEG 文件标识)
&&- 任意数量的段 , 见后面
&&- 文件结束 (2 bytes): $ff, $d9 (EOI)
&&- header (4 bytes):
& && & $ff& &&&段标识
& && &&&n& && &段的类型 (1 byte)
& && & sh, sl&&该段长度, 包括这两个字节, 但是不包括前面的 $ff 和 n.
& && && && && &注意: 长度不是 intel 次序, 而是 Motorola 的, 高字节在前,
& && &&&低字节在后!
&&- 该段的内容, 最多 65533 字节
&&- 有一些无参数的段 (下面那些前面注明星号的)
& & 这些段没有长度描述 (而且没有内容), 只有 $ff 和类型字节.
&&- 段之间无论有多少 $ff 都是合法的, 必须被忽略掉.
& &*TEM& &= $01& &可以忽略掉
& & SOF0&&= $c0& &帧开始 (baseline JPEG), 细节附后
& & SOF1&&= $c1& &dito
& & SOF2&&= $c2& &通常不支持
& & SOF3&&= $c3& &通常不支持
& & SOF5&&= $c5& &通常不支持
& & SOF6&&= $c6& &通常不支持
& & SOF7&&= $c7& &通常不支持
& & SOF9&&= $c9& &arithmetic 编码(Huffman 的一种扩展算法), 通常不支持
& & SOF10 = $ca& &通常不支持
& & SOF11 = $cb& &通常不支持
& & SOF13 = $cd& &通常不支持
& & SOF14 = $ce& &通常不支持
& & SOF14 = $ce& &通常不支持
& & SOF15 = $cf& &通常不支持
& & DHT& &= $c4& &定义 Huffman Table,&&细节附后
& & JPG& &= $c8& &未定义/保留 (引起解码错误)
& & DAC& &= $cc& &定义 Arithmetic Table, 通常不支持
& &*RST0&&= $d0& &RSTn 用于 resync, 通常被忽略
& &*RST1&&= $d1
& &*RST2&&= $d2
& &*RST3&&= $d3
& &*RST4&&= $d4
& &*RST5&&= $d5
& &*RST6&&= $d6
& &*RST7&&= $d7
& & SOI& &= $d8& &图片开始
& & EOI& &= $d9& &图片结束
& & SOS& &= $da& &扫描行开始, 细节附后
& & DQT& &= $db& &定义 Quantization Table, 细节附后
& & DNL& &= $dc& &通常不支持, 忽略
& & DRI& &= $dd& &定义重新开始间隔, 细节附后
& & DHP& &= $de& &忽略 (跳过)
& & EXP& &= $df& &忽略 (跳过)
& & APP0&&= $e0& &JFIF APP0 segment marker (细节略)
& & APP15 = $ef& &忽略
& & JPG0&&= $f0& &忽略 (跳过)
& & JPG13 = $fd& &忽略 (跳过)
& & COM& &= $fe& &注释, 细节附后
其它的段类型都保留必须跳过
SOF0: Start Of Frame 0:
~~~~~~~~~~~~~~~~~~~~~~~
&&- $ff, $c0 (SOF0)
&&- 长度 (高字节, 低字节), 8+components*3
&&- 数据精度 (1 byte) 每个样本位数, 通常是 8 (大多数软件不支持 12 和 16)
&&- 图片高度 (高字节, 低字节), 如果不支持 DNL 就必须 &0
&&- 图片宽度 (高字节, 低字节), 如果不支持 DNL 就必须 &0
&&- components 数量(1 byte), 灰度图是 1, YCbCr/YIQ 彩色图是 3, CMYK 彩色图
&&- 每个 component: 3 bytes
& &&&- component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q)
& &&&- 采样系数 (bit 0-3 vert., 4-7 hor.)
& &&&- quantization table 号
DRI: Define Restart Interval:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&&- $ff, $dd (DRI)
&&- 长度 (高字节, 低字节), 必须是 4
&&- MCU 块的单元中的重新开始间隔 (高字节, 低字节),
& & 意思是说, 每 n 个 MCU 块就有一个 RSTn 标记.
& & 第一个标记是 RST0, 然后是 RST1 等, RST7 后再从 RST0 重复
DQT: Define Quantization Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&&- $ff, $db (DQT)
&&- 长度 (高字节, 低字节)
&&- QT 信息 (1 byte):
& &&&bit 0..3: QT 号(0..3, 否则错误)
& &&&bit 4..7: QT 精度, 0 = 8 bit, 否则 16 bit
&&- n 字节的 QT, n = 64*(精度+1)
&&- 一个单独的 DQT 段可以包含多个 QT, 每个都有自己的信息字节
&&- 当精度=1 (16 bit), 每个字都是高位在前低位在后
DAC: Define Arithmetic Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
法律原因, 现在的软件不支持 arithmetic 编码.
不能生产使用 arithmetic 编码的 JPEG 文件
DHT: Define Huffman Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~
&&- $ff, $c4 (DHT)
&&- 长度 (高字节, 低字节)
&&- HT 信息 (1 byte):
& &&&bit 0..3: HT 号 (0..3, 否则错误)
& &&&bit 4& &: HT 类型, 0 = DC table, 1 = AC table
& &&&bit 5..7: 必须是 0
&&- 16 bytes: 长度是 1..16 代码的符号数. 这 16 个数的和应该 &=256
&&- n bytes: 一个包含了按递增次序代码长度排列的符号表
& & (n = 代码总数)
&&- 一个单独的 DHT 段可以包含多个 HT, 每个都有自己的信息字节
COM: 注释:
~~~~~~~~~~
&&- $ff, $fe (COM)
&&- 注释长度 (高字节, 低字节) = L+2
&&- 注释为长度为 L 的字符流
SOS: Start Of Scan:
~~~~~~~~~~~~~~~~~~~
&&- $ff, $da (SOS)
&&- 长度 (高字节, 低字节), 必须是 6+2*(扫描行内组件的数量)
&&- 扫描行内组件的数量 (1 byte), 必须 &= 1 , &=4 (否则是错的) 通常是 3
&&- 每个组件: 2 bytes
& &&&- component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q), 见 SOF0
& &&&- 使用的 Huffman 表:
- bit 0..3: AC table (0..3)
- bit 4..7: DC table (0..3)
&&- 忽略 3 bytes (???)
&&- 图片数据 (一个个扫描行) 紧接着 SOS 段.
程序设计,算法为王。
提出问题;分析问题;确定算法;画出流程图;编辑程序;调试程序;建立文档资料。
大家在开发板块贴代码的时候,请使用“插入代码”的功能。
[code]int main(){return 0;}[/code]
最后说明一下,如果不是搞文件结构的话,所有的图片文件都有对应的处理显示用的接口或类。
重复造轮子的工作吃力不讨好。
程序设计,算法为王。
提出问题;分析问题;确定算法;画出流程图;编辑程序;调试程序;建立文档资料。
大家在开发板块贴代码的时候,请使用“插入代码”的功能。
[code]int main(){return 0;}[/code]
要是用标准的C语言是不是就没有接口和类了?
你要做的东西都需要一个系统平台,比如在DOS、WINDOWS、LINUX等操作系统上编程,那么在该平台上,别人都会做好一些函数和结构体用来打开显示图形的,比如LINUX下你会用到GNOME,WINDOWS下用WIN32API,等等。
不要被那些C++什么类和接口蒙蔽,了解一下GNOME和GDI,你就知道C语言是怎么显示图形的了。
标准C语言只是定义了一些基本规范和函数,图形方面的函数都是系统厂商提供的。
程序设计,算法为王。
提出问题;分析问题;确定算法;画出流程图;编辑程序;调试程序;建立文档资料。
大家在开发板块贴代码的时候,请使用“插入代码”的功能。
[code]int main(){return 0;}[/code]
dos下显示图片
在C语言中,我们也可以给软件加上一个好的封面,这会给你的程序添色不少。
&&·BMP文件的存储格式
&&·DOS方式下调用BMP图像的手段
&&·艺术再现BMP图像
BMP文件的存储格式
BMP文件是标准的Windows位图文件,有16色、256色、16位真彩色及24位真彩色等格式。客观存在按文件头、图像控制信息、彩色表和位图点阵数据的格式来存储。文件头是定义图像文件的类型、长度等的数据结构:图像控制信息是定义图像颜色格式、图像大小、颜色数等的数据结构:彩色表是定义图像颜色的调色板的数组位图点阵,是定义图像数据的数组。
未经压缩的BMP文件中,位图点阵信息是按扫描线从下至上(bottom to top)存储的,即图像的第一个像素值在位图阵列的左下角,最后一个像素值在位图阵列的右上角。对16色位图,每个像素占4位,每个字节存放相邻的两个像素值,高4位存放的第1个像素值在扫描线的前面,低4位存放的第2个像素值在扫描线后面。对256色位图,1个字节存放1个像素值。对24位位图,颜色表为空,位图数据的每3个字节对应1个像素值,其中每个字节分别对应该像素值的P、R、G值。
DOS方式下调用BMP图像的手段
再现一副非压缩静止位图,主要需下面三个步骤:
·设置显示模式;
·打开位图文件,读取图像控制信息,设置调色板;
·读取位图数据度进行显示。
若图像数据是以堵塞压缩的,那么先解压,然后再按上面的步骤进行。
设置显示模式
&&随着计算机硬件的不断发展,尤其是显示卡和显示椿性能的提高,显示效果越来越好。图像显示效果主要体现在图像分辨率和颜色两个方面,分辨率反映图像的清晰和谐,而颜色则反映了图像与物体本来颜色的逼真程度。虽然,对一个图形图像界面的评价涉及人的审美观,心理因素等主观原因,但也有客观的标准。高分辨率和真彩色是人分辨率追求的最高目标。现在,性能好的显示卡和显示器(如SUPER VGA)能支持高达的分辨率,可以表示的颜色数目可达2:4种。对于DOS用户而言,常用的是640X480分辨率/16色、320X200分辨率/256色和640X480分辨率/256色等几种模式,它们分别是VGA/TVGA中的12h、13h和5dh模式。可通过直接调用DOS的10h中断来设置:
&&相应的函数定义如下:复制内容到剪贴板代码:&&int Set640_480 (void)
& & asm mov ax,4fO2h
& & asm mov bx,OlOlh
& & asm int lob
& & if((_AL==0x4f)&&(_AH==0))
& && &return(0);
&&return(1)
&&}调色板的设置
&&在DOS环境下显示Windows位图时,由于DOS调色板与Windows调色板不同,因此需自行设置Windows调色板,这样,图像才能不失真地显示所需的颜色并与原图像颜色相匹配。具体操作是从图像文件中读出彩色表数值,调用函数int86x写入Windows调色板控制区域。
&&相应的函数定义如下:复制内容到剪贴板代码:&&void set_windows_palette16(unsigned char bmp_top[])
&&/*设置调色板*/
&&unsigned char chg[]={0,1,2,3,4,5,20,7,56,57,58,59,60,61,62,63};
&&int f[16]={0,4,2,6,1,5,3,8,7,12,10,14,9,13,11,15 };
&&for(i=O;i&-I 5;i++)
& & (outportb(Ox3c8,chg[f]);
& & outportb(Ox3c9,bmp top[54+i*4+2]/4);
& & outportb(Ox3c9,bmp_top[5,~+i*4+ 1 ]/4);
& & outportb(Ox3c9 ,bmp top [54+i* 4~-0]/4);}
int bmp_out(int x,int y,char *bmp_name)
&&/*打开文件名为*bmp_name的文件,在(x,y)位置输出图像*/
&&int i,j,k,l=0,c1,c2,x1,y1;
&&unsigned char h,bmp_top[ 128],w,b=0x80,x0;
&&char far *ptr=-(char far *)0xa0000000;
&&char far *p;
&&int fi16]={0,4,2,6,1,5,3,8,7,12,10,14,9,13,11,15 };
&&if((fp=fopen(bmp name,&rb&))==NULL) return(1)
&&fread(bmp_top,118,1,fp);
&&set_windows_palette16(bmp_top);
&&xl=bmp_top[18]+bmp_top[19]*256;
&&y1=bmp_top[22]+bmp_top[23]*256;
&&c1=(8-x1%8)/2; c2=x1%8;
&&x0=b&&(x%8);
&&ptr+=(rdS+80*(y+yl ));
&&outportb(Ox3ce,5);outportb(Ox3cf, 2);
&&for(i=O;i&yl i++)
& & j=0;b=x0;
& & for(l=0;l&x1;l+=2)
& && &&&h=getc(fp);
& && &&&outportb(Ox3ce,8);outportb(Ox3cf,b);b&&=1;
& && &&&p=ptr-i*80+j;
& && &&&w=*p;
& && &&&*p=f[h&&4];
& && &&&if(!b) {b=OxSO;j++; }
& && &&&if(x1%2&&l==x1-1)
& && &&&outportb(Ox3ce,8);outportb(Ox3cf,b);b&&= 1
& && &&&p=ptr-i*80+j;
& && &&&w=*p;
& && &&&*p=f[h&OxOf];
& && &&&if(!b) {b=Ox80;j++;}
& && &if(c2) for(k--O;k&c1 k++) getc(fp);
&&outportb(Ox3ce,8);outportb(Ox3cf,255);
&&outportb(Ox3ce,5) outportb(Ox3cf,O);
&&fclose(fp);
&&return(O);}图像再现
&&下面我们来看一个例子,调出一幅BMP图像。复制内容到剪贴板代码:#include &conio.h&
#include &stdio.h&
#include &dos.h&
#include &stdlib.h&
#define lengthlimit 640
#define& &highlimit 480
int Set640_480 (void)
asm mov ax,4f02h
asm mov bx,0101h
asm int 10h
if((_AL==0x4f)&&(_AH==0))
&&return(0);
return(1);
void Set_Page(int page)
asm mov ax,4f05h
asm mov bx,0
asm mov dx,page
asm int 10h
void myputpixel (int row,int col,unsigned char color)
/*(row,col)画点的坐标,color画点颜色*/
static int totalpage=0;
dantance=1l*col*lengthlimit+
y=(unsigned)(dantance&0X0000ffffl);
page=(int)(1.0*dantance/65536);
if (totalpage!=page) { totalpage= Set_Page(page); }
& & mov ax,0a000h
& & mov es,ax
& & mov si,y
& & mov al,color
& & mov es:[si],al
void bmpout(char *bmpstr)
/* 打开文件名为*bmpstr的BMP文件,输出图象*/
struct bmp{
& && &long biwidth
struct DAC{
struct DAC dacp[256];
int colorcount,x,y,i,j,x0=0,y0=470,k,bibit,
char resev,buf1
Set640_480();
if((bmpfp=fopen(bmpstr,&rb&))==NULL)
printf(&can't open file&);
fread(&bmpp,sizeof(bmpp),1,bmpfp);
fseek(bmpfp,28l,SEEK_SET);
fread(&bibit,2,1,bmpfp);
fseek(bmpfp,46l,SEEK_SET);
fread(&colorcount,sizeof(colorcount),1,bmpfp);
if (colorcount==0) { colorcount=256;}
fseek (bmpfp,54l,SEEK_SET);
for (i=0;i&i++)
&&fread(&dacp,3,1,bmpfp);
&&fread(&resev,1,1,bmpfp);
for(i=0;i&i++)
&&pp=dacp.red&&2;
&&dacp.red=dacp.blue&&2;
&&dacp.blue=
&&dacp.green=(dacp.green&&2);
asm push es
_ES=FP_SEG(dacp);
_DX=FP_OFF (dacp);
asm mov bx,0
asm mov cx,colorcount
asm mov ah,10h
asm mov al,12h
asm int 10h
asm pop es
fseek(bmpfp,bmpp.bfoff,SEEK_SET);
buf=malloc(bmpp.biwidth);
for(i=0;i&bmpp.i++)
&&fread(buf,bmpp.biwidth,1,bmpfp);
&&for( j=x0;j&x0+bmpp.j++)
&&myputpixel(j,y,*((unsigned char*)buf+j));
free(buf);
fclose(bmpfp);
delay(500);
void main()
bmpout(&*.bmp&); /* 打开某一BMP文件并输出图象*/
}下例采用了随即函数产生点的颜色,输出到屏幕缓冲区,得到迷幻的图像。复制内容到剪贴板代码:#include &stdio.h&
#include &dos.h&
#include &math.h&
long Addr[768];
Set_Mode (int mode)
&&union REGS
&&r.h.ah=0;
&&int86 (0x10,&r,&r);
Set_Graphics_Mode (unsigned x,unsigned y)
&&if ((x&321)&&(y&201)) {
& & Set_Mode (0x13);
& & Mode=0x13;
& & for (i=0;i&200;i++) Addr=320*i;
&&else if ((x&641)&&(y&401)) {
& & Set_Mode (0x5c);
& & Mode=0x5c;
& & for (i=0;i&400;i++) Addr=640*i;
&&else if ((x&641)&&(y&481)) {
& & Set_Mode (0x5d);
& & Mode=0x5d;
& & for (i=0;i&480;i++) Addr=640*i;
&&else if ((x&641)&&(y&481)) {
& & Set_Mode (0x5d);
& & Mode=0x5d;
& & for (i=0;i&480;i++) Addr=640*i;
&&else if ((x&801)&&(y&601)) {
& & Set_Mode (0x5e);
& & Mode=0x5e;
& & for (i=0;i&600;i++) Addr=800*i;
&&else if ((x&1025)&&(y&769)) {
& & Set_Mode (0x62);
& & Mode=0x62;
& & for (i=0;i&768;i++) Addr=1024*i;
& & Set_Mode (3);
& & printf (&Not support this mode .\n&);
& & getch ();
set_pattern ()
&&unsigned char pat[256][3];
&&struct SREGS
&&union REGS
&&pat[0][0]=0;pat[0][1]=0;pat[0][2]=0;
&&for (i=1;i&=255;i++) {
& & pat[0]=(unsigned char)((float)(abs(i-127)*63)/127.0+0.5);
& & pat[1]=(unsigned char)((float)(abs(i-127)*63)/127.0+0.5);
& & pat[2]=63;
&&reg.x.ax=0x1012;
&&reg.x.bx=0;
&&reg.x.cx=256;
&&reg.x.dx=FP_OFF(pat);
&&inreg.es=FP_SEG(pat);
&&int86x (0x10,?,?,&inreg);
plot (int x,int y,unsigned char color)
&&unsigned char far *
&&switch (Mode) {
& & case 0x13:
& && &&&offset=Addr[y]+x;
& && &&&address=(unsigned char far *)(0xa0000000L+offset);
& && &&&*address=
& & case 0x5c:
& & case 0x5d:
& & case 0x5e:
& && &&&offset=Addr[y]+x;
& && &&&Page=(offset&&16);
& && &&&outportb (0x3c4,0xe);
& && &&&outportb (0x3c5,Page^0x02);
& && &&&offset=offset&65535;
& && &&&address=(unsigned char far *)(0xa0000000L+offset);
& && &&&*address=
& & case 0x62:
& && &&&offset=Addr[y]+x;
& && &&&Page=y&&6;
& && &&&outportb (0x3c4,0xe);
& && &&&outportb (0x3c5,Page^0x02);
& && &&&offset=offset&65535;
& && &&&address=(unsigned char far *)(0xa0000000L+offset);
& && &&&*address=
& & default:
get_pixel (int x,int y)
&&unsigned char far *
&&switch (Mode) {
& & case 0x13:
& && &&&offset=Addr[y]+x;
& && &&&address=(unsigned char far *)(0xa0000000+offset);
& && &&&color=*
& & case 0x5c:
& & case 0x5d:
& & case 0x5e:
& && &&&offset=Addr[y]+x;
& && &&&Page=(offset&&16);
& && &&&outportb (0x3c4,0xe);
& && &&&outportb (0x3c5,Page^0x02);
& && &&&offset=offset&65535;
& && &&&address=(unsigned char far *)(0xa0000000L+offset);
& && &&&color=*
& & case 0x62:
& && &&&offset=Addr[y]+x;
& && &&&Page=y&&6;
& && &&&outportb (0x3c4,0xe);
& && &&&outportb (0x3c5,Page^0x02);
& && &&&offset=offset&65535;
& && &&&address=(unsigned char far *)(0xa0000000L+offset);
& && &&&color=*
& & default:
&&return (color);
randint (unsigned int range)
&&float sigma=423.1966;
&&static double OldRand=0.4231967;
&&temp=sigma*OldR
&&OldRand=temp-(int)
&&return (int)(OldRand*(float)range);
void New_Col (int xa,int ya,int x,int y,int xb,int yb)
&&color=abs(xa-xb)+abs(ya-yb);
&&color=randint(color&&1)-
&&color=color+(get_pixel(xa,ya)+get_pixel(xb,yb)+1)&&1;
&&if (color&1) color=1;
&&else if (color&255) color=255;
&&if ((get_pixel(x,y)==0)) plot (x,y,color);
void Sub_Divide (int x1,int y1,int x2,int y2)
&&int x,y;
&&if (!((x2-x1&2)&&(y2-y1&2))) {
& & x=(x1+x2)&&1;
& & y=(y1+y2)&&1;
& & New_Col (x1,y1,x,y1,x2,y1);
& & New_Col (x2,y1,x2,y,x2,y2);
& & New_Col (x1,y2,x,y2,x2,y2);
& & New_Col (x1,y1,x1,y,x1,y2);
& & color=(get_pixel(x1,y1)+get_pixel(x2,y1)+get_pixel(x2,y2)+get_pixel (x1,y2)+2)&&2;
& & plot (x,y,color);
& & Sub_Divide (x1,y1,x,y);
& & Sub_Divide (x,y1,x2,y);
& & Sub_Divide (x,y,x2,y2);
& & Sub_Divide (x1,y,x,y2);
&&int x,y;
&&x=320;y=200;
&&Set_Graphics_Mode (x,y);
&&set_pattern ();
&&plot (0,0,randint(254)+1);
&&plot (x-1,0,randint(254)+1);
&&plot (x-1,y-1,randint(254)+1);
&&plot (0,y-1,randint(254)+1);
&&Sub_Divide (0,0,x-1,y-1);
&&getch();
&&Set_Mode (0x03);
程序设计,算法为王。
提出问题;分析问题;确定算法;画出流程图;编辑程序;调试程序;建立文档资料。
大家在开发板块贴代码的时候,请使用“插入代码”的功能。
[code]int main(){return 0;}[/code]
请使用IJG库,以便操作Jpg图像,至于BMP,则非常容易。关于IJG库的编译和使用,可以参考我博客中的那篇文章
想问一下为什么
typedef struct tagBITMAPINFO { /* bmi */
HBITMAPINFOHEADER bmiH
RGBQUAD bmiColors[1];
} BITMAPINFO;&&
里面bmiColors的数组大小设为1?
这是不是就意味着调色板只有一组值?可是对于256色的来说调色板要有256组值啊?
不是就溢出了么?
BITMAPINFO结构由BITMAPINFOHEADER结构和两个或更多个RGBQUAD结构所组成,当你用到多个索引的时候就用多个RGBQUAD结构。
程序设计,算法为王。
提出问题;分析问题;确定算法;画出流程图;编辑程序;调试程序;建立文档资料。
大家在开发板块贴代码的时候,请使用“插入代码”的功能。
[code]int main(){return 0;}[/code]
RGBQUAD是一个结构体,定义如下:复制内容到剪贴板代码: typedef struct tagRGBQUAD {
} RGBQUAD;
程序设计,算法为王。
提出问题;分析问题;确定算法;画出流程图;编辑程序;调试程序;建立文档资料。
大家在开发板块贴代码的时候,请使用“插入代码”的功能。
[code]int main(){return 0;}[/code]
怎么体现出“两个或多个的”?
RGBQUAD bmiColors[1]; 不是说明只有一个么?
原帖由 hagejid 于
16:29 发表
你要做的东西都需要一个系统平台,比如在DOS、WINDOWS、LINUX等操作系统上编程,那么在该平台上,别人都会做好一些函数和结构体用来打开显示图形的,比如LINUX下你会用到GNOME,WINDOWS下用WIN32API,等等。
不要被那些C++什么类 ...
请你把“位图信息头”这一部分看一遍
(3) ClrUsed
BITMAPINFOHEADER结构中的成员ClrUsed指定实际使用的颜色数目。如果ClrUsed设置成0,位图使用的颜色数目就等于biBitCount成员中的数目。请注意,如果ClrUsed的值不是可用颜色的最大值或不是0,则在编程时应该注意调色板尺寸的计算,比如在4位位图中,调色板的缺省尺寸应该是16*sizeof(RGBQUAD),但是,如果ClrUsed的值不是16或者不是0,那么调色板的尺寸就应该是ClrUsed*sizeof(RGBQUAD)。
程序设计,算法为王。
提出问题;分析问题;确定算法;画出流程图;编辑程序;调试程序;建立文档资料。
大家在开发板块贴代码的时候,请使用“插入代码”的功能。
[code]int main(){return 0;}[/code]
研究了一下bmp格式,用C语言写了出来,只是读取文件信息,更改颜色,保存更改后的结果这结果最简单的功能,我把代码贴上来,大家帮忙看看,新手代码写的不好。复制内容到剪贴板代码:#include &stdio.h&
#include &stdlib.h&
typedef struct tagBITMAPFILEHEADER
& & & & unsigned short bfT& & & & //The map type of this file, bmp should be BM
& & & & unsigned long bfS& & & & //Size of this file
& & & & unsigned short bfReserved1;
& & & & unsigned short bfReserved2;
& & & & unsigned long bfOffB& & & & //The offset of the data in bytes
}BITMAPFILEHEADER;
typedef struct tagBIMAPINFOHEADER
& & & & unsigned long biS
& & & & unsigned long biW& & & & //Width of the picture
& & & & unsigned long biH& & & & //Height of the picture
& & & & unsigned short biP
& & & & unsigned short biBitC& & & & //The bits used to represents a pixel
& & & & unsigned long biC& & & & //Type of compression
& & & & unsigned long biSizeI
& & & & unsigned long biXPelsPerM
& & & & unsigned long biYPelsPerM
& & & & unsigned long biClrU
& & & & unsigned long biClrI
}BITMAPINFOHEADER;
typedef struct tagRGBQUAD
& & & & unsigned char rgbB
& & & & unsigned char rgbG
& & & & unsigned char rgbR
& & & & unsigned char rgbR
typedef struct tagBITMAPINFO
& & & & BITMAPINFOHEADER bmiH
& & & & RGBQUAD bmiColors[256];
}BITMAPINFO;
void main(){
& & & & FILE *
& & & & FILE *fp1;
& & & & char filename[50];& & & & //The path of the file
& & & & BITMAPFILEHEADER bmpHeader1;
& & & & BITMAPINFO bmpHeader2;
//& & & & RGBQUAD oldC& & & &
//& & & & RGBQUAD& & & & newC
& & & & unsigned int tempColor[3]={0,0,0},oldColor1[3],newColor1[3];& & & & //Used in 24-bits map calculation
& & & & int oldIndex=0,newIndex=0;& & & & //Get the user input of color index
& & & & int& & & & Index161 = 0,Index162 =0;& & & & //Seperate 1 byte into two parts, used in 16-bit map
& & & && & & & //Counter
& & & & int colorValue=0;& & & & //Index read out from the file
& & & & printf(&\nPlease input the file path:&);
& & & & gets(filename);
& & & & if((fp = fopen(filename,&rb&)) == NULL){
& & & & & & & & printf(&Failed tp open this file.\n&);
& & & & & & & & exit(1);
& & & & fp1 = fopen(&modified.bmp&,&wb&);
& & & & /* The file header information*/
& & & & fread(&bmpHeader1.bfType,2,1,fp);
& & & & fwrite(&bmpHeader1.bfType,2,1,fp1);
& & & & fread(&bmpHeader1.bfSize,4,1,fp);
& & & & fwrite(&bmpHeader1.bfSize,4,1,fp1);
& & & & fread(&bmpHeader1.bfReserved1,2,1,fp);
& & & & fwrite(&bmpHeader1.bfReserved1,2,1,fp1);
& & & & fread(&bmpHeader1.bfReserved2,2,1,fp);
& & & & fwrite(&bmpHeader1.bfReserved2,2,1,fp1);
& & & & fread(&bmpHeader1.bfOffBits,4,1,fp);
& & & & fwrite(&bmpHeader1.bfOffBits,4,1,fp1);
& & & & /*The bitmap header information*/
& & & & fread(&bmpHeader2.bmiHeader.biSize,4,1,fp);
& & & & fwrite(&bmpHeader2.bmiHeader.biSize,4,1,fp1);
& & & & fread(&bmpHeader2.bmiHeader.biWidth,4,1,fp);
& & & & fwrite(&bmpHeader2.bmiHeader.biWidth,4,1,fp1);
& & & & fread(&bmpHeader2.bmiHeader.biHeight,4,1,fp);
& & & & fwrite(&bmpHeader2.bmiHeader.biHeight,4,1,fp1);
& & & & fread(&bmpHeader2.bmiHeader.biPlanes,2,1,fp);
& & & & fwrite(&bmpHeader2.bmiHeader.biPlanes,2,1,fp1);
& & & & fread(&bmpHeader2.bmiHeader.biBitCount,2,1,fp);
& & & & fwrite(&bmpHeader2.bmiHeader.biBitCount,2,1,fp1);
& & & & fread(&bmpHeader2.bmiHeader.biCompression,4,1,fp);
& & & & fwrite(&bmpHeader2.bmiHeader.biCompression,4,1,fp1);
& & & & fread(&bmpHeader2.bmiHeader.biSizeImage,4,1,fp);
& & & & fwrite(&bmpHeader2.bmiHeader.biSizeImage,4,1,fp1);
& & & & fread(&bmpHeader2.bmiHeader.biXPelsPerMeter,4,1,fp);
& & & & fwrite(&bmpHeader2.bmiHeader.biXPelsPerMeter,4,1,fp1);
& & & & fread(&bmpHeader2.bmiHeader.biYPelsPerMeter,4,1,fp);
& & & & fwrite(&bmpHeader2.bmiHeader.biYPelsPerMeter,4,1,fp1);
& & & & fread(&bmpHeader2.bmiHeader.biClrUsed,4,1,fp);
& & & & fwrite(&bmpHeader2.bmiHeader.biClrUsed,4,1,fp1);
& & & & fread(&bmpHeader2.bmiHeader.biClrImportant,4,1,fp);
& & & & fwrite(&bmpHeader2.bmiHeader.biClrImportant,4,1,fp1);
& & & & switch(bmpHeader2.bmiHeader.biBitCount)
& & & & /*For the 2-bit map*/
& & & & case 1:
& & & & & & & & fseek(fp,54L,0);
& & & & & & & & for(i=0;i&8;i++)
& & & & & & & & {
& & & & & & & & & & & & fread(&colorValue,1,1,fp);
& & & & & & & & & & & & fwrite(&colorValue,1,1,fp1);
& & & & & & & & }
& & & & & & & &
& & & & & & & & printf(&\nThis image has 2 colors, which one do you want to change?(0 for black and 1 for white)&);
& & & & & & & & while(scanf(&%d&,&oldIndex) != 1 || oldIndex != 0 || oldIndex != 1)
& & & & & & & & {
& & & & & & & & & & & & getchar();
& & & & & & & & & & & & printf(&\nIt's an invalid value! Please input again:&);
& & & & & & & & }
& & & & & & & &
& & & & & & & & switch(oldIndex)
& & & & & & & & {
& & & & & & & & case 0:
& & & & & & & & & & & & while(!feof(fp))
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & fread(&colorValue,1,1,fp);
& & & & & & & & & & & & & & & & if(colorValue != 255)
& & & & & & & & & & & & & & & & & & & & colorValue = 255;
& & & & & & & & & & & & & & & & fwrite(&colorValue,1,1,fp1);
& & & & & & & & & & & & }
& & & & & & & & & & & &
& & & & & & & & case 1:
& & & & & & & & & & & & while(!feof(fp))
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & fread(&colorValue,1,1,fp);
& & & & & & & & & & & & & & & & if(colorValue != 0)
& & & & & & & & & & & & & & & & & & & & colorValue = 0;
& & & & & & & & & & & & & & & & fwrite(&colorValue,1,1,fp1);
& & & & & & & & & & & & }
& & & & & & & & & & & &
& & & & & & & & }
& & & & & & & &
& & & & /*For the 16-bit color map*/
& & & & case 4:
& & & & & & & & fseek(fp,54L,0);
& & & & & & & & printf(&\nThis is the color palette of this image.&);
& & & & & & & & printf(&\nIndex Blue Green Red Reserved\n&);
& & & & & & & & for(i=0;i&16;i++)
& & & & & & & & {
& & & & & & & & & & & & fread(&bmpHeader2.bmiColors[i].rgbBlue,1,1,fp);
& & & & & & & & & & & & fread(&bmpHeader2.bmiColors[i].rgbGreen,1,1,fp);
& & & & & & & & & & & & fread(&bmpHeader2.bmiColors[i].rgbRed,1,1,fp);
& & & & & & & & & & & & fread(&bmpHeader2.bmiColors[i].rgbReserved,1,1,fp);
& & & & & & & & & & & & fwrite(&bmpHeader2.bmiColors[i].rgbBlue,1,1,fp1);
& & & & & & & & & & & & fwrite(&bmpHeader2.bmiColors[i].rgbGreen,1,1,fp1);
& & & & & & & & & & & & fwrite(&bmpHeader2.bmiColors[i].rgbRed,1,1,fp1);
& & & & & & & & & & & & fwrite(&bmpHeader2.bmiColors[i].rgbReserved,1,1,fp1);
& & & & & & & & & & & & printf(&%3d %4u %4u %4u %4u\n&,i,bmpHeader2.bmiColors[i].rgbBlue,bmpHeader2.bmiColors[i].rgbGreen,bmpHeader2.bmiColors[i].rgbRed,bmpHeader2.bmiColors[i].rgbReserved);
& & & & & & & & }
& & & & & & & & printf(&\nPlease input the index of the old color(from 0 to 255):&);
& & & & & & & & while(scanf(&%d&,&oldIndex) !=1 || oldIndex&15 || oldIndex&0)
& & & & & & & & {
& & & & & & & & & & & & getchar();
& & & & & & & & & & & & printf(&\nIt's an invalid value! Please input again:&);
& & & & & & & & }
& & & & & & & & printf(&\nPlease input the index of the new color(from 0 to 15):&);
& & & & & & & & while(scanf(&%d&,&newIndex) !=1 || newIndex&15 || newIndex&0)
& & & & & & & & {
& & & & & & & & & & & & getchar();
& & & & & & & & & & & & printf(&\nIt's an invalid value! Please input again:&);
& & & & & & & & }
& & & & & & & & fseek(fp,bmpHeader1.bfOffBits,0);
& & & & & & & & while(!feof(fp))
& & & & & & & & {
& & & & & & & & & & & & fread(&colorValue,1,1,fp);
& & & & & & & & & & & & if(colorValue%16 == oldIndex)& & & & //Get the first 4-bits of a byte
& & & & & & & & & & & & & & & & Index161 = newI& & & & //Check the index
& & & & & & & & & & & & else
& & & & & & & & & & & & & & & & Index161 = colorValue%16;
& & & & & & & & & & & & if(((colorValue-colorValue%16)/16) == oldIndex)& & & & //Get the last 4-bits of a byte
& & & & & & & & & & & & & & & & Index162 = newI
& & & & & & & & & & & & else
& & & & & & & & & & & & & & & & Index162 = (colorValue - colorValue%16)/16;
& & & & & & & & & & & & colorValue = Index162*16+Index161;
& & & & & & & & & & & & fwrite(&colorValue,1,1,fp1);
& & & & & & & & }
& & & & & & & &
& & & & /*For the 256-bit color map*/
& & & & case 8:
& & & & & & & & fseek(fp,54L,0);
& & & & & & & & printf(&\nThis is the color palette of this image.&);
& & & & & & & & printf(&Index Blue Green Red Reserved\n&);
& & & & & & & & for(i=0;i&256;i++)& & & & //Read out the RGBQUAD information and display the palette
& & & & & & & & {
& & & & & & & & & & & & fread(&bmpHeader2.bmiColors[i].rgbBlue,1,1,fp);
& & & & & & & & & & & & fread(&bmpHeader2.bmiColors[i].rgbGreen,1,1,fp);
& & & & & & & & & & & & fread(&bmpHeader2.bmiColors[i].rgbRed,1,1,fp);
& & & & & & & & & & & & fread(&bmpHeader2.bmiColors[i].rgbReserved,1,1,fp);
& & & & & & & & & & & & fwrite(&bmpHeader2.bmiColors[i].rgbBlue,1,1,fp1);
& & & & & & & & & & & & fwrite(&bmpHeader2.bmiColors[i].rgbGreen,1,1,fp1);
& & & & & & & & & & & & fwrite(&bmpHeader2.bmiColors[i].rgbRed,1,1,fp1);
& & & & & & & & & & & & fwrite(&bmpHeader2.bmiColors[i].rgbReserved,1,1,fp1);
& & & & & & & & & & & & printf(&%3d %4u %4u %4u %4u\n&,i,bmpHeader2.bmiColors[i].rgbBlue,bmpHeader2.bmiColors[i].rgbGreen,bmpHeader2.bmiColors[i].rgbRed,bmpHeader2.bmiColors[i].rgbReserved);
& & & & & & & & }
& & & & & & & & printf(&\nPlease input the index of the old color(from 0 to 255):&);
& & & & & & & & while(scanf(&%d&,&oldIndex) !=1 || oldIndex&255 || oldIndex&0)
& & & & & & & & {
& & & & & & & & & & & & getchar();
& & & & & & & & & & & & printf(&\nIt's an invalid value! Please input again:&);
& & & & & & & & }
& & & & & & & & printf(&\nPlease input the index of the new color(from 0 to 255):&);
& & & & & & & & while(scanf(&%d&,&newIndex) !=1 || newIndex&255 || newIndex&0)
& & & & & & & & {
& & & & & & & & & & & & getchar();
& & & & & & & & & & & & printf(&\nIt's an invalid value! Please input again:&);
& & & & & & & & }
& & & & & & & & fseek(fp,bmpHeader1.bfOffBits,0);
& & & & & & & & while(!feof(fp))
& & & & & & & & {
& & & & & & & & & & & & fread(&colorValue,1,1,fp);
& & & & & & & & & & & & if(colorValue == oldIndex)
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & fwrite(&newIndex,1,1,fp1);
& & & & & & & & & & & & }
& & & & & & & & & & & & else
& & & & & & & & & & & & & & & & fwrite(&colorValue,1,1,fp1);
& & & & & & & & }
& & & & & & & &
& & & & /*For the 24-bit color map*/
& & & & case 24:
& & & & & & & & fseek(fp,54L,0);
& & & & & & & & /*Get the old and new RGB value of colors*/
& & & & & & & & printf(&\nThis image has 224 colors, which one do you want to change?\n&);
& & & & & & & & printf(&Blue:&);
& & & & & & & & scanf(&%u&,&oldColor1[2]);
& & & & & & & & printf(&Green:&);
& & & & & & & & scanf(&%u&,&oldColor1[1]);
& & & & & & & & printf(&Red:&);
& & & & & & & & scanf(&%u&,&oldColor1[0]);
& & & & & & & & printf(&What is the new color?\n&);
& & & & & & & & printf(&Blue:&);
& & & & & & & & scanf(&%u&,&newColor1[2]);
& & & & & & & & printf(&Green:&);
& & & & & & & & scanf(&%u&,&newColor1[1]);
& & & & & & & & printf(&Red:&);
& & & & & & & & scanf(&%u&,&newColor1[0]);
& & & & & & & & & & & &
& & & & & & & & while(!feof(fp))
& & & & & & & & {
& & & & & & & & & & & & fread(&tempColor[0],1,1,fp);
& & & & & & & & & & & & fread(&tempColor[1],1,1,fp);
& & & & & & & & & & & & fread(&tempColor[2],1,1,fp);
& & & & & & & & & & & & if(tempColor[2] == oldColor1[2] && tempColor[1] == oldColor1[1] && tempColor[0] == oldColor1[0])
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & fwrite(&newColor1[0],1,1,fp1);
& & & & & & & & & & & & & & & & fwrite(&newColor1[1],1,1,fp1);
& & & & & & & & & & & & & & & & fwrite(&newColor1[2],1,1,fp1);
& & & & & & & & & & & & }
& & & & & & & & & & & & else
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & fwrite(&tempColor[0],1,1,fp1);
& & & & & & & & & & & & & & & & fwrite(&tempColor[1],1,1,fp1);
& & & & & & & & & & & & & & & & fwrite(&tempColor[2],1,1,fp1);
& & & & & & & & & & & & }
& & & & & & & & }
& & & & & & & &
& & & & default:
& & & & & & & & printf(&This image is not supported by this program!&);
& & & & & & & &
& & & & fclose(fp);
& & & & fclose(fp1);
强帖啊,不顶没人性啊
版主帮满看看啊~~谢了~~
不好意思,这几天在外边,没编译环境。
程序设计,算法为王。
提出问题;分析问题;确定算法;画出流程图;编辑程序;调试程序;建立文档资料。
大家在开发板块贴代码的时候,请使用“插入代码”的功能。
[code]int main(){return 0;}[/code]
是原创还是转来的呀}

我要回帖

更多关于 01背包问题c语言 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信