#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; } 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,//(png_voidp)user_error_ptr, NULL,//user_error_fn, NULL);//user_warning_fn); 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); if(color_type!=PNG_COLOR_TYPE_RGB){ fprintf(stderr,"color type of %s must be RGB\n",texturePath); // TODO: at this moment, it is only implemented reading RGB images exit(-1); } // TODO: set the value of depth according to the color type int depth=3; // RGB //png_byte bit_depth=png_get_bit_depth(png_ptr,info_ptr); //int number_of_passes=png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr,info_ptr); // allocate memory to store the texture unsigned char *textureBytes= (unsigned char*)malloc((*outImageWidth)* (*outImageHeight)* depth* sizeof(unsigned char)); // read the contents of the file if(setjmp(png_jmpbuf(png_ptr))){ fprintf(stderr,"error reading %s\n",texturePath); exit(-1); } 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); for(int row=0;row<(*outImageHeight);++row){ for(int j=0;j<(*outImageWidth);++j){ for(int k=0;k