最近想用C++在windows下實現一個基本的圖像查看器功能,目前只想到了使用GDI或OpenGL兩種方式。由於實在不想用GDI的API了,就用OpenGL的方式實現了一下基本的顯示功能。用GDAL讀取圖像,這樣就能與圖像格式無關。OpenGL的glDrawPixels()函數也能實現圖像顯示,但是... ...
最近想用C++在windows下實現一個基本的圖像查看器功能,目前只想到了使用GDI或OpenGL兩種方式。由於實在不想用GDI的API了,就用OpenGL的方式實現了一下基本的顯示功能。
用GDAL讀取圖像,這樣就能與圖像格式無關。OpenGL的glDrawPixels()函數也能實現圖像顯示,但是現在高版本的OpenGL都採用glTexImage2D()貼紋理的方式了,也不用考慮圖像大小是否是2的N次方,或者4位元組對齊的問題。具體實現如下:
// 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;
}
最後顯示的情況如下:
另外註意最後需要釋放資源:
glDeleteTextures(1, &texture);
if (imgBuf)
{
delete[] imgBuf;
imgBuf = nullptr;
}