#include // for fread #include "files.h" #include "image_read.h" // The file type is determined from the file extension. enum FileType FileRead::get_file_type(const char *filename){ // find the last '.' in the file name int dotposition=-1; for(int i=strlen(filename)-1;i>=0;--i){ if(filename[i]=='.'){ dotposition=i; break; } } // if '.' was not found, the whole string is considered extension char *ext=(char*)filename+dotposition+1; // file extension if((ext[0]=='j'||ext[0]=='J')&& (ext[1]=='p'||ext[1]=='P')&& ((strlen(ext)==3&&(ext[2]=='g'||ext[2]=='G'))|| (strlen(ext)==4&&(ext[2]=='e'||ext[2]=='E')&& (ext[3]=='g'||ext[3]=='G')))){ return JPEG; } if((ext[0]=='p'||ext[0]=='P')&& (ext[1]=='n'||ext[1]=='N')&& (ext[2]=='g'||ext[2]=='G')){ return PNG; } if((ext[0]=='p'||ext[0]=='P')&& (ext[1]=='n'||ext[1]=='b'||ext[1]=='g'||ext[1]=='p'|| ext[1]=='N'||ext[1]=='B'||ext[1]=='G'||ext[1]=='P')&& (ext[2]=='m'||ext[2]=='M')){ return PNM; } return UNKNOWN; } unsigned char *FileRead::read_image(const char *new_image,int *width,int *height){ #ifndef _MSC_VER // the progname is only used for reading the PNM format const char * const progname=(char*)(PROGNAME); #endif switch(get_file_type(new_image)){ case JPEG: fprintf(stderr,"input image has JPEG format\n"); return jpgRead(new_image,width,height); break; case PNG: fprintf(stderr,"input image has PNG format\n"); return pngRead(new_image,width,height); break; #ifndef _MSC_VER case PNM: fprintf(stderr,"input image has PNM format\n"); return pnmRead(progname,new_image,width,height); break; #endif default: // UNKNOWN fprintf(stderr,"%s: unknown file format\n",new_image); exit(-1); } return NULL; } const char *FileRead::image_types="All images (*.png *.jpg *.jpeg *.pnm *.pbm *.pgm *.ppm);;PNG images (*.png);;JPG images (*.jpg *.jpeg);;PBM images (*.pnm *.pbm *.pgm *.ppm);;All files (*)"; unsigned char *FileRead::jpgRead(const char *texturePath, int *outImageWidth, int *outImageHeight){ FILE *in_file; FOPEN_RO(in_file,texturePath) struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err=jpeg_std_error(&jerr); JSAMPROW row_pointer[1]; jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo,in_file); jpeg_read_header(&cinfo,0); jpeg_start_decompress(&cinfo); *outImageWidth=cinfo.output_width; *outImageHeight=cinfo.output_height; int depth=cinfo.num_components; int textureSize=(*outImageWidth)*(*outImageHeight)*depth; unsigned char *textureBytes= (unsigned char*)malloc(textureSize*sizeof(unsigned char)); unsigned long scanline=*outImageHeight; row_pointer[0]=(unsigned char*)malloc((*outImageWidth)* depth* sizeof(unsigned char)); while(cinfo.output_scanline<(unsigned)*outImageHeight){ --scanline; jpeg_read_scanlines(&cinfo,row_pointer,1); for(int i=0;i<(*outImageWidth)*depth;++i){ textureBytes[scanline*(*outImageWidth)*depth+i]=row_pointer[0][i]; } } fclose(in_file); jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return textureBytes; } unsigned char *FileRead::pngRead(const char *texturePath, int *outImageWidth, int *outImageHeight){ FILE *in_file; FOPEN_RO(in_file,texturePath) // read the header of the file unsigned char header[8]; if(fread(header,1,8,in_file)!=(unsigned long)ftell(in_file)){ fprintf(stderr,"error reading %s\n",texturePath); exit(-1); } // check the file is valid if(png_sig_cmp(header,0,8)){ fprintf(stderr,"%s is not a valid PNG file!\n",texturePath); exit(-1); } // initialize png_structp png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png_ptr){ fprintf(stderr,"error reading %s\n",texturePath); exit(-1); } png_infop info_ptr=png_create_info_struct(png_ptr); if (!info_ptr){ fprintf(stderr,"error reading %s\n",texturePath); png_destroy_read_struct(&png_ptr,(png_infopp)NULL,(png_infopp)NULL); exit(-1); } if(setjmp(png_jmpbuf(png_ptr))){ fprintf(stderr,"error reading %s\n",texturePath); exit(-1); } png_init_io(png_ptr,in_file); png_set_sig_bytes(png_ptr,8); png_read_info(png_ptr,info_ptr); *outImageWidth=png_get_image_width(png_ptr,info_ptr); *outImageHeight=png_get_image_height(png_ptr,info_ptr); png_byte color_type=png_get_color_type(png_ptr,info_ptr); png_byte bit_depth=png_get_bit_depth(png_ptr,info_ptr); if(bit_depth==16) png_set_strip_16(png_ptr); if(bit_depth<8) png_set_expand_gray_1_2_4_to_8(png_ptr); if(color_type==PNG_COLOR_TYPE_GRAY||color_type==PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if(color_type==PNG_COLOR_TYPE_PALETTE){ png_set_palette_to_rgb(png_ptr); // TODO: Read the transparency values for indexed images; // currently, they are ignored by stripping the alpha information. png_set_strip_alpha(png_ptr); } png_read_update_info(png_ptr,info_ptr); // allocate memory to store the texture unsigned char *textureBytes= (unsigned char*)malloc((*outImageWidth)* (*outImageHeight)* 3* // RGB sizeof(unsigned char)); // read the contents of the file if(setjmp(png_jmpbuf(png_ptr))){ fprintf(stderr,"error reading %s\n",texturePath); exit(-1); } // TODO: we can avoid writing in row_pointers[] and later copying to // the texture. png_bytep *row_pointers= (png_bytep*)malloc(sizeof(png_bytep)*(*outImageHeight)); for(int y=0;y<(*outImageHeight);++y) row_pointers[y]=(png_byte*)malloc(png_get_rowbytes(png_ptr,info_ptr)); png_read_image(png_ptr,row_pointers); switch(color_type){ case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_PALETTE: case PNG_COLOR_TYPE_RGB: // RGB: copy directly RGB bits to the texture. for(int row=0;row<(*outImageHeight);++row) for(int j=0;j<(*outImageWidth);++j) for(int k=0;k<3;++k) textureBytes[row*(*outImageWidth)*3+j*3+k]= row_pointers[(*outImageHeight)-row-1][j*3+k]; break; case PNG_COLOR_TYPE_GRAY_ALPHA: case PNG_COLOR_TYPE_RGB_ALPHA: // RGBA: multiply each one of the three first bytes (channels R, G // and B), by the alpha (the fourth byte). for(int row=0;row<(*outImageHeight);++row) for(int j=0;j<(*outImageWidth);++j) for(int k=0;k<3;++k) textureBytes[row*(*outImageWidth)*3+j*3+k]= (double) row_pointers[(*outImageHeight)-row-1][j*4+k]* row_pointers[(*outImageHeight)-row-1][j*4+3]/ 255; break; default: fprintf(stderr,"%s: unrecognized PNG type\n",texturePath); exit(-1); } png_read_end(png_ptr,NULL); png_destroy_read_struct(&png_ptr,&info_ptr,NULL); for(int row=0;row<(*outImageHeight);++row) free(row_pointers[row]); free(row_pointers); fclose(in_file); return textureBytes; } #ifndef _MSC_VER unsigned char *FileRead::pnmRead(const char * const progname, const char *texturePath, int *outImageWidth, int *outImageHeight){ struct pam inpam; pm_init(progname, 0); FILE *in_file; FOPEN_RO(in_file,texturePath) #ifdef PAM_STRUCT_SIZE pnm_readpaminit(in_file,&inpam,PAM_STRUCT_SIZE(tuple_type)); #else pnm_readpaminit(in_file,&inpam,sizeof(struct pam)); #endif *outImageWidth=inpam.width; *outImageHeight=inpam.height; int textureSize= (*outImageWidth)* (*outImageHeight)* inpam.depth* inpam.bytes_per_sample; unsigned char *textureBytes= (unsigned char*)malloc(textureSize*sizeof(unsigned char)); tuple *tuplerow=pnm_allocpamrow(&inpam); for(int row=0;row<*outImageHeight;row++) { int column; pnm_readpamrow(&inpam,tuplerow); for (column=0;column<*outImageWidth;++column) { unsigned int plane; for(plane=0;plane