1 /*
2 * PCL6.cpp
3 * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
4 * Copyright 2003 Michael Pfeiffer.
5 */
6
7
8 #include "PCL6.h"
9
10 #include <memory.h>
11
12 #include <Alert.h>
13 #include <Bitmap.h>
14 #include <File.h>
15
16 #include "DbgMsg.h"
17 #include "DeltaRowCompression.h"
18 #include "Halftone.h"
19 #include "JobData.h"
20 #include "PackBits.h"
21 #include "PCL6Cap.h"
22 #include "PCL6Config.h"
23 #include "PCL6Rasterizer.h"
24 #include "PrinterData.h"
25 #include "UIDriver.h"
26 #include "ValidRect.h"
27
28
29 // DeltaRowStreamCompressor writes the delta row directly to the
30 // in the contructor specified stream.
31 class DeltaRowStreamCompressor : public AbstractDeltaRowCompressor
32 {
33 public:
DeltaRowStreamCompressor(int rowSize,uchar initialSeed,PCL6Writer * writer)34 DeltaRowStreamCompressor(int rowSize, uchar initialSeed,
35 PCL6Writer* writer)
36 :
37 AbstractDeltaRowCompressor(rowSize, initialSeed),
38 fWriter(writer)
39 {}
40
41 protected:
AppendByteToDeltaRow(uchar byte)42 void AppendByteToDeltaRow(uchar byte)
43 {
44 fWriter->Append(byte);
45 }
46
47 private:
48 PCL6Writer* fWriter;
49 };
50
51
PCL6Driver(BMessage * message,PrinterData * printerData,const PrinterCap * printerCap)52 PCL6Driver::PCL6Driver(BMessage* message, PrinterData* printerData,
53 const PrinterCap* printerCap)
54 :
55 GraphicsDriver(message, printerData, printerCap),
56 fWriter(NULL),
57 fMediaSide(PCL6Writer::kFrontMediaSide),
58 fHalftone(NULL)
59 {
60 }
61
62
63 void
Write(const uint8 * data,uint32 size)64 PCL6Driver::Write(const uint8* data, uint32 size)
65 {
66 WriteSpoolData(data, size);
67 }
68
69
70 bool
StartDocument()71 PCL6Driver::StartDocument()
72 {
73 try {
74 _JobStart();
75 fHalftone = new Halftone(GetJobData()->GetSurfaceType(),
76 GetJobData()->GetGamma(), GetJobData()->GetInkDensity(),
77 GetJobData()->GetDitherType());
78 return true;
79 }
80 catch (TransportException& err) {
81 return false;
82 }
83 }
84
85
86 bool
EndDocument(bool)87 PCL6Driver::EndDocument(bool)
88 {
89 try {
90 if (fHalftone)
91 delete fHalftone;
92 _JobEnd();
93 return true;
94 }
95 catch (TransportException& err) {
96 return false;
97 }
98 }
99
100
101 bool
NextBand(BBitmap * bitmap,BPoint * offset)102 PCL6Driver::NextBand(BBitmap* bitmap, BPoint* offset)
103 {
104 DBGMSG(("> nextBand\n"));
105
106 #if __GNUC__ <= 2
107 typedef auto_ptr<Rasterizer> RasterizerPointer;
108 typedef auto_ptr<DeltaRowCompressor> DeltaRowCompressorPointer;
109 #else
110 typedef shared_ptr<Rasterizer> RasterizerPointer;
111 typedef shared_ptr<DeltaRowCompressor> DeltaRowCompressorPointer;
112 #endif
113
114 try {
115 int y = (int)offset->y;
116
117 PCL6Rasterizer* rasterizer;
118 if (_UseColorMode()) {
119 #if COLOR_DEPTH == 8
120 rasterizer = new ColorRGBRasterizer(fHalftone);
121 #elif COLOR_DEPTH == 1
122 rasterizer = new ColorRasterizer(fHalftone);
123 #else
124 #error COLOR_DEPTH must be either 1 or 8!
125 #endif
126 } else
127 rasterizer = new MonochromeRasterizer(fHalftone);
128
129 RasterizerPointer _rasterizer(rasterizer);
130 bool valid = rasterizer->SetBitmap((int)offset->x, (int)offset->y,
131 bitmap, GetPageHeight());
132
133 if (valid) {
134 rasterizer->InitializeBuffer();
135
136 // Use compressor to calculate delta row size
137 DeltaRowCompressor* deltaRowCompressor = NULL;
138 if (_SupportsDeltaRowCompression()) {
139 deltaRowCompressor =
140 new DeltaRowCompressor(rasterizer->GetOutRowSize(), 0);
141 if (deltaRowCompressor->InitCheck() != B_OK) {
142 delete deltaRowCompressor;
143 return false;
144 }
145 }
146 DeltaRowCompressorPointer _deltaRowCompressor(deltaRowCompressor);
147 int deltaRowSize = 0;
148
149 // remember position
150 int xPage = rasterizer->GetX();
151 int yPage = rasterizer->GetY();
152
153 while (rasterizer->HasNextLine()) {
154 const uchar* rowBuffer =
155 static_cast<const uchar*>(rasterizer->RasterizeNextLine());
156
157 if (deltaRowCompressor != NULL) {
158 int size =
159 deltaRowCompressor->CalculateSize(rowBuffer, true);
160 deltaRowSize += size + 2;
161 // two bytes for the row byte count
162 }
163 }
164
165 y = rasterizer->GetY();
166
167 uchar* outBuffer = rasterizer->GetOutBuffer();
168 int outBufferSize = rasterizer->GetOutBufferSize();
169 int outRowSize = rasterizer->GetOutRowSize();
170 int width = rasterizer->GetWidth();
171 int height = rasterizer->GetHeight();
172 _WriteBitmap(outBuffer, outBufferSize, outRowSize, xPage, yPage,
173 width, height, deltaRowSize);
174 }
175
176 if (y >= GetPageHeight()) {
177 offset->x = -1.0;
178 offset->y = -1.0;
179 } else {
180 offset->y += bitmap->Bounds().IntegerHeight()+1;
181 }
182
183 return true;
184 }
185 catch (TransportException& err) {
186 BAlert* alert = new BAlert("", err.What(), "OK");
187 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
188 alert->Go();
189 return false;
190 }
191 }
192
193
194 void
_WriteBitmap(const uchar * buffer,int outSize,int rowSize,int x,int y,int width,int height,int deltaRowSize)195 PCL6Driver::_WriteBitmap(const uchar* buffer, int outSize, int rowSize, int x,
196 int y, int width, int height, int deltaRowSize)
197 {
198 // choose the best compression method
199 PCL6Writer::Compression compressionMethod = PCL6Writer::kNoCompression;
200 int dataSize = outSize;
201
202 #if ENABLE_DELTA_ROW_COMPRESSION
203 if (_SupportsDeltaRowCompression() && deltaRowSize < dataSize) {
204 compressionMethod = PCL6Writer::kDeltaRowCompression;
205 dataSize = deltaRowSize;
206 }
207 #endif
208
209 #if ENABLE_RLE_COMPRESSION
210 if (_SupportsRLECompression()) {
211 int rleSize = pack_bits_size(buffer, outSize);
212 if (rleSize < dataSize) {
213 compressionMethod = PCL6Writer::kRLECompression;
214 dataSize = rleSize;
215 }
216 }
217 #endif
218
219 // write bitmap
220 _Move(x, y);
221
222 _StartRasterGraphics(x, y, width, height, compressionMethod);
223
224 _RasterGraphics(buffer, outSize, dataSize, rowSize, height,
225 compressionMethod);
226
227 _EndRasterGraphics();
228
229 #if DISPLAY_COMPRESSION_STATISTICS
230 fprintf(stderr, "Out Size %d %2.2f\n", (int)outSize, 100.0);
231 #if ENABLE_RLE_COMPRESSION
232 fprintf(stderr, "RLE Size %d %2.2f\n", (int)rleSize,
233 100.0 * rleSize / outSize);
234 #endif
235 #if ENABLE_DELTA_ROW_COMPRESSION
236 fprintf(stderr, "Delta Row Size %d %2.2f\n", (int)deltaRowSize,
237 100.0 * deltaRowSize / outSize);
238 #endif
239 fprintf(stderr, "Data Size %d %2.2f\n", (int)dataSize,
240 100.0 * dataSize / outSize);
241 #endif
242 }
243
244
245 void
_JobStart()246 PCL6Driver::_JobStart()
247 {
248 // PCL6 begin
249 fWriter = new PCL6Writer(this);
250 PCL6Writer::ProtocolClass pc =
251 (PCL6Writer::ProtocolClass)GetProtocolClass();
252 fWriter->PJLHeader(pc, GetJobData()->GetXres(),
253 "Copyright (c) 2003 - 2010 Haiku");
254 fWriter->BeginSession(GetJobData()->GetXres(), GetJobData()->GetYres(),
255 PCL6Writer::kInch, PCL6Writer::kBackChAndErrPage);
256 fWriter->OpenDataSource();
257 fMediaSide = PCL6Writer::kFrontMediaSide;
258 }
259
260
261 bool
StartPage(int)262 PCL6Driver::StartPage(int)
263 {
264 PCL6Writer::Orientation orientation = PCL6Writer::kPortrait;
265 if (GetJobData()->GetOrientation() == JobData::kLandscape) {
266 orientation = PCL6Writer::kLandscape;
267 }
268
269 PCL6Writer::MediaSize mediaSize =
270 _MediaSize(GetJobData()->GetPaper());
271 PCL6Writer::MediaSource mediaSource =
272 _MediaSource(GetJobData()->GetPaperSource());
273 if (GetJobData()->GetPrintStyle() == JobData::kSimplex) {
274 fWriter->BeginPage(orientation, mediaSize, mediaSource);
275 } else if (GetJobData()->GetPrintStyle() == JobData::kDuplex) {
276 // TODO move duplex binding option to UI
277 fWriter->BeginPage(orientation, mediaSize, mediaSource,
278 PCL6Writer::kDuplexVerticalBinding, fMediaSide);
279
280 if (fMediaSide == PCL6Writer::kFrontMediaSide)
281 fMediaSide = PCL6Writer::kBackMediaSide;
282 else
283 fMediaSide = PCL6Writer::kFrontMediaSide;
284 } else
285 return false;
286
287 // PageOrigin from Windows NT printer driver
288 int x = 142 * GetJobData()->GetXres() / 600;
289 int y = 100 * GetJobData()->GetYres() / 600;
290 fWriter->SetPageOrigin(x, y);
291 fWriter->SetColorSpace(_UseColorMode() ? PCL6Writer::kRGB
292 : PCL6Writer::kGray);
293 fWriter->SetPaintTxMode(PCL6Writer::kOpaque);
294 fWriter->SetSourceTxMode(PCL6Writer::kOpaque);
295 fWriter->SetROP(204);
296 return true;
297 }
298
299
300 void
_StartRasterGraphics(int x,int y,int width,int height,PCL6Writer::Compression compressionMethod)301 PCL6Driver::_StartRasterGraphics(int x, int y, int width, int height,
302 PCL6Writer::Compression compressionMethod)
303 {
304 PCL6Writer::ColorDepth colorDepth;
305 if (_UseColorMode()) {
306 #if COLOR_DEPTH == 8
307 colorDepth = PCL6Writer::k8Bit;
308 #elif COLOR_DEPTH == 1
309 colorDepth = PCL6Writer::k1Bit;
310 #else
311 #error COLOR_DEPTH must be either 1 or 8!
312 #endif
313 } else
314 colorDepth = PCL6Writer::k1Bit;
315
316 fWriter->BeginImage(PCL6Writer::kDirectPixel, colorDepth, width, height,
317 width, height);
318 fWriter->ReadImage(compressionMethod, 0, height);
319 }
320
321
322 void
_EndRasterGraphics()323 PCL6Driver::_EndRasterGraphics()
324 {
325 fWriter->EndImage();
326 }
327
328
329 void
_RasterGraphics(const uchar * buffer,int bufferSize,int dataSize,int rowSize,int height,int compressionMethod)330 PCL6Driver::_RasterGraphics(const uchar* buffer, int bufferSize, int dataSize,
331 int rowSize, int height, int compressionMethod)
332 {
333 // write bitmap byte size
334 fWriter->EmbeddedDataPrefix32(dataSize);
335
336 // write data
337 if (compressionMethod == PCL6Writer::kRLECompression) {
338 // use RLE compression
339 uchar* outBuffer = new uchar[dataSize];
340 pack_bits(outBuffer, buffer, bufferSize);
341 fWriter->Append(outBuffer, dataSize);
342 delete[] outBuffer;
343 return;
344 } else if (compressionMethod == PCL6Writer::kDeltaRowCompression) {
345 // use delta row compression
346 DeltaRowStreamCompressor compressor(rowSize, 0, fWriter);
347 if (compressor.InitCheck() != B_OK) {
348 return;
349 }
350
351 const uint8* row = buffer;
352 for (int i = 0; i < height; i ++) {
353 // write row byte count
354 int32 size = compressor.CalculateSize(row);
355 fWriter->Append((uint16)size);
356
357 if (size > 0) {
358 // write delta row
359 compressor.Compress(row);
360 }
361
362 row += rowSize;
363 }
364 } else {
365 // write raw data
366 fWriter->Append(buffer, bufferSize);
367 }
368 }
369
370
371 bool
EndPage(int)372 PCL6Driver::EndPage(int)
373 {
374 try {
375 fWriter->EndPage(GetJobData()->GetCopies());
376 return true;
377 }
378 catch (TransportException& err) {
379 return false;
380 }
381 }
382
383
384 void
_JobEnd()385 PCL6Driver::_JobEnd()
386 {
387 fWriter->CloseDataSource();
388 fWriter->EndSession();
389 fWriter->PJLFooter();
390 fWriter->Flush();
391 delete fWriter;
392 fWriter = NULL;
393 }
394
395
396 void
_Move(int x,int y)397 PCL6Driver::_Move(int x, int y)
398 {
399 fWriter->SetCursor(x, y);
400 }
401
402
403 bool
_SupportsRLECompression()404 PCL6Driver::_SupportsRLECompression()
405 {
406 return GetJobData()->GetColor() != JobData::kColorCompressionDisabled;
407 }
408
409
410 bool
_SupportsDeltaRowCompression()411 PCL6Driver::_SupportsDeltaRowCompression()
412 {
413 return GetProtocolClass() >= PCL6Writer::kProtocolClass2_1
414 && GetJobData()->GetColor() != JobData::kColorCompressionDisabled;
415 }
416
417
418 bool
_UseColorMode()419 PCL6Driver::_UseColorMode()
420 {
421 return GetJobData()->GetColor() != JobData::kMonochrome;
422 }
423
424
425 PCL6Writer::MediaSize
_MediaSize(JobData::Paper paper)426 PCL6Driver::_MediaSize(JobData::Paper paper)
427 {
428 switch (paper) {
429 case JobData::kLetter:
430 return PCL6Writer::kLetterPaper;
431 case JobData::kLegal:
432 return PCL6Writer::kLegalPaper;
433 case JobData::kA4:
434 return PCL6Writer::kA4Paper;
435 case JobData::kExecutive:
436 return PCL6Writer::kExecPaper;
437 case JobData::kLedger:
438 return PCL6Writer::kLedgerPaper;
439 case JobData::kA3:
440 return PCL6Writer::kA3Paper;
441 case JobData::kB5:
442 return PCL6Writer::kB5Paper;
443 case JobData::kJapanesePostcard:
444 return PCL6Writer::kJPostcard;
445 case JobData::kA5:
446 return PCL6Writer::kA5Paper;
447 case JobData::kB4:
448 return PCL6Writer::kJB4Paper;
449 /*
450 case : return PCL6Writer::kCOM10Envelope;
451 case : return PCL6Writer::kMonarchEnvelope;
452 case : return PCL6Writer::kC5Envelope;
453 case : return PCL6Writer::kDLEnvelope;
454 case : return PCL6Writer::kJB4Paper;
455 case : return PCL6Writer::kJB5Paper;
456 case : return PCL6Writer::kB5Envelope;
457 case : return PCL6Writer::kJPostcard;
458 case : return PCL6Writer::kJDoublePostcard;
459 case : return PCL6Writer::kA5Paper;
460 case : return PCL6Writer::kA6Paper;
461 case : return PCL6Writer::kJB6Paper;
462 case : return PCL6Writer::kJIS8KPaper;
463 case : return PCL6Writer::kJIS16KPaper;
464 case : return PCL6Writer::kJISExecPaper;
465 */
466 default:
467 return PCL6Writer::kLegalPaper;
468 }
469 }
470
471
472 PCL6Writer::MediaSource
_MediaSource(JobData::PaperSource source)473 PCL6Driver::_MediaSource(JobData::PaperSource source)
474 {
475 switch (source) {
476 case JobData::kAuto:
477 return PCL6Writer::kAutoSelect;
478 case JobData::kCassette1:
479 return PCL6Writer::kDefaultSource;
480 case JobData::kCassette2:
481 return PCL6Writer::kEnvelopeTray;
482 case JobData::kLower:
483 return PCL6Writer::kLowerCassette;
484 case JobData::kUpper:
485 return PCL6Writer::kUpperCassette;
486 case JobData::kMiddle:
487 return PCL6Writer::kThirdCassette;
488 case JobData::kManual:
489 return PCL6Writer::kManualFeed;
490 case JobData::kCassette3:
491 return PCL6Writer::kMultiPurposeTray;
492 default:
493 return PCL6Writer::kAutoSelect;
494 }
495 }
496