/* * pbmtojbg85 - Portable Bitmap to JBIG converter (T.85 version) * * Markus Kuhn - http://www.cl.cam.ac.uk/~mgk25/jbigkit/ */ #include #include #include #include #include #include "jbig85.h" char *progname; /* global pointer to argv[0] */ /* * Print usage message and abort */ static void usage(void) { fprintf(stderr, "PBMtoJBIG converter " JBG85_VERSION " (T.85 version) --\n" "creates bi-level image entity (BIE) as output file\n\n" "usage: %s [] [ | - []]\n\n" "options:\n\n", progname); fprintf(stderr, " -s number\theight of a stripe\n"); fprintf(stderr, " -m number\tmaximum adaptive template pixel horizontal offset (default 8)\n" " -p number\toptions byte value: add TPBON=8, LRLTWO=64\n" "\t\t(default 8 = TPBON)\n"); fprintf(stderr, " -C string\tadd the provided string as a comment marker segment\n"); fprintf(stderr, " -Y yi yr\tannounce in header initially the larger image height yi\n" "\t\tand then announce after line yr has been encoded the real height\n" "\t\tusing NEWLEN marker (for testing NEWLEN and VLENGTH=1 function)\n\n"); exit(1); } /* * malloc() with exception handler */ void *checkedmalloc(size_t n) { void *p; if ((p = malloc(n)) == NULL) { fprintf(stderr, "Sorry, not enough memory available!\n"); exit(1); } return p; } /* * Read an ASCII integer number from file f and skip any PBM * comments which are encountered. */ static unsigned long getint(FILE *f) { int c; unsigned long i; while ((c = getc(f)) != EOF) if (c == '#') while ((c = getc(f)) != EOF && !(c == 13 || c == 10)) ; else if (!isspace(c)) break; if (c == EOF) return 0; ungetc(c, f); if (fscanf(f, "%lu", &i) != 1) { fprintf(stderr, "Unsigned integer value expected!\n"); exit(1); } return i; } /* * Callback procedure which is used by JBIG encoder to deliver the * encoded data. It simply sends the bytes to the output file. */ static void data_out(unsigned char *start, size_t len, void *file) { fwrite(start, len, 1, (FILE *) file); return; } int main (int argc, char **argv) { FILE *fin = stdin, *fout = stdout; const char *fnin = NULL, *fnout = NULL; int i, j, c; int all_args = 0, files = 0; unsigned long x, y; unsigned long width, height; size_t bpl; char type; unsigned char *p, *lines, *next_line; unsigned char *prev_line = NULL, *prevprev_line = NULL; struct jbg85_enc_state s; int mx = -1; unsigned long l0 = 0, yi = 0, yr = 0; char *comment = NULL; int options = JBG_TPBON; /* parse command line arguments */ progname = argv[0]; for (i = 1; i < argc; i++) { if (!all_args && argv[i][0] == '-') if (argv[i][1] == 0) { if (files++) usage(); } else for (j = 1; j > 0 && argv[i][j]; j++) switch(argv[i][j]) { case '-' : all_args = 1; break; case 0 : if (files++) usage(); break; case 'Y': if (i+2 >= argc) usage(); j = -1; yi = atol(argv[++i]); yr = atol(argv[++i]); break; case 'p': if (++i >= argc) usage(); j = -1; options = atoi(argv[i]); break; case 's': if (++i >= argc) usage(); j = -1; l0 = atol(argv[i]); break; case 'm': if (++i >= argc) usage(); j = -1; mx = atoi(argv[i]); break; case 'C': if (++i >= argc) usage(); j = -1; comment = argv[i]; break; default: usage(); } else switch (files++) { case 0: fnin = argv[i]; break; case 1: fnout = argv[i]; break; default: usage(); } } /* open input file */ if (fnin) { fin = fopen(fnin, "rb"); if (!fin) { fprintf(stderr, "Can't open input file '%s", fnin); perror("'"); exit(1); } } else fnin = ""; /* read PBM header */ while ((c = getc(fin)) != EOF && (isspace(c) || c == '#')) if (c == '#') while ((c = getc(fin)) != EOF && !(c == 13 || c == 10)) ; type = getc(fin); if (c != 'P' || (type != '1' && type != '4')) { fprintf(stderr, "Input file '%s' does not look like a PBM file!\n", fnin); exit(1); } width = getint(fin); height = getint(fin); fgetc(fin); /* skip line feed */ /* Test for valid parameters */ if (width < 1 || height < 1 || width > 0xffffffff || height > 0xffffffff) { fprintf(stderr, "Invalid width or height!\n"); exit(1); } /* allocate buffer for a single image line */ bpl = (width >> 3) + !!(width & 7); /* bytes per line */ lines = (unsigned char *) checkedmalloc(bpl * 3); /* open output file */ if (fnout) { fout = fopen(fnout, "wb"); if (!fout) { fprintf(stderr, "Can't open input file '%s", fnout); perror("'"); exit(1); } } else fnout = ""; /* initialize parameter struct for JBIG encoder*/ jbg85_enc_init(&s, width, yi ? yi : height, data_out, fout); /* Specify a few other options (each is ignored if negative) */ if (yi) options |= JBG_VLENGTH; if (comment) { s.comment_len = strlen(comment); s.comment = (unsigned char *) comment; } jbg85_enc_options(&s, options, l0, mx); for (y = 0; y < height; y++) { /* Use a 3-line ring buffer, because the encoder requires that the two * previously supplied lines are still in memory when the next line is * processed. */ next_line = lines + (y%3)*bpl; switch (type) { case '1': /* PBM text format */ p = next_line; for (x = 0; x <= ((width-1) | 7); x++) { *p <<= 1; if (x < width) *p |= getint(fin) & 1; if ((x & 7) == 7) ++p; } break; case '4': /* PBM raw binary format */ fread(next_line, bpl, 1, fin); break; default: fprintf(stderr, "Unsupported PBM type P%c!\n", type); exit(1); } if (ferror(fin)) { fprintf(stderr, "Problem while reading input file '%s", fnin); perror("'"); exit(1); } if (feof(fin)) { fprintf(stderr, "Unexpected end of input file '%s'!\n", fnin); exit(1); } /* JBIG compress another line and write out result via callback */ jbg85_enc_lineout(&s, next_line, prev_line, prevprev_line); prevprev_line = prev_line; prev_line = next_line; /* adjust final image height via NEWLEN */ if (yi && y == yr) jbg85_enc_newlen(&s, height); } /* check for file errors and close fout */ if (ferror(fout) || fclose(fout)) { fprintf(stderr, "Problem while writing output file '%s", fnout); perror("'"); exit(1); } return 0; }