Jump to content

PPM Image Reader Bug


photo

Recommended Posts

Problem

 

PPM/PGM image header data read might fail in case of # character only comment line before data line

 

P5
# Next line will cause invalid image dimensions because width and height line will be skipped 
#
752 480
65535
@@€

 

Cause

 

Image.cpp

int Image::load_ppm(const char *name) {
....
while(file.eof() == 0 && num_colors == -1) {
	file.readToken(buf,sizeof(buf));
	if(buf[0] == '#') {
		file.readLine();     // THIS WILL SKIP WIDTH HEIGHT LINE IN PREVIOUS EXAMPLE
		continue;
	}
	if(width == -1) width = atoi(buf);
	else if(height == -1) height = atoi(buf);
	else if(num_colors == -1) num_colors = atoi(buf);
}

 

Temporary Workaround

 

In case of problems users can remove single # comment line by hand.

Link to comment

Proposal

 

Additional support for PPM/PGM ASCII P2/P3 formats as outputted by GlobalMapper tool.

 

Image.cpp

/******************************************************************************\
*
* PPM format
*
\******************************************************************************/

static void ppm_read_pixel_tokens(unsigned char *data,const File &file,size_t size,int num_colors) {
   char buf[1024];

   for(size_t i = 0; i < size; i++) {
       if( file.readToken(buf,sizeof(buf)) == 0 )
           break;

       int pixel = atoi(buf);

       if( num_colors <= 255 ) { *((unsigned char*)  data) = (unsigned char)  pixel; data += 1; }  
       else                    { *((unsigned short*) data) = (unsigned short) pixel; data += 2; }
   }
}

/*
*/
int Image::load_ppm(const char *name) {
...
   if(strcmp(header,"P2") && strcmp(header,"P3") && strcmp(header,"P5") && strcmp(header,"P6")) {
....	
....
   if(num_colors <= 255) {
       if(!strcmp(header,"P5")) {
   	    create2D(width,height,FORMAT_R8,1,0);
    file.read(data,sizeof(unsigned char),width * height);
} else if(!strcmp(header,"P6")) {
    create2D(width,height,FORMAT_RGB8,1,0);
    file.read(data,sizeof(unsigned char),width * height * 3);
} else if(!strcmp(header,"P2")) {
    create2D(width,height,FORMAT_R8,1,0);
           ppm_read_pixel_tokens(data,file,width * height,num_colors);
} else if(!strcmp(header,"P3")) {
    create2D(width,height,FORMAT_RGB8,1,0);
           ppm_read_pixel_tokens(data,file,width * height * 3,num_colors);
} else {
    assert(0 && "Image::load_ppm(): unknown image format");
       }
   } else if(num_colors <= 65535) {
if(!strcmp(header,"P5")) {
           create2D(width,height,FORMAT_R16,1,0);
    file.readUShortArrayBig((unsigned short*)data,width * height);
} else if(!strcmp(header,"P6")) {
    create2D(width,height,FORMAT_RGB16,1,0);
    file.readUShortArrayBig((unsigned short*)data,width * height * 3);
} else if(!strcmp(header,"P2")) {
    create2D(width,height,FORMAT_R16,1,0);
           ppm_read_pixel_tokens(data,file,width * height,num_colors);
} else if(!strcmp(header,"P3")) {
    create2D(width,height,FORMAT_RGB16,1,0);
           ppm_read_pixel_tokens(data,file,width * height * 3,num_colors);
} else {
    assert(0 && "Image::load_ppm(): unknown image format");
}
....
}

Link to comment

Thanks.

This is a fix for single symbol comments:

char buf[1024];
int width = -1;
int height = -1;
int num_colors = -1;
while(file.eof() == 0 && num_colors == -1) {
int offset = file.tell();
file.readToken(buf,sizeof(buf));
if(buf[0] == '#') {
	file.seekSet(offset);
	file.readLine();
	continue;
}
if(width == -1) width = atoi(buf);
else if(height == -1) height = atoi(buf);
else if(num_colors == -1) num_colors = atoi(buf);
}

Support of P2 and P3 is also added.

Link to comment
×
×
  • Create New...