about summary refs log tree commit diff
path: root/converter/pbm/pktopbm.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/pbm/pktopbm.c')
-rw-r--r--converter/pbm/pktopbm.c442
1 files changed, 442 insertions, 0 deletions
diff --git a/converter/pbm/pktopbm.c b/converter/pbm/pktopbm.c
new file mode 100644
index 00000000..32ed4fde
--- /dev/null
+++ b/converter/pbm/pktopbm.c
@@ -0,0 +1,442 @@
+/*
+  pktopbm, adapted from "pktopx in C by Tomas Rokicki" by AJCD 1/8/90
+  1998-09-22: jcn <janneke@gnu.org>
+     - lots of bugfixes:
+     * always read x/y offset bytes (3x)
+     * reset bmx, bmy to defaults for each char
+     * fix bitmap y placement of dynamically packed char
+     * skip char early if no output file allocated
+     - added debug output
+  
+  compile with: cc -lpbm -o pktopbm pktopbm.c
+  */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "pm_c_util.h"
+#include "nstring.h"
+#include "pbm.h"
+
+#define NAMELENGTH 80
+#define MAXROWWIDTH 3200
+#define MAXPKCHAR 256
+
+typedef int integer ;
+typedef unsigned char quarterword ;
+typedef char boolean ;
+typedef quarterword eightbits ;
+
+static FILE *pkfile ;
+static char pkname[NAMELENGTH+1] ;
+static integer pktopbm_pkloc = 0;
+static char *filename[MAXPKCHAR] ;
+static bit **bitmap = NULL ;
+static integer dynf ;
+static eightbits inputbyte ;
+static eightbits bitweight ;
+static integer repeatcount ;
+static integer flagbyte ;
+static integer debug=0;
+
+#define dprintf(s,d) if (debug) printf(s,d)
+#define dprintf0(s) if (debug) printf(s)
+
+/* add a suffix to a filename in an allocated space */
+static void
+pktopbm_add_suffix(char *       const name, 
+                   const char * const suffix) {
+
+    char * const slash = strrchr(name, '/');
+    char * const dot   = strrchr(name, '.');
+    
+    if ((dot && slash ? dot < slash : !dot) && !STREQ(name, "-"))
+        strcat(name, suffix);
+}
+
+
+
+/* get a byte from the PK file */
+static eightbits 
+pktopbm_pkbyte(void) {
+   pktopbm_pkloc++ ;
+   return(getc(pkfile)) ;
+}
+
+
+
+/* get a 16-bit half word from the PK file */
+static integer 
+get16(void) {
+   integer const a = pktopbm_pkbyte() ;
+   return((a<<8) + pktopbm_pkbyte()) ;
+}
+
+
+
+/* get a 32-bit word from the PK file */
+static integer get32(void) {
+    integer a;
+    a = get16() ;
+    if (a > 32767) a -= 65536 ;
+    return((a<<16) + get16()) ;
+}
+
+
+
+/* get a nibble from current input byte, or new byte if no current byte */
+static integer 
+getnyb(void) {
+    eightbits temp;
+    if (bitweight == 0) {
+        inputbyte = pktopbm_pkbyte() ;
+        bitweight = 16 ;
+    }
+    temp = inputbyte / bitweight ;
+    inputbyte -= temp * bitweight ;
+    bitweight >>= 4 ;
+    return(temp) ;
+}
+
+
+
+/* get a bit from the current input byte, or a new byte if no current byte */
+static bool
+getbit(void) {
+    bool temp ;
+    bitweight >>= 1 ;
+    if (bitweight == 0) {
+        inputbyte = pktopbm_pkbyte() ;
+        bitweight = 128 ;
+    }
+    temp = (inputbyte >= bitweight) ;
+    if (temp) inputbyte -= bitweight ;
+    return(temp) ;
+}
+
+
+
+/* unpack a dynamically packed number. dynf is dynamic packing threshold  */
+static integer 
+pkpackednum(void) {
+    integer i, j ;
+    i = getnyb() ;
+    if (i == 0) {           /* large run count, >= 3 nibbles */
+        do {
+            j = getnyb() ;          /* count extra nibbles */
+            i++ ;
+        } while (j == 0) ;
+        while (i > 0) {
+            j = (j<<4) + getnyb() ; /* add extra nibbles */
+            i-- ;
+        }
+        return (j - 15 +((13 - dynf)<<4) + dynf) ;
+    } else if (i <= dynf) return (i) ;  /* number > 0 and <= dynf */
+    else if (i < 14) return (((i - dynf - 1)<<4) + getnyb() + dynf + 1) ;
+    else {
+        if (i == 14) repeatcount = pkpackednum() ;  /* get repeat count */
+        else repeatcount = 1 ;      /* value 15 indicates repeat count 1 */
+        return(pkpackednum()) ;
+    }
+}
+
+
+
+/* skip specials in PK files, inserted by Metafont or some other program */
+static void
+skipspecials(void) {
+    integer i, j;
+    do {
+        flagbyte = pktopbm_pkbyte() ;
+        if (flagbyte >= 240)
+            switch(flagbyte) {
+            case 240:           /* specials of size 1-4 bytes */
+            case 241:
+            case 242:
+            case 243:
+                i = 0 ;
+                for (j = 240 ; j <= flagbyte ; ++j) 
+                    i = (i<<8) + pktopbm_pkbyte() ;
+                for (j = 1 ; j <= i ; ++j) 
+                    pktopbm_pkbyte() ;  /* ignore special */
+                break ;
+            case 244:           /* no-op, parameters to specials */
+                get32() ;
+            case 245:           /* start of postamble */
+            case 246:           /* no-op */
+                break ;
+            case 247:           /* pre-amble in wrong place */
+            case 248:
+            case 249:
+            case 250:
+            case 251:
+            case 252:
+            case 253:
+            case 254:
+            case 255:
+                pm_error("unexpected flag byte %d", flagbyte) ;
+            }
+    } while (!(flagbyte < 240 || flagbyte == 245)) ;
+}
+
+
+
+/* ignore character packet */
+static void
+ignorechar(integer const car, 
+           integer const endofpacket) {
+
+   while (pktopbm_pkloc != endofpacket) pktopbm_pkbyte() ;
+   if (car < 0 || car >= MAXPKCHAR)
+      pm_message("Character %d out of range", car) ;
+   skipspecials() ;
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+    integer x;
+    integer endofpacket ;
+    boolean turnon ;
+    integer i, j;
+    integer car ;
+    integer bmx=0, bmy=0;
+    integer set_bmx=0, set_bmy=0;
+    bit row[MAXROWWIDTH+1] ;
+    const char * const usage = 
+        "pkfile[.pk] [-d] [[-x width] [-y height] [-c num] pbmfile]...";
+   
+    pbm_init(&argc, argv);
+    for (i = 0 ; i < MAXPKCHAR ; i ++) filename[i] = NULL ;
+
+    pm_message("This is PKtoPBM, version 2.5") ;
+
+    if (--argc < 1) pm_usage(usage) ;
+
+    strcpy(pkname, *++argv) ;
+    pktopbm_add_suffix(pkname, ".pk") ;
+
+    car = 0 ;
+    /* urg: use getopt */
+    while (++argv, --argc) {
+        if (argv[0][0] == '-' && argv[0][1])
+            switch (argv[0][1]) {
+            case 'X':
+            case 'x':
+                if (argv[0][2]) bmx = atoi(*argv+2) ;
+                else if (++argv, --argc) set_bmx = atoi(*argv) ;
+                else pm_usage(usage) ;
+                continue ;
+            case 'Y':
+            case 'y':
+                if (argv[0][2]) bmy = atoi(*argv+2) ;
+                else if (++argv, --argc) set_bmy = atoi(*argv) ;
+                else pm_usage(usage) ;
+                continue ;
+            case 'C':
+            case 'c':
+                if (argv[0][2]) car = atoi(*argv+2) ;
+                else if (++argv, --argc) car = atoi(*argv) ;
+                else pm_usage(usage) ;
+                break ;
+            case 'd':
+                debug=1;
+                break ;
+            default:
+                pm_usage(usage) ;
+            } else if (car < 0 || car >= MAXPKCHAR) {
+                pm_error("character must be in range 0 to %d (-c)", 
+                         MAXPKCHAR-1) ;
+            } else filename[car++] = *argv ;
+    }
+
+    pkfile = pm_openr(pkname);
+    if (pktopbm_pkbyte() != 247)
+        pm_error("bad PK file (pre command missing)") ;
+    if (pktopbm_pkbyte() != 89)
+        pm_error("wrong version of packed file") ;
+    j = pktopbm_pkbyte() ;              /* get header comment size */
+    for (i = 1 ; i <= j ; i ++) pktopbm_pkbyte() ;  /* ignore header comment */
+    get32() ;                   /* ignore designsize */
+    get32() ;                   /* ignore checksum */
+    if (get32() != get32())         /* h & v pixels per point */
+        pm_message("Warning: aspect ratio not 1:1") ;
+    skipspecials() ;
+    while (flagbyte != 245) {           /* not at postamble */
+        integer cheight, cwidth ;
+        integer xoffs=0, yoffs=0;
+        FILE *ofp;
+
+        bmx=set_bmx;
+        bmy=set_bmy;
+        dynf = (flagbyte>>4) ;          /* get dynamic packing value */
+        flagbyte &= 15 ;
+        turnon = (flagbyte >= 8) ;      /* black or white initially? */
+        if (turnon) flagbyte &= 7 ;     /* long or short form */
+        if (flagbyte == 7) {            /* long form preamble */
+            integer packetlength = get32() ;    /* character packet length */
+            car = get32() ;         /* character number */
+            endofpacket = packetlength + pktopbm_pkloc;
+                /* calculate end of packet */
+            if ((car >= MAXPKCHAR) || !filename[car]) {
+                ignorechar(car, endofpacket);
+                continue;
+            }
+            dprintf0 ("flagbyte7\n");
+            dprintf ("car: %d\n", car);
+            get32() ;               /* ignore tfmwidth */
+            x=get32() ;             /* ignore horiz escapement */
+            x=get32() ;             /* ignore vert escapement */
+            dprintf ("horiz esc %d\n", x);
+            dprintf ("vert esc %d\n", x);
+            cwidth = get32() ;          /* bounding box width */
+            cheight = get32() ;         /* bounding box height */
+            dprintf ("cwidth %d\n", cwidth);
+            dprintf ("cheight %d\n", cheight);
+            if (cwidth < 0 || cheight < 0 || 
+                cwidth > 65535 || cheight > 65535) {
+                ignorechar(car, endofpacket);
+                continue;
+            }
+            xoffs= get32() ;              /* horiz offset */
+            yoffs= get32() ;              /* vert offset */
+            dprintf ("xoffs %d\n", xoffs);
+            dprintf ("yoffs %d\n", yoffs);
+        } else if (flagbyte > 3) {      /* extended short form */
+            integer packetlength = ((flagbyte - 4)<<16) + get16() ;
+            /* packet length */
+            car = pktopbm_pkbyte() ;            /* char number */
+            endofpacket = packetlength + pktopbm_pkloc ; 
+                /* calculate end of packet */
+            if ((car >= MAXPKCHAR) || !filename[car]) {
+                ignorechar(car, endofpacket);
+                continue;
+            }
+            dprintf0 ("flagbyte>3\n");
+            dprintf ("car: %d\n", car);
+            pktopbm_pkbyte() ;              /* ignore tfmwidth (3 bytes) */
+            get16() ;               /* ignore tfmwidth (3 bytes) */
+            get16() ;               /* ignore horiz escapement */
+            cwidth = get16() ;          /* bounding box width */
+            cheight = get16() ;         /* bounding box height */
+            dprintf ("cwidth %d\n", cwidth);
+            dprintf ("cheight %d\n", cheight);
+            xoffs=get16();                         /* horiz offset */
+            if (xoffs >= 32768)
+                xoffs-= 65536;
+            yoffs=get16();                         /* vert offset */
+            if (yoffs >= 32768)
+                yoffs-= 65536;
+            dprintf ("xoffs %d\n", xoffs);
+            dprintf ("yoffs %d\n", yoffs);
+        } else {                    /* short form preamble */
+            integer packetlength = (flagbyte<<8) + pktopbm_pkbyte() ;
+            /* packet length */
+            car = pktopbm_pkbyte() ;            /* char number */
+            endofpacket = packetlength + pktopbm_pkloc ;    
+                /* calculate end of packet */
+            if ((car >= MAXPKCHAR) || !filename[car]) {
+                ignorechar(car, endofpacket);
+                continue;
+            }
+            dprintf0 ("flagbyte<=3\n");
+            dprintf ("car: %d\n", car);
+            pktopbm_pkbyte() ;          /* ignore tfmwidth (3 bytes) */
+            get16() ;               /* ignore tfmwidth (3 bytes) */
+            x = pktopbm_pkbyte() ;  /* ignore horiz escapement */
+            dprintf ("horiz esc %d\n", x);
+            cwidth = pktopbm_pkbyte() ;            /* bounding box width */
+            cheight = pktopbm_pkbyte() ;           /* bounding box height */
+            dprintf ("cwidth %d\n", cwidth);
+            dprintf ("cheight %d\n", cheight);
+            xoffs=pktopbm_pkbyte ();               /* horiz offset */
+            if (xoffs >= 128)
+                xoffs-=256;
+            yoffs=pktopbm_pkbyte ();               /* vert offset */
+            if (yoffs >= 128)
+                yoffs-=256;
+            dprintf ("xoffs %d\n", xoffs);
+            dprintf ("yoffs %d\n", yoffs);
+        }
+        if (filename[car]) {
+            if (!bmx) bmx= cwidth;
+            if (!bmy) bmy= cheight;
+            bitmap = pbm_allocarray(bmx, bmy) ;
+            if (bitmap == NULL)
+                pm_error("out of memory allocating bitmap") ;
+        } else {
+            ignorechar(car, endofpacket);
+            continue;
+        }
+        bitweight = 0 ;
+        for (i = 0 ; i < bmy ; i ++)           /* make it blank */
+            for (j = 0 ; j < bmx ; j ++)
+                bitmap[i][j]= PBM_WHITE;
+        if (dynf == 14) {               /* bitmapped character */
+            dprintf ("bmy: %d\n ", bmy);
+            dprintf ("y: %d\n ", bmy-yoffs-1);
+            for (i = 0 ; i < cheight ; i ++) {
+                int yi= i+(bmy-yoffs-1);
+                for (j = 0 ; j < cwidth ; j ++) {
+                    int xj= j-xoffs;
+                    if (getbit() && 0<=xj && xj<bmx && 0<=yi && yi<bmy)
+                        bitmap[yi][xj] = PBM_BLACK ;
+                }
+            }
+        } else {                    /* dynamically packed char */
+            integer rowsleft = cheight ;
+            integer hbit = cwidth ;
+            integer rp = 0;
+            repeatcount = 0 ;
+            dprintf ("bmy: %d\n ", bmy);
+            dprintf ("y: %d\n", cheight-rowsleft+(bmy-2*yoffs-1));
+            while (rowsleft > 0) {
+                integer count = pkpackednum() ; /* get current color count */
+                while (count > 0) {
+                    if (count < hbit) {     /* doesn't extend past row */
+                        hbit -= count ;
+                        while (count--)
+                            row[rp++] = turnon ? PBM_BLACK : PBM_WHITE;
+                    } else {                /* reaches end of row */
+                        count -= hbit ;
+                        while (hbit--)
+                            row[rp++] = turnon ? PBM_BLACK : PBM_WHITE;
+                        for (i = 0; i <= repeatcount; i++) {  /* fill row */
+                            int yi= i+cheight-rowsleft-1;
+                            if (0<=yi && yi < bmy)
+                                for (j = 0; j < cwidth; j++) {
+                                    int xj= j-xoffs;
+                                    if (0<=xj && xj<bmx)
+                                        bitmap[yi][xj] = row[j] ;
+                                }
+                        }
+                        rowsleft -= repeatcount + 1;
+                        repeatcount = rp = 0 ;
+                        hbit = cwidth ;
+                    }
+                }
+                turnon = !turnon ;
+            }
+            if (rowsleft != 0 || hbit != cwidth)
+                pm_error("bad pk file (more bits than required)") ;
+        }
+        if (endofpacket != pktopbm_pkloc)
+            pm_error("bad pk file (bad packet length)") ;
+
+        ofp = pm_openw(filename[car]);
+        filename[car] = NULL;
+        pbm_writepbm(ofp, bitmap, bmx, bmy, 0) ;
+        pbm_freearray(bitmap, bmy) ;
+        pm_close(ofp) ;
+        skipspecials() ;
+    }
+    while (! feof(pkfile)) pktopbm_pkbyte() ;       /* skip trailing junk */
+    pm_close(pkfile);
+    for (car = 0; car < MAXPKCHAR; car++)
+        if (filename[car])
+            pm_message("Warning: No character in position %d (file %s).",
+                       car, filename[car]) ;
+    pm_message("%d bytes read from packed file.", pktopbm_pkloc-1) ;
+    return 0;
+}