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->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 180 alert->Go(); 181 return false; 182 } 183 } 184 185 186 void 187 PCL6Driver::_WriteBitmap(const uchar* buffer, int outSize, int rowSize, int x, 188 int y, int width, int height, int deltaRowSize) 189 { 190 // choose the best compression method 191 PCL6Writer::Compression compressionMethod = PCL6Writer::kNoCompression; 192 int dataSize = outSize; 193 194 #if ENABLE_DELTA_ROW_COMPRESSION 195 if (_SupportsDeltaRowCompression() && deltaRowSize < dataSize) { 196 compressionMethod = PCL6Writer::kDeltaRowCompression; 197 dataSize = deltaRowSize; 198 } 199 #endif 200 201 #if ENABLE_RLE_COMPRESSION 202 if (_SupportsRLECompression()) { 203 int rleSize = pack_bits_size(buffer, outSize); 204 if (rleSize < dataSize) { 205 compressionMethod = PCL6Writer::kRLECompression; 206 dataSize = rleSize; 207 } 208 } 209 #endif 210 211 // write bitmap 212 _Move(x, y); 213 214 _StartRasterGraphics(x, y, width, height, compressionMethod); 215 216 _RasterGraphics(buffer, outSize, dataSize, rowSize, height, 217 compressionMethod); 218 219 _EndRasterGraphics(); 220 221 #if DISPLAY_COMPRESSION_STATISTICS 222 fprintf(stderr, "Out Size %d %2.2f\n", (int)outSize, 100.0); 223 #if ENABLE_RLE_COMPRESSION 224 fprintf(stderr, "RLE Size %d %2.2f\n", (int)rleSize, 225 100.0 * rleSize / outSize); 226 #endif 227 #if ENABLE_DELTA_ROW_COMPRESSION 228 fprintf(stderr, "Delta Row Size %d %2.2f\n", (int)deltaRowSize, 229 100.0 * deltaRowSize / outSize); 230 #endif 231 fprintf(stderr, "Data Size %d %2.2f\n", (int)dataSize, 232 100.0 * dataSize / outSize); 233 #endif 234 } 235 236 237 void 238 PCL6Driver::_JobStart() 239 { 240 // PCL6 begin 241 fWriter = new PCL6Writer(this); 242 PCL6Writer::ProtocolClass pc = 243 (PCL6Writer::ProtocolClass)GetProtocolClass(); 244 fWriter->PJLHeader(pc, GetJobData()->GetXres(), 245 "Copyright (c) 2003 - 2010 Haiku"); 246 fWriter->BeginSession(GetJobData()->GetXres(), GetJobData()->GetYres(), 247 PCL6Writer::kInch, PCL6Writer::kBackChAndErrPage); 248 fWriter->OpenDataSource(); 249 fMediaSide = PCL6Writer::kFrontMediaSide; 250 } 251 252 253 bool 254 PCL6Driver::StartPage(int) 255 { 256 PCL6Writer::Orientation orientation = PCL6Writer::kPortrait; 257 if (GetJobData()->GetOrientation() == JobData::kLandscape) { 258 orientation = PCL6Writer::kLandscape; 259 } 260 261 PCL6Writer::MediaSize mediaSize = 262 _MediaSize(GetJobData()->GetPaper()); 263 PCL6Writer::MediaSource mediaSource = 264 _MediaSource(GetJobData()->GetPaperSource()); 265 if (GetJobData()->GetPrintStyle() == JobData::kSimplex) { 266 fWriter->BeginPage(orientation, mediaSize, mediaSource); 267 } else if (GetJobData()->GetPrintStyle() == JobData::kDuplex) { 268 // TODO move duplex binding option to UI 269 fWriter->BeginPage(orientation, mediaSize, mediaSource, 270 PCL6Writer::kDuplexVerticalBinding, fMediaSide); 271 272 if (fMediaSide == PCL6Writer::kFrontMediaSide) 273 fMediaSide = PCL6Writer::kBackMediaSide; 274 else 275 fMediaSide = PCL6Writer::kFrontMediaSide; 276 } else 277 return false; 278 279 // PageOrigin from Windows NT printer driver 280 int x = 142 * GetJobData()->GetXres() / 600; 281 int y = 100 * GetJobData()->GetYres() / 600; 282 fWriter->SetPageOrigin(x, y); 283 fWriter->SetColorSpace(_UseColorMode() ? PCL6Writer::kRGB 284 : PCL6Writer::kGray); 285 fWriter->SetPaintTxMode(PCL6Writer::kOpaque); 286 fWriter->SetSourceTxMode(PCL6Writer::kOpaque); 287 fWriter->SetROP(204); 288 return true; 289 } 290 291 292 void 293 PCL6Driver::_StartRasterGraphics(int x, int y, int width, int height, 294 PCL6Writer::Compression compressionMethod) 295 { 296 PCL6Writer::ColorDepth colorDepth; 297 if (_UseColorMode()) { 298 #if COLOR_DEPTH == 8 299 colorDepth = PCL6Writer::k8Bit; 300 #elif COLOR_DEPTH == 1 301 colorDepth = PCL6Writer::k1Bit; 302 #else 303 #error COLOR_DEPTH must be either 1 or 8! 304 #endif 305 } else 306 colorDepth = PCL6Writer::k1Bit; 307 308 fWriter->BeginImage(PCL6Writer::kDirectPixel, colorDepth, width, height, 309 width, height); 310 fWriter->ReadImage(compressionMethod, 0, height); 311 } 312 313 314 void 315 PCL6Driver::_EndRasterGraphics() 316 { 317 fWriter->EndImage(); 318 } 319 320 321 void 322 PCL6Driver::_RasterGraphics(const uchar* buffer, int bufferSize, int dataSize, 323 int rowSize, int height, int compressionMethod) 324 { 325 // write bitmap byte size 326 fWriter->EmbeddedDataPrefix32(dataSize); 327 328 // write data 329 if (compressionMethod == PCL6Writer::kRLECompression) { 330 // use RLE compression 331 uchar* outBuffer = new uchar[dataSize]; 332 pack_bits(outBuffer, buffer, bufferSize); 333 fWriter->Append(outBuffer, dataSize); 334 delete[] outBuffer; 335 return; 336 } else if (compressionMethod == PCL6Writer::kDeltaRowCompression) { 337 // use delta row compression 338 DeltaRowStreamCompressor compressor(rowSize, 0, fWriter); 339 if (compressor.InitCheck() != B_OK) { 340 return; 341 } 342 343 const uint8* row = buffer; 344 for (int i = 0; i < height; i ++) { 345 // write row byte count 346 int32 size = compressor.CalculateSize(row); 347 fWriter->Append((uint16)size); 348 349 if (size > 0) { 350 // write delta row 351 compressor.Compress(row); 352 } 353 354 row += rowSize; 355 } 356 } else { 357 // write raw data 358 fWriter->Append(buffer, bufferSize); 359 } 360 } 361 362 363 bool 364 PCL6Driver::EndPage(int) 365 { 366 try { 367 fWriter->EndPage(GetJobData()->GetCopies()); 368 return true; 369 } 370 catch (TransportException& err) { 371 return false; 372 } 373 } 374 375 376 void 377 PCL6Driver::_JobEnd() 378 { 379 fWriter->CloseDataSource(); 380 fWriter->EndSession(); 381 fWriter->PJLFooter(); 382 fWriter->Flush(); 383 delete fWriter; 384 fWriter = NULL; 385 } 386 387 388 void 389 PCL6Driver::_Move(int x, int y) 390 { 391 fWriter->SetCursor(x, y); 392 } 393 394 395 bool 396 PCL6Driver::_SupportsRLECompression() 397 { 398 return GetJobData()->GetColor() != JobData::kColorCompressionDisabled; 399 } 400 401 402 bool 403 PCL6Driver::_SupportsDeltaRowCompression() 404 { 405 return GetProtocolClass() >= PCL6Writer::kProtocolClass2_1 406 && GetJobData()->GetColor() != JobData::kColorCompressionDisabled; 407 } 408 409 410 bool 411 PCL6Driver::_UseColorMode() 412 { 413 return GetJobData()->GetColor() != JobData::kMonochrome; 414 } 415 416 417 PCL6Writer::MediaSize 418 PCL6Driver::_MediaSize(JobData::Paper paper) 419 { 420 switch (paper) { 421 case JobData::kLetter: 422 return PCL6Writer::kLetterPaper; 423 case JobData::kLegal: 424 return PCL6Writer::kLegalPaper; 425 case JobData::kA4: 426 return PCL6Writer::kA4Paper; 427 case JobData::kExecutive: 428 return PCL6Writer::kExecPaper; 429 case JobData::kLedger: 430 return PCL6Writer::kLedgerPaper; 431 case JobData::kA3: 432 return PCL6Writer::kA3Paper; 433 case JobData::kB5: 434 return PCL6Writer::kB5Paper; 435 case JobData::kJapanesePostcard: 436 return PCL6Writer::kJPostcard; 437 case JobData::kA5: 438 return PCL6Writer::kA5Paper; 439 case JobData::kB4: 440 return PCL6Writer::kJB4Paper; 441 /* 442 case : return PCL6Writer::kCOM10Envelope; 443 case : return PCL6Writer::kMonarchEnvelope; 444 case : return PCL6Writer::kC5Envelope; 445 case : return PCL6Writer::kDLEnvelope; 446 case : return PCL6Writer::kJB4Paper; 447 case : return PCL6Writer::kJB5Paper; 448 case : return PCL6Writer::kB5Envelope; 449 case : return PCL6Writer::kJPostcard; 450 case : return PCL6Writer::kJDoublePostcard; 451 case : return PCL6Writer::kA5Paper; 452 case : return PCL6Writer::kA6Paper; 453 case : return PCL6Writer::kJB6Paper; 454 case : return PCL6Writer::kJIS8KPaper; 455 case : return PCL6Writer::kJIS16KPaper; 456 case : return PCL6Writer::kJISExecPaper; 457 */ 458 default: 459 return PCL6Writer::kLegalPaper; 460 } 461 } 462 463 464 PCL6Writer::MediaSource 465 PCL6Driver::_MediaSource(JobData::PaperSource source) 466 { 467 switch (source) { 468 case JobData::kAuto: 469 return PCL6Writer::kAutoSelect; 470 case JobData::kCassette1: 471 return PCL6Writer::kDefaultSource; 472 case JobData::kCassette2: 473 return PCL6Writer::kEnvelopeTray; 474 case JobData::kLower: 475 return PCL6Writer::kLowerCassette; 476 case JobData::kUpper: 477 return PCL6Writer::kUpperCassette; 478 case JobData::kMiddle: 479 return PCL6Writer::kThirdCassette; 480 case JobData::kManual: 481 return PCL6Writer::kManualFeed; 482 case JobData::kCassette3: 483 return PCL6Writer::kMultiPurposeTray; 484 default: 485 return PCL6Writer::kAutoSelect; 486 } 487 } 488