/* pjtoppm.c - convert an HP PainJetXL image to a PPM ** ** Copyright (C) 1990 by Christos Zoulas (christos@ee.cornell.edu) ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include #include #include "ppm.h" #include "pm_c_util.h" #include "mallocvar.h" static unsigned int uintProduct(unsigned int const multiplicand, unsigned int const multiplier) { if (UINT_MAX / multiplier < multiplicand) pm_error("Airthmetic overflow"); return multiplicand * multiplier; } static int egetc(FILE * const ifP) { int c; c = fgetc(ifP); if (c == -1) pm_error("unexpected end of file"); return c; } static void modifyImageMode1(unsigned int const rows, unsigned int const planes, const int * const imlen, unsigned char ** const image, unsigned int * const colsP) { unsigned int const newcols = 10240; /* It could not be larger than that! */ unsigned int cols; unsigned int row; for (row = 0, cols = 0; row < rows; ++row) { unsigned int plane; if (image[row * planes]) { for (plane = 0; plane < planes; ++plane) { unsigned int i; unsigned int col; unsigned char * buf; MALLOCARRAY(buf, newcols); if (buf == NULL) pm_error("out of memory"); for (i = 0, col = 0; col < imlen[row * planes + plane]; col += 2) { int cmd, val; for (cmd = image[row * planes + plane][col], val = image[plane + row * planes][col+1]; cmd >= 0 && i < newcols; --cmd, ++i) buf[i] = val; } cols = MAX(cols, i); free(image[row * planes + plane]); /* * This is less than what we have so it realloc should * not return null. Even if it does, tough! We will * lose a line, and probably die on the next line anyway */ image[row * planes + plane] = realloc(buf, i); } } } *colsP = cols * 8; assert(cols < UINT_MAX/8); } static void writePpm(FILE * const ofP, unsigned int const cols, unsigned int const rows, unsigned int const planes, unsigned char ** const image, int const mode, const int * const imlen) { pixel * pixrow; unsigned int row; ppm_writeppminit(stdout, cols, rows, 255, 0); pixrow = ppm_allocrow(cols); for (row = 0; row < rows; ++row) { if (image[row * planes + 0] == NULL) { unsigned int col; for (col = 0; col < cols; ++col) PPM_ASSIGN(pixrow[col], 0, 0, 0); } else { unsigned int col; unsigned int cmd; for (cmd = 0, col = 0; col < cols; col += 8, ++cmd) { unsigned int i; for (i = 0; i < 8 && col + i < cols; ++i) { unsigned int plane; unsigned char bf[3]; assert(planes == 3); for (plane = 0; plane < planes; ++plane) { if (mode == 0 && cmd >= imlen[row * planes + plane]) bf[plane] = 0; else bf[plane] = (image[row * planes + plane][cmd] & (1 << (7 - i))) ? 255 : 0; } PPM_ASSIGN(pixrow[col + i], bf[0], bf[1], bf[2]); } } ppm_writeppmrow(stdout, pixrow, cols, 255, 0); } } } int main(int argc, const char ** argv) { int cmd, val; char buffer[BUFSIZ]; unsigned int planes; unsigned int rows; unsigned int rowsX; unsigned int cols; bool colsIsSet; unsigned char ** image; /* malloc'ed */ int * imlen; /* malloc'ed */ FILE * ifP; int mode; bool modeIsSet; int c; unsigned int plane; unsigned int row; pm_proginit(&argc, argv); if (argc-1 > 0) ifP = pm_openr(argv[1]); else ifP = stdin; if (argc-1 > 2) pm_error("Too many arguments (%u). Only possible argument is " "input file name", argc-1); row = 0; /* initial value */ plane = 0; /* initial value */ modeIsSet = false; /* initial value */ colsIsSet = false; /* initial value */ rowsX = 0; /* initial value */ image = NULL; /* initial value */ imlen = NULL; /* initial value */ planes = 3; /* initial value */ while ((c = fgetc(ifP)) != -1) { if (c != '\033') continue; switch (c = egetc(ifP)) { case 'E': /* reset */ break; case '*': { unsigned int i; cmd = egetc(ifP); for (i = 0; i < BUFSIZ; i++) { if (!isdigit(c = egetc(ifP)) && c != '+' && c != '-') break; buffer[i] = c; } if (i != 0) { buffer[i] = '\0'; if (sscanf(buffer, "%d", &val) != 1) pm_error("bad value `%s' at *%c%c", buffer, cmd, c); } else val = -1; switch (cmd) { case 't': switch (c) { case 'J': /* render */ break; case 'K': /* back scale */ break; case 'I': /* gamma */ break; case 'R': break; /* set resolution */ default: pm_message("uninmplemented *%c%d%c", cmd, val, c); break; } break; case 'r': switch (c) { case 'S': /* width */ if (val < 0) pm_error("invalid width value"); else { cols = val; colsIsSet = true; } break; case 'T': /* height */ if (val < 0) pm_error ("invalid height value"); else rowsX = val; break; case 'U': /* planes */ planes = val; if (planes != 3) pm_error("can handle only 3 plane files"); break; case 'A': /* begin raster */ break; case 'B': case 'C': /* end raster */ break; case 'V': break; /* set deci height */ case 'H': break; /* set deci width */ default: pm_message("uninmplemented *%c%d%c", cmd, val, c); break; } break; case 'b': switch (c) { case 'M': /* transmission mode */ if (val != 0 && val != 1) pm_error("unimplemented transmission mode %d", val); mode = val; modeIsSet = true; break; case 'V': /* send plane */ case 'W': /* send last plane */ if (row >= rowsX || image == NULL) { if (row >= rowsX) rowsX += 100; REALLOCARRAY(image, uintProduct(rowsX, planes)); REALLOCARRAY(imlen, uintProduct(rowsX, planes)); } if (image == NULL || imlen == NULL) pm_error("out of memory"); if (plane >= planes) pm_error("too many planes"); if (!colsIsSet) pm_error("missing width value"); cols = MAX(cols, val); imlen[row * planes + plane] = val; MALLOCARRAY(image[row * planes + plane], val); if (image[row * planes + plane] == NULL) pm_error("out of memory"); if (fread(image[row * planes + plane], 1, val, ifP) != val) pm_error("short data"); if (c == 'V') ++plane; else { plane = 0; if (row > UINT_MAX/planes-100) pm_error("Too many rows (more than %u) " "for computation", row); ++row; } break; default: pm_message("uninmplemented *%c%d%c", cmd, val, c); break; } break; case 'p': /* Position */ if (plane != 0) pm_error("changed position in the middle of " "transferring planes"); switch (c) { case 'X': pm_message("can only position in y"); break; case 'Y': if (buffer[0] == '+') val = row + val; if (buffer[0] == '-') val = row - val; for (; val > row; ++row) for (plane = 0; plane < 3; ++plane) { imlen[row * planes + plane] = 0; image[row * planes + plane] = NULL; } row = val; break; default: pm_message("uninmplemented *%c%d%c", cmd, val, c); break; } default: pm_message("uninmplemented *%c%d%c", cmd, val, c); break; } } /* case */ } /* switch */ } pm_close(ifP); if (!modeIsSet) pm_error("Input does not contain a 'bM' transmission mode order"); rows = row; if (mode == 1) { modifyImageMode1(rows, planes, imlen, image, &cols); } writePpm(stdout, cols, rows, planes, image, mode, imlen); pm_close(stdout); return 0; }