Tue, 18 Mar 2014 01:27:15 +0000
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 }