about summary refs log tree commit diff
path: root/converter/other/jbig/pnmtojbig.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other/jbig/pnmtojbig.c')
-rw-r--r--converter/other/jbig/pnmtojbig.c463
1 files changed, 463 insertions, 0 deletions
diff --git a/converter/other/jbig/pnmtojbig.c b/converter/other/jbig/pnmtojbig.c
new file mode 100644
index 00000000..9dbef3fa
--- /dev/null
+++ b/converter/other/jbig/pnmtojbig.c
@@ -0,0 +1,463 @@
+/*
+    pnmtojbig - PNM to JBIG converter
+  
+    This program was derived from pbmtojbg.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.
+
+ */
+
+/*
+     The JBIG standard doesn't say which end of the scale is white and
+     which end is black in a BIE.  It has a recommendation in terms of
+     foreground and background (a concept which does not exist in the
+     Netpbm formats) for single-plane images, and is silent for
+     multi-plane images.
+
+     Kuhn's implementation of the JBIG standard says if the BIE has a
+     single plane, then in that plane a zero bit means white and a one
+     bit means black.  But if it has multiple planes, a composite zero
+     value means black and a composite maximal value means white.
+
+     Actually, Kuhn's pbmtojbg doesn't even implement this, but rather
+     bases the distinction on whether the input file was PBM or PGM.
+     This means that if you convert a PGM file with maxval 1 to a JBIG
+     file and then back, the result (which is a PBM file) is the
+     inverse of what you started with.  Same if the PGM file has
+     maxval > 1 but you use a -t option to write only one plane.  We
+     assume this is just a bug in pbmtojpg and that hardly anybody does
+     this.  So we adopt the implementation described above.
+
+     This means that after jbg_split_planes() hands us a set of bitmap
+     planes, if there is only one of them, we have to invert all the
+     bits in it.
+
+*/
+  
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <jbig.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "pnm.h"
+
+static unsigned long total_length = 0;  
+  /* used for determining output file length */
+
+/*
+ * malloc() with exception handler
+ */
+static void
+*checkedmalloc(size_t n)
+{
+  void *p;
+  
+  if ((p = malloc(n)) == NULL) {
+    fprintf(stderr, "Sorry, not enough memory available!\n");
+    exit(1);
+  }
+  
+  return p;
+}
+
+
+/*
+ * 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);
+  total_length += len;
+  return;
+}
+
+
+
+static void
+readPbm(FILE *            const fin,
+        unsigned int      const cols,
+        unsigned int      const rows,
+        unsigned char *** const bitmapP) {
+
+    unsigned int const bytes_per_line = pbm_packed_bytes(cols);
+
+    unsigned char ** bitmap;
+
+    /* Read the input image into bitmap[] */
+    /* Shortcut for PBM */
+    int row;
+    bitmap = (unsigned char **) checkedmalloc(sizeof(unsigned char *));
+    bitmap[0] = (unsigned char *) checkedmalloc(bytes_per_line * rows);
+    
+    for (row = 0; row < rows; row++)
+        pbm_readpbmrow_packed(fin, &bitmap[0][row*bytes_per_line],
+                              cols, RPBM_FORMAT);
+
+    *bitmapP = bitmap;
+} 
+
+
+
+static void
+readImage(FILE * const fin,
+          unsigned int     const cols,
+          unsigned int     const rows,
+          xelval           const maxval,
+          int              const format,
+          unsigned int     const bpp,
+          unsigned char ** const imageP) {
+/*----------------------------------------------------------------------------
+  Read the input image and put it into *imageP;
+
+  Although the PBM case is separated, this logic works also for
+  PBM, bpp=1.
+-----------------------------------------------------------------------------*/
+    unsigned char *image;
+        /* This is a representation of the entire image with 'bpp' bytes per
+           pixel.  The 'bpp' bytes for each pixel are arranged MSB first
+           and its numerical value is the value from the PNM input.
+           The pixels are laid out in row-major format in this rectangle.
+           
+           The point of this data structure is it is what jbg_split_planes()
+           wants for input.
+        */
+    xel* pnm_row;
+    unsigned int row;
+
+    pnm_row = pnm_allocrow(cols);  /* row buffer */
+    MALLOCARRAY_NOFAIL(image, cols * rows * bpp);
+    
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        pnm_readpnmrow(fin, pnm_row, cols, maxval, format);
+        for (col = 0; col < cols; col++) {
+            unsigned int j;
+            /* Move each byte of the sample into image[], MSB first */
+            for (j = 0; j < bpp; ++j)
+                image[(((row*cols)+col) * bpp) + j] = (unsigned char)
+                    PNM_GET1(pnm_row[col]) >> ((bpp-1-j) * 8);
+        }
+    }
+    pnm_freerow(pnm_row);
+    *imageP = image;
+}
+      
+
+
+static void
+convertImageToBitmap(unsigned char *   const image,
+                     unsigned char *** const bitmapP,
+                     unsigned int      const encode_planes,
+                     unsigned int      const bytes_per_line,
+                     unsigned int      const lines) {
+    
+    /* Convert image[] into bitmap[]  */
+    
+    unsigned char ** bitmap;
+    unsigned int i;
+    
+    MALLOCARRAY_NOFAIL(bitmap, encode_planes);
+    for (i = 0; i < encode_planes; ++i)
+        MALLOCARRAY_NOFAIL(bitmap[i], bytes_per_line * lines);
+
+    *bitmapP = bitmap;
+}
+
+
+
+static void
+readPnm(FILE *            const fin,
+        unsigned int      const cols,
+        unsigned int      const rows,
+        xelval            const maxval,
+        int               const format,
+        unsigned int      const bpp,
+        unsigned int      const planes,
+        unsigned int      const encode_planes,
+        bool              const use_graycode,
+        unsigned char *** const bitmapP) {
+
+    unsigned int const bytes_per_line = pbm_packed_bytes(cols);
+
+    unsigned char * image;
+    unsigned char ** bitmap;
+
+    readImage(fin, cols, rows, maxval, format, bpp, &image);
+
+    convertImageToBitmap(image, &bitmap, encode_planes, bytes_per_line, rows);
+
+    jbg_split_planes(cols, rows, planes, encode_planes, image, bitmap,
+                     use_graycode);
+    free(image);
+    
+    /* Invert the image if it is just one plane.  See top of this file
+       for an explanation why.  Due to the separate handling of PBM,
+       this is for exceptional PGM files.  
+    */
+
+    if (encode_planes == 1) {
+        unsigned int row;
+        for (row = 0; row < rows; ++row) {
+            unsigned int i;
+            for (i = 0; i < bytes_per_line; i++)
+                bitmap[0][(row*bytes_per_line) + i] ^= 0xff;
+
+            if (cols % 8 > 0) {   
+                bitmap[0][ (row+1)*bytes_per_line  -1] >>= 8-cols%8;
+                bitmap[0][ (row+1)*bytes_per_line  -1] <<= 8-cols%8;
+            }
+        }
+    }
+    *bitmapP = bitmap;
+}
+
+
+
+int
+main(int argc, char **argv) {
+    FILE *fin = stdin, *fout = stdout;
+    const char *fnin = "<stdin>", *fnout = "<stdout>";
+    int i;
+    int all_args = 0, files = 0;
+    int bpp, planes, encode_planes = -1;
+    int cols, rows;
+    xelval maxval;
+    int format;
+    unsigned char **bitmap;
+    /* This is an array of the planes of the image.  Each plane is a
+       two-dimensional array of pixels laid out in row-major format.
+       format with each pixel being one bit.  A byte in the array 
+       contains 8 pixels left to right, msb to lsb.
+    */
+
+    struct jbg_enc_state s;
+    int verbose = 0, delay_at = 0, use_graycode = 1;
+    long mwidth = 640, mheight = 480;
+    int dl = -1, dh = -1, d = -1, l0 = -1, mx = -1;
+    int options = JBG_TPDON | JBG_TPBON | JBG_DPON;
+    int order = JBG_ILEAVE | JBG_SMID;
+
+    pbm_init(&argc, argv);
+
+    /* parse command line arguments */
+    for (i = 1; i < argc; ++i) {
+        int j;
+        if (!all_args && argv[i][0] == '-') {
+            if (argv[i][1] == '\0' && files == 0)
+                ++files;
+            else {
+                for (j = 1; j > 0 && argv[i][j]; j++) {
+                    switch(tolower(argv[i][j])) {
+                    case '-' :
+                        all_args = 1;
+                        break;
+                    case 'v':
+                        verbose = 1;
+                        break;
+                    case 'b':
+                        use_graycode = 0;
+                        break;
+                    case 'c':
+                        delay_at = 1;
+                        break;
+                    case 'x':
+                        if (++i >= argc)
+                            pm_error("-x needs a value");
+                        j = -1;
+                        mwidth = atol(argv[i]);
+                        break;
+                    case 'y':
+                        if (++i >= argc)
+                            pm_error("-y needsa  value");
+                        j = -1;
+                        mheight = atol(argv[i]);
+                        break;
+                    case 'o':
+                        if (++i >= argc)
+                            pm_error("-o needs a value");
+                        j = -1;
+                        order = atoi(argv[i]);
+                        break;
+                    case 'p':
+                        if (++i >= argc)
+                            pm_error("-p needs a value");
+                        j = -1;
+                        options = atoi(argv[i]);
+                        break;
+                    case 'l':
+                        if (++i >= argc)
+                            pm_error("-l needs a value");
+                        j = -1;
+                        dl = atoi(argv[i]);
+                        break;
+                    case 'h':
+                        if (++i >= argc)
+                            pm_error("-h needs a value");
+                        j = -1;
+                        dh = atoi(argv[i]);
+                        break;
+                    case 'q':
+                        d = 0;
+                        break;
+                    case 'd':
+                        if (++i >= argc)
+                            pm_error("-d needs a value");
+                        j = -1;
+                        d = atoi(argv[i]);
+                        break;
+                    case 's':
+                        if (++i >= argc)
+                            pm_error("-s needs a value");
+                        j = -1;
+                        l0 = atoi(argv[i]);
+                        break;
+                    case 't':
+                        if (++i >= argc)
+                            pm_error("-t needs a value");
+                        j = -1;
+                        encode_planes = atoi(argv[i]);
+                        break;
+                    case 'm':
+                        if (++i >= argc)
+                            pm_error("-m needs a value");
+                        j = -1;
+                        mx = atoi(argv[i]);
+                        break;
+                    default:
+                        pm_error("Unrecognized option: %c", argv[i][j]);
+                    }
+                }
+            }
+        } else {
+            switch (files++) {
+            case 0:
+                if (argv[i][0] != '-' || argv[i][1] != '\0') {
+                    fnin = argv[i];
+                    fin = fopen(fnin, "rb");
+                    if (!fin) {
+                        fprintf(stderr, "Can't open input file '%s", fnin);
+                        perror("'");
+                        exit(1);
+                    }
+                }
+                break;
+            case 1:
+                fnout = argv[i];
+                fout = fopen(fnout, "wb");
+                if (!fout) {
+                    fprintf(stderr, "Can't open input file '%s", fnout);
+                    perror("'");
+                    exit(1);
+                }
+                break;
+            default:
+                pm_error("too many non-option arguments");
+            }
+        }
+    }
+
+    pnm_readpnminit(fin, &cols, &rows, &maxval, &format);
+
+    if (PNM_FORMAT_TYPE(format) != PGM_TYPE &&
+        PNM_FORMAT_TYPE(format) != PBM_TYPE)
+        pm_error("This program accepts PBM and PGM input only.  "
+                 "Try Ppmtopgm.");
+
+    planes = pm_maxvaltobits(maxval);
+
+    /* In a JBIG file, maxvals are determined only by the number of planes,
+       so must be a power of 2 minus 1
+    */
+  
+    if ((1UL << planes)-1 != maxval) 
+        pm_error("Input image has unacceptable maxval: %d.  JBIG files must "
+                 "have a maxval which is a power of 2 minus 1.  Use "
+                 "Ppmdepth to adjust the image's maxval", maxval);
+
+    bpp = (planes + 7) / 8;
+
+    if (encode_planes < 0 || encode_planes > planes)
+        encode_planes = planes;
+
+    if (bpp == 1 && PNM_FORMAT_TYPE(format) == PBM_TYPE)
+        readPbm(fin, cols, rows, &bitmap);
+    else
+        readPnm(fin, cols, rows, maxval, format, bpp, 
+                planes, encode_planes, use_graycode, 
+                &bitmap);
+
+    /* Apply JBIG algorithm and write BIE to output file */
+
+  /* initialize parameter struct for JBIG encoder*/
+    jbg_enc_init(&s, cols, rows, encode_planes, bitmap, data_out, fout);
+
+    /* Select number of resolution layers either directly or based
+   * on a given maximum size for the lowest resolution layer */
+    if (d >= 0)
+        jbg_enc_layers(&s, d);
+    else
+        jbg_enc_lrlmax(&s, mwidth, mheight);
+
+  /* Specify a few other options (each is ignored if negative) */
+    if (delay_at)
+        options |= JBG_DELAY_AT;
+    jbg_enc_lrange(&s, dl, dh);
+    jbg_enc_options(&s, order, options, l0, mx, -1);
+
+  /* now encode everything and send it to data_out() */
+    jbg_enc_out(&s);
+
+    /* give encoder a chance to free its temporary data structures */
+    jbg_enc_free(&s);
+
+    /* check for file errors and close fout */
+    if (ferror(fout) || fclose(fout)) {
+        fprintf(stderr, "Problem while writing output file '%s", fnout);
+        perror("'");
+        exit(1);
+    }
+
+    /* In case the user wants to know all the gory details ... */
+    if (verbose) {
+        fprintf(stderr, "Information about the created JBIG bi-level image entity "
+                "(BIE):\n\n");
+        fprintf(stderr, "              input image size: %ld x %ld pixel\n",
+                s.xd, s.yd);
+        fprintf(stderr, "                    bit planes: %d\n", s.planes);
+        if (s.planes > 1)
+            fprintf(stderr, "                      encoding: %s code, MSB first\n",
+                    use_graycode ? "Gray" : "binary");
+        fprintf(stderr, "                       stripes: %ld\n", s.stripes);
+        fprintf(stderr, "   lines per stripe in layer 0: %ld\n", s.l0);
+        fprintf(stderr, "  total number of diff. layers: %d\n", s.d);
+        fprintf(stderr, "           lowest layer in BIE: %d\n", s.dl);
+        fprintf(stderr, "          highest layer in BIE: %d\n", s.dh);
+        fprintf(stderr, "             lowest layer size: %lu x %lu pixel\n",
+                jbg_ceil_half(s.xd, s.d - s.dl), jbg_ceil_half(s.yd, s.d - s.dl));
+        fprintf(stderr, "            highest layer size: %lu x %lu pixel\n",
+                jbg_ceil_half(s.xd, s.d - s.dh), jbg_ceil_half(s.yd, s.d - s.dh));
+        fprintf(stderr, "                   option bits:%s%s%s%s%s%s%s\n",
+                s.options & JBG_LRLTWO  ? " LRLTWO" : "",
+                s.options & JBG_VLENGTH ? " VLENGTH" : "",
+                s.options & JBG_TPDON   ? " TPDON" : "",
+                s.options & JBG_TPBON   ? " TPBON" : "",
+                s.options & JBG_DPON    ? " DPON" : "",
+                s.options & JBG_DPPRIV  ? " DPPRIV" : "",
+                s.options & JBG_DPLAST  ? " DPLAST" : "");
+        fprintf(stderr, "                    order bits:%s%s%s%s\n",
+                s.order & JBG_HITOLO ? " HITOLO" : "",
+                s.order & JBG_SEQ    ? " SEQ" : "",
+                s.order & JBG_ILEAVE ? " ILEAVE" : "",
+                s.order & JBG_SMID   ? " SMID" : "");
+        fprintf(stderr, "           AT maximum x-offset: %d\n"
+                "           AT maximum y-offset: %d\n", s.mx, s.my);
+        fprintf(stderr, "         length of output file: %lu byte\n\n",
+                total_length);
+    }
+
+    return 0;
+}