用qt编写的解析tiff文件的类

本机系统配置:ThinkPadT570、Windows10、QT5.12.2(QtCreater4.8.2)
需求如下:我们需要用qt导入16位深的tiff灰度图,但用QImage只能导入8位深的tiff灰度图,如果用qt的QImage导入16位深的灰度图,图像数据会被强制转换成argb格式的图像,数据就被更改了,所以我需要自己编写一个解析tiff文件的功能,我翻阅了很多博客,其中如下链接给我的帮助最大:
https://blog.csdn.net/chenlu5201314/article/details/56276903
上述博客作为详细解析tiff文件结构的说明文档,写的非常详细,我也是根据上面的内容,自己编写了一个解析tiff文件的类(当然功能很少,只能解析符合特定条件的tiff文件),具体如下:
头文件:

#ifndef MYTIFLIB_H
#define MYTIFLIB_H
//************************************************************
//by Bruce Xu
//注:该类只解析特定的tiff文件!
//1.解析的tiff文件中只存在一幅图,如果文件中存在多幅图,本类不支持解析!
//2.图像数据为8位或16位深度的灰度图,如果是其他类型的图片,本类不支持解析!
//3.图片没有被压缩过!
//************************************************************
#include <QObject>
#include <QVector>
#include <QString>
#include <QFile>
struct MY_IFH//Image File Head
{
    qint16          nByteOrder;//TIF标记,其值为0x4D4D或0x4949
    qint16          nVersion;//版本号,其值恒为0x2A
    qint32          nOffset2FirstIFD;//第一个IFD的偏移量
};
struct MY_DE//Directory Entry
{
    qint16          nTagID;//本属性的标签编号
    qint16          nType;//本属性值的数据类型
    qint32          nLength;//该种类型的数据的个数,而不是某个数据的长度
    qint32          nValueOffset;//tagID代表的变量值相对文件开始处的偏移量,但如果变量值占用的空间不多于4个字节(例如只有1个Integer类型的值),那么该值就直接存放在valueOffset中,没必要再另外指向一个地方了。
};
struct MY_IFD//image file directory
{
    qint16          nIDNum;//本IFD中DE的数量
    QVector<MY_DE>  vMyDE;//本IFD中的DE
};

struct MY_ImgInfo//图片属性信息
{
    qint32          nHeight;//图像的宽度
    qint32          nWidth;//图像的高度
    qint16          nDepth;//图像的深度
    bool            bCompressed;//图像是否被压缩
    qint32          nDataOffset;//图像第一个像素数据距离的偏移多少字节
    qint32          nDataSize;//图像数据字节总数
};

struct MY_TIFF//Image File Struct
{
    MY_IFH                  tMyIFH;//Image File Head
    MY_IFD                  tMyIFD;//放image file directory的容器
    QVector<unsigned char>  vUcharData;//如果是8位深的灰度图用unsigned char 放数据
    QVector<unsigned short> vShortData;//如果是16位深的灰度图用short* 放数据
    MY_ImgInfo              tImgInfo;//图片属性信息
};

class MyTifLib
{
public:
    MyTifLib();
    ~MyTifLib();
    bool            ParseTIFF(QString sFilePath, MY_TIFF &myTIFF);
};

#endif // MYTIFLIB_H

源文件:

#include "mytiflib.h"
MyTifLib::MyTifLib()
{    
}    
MyTifLib::~MyTifLib()
{    
}    
bool MyTifLib::ParseTIFF(QString sFilePath, MY_TIFF &myTIFF)
{
    QFile file(sFilePath);
    if(!file.open(QIODevice::ReadOnly))
    {
        return false;
    }
    QByteArray t = file.readAll();
    file.close();
    memcpy((char*)&myTIFF.tMyIFH.nByteOrder,t.data(),2*sizeof(char));
    memcpy((char*)&myTIFF.tMyIFH.nVersion,t.data()+2,2*sizeof(char));
    memcpy((char*)&myTIFF.tMyIFH.nOffset2FirstIFD,t.data()+4,4*sizeof(char));
    memcpy((char*)&myTIFF.tMyIFD.nIDNum,t.data()+myTIFF.tMyIFH.nOffset2FirstIFD,2*sizeof(char));
    myTIFF.tMyIFD.vMyDE.resize(myTIFF.tMyIFD.nIDNum);
    for (int i=0;i<myTIFF.tMyIFD.nIDNum;i++)
    {
        memcpy((char*)&myTIFF.tMyIFD.vMyDE[i].nTagID,t.data()+myTIFF.tMyIFH.nOffset2FirstIFD+2+12*i,2*sizeof(char));
        memcpy((char*)&myTIFF.tMyIFD.vMyDE[i].nType,t.data()+myTIFF.tMyIFH.nOffset2FirstIFD+2+12*i+2,2*sizeof(char));
        memcpy((char*)&myTIFF.tMyIFD.vMyDE[i].nLength,t.data()+myTIFF.tMyIFH.nOffset2FirstIFD+2+12*i+4,4*sizeof(char));
        memcpy((char*)&myTIFF.tMyIFD.vMyDE[i].nValueOffset,t.data()+myTIFF.tMyIFH.nOffset2FirstIFD+2+12*i+8,4*sizeof(char));
        if(myTIFF.tMyIFD.vMyDE[i].nTagID == 0x0100)//表示图像宽度
        {
            myTIFF.tImgInfo.nWidth = myTIFF.tMyIFD.vMyDE[i].nValueOffset;
        }
        if(myTIFF.tMyIFD.vMyDE[i].nTagID == 0x0101)//表示图像高
        {
            myTIFF.tImgInfo.nHeight = myTIFF.tMyIFD.vMyDE[i].nValueOffset;
        }
        if(myTIFF.tMyIFD.vMyDE[i].nTagID == 0x0102)//表示图像每个像素深度,即占多少位宽
        {
            myTIFF.tImgInfo.nDepth = myTIFF.tMyIFD.vMyDE[i].nValueOffset;
        }
        if(myTIFF.tMyIFD.vMyDE[i].nTagID == 0x0103)//表示图像数据是否压缩
        {
            if(myTIFF.tMyIFD.vMyDE[i].nValueOffset == 5)
            {
                myTIFF.tImgInfo.bCompressed = true;
            }
            else
            {
                myTIFF.tImgInfo.bCompressed = false;
            }
        }
        if(myTIFF.tMyIFD.vMyDE[i].nTagID == 0x0111)//图像数据起始字节相对于文件开始处的偏移量
        {
            myTIFF.tImgInfo.nDataOffset = myTIFF.tMyIFD.vMyDE[i].nValueOffset;
        }
        if(myTIFF.tMyIFD.vMyDE[i].nTagID == 0x0117)//图像数据字节总数
        {
            myTIFF.tImgInfo.nDataSize = myTIFF.tMyIFD.vMyDE[i].nValueOffset;
        }
    }
    if(myTIFF.tImgInfo.bCompressed)
    {
        return false;
    }
    if(myTIFF.tImgInfo.nDepth == 16)
    {
        //TODO:
        myTIFF.vShortData.resize(myTIFF.tImgInfo.nWidth*myTIFF.tImgInfo.nHeight);
        if(myTIFF.vShortData.size()<1)
        {
            return false;
        }
        memcpy((char*)&myTIFF.vShortData[0],t.data()+myTIFF.tImgInfo.nDataOffset,myTIFF.tImgInfo.nDataSize*sizeof(char));
    }
    else if(myTIFF.tImgInfo.nDepth == 12)
    {
        //TODO:
        myTIFF.vShortData.resize(myTIFF.tImgInfo.nWidth*myTIFF.tImgInfo.nHeight);
        if(myTIFF.vShortData.size()<1)
        {
            return false;
        }
        memcpy((char*)&myTIFF.vShortData[0],t.data()+myTIFF.tImgInfo.nDataOffset,myTIFF.tImgInfo.nDataSize*sizeof(char));
    }
    else if(myTIFF.tImgInfo.nDepth == 8)
    {
        //TODO:
        myTIFF.vUcharData.resize(myTIFF.tImgInfo.nWidth*myTIFF.tImgInfo.nHeight);
        if(myTIFF.vUcharData.size()<1)
        {
            return false;
        }
        memcpy((char*)&myTIFF.vUcharData[0],t.data()+myTIFF.tImgInfo.nDataOffset,myTIFF.tImgInfo.nDataSize*sizeof(char));
    }
    else
    {
        return false;
    }
    return true;
}

用法:
首先包含该类头文件
#include “”
然后在需要用的地方添加如下代码:
MyTifLib m_MyTifLib;//定义一个类对象
MY_TIFF myTIFF;//定义一个tiff数据结构体
m_MyTifLib.ParseTIFF(“需要解析的tiff文件路径的QString类型的字符串”,myTIFF);//解析tiff文件
这时候,你要的tiff文件中的图像数据就在myTIFF.vShortData或者myTIFF.vUcharData里面了。
注:如果需要解析的图像是8位深的,则数据存放在myTIFF.vUcharData里面
如果需要解析的图像是16位深的,则数据存放在myTIFF.vShortData里面

源码地址:https://download.csdn.net/download/weixin_43935474/11188206

  • 0
    点赞
  • 8
    收藏
  • 打赏
    打赏
  • 0
    评论
#ifndef JPEGDECODE_H #define JPEGDECODE_H #include "global.h" #include "globalextern.h" typedef unsigned char BYTE; struct ImageComponentData { double value[3]; }; class MBitReader { public: BYTE* Data; int m_currentData; int m_currentDataIndex; int m_currentBitPosition; MBitReader(BYTE* data,int currentDataIndex) { Data=data; m_currentBitPosition=8; m_currentDataIndex=currentDataIndex; m_currentData=Data[m_currentDataIndex]; } public: int ReadNextBit() { if (m_currentBitPosition-1> m_currentBitPosition) & 0x01; } }; class MJpegDecode { public: struct _JFIFAPPOInfo { BYTE APP0[2]; /* 02h Application Use Marker */ BYTE Length[2]; /* 04h Length of APP0 Field */ BYTE Identifier[5]; /* 06h "JFIF" (zero terminated) Id String */ BYTE Version[2]; /* 0Bh JFIF Format Revision */ BYTE Units; /* 0Dh Units used for Resolution */ BYTE Xdensity[2]; /* 0Eh Horizontal Resolution */ BYTE Ydensity[2]; /* 10h Vertical Resolution */ BYTE XThumbnail; /* 12h Thumbnail Horizontal Pixel Count */ BYTE YThumbnail; /* 13h Thumbnail Vertical Pixel Count */ } JFIFAPPOINFO; struct _JFIFDQTInfo { BYTE DQT[2]; // 14h 量化表段标记 BYTE Length[2]; // 16h 量化表段长度 BYTE Identifier; // 18h 量化表ID BYTE QTData[64]; // 19h 量化表数据 } JFIFDQTINFO[2]; struct _JFIFSOFOInfo { BYTE SOFO[2]; // 9Eh 帧开始段标记 BYTE Length[2]; // A0h 帧开始段长度 BYTE BitCount; // A2h 样本精度bit位数 BYTE Height[2]; // A5h 像像素宽度 BYTE Width[2]; // A3h 像像素高度 BYTE ComponentsCount; // A7h 像组件计数 BYTE YIdentifier; // A8h 亮度YID号 BYTE YHVSamplingCoefficient; // A9h 亮度Y垂直和水平采样系数 BYTE YUsedDQTIdentifier; // AAh 亮度Y使量化表ID号 BYTE CbIdentifier; // ABh 色度CbID号 BYTE CbHVSamplingCoefficient; // ACh 色度Cb垂直和水平采样系数 BYTE CbUsedDQTIdentifier; // ADh 色度Cb使量化表ID号 BYTE CrIdentifier; // AEh 色度CrID号 BYTE CrHVSamplingCoefficient; // AFh 色度Cr垂直和水平采样系数 BYTE CrUsedDQTIdentifier; // B0h 色度Cr使量化表ID号 } JFIFSOFOINFO; struct _JFIFDRIInfo { BYTE DRI[2]; BYTE Length[2]; BYTE NMCUReset[2]; //每n个MCU块就有一个 RSTn 标记. } JFIFDRIINFO; struct _JFIFDHTInfo { BYTE DHT[2]; // B1h 哈夫曼表定义段标记 BYTE Length[2]; // B3h 哈夫曼表段长度 BYTE HTIdentifier; // B5h 哈夫曼表号 BYTE NBitsSymbolsCount[16]; // B6h (符号二进制位长度为n)符号个数 BYTE SymbolsTable[256]; // C6h 按递增次序代码长度排列符号表 } JFIFDHTINFO[2][2]; struct _JFIFSOSInfo { BYTE SOS[2]; // 261h 扫描开始段标记 BYTE Length[2]; // 263h 扫描开始段长度 BYTE ComponentsCount; // 265h 扫描行内组件数量 BYTE YIdentifier; // 266h 亮度YID号 BYTE YHTTableID; // 267h 亮度Y使哈夫曼表ID号 BYTE CbIdentifier; // 268h 色度CbID号 BYTE CbHTTableID; // 269h 色度Cb使哈夫曼表ID号 BYTE CrIdentifier; // 26Ah 色度CrID号 BYTE CrHTTableID; // 26Bh 色度Cr使哈夫曼表ID号 BYTE Reserved[3]; // 26Ch 3个未知保留字节 } JFIFSOSINFO; private: struct HuffmanTable { int CodeOfFirstNLengthSymbol[17]; //长度为N第一个码字整数值 int NLengthToSymbolsTableIndex[16]; //查表得到第一个长度为N符号位于符号表索引 } HUFFMANTABLE[2][2]; public: int ReadJFIFInfo(const BYTE* const jfifData,int jfifDataSize); void DecodeData(int mcuStartIndex,BYTE* jfifData,int jfifDataSize,ImageComponentData*& targetBitmapData); void SetHuffmanTable(); void DecodeOneDUDC(MBitReader* myBitReader,double* DU,double& lastDC,int index1,int index2); void DecodeOneDUAC(MBitReader* myBitReader,double* DU,int index1,int index2); void DecodeOneMCU(MBitReader* myBitReader,int mcuXn,int mcuYn,int mcuWidth,int mcuHeight,double *DU,ImageComponentData* targetImage); void InverseQuantization(double* du,BYTE* quantizationTable); void InverseZigzag(double* sourceDU,double* targetDU); void IDCT(double* sourceDU,double* targetDU); void YCbCrToRGB(ImageComponentData* sourceImage,ImageComponentData* targetImage); public: int imageHeight; int imageWidth; int alignedImageWidth; int alignedImageHeight; HuffmanTable* HT; double DC[3]; int HSamplingCoefficient[3]; int VSamplingCoefficient[3]; int DQTID[3]; int nMCUReset; }; #endif // JPEGDECODE_H
1.该程序QT开发,实现图片导入、显示、缩放、拖动及处理(冷暖色、灰度、亮度、饱和、模糊、锐化)。 经实测,我写这个软件在导入10000*7096像素超大图片时候,缩放速度比2345看软件还快,2345缩放超大会卡顿,但本软件不会^_^ 关于程序中缩放拖动部分说面参见我博客https://blog.csdn.net/weixin_43935474/article/details/89327314; 2.载入图片后,鼠标移动时候可以显示鼠所在点坐标以及灰度; 3.缩放时候,图片右上角可以显示当前图片缩放比例; 4.户可导入16位深tiff灰度图文件(一般来说是由相机拍摄灰度图数据),导入16位深tiff时候,户需要先点击界面左上角checkbox,然后再导入tiff图片,否则图片解析不出来。 注:Qt自带QImage只能导入8位深tiff灰度图,如果qtQImage导入16位深灰度图像数据会被强制转换成argb格式像,数据就被更改了,所以我自己编写一个解析tiff文件功能,我翻阅了很多博客,其中如下链接给我帮助最大: https://blog.csdn.net/chenlu5201314/article/details/56276903 上述博客作为详细解析tiff文件结构说明文档,写非常详细,我也是根据上面内容,自己编写了一个解析tiff文件(当然功能很少,只能解析符合特定条件tiff文件) //************************************************************ //by Bruce Xu //注:解析tiff解析特定tiff文件! //1.解析tiff文件中只存在一幅,如果文件中存在多幅,本不支持解析! //2.像数据为8位或16位深灰度图,如果是其他图片,本不支持解析! //3.图片没有被压缩过! //************************************************************

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

GreenHandBruce

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值