TIFF图像文件格式详解 - vstion - 博客园
根据TIF图像的格式来编写了TIF读写程序。不用调包。
#pragma once #include#include #include #include #include #include #include using namespace std; typedef struct { uint16_t endian; uint16_t magic; uint32_t ifdOffset; }IFH; typedef struct { uint16_t tag; // TAG的唯一标识 uint16_t type; // 数据类型 uint32_t size; // 数量 uint32_t valOffset; }DE; typedef struct { uint16_t size; char* beginptr; }Endptr; typedef struct IFDclass { uint16_t n; // 表示此IFD包含了多少个DE,假设数目为n DE* p; uint32_t nextIfdOffset; // 下一个IFD的偏移量,如果没有则置为0 IFDclass() :p(nullptr) {}; ~IFDclass() { free(p); p = nullptr; }; }IFD; typedef enum { whiteIsZeros = 0, BlackIsZeros = 1, RGB = 2, RGBPalette = 3, transparencyMask = 4, KCMYK = 5, YCbCr = 6, CIELAB = 8 }PhotometricInterpretation; typedef struct imgInfo { PhotometricInterpretation _PhotometricInterpretation; uint16_t stripsPerImage; uint16_t* BitsPerSample; uint16_t channel; // 表示图像通道数 uint16_t orientation; uint16_t subFileNum; uint32_t height; // 表示图像高度 uint32_t width; // 表示图像宽度 uint32_t* stripOffsets;// 图像条带数据起始地址存储位置相对于文件开始的位置val的保存位置,共有stripsPerImage个 uint32_t* stripByteCouts; //每压缩带字节数 uint16_t Compression;//1代表没有压缩、7代表JPEG压缩、32773代表packBits压缩 uint32_t rowsPerStrip; uint32_t allBytes;//全部比特数 imgInfo() :_PhotometricInterpretation(BlackIsZeros), stripsPerImage(1), channel(1), allBytes(0), orientation(1), subFileNum(1), height(0), width(0), Compression(1), rowsPerStrip(height), BitsPerSample(nullptr), stripOffsets(nullptr), stripByteCouts(nullptr) {}; ~imgInfo() { free(BitsPerSample); BitsPerSample = nullptr; free(stripOffsets); stripOffsets = nullptr; free(stripByteCouts); stripByteCouts = nullptr; } }imInfo; inline bool mashineEndian(void) { uint16_t a = 1; uint16_t* p = &a; return *((uint8_t*)p) == a; } template struct tiffTypeMap { uint16_t typeValue = 1; }; template<> struct tiffTypeMap { uint16_t typeValue = 1; }; template<> struct tiffTypeMap { uint16_t typeValue = 3; }; template<> struct tiffTypeMap { uint16_t typeValue = 4; }; template<> struct tiffTypeMap { uint16_t typeValue = 5; }; template<> struct tiffTypeMap { uint16_t typeValue = 6; }; template<> struct tiffTypeMap { uint16_t typeValue = 8; }; template<> struct tiffTypeMap { uint16_t typeValue = 9; }; template<> struct tiffTypeMap { uint16_t typeValue = 10; }; template<> struct tiffTypeMap { uint16_t typeValue = 11; }; template<> struct tiffTypeMap { uint16_t typeValue = 12; }; class TiffImg { public: imInfo _imInfo; uint8_t* data; IFH _IFH; IFD _IFD; Endptr endptr; TiffImg(string path); template TiffImg(T, uint32_t height, uint32_t width, uint8_t channel = 1); void getmin(); void save(string savePath = "defaultSave.tif"); ~TiffImg() { free(data); data = nullptr; } template T& operator()(T, uint32_t row, uint32_t col, uint8_t depth = 1) { uint64_t sum = ((row - 1) * _imInfo.width + (col - 1)) * chanBytes(_imInfo.channel, _imInfo.BitsPerSample) + chanBytes(depth - 1, _imInfo.BitsPerSample); return *((T*)(data + sum)); } private: bool EndianTrans; bool read(string path, uint32_t IFDoffset = 0); const uint16_t littleEndian = 0x4949; const uint16_t bigEndian = 0x4d4d; uint8_t chanBytes(uint16_t channel, uint16_t* BitsPerSample); }; uint8_t TiffImg::chanBytes(uint16_t channel, uint16_t* BitsPerSample) { uint8_t res{}; for (int i = 0; i < channel; ++i) { res += (BitsPerSample[i] / 8 + BitsPerSample[i] % 8); } return res; }; template TiffImg::TiffImg(T, uint32_t height, uint32_t width, uint8_t channel) { _imInfo.height = height; _imInfo.width = width; _imInfo.channel = channel; _imInfo.BitsPerSample = sizeof(T) * 8; endptr.beginptr = new char[1024]; endptr.size = 0; _imInfo.stripByteCouts[0] = height * width * channel * sizeof(T); if (_imInfo.stripByteCouts[0] % 2 != 0) { ++_imInfo.stripByteCouts[0]; } uint8_t typeLabel = tiffTypeMap ().typeValue; //_imInfo.ImageStart[0] = sizeof(_IFH); _imInfo.stripOffsets[0] = 22550; data = (uint8_t*)malloc(_imInfo.stripByteCouts[0]); EndianTrans = false; _IFH.endian = mashineEndian ? littleEndian : bigEndian; _IFH.magic = 42; _IFH.ifdOffset = _imInfo.stripByteCouts[0] + sizeof(_IFH); _IFH.ifdOffset = sizeof(_IFH); _IFD.n = 6; _IFD.p = (DE*)malloc(_IFD.n * sizeof(DE)); memset((void*)_IFD.p, 0, _IFD.n * sizeof(DE)); DE* temp = _IFD.p; temp->tag = 0x0100; temp->type; temp->size; temp->valOffset = _imInfo.width; ++temp; temp->tag = 0x0101; temp->type; temp->size; temp->valOffset = _imInfo.height; ++temp; temp->tag = 0x0102; temp->type = typeLabel; temp->size; temp->valOffset; ++temp; temp->tag = 0x0106; temp->type; temp->size; temp->valOffset = _imInfo.channel; ++temp; temp->tag = 0x0111; temp->type; temp->size; temp->valOffset = _imInfo.stripOffsets[0]; ++temp; temp->tag = 0x0117; temp->type; temp->size; temp->valOffset = _imInfo.stripByteCouts[0]; _IFD.nextIfdOffset = 1; } TiffImg::TiffImg(string path) { _IFD.nextIfdOffset = 0; bool hasNext = true; _imInfo.subFileNum = 0; _imInfo.allBytes = 0; while (read(path, _IFD.nextIfdOffset) && hasNext) { ifstream frd(path, ios::in | ios::binary); if (frd) {//文件打开成功 auto chanBytes = [](auto channel, auto BitsPerSample)->uint8_t { uint8_t res{}; for (int i = 0; i < channel; ++i) { res += (BitsPerSample[i] / 8 + BitsPerSample[i] % 8); } return res; }; auto subSum = _imInfo.height * _imInfo.width * chanBytes(_imInfo.channel, _imInfo.BitsPerSample); auto subdat = (uint8_t*)malloc(subSum); memset(subdat, 0, subSum); data = subdat; auto tripBytes = [](auto strips, auto stripByteCouts)->uint32_t { uint32_t res{}; for (int i = 0; i < strips; ++i) { res += stripByteCouts[i]; } return res; }; int tempsum{}; for (auto k = 0; k < _imInfo.stripsPerImage; ++k) { frd.seekg(static_cast (_imInfo.stripOffsets[k]), ios::beg); for (auto i = 0; i < _imInfo.stripByteCouts[k]; ++i) { if (_imInfo.Compression == 1) { frd.read(reinterpret_cast (subdat + tempsum), _imInfo.stripByteCouts[k]); tempsum += _imInfo.stripByteCouts[k]; break; } else if (_imInfo.Compression == 7) { cerr << "JPEG压缩还没写"; } else if (_imInfo.Compression == 32773) { int8_t temp{}; frd.read(reinterpret_cast (&temp), 1); if (temp == -128) { } else if (temp < 0) { uint8_t nextdata{}; frd.read(reinterpret_cast (&nextdata), 1); memset(subdat + tempsum, nextdata, 1 - temp); tempsum += 1 - temp; ++i; } else { frd.read(reinterpret_cast (subdat + tempsum), temp + 1); tempsum += 1 + temp; i += temp + 1; } } } if (EndianTrans) { cerr << "大小端转换还没写"; } } if (!_IFD.nextIfdOffset) { hasNext = false; } frd.close(); _imInfo.allBytes += subSum; ++_imInfo.subFileNum; } } }; uint8_t getsize(uint16_t typeLabel) { switch (typeLabel) { case 1:;//Byte case 2:return 1; break;//文本类型,7位Ascii码加1位二进制0 case 3:; return sizeof(uint16_t); break;//2字节 case 4: return sizeof(uint32_t); break;//4字节 case 5:; return sizeof(uint64_t); break;//有理数,第一无符号Long为分子,第二个为分母部分 case 6:; return sizeof(int8_t); break; case 8:; return sizeof(int16_t); break; case 9:; return sizeof(int32_t); break; case 10:; return sizeof(int64_t); break;///有理数,第一无符号Long为分子,第二个为分母部分 case 11:; return sizeof(float); break; case 12:; return sizeof(double); break; default:; return 1; break; } } bool TiffImg::read(string path, uint32_t IfdOffset) { ifstream frd(path, ios::in | ios::binary); while (frd) { frd.seekg(IfdOffset, ios::beg); frd.read(reinterpret_cast (&(_IFH)), sizeof(_IFH)); bool imEndian{ _IFH.endian == littleEndian }; EndianTrans = (imEndian != mashineEndian()); auto IFD_Start = _IFH.ifdOffset; frd.seekg(static_cast (IFD_Start), ios::beg); frd.read(reinterpret_cast (&(_IFD.n)), sizeof(_IFD.n)); if (EndianTrans) { ; } auto DE_n = _IFD.n; _IFD.p = (DE*)malloc(sizeof(DE) * DE_n); frd.read(reinterpret_cast (_IFD.p), sizeof(DE) * DE_n); endptr.beginptr = new char[1000000]; endptr.size = 0; auto getNdata = [path](auto& DE_ele, auto* res, auto endptr)->void { uint8_t typ = getsize(DE_ele.type); auto DE_val_size = typ * DE_ele.size; if (DE_val_size > 4) { ifstream fr(path, ios::in | ios::binary); fr.seekg(static_cast (DE_ele.valOffset), ios::beg); fr.read(reinterpret_cast (res), DE_val_size); //memcpy(&endptr->beginptr[endptr->size], reinterpret_cast (res), DE_val_size); //endptr->size += DE_val_size; fr.close(); } else { memcpy(reinterpret_cast (res), reinterpret_cast (&DE_ele.valOffset), DE_val_size); } }; for (uint32_t i = 0; i < DE_n; ++i) { DE& temp = _IFD.p[i]; switch (temp.tag) { case 0x00FE: { if (temp.valOffset & 1) { } if (temp.valOffset & 2) { } if (temp.valOffset & 4) { } break; } case 0x00FF: { if (temp.valOffset == 1) { } if (temp.valOffset == 2) { } if (temp.valOffset == 3) { } break; } case 0x0100: getNdata(temp, &_imInfo.width,&endptr); break;// 图像宽度存储位置 case 0x0101: getNdata(temp, &_imInfo.height, &endptr); break;// 图像高度存储位置 case 0x0102: {//每个通道的Bit数 SHORT ,长度为SamplesPerPixel _imInfo.channel = temp.size; _imInfo.BitsPerSample = new uint16_t[_imInfo.channel]; getNdata(temp, _imInfo.BitsPerSample, &endptr); break; } case 0x0103: {// 图像是否压缩 05表示压缩 short、1 getNdata(temp, &_imInfo.Compression, &endptr); break; } case 0x0106: {// 表示图像的种类 _imInfo._PhotometricInterpretation = (PhotometricInterpretation)_IFD.p[i].valOffset; break; } case 0x0111: {// 图像条带数据起始地址存储位置相对于文件开始的位置val的保存位置 _imInfo.stripsPerImage = _IFD.p[i].size; _imInfo.stripOffsets = new uint32_t[_imInfo.stripsPerImage]; getNdata(temp, _imInfo.stripOffsets, &endptr); break; } case 0x0112: { getNdata(temp, &_imInfo.orientation, &endptr); break; } case 0x0114: break; case 0x0115:getNdata(_IFD.p[i], &_imInfo.channel, &endptr); break; case 0x0116: { getNdata(temp, &_imInfo.rowsPerStrip, &endptr); break; } case 0x0117: { _imInfo.stripsPerImage = _IFD.p[i].size; _imInfo.stripByteCouts = new uint32_t[_imInfo.stripsPerImage]; getNdata(temp, _imInfo.stripByteCouts, &endptr); break; } case 284: break; case 0x0128: break; case 0x011A: break; case 0x011B: break; default: break; } } frd.read(reinterpret_cast (&_IFD.nextIfdOffset), sizeof(_IFD.nextIfdOffset)); auto comf = frd.tellg(); frd.seekg(0L,ios::end); auto come = frd.tellg(); frd.seekg(comf); frd.read(endptr.beginptr, come - comf); endptr.size = come - comf; frd.close(); return true; } return false; } void TiffImg::save(string savePath) { ofstream fd{ savePath, ios::out | ios::binary }; if (fd.is_open()) { fd.seekp(0L, ios::beg); if (EndianTrans) { uint16_t Endian = (_IFH.endian == littleEndian ? bigEndian : littleEndian); fd.write((char*)(&(Endian)), sizeof(_IFH.endian)); } else { fd.write((char*)&(_IFH.endian), sizeof(_IFH.endian)); } fd.write((char*)&(_IFH.magic), sizeof(_IFH.magic)); fd.write((char*)&(_IFH.ifdOffset), sizeof(_IFH.ifdOffset)); fd.seekp(_IFH.ifdOffset, ios::beg); fd.write((char*)&(_IFD.n), sizeof(_IFD.n)); fd.write((char*)(_IFD.p), sizeof(DE) * _IFD.n); fd.write((char*)(&(_IFD.nextIfdOffset)), sizeof(_IFD.nextIfdOffset)); fd.write(endptr.beginptr, endptr.size); fd.seekp(_imInfo.stripOffsets[0], ios::beg); fd.write((char*)(data), _imInfo.allBytes); fd.close(); } }



