#include #include #include #include #include #define PRINT_IMG_STATS /*Program by Robert R. Pavlis. This program takes a binary ppm file and converts it into three binary pgm files. It does in a sensible way what pamchannel does from the netpnm utilities. If you do not want colours and image size comment away the define for PRINT_IMG_STATS*/ int filelength (const char *fileName); int main (int argc, char *argv[]) { unsigned char *ppmimage; char redname[256], greenname[256], bluename[256], filebase[256]; int width, height, count, colours, fstrlen; long int i, j, k, m, lengthppm, ppmheader; FILE *infileppm, *outfilered, *outfilegreen, *outfileblue; if (argc != 2) { fprintf (stderr, "This program requires a ppm file name\n"); exit (1); } infileppm = fopen (argv[1], "rb"); if (infileppm == NULL) { printf ("ppm Input file not opened\n"); exit (1); } lengthppm = filelength (argv[1]); ppmimage = (char *) malloc (lengthppm); fread (ppmimage, lengthppm, 1, infileppm); /*the file must be in the binary ppm format, whose magic number is 0x50 0x36 */ if ((ppmimage[0] == 0x50) && (ppmimage[1] == 0x33)) /*magic number for text ppm */ { free (ppmimage); fprintf (stderr, "This program must use binary ppm only!\n"); exit (1); } if ((ppmimage[0] != 0x50) || (ppmimage[1] != 0x36)) { free (ppmimage); fprintf (stderr, "Bad Magic Number!\n"); fprintf (stderr, "%s is NOT a ppm file!\n", argv[1]); exit (1); } fclose (infileppm); /*now we have to parse the start of the headers and see if they contain comments, then we must locate the bytes that have width and length specifications. We then need to search for the 0x0A that ends the preliminary specifications. We must read the bit count/colour */ count = 0; ppmheader = 0; for (i = 0; i < 256; i++) { if (count == 1) break; if (ppmimage[i] == 0x0A) if (ppmimage[i + 1] != 0x23) if (count == 0) { width = atoi (ppmimage + i + 1); count = 1; for (j = 1; j < 16; j++) { if (ppmimage[i + j] == 0x20) { height = atoi (ppmimage + i + j + 1); i = i + j; break; } } for (k = 1; k < 16; k++) { if (ppmimage[i + k] == 0x0A) { colours = atoi (ppmimage + i + k + 1); i = i + k; break; } } } } count = 0; for (m = i; m < 256; m++) { if (ppmimage[m] == 0x0A) count++; if (count == 1) { ppmheader = m + 1; break; } } /*at this point the program has parsed the header */ strcpy (filebase, argv[1]); fstrlen = strlen (filebase); filebase[fstrlen - 2] = 0x67; strcpy (redname, "red_"); strcpy (greenname, "green_"); strcpy (bluename, "blue_"); strcat (redname, filebase); strcat (greenname, filebase); strcat (bluename, filebase); outfilered = fopen (redname, "wb"); if (outfilered == NULL) { printf ("Red output file not opened\n"); exit (1); } outfilegreen = fopen (greenname, "wb"); if (outfilegreen == NULL) { printf ("Green output file not opened\n"); exit (1); } outfileblue = fopen (bluename, "wb"); if (outfileblue == NULL) { printf ("Blue output file not opened\n"); exit (1); } ppmimage[1] = 0x35; /*make header into pgm */ fwrite (ppmimage, 1, ppmheader, outfilered); fwrite (ppmimage, 1, ppmheader, outfilegreen); fwrite (ppmimage, 1, ppmheader, outfileblue); if (colours < 0x100) for (i = ppmheader; i < lengthppm; i += 3) { fwrite (ppmimage + i, 1, 1, outfilered); fwrite (ppmimage + i + 1, 1, 1, outfilegreen); fwrite (ppmimage + i + 2, 1, 1, outfileblue); } else for (i = ppmheader; i < lengthppm; i += 6) { fwrite (ppmimage + i, 1, 2, outfilered); fwrite (ppmimage + i + 2, 1, 2, outfilegreen); fwrite (ppmimage + i + 4, 1, 2, outfileblue); } free (ppmimage); fclose (outfilered); fclose (outfilegreen); fclose (outfileblue); #ifdef PRINT_IMG_STATS printf ("width=%d, height=%d colours=%d\n", width, height, colours); #endif } int filelength (const char *fileName) { struct stat *st; st = (struct stat *) malloc (sizeof (struct stat)); if (stat (fileName, st) == -1) exit (1); return st->st_size; }