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