PTdecode/src/main.cpp

Mon, 03 Aug 2009 14:09:20 +0100

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

added P-touch decoder source

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