最近想用C++在windows下实现一个基本的图像查看器功能,目前只想到了使用GDI或OpenGL两种方式。因为实在不想用GDI的API了,就用OpenGL的方式实现了一下基本的显示功能。ios
用GDAL读取图像,这样就能与图像格式无关。OpenGL的glDrawPixels()函数也能实现图像显示,可是如今高版本的OpenGL都采用glTexImage2D()贴纹理的方式了,也不用考虑图像大小是不是2的N次方,或者4字节对齐的问题。具体实现以下:windows
// ImageShow.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "ImageShow.h" #include <iostream> #include <gl\glew.h> // 包含最新的gl.h,glu.h库 #include <gl\freeglut.h> // 包含OpenGL实用库 #include <gdal_priv.h> using namespace std; unsigned int texture; // 纹理对象 unsigned char* imgBuf = nullptr; int imgWidth; int imgHeight; void ReadImage() { GDALAllRegister(); GDALDataset* img = (GDALDataset *)GDALOpen("lena.bmp", GA_ReadOnly); //GDALDataset* img = (GDALDataset *)GDALOpen("dst.tif", GA_ReadOnly); if (img == nullptr) { return; } imgWidth = img->GetRasterXSize(); //图像宽度 imgHeight = img->GetRasterYSize(); //图像高度 int bandNum = img->GetRasterCount(); //波段数 int depth = GDALGetDataTypeSize(img->GetRasterBand(1)->GetRasterDataType()) / 8; //图像深度 //申请buf size_t imgBufNum = (size_t)imgWidth * imgHeight * bandNum * depth; size_t imgBufOffset = (size_t)imgWidth * (imgHeight - 1) * bandNum * depth; imgBuf = new GByte[imgBufNum]; //读取 img->RasterIO(GF_Read, 0, 0, imgWidth, imgHeight, imgBuf + imgBufOffset, imgWidth, imgHeight, GDT_Byte, bandNum, nullptr, bandNum*depth, -imgWidth*bandNum*depth, depth); GDALClose(img); } void InitGL() { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); //平滑着色 glEnable(GL_DEPTH_TEST); //深度测试 glEnable(GL_CULL_FACE); //只渲染某一面 glFrontFace(GL_CCW); //逆时针正面 glEnable(GL_TEXTURE_2D); //启用2D纹理映射 //载入纹理图像: ReadImage(); //生成纹理对象: glGenTextures(1, &texture); } void DrawGLScene() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBindTexture(GL_TEXTURE_2D, texture); //绑定纹理: glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //支持4字节对齐 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); //S方向上贴图 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); //T方向上贴图 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //放大纹理过滤方式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //缩小纹理过滤方式 glTexImage2D(GL_TEXTURE_2D, 0, 3, imgWidth, imgHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, imgBuf); //载入纹理: glMatrixMode(GL_MODELVIEW); // 选择模型观察矩阵 glLoadIdentity(); // 重置模型观察矩阵 glMatrixMode(GL_PROJECTION); // 选择投影矩阵 glLoadIdentity(); glEnable(GL_TEXTURE_2D); //启用2D纹理映射 glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5f, -0.5f, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5f, 0.5f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, 0.5f, 0.0f); glEnd(); glDisable(GL_TEXTURE_2D); glutSwapBuffers(); } GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // 重置OpenGL窗口大小 { glViewport(0, 0, width, height); } int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitContextProfile(GLUT_CORE_PROFILE); glutInitWindowSize(600, 600); glutInitWindowPosition(0, 0); glutCreateWindow("opengl"); InitGL(); glutDisplayFunc(DrawGLScene); glutReshapeFunc(ReSizeGLScene); //glutKeyboardFunc(keyboard); //glutMouseWheelFunc(mouse_wheel); //glutIdleFunc(idle); glutMainLoop(); return 0; }
最后显示的状况以下:函数
另外注意最后须要释放资源:oop
glDeleteTextures(1, &texture); if (imgBuf) { delete[] imgBuf; imgBuf = nullptr; }