Saturday, May 14, 2011

6、Opengl对像素的操作

读取,写入和复制像素数据:
glReadPixels():从帧缓存区读取一个矩形像素数组,并把数据保存在内存中。
glDrawPixels():把内存中所保存的一个矩形像素数组写入到帧缓冲区中由glRasterPos*()所指定的当前位置。
glCopyPixels():把一个矩形像素数组从帧缓冲区的一个部分复制到另一部分。这个函数相当于先Read再Draw,但数据并不会写入内存中(可能)。(Opengl第四版,Page193)
读取(屏幕截图):
假设我们先建立一个1*1大小的24位色BMP,文件名为dummy.bmp,又假设新的BMP文件名称为grab.bmp。则可以编写如下代码:
#include <stdio.h>
#include <stdlib.h>
//截取函数grab,抓取窗口中宽度WindowWidth和WindowHeigh的像素
#define BMP_HEADER_LENGHT 54
void grad( void )
{
FILE * PdUMMYfILE;
FILE * pWritingFile;
GLubyte* pPixelData;
GLubyte BMP_HEADER[BMP_Header_Lenght];
GLint i, j;
GLint PixelDataLength;
//3-》24位色BMP,这个值可以通过位图信息头来获取
//里面有个参数biBitCount指定了颜色要用到的位数
//计算像素数据的实际长度
i = WidhowWidth*3; //得到每一行的像素数据长度
while( i%4!=0) //补充数据,直到是4的倍数
++i; 
PixelDataLenght=i*WindowHeight; //实际的数据量
//分配内存和打开文件
pPixelData = (GLubyte*)malloc(PixelDataLength);
if( pPixelData==0 ) //分配失败
exit(0);
//读取像素
glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
glReadPixels( 0, 0, WindowWidth, WindowHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, pPixelData);
//把dummy.bmp的文件头复制为新文件的文件头
fread( BMP_HEADER, sizeof( BMP_HEADER), 1, pDummyFile);
fwrite( BMP_HEADER, sizeof( BMP_HEADER), 1, pWritingFile );
fseek( pWritingFile, 0x0012, SEEK_SET );
i = WindowWidth;
j = WindowHeight;
fwrite( &i, sizeof(i), pWritingFile );
fwrite( &j, sizeof(j), pWritingFile );
//写入像素数据
fseek( pWritingFile, 0, SEEK_END );
fwrite( pPixelData, PixelDataLength, 1, pWritingFile );
//释放内存和关闭文件
fclose( pDummyFile );
fclose( pWritingFile );
free( pPixelData );}
绘制:(完整代码)。
#include <gl/glut.h>
#include <stdio.h>
#include <stdlib.h>
#define FileName "Bliss.bmp"
static GLint ImageWidth;
static GLint ImageHeigth;
static GLint PixelLength;
static GLubyte* PixelData;
void display( void )
{ glClear( GL_COLOR_BUFFER_BIT );
//绘制像素
//宽度,高度,像素数据内容,像素数据在内存中的格式,数据位置
glDrawPixels( ImageWidth,ImageHeigth, GL_BGR_EXT, GL_UNSIGNED_BYTE, PixelData);
//完成绘制
glutSwapBuffers();}
int main( int argc, char* argv[] )
{ // 打开文件
     FILE* pFile = fopen("Bliss.bmp", "rb");
     if( pFile == 0 )
         exit(0);
     // 读取图象的大小信息
     fseek(pFile, 0x0012, SEEK_SET);
     fread(&ImageWidth, sizeof(ImageWidth), 1, pFile);
     fread(&ImageHeigth, sizeof(ImageHeigth), 1, pFile);
     // 计算像素数据长度
     PixelLength = ImageWidth * 3;
     while( PixelLength % 4 != 0 )
         ++PixelLength;
     PixelLength *= ImageHeigth;
     // 读取像素数据
     PixelData = (GLubyte*)malloc(PixelLength);
     if( PixelData == 0 )
         exit(0);
     fseek(pFile, 54, SEEK_SET);
     fread(PixelData, PixelLength, 1, pFile);
     // 关闭文件
     fclose(pFile);
// 初始化GLUT并运行
     glutInit(&argc, argv);
     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
     glutInitWindowPosition(100, 100);
     glutInitWindowSize(ImageWidth, ImageHeigth);
     glutCreateWindow(FileName);
     glutDisplayFunc(&display);
     glutMainLoop();
     // 释放内存
     // 实际上,glutMainLoop函数永远不会返回,这里也永远不会到达
     // 这里写释放内存只是出于一种个人习惯
     // 不用担心内存无法释放。在程序结束时操作系统会自动回收所有内存
     free(PixelData);
     return 0;}
复制像素:
#include <gl/glut.h>
#include <stdio.h>
#include <stdlib.h>
#define WindowWidth   400
#define WindowHeight 400
void display(void)
{   // 清除屏幕
     glClear(GL_COLOR_BUFFER_BIT);
     // 绘制
     glBegin(GL_TRIANGLES);
         glColor3f(1.0f, 0.0f, 0.0f);     glVertex2f(0.0f, 0.0f);
         glColor3f(0.0f, 1.0f, 0.0f);     glVertex2f(1.0f, 0.0f);
         glColor3f(0.0f, 0.0f, 1.0f);     glVertex2f(0.5f, 1.0f);
     glEnd();
     glPixelZoom( -0.5f, -0.5f);
     glRasterPos2i( 0, 0 );
//1、2表示复制像素来源的矩形的左下角坐标
//3、4表示复制像素来源的矩形的高度和宽度
//复制像素的颜色,可以是GL_DEPTH或GL_STENCIL,深度/模板缓存
     glCopyPixels(WindowWidth/2, WindowHeight/2,
        WindowWidth/2, WindowHeight/2, GL_COLOR);
     // 完成绘制,并抓取图象保存为BMP文件
     glutSwapBuffers();
}
int main( int argc, char* argv[] )
{ // 初始化GLUT并运行
     glutInit(&argc, argv);
     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
     glutInitWindowPosition(0, 0);
     glutInitWindowSize(WindowWidth, WindowHeight);
     glutCreateWindow("FileName");
     glutDisplayFunc(display);
     glutMainLoop();
     return 0;}

No comments:

Post a Comment