diff options
Diffstat (limited to 'converter')
-rw-r--r-- | converter/pbm/g3.h | 297 | ||||
-rw-r--r-- | converter/pbm/g3topbm.c | 58 | ||||
-rw-r--r-- | converter/pbm/pbmtog3.c | 722 |
3 files changed, 769 insertions, 308 deletions
diff --git a/converter/pbm/g3.h b/converter/pbm/g3.h index e982f2da..42ba91c5 100644 --- a/converter/pbm/g3.h +++ b/converter/pbm/g3.h @@ -24,12 +24,30 @@ There is also the newer G4. */ -typedef struct g3TableEntry { - short int code; - short int length; -} g3TableEntry; +typedef struct G3TableEntry { + unsigned short int code; + unsigned short int length; +} G3TableEntry; -static struct g3TableEntry ttable[] = { + +struct BitString { + /* A string of bits, up to as many fit in 32 bits. */ + uint32_t intBuffer; + /* The bits are in the 'bitCount' least significant bit positions + of this number. The rest of the bits of this number are always + zero. + */ + unsigned int bitCount; + /* The length of the bit string */ + + /* Example: The bit string 010100 would be represented by + bitCount = 6, intBuffer = 20 + (N.B. 20 = 00000000 00000000 00000000 00010100 in binary) + */ +}; + + +static struct G3TableEntry ttable[] = { /* TERMWHITE TERMBLACK */ { 0x35, 8 }, { 0x37, 10 }, /* white 0 , black 0 */ { 0x07, 6 }, { 0x02, 3 }, @@ -143,4 +161,273 @@ static struct g3TableEntry ttable[] = { #define mtable ((ttable)+64*2) + +struct PrefabCode { + unsigned int leadBits; + unsigned int trailBits; + struct BitString activeBits; +}; + + +struct PrefabCode const prefabCode[256] = +{ +{ 0, 8, { 0x0000, 0}}, /* 000 */ +{ 7, 1, { 0x0000, 0}}, /* 001 */ +{ 6, 1, { 0x0002, 3}}, /* 002 */ +{ 6, 2, { 0x0000, 0}}, /* 003 */ +{ 5, 2, { 0x0002, 3}}, /* 004 */ +{ 5, 1, { 0x0087, 9}}, /* 005 */ +{ 5, 1, { 0x0003, 2}}, /* 006 */ +{ 5, 3, { 0x0000, 0}}, /* 007 */ +{ 4, 3, { 0x0002, 3}}, /* 008 */ +{ 4, 1, { 0x0027, 7}}, /* 009 */ +{ 4, 1, { 0x043a, 12}}, /* 010 */ +{ 4, 2, { 0x0087, 9}}, /* 011 */ +{ 4, 2, { 0x0003, 2}}, /* 012 */ +{ 4, 1, { 0x00c7, 8}}, /* 013 */ +{ 4, 1, { 0x0002, 2}}, /* 014 */ +{ 4, 4, { 0x0000, 0}}, /* 015 */ +{ 3, 4, { 0x0002, 3}}, /* 016 */ +{ 3, 1, { 0x0028, 7}}, /* 017 */ +{ 3, 1, { 0x013a, 10}}, /* 018 */ +{ 3, 2, { 0x0027, 7}}, /* 019 */ +{ 3, 2, { 0x043a, 12}}, /* 020 */ +{ 3, 1, { 0x10e87, 18}}, /* 021 */ +{ 3, 1, { 0x021f, 11}}, /* 022 */ +{ 3, 3, { 0x0087, 9}}, /* 023 */ +{ 3, 3, { 0x0003, 2}}, /* 024 */ +{ 3, 1, { 0x0037, 6}}, /* 025 */ +{ 3, 1, { 0x063a, 11}}, /* 026 */ +{ 3, 2, { 0x00c7, 8}}, /* 027 */ +{ 3, 2, { 0x0002, 2}}, /* 028 */ +{ 3, 1, { 0x0087, 8}}, /* 029 */ +{ 3, 1, { 0x0003, 3}}, /* 030 */ +{ 3, 5, { 0x0000, 0}}, /* 031 */ +{ 2, 5, { 0x0002, 3}}, /* 032 */ +{ 2, 1, { 0x002b, 7}}, /* 033 */ +{ 2, 1, { 0x0142, 10}}, /* 034 */ +{ 2, 2, { 0x0028, 7}}, /* 035 */ +{ 2, 2, { 0x013a, 10}}, /* 036 */ +{ 2, 1, { 0x4e87, 16}}, /* 037 */ +{ 2, 1, { 0x009f, 9}}, /* 038 */ +{ 2, 3, { 0x0027, 7}}, /* 039 */ +{ 2, 3, { 0x043a, 12}}, /* 040 */ +{ 2, 1, { 0x43a7, 16}}, /* 041 */ +{ 2, 1, { 0x8743a, 21}}, /* 042 */ +{ 2, 2, { 0x10e87, 18}}, /* 043 */ +{ 2, 2, { 0x021f, 11}}, /* 044 */ +{ 2, 1, { 0x87c7, 17}}, /* 045 */ +{ 2, 1, { 0x021e, 11}}, /* 046 */ +{ 2, 4, { 0x0087, 9}}, /* 047 */ +{ 2, 4, { 0x0003, 2}}, /* 048 */ +{ 2, 1, { 0x0038, 6}}, /* 049 */ +{ 2, 1, { 0x01ba, 9}}, /* 050 */ +{ 2, 2, { 0x0037, 6}}, /* 051 */ +{ 2, 2, { 0x063a, 11}}, /* 052 */ +{ 2, 1, { 0x18e87, 17}}, /* 053 */ +{ 2, 1, { 0x031f, 10}}, /* 054 */ +{ 2, 3, { 0x00c7, 8}}, /* 055 */ +{ 2, 3, { 0x0002, 2}}, /* 056 */ +{ 2, 1, { 0x0027, 6}}, /* 057 */ +{ 2, 1, { 0x043a, 11}}, /* 058 */ +{ 2, 2, { 0x0087, 8}}, /* 059 */ +{ 2, 2, { 0x0003, 3}}, /* 060 */ +{ 2, 1, { 0x00c7, 9}}, /* 061 */ +{ 2, 1, { 0x0003, 4}}, /* 062 */ +{ 2, 6, { 0x0000, 0}}, /* 063 */ +{ 1, 6, { 0x0002, 3}}, /* 064 */ +{ 1, 1, { 0x002c, 7}}, /* 065 */ +{ 1, 1, { 0x015a, 10}}, /* 066 */ +{ 1, 2, { 0x002b, 7}}, /* 067 */ +{ 1, 2, { 0x0142, 10}}, /* 068 */ +{ 1, 1, { 0x5087, 16}}, /* 069 */ +{ 1, 1, { 0x00a3, 9}}, /* 070 */ +{ 1, 3, { 0x0028, 7}}, /* 071 */ +{ 1, 3, { 0x013a, 10}}, /* 072 */ +{ 1, 1, { 0x13a7, 14}}, /* 073 */ +{ 1, 1, { 0x2743a, 19}}, /* 074 */ +{ 1, 2, { 0x4e87, 16}}, /* 075 */ +{ 1, 2, { 0x009f, 9}}, /* 076 */ +{ 1, 1, { 0x27c7, 15}}, /* 077 */ +{ 1, 1, { 0x009e, 9}}, /* 078 */ +{ 1, 4, { 0x0027, 7}}, /* 079 */ +{ 1, 4, { 0x043a, 12}}, /* 080 */ +{ 1, 1, { 0x43a8, 16}}, /* 081 */ +{ 1, 1, { 0x21d3a, 19}}, /* 082 */ +{ 1, 2, { 0x43a7, 16}}, /* 083 */ +{ 1, 2, { 0x8743a, 21}}, /* 084 */ +{ 1, 1, {0x21d0e87, 27}}, /* 085 */ +{ 1, 1, { 0x43a1f, 20}}, /* 086 */ +{ 1, 3, { 0x10e87, 18}}, /* 087 */ +{ 1, 3, { 0x021f, 11}}, /* 088 */ +{ 1, 1, { 0x21f7, 15}}, /* 089 */ +{ 1, 1, { 0x43e3a, 20}}, /* 090 */ +{ 1, 2, { 0x87c7, 17}}, /* 091 */ +{ 1, 2, { 0x021e, 11}}, /* 092 */ +{ 1, 1, { 0x8787, 17}}, /* 093 */ +{ 1, 1, { 0x043b, 12}}, /* 094 */ +{ 1, 5, { 0x0087, 9}}, /* 095 */ +{ 1, 5, { 0x0003, 2}}, /* 096 */ +{ 1, 1, { 0x003b, 6}}, /* 097 */ +{ 1, 1, { 0x01c2, 9}}, /* 098 */ +{ 1, 2, { 0x0038, 6}}, /* 099 */ +{ 1, 2, { 0x01ba, 9}}, /* 100 */ +{ 1, 1, { 0x6e87, 15}}, /* 101 */ +{ 1, 1, { 0x00df, 8}}, /* 102 */ +{ 1, 3, { 0x0037, 6}}, /* 103 */ +{ 1, 3, { 0x063a, 11}}, /* 104 */ +{ 1, 1, { 0x63a7, 15}}, /* 105 */ +{ 1, 1, { 0xc743a, 20}}, /* 106 */ +{ 1, 2, { 0x18e87, 17}}, /* 107 */ +{ 1, 2, { 0x031f, 10}}, /* 108 */ +{ 1, 1, { 0xc7c7, 16}}, /* 109 */ +{ 1, 1, { 0x031e, 10}}, /* 110 */ +{ 1, 4, { 0x00c7, 8}}, /* 111 */ +{ 1, 4, { 0x0002, 2}}, /* 112 */ +{ 1, 1, { 0x0028, 6}}, /* 113 */ +{ 1, 1, { 0x013a, 9}}, /* 114 */ +{ 1, 2, { 0x0027, 6}}, /* 115 */ +{ 1, 2, { 0x043a, 11}}, /* 116 */ +{ 1, 1, { 0x10e87, 17}}, /* 117 */ +{ 1, 1, { 0x021f, 10}}, /* 118 */ +{ 1, 3, { 0x0087, 8}}, /* 119 */ +{ 1, 3, { 0x0003, 3}}, /* 120 */ +{ 1, 1, { 0x0037, 7}}, /* 121 */ +{ 1, 1, { 0x063a, 12}}, /* 122 */ +{ 1, 2, { 0x00c7, 9}}, /* 123 */ +{ 1, 2, { 0x0003, 4}}, /* 124 */ +{ 1, 1, { 0x00c7, 10}}, /* 125 */ +{ 1, 1, { 0x0002, 4}}, /* 126 */ +{ 1, 7, { 0x0000, 0}}, /* 127 */ +{ 1, 7, { 0x0000, 0}}, /* 128 */ +{ 1, 1, { 0x000e, 4}}, /* 129 */ +{ 1, 1, { 0x0062, 7}}, /* 130 */ +{ 1, 2, { 0x000c, 4}}, /* 131 */ +{ 1, 2, { 0x005a, 7}}, /* 132 */ +{ 1, 1, { 0x1687, 13}}, /* 133 */ +{ 1, 1, { 0x002f, 6}}, /* 134 */ +{ 1, 3, { 0x000b, 4}}, /* 135 */ +{ 1, 3, { 0x0042, 7}}, /* 136 */ +{ 1, 1, { 0x0427, 11}}, /* 137 */ +{ 1, 1, { 0x843a, 16}}, /* 138 */ +{ 1, 2, { 0x1087, 13}}, /* 139 */ +{ 1, 2, { 0x0023, 6}}, /* 140 */ +{ 1, 1, { 0x08c7, 12}}, /* 141 */ +{ 1, 1, { 0x0022, 6}}, /* 142 */ +{ 1, 4, { 0x0008, 4}}, /* 143 */ +{ 1, 4, { 0x003a, 7}}, /* 144 */ +{ 1, 1, { 0x03a8, 11}}, /* 145 */ +{ 1, 1, { 0x1d3a, 14}}, /* 146 */ +{ 1, 2, { 0x03a7, 11}}, /* 147 */ +{ 1, 2, { 0x743a, 16}}, /* 148 */ +{ 1, 1, { 0x1d0e87, 22}}, /* 149 */ +{ 1, 1, { 0x3a1f, 15}}, /* 150 */ +{ 1, 3, { 0x0e87, 13}}, /* 151 */ +{ 1, 3, { 0x001f, 6}}, /* 152 */ +{ 1, 1, { 0x01f7, 10}}, /* 153 */ +{ 1, 1, { 0x3e3a, 15}}, /* 154 */ +{ 1, 2, { 0x07c7, 12}}, /* 155 */ +{ 1, 2, { 0x001e, 6}}, /* 156 */ +{ 1, 1, { 0x0787, 12}}, /* 157 */ +{ 1, 1, { 0x003b, 7}}, /* 158 */ +{ 1, 5, { 0x0007, 4}}, /* 159 */ +{ 1, 5, { 0x003a, 9}}, /* 160 */ +{ 1, 1, { 0x03ab, 13}}, /* 161 */ +{ 1, 1, { 0x1d42, 16}}, /* 162 */ +{ 1, 2, { 0x03a8, 13}}, /* 163 */ +{ 1, 2, { 0x1d3a, 16}}, /* 164 */ +{ 1, 1, { 0x74e87, 22}}, /* 165 */ +{ 1, 1, { 0x0e9f, 15}}, /* 166 */ +{ 1, 3, { 0x03a7, 13}}, /* 167 */ +{ 1, 3, { 0x743a, 18}}, /* 168 */ +{ 1, 1, { 0x743a7, 22}}, /* 169 */ +{ 1, 1, { 0xe8743a, 27}}, /* 170 */ +{ 1, 2, { 0x1d0e87, 24}}, /* 171 */ +{ 1, 2, { 0x3a1f, 17}}, /* 172 */ +{ 1, 1, { 0xe87c7, 23}}, /* 173 */ +{ 1, 1, { 0x3a1e, 17}}, /* 174 */ +{ 1, 4, { 0x0e87, 15}}, /* 175 */ +{ 1, 4, { 0x001f, 8}}, /* 176 */ +{ 1, 1, { 0x01f8, 12}}, /* 177 */ +{ 1, 1, { 0x0fba, 15}}, /* 178 */ +{ 1, 2, { 0x01f7, 12}}, /* 179 */ +{ 1, 2, { 0x3e3a, 17}}, /* 180 */ +{ 1, 1, { 0xf8e87, 23}}, /* 181 */ +{ 1, 1, { 0x1f1f, 16}}, /* 182 */ +{ 1, 3, { 0x07c7, 14}}, /* 183 */ +{ 1, 3, { 0x001e, 8}}, /* 184 */ +{ 1, 1, { 0x01e7, 12}}, /* 185 */ +{ 1, 1, { 0x3c3a, 17}}, /* 186 */ +{ 1, 2, { 0x0787, 14}}, /* 187 */ +{ 1, 2, { 0x003b, 9}}, /* 188 */ +{ 1, 1, { 0x0ec7, 15}}, /* 189 */ +{ 1, 1, { 0x0073, 10}}, /* 190 */ +{ 1, 6, { 0x0007, 6}}, /* 191 */ +{ 2, 6, { 0x0000, 0}}, /* 192 */ +{ 2, 1, { 0x000c, 4}}, /* 193 */ +{ 2, 1, { 0x005a, 7}}, /* 194 */ +{ 2, 2, { 0x000b, 4}}, /* 195 */ +{ 2, 2, { 0x0042, 7}}, /* 196 */ +{ 2, 1, { 0x1087, 13}}, /* 197 */ +{ 2, 1, { 0x0023, 6}}, /* 198 */ +{ 2, 3, { 0x0008, 4}}, /* 199 */ +{ 2, 3, { 0x003a, 7}}, /* 200 */ +{ 2, 1, { 0x03a7, 11}}, /* 201 */ +{ 2, 1, { 0x743a, 16}}, /* 202 */ +{ 2, 2, { 0x0e87, 13}}, /* 203 */ +{ 2, 2, { 0x001f, 6}}, /* 204 */ +{ 2, 1, { 0x07c7, 12}}, /* 205 */ +{ 2, 1, { 0x001e, 6}}, /* 206 */ +{ 2, 4, { 0x0007, 4}}, /* 207 */ +{ 2, 4, { 0x003a, 9}}, /* 208 */ +{ 2, 1, { 0x03a8, 13}}, /* 209 */ +{ 2, 1, { 0x1d3a, 16}}, /* 210 */ +{ 2, 2, { 0x03a7, 13}}, /* 211 */ +{ 2, 2, { 0x743a, 18}}, /* 212 */ +{ 2, 1, { 0x1d0e87, 24}}, /* 213 */ +{ 2, 1, { 0x3a1f, 17}}, /* 214 */ +{ 2, 3, { 0x0e87, 15}}, /* 215 */ +{ 2, 3, { 0x001f, 8}}, /* 216 */ +{ 2, 1, { 0x01f7, 12}}, /* 217 */ +{ 2, 1, { 0x3e3a, 17}}, /* 218 */ +{ 2, 2, { 0x07c7, 14}}, /* 219 */ +{ 2, 2, { 0x001e, 8}}, /* 220 */ +{ 2, 1, { 0x0787, 14}}, /* 221 */ +{ 2, 1, { 0x003b, 9}}, /* 222 */ +{ 2, 5, { 0x0007, 6}}, /* 223 */ +{ 3, 5, { 0x0000, 0}}, /* 224 */ +{ 3, 1, { 0x000b, 4}}, /* 225 */ +{ 3, 1, { 0x0042, 7}}, /* 226 */ +{ 3, 2, { 0x0008, 4}}, /* 227 */ +{ 3, 2, { 0x003a, 7}}, /* 228 */ +{ 3, 1, { 0x0e87, 13}}, /* 229 */ +{ 3, 1, { 0x001f, 6}}, /* 230 */ +{ 3, 3, { 0x0007, 4}}, /* 231 */ +{ 3, 3, { 0x003a, 9}}, /* 232 */ +{ 3, 1, { 0x03a7, 13}}, /* 233 */ +{ 3, 1, { 0x743a, 18}}, /* 234 */ +{ 3, 2, { 0x0e87, 15}}, /* 235 */ +{ 3, 2, { 0x001f, 8}}, /* 236 */ +{ 3, 1, { 0x07c7, 14}}, /* 237 */ +{ 3, 1, { 0x001e, 8}}, /* 238 */ +{ 3, 4, { 0x0007, 6}}, /* 239 */ +{ 4, 4, { 0x0000, 0}}, /* 240 */ +{ 4, 1, { 0x0008, 4}}, /* 241 */ +{ 4, 1, { 0x003a, 7}}, /* 242 */ +{ 4, 2, { 0x0007, 4}}, /* 243 */ +{ 4, 2, { 0x003a, 9}}, /* 244 */ +{ 4, 1, { 0x0e87, 15}}, /* 245 */ +{ 4, 1, { 0x001f, 8}}, /* 246 */ +{ 4, 3, { 0x0007, 6}}, /* 247 */ +{ 5, 3, { 0x0000, 0}}, /* 248 */ +{ 5, 1, { 0x0007, 4}}, /* 249 */ +{ 5, 1, { 0x003a, 9}}, /* 250 */ +{ 5, 2, { 0x0007, 6}}, /* 251 */ +{ 6, 2, { 0x0000, 0}}, /* 252 */ +{ 6, 1, { 0x0007, 6}}, /* 253 */ +{ 7, 1, { 0x0000, 0}}, /* 254 */ +{ 0, 8, { 0x0000, 0}}, /* 255 */ + }; + #endif + diff --git a/converter/pbm/g3topbm.c b/converter/pbm/g3topbm.c index 83479b91..f50339fd 100644 --- a/converter/pbm/g3topbm.c +++ b/converter/pbm/g3topbm.c @@ -44,11 +44,11 @@ #define HASHSIZE 1021 -static g3TableEntry * whash[HASHSIZE]; -static g3TableEntry * bhash[HASHSIZE]; +static G3TableEntry * whash[HASHSIZE]; +static G3TableEntry * bhash[HASHSIZE]; -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -63,8 +63,8 @@ struct cmdlineInfo { static void -parseCommandLine(int argc, char ** const argv, - struct cmdlineInfo * const cmdlineP) { +parseCommandLine(int argc, const char ** const argv, + struct 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. @@ -98,7 +98,7 @@ parseCommandLine(int argc, char ** const argv, opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ - pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char**)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (widthSpec && paper_sizeSpec) @@ -136,7 +136,7 @@ parseCommandLine(int argc, char ** const argv, -struct bitStream { +struct BitStream { FILE * fileP; bool reversebits; @@ -156,7 +156,7 @@ struct bitStream { static void -readBit(struct bitStream * const bitStreamP, +readBit(struct BitStream * const bitStreamP, unsigned int * const bitP, const char ** const errorP) { /*---------------------------------------------------------------------------- @@ -189,7 +189,7 @@ readBit(struct bitStream * const bitStreamP, static void -readBitAndDetectEol(struct bitStream * const bitStreamP, +readBitAndDetectEol(struct BitStream * const bitStreamP, unsigned int * const bitP, bool * const eolP, const char ** const errorP) { @@ -217,7 +217,7 @@ readBitAndDetectEol(struct bitStream * const bitStreamP, static void -initBitStream(struct bitStream * const bitStreamP, +initBitStream(struct BitStream * const bitStreamP, FILE * const fileP, bool const reversebits) { @@ -230,7 +230,7 @@ initBitStream(struct bitStream * const bitStreamP, static void -skipToNextLine(struct bitStream * const bitStreamP) { +skipToNextLine(struct BitStream * const bitStreamP) { bool eol; const char * error; @@ -248,8 +248,8 @@ skipToNextLine(struct bitStream * const bitStreamP) { static void -addtohash(g3TableEntry * hash[], - g3TableEntry table[], +addtohash(G3TableEntry * hash[], + G3TableEntry table[], unsigned int const n, int const a, int const b) { @@ -257,7 +257,7 @@ addtohash(g3TableEntry * hash[], unsigned int i; for (i = 0; i < n; ++i) { - g3TableEntry * const teP = &table[i*2]; + G3TableEntry * const teP = &table[i*2]; unsigned int const pos = ((teP->length + a) * (teP->code + b)) % HASHSIZE; if (hash[pos]) @@ -268,15 +268,15 @@ addtohash(g3TableEntry * hash[], -static g3TableEntry * -hashfind(g3TableEntry * hash[], +static G3TableEntry * +hashfind(G3TableEntry * hash[], int const length, int const code, int const a, int const b) { unsigned int pos; - g3TableEntry * te; + G3TableEntry * te; pos = ((length + a) * (code + b)) % HASHSIZE; te = hash[pos]; @@ -286,8 +286,8 @@ hashfind(g3TableEntry * hash[], static void -buildHashes(g3TableEntry * (*whashP)[HASHSIZE], - g3TableEntry * (*bhashP)[HASHSIZE]) { +buildHashes(G3TableEntry * (*whashP)[HASHSIZE], + G3TableEntry * (*bhashP)[HASHSIZE]) { unsigned int i; @@ -315,7 +315,7 @@ makeRowWhite(unsigned char * const packedBitrow, -static g3TableEntry * +static G3TableEntry * g3code(unsigned int const curcode, unsigned int const curlen, bit const color) { @@ -326,7 +326,7 @@ g3code(unsigned int const curcode, Note that it is the _position_ in the table that determines the meaning of the code. The contents of the table entry do not. -----------------------------------------------------------------------------*/ - g3TableEntry * retval; + G3TableEntry * retval; switch (color) { case PBM_WHITE: @@ -383,7 +383,7 @@ writeBlackBitSpan(unsigned char * const packedBitrow, enum g3tableId {TERMWHITE, TERMBLACK, MKUPWHITE, MKUPBLACK}; static void -processG3Code(const g3TableEntry * const teP, +processG3Code(const G3TableEntry * const teP, unsigned char * const packedBitrow, unsigned int * const colP, bit * const colorP, @@ -452,7 +452,7 @@ formatBadCodeException(const char ** const exceptionP, static void -readFaxRow(struct bitStream * const bitStreamP, +readFaxRow(struct BitStream * const bitStreamP, unsigned char * const packedBitrow, unsigned int * const lineLengthP, const char ** const exceptionP, @@ -526,7 +526,7 @@ readFaxRow(struct bitStream * const bitStreamP, formatBadCodeException(exceptionP, col, curlen, curcode); done = TRUE; } else if (curcode != 0) { - const g3TableEntry * const teP = + const G3TableEntry * const teP = g3code(curcode, curlen, currentColor); /* Address of structure that describes the current G3 code. Null means 'curcode' isn't @@ -680,7 +680,7 @@ analyzeLineSize(lineSizeAnalyzer * const analyzerP, */ static void -readFax(struct bitStream * const bitStreamP, +readFax(struct BitStream * const bitStreamP, bool const stretch, unsigned int const expectedLineSize, bool const tolerateErrors, @@ -747,16 +747,16 @@ readFax(struct bitStream * const bitStreamP, int -main(int argc, char * argv[]) { +main(int argc, const char * argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE * ifP; - struct bitStream bitStream; + struct BitStream bitStream; unsigned int rows, cols; unsigned char ** packedBits; int row; - pbm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); diff --git a/converter/pbm/pbmtog3.c b/converter/pbm/pbmtog3.c index f0fd1252..4f19ec2f 100644 --- a/converter/pbm/pbmtog3.c +++ b/converter/pbm/pbmtog3.c @@ -1,84 +1,59 @@ /* pbmtog3.c - read a PBM image and produce a Group 3 FAX file -** -** Copyright (C) 1989 by Paul Haeberli <paul@manray.sgi.com>. -** -** 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. -*/ -/* - For specifications for Group 3 (G3) fax MH coding see ITU-T T.4 - This program generates only MH. It is coded with future expansion for - MR and MMR in mind. + For specifications for Group 3 (G3) fax MH coding see ITU-T T.4: + Standardization of Group 3 facsimile terminals for document transmission + https://www.itu.int/rec/T-REC-T.4/en + + This program generates only MH. */ + #include <assert.h> #include "pm_c_util.h" #include "shhopt.h" #include "mallocvar.h" #include "bitreverse.h" -#include "wordaccess.h" -#include "wordintclz.h" +#include "intcode.h" #include "g3.h" #include "pbm.h" -#define TC_MC 64 +enum G3eol {EOL, ALIGN8, ALIGN16, NO_EOL, NO_RTC, NO_EOLRTC}; -static bool const pbmtorl = -#ifdef PBMTORL - TRUE; -#else - FALSE; -#endif +enum OutMode {BINARY, DUMP}; +struct OutStream; -struct bitString { - /* A string of bits, up to as many fit in a word. */ - unsigned int bitCount; - /* The length of the bit string */ - wordint intBuffer; - /* The bits are in the 'bitCount' least significant bit positions - of this number. The rest of the bits of this number are always - zero. - */ +typedef void PutbitsFn(struct OutStream * const outP, + struct BitString const newBits); - /* Example: The bit string 010100, on a machine with a 32 bit word, - would be represented by bitCount = 6, intBuffer = 20 - (N.B. 20 = 00000000 00000000 00000000 00010100 in binary) - */ +struct OutStream { + FILE * fp; + struct BitString buffer; + bool reverseBits; /* Reverse bit order */ + PutbitsFn * putbitsFn; + enum G3eol eolAlign; /* Omit EOL and/or RTC; align EOL to 8/16 bits */ + void * data; /* Reserved for future expansion */ }; -struct outStream { - struct bitString buffer; - - bool reverseBits; -}; - -/* This is a global variable for speed. */ -static struct outStream out; - - struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ const char * inputFileName; unsigned int reversebits; - unsigned int nofixedwidth; + enum G3eol align; + unsigned int dump; + unsigned int desiredWidth; unsigned int verbose; }; static void -parseCommandLine(int argc, char ** const argv, +parseCommandLine(int argc, const char ** const argv, struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that @@ -87,6 +62,8 @@ parseCommandLine(int argc, char ** const argv, optEntry * option_def; /* Instructions to OptParseOptions2 on how to parse our options. */ optStruct3 opt; + unsigned int nofixedwidth; + unsigned int align8, align16; unsigned int option_def_index; @@ -95,24 +72,45 @@ parseCommandLine(int argc, char ** const argv, option_def_index = 0; /* incremented by OPTENTRY */ OPTENT3(0, "reversebits", OPT_FLAG, NULL, &cmdlineP->reversebits, 0); - OPTENT3(0, "nofixedwidth", OPT_FLAG, NULL, &cmdlineP->nofixedwidth, + OPTENT3(0, "nofixedwidth", OPT_FLAG, NULL, &nofixedwidth, + 0); + OPTENT3(0, "align8", OPT_FLAG, NULL, &align8, + 0); + OPTENT3(0, "align16", OPT_FLAG, NULL, &align16, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); + OPTENT3(0, "dump", OPT_FLAG, NULL, &cmdlineP->dump, + 0); /* TODO Explicit fixed widths: -A4 -B4 -A3 */ opt.opt_table = option_def; - opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ - opt.allowNegNum = TRUE; /* We may have parms that are negative numbers */ + opt.short_allowed = false; /* We have no short (old-fashioned) options */ + opt.allowNegNum = true; /* We may have parms that are negative numbers */ - pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ free(option_def); + if (align8) { + if (align16) + pm_error("You can't specify both -align8 and -align16"); + else + cmdlineP->align = ALIGN8; + } else if (align16) + cmdlineP->align = ALIGN16; + else + cmdlineP->align = EOL; + + if (nofixedwidth) + cmdlineP->desiredWidth = 0; + else + cmdlineP->desiredWidth = 1728; + if (argc-1 == 0) cmdlineP->inputFileName = "-"; else if (argc-1 != 1) @@ -129,27 +127,74 @@ reversebuffer(unsigned char * const p, unsigned int const n) { unsigned int i; + for (i = 0; i < n; ++i) p[i] = bitreverse[p[i]]; } -static struct bitString -makeBs(wordint const bits, - unsigned int const bitCount) { +static void +flushBuffer(struct OutStream * const outP) { +/*---------------------------------------------------------------------------- + Flush the contents of the bit buffer +-----------------------------------------------------------------------------*/ + struct BitString const buffer = outP->buffer; - struct bitString retval; - retval.intBuffer = bits; - retval.bitCount = bitCount; + assert (buffer.bitCount <= 32); - return retval; + if (buffer.bitCount > 0) { + unsigned int const fullBuffer = sizeof(buffer.intBuffer) * 8; + unsigned int const bytesToWrite = (buffer.bitCount+7)/8; + bigend32 outbytes; + size_t rc; + + outbytes = pm_bigendFromUint32( + buffer.intBuffer << (fullBuffer - buffer.bitCount)); + if (outP->reverseBits) + reversebuffer((unsigned char *)&outbytes, bytesToWrite); + rc = fwrite((unsigned char *)&outbytes, 1, bytesToWrite, outP->fp); + if (rc != bytesToWrite) + pm_error("Output error"); + } } -static __inline__ void -putbits(struct bitString const newBits) { +static PutbitsFn putbitsDump; + +static void +putbitsDump(struct OutStream * const outP, + struct BitString const newBits) { +/*---------------------------------------------------------------------------- + Print the content of the bit put request, in human readable text form + For debugging. Also good for studying how the coding scheme works. +-----------------------------------------------------------------------------*/ + unsigned int const bitCount = newBits.bitCount; + + unsigned int i; + char charBuff[128]; + + assert (bitCount >= 0 && bitCount < 32); + assert (sizeof(newBits.intBuffer) + 2 < 128); + + for (i = 0; i < bitCount; ++i) { + unsigned int const n = bitCount - i - 1; + charBuff[i] = ((newBits.intBuffer >> n) & 0x01) + '0'; + } + + charBuff[bitCount] = '\n'; + charBuff[bitCount+1] = '\0'; + fwrite(charBuff, 1, bitCount+1, outP->fp); +} + + + +static PutbitsFn putbitsDump; + +static void +putbitsBinary(struct OutStream * const outP, + struct BitString const newBits) { /*---------------------------------------------------------------------------- Push the bits 'newBits' onto the right end of output buffer out.buffer (moving the bits already in the buffer left). @@ -158,334 +203,463 @@ putbits(struct bitString const newBits) { 'newBits' must be shorter than a whole word. - N.B. the definition of struct bitString requires upper bits to be zero. + N.B. the definition of struct BitString requires upper bits to be zero. -----------------------------------------------------------------------------*/ - unsigned int const spaceLeft = - sizeof(out.buffer.intBuffer)*8 - out.buffer.bitCount; + unsigned int const fullBuffer = sizeof(outP->buffer.intBuffer) * 8; + unsigned int const spaceLeft = fullBuffer - outP->buffer.bitCount; /* Number of bits of unused space (at the high end) in buffer */ - assert(newBits.bitCount < sizeof(out.buffer.intBuffer) * 8); + assert(newBits.bitCount < fullBuffer); assert(newBits.intBuffer >> newBits.bitCount == 0); if (spaceLeft > newBits.bitCount) { /* New bits fit with bits to spare */ - out.buffer.intBuffer = - out.buffer.intBuffer << newBits.bitCount | newBits.intBuffer; - out.buffer.bitCount += newBits.bitCount; + outP->buffer.intBuffer = + outP->buffer.intBuffer << newBits.bitCount | newBits.intBuffer; + outP->buffer.bitCount += newBits.bitCount; } else { /* New bits fill buffer. We'll have to flush the buffer to stdout and put the rest of the bits in the new buffer. */ unsigned int const nextBufBitCount = newBits.bitCount - spaceLeft; + unsigned int const bitMask = ((1<<nextBufBitCount) - 1); - wordintBytes outbytes; - size_t rc; - - wordintToBytes(&outbytes, - (out.buffer.intBuffer << spaceLeft) - | (newBits.intBuffer >> nextBufBitCount)); - if (out.reverseBits) - reversebuffer(outbytes, sizeof(outbytes)); + outP->buffer.intBuffer = ( (outP->buffer.intBuffer << spaceLeft) + | (newBits.intBuffer >> nextBufBitCount)); + outP->buffer.bitCount = fullBuffer; + flushBuffer(outP); - rc = fwrite(outbytes, 1, sizeof(outbytes), stdout); - if (rc != sizeof(outbytes)) - pm_error("Output error. Unable to fwrite() to stdout"); - - out.buffer.intBuffer = newBits.intBuffer & ((1<<nextBufBitCount) - 1); - out.buffer.bitCount = nextBufBitCount; + outP->buffer.intBuffer = newBits.intBuffer & bitMask; + outP->buffer.bitCount = nextBufBitCount; } } static void -initOutStream(bool const reverseBits) { - out.buffer.intBuffer = 0; - out.buffer.bitCount = 0; - out.reverseBits = reverseBits; +initOutStream(struct OutStream * const outP, + bool const reverseBits, + enum G3eol const eolAlign, + bool const wantDump) { + + outP->buffer.intBuffer = 0; + outP->buffer.bitCount = 0; + outP->reverseBits = reverseBits; + outP->putbitsFn = wantDump ? &putbitsDump : &putbitsBinary; + outP->fp = wantDump ? stderr : stdout; + outP->eolAlign = eolAlign; +} + + + +static struct BitString +tableEntryToBitString(G3TableEntry const tableEntry) { + + struct BitString retval; + + retval.intBuffer = tableEntry.code; + retval.bitCount = tableEntry.length; + + return retval; } -static __inline__ void -putcode(unsigned int const clr, - unsigned int const ix) { +static void +putbits(struct OutStream * const outP, + struct BitString const newBits) { + + outP->putbitsFn(outP, newBits); +} + + + +static void +putcodeShort(struct OutStream * const outP, + bit const color, + unsigned int const runLength) { /* Note that this requires ttable to be aligned white entry, black - entry, white, black, etc. + entry, white, black, etc. */ - putbits(makeBs(ttable[ix * 2 + clr].code, ttable[ix * 2 + clr].length)); + unsigned int index = runLength * 2 + color; + putbits(outP, tableEntryToBitString(ttable[index])); } -static __inline__ void -putcode2(int const clr, - int const ix) { +static void +putcodeLong(struct OutStream * const outP, + bit const color, + unsigned int const runLength) { /*---------------------------------------------------------------------------- Output Make-up code and Terminating code at once. - For run lengths above TC_MC threshold (usually 64). + For run lengths which require both: length 64 and above The codes are combined here to avoid calculations in putbits() - wordint is usually wide enough, with 32 or 64 bits. - Provisions are made for 16 bit wordint (for debugging). Terminating code is max 12 bits, Make-up code is max 13 bits. - (See ttable, mtable entries in pbmtog3.h) + (See ttable, mtable entries in pbmtog3.h) Also reduces object code size when putcode is compiled inline. -----------------------------------------------------------------------------*/ - unsigned int const loIndex = ix % 64 * 2 + clr; - unsigned int const hiIndex = ix / 64 * 2 + clr; - - if (sizeof(wordint) * 8 > 24) { - unsigned int const l1 = ttable[loIndex].length; - - putbits( - makeBs(mtable[hiIndex].code << l1 | ttable[loIndex].code, - mtable[hiIndex].length + l1) - ); - } else { /* typically 16 bit wordint used for debugging */ - putbits(makeBs(mtable[hiIndex].code, mtable[hiIndex].length)); - putbits(makeBs(ttable[loIndex].code, ttable[loIndex].length)); - } + unsigned int const loIndex = runLength % 64 * 2 + color; + unsigned int const hiIndex = runLength / 64 * 2 + color; + unsigned int const loLength = ttable[loIndex].length; + unsigned int const hiLength = mtable[hiIndex].length; + + struct BitString combinedCode; + + combinedCode.intBuffer = mtable[hiIndex].code << loLength | + ttable[loIndex].code; + combinedCode.bitCount = hiLength + loLength; + + putbits(outP, combinedCode); } -static __inline__ void -putspan_normal(bit const color, - unsigned int const len) { +static void +putcodeExtra(struct OutStream * const outP, + int const color, + int const runLength) { +/*---------------------------------------------------------------------------- + Lengths over 2560. This is rare. + According to the standard, the mark-up code for 2560 can be issued as + many times as necessary without terminal codes. + --------------------------------------------------------------------------*/ + G3TableEntry const markUp2560 = mtable[2560/64]; + /* Same code for black and white */ - if (len < TC_MC) - putcode(color, len); - else if (len < 2624) - putcode2(color, len); - else { /* len >= 2624 : rare */ - unsigned int remainingLen; + unsigned int remainingLen; - for (remainingLen = len; - remainingLen >= 2624; - remainingLen -= 2623) { + for (remainingLen = runLength; remainingLen > 2560; remainingLen -= 2560) + putbits(outP, tableEntryToBitString(markUp2560)); + /* after the above: 0 < remainingLen <= 2560 */ - putcode2(color, 2560+63); - putcode(!color, 0); - } - if (remainingLen < TC_MC) - putcode(color, remainingLen); - else /* TC_MC <= len < 2624 */ - putcode2(color, remainingLen); - } + if (remainingLen >= 64) + putcodeLong(outP, color, remainingLen); + else + putcodeShort(outP, color, remainingLen); } -static __inline__ void -putspan(bit const color, - unsigned int const len) { -/*---------------------------------------------------------------------------- - Put a span of 'len' pixels of color 'color' in the output. ------------------------------------------------------------------------------*/ - if (pbmtorl) { - if (len > 0) - printf("%c %d\n", color == PBM_WHITE ? 'W' : 'B', len); - } else - putspan_normal(color, len); +static void +putspan(struct OutStream * const outP, + bit const color, + unsigned int const runLength) { + + if (runLength < 64) + putcodeShort(outP, color, runLength); + else if (runLength < 2560) + putcodeLong (outP, color, runLength); + else /* runLength > 2560 : rare */ + putcodeExtra(outP, color, runLength); } static void -puteol(void) { +puteol(struct OutStream * const outP) { + + switch (outP->eolAlign) { + case EOL: { + struct BitString const eol = { 1, 12 }; + + putbits(outP, eol); + } break; + case ALIGN8: case ALIGN16: { + unsigned int const bitCount = outP->buffer.bitCount; + unsigned int const fillbits = + (outP->eolAlign == ALIGN8) ? (44 - bitCount) % 8 + : (52 - bitCount) % 16; + + struct BitString eol; + + eol.bitCount = 12 + fillbits; eol.intBuffer = 1; + putbits(outP, eol); + } break; + case NO_EOL: case NO_EOLRTC: + break; + case NO_RTC: + pm_error("INTERNAL ERROR: no-RTC EOL treatment not implemented"); + break; + } +} - if (pbmtorl) - puts("EOL"); - else { - struct bitString const eol = {12, 1}; - putbits(eol); + +static void +putrtc(struct OutStream * const outP) { + + switch (outP->eolAlign) { + case NO_RTC: case NO_EOLRTC: + break; + default: + puteol(outP); puteol(outP); puteol(outP); + puteol(outP); puteol(outP); puteol(outP); } } -/* - PBM raw bitrow to inflection point array +static void +readOffSideMargins(unsigned char * const bitrow, + unsigned int const colChars, + unsigned int * const firstNonWhiteCharP, + unsigned int * const lastNonWhiteCharP, + bool * const blankRowP) { +/*---------------------------------------------------------------------------- + Determine the white margins on the left and right side of a row. + This is an enhancement: convertRowToG3() works without this. +-----------------------------------------------------------------------------*/ + unsigned int charCnt; + unsigned int firstChar; + unsigned int lastChar; + bool blankRow; + + assert(colChars > 0); - Write inflection (=color change) points into array milepost[]. - It is easy to calculate run length from this. + for (charCnt = 0; charCnt < colChars && bitrow[charCnt] == 0; ++charCnt); - In milepost, a white-to-black (black-to-white) inflection point - always has an even (odd) index. A line starting with black is - indicated by bitrow[0] == 0. + if (charCnt >= colChars) { + /* Reached end of bitrow with no black pixels encountered */ + firstChar = lastChar = 0; + blankRow = true; + } else { + /* There is at least one black pixel in the row */ + firstChar = charCnt; + blankRow = false; - WWWWWWWBBWWWWWWW ... = 7,2,7, ... - BBBBBWBBBBBWBBBB ... = 0,5,1,5,1,4, ... + charCnt = colChars - 1; - Return the number of milepost elements written. - Note that max number of entries into milepost = cols+1 . + while (bitrow[charCnt--] == 0x00) + ; + lastChar = charCnt + 1; + } - The inflection points are calculated like this: + *firstNonWhiteCharP = firstChar; + *lastNonWhiteCharP = lastChar; + *blankRowP = blankRow; +} - r1: 00000000000111111110011111000000 - r2: c0000000000011111111001111100000 0->carry - xor: ?0000000000100000001010000100000 - The 1 bits in the xor above are the inflection points. -*/ -static __inline__ void -convertRowToRunLengths(unsigned char * const bitrow, - int const cols, - unsigned int * const milepost, - unsigned int * const lengthP) { - - unsigned int const bitsPerWord = sizeof(wordint) * 8; - wordint * const bitrowByWord = (wordint *) bitrow; - int const wordCount = (cols + bitsPerWord - 1)/bitsPerWord; - /* Number of full and partial words in the row */ - - - if (cols % bitsPerWord != 0) { - /* Clean final word in row. For loop simplicity */ - wordint r1; - r1 = bytesToWordint((unsigned char *)&bitrowByWord[wordCount - 1]); - r1 >>= bitsPerWord - cols % bitsPerWord; - r1 <<= bitsPerWord - cols % bitsPerWord; - wordintToBytes((wordintBytes *)&bitrowByWord[wordCount - 1], r1); +static void +setBlockBitsInFinalChar(unsigned char * const finalByteP, + unsigned int const cols) { +/*---------------------------------------------------------------------------- + If the char in the row is fractional, set it up so that the don't care + bits are the opposite color of the last valid pixel. +----------------------------------------------------------------------------*/ + unsigned char const finalByte = *finalByteP; + unsigned int const silentBitCnt = 8 - cols % 8; + bit const rowEndColor = (finalByte >> silentBitCnt) & 0x01; + + if (rowEndColor == PBM_WHITE) { + unsigned char const blackMask = (0x01 << silentBitCnt) - 1; + + *finalByteP = finalByte | blackMask; } - { - - wordint carry; - wordint r1, r2; - unsigned int n; - int i,c,k; - - for (i = carry = n = 0; i < wordCount; ++i) { - r1 = r2 = bytesToWordint((unsigned char *)&bitrowByWord[i]); - r2 = r1 ^ (carry << (bitsPerWord-1) | r2 >> 1); - carry = r1 & 0x1; k = 0; - while (r2 != 0) { - /* wordintClz(r2) reports most significant "1" bit of r2 - counting from MSB = position 0. - */ - c = wordintClz(r2); - milepost[n++] = i * bitsPerWord + k + c; - r2 <<= c++; r2 <<= 1; k += c; - } + /* No adjustment required if the row ends with a black pixel. + pbm_cleanrowend_packed() takes care of this. + */ +} + + + +static void +trimFinalChar(struct OutStream * const outP, + bit const color, + int const carryLength, + int const existingCols, + int const desiredWidth) { +/*--------------------------------------------------------------------------- + If the carry value from the last char in the row represents a valid + sequence, output it. + + (1) If input row width is not a whole multiple of 8 and -nofixwidth + was specified, the final carry value represents inactive bits + at the row end. Emit no code. See setBlockBitsInFinalChar(). + + (2) If there is white margin on the right side, the final carry value + is valid. We add to it the margin width. Right-side margin may + be added in main() to a narrow input image, detected in the + input row by readOffSideMargins() or both. The same treatment + applies regardless of the nature of the right-side margin. +----------------------------------------------------------------------------*/ + if (existingCols == desiredWidth) { + if (existingCols % 8 == 0) + putspan(outP, color, carryLength); /* Code up to byte boundary */ + /* Emit nothing if existingCols is not a whole multiple of 8 */ + } else if (existingCols < desiredWidth) { + if (color == 0) { /* Last bit sequence in final char: white */ + unsigned int const totalLength = + carryLength + (desiredWidth - existingCols); + putspan(outP, 0, totalLength); + } else { /* Black */ + unsigned int const padLength = desiredWidth - existingCols; + putspan(outP, 1, carryLength); + putspan(outP, 0, padLength); } - if (n == 0 || milepost[n - 1] != cols) - milepost[n++] = cols; - *lengthP = n; } } static void -padToDesiredWidth(unsigned int * const milepost, - unsigned int * const nRunP, - int const existingCols, - int const desiredCols) { - - if (existingCols < desiredCols) { - /* adjustment for narrow input in fixed width mode - nRun % 2 == 1 (0) means last (=rightmost) pixel is white (black) - if white, extend the last span to outwidth - if black, fill with a white span len (outwidth - readcols) - */ - if (*nRunP % 2 == 0) - ++*nRunP; - milepost[*nRunP - 1] = desiredCols; +convertRowToG3(struct OutStream * const outP, + unsigned char * const bitrow, + unsigned int const existingCols, + unsigned int const desiredWidth) { +/*---------------------------------------------------------------------------- + Table based Huffman coding + + Normally Huffman code encoders count sequences of ones and zeros + and convert them to binary codes as they terminate. This program + recognizes chains of pixels and converts them directly, reading + prefabricated code chains from an indexed table. + + For example the 8-bit sequence 01100110 translates to + Huffman code: 000111 11 0111 11 000111. + + In reality things are more complicated. The leftmost 0 (MSB) may be + part of a longer sequence starting in the adjacent byte or perhaps + spanning several bytes. Likewise for the rightmost 0. + + So we first remove the sequence on the left side and compare its + color with the leftmost pixel of the adjacent byte and emit codes + for either ones sequence if they agree, or two if they disagree. + Next the composite code for the central part (in the above example + 110011 -> 11 0111 11) is emitted. Finally we save the length and + color of the sequence on the right end as carry-over for the next + byte cycle. Some 8-bit input sequences (00000000, 01111111, + 00111111, etc.) have no central part: these are special cases. +---------------------------------------------------------------------------*/ + unsigned int const colChars = pbm_packed_bytes(existingCols); + + unsigned int charCnt; + unsigned int firstActiveChar; + unsigned int lastActiveChar; + bool blankRow; + bit borderColor; + + borderColor = PBM_WHITE; /* initial value */ + + if (existingCols == desiredWidth && (desiredWidth % 8) > 0) + setBlockBitsInFinalChar(&bitrow[colChars-1], desiredWidth); + + readOffSideMargins(bitrow, colChars, + &firstActiveChar, &lastActiveChar, &blankRow); + + if (blankRow) + putspan(outP, PBM_WHITE, desiredWidth); + else { + unsigned int carryLength; + + for (charCnt = firstActiveChar, carryLength = firstActiveChar * 8; + charCnt <=lastActiveChar; + ++charCnt) { + + unsigned char const byte = bitrow[charCnt]; + bit const rColor = !borderColor; + + if (byte == borderColor * 0xFF) { + carryLength += 8; + } else if (byte == (unsigned char) ~(borderColor * 0xFF)) { + putspan(outP, borderColor, carryLength); + carryLength = 8; + borderColor = rColor; + } else { + struct PrefabCode const code = prefabCode[byte]; + unsigned int const activeLength = + 8 - code.leadBits - code.trailBits; + + if (borderColor == (byte >> 7)) { + putspan(outP, borderColor, carryLength + code.leadBits); + } else { + putspan(outP, borderColor, carryLength); + putcodeShort(outP, rColor, code.leadBits); + } + if (activeLength > 0) + putbits(outP, code.activeBits); + + borderColor = byte & 0x01; + carryLength = code.trailBits; + } + } + trimFinalChar(outP, borderColor, carryLength, + (lastActiveChar + 1) * 8, desiredWidth); } + puteol(outP); } int -main(int argc, - char * argv[]) { +main(int argc, + const char * argv[]) { struct CmdlineInfo cmdline; FILE * ifP; unsigned char * bitrow; /* This is the bits of the current row, as read from the input and - modified various ways at various points in the program. It has - a word of zero padding on the high (right) end for the convenience - of code that accesses this buffer in word-size bites. + modified various ways at various points in the program. It has + a word of zero padding on the high (right) end for the convenience + of code that accesses this buffer in word-size bites. */ int rows; int cols; - int readcols; - int outwidth; int format; - int row; - unsigned int * milepost; + unsigned int existingCols; + unsigned int desiredWidth; + unsigned int row; + struct OutStream out; - pbm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFileName); pbm_readpbminit(ifP, &cols, &rows, &format); - if (cmdline.nofixedwidth) - readcols = outwidth = cols; + + if (cmdline.desiredWidth == 0) + desiredWidth = existingCols = cols; else { - readcols = MIN(cols, 1728); - outwidth = 1728; + if (cmdline.desiredWidth < cols) + existingCols = desiredWidth = cmdline.desiredWidth; + else { + existingCols = pbm_packed_bytes(cols) * 8; + desiredWidth = cmdline.desiredWidth; + } } - MALLOCARRAY_NOFAIL(bitrow, pbm_packed_bytes(cols) + sizeof(wordint)); + MALLOCARRAY(bitrow, pbm_packed_bytes(cols) + sizeof(uint32_t)); - MALLOCARRAY_NOFAIL(milepost, readcols + 2); + if (!bitrow) + pm_error("Failed to allocate a row buffer for %u columns", cols); - initOutStream(cmdline.reversebits); - puteol(); + initOutStream(&out, cmdline.reversebits, cmdline.align, cmdline.dump); + + puteol(&out); for (row = 0; row < rows; ++row) { - unsigned int nRun; /* Number of runs in milepost[] */ - unsigned int p; - unsigned int i; - pbm_readpbmrow_packed(ifP, bitrow, cols, format); - - convertRowToRunLengths(bitrow, readcols, milepost, &nRun); - - padToDesiredWidth(milepost, &nRun, readcols, outwidth); - - for (i = p = 0; i < nRun; p = milepost[i++]) - putspan(i%2 == 0 ? PBM_WHITE : PBM_BLACK, milepost[i] - p); - /* TODO 2-dimensional coding MR, MMR */ - puteol(); + pbm_cleanrowend_packed(bitrow, cols); + convertRowToG3(&out, bitrow, existingCols, desiredWidth); } - free(milepost); pbm_freerow_packed(bitrow); - - { - unsigned int i; - for( i = 0; i < 6; ++i) - puteol(); - } - if (out.buffer.bitCount > 0) { - /* flush final partial buffer */ - unsigned int const bytesToWrite = (out.buffer.bitCount+7)/8; - - unsigned char outbytes[sizeof(wordint)]; - size_t rc; - wordintToBytes(&outbytes, - out.buffer.intBuffer << (sizeof(out.buffer.intBuffer)*8 - - out.buffer.bitCount)); - if (out.reverseBits) - reversebuffer(outbytes, bytesToWrite); - rc = fwrite(outbytes, 1, bytesToWrite, stdout); - if (rc != bytesToWrite) - pm_error("Output error"); - } + putrtc(&out); + flushBuffer(&out); pm_close(ifP); return 0; } + + + |