PTdecode/src/main.cpp

Tue, 18 Mar 2014 01:27:15 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Tue, 18 Mar 2014 01:27:15 +0000
changeset 23
f2c7acb4a258
parent 13
a933b13e087f
permissions
-rw-r--r--

Update PTdecode to handle output from other Ptouch drivers

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