最近想用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; }