/* jbigtopnm - JBIG to PNM converter This program was derived from jbgtopbm.c in Markus Kuhn's JBIG-KIT package by Bryan Henderson on 2000.05.11 The main difference is that this version uses the Netpbm libraries. */ #include #include #include #include #include #include #include "pnm.h" #include "shhopt.h" #include "mallocvar.h" #define BUFSIZE 8192 typedef struct { /* All the information the user supplied in the command line, in a form easy for the program to use. */ const char * inputFileName; const char * outputFileName; unsigned long xmax; unsigned long ymax; unsigned int binary; unsigned int diagnose; unsigned int planeSpec; unsigned int plane; } CmdlineInfo; static void parseCommandLine(int argc, const char ** const argv, CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. -----------------------------------------------------------------------------*/ optEntry * option_def; optStruct3 opt; unsigned int xmaxSpec, ymaxSpec; unsigned int option_def_index; MALLOCARRAY_NOFAIL(option_def, 100); option_def_index = 0; /* incremented by OPTENT3 */ OPTENT3(0, "binary", OPT_FLAG, NULL, &cmdlineP->binary, 0); OPTENT3(0, "diagnose", OPT_FLAG, NULL, &cmdlineP->diagnose, 0); OPTENT3(0, "plane", OPT_UINT, &cmdlineP->plane, &cmdlineP->planeSpec,0); OPTENT3(0, "xmax", OPT_UINT, &cmdlineP->xmax, &xmaxSpec, 0); OPTENT3(0, "ymax", OPT_UINT, &cmdlineP->ymax, &ymaxSpec, 0); opt.opt_table = option_def; opt.short_allowed = false; /* We have no short (old-fashioned) options */ opt.allowNegNum = false; /* We have no parms that are negative numbers */ pm_optParseOptions3(&argc, (char**)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!xmaxSpec) cmdlineP->xmax = UINT_MAX; if (!ymaxSpec) cmdlineP->ymax = UINT_MAX; cmdlineP->inputFileName = (argc-1 >= 1) ? argv[1] : "-"; cmdlineP->outputFileName = (argc-1 >= 2) ? argv[2] : "-"; if (argc-1 > 2) pm_error("Too many arguments: %u. The only possible " "non-option arguments are input file name and " "output file name", argc-1); } static void collect_image (unsigned char *data, size_t len, void *image) { static int cursor = 0; int i; for (i = 0; i < len; i++) { ((unsigned char *)image)[cursor++] = data[i]; } } static void write_pnm (FILE *fout, const unsigned char * const image, const int bpp, const int rows, const int cols, const int maxval, const int format) { int row; xel *pnm_row; pnm_writepnminit(fout, cols, rows, maxval, format, 0); pnm_row = pnm_allocrow(cols); for (row = 0; row < rows; row++) { int col; for (col = 0; col < cols; col++) { int j; for (j = 0; j < bpp; j++) PNM_ASSIGN1(pnm_row[col], image[(((row*cols)+col) * bpp) + j]); } pnm_writepnmrow(fout, pnm_row, cols, maxval, format, 0); } pnm_freerow(pnm_row); } static void write_raw_pbm(FILE * const fout, const unsigned char * const binary_image, int const cols, int const rows) { unsigned int const bytes_per_row = pbm_packed_bytes(cols); int row; pbm_writepbminit(fout, cols, rows, 0); for (row = 0; row < rows; ++row) pbm_writepbmrow_packed(fout, &binary_image[row*bytes_per_row], cols, 0); } /* * */ static void diagnose_bie(FILE *f) { unsigned char bih[20]; int len; unsigned long xd, yd, l0; len = fread(bih, 1, 20, f); if (len < 20) { printf("Input file is %d < 20 bytes long and does therefore not " "contain an intact BIE header!\n", len); return; } printf("Decomposition of BIH:\n\n DL = %d\n D = %d\n P = %d\n" " - = %d\n XD = %lu\n YD = %lu\n L0 = %lu\n MX = %d\n" " MY = %d\n", bih[0], bih[1], bih[2], bih[3], xd = ((unsigned long) bih[ 4] << 24) | ((unsigned long)bih[ 5] << 16)| ((unsigned long) bih[ 6] << 8) | ((unsigned long) bih[ 7]), yd = ((unsigned long) bih[ 8] << 24) | ((unsigned long)bih[ 9] << 16)| ((unsigned long) bih[10] << 8) | ((unsigned long) bih[11]), l0 = ((unsigned long) bih[12] << 24) | ((unsigned long)bih[13] << 16)| ((unsigned long) bih[14] << 8) | ((unsigned long) bih[15]), bih[16], bih[17]); printf(" order = %d %s%s%s%s%s\n", bih[18], bih[18] & JBG_HITOLO ? " HITOLO" : "", bih[18] & JBG_SEQ ? " SEQ" : "", bih[18] & JBG_ILEAVE ? " ILEAVE" : "", bih[18] & JBG_SMID ? " SMID" : "", bih[18] & 0xf0 ? " other" : ""); printf(" options = %d %s%s%s%s%s%s%s%s\n", bih[19], bih[19] & JBG_LRLTWO ? " LRLTWO" : "", bih[19] & JBG_VLENGTH ? " VLENGTH" : "", bih[19] & JBG_TPDON ? " TPDON" : "", bih[19] & JBG_TPBON ? " TPBON" : "", bih[19] & JBG_DPON ? " DPON" : "", bih[19] & JBG_DPPRIV ? " DPPRIV" : "", bih[19] & JBG_DPLAST ? " DPLAST" : "", bih[19] & 0x80 ? " other" : ""); printf("\n %lu stripes, %d layers, %d planes\n\n", ((yd >> bih[1]) + ((((1UL << bih[1]) - 1) & xd) != 0) + l0 - 1) / l0, bih[1] - bih[0], bih[2]); return; } int main (int argc, const char **argv) { CmdlineInfo cmdline; FILE * ifP; FILE * ofP; pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFileName); ofP = pm_openw(cmdline.outputFileName); if (cmdline.diagnose) diagnose_bie(ifP); else { struct jbg_dec_state s; unsigned char * buffer; int result; MALLOCARRAY(buffer, BUFSIZE); if (!buffer) pm_error("Failed to get %u bytes of memory for buffer", BUFSIZE); /* send input file to decoder */ jbg_dec_init(&s); jbg_dec_maxsize(&s, cmdline.xmax, cmdline.ymax); result = JBG_EAGAIN; do { size_t len; size_t cnt; unsigned char * p; len = fread(buffer, 1, BUFSIZE, ifP); if (len == 0) break; cnt = 0; p = &buffer[0]; while (len > 0 && (result == JBG_EAGAIN || result == JBG_EOK)) { result = jbg_dec_in(&s, p, len, &cnt); p += cnt; len -= cnt; } } while (result == JBG_EAGAIN || result == JBG_EOK); if (ferror(ifP)) pm_error("Error reading input file"); if (result != JBG_EOK && result != JBG_EOK_INTR) pm_error("Invalid contents of input file. %s", jbg_strerror(result)); if (cmdline.planeSpec && jbg_dec_getplanes(&s) <= cmdline.plane) pm_error("Image has only %u planes", jbg_dec_getplanes(&s)); { /* Write it out */ int rows, cols; int maxval; int bpp; bool justOnePlane; unsigned int plane_to_write; cols = jbg_dec_getwidth(&s); rows = jbg_dec_getheight(&s); maxval = pm_bitstomaxval(jbg_dec_getplanes(&s)); bpp = (jbg_dec_getplanes(&s)+7)/8; if (jbg_dec_getplanes(&s) == 1) { justOnePlane = true; plane_to_write = 0; } else { if (cmdline.planeSpec) { justOnePlane = true; plane_to_write = cmdline.plane; } else justOnePlane = false; } if (justOnePlane) { unsigned char * binary_image; pm_message("WRITING PBM FILE"); binary_image=jbg_dec_getimage(&s, plane_to_write); write_raw_pbm(ofP, binary_image, cols, rows); } else { unsigned char *image; pm_message("WRITING PGM FILE"); /* Write out all the planes */ /* What jbig.doc doesn't tell you is that jbg_dec_merge_planes delivers the image in chunks, in consecutive calls to the data-out callback function. And a row can span two chunks. */ image = malloc(cols*rows*bpp); jbg_dec_merge_planes(&s, !cmdline.binary, collect_image, image); write_pnm(ofP, image, bpp, rows, cols, maxval, PGM_TYPE); free(image); } jbg_dec_free(&s); } pm_close(ofP); pm_close(ifP); free(buffer); } return 0; }