使用 Opengl 和 c++ 读取 PPM 文件并显示。颜色不正确

Read PPM file and display with Opengl and c++. The colors are incorrect

我正在开发一个读取 PPM 文件(P6 格式)并使用 Opengl 和 C++ 显示它的程序。

PPM 图像可以用我的代码显示,但图像的颜色不正确。这个人的脸应该是棕色的,背景应该是蓝色的。

我用 ifstream 读取文件并将数据放入 char 数组 dataByte[] 中。然后我使用 glDrawPixels() 来显示图像。它适用于 PGM 文件。

这是我的代码。我需要对 image.The 操作进行一些操作,但只有当我显示 PPM 文件时,图像的颜色才不像它在 photoshop 中显示的那样。

背景应该是蓝色的,但它变成了红色等等...我现在无法上传图片所以这里是图片的屏幕截图link

the image should be display but it display in this way

我认为问题出在我读取数据的函数上。

 #include "stdafx.h"
    #include <stdlib.h>
    #include <GL/glut.h>
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <stdio.h>

    using namespace std;
    GLint width;
    GLint height;
    GLint wholeLength;
    GLint  grayLevel;
    //GLubyte *dataByte;
    char* dataByte;
    GLint type;





//ignore the comment in PPM    
void ignoreComment(ifstream &f){
            char buf[1024];
            char t;
            t=f.peek();
            while (t=='\n' || t=='\r'){
                f.get();
                t=f.peek();
            }
            if(t=='#'){
                f.getline(buf,1023);
            }

        }

这是我读取图像并将数据放入dataByte[]中的函数。我认为问题是因为我从 PPM 文件中获取数据的方式。但是不知道怎么解决

    void readImage(string fname){


       ifstream f;
       f.open(fname.c_str(), ifstream::in | ifstream::binary);
       cout<<fname.c_str()<<endl;
       if(!f.is_open() ){
         cout<<"Cannot open the file"<<endl;
         return;
       }
       else
           cout<<"opened"<<endl;

        //get type
       ignoreComment(f);
       string temp;
       f >> temp;
       if( (!(temp[0]=='P' )  && !(temp[0]=='p' ) )|| 
           ( !(temp[1]=='6' )  && !(temp[1]=='5' ))
          ){
        cout<<temp<<endl;
        cout<<"cannot read this format"<<endl;
        f.close();
        return;
       }
       else{
        cout<<"file opened"<<endl;
        cout<<temp<<endl;
       }


     if(temp[1]=='5'){
        type=5;
        cout<<"type:"<<type<<endl;
       }
      if(temp[1]=='6'){
        type=6;
        cout<<"type:"<<type<<endl;
       }


        //get width,height
       ignoreComment(f);
       f >> width;
       ignoreComment(f);
       f >> height;
       ignoreComment(f);
       f >> grayLevel;

        if(width < 1 || height < 1 || grayLevel < 0 || grayLevel >255){
            cout<<"Cannot get the size or gray level"<<endl;
            f.close();
            return;
        }

        //allocate data size
        if( type==5){
            wholeLength=width*height;
            cout<<"width="<<width<<" height:"<<height<<endl;

        }
        if(type==6){
            wholeLength=3*width*height;
            cout<<"width="<<width<<" height:"<<height<<endl;
        }


        if(type==5 || type ==6){
            //dataByte=new GLubyte[wholeLength];
            dataByte=new unsigned char[wholeLength];
            //f.read((char*)&dataByte[0], wholeLength);
            //GLubyte j;
            int w;
            if(type==5)
                w=width;
            if(type==6)
                w=3*width;
            int count=0;int counth=0;
            for(int i=height;i>0;i--){
                for(int k=0;k<w;k++){
                    //j=(GLubyte)f.get();
                    //dataByte[(i-1)*w+k]=j;
                    f.read((char*)&dataByte[(i-1)*w+k],sizeof(unsigned char));

                    count++;
                }
                cout<<"count:"<<count<<endl;
                count=0;
                counth++;

            }
            cout<<"counth:"<<counth<<endl;
        }
        f.close();
    }





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

        //string n;
        //cout<<"Please enter the name of the image"<<endl;
        //cin>>n;
        readImage("small.ppm");
        glutInit(&argc,argv);
        glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB); 
        ori();
        getChoice();

        glutMainLoop();



        return 0;
    }

这是我的显示功能。他们可以显示PGM文件和PPM文件。

void drawAsType(char * d){

    if(type==5){
        glDrawPixels(width,height,GL_LUMINANCE,GL_UNSIGNED_BYTE,d);
        glFlush();
        glutSwapBuffers();
    }
    if(type==6 ){
        glDrawPixels(width,height,GL_RGB,GL_UNSIGNED_BYTE,d);
        glFlush();
        glutSwapBuffers();
    }   
}

void changeSize(int w,int h){
    glViewport(0,0,w,h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluOrtho2D(0.0,(GLfloat)w,0.0,(GLfloat)h);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}


void display(void){
    glClear(GL_COLOR_BUFFER_BIT);

    glRasterPos2i(0,0);


    glColor3f(1.0f,1.0f,1.0f);

    drawAsType(dataByte);

}

void ori(){

    glutInitWindowSize(width,height);
    glutCreateWindow("Origin");
    glutReshapeFunc(changeSize);
    glutDisplayFunc(&display);


}

谁能帮我解决这个问题?

感谢 haraldK 的。

我发现原因是因为在 ignoreComent() 函数中我使用 peek() 来检查下一个字符是 '\n' 还是 '\t' 或 '#'。

void ignoreComment(ifstream &f){
    char buf[1024];
    char t;
    while ( t=f.peek(),t=='\n'|| t=='\r'){
        f.get();
    }
    if(t=='#'){
        f.getline(buf,1023);
    }

}

peek() 函数 returns 输入序列中的下一个字符,不提取它:该字符作为下一个要从流中提取的字符 .--表格 cplusplus.com

所以在最后一次调用peek() 之后检查garyLevel 的行。

ignoreComment(f);

由于garyLevel的第一个字符是'2',因为'2'不应该被忽略,所以程序执行下一行f >> grayLevel

然后执行读取图像数据部分。 But 流中的第一个字符是来自 peek() 的“2”。 所以我的数组 dataByte[] 的第一个字符将是 2 而不是真正的第一个字符图像块。

解决方法是替换'2'。所以我应该使用 f.get() 在我开始读取 RGB 数据之前再次。

所以只需在两个for循环之前添加f.get()

if(type==5 || type ==6){

        dataByte=new  char[wholeLength];


        f.get();    /*ADD THIS GUY!*/

        int w;
        if(type==5)
            w=width;
        if(type==6)
            w=3*width;
        int count=0;int counth=0;
        char t;

        for(int i=height;i>0;i--){
            for(int k=0;k<w;k++){

             //read image RGB data
            }
         }