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. 31class DeltaRowStreamCompressor : public AbstractDeltaRowCompressor 32{ 33public: 34 DeltaRowStreamCompressor(int rowSize, uchar initialSeed, 35 PCL6Writer* writer) 36 : 37 AbstractDeltaRowCompressor(rowSize, initialSeed), 38 fWriter(writer) 39 {} 40 41protected: 42 void AppendByteToDeltaRow(uchar byte) 43 { 44 fWriter->Append(byte); 45 } 46 47private: 48 PCL6Writer* fWriter; 49}; 50 51 52PCL6Driver::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 63void 64PCL6Driver::Write(const uint8* data, uint32 size) 65{ 66 WriteSpoolData(data, size); 67} 68 69 70bool 71PCL6Driver::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 86bool 87PCL6Driver::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 101bool 102PCL6Driver::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 194void 195PCL6Driver::_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 245void 246PCL6Driver::_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 261bool 262PCL6Driver::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 300void 301PCL6Driver::_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 322void 323PCL6Driver::_EndRasterGraphics() 324{ 325 fWriter->EndImage(); 326} 327 328 329void 330PCL6Driver::_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 371bool 372PCL6Driver::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 384void 385PCL6Driver::_JobEnd() 386{ 387 fWriter->CloseDataSource(); 388 fWriter->EndSession(); 389 fWriter->PJLFooter(); 390 fWriter->Flush(); 391 delete fWriter; 392 fWriter = NULL; 393} 394 395 396void 397PCL6Driver::_Move(int x, int y) 398{ 399 fWriter->SetCursor(x, y); 400} 401 402 403bool 404PCL6Driver::_SupportsRLECompression() 405{ 406 return GetJobData()->GetColor() != JobData::kColorCompressionDisabled; 407} 408 409 410bool 411PCL6Driver::_SupportsDeltaRowCompression() 412{ 413 return GetProtocolClass() >= PCL6Writer::kProtocolClass2_1 414 && GetJobData()->GetColor() != JobData::kColorCompressionDisabled; 415} 416 417 418bool 419PCL6Driver::_UseColorMode() 420{ 421 return GetJobData()->GetColor() != JobData::kMonochrome; 422} 423 424 425PCL6Writer::MediaSize 426PCL6Driver::_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 472PCL6Writer::MediaSource 473PCL6Driver::_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