鼓楼医院高级专家门诊:各种图片文件格式及pcx格式的介绍

来源:百度文库 编辑:九乡新闻网 时间:2024/04/27 15:36:36
各种图片文件格式及pcx格式的介绍 2007-07-27 10:58

先来看看几种位图文件格式简介:

bmp文件

  bmp(bitmap的缩写)文件格式是windows本身的位图文件格式,所谓本身是指windows内部存储位图即采用这种格式。一个.bmp格式的文件通常有.bmp的扩展名,但有一些是以.rle为扩展名的,rle的意思是行程长度编码(runlengthencoding)。这样的文件意味着其使用的数据压缩方法是.bmp格式文件支持的两种rle方法中的一种。

  bmp文件可用每象素1、4、8、16或24位来编码颜色信息,这个位数称作图象的颜色深度,它决定了图象所含的最大颜色数。一幅1-bpp(位每象素,bitperpixel)的图象只能有两种颜色。而一幅24-bpp的图象可以有超过16兆种不同的颜色。

  下一页的图说明了一个典型.bmp文件的结构。它是以256色也就是8-bpp为例的,文件被分成四个主要的部分:一个位图文件头,一个位图信息头,一个色表和位图数据本身。位图文件头包含关于这个文件的信息。如从哪里开始是位图数据的定位信息,位图信息头含有关于这幅图象的信息,例如以象素为单位的宽度和高度。色表中有图象颜色的rgb值。对显示卡来说,如果它不能一次显示超过256种颜色,读取和显示.bmp文件的程序能够把这些rgb值转换到显示卡的调色板来产生准确的颜色。

  bmp文件的位图数据格式依赖于编码每个象素颜色所用的位数。对于一个256色的图象来说,每个象素占用文件中位图数据部分的一个字节。象素的值不是rgb颜色值,而是文件中色表的一个索引。所以在色表中如果第一个r/g/b值是255/0/0,那么象素值为0表示它是鲜红色,象素值按从左到右的顺序存储,通常从最后一行开始。所以在一个256色的文件中,位图数据中第一个字节就是图象左下角的象素的颜色索引,第二个就是它右边的那个象素的颜色索引。如果位图数据中每行的字节数是奇数,就要在每行都加一个附加的字节来调整位图数据边界为16位的整数倍。

  并不是所有的bmp文件结构都象表中所列的那样,例如16和24-bpp,文件就没有色表,象素值直接表示rgb值,另外文件私有部分的内部存储格式也是可以变化的。例如,在16和256色.bmp文件中的位图数据采用rle算法来压缩,这种算法用颜色加象素个数来取代一串颜色相同的序列,而且,windows还支持os/2下的.bmp文件,尽管它使用了不同的位图信息头和色表格式。

pcx文件

  .pcx是在pc上成为位图文件存储标准的第一种图象文件格式。它最早出现在zsoft公司的paintbrush软件包中,在80年代早期授权给微软与其产品捆绑发行,而后转变为microsoftpaintbrush,并成为windows的一部分。虽然使用这种格式的人在减少,但这种带有.pcx扩展名的文件在今天仍是十分常见的。

  pcx文件分为三部分,依次为:pcx文件头,位图数据和一个可选的色表。文件头长达128个字节,分为几个域,包括图象的尺寸和每个象素颜色的编码位数。位图数据用一种简单的rle算法压缩,最后的可选色表有256个rgb值,pcx格式最初是为cga和ega来设计的,后来经过修改也支持vga和真彩色显示卡,现在pcx图象可以用1、4、8或24-bpp来对颜色数据进行编码。

tiff文件

  pcx格式是所有位图文件格式中最简单的,而tiff(taggedimagefileformat)则是最难的一种。

  tiff文件含有.tif的扩展名。它以8字节长的图象文件头开始(ifh),这个文件头中最重要的成员是一个指向名为图象文件目录(ifd)的数据结构的指针。ifd是一个名为标记(tag)的用于区分一个或多个可变长度数据块的表,标记中含有关于图象的信息。tiff文件格式定义70多种不同类型的标记,有的用来存放以象素为单位的图象宽度和高度,有的用来存放色表(如果需要的话),当然还必须有用来存放位图数据的标记,一个tiff格式文件完全为它的标记所决定,而且这种文件结构极易扩展,因为你要附加一些特征只须增加一些额外的标记。

  究竟是什么使tiff文件如此复杂?一方面,要写一种能够识别所用不同标记的软件非常困难。大多数tiff的阅读程序只能识别一部分标记,所以会出现这种情况:有时一个应用程序创建的tiff文件,另一个应用程序却不能使用。创建tiff文件的程序还可能会在文件中加一些只有它自己认识的标记,虽然tiff的阅读程序可以跳过那些它们不认得的标记,但这样做总是有可能影响到图象的质量。

  另一方面,一个tiff文件可以包含多个图象,每个图象都有自己的ifd和一系列标记。tiff文件中的位图数据可能会用好几种方法来压缩,所以一个完备的tiff阅读程序应该有rle解压缩程序,lzw解压缩程序和其他一些算法的解压缩程序。然而更糟的是使用lzw的解码必须得到unisys公司的同意,且通常是需要付版税的。所以即使是一些相当不错的tiff阅读程序在它们遇到lzw算法压缩的图象时也是无能为力的。

  尽管tiff是那么的复杂,但仍是一种最好的跨平台格式。因为它非常灵活,无论在视觉上还是其他方面,都能把任何图象编码成二进制形式而不丢失任何属性。

gif文件

  当许多图象方面的权威一想到lzw的时候,他们也会想到gif(graphicsinterchangeformat,读作jiff)这是一种常用的跨平台的位图文件格式,最初为compuserve公司所创。gif文件通常带有.gif的扩展名,而且在compuseve上大量存在。

  gif文件的结构取决于它属于哪一个版本,目前的两种版本分别是gif87a和gif89a,前者较简单。无论是哪个版本,它都以一个长13字节的文件头开始,文件头中包含判定此文件是gif文件的标记、版本号和其他的一些信息。如果这个文件只有一幅图象,文件头后紧跟一个全局色表来定义图象中的颜色。如果含有多幅图象(gif和tiff格式一样,允许在一个文件里编码多个图象),那么全局色表就被各个图象自带的局部色表所替代。

  在gif87a文件中,文件头和全局色表之后是图象,它可能会是头尾相接的一串图象中的第一个,每个图象由三部分组成,一个10字节长的图象描述,一个可选的局部色表和位图数据。为有效利用空间,位图数据用lzw算法来压缩。

  gif89a结构与此类似,但它还包括可选的扩展块来存放每个图象的附加信息。gif89a详细定义了四种扩展块:图象控制扩展块,它用来描述图象怎样被显示(例如,显示是应该象一个透明物去覆盖上一个图象,还是简单的替换它);简单文本扩展块,它包含显示在图象中的文本;注释扩展块,它以ascii文本形式存放注释;应用扩展块,它存放生成该文件的应用程序的私有数据。这些扩展块可以出现在文件中全局色表的任何地方。

  gif最显著的优点是它的广泛使用和它的紧密性。但它有两个弱点,一个是用gif格式存放的文件最多只能含有256种颜色。另一个可能更重要,就是那些使用了gif格式的软件开发者必须征得compuserve的同意,他们每卖出一个拷贝都要向compuserve付版税。这个政策是compuserve仿效unisys公司作出的,它抑制了那些程序员在他的图象应用程序中支持gif文件。

png文件

  png(portablenetworkgraphic,发音做ping)文件格式是作为gif的替代品开发的,它能够避免使用gif文件所遇到的常见问题。它从gif那里继承了许多特征,而且支持真彩色图象。更重要的是,在压缩位图数据时它采用了一种颇受好评的lz77算法的一个变种,lz77则是lzw的前身,而且可以免费使用。由于篇幅所限,在这里就不花时间来具体讨论png格式了。

jpeg文件

  jpeg(jointphotographicexpertsgroup,发音做jay-peg)文件格式最初由c-cubemicrosystems推出,是为了提供一种存储深度位象素的有效方法,例如对于照片扫描,颜色很多而且差别细微(有时也不细微)。jpeg和这里讨论的其他格式的最大区别是jpeg使用一种有损压缩算法,无损压缩算法能在解压后准确再现压缩前的图象,而有损压缩则牺牲了一部分的图象数据来达到较高的压缩率。但是这种损失很小以至于人们很难察觉。

  jpeg图象压缩是一个复杂的过程,经常需要专门的硬件来帮助。首先图象以象素为单位分成8*8的块。然后,每个块分三个步骤被压缩。第一步使用dct(discretecosinetransform)离散余弦变换把8*8的象素矩阵变成8*8的频率(也就是颜色改变的速度)矩阵。第二步对频率矩阵中的值用量化矩阵进行量化,滤掉那些总体上对图象不重要的部分。第三步,也就是最后一步,对量化后的频率矩阵使用无损压缩。

  因为被量化后的频率矩阵缺了许多高频信息,通常能被压缩到一半甚至更少。无损压缩一般根本不能压缩真正的照片图象,所以50%的压缩率已是相当不错了,但另一方面,无损压缩能把一些图象文件尺寸减少90%,这样的图象文件就不适合用jpeg来压缩。

  jpeg的有损部分产生在第二步,量化矩阵的值越高,从图象中丢掉的信息就越多,从而压缩率就越高,可是同时图象的质量就越差。在jpeg压缩时可以选择一个量化因子,这个因子的值决定了量化矩阵中的数值。理想的量化因子要在压缩率和图象质量间达到平衡,所以对不同的图象要选择不同的量化因子,通常要经过若干次尝试后方可确定。

=======================================================================

PCX图象格式[转]

PCX图象文件按顺序包含文件头结构、图象数据和调色板(256色图象)等三个部分。
1、文件头结构:
typedef struct tagPCXFILEHEADER
{
BYTE Manufacturer;
BYTE Version;
BYTE Encoding;
BYTE BitsPerPixel;
UINT XMin,YMin;
UINT XMax,YMax;
UINT XRes,YRes;
BYTE Palette[48];
BYTE Reserved;
BYTE ColorPlanes;
UINT BytesPerLine;
UINT PaletteType;
BYTE Filler[58];
} PCXFILEHEADER;
(1)、黑白图象文件头结构:
Mnufacturer=0x0a; //PCX图象文件标志
Version=5;
Encoding=1; //PCX图象文件中的图象数据总是压缩数据
BitsPerPixel=1;
XMin=0;
YMin=0;
XMax=图象宽度-1; //象素
YMax=图象高度-1; //象素
XRes=图象横向分辩率;//象素/英寸(DPI)
YRes=图象纵向分辩率;//象素/英寸(DPI)
Palette[48]; //无效
Reserved; //保留
ColorPlanes=1;
BytesPerLine=每行图象数据的字节宽度;//=(象素宽度+7)/8
PaletteType=2;
Filler[58]; //无效
(2)、灰度图象文件头结构:
Mnufacturer=0x0a;
Version=5;
Encoding=1;
BitsPerPixel=8;
XMin=0;
YMin=0;
XMax=图象宽度-1; //象素
YMax=图象高度-1; //象素
XRes=图象横向分辩率;//象素/英寸(DPI)
YRes=图象纵向分辩率;//象素/英寸(DPI)
Palette[48]; //无效
Reserved; //保留
ColorPlanes=1;
BytesPerLine=每行图象数据的字节宽度;//=象素宽度
PaletteType=2;
Filler[58]; //无效
(3)、256色图象文件头结构:
Mnufacturer=0x0a;
Version=5;
Encoding=1;
BitsPerPixel=8;
XMin=0;
YMin=0;
XMax=图象宽度-1; //象素
YMax=图象高度-1; //象素
XRes=图象横向分辩率;//象素/英寸(DPI)
YRes=图象纵向分辩率;//象素/英寸(DPI)
Palette[48]; //无效
Reserved; //保留
ColorPlanes=1;
BytesPerLine=每行图象数据的字节宽度;//=象素宽度
PaletteType=1;
Filler[58]; //无效
(4)、真彩色图象文件头结构:
Mnufacturer=0x0a;
Version=5;
Encoding=1;
BitsPerPixel=8;
XMin=0;
YMin=0;
XMax=图象宽度-1; //象素
YMax=图象高度-1; //象素
XRes=图象横向分辩率;//象素/英寸(DPI)
YRes=图象纵向分辩率;//象素/英寸(DPI)
Palette[48]; //无效
Reserved; //保留
ColorPlanes=3;
BytesPerLine=每行图象数据的字节宽度;//=象素宽度
PaletteType=1;
Filler[58]; //无效
2、图象数据
PCX图象文件对原始图象以字节为单位进行游程编码压缩,压缩算法描述如下:
(1)、从一行图象数据的第一个字节开始,M=1,V=字节值。
(2)、检查具有相同值V的连续字节个数N。
(3)、如果N>1
如果N>63,则N=63
以两个字节表示这N个字节,字节1=N,字节2=V
如果N=1
如果V>63,以两个字节表示这N个字节,字节1=1,字节2=V
否则,以一个字节表示,字节1=V。
(4)、M=M+N,从第M个字节开始,V=字节值,重复2-4的步骤,直到行结束。
黑白图象:
原始数据为每象素一位,象素值=0(黑)/1(白),按行对原始数据进行压缩。
灰度图象:
每象素一个字节,象素值=灰度级(0-255),按行对原始数据进行压缩。
256色图象:
每象素一个字节,象素值=调色板索引号,按行对原始数据进行压缩。
每行真彩色图象的数据分成三行,分别是R行、G行、B行(而不是按RGBRGB...的格式
存放),对这三行数据分别进行压缩。
3、调色板
只有256色图象含有调色板,调色板数据共有256×3+1=769个字节,这是因为第一个字
节是调色板数据的标志,为0x0c。
调色板结构:
typedef struct tagPCXPALETTE
{ BYTE rgbRed;
BYTE rgbGreen;
BYTE rgbBlue;
} PCXPALETTE;
在PCX图象中,我们是按照BitPerPixle,ColorPlanes和Palette的值来判断它倒底是何种
类型。=============================================

PCX 图象文件格式的读写[转]

PCX图象文件格式最早出现于Zsoft公司开发的PC Paintbrush绘图软件,由于该绘图软件功能强大并成功移植到Windows操作系统,
加上PCX是最早支持彩色的图象格式之一,PCX成为目前比较流行的图象格式。

对于开发图象浏览、处理软件的程序员来讲,如何读取、保存PCX图象格式是最为基本的话题,作者根据自己对PCX图象格式理解,
开发了相应的代码,希望对读者有用,由于篇幅限制,在此对文件格式不予介绍,读者可以参考相关数目。

代码如下,调用方法程序段之后简单讲解,水平有限,还请包涵;我的电子信箱是:cadinfo@263.net,欢迎探讨。

========================================================
/****************************************************************************
* 函数名称:LoadPCXLine(PPCXHEAD ppcxHdr, LPBYTE ppcxImg, LPBYTE ppcxBits) const
*
* 参数:PPCXHEAD ppcxHdr -指向PCXHEAD结构的指针!NULL,导入BitPlane,BytePerLine,=>clScanLineSize
* LPBYTE ppcxImg -指向PCX图象区指针!NULL,RLE压缩编码,位置递增+=rec。
*      调用之前获得首地址指针:
* LPBYTE ppcxBits -指向DIB数据区的指针,按扫描行(scanline)长度递增
*
* 返回:UINT rec -返回每行解压以后的字节数目
*
* 说明:根据PCX图象数据指针,对RLE进行解码
****************************************************************************/
UINT CPcxImage::LoadPCXLine(PPCXHEAD ppcxHdr, LPBYTE ppcxImg, LPBYTE ppcxBits) const
{
ASSERT(ppcxHdr!=NULL&&ppcxImg!=NULL&&ppcxBits!=NULL);

// because in bitmap bits order, it's blue=>green=>red
// however pcx is red=>green=>blue so use decrease order
//-----------------------------------------
UINT lPos(0),   // 记录存入ppcxBits的总数
    iX(0), // 记录每个位平面字节序号
    rec(0); // 读取_ppcxImg_ 字节序号
for ( int bp=ppcxHdr->BitPlane-1; bp >= 0;   bp-- )
{
   // RLE 解码=======
   iX=0;
  
   while ( iXBytePerLine )
   {
    BYTE uiValue = ppcxImg[rec++];
    if ( (uiValue & 0xc0) == 0xc0 )   // 判断高位字节是否设置 0xc0
    {
     uiValue = uiValue & 0x3f ;   // 计算重复
     BYTE Color = ppcxImg[rec++]; // 提取颜色
    
     // 存放到内存DIB
     for ( BYTE bRepeat=0; bRepeat < uiValue; bRepeat++ )
     {
      ppcxBits[(iX++)*ppcxHdr->BitPlane+bp] = Color;
      lPos++;
     }
    }
    else
    {
     ppcxBits[(iX++)*ppcxHdr->BitPlane+bp] = uiValue;
     lPos++;
    }
   }
  
}

return rec;
}


/****************************************************************************
* 函数名称:PackPCXLine(PPCXHEAD ppcxHdr, LPBYTE ppcxImg, LPBYTE ppcxBits) const
*
* 参数:PPCXHEAD ppcxHdr -指向PCXHEAD结构的指针!NULL,导入BitPlane,BytePerLine,=>clScanLineSize
* LPBYTE ppcxBits -指向DIB数据区的指针,按扫描行(scanline)长度递增
* LPBYTE ppcxImg -指向PCX图象区指针!NULL,RLE压缩编码。
*      调用之前声明: LPBYTE ppcxImg=new BYTE[2*BitPlane*BytePerLine]
*
* 返回:UINT rec -返回每行压缩以后的字节数目
*
* 说明:根据DIB图象数据指针,进行RLE编码(经过测试算法很完善,支持256和24bit真彩色)
****************************************************************************/
UINT CPcxImage::PackPCXLine(PPCXHEAD ppcxHdr, LPBYTE ppcxBits, LPBYTE ppcxImg) const
{
//----------------------------------------
// RLE压缩
ASSERT(ppcxHdr!=NULL && ppcxBits!=NULL && ppcxImg!=NULL);

BYTE i(1);
UINT lPos(0), rec(0);

// ☆RLE编码,最大重复<=63☆
for(int bp=ppcxHdr->BitPlane-1; bp>=0; bp--)
{
   lPos=0;   // 处理到的RGB序列

   while(lPosBytePerLine)   // 等价小于图象宽度
   {
    i=1; // 重置步长-1
   
    //----------------->以下代码检查
    while((ppcxBits[(i-1+lPos)*ppcxHdr->BitPlane+bp]==ppcxBits[(i+lPos)*ppcxHdr->BitPlane+bp])
     &&((lPos+i)BytePerLine)&&(i<63)) i++;
    if(i>1 && i<64)
    {
     // 表明当前象素位置开始存在i个重复象素值,依次写入PCX图象数据Buffer
     // 1.重复次数
     ppcxImg[rec++]=i|0xc0;
     // 2.象素值
     ppcxImg[rec++]=ppcxBits[lPos*ppcxHdr->BitPlane+bp];
    
     lPos+=i; // lPos-记录当前扫描行中已经处理的字节数
     // rec -记录当前已经写入PCX文件的字节数
    }
    else
    {
     // 表明当前象素位置开始不存在重复象素值
     // 象素值大于0xc0(192),写标志0xc1
     if((ppcxBits[lPos*ppcxHdr->BitPlane+bp]&0xc0)==0xc0) ppcxImg[rec++]=0xc1;
     ppcxImg[rec++]=ppcxBits[lPos*ppcxHdr->BitPlane+bp]; lPos++;
    }
   }
}

// 写图象数据结束
return rec;
}

===========================================================
调用如下:
1.// RLE解码-------------> 已经包含8、24bit图象
for( int iY=0; iY<=ppcxHdr->YMax; iY++ )
{
   ZeroMemory(ppcxBits, clScanLineSize);
   ppcxImg+=LoadPCXLine(ppcxHdr, ppcxImg, ppcxBits); // 读取扫描行数据
   ppcxBits+=clScanLineSize;
}
ppcxHdr是指向PCXHEAD结构(128BYTE)的指针,ppcxBits是存放解码后图象数据的buffer,ppcxImg是指向pcx图象文件
中图象数据的指针,此处随扫描行递增。完成功能是从pcx文件中解码图象数据到windows位图格式的图象数据。

2.// RLE压缩-------------> 已经包含8、24bit图象
// 最坏情况下申请2倍的缓冲,相邻都不重复,并且都大于0xc0
LPBYTE ppcxImg=new BYTE[2*pcxHdr.BitPlane*pcxHdr.BytePerLine]; // 存放临时扫描行
UINT rec(0); // 计数器,写如PCX文件字节数
for( int iY=0; iY<=pcxHdr.YMax; iY++ )
{
   ZeroMemory(ppcxImg,2*pcxHdr.BitPlane*pcxHdr.BytePerLine);
   rec=PackPCXLine(&pcxHdr, ppcxBits, ppcxImg);
  
   // DIB 扫描行递增
   ppcxBits+=clScanLineSize;
  
   pFile->Write(ppcxImg,rec);
}
delete []ppcxImg;
具体参数大致同1.ppcxImg为临时RLE压缩后的buffer。
------【OVER】------