PTdecode/src/main.cpp

Mon, 03 Aug 2009 16:14:35 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 03 Aug 2009 16:14:35 +0100
changeset 8
a2989aa17d21
parent 5
1204ebf9340d
child 13
a933b13e087f
permissions
-rw-r--r--

remove more hg_image detritus

philpem@5 1 /****************************************************************************
philpem@5 2 * ptdecode: P-touch PT-2450DX output decoder
philpem@5 3 ****************************************************************************/
philpem@5 4
philpem@5 5 #include <cstdio>
philpem@5 6 #include <exception>
philpem@5 7 #include "CImg.h"
philpem@5 8
philpem@5 9 using namespace std;
philpem@5 10 using namespace cimg_library;
philpem@5 11
philpem@5 12 // maximum size of a Ptouch printer head in dots
philpem@5 13 const unsigned int PT_HEAD_WIDTH = 1024;
philpem@5 14
philpem@5 15 // If defined, makes "blank row" blocks visible
philpem@5 16 //#define MAKE_BLANK_ROWS_VISIBLE
philpem@5 17
philpem@5 18 // custom exception class for file read errors
philpem@5 19 class EReadError : public exception {
philpem@5 20 public:
philpem@5 21 virtual const char* what() const throw()
philpem@5 22 {
philpem@5 23 return "Read error";
philpem@5 24 }
philpem@5 25 };
philpem@5 26
philpem@5 27 FILE *fp;
philpem@5 28
philpem@5 29 // get next character from file
philpem@5 30 unsigned char getNext() {
philpem@5 31 unsigned char ch;
philpem@5 32 int i;
philpem@5 33
philpem@5 34 i = fread(&ch, 1, 1, fp);
philpem@5 35 if (i != 1) {
philpem@5 36 throw EReadError();
philpem@5 37 } else {
philpem@5 38 return ch;
philpem@5 39 }
philpem@5 40 }
philpem@5 41
philpem@5 42 // Handler for graphics transfer mode 1
philpem@5 43 void runGraphicsXferMode1()
philpem@5 44 {
philpem@5 45 bool exit = false;
philpem@5 46 unsigned int cm = -1;
philpem@5 47 unsigned long xpos = 0;
philpem@5 48 unsigned long ypos = 0;
philpem@5 49 unsigned long ydim = 128;
philpem@5 50 CImg<unsigned char> img(0, 0, 0, 0, (unsigned char)0);
philpem@5 51
philpem@5 52 while (!exit) {
philpem@5 53 unsigned char ch = getNext();
philpem@5 54 unsigned int len = 0;
philpem@5 55 unsigned int rowpos = 0;
philpem@5 56 unsigned char row[PT_HEAD_WIDTH / 8]; // stores uncompressed row data
philpem@5 57
philpem@5 58 switch (ch) {
philpem@5 59 case 'M': // Set compression mode
philpem@5 60 ch = getNext();
philpem@5 61 cm = ch;
philpem@5 62 printf("Set compression mode: 0x%02X", ch);
philpem@5 63 switch (cm) {
philpem@5 64 case 0x02:
philpem@5 65 printf(" (TIFF/Packbits)\n");
philpem@5 66 break;
philpem@5 67 default:
philpem@5 68 printf(" *** Unknown, assuming uncompressed ***\n");
philpem@5 69 cm = 1;
philpem@5 70 break;
philpem@5 71 }
philpem@5 72 break;
philpem@5 73
philpem@5 74 case 'Z': // Blank raster line
philpem@5 75 // Increment x-position and resize the image
philpem@5 76 img.resize(xpos+1, ydim, 1, 1, 0, 0);
philpem@5 77
philpem@5 78 // Blank the new row
philpem@5 79 if (img.dimy() > 0) {
philpem@5 80 // printf("Clear row: x=%lu\n", xpos);
philpem@5 81 for (int i=0; i<img.dimy(); i++) {
philpem@5 82 #ifdef MAKE_BLANK_ROWS_VISIBLE
philpem@5 83 img(xpos, i) = 128;
philpem@5 84 #else
philpem@5 85 img(xpos, i) = 255;
philpem@5 86 #endif
philpem@5 87 }
philpem@5 88 }
philpem@5 89
philpem@5 90 xpos++;
philpem@5 91 break;
philpem@5 92
philpem@5 93 case 'G': // Graphics data row
philpem@5 94 // decode the length
philpem@5 95 ch = getNext();
philpem@5 96 len = (((int)getNext()) << 8) + ch;
philpem@5 97
philpem@5 98 // Dump the gfx data
philpem@5 99 rowpos = 0;
philpem@5 100 while (len > 0) {
philpem@5 101 // get the prefix byte
philpem@5 102 ch = getNext(); len--;
philpem@5 103
philpem@5 104 // Is this a "run" (a single byte replicated) or a "copy"?
philpem@5 105 int runlen;
philpem@5 106 if (ch & 0x80) {
philpem@5 107 // MSB set, it's a run
philpem@5 108 runlen = 257 - ((int)ch);
philpem@5 109
philpem@5 110 // Get the byte to replicate, and replicate it into the o/p buffer
philpem@5 111 ch = getNext(); len--;
philpem@5 112 while (runlen-- > 0) {
philpem@5 113 row[rowpos++] = ch;
philpem@5 114 }
philpem@5 115 } else {
philpem@5 116 // MSB clear, it's a copy
philpem@5 117 runlen = ((int)ch) + 1;
philpem@5 118
philpem@5 119 // Copy N bytes from the input stream to the output
philpem@5 120 while (runlen-- > 0) {
philpem@5 121 row[rowpos++] = getNext();
philpem@5 122 len--;
philpem@5 123 }
philpem@5 124 }
philpem@5 125 }
philpem@5 126
philpem@5 127 // Row decode complete. row contains the image data, and rowpos
philpem@5 128 // contains its length in bytes. Now shuffle it into CImg...
philpem@5 129
philpem@5 130 // If image height is less than size of image row, then make the
philpem@5 131 // image taller.
philpem@5 132 if (((unsigned int)img.dimy()) < (rowpos * 8)) {
philpem@5 133 ydim = rowpos * 8;
philpem@5 134 } else {
philpem@5 135 ydim = img.dimy();
philpem@5 136 }
philpem@5 137
philpem@5 138 // Perform the Y resize if necessary, but also make Xdim=Xdim+1
philpem@5 139 img.resize(xpos+1, ydim, 1, 1, 0, 0);
philpem@5 140
philpem@5 141 img(xpos, ydim/2) = 128;
philpem@5 142
philpem@5 143 // Now copy the image data...
philpem@5 144 ypos = 0;
philpem@5 145 for (unsigned int byte=0; byte<rowpos; byte++) {
philpem@5 146 for (unsigned int bit=0; bit<8; bit++) {
philpem@5 147 if (row[byte] & (0x80>>bit)) {
philpem@5 148 img(xpos, ypos) = 0;
philpem@5 149 } else {
philpem@5 150 img(xpos, ypos) = 255;
philpem@5 151 }
philpem@5 152
philpem@5 153 // Increment y-position
philpem@5 154 ypos++;
philpem@5 155 }
philpem@5 156 }
philpem@5 157
philpem@5 158 // An entire row has been decoded. Increment x-position.
philpem@5 159 xpos++;
philpem@5 160 break;
philpem@5 161
philpem@5 162 case 0x0c: // FF
philpem@5 163 printf("Formfeed: Print without label feed (job completed, more labels follow)\n");
philpem@5 164 exit = true;
philpem@5 165 break;
philpem@5 166
philpem@5 167 case 0x1a: // Ctrl-Z
philpem@5 168 printf("Ctrl-Z: Print with label feed (job completed, no further labels)\n");
philpem@5 169 exit = true;
philpem@5 170 break;
philpem@5 171
philpem@5 172 default: // Something else
philpem@5 173 printf("** Unrecognised command prefix in gfx mode: 0x%02x\n", ch);
philpem@5 174 break;
philpem@5 175 }
philpem@5 176 }
philpem@5 177
philpem@5 178 // Display the contents of the image
philpem@5 179 img.display();
philpem@5 180 }
philpem@5 181
philpem@5 182 // Parse an ESC i command
philpem@5 183 void parse_esc_i()
philpem@5 184 {
philpem@5 185 unsigned char ch = getNext();
philpem@5 186 unsigned int tmpI;
philpem@5 187
philpem@5 188 switch (ch) {
philpem@5 189 case 'B': // ESC i B: Specify baud rate
philpem@5 190 tmpI = getNext();
philpem@5 191 ch = getNext();
philpem@5 192 tmpI += ((int)ch)*256;
philpem@5 193 printf("Set baud rate:\t%d00", tmpI);
philpem@5 194 if ((tmpI != 96) && (tmpI != 576) && (tmpI != 1152)) {
philpem@5 195 printf(" [ILLEGAL SETTING]\n");
philpem@5 196 } else {
philpem@5 197 printf("\n");
philpem@5 198 }
philpem@5 199 break;
philpem@5 200
philpem@5 201 case 'S': // ESC i S: Status request
philpem@5 202 printf("Printer status request\n");
philpem@5 203 break;
philpem@5 204
philpem@5 205 case 'M': // ESC i M: Set mode
philpem@5 206 ch = getNext();
philpem@5 207 printf("Set mode 0x%02X:\tAutoCut %s, Mirror %s\n", ch,
philpem@5 208 (ch & 0x40) ? "on" : "off",
philpem@5 209 (ch & 0x80) ? "on" : "off");
philpem@5 210 break;
philpem@5 211
philpem@5 212 case 'd': // ESC i d: Set margin amount (feed amount)
philpem@5 213 tmpI = getNext();
philpem@5 214 ch = getNext();
philpem@5 215 tmpI += ((int)ch)*256;
philpem@5 216 printf("Set margin:\t%d dots", tmpI);
philpem@5 217 break;
philpem@5 218
philpem@5 219 case 'K': // ESC i K: Set expanded mode
philpem@5 220 ch = getNext();
philpem@5 221 printf("Set expanded mode 0x%02X:\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n", ch,
philpem@5 222 (ch & 0x04) ? "Half-cut on" : "Half-cut off",
philpem@5 223 (ch & 0x08) ? "Chain-print off: last label will be fed and cut" : "Chain-print on: last label will NOT be fed or cut",
philpem@5 224 (ch & 0x20) ? "Label end cut: when printing multiple copies, end of last label is cut" : "Label end cut off",
philpem@5 225 (ch & 0x40) ? "High-resolution (360x720dpi)" : "Normal resolution (360x360dpi)",
philpem@5 226 (ch & 0x80) ? "Copy-printing on (expansion buffer not cleared on form-feed)" : "Copy-printing off"
philpem@5 227 );
philpem@5 228 break;
philpem@5 229
philpem@5 230 case 'R': // ESC i R: Set graphics transfer mode
philpem@5 231 ch = getNext();
philpem@5 232 printf("Set graphics transfer mode 0x%02X: ", ch);
philpem@5 233 if (ch == 1) {
philpem@5 234 printf("Raster graphics mode\n");
philpem@5 235 runGraphicsXferMode1();
philpem@5 236 } else {
philpem@5 237 printf("\n\tUnrecognised graphics transfer mode: remainder of data may be garbage.\n");
philpem@5 238 }
philpem@5 239 break;
philpem@5 240
philpem@5 241 default:
philpem@5 242 printf("Unrecognised cmnd: ESC i 0x%02X\n", ch);
philpem@5 243 break;
philpem@5 244 }
philpem@5 245 }
philpem@5 246
philpem@5 247 // Parse an ESC command
philpem@5 248 void parse_esc()
philpem@5 249 {
philpem@5 250 unsigned char ch = getNext();
philpem@5 251
philpem@5 252 switch(ch) {
philpem@5 253 case 'i': // ESC i: Brother-specific extensions
philpem@5 254 parse_esc_i();
philpem@5 255 break;
philpem@5 256
philpem@5 257 case '@': // ESC @: Initialize
philpem@5 258 printf("Initialize: clear buffer and reset print origin\n");
philpem@5 259 break;
philpem@5 260
philpem@5 261 default:
philpem@5 262 printf("Unrecognised cmnd: ESC 0x%02X\n", ch);
philpem@5 263 break;
philpem@5 264 }
philpem@5 265 }
philpem@5 266
philpem@5 267 int main(int argc, char **argv)
philpem@5 268 {
philpem@5 269 // check params
philpem@5 270 if (argc != 2) {
philpem@5 271 // wrong!
philpem@5 272 printf("Usage: %s filename\n", argv[0]);
philpem@5 273 return -1;
philpem@5 274 }
philpem@5 275
philpem@5 276 // open binary dump file
philpem@5 277 fp = fopen(argv[1], "rb");
philpem@5 278 if (!fp) {
philpem@5 279 printf("Error opening source file\n");
philpem@5 280 return -1;
philpem@5 281 }
philpem@5 282
philpem@5 283 try {
philpem@5 284 while (true) {
philpem@5 285 unsigned char ch;
philpem@5 286
philpem@5 287 ch = getNext();
philpem@5 288
philpem@5 289 switch (ch) {
philpem@5 290 case 0x00: // NULL
philpem@5 291 printf("Null\n");
philpem@5 292 break;
philpem@5 293 case 0x0c: // FF
philpem@5 294 printf("Formfeed: Print without feed\n");
philpem@5 295 break;
philpem@5 296 case 0x1a: // Ctrl-Z
philpem@5 297 printf("Ctrl-Z: Print with label feed\n");
philpem@5 298 break;
philpem@5 299 case 0x1b: // ESC
philpem@5 300 parse_esc();
philpem@5 301 break;
philpem@5 302 default:
philpem@5 303 printf("Unrecognised cmnd: 0x%02X\n", ch);
philpem@5 304 break;
philpem@5 305 }
philpem@5 306 }
philpem@5 307 } catch (EReadError &e) {
philpem@5 308 if (feof(fp)) {
philpem@5 309 printf("EOF reached.\n");
philpem@5 310 } else {
philpem@5 311 printf("Uncaught EReadException: %s\n", e.what());
philpem@5 312 }
philpem@5 313 } catch (exception &e) {
philpem@5 314 printf("Uncaught exception: %s\n", e.what());
philpem@5 315 } catch (...) {
philpem@5 316 printf("Uncaught and unrecognised exception. Something went *really* wrong here...\n");
philpem@5 317 }
philpem@5 318
philpem@5 319 // close the file
philpem@5 320 fclose(fp);
philpem@5 321
philpem@5 322 return 0;
philpem@5 323 }