Wed, 05 Aug 2009 17:32:05 +0100
updated README
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 // Is gfx payload compressed or uncompressed?
99 if (cm == 1) {
100 // Uncompressed. Read straight into the row buffer.
101 while (len > 0) {
102 row[rowpos++] = getNext(); len--;
103 }
104 } else {
105 // Decompress the gfx data
106 rowpos = 0;
107 while (len > 0) {
108 // get the prefix byte
109 ch = getNext(); len--;
111 // Is this a "run" (a single byte replicated) or a "copy"?
112 int runlen;
113 if (ch & 0x80) {
114 // MSB set, it's a run
115 runlen = 257 - ((int)ch);
117 // Get the byte to replicate, and replicate it into the o/p buffer
118 ch = getNext(); len--;
119 while (runlen-- > 0) {
120 row[rowpos++] = ch;
121 }
122 } else {
123 // MSB clear, it's a copy
124 runlen = ((int)ch) + 1;
126 // Copy N bytes from the input stream to the output
127 while (runlen-- > 0) {
128 row[rowpos++] = getNext();
129 len--;
130 }
131 }
132 }
133 }
135 // Row decode complete. row contains the image data, and rowpos
136 // contains its length in bytes. Now shuffle it into CImg...
138 // If image height is less than size of image row, then make the
139 // image taller.
140 if (((unsigned int)img.dimy()) < (rowpos * 8)) {
141 ydim = rowpos * 8;
142 } else {
143 ydim = img.dimy();
144 }
146 // Perform the Y resize if necessary, but also make Xdim=Xdim+1
147 img.resize(xpos+1, ydim, 1, 1, 0, 0);
149 img(xpos, ydim/2) = 128;
151 // Now copy the image data...
152 ypos = 0;
153 for (unsigned int byte=0; byte<rowpos; byte++) {
154 for (unsigned int bit=0; bit<8; bit++) {
155 if (row[byte] & (0x80>>bit)) {
156 img(xpos, ypos) = 0;
157 } else {
158 img(xpos, ypos) = 255;
159 }
161 // Increment y-position
162 ypos++;
163 }
164 }
166 // An entire row has been decoded. Increment x-position.
167 xpos++;
168 break;
170 case 0x0c: // FF
171 printf("Formfeed: Print without label feed (job completed, more labels follow)\n");
172 exit = true;
173 break;
175 case 0x1a: // Ctrl-Z
176 printf("Ctrl-Z: Print with label feed (job completed, no further labels)\n");
177 exit = true;
178 break;
180 default: // Something else
181 printf("** Unrecognised command prefix in gfx mode: 0x%02x\n", ch);
182 break;
183 }
184 }
186 // Display the contents of the image
187 img.display();
188 }
190 // Parse an ESC i command
191 void parse_esc_i()
192 {
193 unsigned char ch = getNext();
194 unsigned int tmpI;
196 switch (ch) {
197 case 'B': // ESC i B: Specify baud rate
198 tmpI = getNext();
199 ch = getNext();
200 tmpI += ((int)ch)*256;
201 printf("Set baud rate:\t%d00", tmpI);
202 if ((tmpI != 96) && (tmpI != 576) && (tmpI != 1152)) {
203 printf(" [ILLEGAL SETTING]\n");
204 } else {
205 printf("\n");
206 }
207 break;
209 case 'S': // ESC i S: Status request
210 printf("Printer status request\n");
211 break;
213 case 'M': // ESC i M: Set mode
214 ch = getNext();
215 printf("Set mode 0x%02X:\tAutoCut %s, Mirror %s\n", ch,
216 (ch & 0x40) ? "on" : "off",
217 (ch & 0x80) ? "on" : "off");
218 break;
220 case 'd': // ESC i d: Set margin amount (feed amount)
221 tmpI = getNext();
222 ch = getNext();
223 tmpI += ((int)ch)*256;
224 printf("Set margin:\t%d dots", tmpI);
225 break;
227 case 'K': // ESC i K: Set expanded mode
228 ch = getNext();
229 printf("Set expanded mode 0x%02X:\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n", ch,
230 (ch & 0x04) ? "Half-cut on" : "Half-cut off",
231 (ch & 0x08) ? "Chain-print off: last label will be fed and cut" : "Chain-print on: last label will NOT be fed or cut",
232 (ch & 0x20) ? "Label end cut: when printing multiple copies, end of last label is cut" : "Label end cut off",
233 (ch & 0x40) ? "High-resolution (360x720dpi)" : "Normal resolution (360x360dpi)",
234 (ch & 0x80) ? "Copy-printing on (expansion buffer not cleared on form-feed)" : "Copy-printing off"
235 );
236 break;
238 case 'R': // ESC i R: Set graphics transfer mode
239 ch = getNext();
240 printf("Set graphics transfer mode 0x%02X: ", ch);
241 if (ch == 1) {
242 printf("Raster graphics mode\n");
243 runGraphicsXferMode1();
244 } else {
245 printf("\n\tUnrecognised graphics transfer mode: remainder of data may be garbage.\n");
246 }
247 break;
249 default:
250 printf("Unrecognised cmnd: ESC i 0x%02X\n", ch);
251 break;
252 }
253 }
255 // Parse an ESC command
256 void parse_esc()
257 {
258 unsigned char ch = getNext();
260 switch(ch) {
261 case 'i': // ESC i: Brother-specific extensions
262 parse_esc_i();
263 break;
265 case '@': // ESC @: Initialize
266 printf("Initialize: clear buffer and reset print origin\n");
267 break;
269 default:
270 printf("Unrecognised cmnd: ESC 0x%02X\n", ch);
271 break;
272 }
273 }
275 int main(int argc, char **argv)
276 {
277 // check params
278 if (argc != 2) {
279 // wrong!
280 printf("Usage: %s filename\n", argv[0]);
281 return -1;
282 }
284 // open binary dump file
285 fp = fopen(argv[1], "rb");
286 if (!fp) {
287 printf("Error opening source file\n");
288 return -1;
289 }
291 try {
292 while (true) {
293 unsigned char ch;
295 ch = getNext();
297 switch (ch) {
298 case 0x00: // NULL
299 printf("Null\n");
300 break;
301 case 0x0c: // FF
302 printf("Formfeed: Print without feed\n");
303 break;
304 case 0x1a: // Ctrl-Z
305 printf("Ctrl-Z: Print with label feed\n");
306 break;
307 case 0x1b: // ESC
308 parse_esc();
309 break;
310 default:
311 printf("Unrecognised cmnd: 0x%02X\n", ch);
312 break;
313 }
314 }
315 } catch (EReadError &e) {
316 if (feof(fp)) {
317 printf("EOF reached.\n");
318 } else {
319 printf("Uncaught EReadException: %s\n", e.what());
320 }
321 } catch (exception &e) {
322 printf("Uncaught exception: %s\n", e.what());
323 } catch (...) {
324 printf("Uncaught and unrecognised exception. Something went *really* wrong here...\n");
325 }
327 // close the file
328 fclose(fp);
330 return 0;
331 }