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