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 #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 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 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 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 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 323 PCL6Driver::_EndRasterGraphics() 324 { 325 fWriter->EndImage(); 326 } 327 328 329 void 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 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 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 397 PCL6Driver::_Move(int x, int y) 398 { 399 fWriter->SetCursor(x, y); 400 } 401 402 403 bool 404 PCL6Driver::_SupportsRLECompression() 405 { 406 return GetJobData()->GetColor() != JobData::kColorCompressionDisabled; 407 } 408 409 410 bool 411 PCL6Driver::_SupportsDeltaRowCompression() 412 { 413 return GetProtocolClass() >= PCL6Writer::kProtocolClass2_1 414 && GetJobData()->GetColor() != JobData::kColorCompressionDisabled; 415 } 416 417 418 bool 419 PCL6Driver::_UseColorMode() 420 { 421 return GetJobData()->GetColor() != JobData::kMonochrome; 422 } 423 424 425 PCL6Writer::MediaSize 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 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