TIF图像文件的读取(c++代码)

一 TIF图像介绍

    TIFF是最复杂的一种位图文件格式。TIFF是基于标记的文件格式,它广泛地应用于对图像质量要求较高的图像的存储与转换。由于它的结构灵活和包容性大,它已成为图像文件格式的一种标准,绝大多数图像系统都支持这种格式。

   TIFF 是一个灵活适应性强的文件格式,通过在文件头中包含“标签”它能够在一个文件中处理多幅图像和数据。标签能够标明图像的如图像大小这样的基本几何尺寸或者定义图像数据是如何排列的并且是否使用了各种各样的图像压缩选项。例如,TIFF可以包含JPEG和行程长度编码压缩的图像。TIFF文件也可以包含基于矢量的裁剪区域(剪切或者构成主体图像的轮廓)。使用无损格式存储图像的能力使TIFF文件成为图像存档的有效方法。与JPEG不同,TIFF文件可以编辑然后重新存储而不会有压缩损失。其它的一些TIFF文件选项包括多层或者多页。

  尽管现今它是一种被广泛接受的标准格式,当TIFF最初出现的时候,它的可扩展性带来了很多兼容问题。程序员可以随意定义新的标签和选项,但是并不是所有的实现程序都能支持这些所有这些创造出的标签。作为结果,它的一个最小特性集成为了“这个”TIFF,即使是在今天大量的TIFF文件和读取它们的代码都是基于简单的32位非压缩图像。

  TIFF有一个使用LZW压缩的选项,这是一种减小文件大小的无损技术,但是这项技术在不同的司法权限内为几个专利所涵盖。到了2005年,除了一个之外这些专利都已经到期,其中包括Unisys所拥有的广为人知又有很多争议的专利。另外一个著名的专利是IBM拥有的将在2006年8月11日到期的专利,IBM也没有要加强它的意思(who has shown no interest to date in enforcing it)。

  每个TIFF文件都是从指示字节顺序的两个字节开始的。“II”表示小字节在先、“MM”表示大字节在先字节顺序。后面的两个字节表示数字42。数字42是“为了其深刻的哲学意义"而选择的。 42的读法取决于头两个字节所表示的字节顺序。整个文件根据所指出的字节顺序进行读取。

  字节顺序在Apple Macintosh和微软视窗程序之间可能产生兼容性的问题,它们通常为TIFF文件使用不同的字节顺序。一些程序提供了保存为Mac或者是Windows字节顺序的选项以使文件能在交叉平台使用。

二TIF图像的读取

    1.TIF的存储结构

       TIFF文件以.tif为扩展名。其数据格式是一种3级体系结构,从高到低依次为:文件头、一个或多个称为IFD的包含标记指针的目录和数据。

    1.文件头(IFH)

  在每一个TIFF文件中第一个数据结构称为图像文件头或IFH,它是图像文件体系结构的最高层。这个结构在一个TIFF文件中是惟一的,有固定的位置。它位于文件的开始部分,包含了正确解释TIFF文件的其他部分所需的必要信息。

   

        IFH数据结构包含3个成员共计8个字节,Byte order成员可能是“MM”(0x4d4d)或“II”(0x4949),0x4d4d表示该TIFF图是摩托罗拉整数格式 0x4949表示该图是Intel整数格式;Version成员总是包含十进制42(0x2a),它用于进一步校验该文件是否为TIF格式,42这个数并 不是一般人 想象中的那样认为是tif软件的版本,实际上,42这个数大概永远不会变化;第三个成员是IFD(接下来要说的第二个数据结构)相对文件开始处的偏移量。

    2.图像文件目录(IFD)

  IFD是TIFF文件中第2个数据结构,它是一个名为标记(tag)的用于区分一个或多个可变长度数据块的表,标记中包含了有关于图像的所有信息。IFD提供了一系列的指针(索引),这些指针告诉我们各种有关的数据字段在文件中的开始位置,并给出每个字段的数据类型及长度。这种方法允许数据字段定位在文件的任何地方,且可以是任意长度,因此文件格式十分灵活。

     IFD是TIF图中最重要的数据结构,它包含了一个TIF文件中最重要的信息,一个TIF图可能有多个IFD,这说明文件中有多个图像,每个IFD标 识1个图像的基本属性。 IFD结构中包含了三类成员,Directory Entry Count指出该结构里面有多少个目录入口;接下来就是N个线性排列的DE序列,数量不定(这就是 为什么称TIF格式文件为可扩充标记的文件,甚至用户可以添加自定义的标记属性),每个DE标识了图像的某一个属性;最后就是一个偏移量, 标识下一个文件目录相对于文件开始处的位置,当然,如果该TIF文件只包含了一幅图像,那么就只有一个IFD,显然,这个偏移量就等于0;


共12个字节,见图二。简单说,一个DE就是一幅图像的某一个属性。例如图像的大小、分辨率、是否压缩、像素的行列数、一个像素由几位 表示(1位代表黑白两色,8位代表256色等等)等。其中:tag成员是该属性的编号,在图像文件目录中,它是按照升序排列的。我们可以通过读 这些编号,然后到TIF格式官方白皮书中查找相应的含义。属性是用数据来表示的,那么type就是代表着该数据的类型,TIF官方指定的有5种数据类型。type=1就是BYTE类型(8位无标记整数)、type=2是ASCII类型(7位ASCII码加1位二进制0)、type=3是SHORT类型 (16位无标记整数)、type=4是LONG 类型(32位无标记整数)、type=5是RATIONAL类型(2个LONG,第一个是分子,第二个是分母)。length成员是数据的数量而不是数据类型的长度。 第4个成员valueOffset很重要,它是tag标识的属性代表的变量值相对文件开始处的偏移量。如果变量值占用的空间小于4个字节,那么该值就存放在 valueOffset中即可,没必要再另外指向一个地方了。


      3.图像数据

  根据IFD所指向的地址.存储相关的图像信息

以下是在6.0下运行的代码

[cpp] view plaincopy
  1. #ifndef TIFREADER_H   
  2. #define TIFREADER_H   
  3.   
  4. #include <stdio.h>  
  5. #include <string.h>  
  6.   
  7. #ifndef NULL  
  8. #define NULL   0  
  9. #endif  
  10.   
  11. #ifndef TRUE  
  12. #define TRUE   1  
  13. #define FALSE  0  
  14. #endif  
  15.   
  16.   
  17. typedef struct    
  18. {  
  19.   unsigned short Byte_order;//  
  20.   unsigned short Version;//校验文件是否是TIF文件  
  21.   unsigned   int OffsetToFirstFID;//相对对文件开始处的偏移量  
  22.  // unsigned short wDECount;//多少目录入口  
  23. }IFH;  
  24.   
  25. typedef struct  
  26. {  
  27.     unsigned short tag;//属性的编号  
  28.     unsigned short type;//数据类型  
  29.     unsigned long length;//数据的数量  
  30.     unsigned long valueOffset;//tag标识的属性代表的变量值相对文件开始处的偏移量  
  31. }DE;  
  32. typedef struct    
  33. {  
  34.     int width;  
  35.     int height;  
  36.       
  37. }Size;  
  38. typedef struct   
  39.  {  
  40.     int *data;  
  41. }DATA;  
  42. typedef struct   
  43. {  
  44.     DE *pde;  
  45.     int wDECount;  
  46. }PDE;  
  47. bool readTIF(char* path,IFH &ifh,PDE &de,Size &size,DATA &Data)  
  48. {  
  49.     unsigned char *data;  
  50.     int *dat;  
  51.     unsigned short wDECount;//多少目录入口  
  52.       
  53. //  ZeroMemory(&ifh, sizeof(IFH));  
  54. //  ZeroMemory(&de, sizeof(DE));  
  55.   
  56.     FILE *fp;  
  57.     fp=fopen(path,"rb");  
  58.     if(fp == NULL)  
  59.     {  
  60.         cout<<"open file error"<<endl;  
  61.         return false;  
  62.     }  
  63.     if(sizeof(IFH) != fread(&ifh, 1,sizeof(IFH),fp))  
  64.     {  
  65.         cout<<"读TIF文件头失败";  
  66.         return FALSE;  
  67.     }  
  68.      if(0x2a != ifh.Version)  
  69.      {  
  70.           cout<<"该文件不是TIF格式,读文件失败";  
  71.           return FALSE;  
  72.      }  
  73.   
  74.      if(0x4949 != ifh.Byte_order)  
  75.      {  
  76.           cout<<"该TIF文件不是IBMPC字节序,读文件失败";  
  77.           return FALSE;  
  78.      }  
  79.   
  80.      fseek(fp,ifh.OffsetToFirstFID,SEEK_SET);//将文件指针定位到IFD  
  81.      //读文件有多少个目录入口   
  82.     if(2 != fread(&wDECount,1,sizeof(unsigned short),fp))  
  83.      {  
  84.           cout<<"无法获得TIF文件目录入口数量";  
  85.           return FALSE;  
  86.      }  
  87.     cout<<"该TIF文件有"<<wDECount<<"个目录入口"<<endl;  
  88.     //创建DE数组,接收信息,数组中有wDECount个元素   
  89.     de.pde = new DE[wDECount];  
  90.     DE* pTemp = de.pde;  
  91.     de.wDECount = wDECount;  
  92.     memset(de.pde, 0, sizeof(DE)*wDECount);  
  93.      if(sizeof(DE)*wDECount != fread(de.pde,1, sizeof(DE)*wDECount,fp))  
  94.      {  
  95.           cout<<"读图象文件目录失败";  
  96.           delete []de.pde;  
  97.           return false ;  
  98.      }  
  99.     //把图像的大小和图像数据的容量保存到成员变量中  
  100.      int m_size_x;  
  101.      int m_size_y;  
  102.      int m_size;  
  103.      int i;  
  104.     for(i=0; i<wDECount; i++)  
  105.      {  
  106.           pTemp =de.pde + i;  
  107.           if(256 == pTemp->tag) //tag为256的目录入口中的变量标识了图象宽度  
  108.           {  
  109.               m_size_x = pTemp->valueOffset;  
  110.           }  
  111.           if(257 == pTemp->tag) //图象高度  
  112.           {  
  113.               m_size_y = pTemp->valueOffset;  
  114.           }  
  115.           if(273 == pTemp->tag) //计算图象数据占用字节数  
  116.           {  
  117.            //m_dwBmSize = pTemp->valueOffset - sizeof(IFH);  
  118.            //或者把tag=256的valueOffset乘以tag=257的valueOffset  
  119.               m_size = m_size_x * m_size_y;  
  120.           }  
  121.     }  
  122.     //填充所有像素数据, 颠倒图象数据从最后一行开始读起  
  123.      int j = 0;  
  124.     // int i = 0;  
  125.      data = (unsigned char*)malloc(m_size*sizeof(BYTE));  
  126.      dat = (int*)malloc(m_size*sizeof(int));  
  127.      for(i=m_size_y-1; i>=0; i--)  
  128.      {  
  129.          fseek(fp,sizeof(IFH) + i*m_size_x, SEEK_SET);  
  130.          fread((BYTE*)(data + 1) + j*m_size_x,sizeof(BYTE), m_size_x,fp);  
  131.           j++;  
  132.      }  
  133.      cout<<"width:"<<m_size_x<<endl;  
  134.      cout<<"height:"<<m_size_y<<endl;  
  135.      unsigned char* p;  
  136.      p = data;  
  137.      int *ptr;  
  138.      ptr = dat;  
  139.      for (i=0;i<m_size;i++,p++,ptr++)  
  140.      {  
  141.          *ptr = (int)(*p);  
  142.          int  h= *ptr;  
  143.         // cout<<h<<" ";  
  144.      }  
  145.      size.width = m_size_x;  
  146.      size.height = m_size_y;  
  147.      Data.data = dat;  
  148.      return TRUE;  
  149.     
  150. }  
  151. bool saveTIF(char* path,IFH ifh,PDE de,Size size,DATA Data)  
  152. {  
  153.     unsigned char *data;  
  154. //    unsigned short wDECount;//多少目录入口  
  155.       
  156. //  ZeroMemory(&ifh, sizeof(IFH));  
  157. //  ZeroMemory(&de, sizeof(DE));  
  158.   
  159.     FILE *fp;  
  160.     fp=fopen(path,"wb");  
  161.     if(fp == NULL)  
  162.     {  
  163.         cout<<"open file error"<<endl;  
  164.         return false;  
  165.     }  
  166.     if(sizeof(IFH) != fwrite(&ifh, 1,sizeof(IFH),fp))  
  167.     {  
  168.         cout<<"写TIF文件头失败";  
  169.         return FALSE;  
  170.     }  
  171.      fseek(fp,ifh.OffsetToFirstFID,SEEK_SET);//将文件指针定位到IFD  
  172.      //读文件有多少个目录入口   
  173.     if(2 != fwrite(&de.wDECount,1,sizeof(unsigned short),fp))  
  174.      {  
  175.           cout<<"无法获得TIF文件目录入口数量";  
  176.           return FALSE;  
  177.      }  
  178.     //创建DE数组,接收信息,数组中有wDECount个元素   
  179.    
  180.      if(sizeof(DE)*de.wDECount != fwrite(de.pde,1, sizeof(DE)*de.wDECount,fp))  
  181.      {  
  182.           cout<<"读图象文件目录失败";  
  183.           return false ;  
  184.      }  
  185.     //填充所有像素数据, 颠倒图象数据从最后一行开始读起  
  186.      int j = 0;  
  187.      int i = 0;  
  188.      data = (unsigned char*)malloc(size.width*size.height*sizeof(BYTE));  
  189.      int *ptr = Data.data;  
  190.   
  191.      unsigned char* p;  
  192.      p = data;  
  193.      for (i=0;i<size.width*size.height;i++,p++,ptr++)  
  194.      {  
  195.          *p = (unsigned char)(*ptr);  
  196.         // int  h= *ptr;  
  197.         // cout<<h<<" ";  
  198.      }    
  199.      for(i=size.height-1; i>=0; i--)  
  200.      {  
  201.          fseek(fp,sizeof(IFH) + i*size.width, SEEK_SET);  
  202.          fwrite((BYTE*)(data + 1) + j*size.width,sizeof(BYTE), size.width,fp);  
  203.           j++;  
  204.      }  
  205.   
  206.      return TRUE;  
  207.     
  208. }  
  209. #endif  


这个代码这是对特定的TIF进行读取,在保存时不知道为什么,不能再windows下正常显示,期待大侠解决呀

转载于:https://www.cnblogs.com/ainima/p/6331168.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/259148.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

g menu i meun_长沙话读“这里”,到底是阁(gó)里还是该(gái)里

“带笼子”、“打抱秋”……这些地道的长沙话&#xff0c;长沙人&#xff0c;你有多久没听过了&#xff1f;/ 长沙人&#xff0c;你还记得长沙话吗 / “去了很多地方&#xff0c;最后还是回到了长沙”“我听见了一句长沙话&#xff0c;就想回长沙了。”逗霸妹听过很多人回长沙的…

git使用---工作区和暂存区

转载于:https://www.cnblogs.com/momo-unique/articles/4380551.html

UC/OS-II的学习

粗略的的看了邵贝贝老师的那本书&#xff0c;感觉有点眉目。UC/OS-II的全局变量繁多&#xff0c;刚接触的时候容易弄混淆&#xff0c;现在总结下&#xff1a; OSRunning&#xff1a; 用于标识多任务环境是否已经开启运行&#xff0c;在OSStart()函数里启动任务后就置为True。 …

偶数哥德巴赫猜想

已知不小于6的偶数都可以分成两个素数之和。请编写6到100000的所有偶数的分解&#xff0c;若有一个偶数可以分解成多个素数之和&#xff0c;只需写出一种即可。 #include <iostream> #include <algorithm> using namespace std;bool isprime(int n)//判断素数{int …

[20170420]表达式加0或者减0不一样.txt

[20170420]表达式加0或者减0不一样.txt --//oracle 有时候避免某个索引采用字段0或者-0的方式&#xff0c;不使用索引&#xff0c;但是两者存在一点点区别&#xff0c;通过例子说明。 1.环境&#xff1a; SCOTTbook> &r/ver1 PORT_STRING VERSION …

MAPLAP开发环境中release模式和debug模式烧写.hex文件的不同之处

昨天看了齐工的报告才知道release模式和debug模式烧写.hex文件的不同。 三&#xff1a;问题分析 1. PIC系列的仿真器和集成开发环境的情况&#xff1a; Release模式和Debug模式是有区别的&#xff1b;Release模式是只把代码烧录到单片机的flash区内&#xff0c;上电执行&am…

JavaWeb -- Session实例 -- 自动登录 和 防止表单重复提交(令牌产生器) MD5码

1、 自动登录 http://blog.csdn.net/xj626852095/article/details/16825659 2. 防止表单重复提交 表单Servlet //负责产生表单 public class FormServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletEx…

电脑常见故障处理_彩超常见故障及维修

彩超是医学检测手段中重要的环节之一&#xff0c;是对产妇以及对病人进行内部组织和结构观察的重要方式之一&#xff0c;彩超应用得当可以及早的诊断出病人的疾病&#xff0c;为患者解除疾病的困扰。彩超设备是一种极为先进的诊断系统&#xff0c;一般彩超系统包括以下几个部分…

微软历史最高市值是多少?

有人说微软在1999 年 12 月达到股价历史最高点 $58.38并不准确。我1999年12月22日增加微软&#xff0c;公司依照1999年12月27日的价格&#xff08;119.125&#xff0c;拆股后变为59.5625&#xff09;给了我一笔期权&#xff0c;这个价格&#xff0c;成为微软股价空前绝后最高点…

京东2016校招编程题

记得有一个大题&#xff0c;说的是给定一个n*n的矩阵&#xff0c;要求从1开始填充矩阵&#xff0c;最后的矩阵是蛇形的。即如下&#xff1a; n3, 7 8 1 6 9 2 5 4 3 n4, 10 11 12 1 9 16 13 2 8 15 14 3 7 6 5 4 给出代码&#xff1a; #incl…

leetcode21

/*** Definition for singly-linked list.* public class ListNode {* public int val;* public ListNode next;* public ListNode(int x) { val x; }* }*/ public class Solution {public ListNode MergeTwoLists(ListNode l1, ListNode l2) {//递归实现链表合并…

springmvc02

1&#xff0c;创建实体类对象User 注意要导入 bean-validator.jar 包 package com.yangw.springmvc.entity;import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotEmpty; import org.hibernate.validator.constraints.Range; im…

用基本信号画出如下的信号_股市入门基本知识丨下跌时期可以抄底的安全信号有哪些...

点击蓝色字体 关注我们 带来更多精彩股票市场中的秘籍其实就是“低买高卖”&#xff0c;不过我们不能在大盘一开始下跌的时候就进行买入&#xff0c;因为不清楚下跌的时间&#xff0c;太早介入&#xff0c;只有在反弹幅度超出我们介入的点的时候才可以进行高卖。那么什么时候才…

Flume数据传输事务分析[转]

本文基于ThriftSource,MemoryChannel,HdfsSink三个组件&#xff0c;对Flume数据传输的事务进行分析&#xff0c;如果使用的是其他组件&#xff0c;Flume事务具体的处理方式将会不同。一般情况下&#xff0c;用MemoryChannel就好了&#xff0c;我们公司用的就是这个&#xff0c;…

最近的一些校招试题摘录

最近又参加了一些校招&#xff0c;真是马不停蹄啊。多参加考试是好的&#xff0c;可以不断发现一些新的问题。下面摘录一些我不太会的题。 1.volatile的作用是什么&#xff1f; 答案&#xff1a;volatile是类型修饰符&#xff0c;用它修饰的类型变量可能会被编译器未知的因素…

yii2中的rules验证规则

2019独角兽企业重金招聘Python工程师标准>>> Rules验证规则&#xff1a;required : 必须值验证属性||CRequiredValidator 的别名, 确保了特性不为空.[[字段名],required,requiredValue>必填值,message>提示信息];email : 邮箱验证||CEmailValidator 的别名,确…

weblogic数据源配置的问题,weblogic密码破解

weblogic 报错 please increase XXX,得知是连接池出了问题&#xff0c;查看weblogic配置&#xff0c;发现没有设置超时 查看oracle 当前session&#xff0c;可以看到连接的机器&#xff0c;用户&#xff0c;当前执行的sqlid select * from v$session; select v$sql where sql_i…

自己写的简易多任务系统---基于pic18fxxx

这个工程只是实现了最简单的OS任务调度&#xff0c;对于理解任务调度有点帮助。其实就是从UC/OS-II里面摘出来的&#xff0c;没有原来的那么复杂&#xff0c;很精简&#xff0c;但道理上是一样的。工程中的CPU.C文件时直接拿Nathan Brown写好的&#xff0c;因为关于PIC任务切换…

python语言整数类型-Python 的内置数值类型

Python 是一种敏捷的、动态类型化的、极富表现力的开源编程语言&#xff0c;可以被自由地安装到多种平台上。Python 代码是被解释的。如果您对编辑、构建和执行循环较为熟悉&#xff0c;则 Python 代码对您来说更简单。但是&#xff0c;请不要搞错&#xff1a;Python 器可以是简…

滴滴出行2016校招编程题

1. 给定一个m*n的数组&#xff08;m,n>2,数组值>0&#xff09;&#xff0c;要求选出和最大的子2*2数组。例如&#xff1a; 1 2 3 4 5 6 7 8 9 显然和最大的2*2子数组是5 6;8 9.下面完成这个功能。 Input: &#xff08;m*n的数组&#xff09; 1 2 3 ; 4 5 6 ; 7 8 9 …