/* * PCL6.cpp * Copyright 1999-2000 Y.Takagi. All Rights Reserved. * Copyright 2003 Michael Pfeiffer. */ #include "PCL6.h" #include #include #include #include #include "DbgMsg.h" #include "DeltaRowCompression.h" #include "Halftone.h" #include "JobData.h" #include "PackBits.h" #include "PCL6Cap.h" #include "PCL6Config.h" #include "PCL6Rasterizer.h" #include "PrinterData.h" #include "UIDriver.h" #include "ValidRect.h" // DeltaRowStreamCompressor writes the delta row directly to the // in the contructor specified stream. class DeltaRowStreamCompressor : public AbstractDeltaRowCompressor { public: DeltaRowStreamCompressor(int rowSize, uchar initialSeed, PCL6Writer* writer) : AbstractDeltaRowCompressor(rowSize, initialSeed), fWriter(writer) {} protected: void AppendByteToDeltaRow(uchar byte) { fWriter->Append(byte); } private: PCL6Writer* fWriter; }; PCL6Driver::PCL6Driver(BMessage* message, PrinterData* printerData, const PrinterCap* printerCap) : GraphicsDriver(message, printerData, printerCap), fWriter(NULL), fMediaSide(PCL6Writer::kFrontMediaSide), fHalftone(NULL) { } void PCL6Driver::Write(const uint8* data, uint32 size) { WriteSpoolData(data, size); } bool PCL6Driver::StartDocument() { try { _JobStart(); fHalftone = new Halftone(GetJobData()->GetSurfaceType(), GetJobData()->GetGamma(), GetJobData()->GetInkDensity(), GetJobData()->GetDitherType()); return true; } catch (TransportException& err) { return false; } } bool PCL6Driver::EndDocument(bool) { try { if (fHalftone) delete fHalftone; _JobEnd(); return true; } catch (TransportException& err) { return false; } } bool PCL6Driver::NextBand(BBitmap* bitmap, BPoint* offset) { DBGMSG(("> nextBand\n")); #if __GNUC__ <= 2 typedef auto_ptr RasterizerPointer; typedef auto_ptr DeltaRowCompressorPointer; #else typedef shared_ptr RasterizerPointer; typedef shared_ptr DeltaRowCompressorPointer; #endif try { int y = (int)offset->y; PCL6Rasterizer* rasterizer; if (_UseColorMode()) { #if COLOR_DEPTH == 8 rasterizer = new ColorRGBRasterizer(fHalftone); #elif COLOR_DEPTH == 1 rasterizer = new ColorRasterizer(fHalftone); #else #error COLOR_DEPTH must be either 1 or 8! #endif } else rasterizer = new MonochromeRasterizer(fHalftone); RasterizerPointer _rasterizer(rasterizer); bool valid = rasterizer->SetBitmap((int)offset->x, (int)offset->y, bitmap, GetPageHeight()); if (valid) { rasterizer->InitializeBuffer(); // Use compressor to calculate delta row size DeltaRowCompressor* deltaRowCompressor = NULL; if (_SupportsDeltaRowCompression()) { deltaRowCompressor = new DeltaRowCompressor(rasterizer->GetOutRowSize(), 0); if (deltaRowCompressor->InitCheck() != B_OK) { delete deltaRowCompressor; return false; } } DeltaRowCompressorPointer _deltaRowCompressor(deltaRowCompressor); int deltaRowSize = 0; // remember position int xPage = rasterizer->GetX(); int yPage = rasterizer->GetY(); while (rasterizer->HasNextLine()) { const uchar* rowBuffer = static_cast(rasterizer->RasterizeNextLine()); if (deltaRowCompressor != NULL) { int size = deltaRowCompressor->CalculateSize(rowBuffer, true); deltaRowSize += size + 2; // two bytes for the row byte count } } y = rasterizer->GetY(); uchar* outBuffer = rasterizer->GetOutBuffer(); int outBufferSize = rasterizer->GetOutBufferSize(); int outRowSize = rasterizer->GetOutRowSize(); int width = rasterizer->GetWidth(); int height = rasterizer->GetHeight(); _WriteBitmap(outBuffer, outBufferSize, outRowSize, xPage, yPage, width, height, deltaRowSize); } if (y >= GetPageHeight()) { offset->x = -1.0; offset->y = -1.0; } else { offset->y += bitmap->Bounds().IntegerHeight()+1; } return true; } catch (TransportException& err) { BAlert* alert = new BAlert("", err.What(), "OK"); alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); alert->Go(); return false; } } void PCL6Driver::_WriteBitmap(const uchar* buffer, int outSize, int rowSize, int x, int y, int width, int height, int deltaRowSize) { // choose the best compression method PCL6Writer::Compression compressionMethod = PCL6Writer::kNoCompression; int dataSize = outSize; #if ENABLE_DELTA_ROW_COMPRESSION if (_SupportsDeltaRowCompression() && deltaRowSize < dataSize) { compressionMethod = PCL6Writer::kDeltaRowCompression; dataSize = deltaRowSize; } #endif #if ENABLE_RLE_COMPRESSION if (_SupportsRLECompression()) { int rleSize = pack_bits_size(buffer, outSize); if (rleSize < dataSize) { compressionMethod = PCL6Writer::kRLECompression; dataSize = rleSize; } } #endif // write bitmap _Move(x, y); _StartRasterGraphics(x, y, width, height, compressionMethod); _RasterGraphics(buffer, outSize, dataSize, rowSize, height, compressionMethod); _EndRasterGraphics(); #if DISPLAY_COMPRESSION_STATISTICS fprintf(stderr, "Out Size %d %2.2f\n", (int)outSize, 100.0); #if ENABLE_RLE_COMPRESSION fprintf(stderr, "RLE Size %d %2.2f\n", (int)rleSize, 100.0 * rleSize / outSize); #endif #if ENABLE_DELTA_ROW_COMPRESSION fprintf(stderr, "Delta Row Size %d %2.2f\n", (int)deltaRowSize, 100.0 * deltaRowSize / outSize); #endif fprintf(stderr, "Data Size %d %2.2f\n", (int)dataSize, 100.0 * dataSize / outSize); #endif } void PCL6Driver::_JobStart() { // PCL6 begin fWriter = new PCL6Writer(this); PCL6Writer::ProtocolClass pc = (PCL6Writer::ProtocolClass)GetProtocolClass(); fWriter->PJLHeader(pc, GetJobData()->GetXres(), "Copyright (c) 2003 - 2010 Haiku"); fWriter->BeginSession(GetJobData()->GetXres(), GetJobData()->GetYres(), PCL6Writer::kInch, PCL6Writer::kBackChAndErrPage); fWriter->OpenDataSource(); fMediaSide = PCL6Writer::kFrontMediaSide; } bool PCL6Driver::StartPage(int) { PCL6Writer::Orientation orientation = PCL6Writer::kPortrait; if (GetJobData()->GetOrientation() == JobData::kLandscape) { orientation = PCL6Writer::kLandscape; } PCL6Writer::MediaSize mediaSize = _MediaSize(GetJobData()->GetPaper()); PCL6Writer::MediaSource mediaSource = _MediaSource(GetJobData()->GetPaperSource()); if (GetJobData()->GetPrintStyle() == JobData::kSimplex) { fWriter->BeginPage(orientation, mediaSize, mediaSource); } else if (GetJobData()->GetPrintStyle() == JobData::kDuplex) { // TODO move duplex binding option to UI fWriter->BeginPage(orientation, mediaSize, mediaSource, PCL6Writer::kDuplexVerticalBinding, fMediaSide); if (fMediaSide == PCL6Writer::kFrontMediaSide) fMediaSide = PCL6Writer::kBackMediaSide; else fMediaSide = PCL6Writer::kFrontMediaSide; } else return false; // PageOrigin from Windows NT printer driver int x = 142 * GetJobData()->GetXres() / 600; int y = 100 * GetJobData()->GetYres() / 600; fWriter->SetPageOrigin(x, y); fWriter->SetColorSpace(_UseColorMode() ? PCL6Writer::kRGB : PCL6Writer::kGray); fWriter->SetPaintTxMode(PCL6Writer::kOpaque); fWriter->SetSourceTxMode(PCL6Writer::kOpaque); fWriter->SetROP(204); return true; } void PCL6Driver::_StartRasterGraphics(int x, int y, int width, int height, PCL6Writer::Compression compressionMethod) { PCL6Writer::ColorDepth colorDepth; if (_UseColorMode()) { #if COLOR_DEPTH == 8 colorDepth = PCL6Writer::k8Bit; #elif COLOR_DEPTH == 1 colorDepth = PCL6Writer::k1Bit; #else #error COLOR_DEPTH must be either 1 or 8! #endif } else colorDepth = PCL6Writer::k1Bit; fWriter->BeginImage(PCL6Writer::kDirectPixel, colorDepth, width, height, width, height); fWriter->ReadImage(compressionMethod, 0, height); } void PCL6Driver::_EndRasterGraphics() { fWriter->EndImage(); } void PCL6Driver::_RasterGraphics(const uchar* buffer, int bufferSize, int dataSize, int rowSize, int height, int compressionMethod) { // write bitmap byte size fWriter->EmbeddedDataPrefix32(dataSize); // write data if (compressionMethod == PCL6Writer::kRLECompression) { // use RLE compression uchar* outBuffer = new uchar[dataSize]; pack_bits(outBuffer, buffer, bufferSize); fWriter->Append(outBuffer, dataSize); delete[] outBuffer; return; } else if (compressionMethod == PCL6Writer::kDeltaRowCompression) { // use delta row compression DeltaRowStreamCompressor compressor(rowSize, 0, fWriter); if (compressor.InitCheck() != B_OK) { return; } const uint8* row = buffer; for (int i = 0; i < height; i ++) { // write row byte count int32 size = compressor.CalculateSize(row); fWriter->Append((uint16)size); if (size > 0) { // write delta row compressor.Compress(row); } row += rowSize; } } else { // write raw data fWriter->Append(buffer, bufferSize); } } bool PCL6Driver::EndPage(int) { try { fWriter->EndPage(GetJobData()->GetCopies()); return true; } catch (TransportException& err) { return false; } } void PCL6Driver::_JobEnd() { fWriter->CloseDataSource(); fWriter->EndSession(); fWriter->PJLFooter(); fWriter->Flush(); delete fWriter; fWriter = NULL; } void PCL6Driver::_Move(int x, int y) { fWriter->SetCursor(x, y); } bool PCL6Driver::_SupportsRLECompression() { return GetJobData()->GetColor() != JobData::kColorCompressionDisabled; } bool PCL6Driver::_SupportsDeltaRowCompression() { return GetProtocolClass() >= PCL6Writer::kProtocolClass2_1 && GetJobData()->GetColor() != JobData::kColorCompressionDisabled; } bool PCL6Driver::_UseColorMode() { return GetJobData()->GetColor() != JobData::kMonochrome; } PCL6Writer::MediaSize PCL6Driver::_MediaSize(JobData::Paper paper) { switch (paper) { case JobData::kLetter: return PCL6Writer::kLetterPaper; case JobData::kLegal: return PCL6Writer::kLegalPaper; case JobData::kA4: return PCL6Writer::kA4Paper; case JobData::kExecutive: return PCL6Writer::kExecPaper; case JobData::kLedger: return PCL6Writer::kLedgerPaper; case JobData::kA3: return PCL6Writer::kA3Paper; case JobData::kB5: return PCL6Writer::kB5Paper; case JobData::kJapanesePostcard: return PCL6Writer::kJPostcard; case JobData::kA5: return PCL6Writer::kA5Paper; case JobData::kB4: return PCL6Writer::kJB4Paper; /* case : return PCL6Writer::kCOM10Envelope; case : return PCL6Writer::kMonarchEnvelope; case : return PCL6Writer::kC5Envelope; case : return PCL6Writer::kDLEnvelope; case : return PCL6Writer::kJB4Paper; case : return PCL6Writer::kJB5Paper; case : return PCL6Writer::kB5Envelope; case : return PCL6Writer::kJPostcard; case : return PCL6Writer::kJDoublePostcard; case : return PCL6Writer::kA5Paper; case : return PCL6Writer::kA6Paper; case : return PCL6Writer::kJB6Paper; case : return PCL6Writer::kJIS8KPaper; case : return PCL6Writer::kJIS16KPaper; case : return PCL6Writer::kJISExecPaper; */ default: return PCL6Writer::kLegalPaper; } } PCL6Writer::MediaSource PCL6Driver::_MediaSource(JobData::PaperSource source) { switch (source) { case JobData::kAuto: return PCL6Writer::kAutoSelect; case JobData::kCassette1: return PCL6Writer::kDefaultSource; case JobData::kCassette2: return PCL6Writer::kEnvelopeTray; case JobData::kLower: return PCL6Writer::kLowerCassette; case JobData::kUpper: return PCL6Writer::kUpperCassette; case JobData::kMiddle: return PCL6Writer::kThirdCassette; case JobData::kManual: return PCL6Writer::kManualFeed; case JobData::kCassette3: return PCL6Writer::kMultiPurposeTray; default: return PCL6Writer::kAutoSelect; } }