//--------------------------------------------------
// Panoramic is an interface for the visualization of panoramas capable of
// handling wide fields of view, based on Möbius transformations.
// Copyright (C) 2015 Luis Peñaranda, Luiz Velho and Leonardo Sacht.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see .
//--------------------------------------------------
#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