/*---------------------------------------------------------------------------- I/O functions: read PGM or ASC images and curve output to PDF or TXT files. Copyright (c) 2016-2017 rafael grompone von gioi , Gregory Randall This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . ----------------------------------------------------------------------------*/ #include #include #include #include #include /*----------------------------------------------------------------------------*/ #ifndef FALSE #define FALSE 0 #endif /* !FALSE */ #ifndef TRUE #define TRUE 1 #endif /* !TRUE */ /*----------------------------------------------------------------------------*/ /* fatal error, print a message to standard error and exit */ static void error(char * msg) { fprintf(stderr,"error: %s\n",msg); exit(EXIT_FAILURE); } /*----------------------------------------------------------------------------*/ /* memory allocation, print an error and exit if fail */ static void * xmalloc(size_t size) { void * p; if( size == 0 ) error("xmalloc input: zero size"); p = malloc(size); if( p == NULL ) error("out of memory"); return p; } /*----------------------------------------------------------------------------*/ /* open file, print an error and exit if fail */ static FILE * xfopen(const char * path, const char * mode) { FILE * f = fopen(path,mode); if( f == NULL ) { fprintf(stderr,"error: unable to open file '%s'\n",path); exit(EXIT_FAILURE); } return f; } /*----------------------------------------------------------------------------*/ /* close file, print an error and exit if fail */ static int xfclose(FILE * f) { if( fclose(f) == EOF ) error("unable to close file"); return 0; } /*----------------------------------------------------------------------------*/ /* skip white characters and comments in a PGM file */ static void skip_whites_and_comments(FILE * f) { int c; do { while(isspace(c=getc(f))); /* skip spaces */ if(c=='#') /* skip comments */ while( c!='\n' && c!='\r' && c!=EOF ) c=getc(f); } while( c == '#' || isspace(c) ); if( c != EOF && ungetc(c,f) == EOF ) error("unable to 'ungetc' while reading PGM file."); } /*----------------------------------------------------------------------------*/ /* read a number in ASCII from a PGM file */ static int get_num(FILE * f) { int num,c; while(isspace(c=getc(f))); if(!isdigit(c)) error("corrupted PGM or PPM file."); num = c - '0'; while( isdigit(c=getc(f)) ) num = 10 * num + c - '0'; if( c != EOF && ungetc(c,f) == EOF ) error("unable to 'ungetc' while reading PGM file."); return num; } /*----------------------------------------------------------------------------*/ /* read a PGM image file */ double * read_pgm_image(char * name, int * X, int * Y) { FILE * f; int i,n,depth,bin=FALSE; double * image; /* open file */ f = xfopen(name,"rb"); /* open to read as a binary file (b option). otherwise, in some systems, it may behave differently */ /* read header */ if( getc(f) != 'P' ) error("not a PGM file!"); if( (n=getc(f)) == '2' ) bin = FALSE; else if( n == '5' ) bin = TRUE; else error("not a PGM file!"); skip_whites_and_comments(f); *X = get_num(f); /* X size */ skip_whites_and_comments(f); *Y = get_num(f); /* Y size */ skip_whites_and_comments(f); depth = get_num(f); /* pixel depth */ if( depth < 0 ) error("pixel depth < 0, unrecognized PGM file"); if( bin && depth > 255 ) error("pixel depth > 255, unrecognized PGM file"); /* white before data */ if(!isspace(getc(f))) error("corrupted PGM file."); /* get memory */ image = (double *) xmalloc( *X * *Y * sizeof(double) ); /* read data */ for(i=0; i<(*X * *Y); i++) image[i] = (double) (bin ? getc(f) : get_num(f)); /* close file */ xfclose(f); /* return image */ return image; } /*----------------------------------------------------------------------------*/ /* read a 2D ASC format file */ double * read_asc_file(char * name, int * X, int * Y) { FILE * f; int i,n,Z,C; double val; double * image; /* open file */ f = xfopen(name,"rb"); /* open to read as a binary file (b option). otherwise, in some systems, it may behave differently */ /* read header */ n = fscanf(f,"%d%*c%d%*c%d%*c%d",X,Y,&Z,&C); if( n!=4 || *X<=0 || *Y<=0 || Z<=0 || C<=0 ) error("invalid ASC file"); /* only gray level images are handled */ if( Z!=1 || C!=1 ) error("only single channel ASC files are handled"); /* get memory */ image = (double *) xmalloc( *X * *Y * Z * C * sizeof(double) ); /* read data */ for(i=0; i<(*X * *Y * Z * C); i++) { n = fscanf(f,"%lf",&val); if( n!=1 ) error("invalid ASC file"); image[i] = val; } /* close file */ xfclose(f); return image; } /*----------------------------------------------------------------------------*/ /* read an image from a file in ASC or PGM formats */ double * read_image(char * name, int * X, int * Y) { int n = (int) strlen(name); char * ext = name+n-4; if( n>=4 && ( strcmp(ext,".asc")==0 || strcmp(ext,".ASC")==0) ) return read_asc_file(name,X,Y); return read_pgm_image(name,X,Y); } /*----------------------------------------------------------------------------*/ /* write curves into a PDF file. the output is PDF version 1.4 as described in "PDF Reference, third edition" by Adobe Systems Incorporated, 2001 */ void write_curves_pdf( double * x, double * y, int * curve_limits, int M, char * filename, int X, int Y, double width ) { FILE * pdf; long start1,start2,start3,start4,start5,startxref,stream_len; int i,j,k; /* check input */ if( filename == NULL ) error("invalid filename in write_curves_pdf"); if( M > 0 && ( x == NULL || y == NULL || curve_limits == NULL ) ) error("invalid curves data in write_curves_pdf"); if( X <= 0 || Y <= 0 ) error("invalid image size in write_curves_pdf"); /* open file */ pdf = xfopen(filename,"wb"); /* open to write as a binary file (b option). otherwise, in some systems, it may behave differently */ /* PDF header */ fprintf(pdf,"%%PDF-1.4\n"); /* The following PDF comment contains characters with ASCII codes greater than 128. This helps to classify the file as containing 8-bit binary data. See "PDF Reference" p.63. */ fprintf(pdf,"%%%c%c%c%c\n",0xe2,0xe3,0xcf,0xd3); /* Catalog, Pages and Page objects */ start1 = ftell(pdf); fprintf(pdf,"1 0 obj\n<>\n"); fprintf(pdf,"endobj\n"); start2 = ftell(pdf); fprintf(pdf,"2 0 obj\n<> /MediaBox [0 0 %d %d]>>\nendobj\n",X,Y); start3 = ftell(pdf); fprintf(pdf,"3 0 obj\n"); fprintf(pdf,"<>\n"); fprintf(pdf,"endobj\n"); /* Contents object - graphic contents */ start4 = ftell(pdf); fprintf(pdf,"4 0 obj\n<>\n"); /* indirect length in obj 5 */ fprintf(pdf,"stream\n"); stream_len = ftell(pdf); fprintf(pdf,"%.4f w\n",width); /* set line width */ for(k=0; k>\n"); fprintf(pdf,"startxref\n"); fprintf(pdf,"%ld\n",startxref); fprintf(pdf,"%%%%EOF\n"); /* close file */ xfclose(pdf); } /*----------------------------------------------------------------------------*/ /* write curves into a TXT file */ void write_curves_txt( double * x, double * y, int * curve_limits, int M, char * filename ) { FILE * txt; int i,k; /* check input */ if( filename == NULL ) error("invalid filename in write_curves_txt"); if( M > 0 && ( x == NULL || y == NULL || curve_limits == NULL ) ) error("invalid curves data in write_curves_txt"); /* open file */ txt = xfopen(filename,"wb"); /* open to write as a binary file (b option). otherwise, in some systems, it may behave differently */ /* write curves */ for(k=0; k 0 && ( x == NULL || y == NULL || curve_limits == NULL ) ) error("invalid curves data in write_curves_svg"); if( X <= 0 || Y <= 0 ) error("invalid image size in write_curves_svg"); /* open file */ svg = xfopen(filename,"wb"); /* open to write as a binary file (b option). otherwise, in some systems, it may behave differently */ /* write SVG header */ fprintf(svg,"\n"); fprintf(svg,"\n"); fprintf(svg,"\n"); /* write curves */ for(k=0; k\n"); /* end of chain */ } /* close SVG file */ fprintf(svg,"\n"); xfclose(svg); } /*----------------------------------------------------------------------------*/