图像处理之tiff图像读写(纯C++不调库)

typedef struct
{
	uint16_t endian;          // 字节顺序标志位,值为II或者MM:II表示小字节在前,又称为little-endian,MM表示大字节在前,又称为big-endian
	uint16_t magic;           // TIFF的标志位,一般都是42
	uint32_t ifdOffset;        // 第一个IFD的偏移量,可以在任意位置,但必须是在一个字的边界,也就是说必须是2的整数倍
}IFH;

typedef struct    
{
	uint16_t tag;                 // TAG的唯一标识
	uint16_t type;               // 数据类型
	uint32_t size;               // 4个字节数量,通过类型和数量可以确定存储此TAG的数据需要占据的字节数
	uint32_t valOffset;         //4个字节,tag标识的属性代表的变量值相对文件开始处的偏移量
}DE;

typedef struct
{
	uint16_t size;       //DE的个数
	char* beginptr;     //开始的指针
}Endptr;   

typedef struct IFDclass
{
	uint16_t n;                        // 表示此IFD包含了多少个DE,假设数目为n
	DE* p;                             //n个DE
	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;               //tif中的图像个数
	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<typename baseType>
struct tiffTypeMap {
	uint16_t typeValue = 1;
};
template<>
struct tiffTypeMap<uint8_t> {
	uint16_t typeValue = 1;
};
template<>
struct tiffTypeMap<uint16_t> {
	uint16_t typeValue = 3;
};
template<>
struct tiffTypeMap<uint32_t> {
	uint16_t typeValue = 4;
};
template<>
struct tiffTypeMap<uint64_t> {
	uint16_t typeValue = 5;
};
template<>
struct tiffTypeMap<int8_t> {
	uint16_t typeValue = 6;
};
template<>
struct tiffTypeMap<int16_t> {
	uint16_t typeValue = 8;
};
template<>
struct tiffTypeMap<int32_t> {
	uint16_t typeValue = 9;
};
template<>
struct tiffTypeMap<int64_t> {
	uint16_t typeValue = 10;
};
template<>
struct tiffTypeMap<float> {
	uint16_t typeValue = 11;
};
template<>
struct tiffTypeMap<double> {
	uint16_t typeValue = 12;
};


class TiffImg 
{
public:
	imInfo _imInfo;
	uint8_t* data;
	IFH _IFH;
	IFD _IFD;
	Endptr endptr;
	TiffImg(string path);
	template<typename T>
	TiffImg(T, uint32_t height, uint32_t width, uint8_t channel = 1);
	void getmin();
	void save(string savePath = "defaultSave.tif");
	~TiffImg() 
	{
		/*save();*/
		free(data);
		data = nullptr;
	}
	template<typename T>
	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;           //Intel整数格式
	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<typename T>

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<T>().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;                                                 //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<long>(_imInfo.stripOffsets[k]), ios::beg);

				for (auto i = 0; i < _imInfo.stripByteCouts[k]; ++i)
				{
					if (_imInfo.Compression == 1) 
					{
						frd.read(reinterpret_cast<char*>(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<char*>(&temp), 1);
						if (temp == -128)
						{
						}
						else if (temp < 0)
						{
							uint8_t nextdata{};
							frd.read(reinterpret_cast<char*>(&nextdata), 1);
							memset(subdat + tempsum, nextdata, 1 - temp);
							tempsum += 1 - temp;
							++i;
						}
						else 
						{
							frd.read(reinterpret_cast<char*>(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;
		}
	}
	cout << "图像读取成功" << endl;
	cout << "图像的高:" << _imInfo.height << endl;
	cout << "图像的宽:" << _imInfo.width << endl;
	cout << "是否压缩:" << _imInfo.Compression << endl;
	cout << "通道数: " << _imInfo.channel << endl;
	cout << "字节长度: " << _imInfo.BitsPerSample << endl;
};


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<char*>(&(_IFH)), sizeof(_IFH));
		bool imEndian{ _IFH.endian == littleEndian };                   //图像存储方式是大端(false)还是小端(true)  
		EndianTrans = (imEndian != mashineEndian());

		auto IFD_Start = _IFH.ifdOffset;
		frd.seekg(static_cast<long>(IFD_Start), ios::beg);
		frd.read(reinterpret_cast<char*>(&(_IFD.n)), sizeof(_IFD.n));
		if (EndianTrans) {
			;
		}
		auto DE_n = _IFD.n;
		_IFD.p = (DE*)malloc(sizeof(DE) * DE_n);
		frd.read(reinterpret_cast<char*>(_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<long>(DE_ele.valOffset), ios::beg);
				fr.read(reinterpret_cast<char*>(res), DE_val_size);
				//memcpy(&endptr->beginptr[endptr->size], reinterpret_cast<char*>(res), DE_val_size);
				//endptr->size += DE_val_size;
				fr.close();
			}
			else {
				memcpy(reinterpret_cast<char*>(res), reinterpret_cast<char*>(&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<char*>(&_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);   //所有图像数据定向输入到data
		fd.close();
	}
	

}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值