# include # include # include # include # include # include # include "ppmb_io.h" /******************************************************************************/ bool ppmb_check_data ( int xsize, int ysize, int maxrgb, unsigned char *rarray, unsigned char *garray, unsigned char *barray ) /******************************************************************************/ /* Purpose: PPMB_CHECK_DATA checks the data for an ASCII portable pixel map file. Example: P3 # feep.ppm 4 4 15 0 0 0 0 0 0 0 0 0 15 0 15 0 0 0 0 15 7 0 0 0 0 0 0 0 0 0 0 0 0 0 15 7 0 0 0 15 0 15 0 0 0 0 0 0 0 0 0 Licensing: This code is distributed under the MIT license. Modified: 16 June 2012 Author: John Burkardt Input: int XSIZE, YSIZE, the number of rows and columns of data. int MAXRGB, the maximum RGB value. unsigned char *RARRAY, *GARRAY, *BARRAY, the arrays of XSIZE by YSIZE data values. Output: bool PPMB_CHECK_DATA, is true, if an error was detected, or false, if the data was legal. */ { int i; unsigned char *index; int j; int k; if ( xsize <= 0 ) { printf ( "\n" ); printf ( "PPMb_CHECK_DATA: 0 >= XSIZE = %d.\n", xsize ); return true; } if ( ysize <= 0 ) { printf ( "\n" ); printf ( "PPMB_CHECK_DATA: 0 >= YSIZE = %d.\n", ysize ); return true; } if ( rarray == NULL || garray == NULL || barray == NULL ) { printf ( "\n" ); printf ( "PPMB_CHECK_DATA: Null pointer to data.\n" ); return true; } for ( k = 0; k < 3; k++ ) { if ( k == 0 ) { index = rarray; } else if ( k == 1 ) { index = garray; } else if ( k == 2 ) { index = barray; } for ( j = 0; j < ysize; j++ ) { for ( i = 0; i < xsize; i++ ) { if ( *index < 0 ) { if ( k == 0 ) { printf ( "\n" ); printf ( "PPMB_CHECK_DATA: R(%d,%d) = %d < 0.\n", i, j, *index ); } else if ( k == 1 ) { printf ( "\n" ); printf ( "PPMB_CHECK_DATA: G(%d,%d) = %d < 0.\n", i, j, *index ); } else if ( k == 2 ) { printf ( "\n" ); printf ( "PPMB_CHECK_DATA: B(%d,%d) = %d < 0.\n", i, j, *index ); } return true; } else if ( *index > maxrgb ) { if ( k == 0 ) { printf ( "\n" ); printf ( "PPMB_CHECK_DATA: R(%d,%d) = %d > %d.\n", i, j, *index, maxrgb ); } else if ( k == 1 ) { printf ( "\n" ); printf ( "PPMB_CHECK_DATA: G(%d,%d) = %d > %d.\n", i, j, *index, maxrgb ); } else if ( k == 2 ) { printf ( "\n" ); printf ( "PPMB_CHECK_DATA: B(%d,%d) = %d > %d.\n", i, j, *index, maxrgb ); } return true; } index = index + 1; } } } return false; } /******************************************************************************/ bool ppmb_example ( int xsize, int ysize, unsigned char *rarray, unsigned char *garray, unsigned char *barray ) /******************************************************************************/ /* Purpose: PPMB_EXAMPLE sets up some PPM data. Licensing: This code is distributed under the MIT license. Modified: 16 June 2012 Author: John Burkardt Input: int XSIZE, YSIZE, the number of rows and columns of data. Values of 200 would be reasonable. Output: unsigned char *RARRAY, *GARRAY, *BARRAY, the arrays of XSIZE by YSIZE RGB values. bool PPMB_EXAMPLE, is true, if an error occurred, false, if no error occurred. */ { float f1; float f2; float f3; int i; unsigned char *indexr; unsigned char *indexg; unsigned char *indexb; int j; float x; float y; indexr = rarray; indexg = garray; indexb = barray; for ( i = 0; i < ysize; i++ ) { y = ( float ) ( ysize + 1 - i ) / ( float ) ( ysize - 1 ); for ( j = 0; j < xsize; j++ ) { x = ( float ) ( j ) / ( float ) ( xsize - 1 ); f1 = 4.0 * ( x - 0.5 ) * ( x - 0.5 ); f2 = sin ( 3.14159265 * x ); f3 = x; if ( y <= f1 ) { *indexr = ( int ) ( 255.0 * f1 ); } else { *indexr = 50; } if ( y <= f2 ) { *indexg = ( int ) ( 255.0 * f2 ); } else { *indexg = 150; } if ( y <= f3 ) { *indexb = ( int ) ( 255.0 * f3 ); } else { *indexb = 250; } indexr = indexr + 1; indexg = indexg + 1; indexb = indexb + 1; } } return false; } /******************************************************************************/ bool ppmb_read ( char *file_name, int *xsize, int *ysize, int *maxrgb, unsigned char **rarray, unsigned char **garray, unsigned char **barray ) /******************************************************************************/ /* Purpose: PPMB_READ reads the header and data from a binary portable pixel map file. Licensing: This code is distributed under the MIT license. Modified: 16 June 2012 Author: John Burkardt Input: char *FILE_NAME, the name of the file containing the binary portable pixel map data. Output: int *XSIZE, *YSIZE, the number of rows and columns of data. int *MAXRGB, the maximum RGB value. unsigned char **RARRAY, **GARRAY, **BARRAY, the arrays of XSIZE by YSIZE data values. bool PPMB_READ, equals true, if the file could not be read, false, if the file was read. */ { FILE *file_pointer; int numbytes; bool result; file_pointer = fopen ( file_name, "rb" ); if ( file_pointer == NULL ) { printf ( "\n" ); printf ( "PPMB_READ: Warning!\n" ); printf ( " Cannot open the input file %s.\n", file_name ); return true; } /* Read the header. */ result = ppmb_read_header ( file_pointer, xsize, ysize, maxrgb ); if ( result ) { printf ( "\n" ); printf ( "PPMB_READ: Warning!\n" ); printf ( " PPMB_READ_HEADER failed.\n" ); return true; } /* Allocate storage for the data. */ numbytes = ( *xsize ) * ( *ysize ) * sizeof ( unsigned char ); *rarray = ( unsigned char * ) malloc ( numbytes ); if ( *rarray == NULL ) { printf ( "\n" ); printf ( "PPMB_READ: Warning!\n" ); printf ( " Unable to allocate memory for data.\n" ); printf ( " Seeking %d bytes.\n", numbytes ); return true; } *garray = ( unsigned char * ) malloc ( numbytes ); if ( *garray == NULL ) { printf ( "\n" ); printf ( "PPMB_READ: Warning!\n" ); printf ( " Unable to allocate memory for data.\n" ); printf ( " Seeking %d bytes.\n", numbytes ); return true; } *barray = ( unsigned char * ) malloc ( numbytes ); if ( *barray == NULL ) { printf ( "\n" ); printf ( "PPMB_READ: Warning!\n" ); printf ( " Unable to allocate memory for data.\n" ); printf ( " Seeking %d bytes.\n", numbytes ); return true; } /* Read the data. */ result = ppmb_read_data ( file_pointer, *xsize, *ysize, *rarray, *garray, *barray ); if ( result ) { printf ( "\n" ); printf ( "PPMB_READ: Warning!\n" ); printf ( " PPMB_READ_DATA failed.\n" ); return true; } /* Close the file. */ fclose ( file_pointer ); return false; } /******************************************************************************/ bool ppmb_read_data ( FILE *file_pointer, int xsize, int ysize, unsigned char *rarray, unsigned char *garray, unsigned char *barray ) /******************************************************************************/ /* Purpose: PPMB_READ_DATA reads the data in a binary portable pixel map file. Discussion: Thanks to Sreepathi Pai for pointing out that fgetc() returns an unsigned char cast to an int, and so the variable C receiving this value should be declared as an int, not a char. Licensing: This code is distributed under the MIT license. Modified: 30 October 2015 Author: John Burkardt Input: FILE *FILE_POINTER, a pointer to the file containing the binary portable pixel map data. int XSIZE, YSIZE, the number of rows and columns of data. unsigned char *RARRAY, *GARRAY, *BARRAY, the arrays of XSIZE by YSIZE data values. Output: bool PPMB_READ_DATA, equals true, if the data could not be read, false, if the data was read. */ { int i; int c; unsigned char *indexb; unsigned char *indexg; unsigned char *indexr; int j; int k; int numval; indexr = rarray; indexg = garray; indexb = barray; numval = 0; for ( j = 0; j < ysize; j++ ) { for ( i = 0; i < xsize; i++ ) { for ( k = 0; k < 3; k++ ) { c = fgetc ( file_pointer ); if ( c == EOF ) { printf ( "\n" ); printf ( "PPMB_READ_DATA - Warning!\n" ); printf ( " Failed reading data byte %d.\n", numval ); return true; } else { if ( k == 0 ) { *indexr = ( unsigned char ) c; indexr = indexr + 1; } else if ( k == 1 ) { *indexg = ( unsigned char ) c; indexg = indexg + 1; } else if ( k == 2 ) { *indexb = ( unsigned char ) c; indexb = indexb + 1; } } numval = numval + 1; } } } return false; } /******************************************************************************/ bool ppmb_read_header ( FILE *file_pointer, int *xsize, int *ysize, int *maxrgb ) /******************************************************************************/ /* Purpose: PPMB_READ_HEADER reads the header of a binary portable pixel map file. Licensing: This code is distributed under the MIT license. Modified: 16 June 2012 Author: John Burkardt Input: FILE *FILE_POINTER, a pointer to the file containing the binary portable pixel map data. Output: int *XSIZE, *YSIZE, the number of rows and columns of data. int *MAXRGB, the maximum RGB value. bool PPMB_READ_HEADER, equals true, if the header could not be read, false, if the header was read. */ { int c_val; int count; int flag; int nchar; int state; char string[255]; state = 0; nchar = 0; for ( ; ; ) { c_val = fgetc ( file_pointer ); if ( c_val == EOF ) { return true; } /* If not whitespace, add the character to the current string. */ flag = isspace ( c_val ); if ( !flag ) { string[nchar] = c_val; nchar = nchar + 1; } /* See if we have finished an old item, or begun a new one. */ if ( state == 0 ) { if ( !flag ) { state = 1; } else { return true; } } else if ( state == 1 ) { if ( flag ) { string[nchar] = 0; nchar = nchar + 1; if ( strcmp ( string, "P6" ) != 0 && strcmp ( string, "p6" ) != 0 ) { printf ( "\n" ); printf ( "PPMB_READ_HEADER: Warning!\n" ); printf ( " Bad magic number = %s.\n", string ); return true; } nchar = 0; state = 2; } } else if ( state == 2 ) { if ( !flag ) { state = 3; } } else if ( state == 3 ) { if ( flag ) { string[nchar] = 0; nchar = nchar + 1; count = sscanf ( string, "%d", xsize ); if ( count == EOF ) { return true; } nchar = 0; state = 4; } } else if ( state == 4 ) { if ( !flag ) { state = 5; } } else if ( state == 5 ) { if ( flag ) { string[nchar] = 0; nchar = nchar + 1; count = sscanf ( string, "%d", ysize ); if ( count == EOF ) { return true; } nchar = 0; state = 6; } } else if ( state == 6 ) { if ( !flag ) { state = 7; } } else if ( state == 7 ) { if ( flag ) { string[nchar] = 0; nchar = nchar + 1; count = sscanf ( string, "%d", maxrgb ); if ( count == EOF ) { return true; } nchar = 0; return false; } } } } /******************************************************************************/ bool ppmb_read_test ( char *file_name ) /******************************************************************************/ /* Purpose: PPMB_READ_TEST tests the binary portable pixel map read routines. Licensing: This code is distributed under the MIT license. Modified: 16 June 2012 Author: John Burkardt Input: char *FILE_NAME, the name of the file containing the binary portable pixel map data. Output: bool PPMB_READ_TEST, equals true, if the test could not be carried out, false, if the test was carried out. */ { unsigned char *barray; unsigned char *garray; int maxrgb; unsigned char *rarray; bool result; int xsize; int ysize; rarray = NULL; garray = NULL; barray = NULL; /* Read the data. */ result = ppmb_read ( file_name, &xsize, &ysize, &maxrgb, &rarray, &garray, &barray ); if ( result ) { printf ( "\n" ); printf ( "PPMB_READ_TEST: Warning!\n" ); printf ( " PPMB_READ failed.\n" ); if ( rarray != NULL ) { free ( rarray ); } if ( garray != NULL ) { free ( garray ); } if ( barray != NULL ) { free ( barray ); } return true; } /* Check the data. */ result = ppmb_check_data ( xsize, ysize, maxrgb, rarray, garray, barray ); if ( rarray != NULL ) { free ( rarray ); } if ( garray != NULL ) { free ( garray ); } if ( barray != NULL ) { free ( barray ); } if ( result ) { printf ( "\n" ); printf ( " PPMB_CHECK_DATA reports bad data from the file.\n" ); return true; } printf ( "\n" ); printf ( " PPMB_CHECK_DATA passes the data from the file.\n" ); return false; } /******************************************************************************/ bool ppmb_write ( char *file_name, int xsize, int ysize, unsigned char *rarray, unsigned char *garray, unsigned char *barray ) /******************************************************************************/ /* Purpose: PPMB_WRITE writes the header and data for a binary portable pixel map file. Licensing: This code is distributed under the MIT license. Modified: 16 June 2012 Author: John Burkardt Input: char *FILE_NAME, the name of the file to contain the binary portable pixel map data. int XSIZE, YSIZE, the number of rows and columns of data. unsigned char *RARRAY, *GARRAY, *BARRAY, the arrays of XSIZE by YSIZE data values. Output: bool PPMB_WRITE, equals true, if the file could not be written, false, if the file was written. */ { FILE *file_pointer; int i; unsigned char *indexb; unsigned char *indexg; unsigned char *indexr; int j; int maxrgb; bool result; /* Open the output file. */ file_pointer = fopen ( file_name, "wb" ); if ( file_pointer == NULL ) { printf ( "\n" ); printf ( "PPMB_WRITE: Warning!\n" ); printf ( " Cannot open the output file %s.\n", file_name ); return true; } /* Compute the maximum. */ maxrgb = 0; indexr = rarray; indexg = garray; indexb = barray; for ( j = 0; j < ysize; j++ ) { for ( i = 0; i < xsize; i++ ) { if ( maxrgb < *indexr ) { maxrgb = *indexr; } if ( maxrgb < *indexg ) { maxrgb = *indexg; } if ( maxrgb < *indexb ) { maxrgb = *indexb; } indexr = indexr + 1; indexg = indexg + 1; indexb = indexb + 1; } } /* Write the header. */ result = ppmb_write_header ( file_pointer, xsize, ysize, maxrgb ); if ( result ) { printf ( "\n" ); printf ( "PPMB_WRITE: Warning!\n" ); printf ( " PPMB_WRITE_HEADER failed.\n" ); return true; } /* Write the data. */ result = ppmb_write_data ( file_pointer, xsize, ysize, rarray, garray, barray ); if ( result ) { printf ( "\n" ); printf ( "PPMB_WRITE: Warning!\n" ); printf ( " PPMB_WRITE_DATA failed.\n" ); return true; } /* Close the file. */ fclose ( file_pointer ); return false; } /******************************************************************************/ bool ppmb_write_data ( FILE *file_pointer, int xsize, int ysize, unsigned char *rarray, unsigned char *garray, unsigned char *barray ) /******************************************************************************/ /* Purpose: PPMB_WRITE_DATA writes the data for a binary portable pixel map file. Licensing: This code is distributed under the MIT license. Modified: 16 June 2012 Author: John Burkardt Input: FILE *FILE_POINTER, a pointer to the file to contain the binary portable pixel map data. int XSIZE, YSIZE, the number of rows and columns of data. unsigned char *RARRAY, *GARRAY, *BARRAY, the arrays of XSIZE by YSIZE data values. Output: bool PPMB_WRITE_DATA, equals true, if the data could not be written, false, if the data was written. */ { int i; unsigned char *indexb; unsigned char *indexg; unsigned char *indexr; int j; indexr = rarray; indexg = garray; indexb = barray; for ( j = 0; j < ysize; j++ ) { for ( i = 0; i < xsize; i++ ) { fputc ( *indexr, file_pointer ); fputc ( *indexg, file_pointer ); fputc ( *indexb, file_pointer ); indexr = indexr + 1; indexg = indexg + 1; indexb = indexb + 1; } } return false; } /******************************************************************************/ bool ppmb_write_header ( FILE *file_pointer, int xsize, int ysize, int maxrgb ) /******************************************************************************/ /* Purpose: PPMB_WRITE_HEADER writes the header of a binary portable pixel map file. Licensing: This code is distributed under the MIT license. Modified: 16 June 2012 Author: John Burkardt Input: FILE *FILE_POINTER, a pointer to the file to contain the binary portable pixel map data. int XSIZE, YSIZE, the number of rows and columns of data. int MAXRGB, the maximum RGB value. Output: bool PPMB_WRITE_HEADER, equals true, if the header could not be written, false, if the header was written. */ { fprintf ( file_pointer, "P6 %d %d %d ", xsize, ysize, maxrgb ); return false; } /******************************************************************************/ bool ppmb_write_test ( char *file_name ) /******************************************************************************/ /* Purpose: PPMB_WRITE_TEST tests the binary portable pixel map write routines. Licensing: This code is distributed under the MIT license. Modified: 16 June 2012 Author: John Burkardt Input: char *FILE_NAME, the name of the file to contain the binary portable pixel map data. Output: bool PPMB_WRITE_TEST equals true, if the test could not be carried out, false, if the test was carried out. */ { unsigned char *barray; unsigned char *garray; unsigned char *rarray; bool result; int xsize; int ysize; xsize = 200; ysize = 200; /* Allocate memory. */ rarray = ( unsigned char * ) malloc ( xsize * ysize * sizeof ( unsigned char ) ); if ( rarray == NULL ) { printf ( "\n" ); printf ( "PPMB_WRITE_TEST: Warning!\n" ); printf ( " Unable to allocate memory for data.\n" ); return true; } garray = ( unsigned char * ) malloc ( xsize * ysize * sizeof ( unsigned char ) ); if ( garray == NULL ) { printf ( "\n" ); printf ( "PPMB_WRITE_TEST: Warning!\n" ); printf ( " Unable to allocate memory for data.\n" ); return true; } barray = ( unsigned char * ) malloc ( xsize * ysize * sizeof ( unsigned char ) ); if ( barray == NULL ) { printf ( "\n" ); printf ( "PPMB_WRITE_TEST: Warning!\n" ); printf ( " Unable to allocate memory for data.\n" ); return true; } /* Set the data. */ result = ppmb_example ( xsize, ysize, rarray, garray, barray ); if ( result ) { printf ( "\n" ); printf ( "PPMB_WRITE_TEST: Warning!\n" ); printf ( " PPM_EXAMPLE failed.\n" ); return true; } /* Write the data to the file. */ result = ppmb_write ( file_name, xsize, ysize, rarray, garray, barray ); if ( rarray != NULL ) { free ( rarray ); } if ( garray != NULL ) { free ( garray ); } if ( barray != NULL ) { free ( barray ); } if ( result ) { printf ( "\n" ); printf ( "PPMB_WRITE_TEST: Warning!\n" ); printf ( " PPMB_WRITE failed.\n" ); return true; } return false; }