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