【OpenGL】读取像素代码示例

#pragma comment(lib, "gltools.lib")

#define _CRT_SECURE_NO_DEPRECATE

#include <GLTools.h>	// OpenGL toolkit
#include <GLShaderManager.h>

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

#pragma pack(1)
typedef struct
{
	GLbyte	identsize;              // Size of ID field that follows header (0)
	GLbyte	colorMapType;           // 0 = None, 1 = paletted
	GLbyte	imageType;              // 0 = none, 1 = indexed, 2 = rgb, 3 = grey, +8=rle
	unsigned short	colorMapStart;          // First colour map entry
	unsigned short	colorMapLength;         // Number of colors
	unsigned char 	colorMapBits;   // bits per palette entry
	unsigned short	xstart;                 // image x origin
	unsigned short	ystart;                 // image y origin
	unsigned short	width;                  // width in pixels
	unsigned short	height;                 // height in pixels
	GLbyte	bits;                   // bits per pixel (8 16, 24, 32)
	GLbyte	descriptor;             // image descriptor
} TGAHEADER;
#pragma pack()

GLShaderManager shaderManager;

void SetupRC()
{
	glClearColor(0, 0, 1, 1);

	shaderManager.InitializeStockShaders();
}

void ChangeSize(int w, int h)
{
	glViewport(0, 0, w, h);
}

void RenderScene(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

	glutSwapBuffers();
}

//程序清单5.1 用gltWriteTGA函数来将屏幕图像保存为一个Targa文件
GLint gltWriteTGA(const char *szFileName)
{
	FILE *pFile; //文件指针
	TGAHEADER tgaHeader; //TGA文件头(TGAHEADER结构体是在上方定义的,原本是没有的百度找了个)

	unsigned long lImageSize;// 图像的大小 字节表示
	GLbyte *pBits = NULL; //指向位的指针
	GLint iViewport[4]; //以像素表示的视口
	GLint lastBuffer;  //存储当前的读取缓冲区设置(书籍是GLenum但由于类型不符改为GLint)

	//获取视口大小
	glGetIntegerv(GL_VIEWPORT, iViewport);

	//图像应该多大(targa文件将被紧密包装)
	lImageSize = iViewport[2] * 3 * iViewport[3];

	//分配块
	pBits = (GLbyte *)malloc(lImageSize);
	if (pBits == NULL)
		return 0;

	//从颜色缓冲区读取位
	glPixelStorei(GL_PACK_ALIGNMENT, 1);
	glPixelStorei(GL_PACK_ROW_LENGTH, 0);
	glPixelStorei(GL_PACK_SKIP_ROWS, 0);
	glPixelStorei(GL_PACK_SKIP_PIXELS, 0);

	//获取当前读取缓冲区设置并进行保存
	glGetIntegerv(GL_READ_BUFFER, &lastBuffer);
	//切换到前台缓冲区并进行读取操作
	glReadBuffer(GL_FRONT);
	glReadPixels(0, 0, iViewport[2], iViewport[3], GL_BGR, GL_UNSIGNED_BYTE, pBits);
	//恢复读取缓冲区状态
	glReadBuffer(lastBuffer);

	//初始化Targa头
	tgaHeader.identsize = 0;
	tgaHeader.colorMapType = 0;
	tgaHeader.imageType = 2;
	tgaHeader.colorMapStart = 0;
	tgaHeader.colorMapLength = 0;
	tgaHeader.colorMapBits = 0;
	tgaHeader.xstart = 0;
	tgaHeader.ystart = 0;
	tgaHeader.width = iViewport[2];
	tgaHeader.height = iViewport[3];
	tgaHeader.bits = 24;
	tgaHeader.descriptor = 0;

	//为大小字节存储顺序问题而进行字节交换
#ifdef __APPLE__
	LITTLE_ENDIAN_WORD(&tgaHeader.colorMapStart);
	LITTLE_ENDIAN_WORD(&tgaHeader.colorMapLength);
	LITTLE_ENDIAN_WORD(&tgaHeader.xstart);
	LITTLE_ENDIAN_WORD(&tgaHeader.ystart);
	LITTLE_ENDIAN_WORD(&tgaHeader.width);
	LITTLE_ENDIAN_WORD(&tgaHeader.height);
#endif

	//尝试打开文件
	pFile = fopen(szFileName, "wb");
	if (pFile == NULL)
	{
		free(pBits); //释放缓冲区并返回错误
		return 0;
	}

	//写入头文件
	fwrite(&tgaHeader, sizeof(TGAHEADER), 1, pFile);

	//写入图像数据
	fwrite(pBits, lImageSize, 1, pFile);

	//释放临时缓冲区并关闭文件
	free(pBits);
	fclose(pFile);
	//成功!
	return 1;

}

GLbyte *gltReadTGABits(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat)
{
	FILE *pFile;
	TGAHEADER tgaHeader;
	unsigned long lImageSize;
	short sDepth;
	GLbyte *pBits = NULL;

	*iWidth = 0;
	*iHeight = 0;
	*eFormat = GL_RGB;
	*iComponents = GL_RGB;

	pFile = fopen(szFileName, "rb");
	if (pFile == NULL)
	{
		return NULL;
	}
	//读取文件头tgaheader
	fread(&tgaHeader, 18, 1, pFile);

#ifdef __APPLE__
	LITTLE_ENDIAN_WORD(&tgaHeader.colorMapStart);
	LITTLE_ENDIAN_WORD(&tgaHeader.colorMapLength);
	LITTLE_ENDIAN_WORD(&tgaHeader.xstart);
	LITTLE_ENDIAN_WORD(&tgaHeader.ystart);
	LITTLE_ENDIAN_WORD(&tgaHeader.width);
	LITTLE_ENDIAN_WORD(&tgaHeader.height);
#endif
	*iWidth = tgaHeader.width;
	*iHeight = tgaHeader.height;
	//图像每像素多少字节
	sDepth = tgaHeader.bits / 8;
	//只处理像素占8、24、32位的
	if (tgaHeader.bits != 8 && tgaHeader.bits != 24 && tgaHeader.bits != 32)
	{
		return NULL;
	}
	//计算图像缓冲区大小
	lImageSize = tgaHeader.width * tgaHeader.height * sDepth;

	//进行内存定义并进行成功检验
	pBits = (GLbyte*)malloc(lImageSize * sizeof(GLbyte));
	if (pBits == NULL)
		return NULL;

	//读入位 检查读取错误。这项操作应该发现RLE或者其他我们不想识别的奇怪格式
	if (fread(pBits, lImageSize, 1, pFile) != 1)
	{
		free(pBits);
		return NULL;
	}
	//设置成希望的OpenGL格式
	switch (sDepth)
	{
#ifdef OPENGL_ES
	case 3://最可能情况
		*eFormat = GL_BGR;
		*iComponents = GL_RGB;
		break;
#endif
#ifdef WIN32
	case 3:
		*eFormat = GL_BGR;
		*iComponents = GL_RGB;
		break;
#endif
#ifdef linux
	case 3:
		*eFormat = GL_BGR;
		*iComponents = GL_RGB;
		break;
#endif
	case 4:
		*eFormat = GL_BGRA;
		*iComponents = GL_RGBA;
		break;
	case 1:
		*eFormat = GL_LUMINANCE;
		*iComponents = GL_LUMINANCE;
		break;
	default: //RGB  
		//如果是在iPhone上,TGA为BGR,并且iPhone不支持没有Alpha的BGR, 但是它支持RGB,所以只要将红色和蓝色调整一下就能满足需求
		//但为了加快iPhone的载入速度,请保存带有Alpha的TGA。	
#ifdef OPENGL_ES 
		//不带Alpha的tga图 原本为BGR ,这里互换B和R,变成RGB,让iPhone能支持没有Alpha的tga图片,但最好给tga图加上alpha值让iPhone加快加载速度
		for (int i = 0; i < lImageSize; i += 3)
		{
			GLbyte temp = pBits[i];
			pBits[i] = pBits[i + 2];
			pBits[i + 2] = temp;
		}
#endif
		break;
	}
	//文件操作完成
	fclose(pFile);
	//返回指向图像数据的指针
	return pBits;
}

void KeyboardFunc(unsigned char key, int x, int y)
{
	if (key == 32)
	{
		gltWriteTGA("hahaha");
	}
}

int main(int argc, char* argv[])
{
	gltSetWorkingDirectory(argv[0]);

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
	glutInitWindowSize(800, 600);
	glutCreateWindow("Test Read Write Pixel");

	GLenum err = glewInit();
	if (GLEW_OK != err) {
		fprintf(stderr, "Error:%s\n", glewGetErrorString(err));
		return 1;
	}

	glutReshapeFunc(ChangeSize);
	glutDisplayFunc(RenderScene);
	glutKeyboardFunc(KeyboardFunc);

	SetupRC();

	glutMainLoop();

	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值