以下哪个代码属于h5头部代码信息的组成

查看:25936|回复:2
我用抓包软件抓了http的包,发现accept大多数有两种情况。
第一种:Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, */*
第二种:Accept: */*
这两种形式有什么区别呢?而且这两种形式都有*/*,为什么第一种形式还要加入其他的格式呢?
没抓过HTTP的包,你试着把完整包发上来看看,配上当时操作说明。
不过我认为是下载文件(第二种数据包)和浏览网页(第一种数据包)的不同。
程序设计,算法为王。
提出问题;分析问题;确定算法;画出流程图;编辑程序;调试程序;建立文档资料。
大家在开发板块贴代码的时候,请使用“插入代码”的功能。
[code]int main(){return 0;}[/code]
(转) HTTP协议的头信息详解 &1&
HTTP协议的头信息详解
HTTP(HyperTextTransferProtocol)是超文本传输协议的缩写,它用于传送WWW方式的数据,关于HTTP 协议的详细内容请参 考RFC2616。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求,请求头包含请求的方法、URI、协议版本、以及包含请求修饰符、客户 信息和内容的类似于MIME的消息结构。服务器以一个状态行作为响应,相应的内容包括消息协议的版本,成功或者错误编码加上包含服务器信息、实体元信息以 及可能的实体内容。
  通常HTTP消息包括客户机向服务器的请求消息和服务器向客户机的响应消息。这两种类型的消息由一个起始行,一个或者多个头域,一个只是头域结束的空行和可 选的消息体组成。HTTP的头域包括通用头,请求头,响应头和实体头四个部分。每个头域由一个域名,冒号(:)和域值三部分组成。域名是大小写无关的,域 值前可以添加任何数量的空格符,头域可以被扩展为多行,在每行开始处,使用至少一个空格或制表符。
  通用头域
  通用头 域包含请求和响应消息都支持的头域,通用头域包含Cache-Control、 Connection、Date、Pragma、Transfer-Encoding、Upgrade、Via。对通用头域的扩展要求通讯双方都支持此扩 展,如果存在不支持的通用头域,一般将会作为实体头域处理。下面简单介绍几个在UPnP消息中使用的通用头域。
  Cache-Control头域
  Cache -Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置 Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。请求时的缓存指令包括no-cache、no-store、max-age、 max-stale、min-fresh、only-if-cached,响应消息中的指令包括public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age。各个消息中的指令含义如 下:
  Public指示响应可被任何缓存区缓存。
  Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
  no-cache指示请求或响应消息不能缓存
  no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
  max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
  min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
  max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。
  Date头域
  Date头域表示消息发送的时间,时间的描述格式由rfc822定义。例如,Date:Mon,31Dec:57GMT。Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。
  Pragma头域
  Pragma头域用来包含实现特定的指令,最常用的是Pragma:no-cache。在HTTP/1.1协议中,它的含义和Cache- Control:no-cache相同。
  请求消息
  请求消息的第一行为下面的格式:
  MethodSPRequest-URISPHTTP-VersionCRLFMethod 表示对于Request-URI完成的方法,这个字段是大小写敏感的,包括OPTIONS、GET、HEAD、POST、PUT、DELETE、 TRACE。方法GET和HEAD应该被所有的通用WEB服务器支持,其他所有方法的实现是可选的。GET方法取回由Request-URI标识的信息。 HEAD方法也是取回由Request-URI标识的信息,只是可以在响应时,不返回消息体。POST方法可以请求服务器接收包含在请求中的实体信息,可 以用于提交表单,向新闻组、BBS、邮件群组和数据库发送消息。
  SP表示空格。Request-URI遵循URI格式,在此字段为星 号(*)时,说明请求并不用于某个特定的资源地址,而是用于服务器本身。HTTP- Version表示支持的HTTP版本,例如为HTTP/1.1。CRLF表示换行回车符。请求头域允许客户端向服务器传递关于请求或者关于客户机的附加 信息。请求头域可能包含下列字段Accept、Accept-Charset、Accept- Encoding、Accept-Language、Authorization、From、Host、If-Modified-Since、If- Match、If-None-Match、If-Range、If-Range、If-Unmodified-Since、Max-Forwards、 Proxy-Authorization、Range、Referer、User-Agent。对请求头域的扩展要求通讯双方都支持,如果存在不支持的请 求头域,一般将会作为实体头域处理。
  典型的请求消息:
  Host: download.microtool.de
  Accept:*/*
  Pragma: no-cache
  Cache-Control: no-cache
  Referer:
  User-Agent:Mozilla/4.04[en](Win95;I;Nav)
  Range:bytes=554554-
  上例第一行表示HTTP客户端(可能是浏览器、下载程序)通过GET方法获得指定URL下的文件。棕色的部分表示请求头域的信息,绿色的部分表示通用头部分。
  Host头域
  Host头域指定请求资源的Intenet主机和端口号,必须表示请求url的原始服务器或网关的位置。HTTP/1.1请求必须包含主机头域,否则系统会以400状态码返回。
  Referer头域
  Referer 头域允许客户端指定请求uri的源资源地址,这可以允许服务器生成回退链表,可用来登陆、优化cache等。他也允许废除的或错误的连接由于维护的目的被 追踪。如果请求的uri没有自己的uri地址,Referer不能被发送。如果指定的是部分uri地址,则此地址应该是一个相对地址。
  Range头域
  Range头域可以请求实体的一个或者多个子范围。例如,
  表示头500个字节:bytes=0-499
  表示第二个500字节:bytes=500-999
  表示最后500个字节:bytes=-500
  表示500字节以后的范围:bytes=500-
  第一个和最后一个字节:bytes=0-0,-1
  同时指定几个范围:bytes=500-600,601-999
  但是服务器可以忽略此请求头,如果无条件GET包含Range请求头,响应会以状态码206(PartialContent)返回而不是以200 (OK)。
  User-Agent头域
  User-Agent头域的内容包含发出请求的用户信息。
  响应消息
  响应消息的第一行为下面的格式:
  HTTP-VersionSPStatus-CodeSPReason-PhraseCRLF
  HTTP -Version表示支持的HTTP版本,例如为HTTP/1.1。Status- Code是一个三个数字的结果代码。Reason-Phrase给Status-Code提供一个简单的文本描述。Status-Code主要用于机器自 动识别,Reason-Phrase主要用于帮助用户理解。Status-Code的第一个数字定义响应的类别,后两个数字没有分类的作用。第一个数字可 能取5个不同的值:
  1xx:信息响应类,表示接收到请求并且继续处理
  2xx:处理成功响应类,表示动作被成功接收、理解和接受
  3xx:重定向响应类,为了完成指定的动作,必须接受进一步处理
  4xx:客户端错误,客户请求包含语法错误或者是不能正确执行
  5xx:服务端错误,服务器不能正确执行一个正确的请求
  响应头域允许服务器传递不能放在状态行的附加信息,这些域主要描述服务器的信息和 Request-URI进一步的信息。响应头域包含Age、Location、Proxy-Authenticate、Public、Retry- After、Server、Vary、Warning、WWW-Authenticate。对响应头域的扩展要求通讯双方都支持,如果存在不支持的响应头 域,一般将会作为实体头域处理。
  典型的响应消息:
  HTTP/1.0200OK
  Date:Mon,31Dec:57GMT
  Server:Apache/1.3.14(Unix)
  Content-type:text/html
  Last-modified:Tue,17Apr:28GMT
  Etag:&a030f020ac7c01:1e9f&
  Content-length:
  Content-range:bytes80
  上例第一行表示HTTP服务端响应一个GET方法。棕色的部分表示响应头域的信息,绿色的部分表示通用头部分,红色的部分表示实体头域的信息。
  Location响应头
  Location响应头用于重定向接收者到一个新URI地址。
  Server响应头
  Server响应头包含处理请求的原始服务器的软件信息。此域能包含多个产品标识和注释,产品标识一般按照重要性排序。
  请求消息和响应消息都可以包含实体信息,实体信息一般由实体头域和实体组成。实体头域包含关于实体的原信息,实体头包括Allow、Content- Base、Content-Encoding、Content-Language、 Content-Length、Content-Location、Content-MD5、Content-Range、Content-Type、 Etag、Expires、Last-Modified、extension-header。extension-header允许客户端定义新的实体 头,但是这些域可能无法未接受方识别。实体可以是一个经过编码的字节流,它的编码方式由Content-Encoding或Content-Type定 义,它的长度由Content-Length或Content-Range定义。
  Content-Type实体头
  Content-Type实体头用于向接收方指示实体的介质类型,指定HEAD方法送到接收方的实体介质类型,或GET方法发送的请求介质类型 Content-Range实体头
  Content-Range实体头用于指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度。一般格式:
  Content-Range:bytes-unitSPfirst-byte-pos-last-byte-pos/entity-legth
  例如,传送头500个字节次字段的形式:Content-Range:bytes0- 499/1234如果一个http消息包含此节(例如,对范围请求的响应或对一系列范围的重叠请求),Content-Range表示传送的范围, Content-Length表示实际传送的字节数。
  Last-modified实体头
应答头说明Allow服务器支持哪些请求方法(如GET、POST等)。Content-Encoding文 档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的 下载时间。Java的GZIPOutputStream可以很方便地进行gzip压缩,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet应该通过查看Accept-Encoding头(即request.getHeader(&Accept- Encoding&))检查浏览器是否支持gzip,为支持gzip的浏览器返回经gzip压缩的HTML页面,为其他浏览器返回普通页面。Content-Length表 示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。如果你想要利用持久连接的优势,可以把输出文档写入 ByteArrayOutputStram,完成后查看其大小,然后把该值放入Content-Length头,最后通过 byteArrayStream.writeTo(response.getOutputStream()发送内容。Content-Type表示后面的文档属于什么MIME类型。Servlet默认为text/plain,但通常需要显式地指定为text/html。由于经常要设置Content-Type,因此HttpServletResponse提供了一个专用的方法setContentTyep。Date当前的GMT时间。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。Expires应该在什么时候认为文档已经过期,从而不再缓存它?Last-Modified文 档的最后改动时间。客户可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档 才会返回,否则返回一个304(Not Modified)状态。Last-Modified也可用setDateHeader方法来设置。Location表示客户应当到哪里去提取文档。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。Refresh表示浏览器应该在多少时间之后刷新文档,以秒计。除了刷新当前文档之外,你还可以通过setHeader(&Refresh&, &5; URL=http://host/path&)让浏览器读取指定的页面。
注 意这种功能通常是通过设置HTML页面HEAD区的<META HTTP-EQUIV=&Refresh& CONTENT=&5;URL=http://host/path&>实现,这是因为,自动刷新或重定向对于那些不能使用CGI或Servlet的 HTML编写者十分重要。但是,对于Servlet来说,直接设置Refresh头更加方便。
注意Refresh的意义是“N秒之后 刷新本页面或访问指定页面”,而不是“每隔N秒刷新本页面或访问指定页面”。因此,连续刷新要求每次都发送一个Refresh头,而发送204状态代码则 可以阻止浏览器继续刷新,不管是使用Refresh头还是<META HTTP-EQUIV=&Refresh& ...>。
注意Refresh头不属于HTTP 1.1正式规范的一部分,而是一个扩展,但Netscape和IE都支持它。Server服务器名字。Servlet一般不设置这个值,而是由Web服务器自己设置。Set-Cookie设置和页面关联的Cookie。Servlet不应使用response.setHeader(&Set-Cookie&, ...),而是应使用HttpServletResponse提供的专用方法addCookie。参见下文有关Cookie设置的讨论。WWW-Authenticate客 户应该在Authorization头中提供什么类型的授权信息?在包含401(Unauthorized)状态行的应答中这个头是必需的。例如, response.setHeader(&WWW-Authenticate&, &BASIC realm=\&executives\&&)。
注意Servlet一般不进行这方面的处理,而是让Web服务器的专门机制来控制受密码保护页面的访问(例如.htaccess)。
(一)初识HTTP消息头
但凡搞WEB开发的人都离不开HTTP(超文本传输协议),而要了解HTTP,除了HTML本身以外,还有一部分不可忽视的就是HTTP消息头。
做过Socket编程的人都知道,当我们设计一个通信协议时,“消息头/消息体”的分割方式是很常用的,消息头告诉对方这个消息是干什么的,消息体告诉对方怎么干。HTTP传输的消息也是这样规定的,每一个HTTP包都分为HTTP头和HTTP体两部分,后者是可选的,而前者是必须的。每当我们打开一个网页,在上面点击右键,选择“查看源文件”,这时看到的HTML代码就是HTTP的消息体,那么消息头又在哪呢?IE浏览器不让我们看到这部分,但我们可以通过截取数据包等方法看到它。
下面就来看一个简单的例子:
首先制作一个非常简单的网页,它的内容只有一行:
&html&&body&hello world&/body&&/html&
把它放到WEB服务器上,比如IIS,然后用IE浏览器请求这个页面(),当我们请求这个页面时,浏览器实际做了以下四项工作:
1 解析我们输入的地址,从中分解出协议名、主机名、端口、对象路径等部分,对于我们的这个地址,解析得到的结果如下:
协议名:http
主机名:localhost
端口:8080
对象路径:/simple.htm
2 把以上部分结合本机自己的信息,封装成一个HTTP请求数据包
3 使用TCP协议连接到主机的指定端口(localhost, 8080),并发送已封装好的数据包
4 等待服务器返回数据,并解析返回数据,最后显示出来
由截取到的数据包我们不难发现浏览器生成的HTTP数据包的内容如下:
GET /simple.htm HTTP/1.1&CR&
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*&CR&
Accept-Language: zh-cn&CR&
Accept-Encoding: gzip, deflate&CR&
User-Agent: Mozilla/4.0 ( MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)&CR&
Host: localhost:8080&CR&
Connection: Keep-Alive&CR&
为了显示清楚我把所有的回车的地方都加上了“&CR&”,注意最后还有一个空行加一个回车,这个空行正是HTTP规定的消息头和消息体的分界线,第一个空行以下的内容就是消息体,这个请求数据包是没有消息体的。
消息的第一行“GET”表示我们所使用的HTTP动作,其他可能的还有“POST”等,GET的消息没有消息体,而POST消息是有消息体的,消息体的内容就是要POST的数据。后面/simple.htm就是我们要请求的对象,之后HTTP1.1表示使用的是HTTP1.1协议。
第二行表示我们所用的浏览器能接受的Content-type,三四两行则是语言和编码信息,第五行显示出本机的相关系信息,包括浏览器类型、操作系统信息等,很多网站可以显示出你所使用的浏览器和操作系统版本,就是因为可以从这里获取到这些信息。
第六行表示我们所请求的主机和端口,第七行表示使用Keep-Alive方式,即数据传递完并不立即关闭连接。
服务器接收到这样的数据包以后会根据其内容做相应的处理,例如查找有没有“/simple.htm”这个对象,如果有,根据服务器的设置来决定如何处理,如果是HTM,则不需要什么复杂的处理,直接返回其内容即可。但在直接返回之前,还需要加上HTTP消息头。
服务器发回的完整HTTP消息如下:
HTTP/1.1 200 OK&CR&
Server: Microsoft-IIS/5.1&CR&
X-Powered-By: ASP.NET&CR&
Date: Fri, 03 Mar :03 GMT&CR&
Content-Type: text/html&CR&
Accept-Ranges: bytes&CR&
Last-Modified: Fri, 03 Mar :18 GMT&CR&
ETag: &5ca4f75b8c3ec61:9ee&&CR&
Content-Length: 37&CR&
&html&&body&hello world&/body&&/html&
同样,我用“&CR&”来表示回车。可以看到,这个消息也是用空行切分成消息头和消息体两部分,消息体的部分正是我们前面写好的HTML代码。
消息头第一行“HTTP/1.1”也是表示所使用的协议,后面的“200 OK”是HTTP返回代码,200就表示操作成功,还有其他常见的如404表示对象未找到,500表示服务器错误,403表示不能浏览目录等等。
第二行表示这个服务器使用的WEB服务器软件,这里是IIS 5.1。第三行是ASP.Net的一个附加提示,没什么实际用处。第四行是处理此请求的时间。第五行就是所返回的消息的content-type,浏览器会根据它来决定如何处理消息体里面的内容,例如这里是text/html,那么浏览器就会启用HTML解析器来处理它,如果是image/jpeg,那么就会使用JPEG的解码器来处理。
消息头最后一行“Content-Length”表示消息体的长度,从空行以后的内容算起,以字节为单位,浏览器接收到它所指定的字节数的内容以后就会认为这个消息已经被完整接收了。
理解HTTP消息头 (二)常见的HTTP返回码上一篇文章里我简要的说了说HTTP消息头的格式,注意到在服务器返回的HTTP消息头里有一个“HTTP/1.1 200 OK”,这里的200是HTTP规定的返回代码,表示请求已经被正常处理完成。浏览器通过这个返回代码就可以知道服务器对所发请求的处理情况是什么,每一种返回代码都有自己的含义。这里列举几种常见的返回码。
1 403 Access Forbidden如果我们试图请求服务器上一个文件夹,而在WEB服务器上这个文件夹并没有允许对这个文件夹列目录的话,就会返回这个代码。一个完整的403回复可能是这样的:(IIS5.1)
HTTP/1.1 403 Access Forbidden
Server: Microsoft-IIS/5.1
Date: Mon, 06 Mar :39 GMT
Connection: close
Content-Type: text/html
Content-Length: 172
&html&&head&&title&Directory Listing Denied&/title&&/head&
&body&&h1&Directory Listing Denied&/h1&This Virtual Directory does not allow contents to be listed.&/body&&/html&
2 404 Object not found当我们请求的对象在服务器上并不存在时,就会给出这个返回代码,这可能也是最常见的错误代码了。IIS给出的404消息内容很长,除了消息头以外还有一个完整的说明“为什么会这样”的网页。APACHE服务器的404消息比较简短,如下:
HTTP/1.1 404 Not Found
Date: Mon, 06 Mar :14 GMT
Server: Apache/2.0.55 (Unix) PHP/5.0.5
Content-Length: 291
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/ charset=iso-8859-1
&!DOCTYPE HTML PUBLIC &-//IETF//DTD HTML 2.0//EN&&
&html&&head&
&title&404 Not Found&/title&
&/head&&body&
&h1&Not Found&/h1&
&p&The requested URL /notexist was not found on this server.&/p&
&address&Apache/2.0.55 (Unix) PHP/5.0.5 Server at localhost Port 8080&/address&
&/body&&/html&
也许你会问,无论是404还是200,都会在消息体内给出一个说明网页,那么对于客户端来说二者有什么区别呢?一个比较明显的区别在于200是成功请求,浏览器会记录下这个地址,以便下次再访问时可以自动提示该地址,而404是失败请求,浏览器只会显示出返回的页面内容,并不会记录此地址,要再次访问时还需要输入完整的地址。
3 401 Access Denied当WEB服务器不允许匿名访问,而我们又没有提供正确的用户名/密码时,服务器就会给出这个返回代码。在IIS中,设置IIS的安全属性为不允许匿名访问(如下图),此时直接访问的话就会得到以下返回结果:
HTTP/1.1 401 Access Denied
Server: Microsoft-IIS/5.1
Date: Mon, 06 Mar :55 GMT
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
Connection: close
Content-Length: 3964
Content-Type: text/html
&!DOCTYPE HTML PUBLIC &-//W3C//DTD HTML 3.2 Final//EN&&
&html dir=ltr&
此时浏览器上给出的提示如下图,让我们输入用户名和密码:
因返回信息中消息体较长,只取前面两行内容。注意,如果是用localhost来访问本机的IIS,因IE可以直接取得当前用户的身份,它会和服务器间直接进行协商,所以不会看到401提示。
当我们在输入了用户名和密码以后,服务器与客户端会再进行两次对话。首先客户端向服务器索取一个公钥,服务器端会返回一个公钥,二者都用BASE64编码,相应的消息如下(编码部分已经做了处理):
GET / HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 ( MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
Host: 192.168.0.55:8080
Connection: Keep-Alive
Authorization: Negotiate ABCDEFG……
HTTP/1.1 401 Access Denied
Server: Microsoft-IIS/5.1
Date: Mon, 06 Mar :53 GMT
WWW-Authenticate: Negotiate HIJKLMN……
Content-Length: 3715
Content-Type: text/html
&!DOCTYPE HTML PUBLIC &-//W3C//DTD HTML 3.2 Final//EN&&
&html dir=ltr&
客户端拿到公钥之后使用公钥对用户名和密码进行加密码,然后把加密以后的结果重新发给服务器:
GET / HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 ( MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
Host: 192.168.0.55:8080
Connection: Keep-Alive
Authorization: Negotiate OPQRST……
这样,如果验证通过,服务器端就会把请求的内容发送过来了,也就是说禁止匿名访问的网站会经过三次请求才可以看到页面。但因为客户端浏览器已经缓存了公钥,用同一个浏览器窗口再次请求这个网站上的其它页面时就可以直接发送验证信息,从而一次交互就可以完成了。WMF文件的数据结构以及将绘图保存为WMF图像的代码  Wmf 是 Windows Metafile 的缩写,简称图元文件,它是微软公司定义的一种 Windows平台下的图形文件格式,是一个16位矢量图元文件格式,可以同时包含矢量信息和位图信息。图元文件与其它图形文件的最大区别在于:图元文件保存的是一系列用来重建图片的GDI函数(注:GDI函数是API 函数中的绘图函数)和参数,而其它图形文件则保存的是用以构成图像的像素数据。  WMF 图元文件是与设备无关的,它的图象完全由GDI 函数来完成,因此在建立图元文件时,不能实现即画即得,而是将GDI 调用记录在图元文件中,之后,在GDI 环境中重新执行,才可显示图象。正因为没有保存构成图像的像素数据,WMF 图元文件所占的磁盘空间比其它任何格式的图形文件都要小,形成文件的速度要远大于其它图形格式的文件。又正是因为显示图像时需要调用一系列的GDI 函数,所以WMF 图元文件的显示速度要比其它格式的图象文件慢。  WMF 文件又分为内存图元文件和磁盘图元文件。内存图元文件是仅在内存某一个区域进行操作并存放的,大多用于图象的绘制、拷贝或者进程间的剪切板图形共享;磁盘图元文件则主要用于将绘制图象保存到磁盘文件中,以便事后重看。  WMF 文件还可分为一般图元文件和&可确定位置&的图元文件。一般图元文件包含绘制直线、曲线和文本等记录,而可确定位置的图元文件还可以包含位图化图像。如果放大一般图元文件,那么得到的结果是放大的直线、曲线和其他输出,其抗锯齿能力很好。如果放大包含位图的图元文件,那么得到的结果是相对块状放大的位图,其抗锯齿能力要差一些。但一般图元文件也有不足之处,那就是:当将一个包含绘图命令的图元文件加载到一个应用程序时,可能会发现椭圆和文本不能正常地绘制出来,这是因为并不是所有程序都能够理解所有图元文件命令。一、数据结构  WMF 文件的结构主要有两种,包括: ①WMF 文件头: 如果是可确定位置的图元文件,则还必须在WMF 文件头之前加上一个&位置头&。 ②图元文件记录:其长度可变,记录中包含了建立图象时所需要的GDI 函数及参数。  下面以&可确定位置的图元文件&为例,介绍WMF文件的数据结构:1.位置头,22字节:-------------------------------------------------------------------------------偏移量 名称&&&&& 数据类型& 说明-------------------------------------------------------------------------------0000&&& 键&&&&&&& Long&&&&& 总是=D7CDC69A,表示这是一个可确定位置的图元文件0004&&& 保留的&&& Integer&& 总是=0  (以下4个数据构成位图化图像的原始大小(逻辑单位) 0006&&& Left&&&&& Integer&& 左上角X坐标0008&&& Top&&&&&& Integer&& 左上角Y坐标000A&&& Right&&&& Integer&& 右下角X坐标000C&&& Bottom&&& Integer&& 右下角Y坐标000E&&& 图像单元& Integer&& 每英寸逻辑单位数目0010&&& 保留的&&& Long&&&&& 总是=00014&&& 校验和&&& Integer-------------------------------------------------------------------------------  说明:在资源管理器左侧的&详细信息&中显示的&尺寸&,宽度尺寸就是用Right值减去Left值、高度尺寸就是用Botton值减去Top值得到的。2.WMF文件头,18字节:---------------------------------------------------------------------偏移量  名称&&&&&& 数据类型 说明---------------------------------------------------------------------0016&&& 文件类型&&&& Integer&&& 0=内存图元文件, 1=磁盘图元文件0018&&& 文件头大小&& Integer&&& 总是=9001A&&& 版本&&&&&&&& Integer&&& 0300=支持设备无关位图,0100=不支持001C&&& 文件大小&&&& Long&&&&&& 文件的总长度0020&&& 对象个数&&&& Integer&&& 文件中可以同时使用的对象数目0022&&& 最大记录大小 Integer&&& 文件中最大记录的长度0024&&& 保留的&&&&&& Long&&&&&& 未使用,总是=0---------------------------------------------------------------------  说明:WMF 文件中的长度值是以&字数&为单位的(一个字=2字节),&文件头大小&、&文件大小&、&最大记录大小&,以及下面将要讲到的&文件记录大小&,都是如此。例如&文件头大小&总是=9,而 9&2=18字节。当然,这只是笔者的推测:这个推测还需验证。3.文件记录:长度不定  紧接文件头的是文件记录,这是图元文件中最重要的组成部分,它表明当前图元文件所描述图像的基本构成信息,每个记录都是由记录头,定义函数的相应代码以及函数调用所需要的参数说明三部分组成,一个文件记录中只记录了一个GDI 函数及对应的参数。大多数情况下,记录中包含的参数恰好为需要传送到相应GDI 函数中的数据值,但对于某些包含结构的复杂类型定义,这些参数值也可能是非常复杂的数据编码。  文件记录是一个接一个地存放着的,它的结构如下:----------------------------------------------------------------偏移量 名称  数据类型  说明----------------------------------------------------------------0028&& 大小&& Long&&&&&&& 该记录的长度002C&& 函数&& Integer&&&& GDI函数编号002E&& 参数表&&&&&&&&&&&& 欲传递给函数的参数值,整型和长整型参数       &&&&&&&   均为2字节,逻辑型或字节型参数为1字节----------------------------------------------------------------  说明:①记录的长度值,正如前面笔者所推测的,是指有多少个字。②文件记录中的GDI 函数并不是它们的函数名称,而是对应的函数编号,根据这个编号来调用函数。③有些API函数需用句柄,但句柄似乎没有保存。④参数的排列规律为:如果是一般的参数,反序排列,如果是一个结构,顺序排列。4.GDI函数在WMF文件中的16进制编号:------------------------------------------------------------------GDI函数名&&&&&&&&&&&& 编号  作用------------------------------------------------------------------savedc&&&&&&&&&&&&&&& 001E&& 将设备场景状态保存到堆栈Realizepalette&&&&&&& 0035&& 将逻辑调色板映像为系统调色板SETPALENTRIES&&&&&&&& 0037AbortDoc&&&&&&&&&&&&& 0052&& 取消一份文档的打印CreatePalette&&&&&&&& 00F7&& 建立逻辑色彩调色板SetBkMode&&&&&&&&&&&& 0102&& 指定填充方式setmapmode&&&&&&&&&&& 0103&& 设置设备场景的映射模式SetROP2&&&&&&&&&&&&&& 0104&& 设置绘图模式SetRelabs&&&&&&&&&&&& 0105SetPolyFillMode&&&&&& 0106&& 设置多边形的填充模式SetStretchBltMode&&&& 0107&& 指定函数的伸缩模式SetTextCharacterExtra 0108&& 指定要在描绘的文本间插入的额外间距RestoreDC&&&&&&&&&&&& 0127&& 从堆栈恢复一个原先保存的设备场景INVERTREGION&&&&&&&&& 012APAINTREGION&&&&&&&&&& 012BSELECTCLIPREGION&&&&& 012CSelectObject&&&&&&&&& 012D&& 选入图形对象到设备场景SetTextAlign&&&&&&&&& 012E&& 设置文本对齐方式Resizepalette&&&&&&&& 0139&& 修改逻辑调色板大小DIBCREATEPATTERNBRUSH 0142DeleteObject&&&&&&&&& 01F0&& 删除GDI对象CreatePatternBrush&&& 01F9&& 创建一个刷子SetBkColor&&&&&&&&&&& 0201&& 设置背景颜色SetTextColor&&&&&&&&& 0209&& 设置文本颜色SetTextJustification& 020A&& 指定一个文本行应占据的额外空间SetWindowOrg&&&&&&&&& 020B&& 设置设备场景窗口起点SetWindowExt&&&&&&&&& 020C&& 设置设备场景窗口范围SetViewportOrg&&&&&&& 020D&& 设置设备场景视口起点SetViewportExt&&&&&&& 020E&& 设置设备场景视口范围OffsetWindowOrg&&&&&& 020F&& 平移设备场景窗口起点OffsetViewportOrg&&&& 0211&& 平移设备场景视口区域LineTo&&&&&&&&&&&&&&& 0213&& 用当前画笔画一条线MoveTo&&&&&&&&&&&&&&& 0214&& 为设备场景指定一个新的当前画笔位置OffsetClipRgn&&&&&&&& 0220&& 按指定量平移设备场景剪裁区SetMapperFlags&&&&&&& 0231&& 选择与目标设备的纵横比相符的光栅字体SelectPalette&&&&&&&& 0234&& 选定调色板CreatePenIndirect&&&& 02FA&& 根据指定的LOGPEN结构创建一个画笔CreateFontIndirect&&& 02FB&& 用指定的属性创建一种逻辑字体CreateBrushIndirect&& 02FC&& 在LOGBRUSH结构的基础上创建一个刷子Polygon&&&&&&&&&&&&&& 0324&& 描绘一个多边形Polyline&&&&&&&&&&&&& 0325&& 用当前画笔描绘一系列线段ScaleWindowExt&&&&&&& 0410&& 缩放设备场景窗口范围ScaleViewportExt&&&&& 0412&& 缩放设备场景视口范围ExcludeClipRect&&&&&& 0415&& 从设备场景剪裁区中去掉一个矩形区IntersectClipRect&&&& 0416&& 为指定设备定义一个新的剪裁区Ellipse&&&&&&&&&&&&&& 0418&& 描绘一个椭圆FloodFill&&&&&&&&&&&& 0419&& 用选定的刷子在设备场景中填充一个区域Rectangle&&&&&&&&&&&& 041B&& 用选定的画笔描绘矩形SetPixel&&&&&&&&&&&&& 041F&& 在设备场景中画点(像素的RGB值)AnimatePalette&&&&&&& 0436&& 替换逻辑调色板中的项目TextOut&&&&&&&&&&&&&& 0521&& 文本绘图PolyPolygon&&&&&&&&&& 0538&& 用选定画笔描绘多边形ExtFloodFill&&&&&&&&& 0548&& 用选择的刷子填充一个区域RoundRect&&&&&&&&&&&& 061C&& 画一个圆角矩形PatBlt&&&&&&&&&&&&&&& 061D&& 用一个图案填充指定的设备场景Escape&&&&&&&&&&&&&&& 0626&& 设备控制CREATEREGION&&&&&&&&& 06FFArc&&&&&&&&&&&&&&&&&& 0817&& 画一个圆弧Pie&&&&&&&&&&&&&&&&&& 081A&& 画一个饼图Chord&&&&&&&&&&&&&&&& 0830&& 画一个弦BitBlt&&&&&&&&&&&&&&& 0922&& 将位图从一个设备场景复制到另一个DIBBITBLT&&&&&&&&&&&& 0940ExtTextOut&&&&&&&&&&& 0A32&& 文本描绘StretchBlt&&&&&&&&&&& 0B23&& 将位图从一个设备场景缩放到另一个DIBSTRETCHBLT&&&&&&&& 0B41SETDIBTODEV&&&&&&&&&& 0D33StretchDIB&&&&&&&&&&& 0F43&& 将位图部分数据复制到指定的设备场景------------------------------------------------------------------二、将绘画保存为WMF文件的源代码举例(画一个椭圆,在椭圆中打印&矢量图像&4个字):  在窗体上添加1个按纽,3个图片框,Picture1 用来观看原图形(Width=3090,Height=1455),Picture2 用来观看采用向量方式放大的图形(宽、高要设置得大一些),Picture3 用来观看采用位图方式放大的图形(宽、高设置得与Picture2 一样大)。Option Explicit* Type LOGFONT& lfHeight As Long&&&&&&&& 字体高度& lfWidth As Long&&&&&&&&& 字体平均宽度& lfEscapement As Long&&&& 输出方向与当前坐标系X轴之间的字体旋转的角度,以1/10度为单位& lfOrientation As Long&&& 每个字符与当前坐标系X轴之间的角度,以1/10度为单位& lfWeight As Long&&&&&&&& 是否粗体(范围为0-1000,字体加重程度:标准=400,加重=700)& lfItalic As Byte&&&&&&&& 是否斜体(不为0表示采用斜体字)& lfUnderline As Byte&&&&& 是否有下划线(不为0表示带下划线)& lfStrikeOut As Byte&&&&& 是否有中划线(不为0表示带中划线)& lfCharSet As Byte&&&&&&& 字符集& lfOutPrecision As Byte&& 输出精度& lfClipPrecision As Byte& 剪裁精度& lfQuality As Byte&&&&&&& 品质& lfPitchAndFamily As Byte 间距& lfFaceName(0 To 31) As Byte 字体名称* Type LOGFONTEnd Type* Type SIZE& cx As Long& cy As LongEnd Type* Declare Function lcreat Lib &kernel32& Alias &_lcreat& (ByVal lpPathName As String, ByVal iAttribute As Long) As Long* Declare Function lclose Lib &kernel32& Alias &_lclose& (ByVal hFile As Long) As Long* Declare Function lopen Lib &kernel32& Alias &_lopen& (ByVal lpPathName As String, ByVal iReadWrite As Long) As Long* Declare Function CreateMetaFile Lib &gdi32& Alias &CreateMetaFileA& (ByVal lpString As String) As Long* Declare Function CloseMetaFile Lib &gdi32& (ByVal hMF As Long) As Long* Declare Function GetMetaFileBitsEx Lib &gdi32& (ByVal hMF As Long, ByVal nSize As Long, lpvData As Long) As Long Any) As Long* Declare Function GlobalAlloc Lib &kernel32& (ByVal wFlags As Long, ByVal dwBytes As Long) As Long* Declare Function GlobalLock Lib &kernel32& (ByVal hMem As Long) As Long* Declare Function lwrite Lib &kernel32& Alias &_lwrite& (ByVal hFile As Long, ByVal lpBuffer As Any, ByVal wBytes As Long) As Long* Declare Function GlobalUnlock Lib &kernel32& (ByVal hMem As Long) As Long* Declare Function GlobalFree Lib &kernel32& (ByVal hMem As Long) As Long* Declare Function DeleteMetaFile Lib &gdi32& (ByVal hMF As Long) As Long* Declare Function SetTextColor Lib &gdi32& (ByVal hdc As Long, ByVal crColor As Long) As Long* Declare Sub RtlMoveMemory Lib &kernel32& (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)* Declare Function CreateFontIndirect Lib &gdi32& Alias &CreateFontIndirectA& (lpLogFont As LOGFONT) As Long* Declare Function SelectObject Lib &gdi32& (ByVal hdc As Long, ByVal hObject As Long) As Long* Declare Function TextOut Lib &gdi32& Alias &TextOutA& (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal lpString As String, ByVal nCount As Long) As Long* Declare Function Ellipse Lib &gdi32& (ByVal hdc As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long* Declare Function StretchBlt Lib &gdi32& (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long* Declare Function PlayMetaFile Lib &gdi32& (ByVal hdc As Long, ByVal hMF As Long) As Long* Declare Function SetMapMode Lib &gdi32& (ByVal hdc As Long, ByVal nMapMode As Long) As Long* Declare Function SetViewportExtEx Lib &gdi32& (ByVal hdc As Long, ByVal nX As Long, ByVal nY As Long, lpSize As SIZE) As Long* Declare Function SetWindowExtEx Lib &gdi32& (ByVal hdc As Long, ByVal nX As Long, ByVal nY As Long, lpSize As SIZE) As Long* Sub Command1_Click()Dim dc As Long, hWMF As Long, DCsize As SIZE, font As LOGFONTDim hFont As LongDim fhnd As LongDim mfinfosize As LongDim mfglbhnd As LongDim gptr As Longfhnd = lcreat(&D:\Temp\Image.wmf&, 0) 在磁盘上创建一个图元文件lclose fhnd&&&&&&&&&&&&&&&&&&&&&&&&&& 关闭图元文件fhnd = lopen(&D:\Temp\Image.wmf&, 2)& 打开图元文件dc = CreateMetaFile(vbNullString)&&&& 在内存中创建一个没有&位置头&的图元文件的设备场景用 GDI 函数画椭圆和打印文字Ellipse dc, 0, 0, 200, 90&&&&&&&&&&&& 在设备场景中画一个椭圆RtlMoveMemory font.lfFaceName(0), ByVal CStr(&宋体&), LenB(StrConv(&宋体&, vbFromUnicode)) + 1font.lfHeight = 30font.lfWidth = 15font.lfCharSet = 1hFont = CreateFontIndirect(font)&&& 创建逻辑字体SelectObject dc, hFont&&&&&&&&&&&&& 把逻辑字体选入设备场景SetTextColor dc, vbRed&&&&&&&&&&&&& 设置字符为红色TextOut dc, 40, 30, &矢量图像&, LenB(StrConv(&矢量图像&, vbFromUnicode)) 在设备场景中打印文本hWMF = CloseMetaFile(dc)&&&&&&&&&&& 关闭图元文件设备场景,返回向量图像句柄Picture1.ClsPicture2.ClsPicture3.ClsPlayMetaFile Picture1.hdc, hWMF&&&& 将向量图像显示在picture1中StretchBlt Picture3.hdc, 0, 0, Picture3.ScaleWidth, Picture3.ScaleHeight, Picture1.hdc, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, vbSrcCopy 将图像以位图放大方式显示在picture3中dc = Picture2.hdcSetMapMode dc, 8&&&&&&&&&&&&&&&&&&& 设置Picture2的映射模式:视口和窗口范围任意SetWindowExtEx dc, Picture1.ScaleWidth, Picture1.ScaleHeight, DCsize&& 设置Picture2窗口范围SetViewportExtEx dc, Picture2.ScaleWidth, Picture2.ScaleHeight, DCsize 设置Picture2视口范围PlayMetaFile dc, hWMF&&&&&&&&&&&&&& 将图像以向量放大方式显示在picture2中mfinfosize = GetMetaFileBitsEx(hWMF, 0, ByVal 0)& 获取向量图像的大小mfglbhnd = GlobalAlloc(&H42, mfinfosize)&&&&&&&&& 在堆栈中分配内存gptr = GlobalLock(mfglbhnd)&&&&&&&&&&&&&&&&&&&&&& 锁定内存GetMetaFileBitsEx hWMF, mfinfosize, ByVal gptr&&& 将向量图像数据复制到内存缓冲区gptrlwrite fhnd, ByVal gptr, mfinfosize 将gptr内存缓冲区中的mfinfosize个数据写入文件fhndGlobalUnlock mfglbhnd&&&&&&&&&&&&&& 内存块解锁GlobalFree mfglbhnd&&&&&&&&&&&&&&&& 释放全局内存块DeleteMetaFile hWMF&&&&&&&&&&&&&&&& 删除设备场景lclose fhnd&&&&&&&&&&&&&&&&&&&&&&&& 关闭图元文件End Sub  参考代码:用GDI 函数画矩形和正弦曲线,你可以用这段代码替换上面那段画椭圆和打印文字的代码(请自行声明API函数):Const cycle = 200& 周期Const extent = 40& 振幅Const posX = 45&&& X轴位置Const Pi = 6.2832Dim i As IntegerRectangle dc, 0, 0, cycle, posX * 2 画矩形For i = 0 To cycle& LineTo dc, i, posX - Sin(((i Mod cycle) * Pi) / cycle) * extent 画曲线Next  执行程序后,你可以看到,picture3的图像粗糙有锯齿,而picture2的图像线条流畅,没有锯齿。  另外,由于D:\Temp\Image.wmf 这个文件没有&位置头&,但在资源管理器和画图程序中显示其宽高分别为200、90,这说明对于一般的WMF 图元文件,Windows会自动计算绘图中的所有有关尺寸,并取最大的尺寸作为图片的尺寸。  如果你只想把图形直接保存到磁盘文件,不需要即时显示或放大,那么可采用更简单的代码(请自行删除多余的API函数和结构):* Sub Command1_Click()Dim dc As Long, hFont As Long, hWMF As Long, font As LOGFONTdc = CreateMetaFile(&D:\Temp\Image.wmf&) 在磁盘上创建一个图元文件Ellipse dc, 0, 0, 200, 90 RtlMoveMemory font.lfFaceName(0), ByVal CStr(&宋体&), LenB(StrConv(&宋体&, vbFromUnicode)) + 1font.lfHeight = 30font.lfWidth = 15font.lfCharSet = 1hFont = CreateFontIndirect(font) SelectObject dc, hFont SetTextColor dc, vbRed TextOut dc, 40, 30, &矢量图像&, LenB(StrConv(&矢量图像&, vbFromUnicode)) 在图元文件中打印文本hWMF = CloseMetaFile(dc)DeleteMetaFile hWMFEnd Sub  由此我们可以总结出将绘画保存为WMF文件的步骤(注意所有的步骤都是调用API函数):①在磁盘上用API 函数创建一个WMF 文件。②直接在这个文件上用API函数画图或打印文字③关闭WMF 文件④删除WMF 文件句柄三、D:\Temp\Image.wmf 的数据分析  用Hex编辑器打开这个WMF 文件,它的全部数据如下(你的数据可能会有差异): 09 00 00 03 42 00 00 00 01 00 1C 00 00 00 07 00 00 00 18 04 5A 00 C8 00 00 00 00 00 00 00 FB 02 1E 00 0F 00 00 00 00 00 00 00 00 01 00 00 00 00 CB CE CC E5 00 19 C5 77 00 00 9F 11 0A 5F 16 43 C5 77 1F 43 C5 77 C7 77 00 00 30 00 04 00 00 00 2D 01 00 00 00 00 09 02 FF 00 00 00 0A 00 00 00 21 05 CA B8 C1 BF CD BC CF F1 1E 00 28 00 03 00 00 00:WMF文件头,其中:  :数据=1,表示这是一个磁盘图元文件  :这个数据总是=9  :版本号=300,支持设备无关位图  :文件总长度=42个字(10进制的66),66&2=132字节  000A-000B:文件中有1个对象  000C-000D:最大记录的长度=1C 个字  000E-0011:保留的F:第1个文件记录,其中:  :记录长度=7  :调用编号为418的API函数(Ellipse,下面的参数为反序排列)  :椭圆的y2=5A(10进制的90)  001A-001B:椭圆的x2=C8(10进制的200)  001C-001D:椭圆的y1=0  001E-001F:椭圆的x1=0:第2个文件记录,其中:  :记录长度=1C  :调用编号为2FB的API函数(CreateFontIndirect,它的参数是一个结构,顺序排列)  :字体高=1E(10进制的30)  :字体宽=F(10进制的15)  002A-002F:3个整型数据参数=0,未设置  :3个字节型参数=0,未设置  :字符集=1(字节型参数)  :3个字节型参数=0,未设置  B:4个字节型参数=&宋体&字符的编码  003C-0057:这些数据用途不明,也许是前面讲过的&非常复杂的数据编码&?F:第3文件记录,其中:  B:记录长度=4  005C-005D:调用编号为12D的API函数(SelectObject)  005E-005F:参数值为0:第4个文件记录,其中:  :记录长度=5  :调用编号为209的API函数(SetTextColor)  :参数=FF000000,这是红色的RGB值006A-007D:第5个文件记录,其中:  006A-006D:记录长度=A  006E-006F:调用编号为521的API函数(TextOut,下面的参数为反序排列)  :欲打印的字串长度为8个字节  :欲打印的字符串&矢量图像&的编码  007A-007B:打印的Y坐标=1E(10进制的30)  007C-007D:打印的X坐标=28(10进制的40)007E-0083:笔者猜测这6个字节可能是矢量补充数据,又或者是WMF文件尾,存疑。&
会员帐号:
密  码:
内  容:
验 证 码:}

我要回帖

更多关于 返回头部代码 的文章

更多推荐

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

点击添加站长微信