1 // -*- C++ -*-
2 // $Id: LabelWriterDriver.cpp 15934 2011-08-31 17:42:29Z pineichen $
3
4 // DYMO LabelWriter Drivers
5 // Copyright (C) 2008 Sanford L.P.
6
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21
22 #include "LabelWriterDriver.h"
23 #include <assert.h>
24 #include <stdio.h>
25 #pragma warning(disable:4267)
26
27 namespace DymoPrinterDriver
28 {
29
30
31 const byte ESC = 0x1B;
32 const byte SYN = 0x16;
33 const byte ETB = 0x17;
34
CLabelWriterDriver(IPrintEnvironment & Environment)35 CLabelWriterDriver::CLabelWriterDriver(IPrintEnvironment& Environment):
36 Environment_(Environment),
37 Resolution_(resUnknown), Density_(pdNormal), Quality_(pqText), PageHeight_(0x0800), PaperType_(ptRegular),
38 MaxPrintWidth_(84),PageOffset_(0, 0),LastDotTab_(size_t(-1)), LastBytesPerLine_(size_t(-1)), EmptyLinesCount_(0)
39 {
40 }
41
~CLabelWriterDriver()42 CLabelWriterDriver::~CLabelWriterDriver()
43 {
44 }
45
46 void
StartDoc()47 CLabelWriterDriver::StartDoc()
48 {
49 SendCommand(GetResetCommand());
50 SendResolution(Resolution_);
51 SendLineTab(0);
52 SendDotTab(0);
53 SendPrintQuality(Quality_);
54 SendPrintDensity(Density_);
55 }
56
57 void
EndDoc()58 CLabelWriterDriver::EndDoc()
59 {
60 }
61
62 void
StartPage()63 CLabelWriterDriver::StartPage()
64 {
65 switch (PaperType_)
66 {
67 case ptRegular: SendLabelLength(PageHeight_); break;
68 case ptContinuous: SendLabelLength(0xffff); break;
69 default: assert(0);
70 }
71
72 LastDotTab_ = size_t(-1);
73 LastBytesPerLine_ = size_t(-1);
74 EmptyLinesCount_ = 0;
75 }
76
77 void
EndPage()78 CLabelWriterDriver::EndPage()
79 {
80 SendFormFeed();
81 }
82
83
84 void
SendNotCompressedData(const buffer_t & Buf,size_t LeaderBlanks,size_t TrailerBlanks)85 CLabelWriterDriver::SendNotCompressedData(
86 const buffer_t& Buf, size_t LeaderBlanks, size_t TrailerBlanks)
87 {
88 byte syn = SYN;
89
90 size_t DataSize = Buf.size() - LeaderBlanks - TrailerBlanks;
91
92 // set bytes per line in case of it changes from last raster line
93 if (LastBytesPerLine_ != DataSize)
94 {
95 SendBytesPerLine(DataSize);
96 LastBytesPerLine_ = DataSize;
97 }
98
99 SendCommand(&syn, sizeof(syn));
100 SendCommand(&Buf[0] + LeaderBlanks, DataSize);
101 }
102
103 void
SendCompressedData(const buffer_t & CompressedBuf,size_t NotCompressedSize)104 CLabelWriterDriver::SendCompressedData(
105 const buffer_t& CompressedBuf, size_t NotCompressedSize)
106 {
107 byte etb = ETB;
108
109 // set bytes per line in case of it changes from last raster line
110 if (LastBytesPerLine_ != NotCompressedSize)
111 {
112 SendBytesPerLine(NotCompressedSize);
113 LastBytesPerLine_ = NotCompressedSize;
114 }
115
116 SendCommand(&etb, sizeof(etb));
117 SendCommand(&CompressedBuf[0], CompressedBuf.size());
118 }
119
120 void
GetBlanks(const buffer_t & Buf,size_t & LeaderBlanks,size_t & TrailerBlanks)121 CLabelWriterDriver::GetBlanks(
122 const buffer_t& Buf, size_t& LeaderBlanks, size_t& TrailerBlanks)
123 {
124 ssize_t i = 0;
125
126 LeaderBlanks = 0;
127 TrailerBlanks = 0;
128
129 ssize_t BufSize = Buf.size();
130
131 // count left spaces
132 for (i = 0; i < BufSize; ++i)
133 if (Buf[i] == 0)
134 ++LeaderBlanks;
135 else
136 break;
137
138 if (i == BufSize) return;
139
140 // count right spaces
141 for (i = BufSize - 1; i >= 0; --i)
142 if (Buf[i] == 0)
143 ++TrailerBlanks;
144 else
145 break;
146 } // GetBlanks()
147
148 // bit numbers in byte
149 // 7 6 5 4 3 2 1 0
150 // msb lsb
151
152 // Returns Value of bit BitNo in byte Data
153 // if bit unset returns 0, else - not 0
154 static inline byte
GetBitValue(byte data,size_t bitNo)155 GetBitValue(byte data, size_t bitNo)
156 {
157 return data & (1 << bitNo);
158 }
159
160 // Advanses to one bit in byte sequence
161 static inline void
NextBit(size_t & curByteNo,size_t & curBitNo)162 NextBit(size_t& curByteNo, size_t& curBitNo)
163 {
164 if (curBitNo == 0)
165 {
166 curByteNo = curByteNo + 1;
167 curBitNo = 7;
168 }
169 else
170 curBitNo = curBitNo - 1;
171 }
172
173 // Returns RLE compressed value for data in Data with size DataLen
174 // start compression at CurByteNo/CurBitNo
175 // At exit CureByteNo, CurBitNo contains next bit after compressed sequence
176 static byte
GetCompressedSequenceValue(const byte * data,size_t dataLen,size_t & curByteNo,size_t & curBitNo)177 GetCompressedSequenceValue(const byte* data, size_t dataLen, size_t& curByteNo, size_t& curBitNo)
178 {
179 byte bitCount = 0;
180 byte bitValue = 0;
181 byte startBitValue = GetBitValue(data[curByteNo], curBitNo);
182 NextBit(curByteNo, curBitNo);
183
184 // while data exist and not max len of sequence
185 while ((curByteNo < dataLen) && (bitCount < 0x7f))
186 {
187 bitValue = GetBitValue(data[curByteNo], curBitNo);
188
189 // same as prev bit
190 if ((startBitValue && bitValue) || (!startBitValue && !bitValue))
191 {
192 bitCount++;
193 NextBit(curByteNo, curBitNo);
194 }
195 else // end of sequence
196 break;
197 } // while
198
199 if (startBitValue)
200 return bitCount | 0x80; // set high bit for "black" pixels
201 else
202 return bitCount;
203 }
204
205 static void
CompressData(buffer_t & CompressedData,const byte * Data,size_t DataSize)206 CompressData(buffer_t& CompressedData, const byte* Data, size_t DataSize)
207 {
208 size_t CurByteNo = 0;
209 size_t CurBitNo = 7;
210 size_t CompressedOffset = 0;
211
212 while (CurByteNo < DataSize)
213 {
214 if (CompressedOffset >= DataSize - 1)
215 {
216 CompressedData.clear(); // will write non-compressed data
217 return;
218 }
219 CompressedData.push_back(GetCompressedSequenceValue(Data, DataSize, CurByteNo, CurBitNo));
220 ++CompressedOffset;
221 }
222 }
223
224 static void
ShiftDataRight(const buffer_t & Buf,buffer_t & ShiftedBuf,size_t ShiftValue)225 ShiftDataRight(const buffer_t& Buf, buffer_t& ShiftedBuf, size_t ShiftValue)
226 {
227 // shift bytes first
228 int ShiftedLen = ShiftedBuf.size() - ShiftValue / 8;
229 size_t ShiftedOffset = ShiftValue / 8;
230 ShiftValue = ShiftValue % 8;
231
232 if ((ShiftedLen <= 0) || (Buf.size() == 0)) return;
233
234 // shift bits
235 ShiftedBuf[ShiftedOffset] = Buf[0] >> ShiftValue; // first
236 size_t i = 0;
237 for (i = 1; ((i < Buf.size()) && (i < size_t(ShiftedLen))); ++i)
238 ShiftedBuf[ShiftedOffset + i] = (Buf[i - 1] << (8 - ShiftValue)) | (Buf[i] >> ShiftValue);
239 if (i < size_t(ShiftedLen))
240 ShiftedBuf[ShiftedOffset + Buf.size()] = (Buf[Buf.size() - 1] << (8 - ShiftValue));
241 }
242
243 static void
ShiftDataLeft(const buffer_t & Buf,buffer_t & ShiftedBuf,size_t ShiftValue)244 ShiftDataLeft(const buffer_t& Buf, buffer_t& ShiftedBuf, size_t ShiftValue)
245 {
246 // shift bytes first
247 int ShiftedLen = ShiftedBuf.size() - ShiftValue / 8;
248 ShiftValue = ShiftValue % 8;
249
250 if ((ShiftedLen <= 0) || (Buf.size() == 0)) return;
251
252 // shift bits
253 size_t i = 0;
254 for (i = 0; ((i < Buf.size() - 1) && (i < size_t(ShiftedLen))); ++i)
255 ShiftedBuf[i] = (Buf[i] << ShiftValue) | (Buf[i + 1] >> (8 - ShiftValue));
256 if (i < size_t(ShiftedLen))
257 ShiftedBuf[Buf.size() - 1] = (Buf[Buf.size() - 1] << ShiftValue); // last
258 }
259
260
261 static void
ShiftData(const buffer_t & Buf,buffer_t & ShiftedBuf,int ShiftValue)262 ShiftData(const buffer_t& Buf, buffer_t& ShiftedBuf, int ShiftValue)
263 {
264 // clear shift buffer first
265 for (size_t i = 0; i < ShiftedBuf.size(); ++i)
266 ShiftedBuf[i] = 0;
267
268 if (ShiftValue >= 0)
269 ShiftDataRight(Buf, ShiftedBuf, ShiftValue);
270 else
271 ShiftDataLeft(Buf, ShiftedBuf, -ShiftValue);
272 }
273
274 void
ProcessRasterLine(const buffer_t & lineBuffer)275 CLabelWriterDriver::ProcessRasterLine(const buffer_t& lineBuffer)
276 {
277 buffer_t b = lineBuffer;
278
279 if (PageOffset_.x > 0)
280 {
281 buffer_t b2(b.size() + (PageOffset_.x + 7) / 8, 0);
282 ShiftData(b, b2, PageOffset_.x);
283 b = b2;
284 }
285
286 if (b.size() > MaxPrintWidth_)
287 {
288 fputs("WARNING: CLabelWriterDriver::ProcessRasterLine(): page width is greater max page width, truncated\n", stderr);
289 b = buffer_t(b.begin(), b.begin() + MaxPrintWidth_);
290 }
291
292 size_t LeaderBlanks = 0;
293 size_t TrailerBlanks = 0;
294
295 // get blanks count
296 GetBlanks(b, LeaderBlanks, TrailerBlanks);
297
298 if (LeaderBlanks + TrailerBlanks == b.size())
299 {
300 // remember empty line
301 ++EmptyLinesCount_;
302 }
303 else // not empty line
304 {
305 // skip empty lines
306 if (EmptyLinesCount_)
307 SendSkipLines(EmptyLinesCount_);
308
309 EmptyLinesCount_ = 0;
310
311 // set dot tab
312 // Bug Fix for DLS80AM-1421
313 // NOTE: an ESC B needs to be send for each raster line. Otherwise the LW 3xx series output
314 // will be distorted.
315 //if (LastDotTab_ != LeaderBlanks)
316 //{
317 SendDotTab(LeaderBlanks);
318 LastDotTab_ = LeaderBlanks;
319 //}
320
321 // calculate compressed data size
322 buffer_t CompressedData;
323 CompressData(CompressedData, &b[0] + LeaderBlanks, b.size() - LeaderBlanks - TrailerBlanks);
324
325 if ((CompressedData.size() > 0) && (CompressedData.size() < b.size() - LeaderBlanks - TrailerBlanks))
326 SendCompressedData(CompressedData, b.size() - LeaderBlanks - TrailerBlanks);
327 else
328 SendNotCompressedData(b, LeaderBlanks, TrailerBlanks);
329 }
330
331
332 }
333
334
335 void
SendCommand(const byte * Buf,size_t BufSize)336 CLabelWriterDriver::SendCommand(const byte* Buf, size_t BufSize)
337 {
338 Environment_.WriteData(buffer_t(Buf, Buf + BufSize));
339 }
340
341 void
SendCommand(const buffer_t & Buf)342 CLabelWriterDriver::SendCommand(const buffer_t& Buf)
343 {
344 Environment_.WriteData(Buf);
345 }
346
347 CLabelWriterDriver::resolution_t
GetResolution()348 CLabelWriterDriver::GetResolution()
349 {
350 return Resolution_;
351 }
352
353 CLabelWriterDriver::density_t
GetDensity()354 CLabelWriterDriver::GetDensity()
355 {
356 return Density_;
357 }
358
359 CLabelWriterDriver::quality_t
GetQuality()360 CLabelWriterDriver::GetQuality()
361 {
362 return Quality_;
363 }
364
365 size_t
GetPageHeight()366 CLabelWriterDriver::GetPageHeight()
367 {
368 return PageHeight_;
369 }
370
371 CLabelWriterDriver::paper_type_t
GetPaperType()372 CLabelWriterDriver::GetPaperType()
373 {
374 return PaperType_;
375 }
376
377 void
SetResolution(CLabelWriterDriver::resolution_t Value)378 CLabelWriterDriver::SetResolution(CLabelWriterDriver::resolution_t Value)
379 {
380 Resolution_ = Value;
381 }
382
383 void
SetDensity(CLabelWriterDriver::density_t Value)384 CLabelWriterDriver::SetDensity(CLabelWriterDriver::density_t Value)
385 {
386 Density_ = Value;
387 }
388
389 void
SetQuality(CLabelWriterDriver::quality_t Value)390 CLabelWriterDriver::SetQuality(CLabelWriterDriver::quality_t Value)
391 {
392 Quality_ = Value;
393 }
394
395 void
SetPageHeight(size_t Value)396 CLabelWriterDriver::SetPageHeight(size_t Value)
397 {
398 PageHeight_ = Value;
399 }
400
401 void
SetPaperType(CLabelWriterDriver::paper_type_t Value)402 CLabelWriterDriver::SetPaperType(CLabelWriterDriver::paper_type_t Value)
403 {
404 PaperType_ = Value;
405 }
406
407 void
SetMaxPrintWidth(size_t Value)408 CLabelWriterDriver::SetMaxPrintWidth(size_t Value)
409 {
410 MaxPrintWidth_ = Value;
411 }
412
413 void
SetPageOffset(point_t Value)414 CLabelWriterDriver::SetPageOffset(point_t Value)
415 {
416 PageOffset_ = Value;
417 }
418
419 void
SendLineTab(size_t Value)420 CLabelWriterDriver::SendLineTab(size_t Value)
421 {
422 byte buf[] = {ESC, 'Q', 0, 0};
423 buf[2] = (Value >> 8) & 0xff;
424 buf[3] = Value & 0xff;
425
426 SendCommand(buf, sizeof(buf));
427 }
428
429 void
SendDotTab(size_t Value)430 CLabelWriterDriver::SendDotTab(size_t Value)
431 {
432 byte buf[] = {ESC, 'B', 0};
433 buf[2] = Value;
434
435 SendCommand(buf, sizeof(buf));
436 }
437
438 void
SendFormFeed()439 CLabelWriterDriver::SendFormFeed()
440 {
441 byte buf[] = {ESC, 'E'};
442
443 SendCommand(buf, sizeof(buf));
444 }
445
446 void
SendBytesPerLine(size_t Value)447 CLabelWriterDriver::SendBytesPerLine(size_t Value)
448 {
449 byte buf[] = {ESC, 'D', 0};
450 buf[2] = Value;
451
452 SendCommand(buf, sizeof(buf));
453 }
454
455 void
SendSkipLines(size_t Value)456 CLabelWriterDriver::SendSkipLines(size_t Value)
457 {
458 const size_t MAX_LINES = 255;
459
460 // a hardware can skip no more 255 lines at time
461 byte buf[] = {ESC, 'f', 1, 0};
462
463 while (Value > 0)
464 {
465 if (Value > MAX_LINES)
466 {
467 buf[3] = MAX_LINES;
468 Value -= MAX_LINES;
469 }
470 else
471 {
472 buf[3] = Value;
473 Value = 0;
474 }
475
476 SendCommand(buf, sizeof(buf));
477 }
478 }
479
480 void
SendLabelLength(size_t Value)481 CLabelWriterDriver::SendLabelLength(size_t Value)
482 {
483 byte buf[] = {ESC, 'L', 0, 0};
484 buf[2] = (Value >> 8) & 0xff;
485 buf[3] = Value & 0xff;
486
487 SendCommand(buf, sizeof(buf));
488 }
489
490 void
SendResolution(resolution_t Value)491 CLabelWriterDriver::SendResolution(resolution_t Value)
492 {
493 if (Value == resUnknown)
494 return;
495
496 byte buf[] = {ESC, 0};
497 switch (Value)
498 {
499 case res136:
500 buf[1] = 'z';
501 break;
502 case res204:
503 buf[1] = 'y';
504 break;
505 default:
506 assert(0);
507 break;
508 }
509
510 SendCommand(buf, sizeof(buf));
511 }
512
513 void
SendPrintDensity(density_t Value)514 CLabelWriterDriver::SendPrintDensity(density_t Value)
515 {
516 byte buf[] = {ESC, 'e'};
517
518 switch (Value)
519 {
520 case pdLow: buf[1] = 'c'; break;
521 case pdMedium: buf[1] = 'd'; break;
522 case pdNormal: buf[1] = 'e'; break;
523 case pdHigh: buf[1] = 'g'; break;
524 default: buf[1] = 'e'; break; // normal
525 }
526
527 SendCommand(buf, sizeof(buf));
528 }
529
530 void
SendPrintQuality(quality_t Value)531 CLabelWriterDriver::SendPrintQuality(quality_t Value)
532 {
533 byte buf[] = {ESC, 'h'};
534
535 switch (Value)
536 {
537 case pqText: buf[1] = 'h'; break;
538 case pqBarcodeAndGraphics: buf[1] = 'i'; break;
539 default: buf[1] = 'h'; break; // text
540 }
541
542 SendCommand(buf, sizeof(buf));
543 }
544
545 buffer_t
GetResetCommand()546 CLabelWriterDriver::GetResetCommand()
547 {
548 return buffer_t(156, ESC);
549 }
550
551 buffer_t
GetRequestStatusCommand()552 CLabelWriterDriver::GetRequestStatusCommand()
553 {
554 byte buf[] = {ESC, 'A'};
555
556 return buffer_t(buf, buf + sizeof(buf));
557 }
558
559 size_t
GetEmptyLinesCount()560 CLabelWriterDriver::GetEmptyLinesCount()
561 {
562 return EmptyLinesCount_;
563 }
564
565 void
SetEmptyLinesCount(size_t Value)566 CLabelWriterDriver::SetEmptyLinesCount(size_t Value)
567 {
568 EmptyLinesCount_ = Value;
569 }
570
571 ////////////////////////////////////////////////////////////////
572 // CLabelWriterDriver400
573 ////////////////////////////////////////////////////////////////
574
CLabelWriterDriver400(IPrintEnvironment & Environment)575 CLabelWriterDriver400::CLabelWriterDriver400(IPrintEnvironment& Environment):
576 CLabelWriterDriver(Environment)
577 {
578 }
579
~CLabelWriterDriver400()580 CLabelWriterDriver400::~CLabelWriterDriver400()
581 {
582 }
583
584 void
StartDoc()585 CLabelWriterDriver400::StartDoc()
586 {
587 CLabelWriterDriver::StartDoc();
588 }
589
590 void
EndDoc()591 CLabelWriterDriver400::EndDoc()
592 {
593 SendFormFeed();
594 }
595
596 void
EndPage()597 CLabelWriterDriver400::EndPage()
598 {
599 SendShortFormFeed();
600 }
601
602 buffer_t
GetShortFormFeedCommand()603 CLabelWriterDriver400::GetShortFormFeedCommand()
604 {
605 byte buf[] = {ESC, 'G'};
606
607 return buffer_t(buf, buf + sizeof(buf));
608 }
609
610 void
SendShortFormFeed()611 CLabelWriterDriver400::SendShortFormFeed()
612 {
613 byte buf[] = {ESC, 'G'};
614
615 SendCommand(buf, sizeof(buf));
616 }
617
618 ////////////////////////////////////////////////////////////////
619 // CLabelWriterDriver TwinTurbo
620 ////////////////////////////////////////////////////////////////
621
CLabelWriterDriverTwinTurbo(IPrintEnvironment & Environment)622 CLabelWriterDriverTwinTurbo::CLabelWriterDriverTwinTurbo(IPrintEnvironment& Environment):
623 CLabelWriterDriver400(Environment), Roll_(rtAuto)
624 {
625 }
626
~CLabelWriterDriverTwinTurbo()627 CLabelWriterDriverTwinTurbo::~CLabelWriterDriverTwinTurbo()
628 {
629 }
630
631 void
StartDoc()632 CLabelWriterDriverTwinTurbo::StartDoc()
633 {
634 CLabelWriterDriver400::StartDoc();
635 SendRollSelect(Roll_);
636 }
637
638 CLabelWriterDriverTwinTurbo::roll_t
GetRoll()639 CLabelWriterDriverTwinTurbo::GetRoll()
640 {
641 return Roll_;
642 }
643
644 void
SetRoll(CLabelWriterDriverTwinTurbo::roll_t Value)645 CLabelWriterDriverTwinTurbo::SetRoll(CLabelWriterDriverTwinTurbo::roll_t Value)
646 {
647 Roll_ = Value;
648 }
649
650 buffer_t
GetRollSelectCommand(roll_t Value)651 CLabelWriterDriverTwinTurbo::GetRollSelectCommand(roll_t Value)
652 {
653 byte buf[] = {ESC, 'q', '0'};
654
655 switch (Value)
656 {
657 case rtLeft: buf[2] = '1'; break;
658 case rtRight: buf[2] = '2'; break;
659 default: buf[2] = '0'; break;
660 }
661
662 return buffer_t(buf, buf + sizeof(buf));
663 }
664
665 void
SendRollSelect(CLabelWriterDriverTwinTurbo::roll_t Value)666 CLabelWriterDriverTwinTurbo::SendRollSelect(CLabelWriterDriverTwinTurbo::roll_t Value)
667 {
668 buffer_t buf = GetRollSelectCommand(Value);
669
670 SendCommand(&buf[0], buf.size());
671 }
672
673
674
675 }; // namespace
676
677 /*
678 * End of "$Id: LabelWriterDriver.cpp 15934 2011-08-31 17:42:29Z pineichen $".
679 */
680