diff --git a/src/add-ons/print/drivers/pcl6/Jamfile b/src/add-ons/print/drivers/pcl6/Jamfile index 2a4f0bc0d0..b3474bf222 100644 --- a/src/add-ons/print/drivers/pcl6/Jamfile +++ b/src/add-ons/print/drivers/pcl6/Jamfile @@ -9,7 +9,9 @@ Addon PCL6\ Compatible : Print : PCL6Entry.cpp PCL6.cpp PCL6Cap.cpp + PCL6Rasterizer.cpp PCL6Writer.cpp + Rasterizer.cpp ; ObjectC++Flags [ FGristFiles jetlib.o ] : -w ; diff --git a/src/add-ons/print/drivers/pcl6/PCL6.cpp b/src/add-ons/print/drivers/pcl6/PCL6.cpp index 48bccbb7e1..d686ef1d7f 100644 --- a/src/add-ons/print/drivers/pcl6/PCL6.cpp +++ b/src/add-ons/print/drivers/pcl6/PCL6.cpp @@ -8,16 +8,19 @@ #include #include #include + #include "PCL6.h" -#include "UIDriver.h" -#include "JobData.h" -#include "PrinterData.h" -#include "PCL6Cap.h" -#include "PackBits.h" -#include "Halftone.h" -#include "ValidRect.h" + #include "DbgMsg.h" #include "DeltaRowCompression.h" +#include "Halftone.h" +#include "JobData.h" +#include "PackBits.h" +#include "PCL6Cap.h" +#include "PrinterData.h" +#include "PCL6Rasterizer.h" +#include "UIDriver.h" +#include "ValidRect.h" #if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) using namespace std; @@ -31,10 +34,16 @@ using namespace std; // Run-Length-Encoding Compression // DO NOT ENABLE HP_M2TIFF_Compress seems to be broken!!! -#define ENABLE_RLE_COMPRESSION 0 +#define ENABLE_RLE_COMPRESSION 0 // Delta Row Compression -#define ENABLE_DELTA_ROW_COMPRESSION 0 +#define ENABLE_DELTA_ROW_COMPRESSION 1 + +// Color depth for color printing. +// Use either 1 or 8. +// If 1 bit depth is used, the class Halftone is used for dithering +// otherwise dithering is not performed. +#define COLOR_DEPTH 1 // DeltaRowStreamCompressor writes the delta row directly to the // in the contructor specified stream. @@ -57,6 +66,7 @@ private: PCL6Writer *fWriter; }; + PCL6Driver::PCL6Driver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap) : GraphicsDriver(msg, printer_data, printer_cap) { @@ -64,7 +74,7 @@ PCL6Driver::PCL6Driver(BMessage *msg, PrinterData *printer_data, const PrinterCa fWriter = NULL; } -void PCL6Driver::writeData(const uint8 *data, uint32 size) +void PCL6Driver::write(const uint8 *data, uint32 size) { writeSpoolData(data, size); } @@ -100,145 +110,68 @@ bool PCL6Driver::nextBand(BBitmap *bitmap, BPoint *offset) DBGMSG(("> nextBand\n")); try { - BRect bounds = bitmap->Bounds(); - - RECT rc; - rc.left = (int)bounds.left; - rc.top = (int)bounds.top; - rc.right = (int)bounds.right; - rc.bottom = (int)bounds.bottom; - - int height = rc.bottom - rc.top + 1; - - int x = (int)offset->x; int y = (int)offset->y; - - int page_height = getPageHeight(); - - if (y + height > page_height) { - height = page_height - y; + + PCL6Rasterizer *rasterizer; + if (getJobData()->getColor() == JobData::kColor) { + #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); } - - rc.bottom = height - 1; - - DBGMSG(("height = %d\n", height)); - DBGMSG(("x = %d\n", x)); - DBGMSG(("y = %d\n", y)); - - if (get_valid_rect(bitmap, &rc)) { - - DBGMSG(("validate rect = %d, %d, %d, %d\n", - rc.left, rc.top, rc.right, rc.bottom)); - - x = rc.left; - y += rc.top; - - bool color; - int width; - int widthByte; - int padBytes; - int out_row_length; - int height; - int out_size; - int delta; - - color = getJobData()->getColor() == JobData::kColor; - - width = rc.right - rc.left + 1; - height = rc.bottom - rc.top + 1; - delta = bitmap->BytesPerRow(); - - if (color) { - widthByte = 3 * width; - } else { - widthByte = (width + 7) / 8; /* byte boundary */ - } - - out_row_length = 4*((widthByte+3)/4); - padBytes = out_row_length - widthByte; /* line length is a multiple of 4 bytes */ - out_size = out_row_length * height; - - - DBGMSG(("width = %d\n", width)); - DBGMSG(("widthByte = %d\n", widthByte)); - DBGMSG(("height = %d\n", height)); - DBGMSG(("out_size = %d\n", out_size)); - DBGMSG(("delta = %d\n", delta)); - DBGMSG(("renderobj->get_pixel_depth() = %d\n", fHalftone->getPixelDepth())); - - uchar *ptr = (uchar *)bitmap->Bits() - + rc.top * delta - + (rc.left * fHalftone->getPixelDepth()) / 8; - - const uchar *buffer; - - uchar *out_buffer = new uchar[out_size]; - - uchar *out_ptr = out_buffer; - - auto_ptr _out_buffer(out_buffer); - - DBGMSG(("move\n")); - - buffer = out_buffer; - - int xPage = x; - int yPage = y; + auto_ptr _rasterizer(rasterizer); + bool valid = rasterizer->SetBitmap((int)offset->x, (int)offset->y, bitmap, getPageHeight()); + + if (valid) { + rasterizer->InitializeBuffer(); - DeltaRowCompressor deltaRowCompressor(out_row_length, 0); - if (deltaRowCompressor.InitCheck() != B_OK) { - return false; + // 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; + } } - + auto_ptr _deltaRowCompressor(deltaRowCompressor); int deltaRowSize = 0; + + // remember position + int xPage = rasterizer->GetX(); + int yPage = rasterizer->GetY(); - // dither entire band into out_buffer - for (int i = rc.top; i <= rc.bottom; i++) { - uchar* out = out_ptr; - if (color) { - uchar* in = ptr; - for (int w = width; w > 0; w --) { - *out++ = in[2]; - *out++ = in[1]; - *out++ = in[0]; - in += 4; - } - } else { - fHalftone->dither(out_ptr, ptr, x, y, width); - // invert pixels - for (int w = widthByte; w > 0; w --, out ++) { - *out = ~*out; - } - } - // pad with 0s - for (int w = padBytes; w > 0; w --, out ++) { - *out = 0; - } - - { - int size = deltaRowCompressor.CalculateSize(out_ptr, true); + while (rasterizer->HasNextLine()) { + const uchar *rowBuffer = (uchar*)rasterizer->RasterizeNextLine(); + + if (deltaRowCompressor != NULL) { + int size = deltaRowCompressor->CalculateSize(rowBuffer, true); deltaRowSize += size + 2; // two bytes for the row byte count } - - ptr += delta; - out_ptr += out_row_length; - y++; } - - writeBitmap(buffer, out_size, out_row_length, xPage, yPage, width, height, deltaRowSize); - - } else { - DBGMSG(("band bitmap is clean.\n")); + + 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 >= page_height) { + if (y >= getPageHeight()) { offset->x = -1.0; offset->y = -1.0; } else { - offset->y += height; + offset->y += bitmap->Bounds().IntegerHeight()+1; } - DBGMSG(("< nextBand\n")); return true; } catch (TransportException &err) { @@ -255,7 +188,7 @@ void PCL6Driver::writeBitmap(const uchar* buffer, int outSize, int rowSize, int int dataSize = outSize; #if ENABLE_DELTA_ROW_COMPRESSION - if (deltaRowSize < dataSize) { + if (supportsDeltaRowCompression() && deltaRowSize < dataSize) { compressionMethod = PCL6Writer::kDeltaRowCompression; dataSize = deltaRowSize; } @@ -279,7 +212,7 @@ void PCL6Driver::writeBitmap(const uchar* buffer, int outSize, int rowSize, int endRasterGraphics(); -#if 1 +#if 0 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)compressedSize, 100.0 * compressedSize / outSize); @@ -294,15 +227,9 @@ void PCL6Driver::writeBitmap(const uchar* buffer, int outSize, int rowSize, int void PCL6Driver::jobStart() { - // PJL header - writeSpoolString("\033%%-12345X@PJL JOB\n" - "@PJL SET RESOLUTION=%d\n" - "@PJL ENTER LANGUAGE=PCLXL\n" - ") HP-PCL XL;1;1;" - "Comment Copyright (c) 2003, 2004 Haiku\n", - getJobData()->getXres()); // PCL6 begin fWriter = new PCL6Writer(this); + fWriter->PJLHeader(PCL6Writer::kProtocolClass1_1, getJobData()->getXres(), "Copyright (c) 2003, 2004 Haiku"); fWriter->BeginSession(getJobData()->getXres(), getJobData()->getYres(), PCL6Writer::kInch, PCL6Writer::kBackChAndErrPage); fWriter->OpenDataSource(); fMediaSide = PCL6Writer::kFrontMediaSide; @@ -347,7 +274,19 @@ bool PCL6Driver::startPage(int) void PCL6Driver::startRasterGraphics(int x, int y, int width, int height, PCL6Writer::Compression compressionMethod) { bool color = getJobData()->getColor() == JobData::kColor; - fWriter->BeginImage(PCL6Writer::kDirectPixel, color ? PCL6Writer::k8Bit : PCL6Writer::k1Bit, width, height, width, height); + PCL6Writer::ColorDepth colorDepth; + if (color) { + #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); } @@ -415,12 +354,10 @@ void PCL6Driver::jobEnd() { fWriter->CloseDataSource(); fWriter->EndSession(); + fWriter->PJLFooter(); fWriter->Flush(); delete fWriter; fWriter = NULL; - // PJL footer - writeSpoolString("\033%%-12345X@PJL EOJ\n" - "\033%%-12345X"); } void PCL6Driver::move(int x, int y) @@ -428,6 +365,12 @@ void PCL6Driver::move(int x, int y) fWriter->SetCursor(x, y); } +bool +PCL6Driver::supportsDeltaRowCompression() +{ + return getProtocolClass() >= kProtocolClass2_1; +} + PCL6Writer::MediaSize PCL6Driver::mediaSize(JobData::Paper paper) { switch (paper) { @@ -437,6 +380,11 @@ PCL6Writer::MediaSize PCL6Driver::mediaSize(JobData::Paper paper) 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; @@ -445,7 +393,6 @@ PCL6Writer::MediaSize PCL6Driver::mediaSize(JobData::Paper paper) case : return PCL6Writer::kJB4Paper; case : return PCL6Writer::kJB5Paper; case : return PCL6Writer::kB5Envelope; - case : return PCL6Writer::kB5Paper; case : return PCL6Writer::kJPostcard; case : return PCL6Writer::kJDoublePostcard; case : return PCL6Writer::kA5Paper; diff --git a/src/add-ons/print/drivers/pcl6/PCL6.h b/src/add-ons/print/drivers/pcl6/PCL6.h index 7b518e1bb2..149fddc29a 100644 --- a/src/add-ons/print/drivers/pcl6/PCL6.h +++ b/src/add-ons/print/drivers/pcl6/PCL6.h @@ -13,12 +13,12 @@ class Halftone; -class PCL6Driver : public GraphicsDriver +class PCL6Driver : public GraphicsDriver, public PCL6WriterStream { public: PCL6Driver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap); - void writeData(const uint8 *data, uint32 size); + void write(const uint8 *data, uint32 size); protected: virtual bool startDoc(); @@ -28,6 +28,7 @@ protected: virtual bool endDoc(bool success); private: + bool supportsDeltaRowCompression(); PCL6Writer::MediaSize mediaSize(JobData::Paper paper); PCL6Writer::MediaSource mediaSource(JobData::PaperSource source); void move(int x, int y); diff --git a/src/add-ons/print/drivers/pcl6/PCL6Cap.cpp b/src/add-ons/print/drivers/pcl6/PCL6Cap.cpp index b7f67d0713..218b20d258 100644 --- a/src/add-ons/print/drivers/pcl6/PCL6Cap.cpp +++ b/src/add-ons/print/drivers/pcl6/PCL6Cap.cpp @@ -8,48 +8,7 @@ #define TO72DPI(a) (a * 72.0f / 600.0f) -const PaperCap a3( - "A3", - false, - JobData::kA3, - BRect(0.0f, 0.0f, TO72DPI(7014.0f), TO72DPI(9920.0f)), - BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(6894.0f), TO72DPI(9800.0f))); - -const PaperCap a4( - "A4", - true, - JobData::kA4, - BRect(0.0f, 0.0f, TO72DPI(4960.0f), TO72DPI(7014.0f)), - BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4840.0f), TO72DPI(6894.0f))); - -const PaperCap a5( - "A5", - false, - JobData::kA5, - BRect(0.0f, 0.0f, TO72DPI(3506.0f), TO72DPI(4960.0f)), - BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(3386.0f), TO72DPI(4840.0f))); - -const PaperCap japanese_postcard( - "Japanese Postcard", - false, - JobData::kJapanesePostcard, - BRect(0.0f, 0.0f, TO72DPI(2362.0f), TO72DPI(3506.0f)), - BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(2242.0f), TO72DPI(3386.0f))); - -const PaperCap b4( - "B4", - false, - JobData::kB4, - BRect(0.0f, 0.0f, TO72DPI(6070.0f), TO72DPI(8598.0f)), - BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(5950.0f), TO72DPI(8478.0f))); - -const PaperCap b5( - "B5", - false, - JobData::kB5, - BRect(0.0f, 0.0f, TO72DPI(4298.0f), TO72DPI(6070.0f)), - BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4178.0f), TO72DPI(5950.0f))); - +// since 1.1 const PaperCap letter( "Letter", false, @@ -57,6 +16,7 @@ const PaperCap letter( BRect(0.0f, 0.0f, TO72DPI(5100.0f), TO72DPI(6600.0f)), BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4980.0f), TO72DPI(6480.0f))); +// since 1.1 const PaperCap legal( "Legal", false, @@ -64,14 +24,121 @@ const PaperCap legal( BRect(0.0f, 0.0f, TO72DPI(5100.0f), TO72DPI(8400.0f)), BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4980.0f), TO72DPI(8280.0f))); -const PaperSourceCap autobin("Auto", true, JobData::kAuto); +// since 1.1 +const PaperCap a4( + "A4", + true, + JobData::kA4, + BRect(0.0f, 0.0f, TO72DPI(4960.0f), TO72DPI(7014.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4840.0f), TO72DPI(6894.0f))); + +// TODO +// since 1.1 +const PaperCap exec( + "Executive", + true, + JobData::kA4, + BRect(0.0f, 0.0f, TO72DPI(4960.0f), TO72DPI(7014.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4840.0f), TO72DPI(6894.0f))); + +// TODO +// since 1.1 +const PaperCap ledger( + "Ledger", + false, + JobData::kLegal, + BRect(0.0f, 0.0f, TO72DPI(5100.0f), TO72DPI(8400.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4980.0f), TO72DPI(8280.0f))); + +// since 1.1 +const PaperCap a3( + "A3", + false, + JobData::kA3, + BRect(0.0f, 0.0f, TO72DPI(7014.0f), TO72DPI(9920.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(6894.0f), TO72DPI(9800.0f))); + +// TODO +// COM10Envelope +// since 1.1 + +// MonarchEnvelope +// since 1.1 + +// C5Envelope +// since 1.1 + +// DLEnvelope +// since 1.1 + +// JB4Paper +// since 1.1 + +// JB5Paper +// since 1.1 + +// since 2.1 +const PaperCap b5( + "B5", + false, + JobData::kB5, + BRect(0.0f, 0.0f, TO72DPI(4298.0f), TO72DPI(6070.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(4178.0f), TO72DPI(5950.0f))); + +// since 1.1 +const PaperCap japanese_postcard( + "Japanese Postcard", + false, + JobData::kJapanesePostcard, + BRect(0.0f, 0.0f, TO72DPI(2362.0f), TO72DPI(3506.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(2242.0f), TO72DPI(3386.0f))); + +// TODO +// JDoublePostcard +// since 1.1 + +// since 1.1 +const PaperCap a5( + "A5", + false, + JobData::kA5, + BRect(0.0f, 0.0f, TO72DPI(3506.0f), TO72DPI(4960.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(3386.0f), TO72DPI(4840.0f))); + +// TODO +// A6 +// since 2.0 + +// JB6 +// since 2.0 +// TBD: Validate. Is this JB4? +const PaperCap b4( + "B4", + false, + JobData::kB4, + BRect(0.0f, 0.0f, TO72DPI(6070.0f), TO72DPI(8598.0f)), + BRect(TO72DPI(120.0f), TO72DPI(120.0f), TO72DPI(5950.0f), TO72DPI(8478.0f))); + + +// JIS8K +// since 2.1 + +// JIS16K +// since 2.1 + +// JISExec +// since 2.1 + +// since 1.1 const PaperSourceCap defaultSource("Default", false, JobData::kCassette1); -const PaperSourceCap envelopeTray("Envelope Tray", false, JobData::kCassette2); -const PaperSourceCap lowerCassette("Lower Cassette", false, JobData::kLower); -const PaperSourceCap upperCassette("Upper Cassette", false, JobData::kUpper); -const PaperSourceCap thridCassette("Thrid Cassette", false, JobData::kMiddle); +const PaperSourceCap autobin("Auto", true, JobData::kAuto); const PaperSourceCap manualFeed("Manual Feed", false, JobData::kManual); const PaperSourceCap multiPurposeTray("Multi Purpose Tray", false, JobData::kCassette3); +const PaperSourceCap upperCassette("Upper Cassette", false, JobData::kUpper); +const PaperSourceCap lowerCassette("Lower Cassette", false, JobData::kLower); +const PaperSourceCap envelopeTray("Envelope Tray", false, JobData::kCassette2); +// since 2.0: +const PaperSourceCap thridCassette("Thrid Cassette", false, JobData::kMiddle); const ResolutionCap dpi150("150dpi", true, 150, 150); const ResolutionCap dpi300("300dpi", true, 300, 300); @@ -81,18 +148,53 @@ const ResolutionCap dpi1200("1200dpi", false, 1200, 1200); const PrintStyleCap simplex("Simplex", true, JobData::kSimplex); const PrintStyleCap duplex("Duplex", false, JobData::kDuplex); -const PaperCap *papers[] = { +const ProtocolClassCap pc1_1("PCL 6 Protocol Class 1.1", true, kProtocolClass1_1, +"Protocol Class 1.1\n" +"* No compression\n" +"* RLE compression (not implemented yet)"); +const ProtocolClassCap pc2_0("PCL 6 Protocol Class 2.0", false, kProtocolClass2_0, +"Protocol Class 2.0\n" +"* Additonal Paper Source: Third Cassette\n" +"* JPEG compression (not implemented yet)"); +const ProtocolClassCap pc2_1("PCL 6 Protocol Class 2.1", false, kProtocolClass2_1, +"Protocol Class 2.1\n" +"* Additional Paper Format: B5\n" +"* Delta Row Compression"); +const ProtocolClassCap pc3_0("PCL 6 Protocol Class 3.0", false, kProtocolClass3_0, +"Protocol Class 3.0"); + +const PaperCap *papers1_1[] = { + &letter, + &legal, + &a4, + &a3, + &a5, + &b4, + &japanese_postcard +}; + +const PaperCap *papers2_1[] = { + &letter, + &legal, &a4, &a3, &a5, &b4, &b5, - &letter, - &legal, &japanese_postcard }; -const PaperSourceCap *papersources[] = { +const PaperSourceCap *paperSources1_1[] = { + &autobin, + &defaultSource, + &envelopeTray, + &lowerCassette, + &upperCassette, + &manualFeed, + &multiPurposeTray +}; + +const PaperSourceCap *paperSources2_0[] = { &autobin, &defaultSource, &envelopeTray, @@ -115,6 +217,13 @@ const PrintStyleCap *printStyles[] = { &duplex }; +const ProtocolClassCap *protocolClasses[] = { + &pc1_1, + &pc2_0, + &pc2_1, + &pc3_0 +}; + const ColorCap color("Color", false, JobData::kColor); const ColorCap monochrome("Monochrome", true, JobData::kMonochrome); @@ -132,15 +241,23 @@ int PCL6Cap::countCap(CapID capid) const { switch (capid) { case kPaper: - return sizeof(papers) / sizeof(papers[0]); + if (getProtocolClass() >= kProtocolClass2_1) { + return sizeof(papers2_1) / sizeof(papers2_1[0]); + } + return sizeof(papers1_1) / sizeof(papers1_1[0]); case kPaperSource: - return sizeof(papersources) / sizeof(papersources[0]); + if (getProtocolClass() >= kProtocolClass2_0) { + return sizeof(paperSources2_0) / sizeof(paperSources2_0[0]); + } + return sizeof(paperSources1_1) / sizeof(paperSources1_1[0]); case kResolution: return sizeof(resolutions) / sizeof(resolutions[0]); case kColor: return sizeof(colors) / sizeof(colors[0]); case kPrintStyle: return sizeof(printStyles) / sizeof(printStyles[0]); + case kProtocolClass: + return sizeof(protocolClasses) / sizeof(protocolClasses[0]); default: return 0; } @@ -150,15 +267,23 @@ const BaseCap **PCL6Cap::enumCap(CapID capid) const { switch (capid) { case kPaper: - return (const BaseCap **)papers; + if (getProtocolClass() >= kProtocolClass2_1) { + return (const BaseCap **)papers2_1; + } + return (const BaseCap **)papers1_1; case kPaperSource: - return (const BaseCap **)papersources; + if (getProtocolClass() >= kProtocolClass2_0) { + return (const BaseCap **)paperSources2_0; + } + return (const BaseCap **)paperSources1_1; case kResolution: return (const BaseCap **)resolutions; case kColor: return (const BaseCap **)colors; case kPrintStyle: return (const BaseCap **)printStyles; + case kProtocolClass: + return (const BaseCap **)protocolClasses; default: return NULL; } @@ -173,6 +298,7 @@ bool PCL6Cap::isSupport(CapID capid) const case kColor: case kCopyCommand: case kPrintStyle: + case kProtocolClass: return true; default: return false; diff --git a/src/add-ons/print/drivers/pcl6/PCL6Cap.h b/src/add-ons/print/drivers/pcl6/PCL6Cap.h index 667ee03a79..3fd91c0a0f 100644 --- a/src/add-ons/print/drivers/pcl6/PCL6Cap.h +++ b/src/add-ons/print/drivers/pcl6/PCL6Cap.h @@ -8,6 +8,13 @@ #include "PrinterCap.h" +enum ProtocolClass { + kProtocolClass1_1, + kProtocolClass2_0, + kProtocolClass2_1, + kProtocolClass3_0, +}; + class PCL6Cap : public PrinterCap { public: PCL6Cap(const PrinterData *printer_data); diff --git a/src/add-ons/print/drivers/pcl6/PCL6Rasterizer.cpp b/src/add-ons/print/drivers/pcl6/PCL6Rasterizer.cpp new file mode 100644 index 0000000000..ad11ed8fe4 --- /dev/null +++ b/src/add-ons/print/drivers/pcl6/PCL6Rasterizer.cpp @@ -0,0 +1,388 @@ +/* +** PCL6Rasterizer.cpp +** Copyright 2005, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ +#include "PCL6Rasterizer.h" + +#include + +#ifdef _PCL6_RASTERIZER_TEST_ + +static void dump(uchar *buffer, int size); +static void dump_bits(uchar *buffer, int size); + +#define DUMP(text, buffer, size) { fprintf text; dump(buffer, size); } +#define DUMP_BITS(text, buffer, size) { fprintf text; dump_bits(buffer, size); } + +#else + +#define DUMP(text, buffer, size) {} +#define DUMP_BITS(text, buffer, size) {} + +#endif + +// MonochromeRasterizer + +MonochromeRasterizer::MonochromeRasterizer(Halftone *halftone) + : PCL6Rasterizer(halftone) + , fOutBuffer(NULL) +{ } + +void +MonochromeRasterizer::InitializeBuffer() { + fWidthByte = RowBufferSize(GetWidth(), 1, 1); + /* line length is a multiple of 4 bytes */ + fOutRowSize = RowBufferSize(GetWidth(), 1, 4); + fPadBytes = fOutRowSize - fWidthByte; + // Total size + SetOutBufferSize(fOutRowSize * GetHeight()); + PCL6Rasterizer::InitializeBuffer(); + fCurrentLine = GetOutBuffer(); +} + +const void * +MonochromeRasterizer::RasterizeLine(int x, int y, const ColorRGB32Little* source) { + GetHalftone()->dither(fCurrentLine, (const uchar*)source, x, y, GetWidth()); + + uchar *out = fCurrentLine; + + // invert pixels + for (int w = fWidthByte; w > 0; w --, out ++) { + *out = ~*out; + } + + // pad with 0s + for (int w = fPadBytes; w > 0; w --, out ++) { + *out = 0; + } + + void *result = fCurrentLine; + fCurrentLine += fOutRowSize; + return result; +} + + +// ColorRGBRasterizer + +ColorRGBRasterizer::ColorRGBRasterizer(Halftone *halftone) + : PCL6Rasterizer(halftone) +{ } + +void +ColorRGBRasterizer::InitializeBuffer() { + fWidthByte = RowBufferSize(GetWidth(), 24, 1); + // line length is a multiple of 4 bytes + fOutRowSize = RowBufferSize(GetWidth(), 24, 4); + fPadBytes = fOutRowSize - fWidthByte; + // Total size + SetOutBufferSize(fOutRowSize * GetHeight()); + PCL6Rasterizer::InitializeBuffer(); + fCurrentLine = GetOutBuffer(); +} + +const void * +ColorRGBRasterizer::RasterizeLine(int x, int y, const ColorRGB32Little* source) { + + uchar *out = fCurrentLine; + int width = GetWidth(); + for (int w = width; w > 0; w --) { + *out++ = source->red; + *out++ = source->green; + *out++ = source->blue; + source ++; + } + + // pad with 0s + for (int w = fPadBytes; w > 0; w --, out ++) { + *out = 0; + } + + void *result = fCurrentLine; + fCurrentLine += fOutRowSize; + return result; +} + + +// ColorRasterizer + +ColorRasterizer::ColorRasterizer::ColorRasterizer(Halftone *halftone) + : PCL6Rasterizer(halftone) +{ + for (int plane = 0; plane < 3; plane ++) { + fPlaneBuffers[plane] = NULL; + } + + halftone->setPlanes(Halftone::kPlaneRGB1); + halftone->setBlackValue(Halftone::kLowValueMeansBlack); +} + +ColorRasterizer::~ColorRasterizer() { + for (int plane = 0; plane < 3; plane ++) { + delete fPlaneBuffers[plane]; + fPlaneBuffers[plane] = NULL; + } +} + +void +ColorRasterizer::InitializeBuffer() { + fWidthByte = RowBufferSize(GetWidth(), 3, 1); + // line length is a multiple of 4 bytes + fOutRowSize = RowBufferSize(GetWidth(), 3, 4); + fPadBytes = fOutRowSize - fWidthByte; + // Total size + SetOutBufferSize(fOutRowSize * GetHeight()); + PCL6Rasterizer::InitializeBuffer(); + fCurrentLine = GetOutBuffer(); + + fPlaneBufferSize = RowBufferSize(GetWidth(), 1, 1); + for (int plane = 0; plane < 3; plane ++) { + fPlaneBuffers[plane] = new uchar[fPlaneBufferSize]; + } +} + +enum { + kRed = 1, + kGreen = 2, + kBlue = 4, +}; + +const void * +ColorRasterizer::RasterizeLine(int x, int y, const ColorRGB32Little* source) { + + DUMP((stderr, "\nRGB32 row at x %d y %d:\n", x, y), (uchar*)source, GetWidth() * 4); + + // dither each color component + for (int plane = 0; plane < 3; plane ++) { + GetHalftone()->dither(fPlaneBuffers[plane], (const uchar*)source, x, y, GetWidth()); + } + + DUMP_BITS((stderr, "red "), fPlaneBuffers[0], fPlaneBufferSize); + DUMP_BITS((stderr, "green "), fPlaneBuffers[1], fPlaneBufferSize); + DUMP_BITS((stderr, "blue "), fPlaneBuffers[2], fPlaneBufferSize); + + MergePlaneBuffersToCurrentLine(); + + DUMP_BITS((stderr, "merged\n"), fCurrentLine, fOutRowSize); + DUMP((stderr, "\n"), fCurrentLine, fOutRowSize); + + void *result = fCurrentLine; + fCurrentLine += fOutRowSize; + return result; +} + +void +ColorRasterizer::MergePlaneBuffersToCurrentLine() +{ + // merge the three planes into output buffer + int remainingPixels = GetWidth(); + uchar *out = fCurrentLine; + uchar value = 0; + uchar outMask = 0x80; // current bit mask (1 << (8 - bit)) in output buffer + + // iterate over the three plane buffers + for (int i = 0; i < fPlaneBufferSize; i ++) { + const uchar values[3] = { + fPlaneBuffers[0][i], + fPlaneBuffers[1][i], + fPlaneBuffers[2][i] + }; + + int pixels = 8; + if (remainingPixels < 8) { + pixels = remainingPixels; + } + remainingPixels -= pixels; + + // for each bit in the current byte of each plane + uchar mask = 0x80; + for (; pixels > 0; pixels --) { + int rgb = 0; + + if (values[0] & mask) { + rgb |= kRed; + } + if (values[1] & mask) { + rgb |= kGreen; + } + if (values[2] & mask) { + rgb |= kBlue; + } + + for (int plane = 0; plane < 3; plane ++) { + // copy pixel value to output value + if (rgb & (1 << plane)) { + value |= outMask; + } + + // increment output mask + if (outMask == 0x01) { + outMask = 0x80; + // write output value to output buffer + *out = value; + out ++; + value = 0; + } else { + outMask >>= 1; + } + } + mask >>= 1; + } + } + + // write last output value + if (outMask != 0x80) { + do { + value |= outMask; + outMask >>= 1; + } while (outMask > 0); + + *out = value; + out ++; + } + + if (out - fCurrentLine != fWidthByte) { + fprintf(stderr, "Error buffer overflow: %d != %d\n", fWidthByte, (int)(out - fCurrentLine)); + } + + // pad with 0s + for (int w = fPadBytes; w > 0; w --, out ++) { + *out = 0xff; + } + + if (out - fCurrentLine != fOutRowSize) { + fprintf(stderr, "Error buffer overflow: %d != %d\n", fOutRowSize, (int)(out - fCurrentLine)); + } +} + +#ifdef _PCL6_RASTERIZER_TEST_ +#include +#include +#include + +#define COLUMNS 40 +#define BIT_COLUMNS 6 + +static void dump(uchar *buffer, int size) +{ + int x = 0; + for (int i = 0; i < size; i ++) { + if ((x % COLUMNS) == COLUMNS - 1) { + fprintf(stderr, "\n"); + } else if (i > 0) { + fprintf(stderr, " "); + } + + fprintf(stderr, "%2.2x", (int)*buffer); + buffer ++; + + x ++; + } + + fprintf(stderr, "\n"); +} + +static void dump_bits(uchar *buffer, int size) +{ + int x = 0; + for (int i = 0; i < size; i ++) { + if ((x % COLUMNS) == COLUMNS - 1) { + fprintf(stderr, "\n"); + } else if (i > 0) { + fprintf(stderr, " "); + } + + uchar value = *buffer; + for (int bit = 0; bit < 8; bit ++) { + if (value & (1 << bit)) { + fprintf(stderr, "*"); + } else { + fprintf(stderr, "."); + } + } + buffer ++; + + x ++; + } + + fprintf(stderr, "\n"); +} + +static void fill(uchar *_row, int width, ColorRGB32Little color) +{ + ColorRGB32Little *row = (ColorRGB32Little *)_row; + for (int i = 0; i < width; i ++) { + *row = color; + row ++; + } +} + +static void initializeBitmap(BBitmap *bitmap, int width, int height) +{ + int bpr = bitmap->BytesPerRow(); + uchar *row = (uchar*)bitmap->Bits(); + // BGRA + ColorRGB32Little black = {0, 0, 0, 0}; + ColorRGB32Little white = {255, 255, 255, 0}; + ColorRGB32Little red = {0, 0, 255, 0}; + ColorRGB32Little green = {0, 255, 0, 0}; + ColorRGB32Little blue = {255, 0, 0, 0}; + + fprintf(stderr, "black row\n"); + fill(row, width, black); + row += bpr; + + fprintf(stderr, "white row\n"); + fill(row, width, white); + row += bpr; + + fprintf(stderr, "red row\n"); + fill(row, width, red); + row += bpr; + + fprintf(stderr, "red green blue pattern"); + ColorRGB32Little *color = (ColorRGB32Little*)row; + for (int i = 0; i < width; i++) { + switch (i % 3) { + case 0: + *color = red; + break; + case 1: + *color = green; + break; + case 2: + *color = blue; + break; + } + color ++; + } +} + +#if 1 +int main() +{ + const int width = 10; + const int height = 4; + + fprintf(stderr, "width: %d\nheight: %d\n", width, height); + BApplication app("application/pcl6-rasterizer-test"); +#if 1 + Halftone halftone(B_RGB32, 0.25f, 0.0f, Halftone::kType1); +#else + Halftone halftone(B_RGB32, 0.25f, 0.0f, Halftone::kTypeFloydSteinberg); +#endif + ColorRasterizer rasterizer(&halftone); + BBitmap bitmap(BRect(0, 0, width-1, height-1), B_RGB32); + + initializeBitmap(&bitmap, width, height); + + rasterizer.SetBitmap(0, 0, &bitmap, height); + rasterizer.InitializeBuffer(); + while (rasterizer.HasNextLine()) { + // const uchar *rowBuffer = (uchar*) + rasterizer.RasterizeNextLine(); + } +} +#endif + +#endif diff --git a/src/add-ons/print/drivers/pcl6/PCL6Rasterizer.h b/src/add-ons/print/drivers/pcl6/PCL6Rasterizer.h new file mode 100644 index 0000000000..4e7ed4c461 --- /dev/null +++ b/src/add-ons/print/drivers/pcl6/PCL6Rasterizer.h @@ -0,0 +1,111 @@ +/* +** PCL6Rasterizer.h +** Copyright 2005, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ +#ifndef _PCL6_RASTERIZER_H +#define _PCL6_RASTERIZER_H +#include "Rasterizer.h" + +class PCL6Rasterizer : public Rasterizer +{ +public: + PCL6Rasterizer(Halftone *halftone) + : Rasterizer(halftone) + , fOutBuffer(NULL) + , fOutBufferSize(0) + { + } + + ~PCL6Rasterizer() + { + delete fOutBuffer; + fOutBuffer = NULL; + } + + void SetOutBufferSize(int size) { fOutBufferSize = size; } + int GetOutBufferSize() { return fOutBufferSize; } + + uchar *GetOutBuffer() { return fOutBuffer; } + + virtual void InitializeBuffer() { + fOutBuffer = new uchar[fOutBufferSize]; + } + + virtual int GetOutRowSize() = 0; + + +private: + uchar *fOutBuffer; + int fOutBufferSize; +}; + +class MonochromeRasterizer : public PCL6Rasterizer +{ +public: + MonochromeRasterizer(Halftone *halftone); + + void InitializeBuffer(); + + int GetOutRowSize() { return fOutRowSize; } + + const void *RasterizeLine(int x, int y, const ColorRGB32Little* source); + +private: + int fWidthByte; + int fOutRowSize; + int fPadBytes; + int fOutSize; + uchar *fOutBuffer; + uchar *fCurrentLine; +}; + +// Output format RGB 8bit per channel +class ColorRGBRasterizer : public PCL6Rasterizer +{ +public: + ColorRGBRasterizer(Halftone *halftone) ; + + void InitializeBuffer(); + + int GetOutRowSize() { return fOutRowSize; } + + const void *RasterizeLine(int x, int y, const ColorRGB32Little* source); + +private: + int fWidthByte; + int fOutRowSize; + int fPadBytes; + uchar *fCurrentLine; +}; + +typedef uchar *PlaneBuffer; + +// Output format: RGB 1bit per channel +// Class Halftone is used for dithering +class ColorRasterizer : public PCL6Rasterizer +{ +public: + ColorRasterizer(Halftone *halftone); + + ~ColorRasterizer(); + + void InitializeBuffer(); + + int GetOutRowSize() { return fOutRowSize; } + + const void *RasterizeLine(int x, int y, const ColorRGB32Little* source); + +private: + void MergePlaneBuffersToCurrentLine(); + + int fWidthByte; + int fOutRowSize; + int fPadBytes; + uchar *fCurrentLine; + + int fPlaneBufferSize; + PlaneBuffer fPlaneBuffers[3]; +}; + +#endif diff --git a/src/add-ons/print/drivers/pcl6/PCL6Writer.cpp b/src/add-ons/print/drivers/pcl6/PCL6Writer.cpp index 27a47d6da0..6b006b1bac 100644 --- a/src/add-ons/print/drivers/pcl6/PCL6Writer.cpp +++ b/src/add-ons/print/drivers/pcl6/PCL6Writer.cpp @@ -4,14 +4,14 @@ ** Distributed under the terms of the OpenBeOS License. */ #include "PCL6Writer.h" -#include "PCL6.h" #include +#include #define BYTE_AT(lvalue, index) (((uint8*)(&lvalue))[index]) -PCL6Writer::PCL6Writer(PCL6Driver *driver, uint32 bufferSize) - : fDriver(driver), +PCL6Writer::PCL6Writer(PCL6WriterStream *stream, uint32 bufferSize) + : fStream(stream), fBuffer(new uint8[bufferSize]), fSize(bufferSize), fIndex(0) @@ -24,7 +24,8 @@ PCL6Writer::~PCL6Writer() { } // throws TransportException -void PCL6Writer::Append(uint8 value) { +void +PCL6Writer::Append(uint8 value) { if (fIndex == fSize) { Flush(); } @@ -32,26 +33,30 @@ void PCL6Writer::Append(uint8 value) { fIndex ++; } -void PCL6Writer::Flush() { +void +PCL6Writer::Flush() { if (fIndex > 0) { - fDriver->writeData(fBuffer, fIndex); + fStream->write(fBuffer, fIndex); fIndex = 0; } } -void PCL6Writer::Append(int16 value) { +void +PCL6Writer::Append(int16 value) { int16 v = B_HOST_TO_LENDIAN_INT16(value); Append(BYTE_AT(v, 0)); Append(BYTE_AT(v, 1)); } -void PCL6Writer::Append(uint16 value) { +void +PCL6Writer::Append(uint16 value) { int16 v = B_HOST_TO_LENDIAN_INT16(value); Append(BYTE_AT(v, 0)); Append(BYTE_AT(v, 1)); } -void PCL6Writer::Append(int32 value) { +void +PCL6Writer::Append(int32 value) { int32 v = B_HOST_TO_LENDIAN_INT32(value); Append(BYTE_AT(v, 0)); Append(BYTE_AT(v, 1)); @@ -59,7 +64,8 @@ void PCL6Writer::Append(int32 value) { Append(BYTE_AT(v, 3)); } -void PCL6Writer::Append(uint32 value) { +void +PCL6Writer::Append(uint32 value) { int32 v = B_HOST_TO_LENDIAN_INT32(value); Append(BYTE_AT(v, 0)); Append(BYTE_AT(v, 1)); @@ -67,7 +73,8 @@ void PCL6Writer::Append(uint32 value) { Append(BYTE_AT(v, 3)); } -void PCL6Writer::Append(float value) { +void +PCL6Writer::Append(float value) { float v = B_HOST_TO_LENDIAN_FLOAT(value); Append(BYTE_AT(v, 0)); Append(BYTE_AT(v, 1)); @@ -75,56 +82,78 @@ void PCL6Writer::Append(float value) { Append(BYTE_AT(v, 3)); } -void PCL6Writer::Append(const uint8* data, uint32 size) { +void +PCL6Writer::Append(const uint8* data, uint32 size) { for (uint32 i = 0; i < size; i++) { Append(data[i]); } } -void PCL6Writer::AppendOperator(Operator op) { + +void +PCL6Writer::AppendString(const char *string) { + uint8 ch = *string; + while (ch != 0) { + Append(ch); + string ++; + ch = *string; + } +} + +void +PCL6Writer::AppendOperator(Operator op) { Append((uint8)op); } -void PCL6Writer::AppendAttribute(Attribute attr) { +void +PCL6Writer::AppendAttribute(Attribute attr) { AppendDataTag(k8BitAttrId); Append((uint8)attr); } -void PCL6Writer::AppendDataTag(DataTag tag) { +void +PCL6Writer::AppendDataTag(DataTag tag) { Append((uint8)tag); } -void PCL6Writer::AppendData(uint8 value) { +void +PCL6Writer::AppendData(uint8 value) { AppendDataTag(kUByteData); Append(value); } -void PCL6Writer::AppendData(int16 value) { +void +PCL6Writer::AppendData(int16 value) { AppendDataTag(kSInt16Data); Append(value); } -void PCL6Writer::AppendData(uint16 value) { +void +PCL6Writer::AppendData(uint16 value) { AppendDataTag(kUInt16Data); Append(value); } -void PCL6Writer::AppendData(int32 value) { +void +PCL6Writer::AppendData(int32 value) { AppendDataTag(kSInt32Data); Append(value); } -void PCL6Writer::AppendData(uint32 value) { +void +PCL6Writer::AppendData(uint32 value) { AppendDataTag(kUInt32Data); Append(value); } -void PCL6Writer::AppendData(float value) { +void +PCL6Writer::AppendData(float value) { AppendDataTag(kReal32Data); Append(value); } -void PCL6Writer::EmbeddedDataPrefix(uint32 size) { +void +PCL6Writer::EmbeddedDataPrefix(uint32 size) { if (size < 256) { AppendDataTag(kEmbeddedDataByte); Append((uint8)size); @@ -134,44 +163,95 @@ void PCL6Writer::EmbeddedDataPrefix(uint32 size) { } } -void PCL6Writer::EmbeddedDataPrefix32(uint32 size) { +void +PCL6Writer::EmbeddedDataPrefix32(uint32 size) { AppendDataTag(kEmbeddedData); Append(size); } -void PCL6Writer::AppendDataXY(uint8 x, uint8 y) { +void +PCL6Writer::AppendDataXY(uint8 x, uint8 y) { AppendDataTag(kUByteXY); Append(x); Append(y); } -void PCL6Writer::AppendDataXY(int16 x, int16 y) { +void +PCL6Writer::AppendDataXY(int16 x, int16 y) { AppendDataTag(kSInt16XY); Append(x); Append(y); } -void PCL6Writer::AppendDataXY(uint16 x, uint16 y) { +void +PCL6Writer::AppendDataXY(uint16 x, uint16 y) { AppendDataTag(kUInt16XY); Append(x); Append(y); } -void PCL6Writer::AppendDataXY(int32 x, int32 y) { +void +PCL6Writer::AppendDataXY(int32 x, int32 y) { AppendDataTag(kSInt32XY); Append(x); Append(y); } -void PCL6Writer::AppendDataXY(uint32 x, uint32 y) { +void +PCL6Writer::AppendDataXY(uint32 x, uint32 y) { AppendDataTag(kUInt32XY); Append(x); Append(y); } -void PCL6Writer::AppendDataXY(float x, float y) { +void +PCL6Writer::AppendDataXY(float x, float y) { AppendDataTag(kReal32XY); Append(x); Append(y); } +void +PCL6Writer::PJLHeader(ProtocolClass protocolClass, int dpi, const char *comment) +{ + BString string; + AppendString("\033%-12345X@PJL JOB\n" + "@PJL SET RESOLUTION="); + string << dpi; + AppendString(string.String()); + AppendString("\n" + "@PJL ENTER LANGUAGE=PCLXL\n" + ") HP-PCL XL;"); + + const char* pc = ""; + switch (protocolClass) { + case kProtocolClass1_1: + pc = "1;1;"; + break; + case kProtocolClass2_0: + pc = "2;0;"; + break; + case kProtocolClass2_1: + pc = "2;1;"; + break; + case kProtocolClass3_0: + pc = "3;0;"; + break; + } + AppendString(pc); + + if (comment != NULL) { + AppendString("Comment "); + AppendString(comment); + } + + AppendString("\n"); +} + +void +PCL6Writer::PJLFooter() +{ + AppendString("\033%-12345X@PJL EOJ\n" + "\033%-12345X"); +} -void PCL6Writer::BeginSession(uint16 xres, uint16 yres, UnitOfMeasure unitOfMeasure, ErrorReporting errorReporting) { +void +PCL6Writer::BeginSession(uint16 xres, uint16 yres, UnitOfMeasure unitOfMeasure, ErrorReporting errorReporting) { AppendDataXY(xres, yres); AppendAttribute(kUnitsPerMeasure); @@ -184,11 +264,13 @@ void PCL6Writer::BeginSession(uint16 xres, uint16 yres, UnitOfMeasure unitOfMeas AppendOperator(kBeginSession); } -void PCL6Writer::EndSession() { +void +PCL6Writer::EndSession() { AppendOperator(kEndSession); } -void PCL6Writer::OpenDataSource() { +void +PCL6Writer::OpenDataSource() { AppendData((uint8)kDefaultDataSource); AppendAttribute(kSourceType); @@ -198,12 +280,14 @@ void PCL6Writer::OpenDataSource() { AppendOperator(kOpenDataSource); } -void PCL6Writer::CloseDataSource() { +void +PCL6Writer::CloseDataSource() { AppendOperator(kCloseDataSource); } -void PCL6Writer::BeginPage(Orientation orientation, MediaSize mediaSize, MediaSource mediaSource) { +void +PCL6Writer::BeginPage(Orientation orientation, MediaSize mediaSize, MediaSource mediaSource) { AppendData((uint8)orientation); AppendAttribute(kOrientation); @@ -216,7 +300,8 @@ void PCL6Writer::BeginPage(Orientation orientation, MediaSize mediaSize, MediaSo AppendOperator(kBeginPage); } -void PCL6Writer::BeginPage(Orientation orientation, MediaSize mediaSize, MediaSource mediaSource, DuplexPageMode duplexPageMode, MediaSide mediaSide) { +void +PCL6Writer::BeginPage(Orientation orientation, MediaSize mediaSize, MediaSource mediaSource, DuplexPageMode duplexPageMode, MediaSide mediaSide) { AppendData((uint8)orientation); AppendAttribute(kOrientation); @@ -235,7 +320,8 @@ void PCL6Writer::BeginPage(Orientation orientation, MediaSize mediaSize, MediaSo AppendOperator(kBeginPage); } -void PCL6Writer::EndPage(uint16 copies) { +void +PCL6Writer::EndPage(uint16 copies) { // if (copies != 1) { AppendData(copies); AppendAttribute(kPageCopies); @@ -245,42 +331,48 @@ void PCL6Writer::EndPage(uint16 copies) { } -void PCL6Writer::SetPageOrigin(int16 x, int16 y) { +void +PCL6Writer::SetPageOrigin(int16 x, int16 y) { AppendDataXY(x, y); AppendAttribute(kPageOrigin); AppendOperator(kSetPageOrigin); } -void PCL6Writer::SetColorSpace(ColorSpace colorSpace) { +void +PCL6Writer::SetColorSpace(ColorSpace colorSpace) { AppendData((uint8)colorSpace); AppendAttribute(kColorSpace); AppendOperator(kSetColorSpace); } -void PCL6Writer::SetPaintTxMode(Transparency transparency) { +void +PCL6Writer::SetPaintTxMode(Transparency transparency) { AppendData((uint8)transparency); AppendAttribute(kTxMode); AppendOperator(kSetPaintTxMode); } -void PCL6Writer::SetSourceTxMode(Transparency transparency) { +void +PCL6Writer::SetSourceTxMode(Transparency transparency) { AppendData((uint8)transparency); AppendAttribute(kTxMode); AppendOperator(kSetSourceTxMode); } -void PCL6Writer::SetROP(uint8 rop) { +void +PCL6Writer::SetROP(uint8 rop) { AppendData((uint8)rop); AppendAttribute(kROP3); AppendOperator(kSetROP); } -void PCL6Writer::SetCursor(int16 x, int16 y) { +void +PCL6Writer::SetCursor(int16 x, int16 y) { AppendDataXY(x, y); AppendAttribute(kPoint); @@ -288,7 +380,8 @@ void PCL6Writer::SetCursor(int16 x, int16 y) { } -void PCL6Writer::BeginImage(ColorMapping colorMapping, ColorDepth colorDepth, uint16 sourceWidth, uint16 sourceHeight, uint16 destWidth, uint16 destHeight) { +void +PCL6Writer::BeginImage(ColorMapping colorMapping, ColorDepth colorDepth, uint16 sourceWidth, uint16 sourceHeight, uint16 destWidth, uint16 destHeight) { AppendData((uint8)colorMapping); AppendAttribute(kColorMapping); @@ -307,7 +400,8 @@ void PCL6Writer::BeginImage(ColorMapping colorMapping, ColorDepth colorDepth, ui AppendOperator(kBeginImage); } -void PCL6Writer::ReadImage(Compression compression, uint16 startLine, uint16 blockHeight, uint8 padBytes) { +void +PCL6Writer::ReadImage(Compression compression, uint16 startLine, uint16 blockHeight, uint8 padBytes) { AppendData(startLine); AppendAttribute(kStartLine); @@ -329,7 +423,8 @@ void PCL6Writer::ReadImage(Compression compression, uint16 startLine, uint16 blo AppendOperator(kReadImage); } -void PCL6Writer::EndImage() { +void +PCL6Writer::EndImage() { AppendOperator(kEndImage); } diff --git a/src/add-ons/print/drivers/pcl6/PCL6Writer.h b/src/add-ons/print/drivers/pcl6/PCL6Writer.h index 904206bafb..af9c45c5d8 100644 --- a/src/add-ons/print/drivers/pcl6/PCL6Writer.h +++ b/src/add-ons/print/drivers/pcl6/PCL6Writer.h @@ -10,6 +10,12 @@ class PCL6Driver; + +class PCL6WriterStream { +public: + virtual void write(const uint8 *data, uint32 size) = 0; +}; + class PCL6Writer { public: // DO NOT change this enumerations the order is important!!! @@ -130,13 +136,23 @@ public: kTrue }; - PCL6Writer(PCL6Driver* driver, uint32 bufferSize = 16 * 1024); + enum ProtocolClass { + kProtocolClass1_1, + kProtocolClass2_0, + kProtocolClass2_1, + kProtocolClass3_0, + }; + + PCL6Writer(PCL6WriterStream* stream, uint32 bufferSize = 16 * 1024); virtual ~PCL6Writer(); // these methods throw TransportException if data could not // be written void Flush(); + void PJLHeader(ProtocolClass protocolClass, int dpi, const char *comment = NULL); + void PJLFooter(); + void BeginSession(uint16 xres, uint16 yres, UnitOfMeasure unitOfMeasure, ErrorReporting errorReporting); void EndSession(); @@ -330,11 +346,12 @@ private: kBinaryLowByteFirst }; + void AppendString(const char* string); void AppendOperator(Operator op); void AppendAttribute(Attribute attr); void AppendDataTag(DataTag tag); - PCL6Driver *fDriver; // the driver used for writing the generated PCL6 data + PCL6WriterStream *fStream; // the stream used for writing the generated PCL6 data uint8 *fBuffer; // the buffer uint32 fSize; // the size of the buffer uint32 fIndex; // the index of the next byte to be written diff --git a/src/add-ons/print/drivers/pcl6/Rasterizer.cpp b/src/add-ons/print/drivers/pcl6/Rasterizer.cpp new file mode 100644 index 0000000000..8c1ce932b2 --- /dev/null +++ b/src/add-ons/print/drivers/pcl6/Rasterizer.cpp @@ -0,0 +1,92 @@ +#include "Rasterizer.h" + +#include + +Rasterizer::Rasterizer(Halftone* halftone) + : fHalftone(halftone) + , fIndex(-1) +{ + fBounds.bottom = -2; +} + +Rasterizer::~Rasterizer() +{ +} + +bool +Rasterizer::SetBitmap(int x, int y, BBitmap *bitmap, int pageHeight) +{ + fX = x; + fY = y; + + BRect bounds = bitmap->Bounds(); + + fBounds.left = (int)bounds.left; + fBounds.top = (int)bounds.top; + fBounds.right = (int)bounds.right; + fBounds.bottom = (int)bounds.bottom; + + int height = fBounds.bottom - fBounds.top + 1; + + if (y + height > pageHeight) { + height = pageHeight - y; + fBounds.bottom = fBounds.top + height - 1; + } + + if (!get_valid_rect(bitmap, &fBounds)) { + return false; + } + + fprintf(stderr, "valid rect (%d, %d, %d, %d)\n", + fBounds.left, fBounds.top, fBounds.right, fBounds.bottom); + + fWidth = fBounds.right - fBounds.left + 1; + fHeight = fBounds.bottom - fBounds.top + 1; + + if (fWidth < 0 || fHeight < 0) { + fprintf(stderr, "Error: get_valid_rect returned an empty rect (%f, %f, %f, %f) -> (%d, %d, %d, %d)!", + bounds.left, bounds.top, bounds.right, bounds.bottom, + fBounds.left, fBounds.top, fBounds.right, fBounds.bottom); + return false; + } + + fBPR = bitmap->BytesPerRow(); + fBits = (uchar*)bitmap->Bits(); + // offset to top, left point of rect + fBits += fBounds.top * fBPR + fBounds.left * 4; + + // XXX why not fX += ...? + fX = fBounds.left; + fY += fBounds.top; + fIndex = fBounds.top; + return true; +} + +bool +Rasterizer::HasNextLine() +{ + return fIndex <= fBounds.bottom; +} + +const void* +Rasterizer::RasterizeNextLine() +{ + if (!HasNextLine()) { + return NULL; + } + + const void *result; + result = RasterizeLine(fX, fY, (const ColorRGB32Little*)fBits); + fBits += fBPR; + fY ++; + fIndex ++; + return result; +} + +void +Rasterizer::RasterizeBitmap() +{ + while (HasNextLine()) { + RasterizeNextLine(); + } +} diff --git a/src/add-ons/print/drivers/pcl6/Rasterizer.h b/src/add-ons/print/drivers/pcl6/Rasterizer.h new file mode 100644 index 0000000000..deff722509 --- /dev/null +++ b/src/add-ons/print/drivers/pcl6/Rasterizer.h @@ -0,0 +1,74 @@ +#ifndef _RASTERIZER_H +#define _RASTERIZER_H + +#include "Halftone.h" +#include "ValidRect.h" + +#include + +// +class Rasterizer { +public: + Rasterizer(Halftone *halftone); + virtual ~Rasterizer(); + + /** + * Sets the bitmap to be rasterized + * Either the iterator methods HasNextLine() and RasterizeNextLine() + * can be used to rasterize the bitmap line per line or the method RasterizeBitamp() + * can be used to rasterize the entire bitmap at once. + * @param x the x position of the image on the page. + * @param y the y position of the image on the page. + * @param bitmap the bitamp to be rasterized. + * @param height the page height. + * @return true if the bitmap is not empty and false if the bitmap is empty. + */ + bool SetBitmap(int x, int y, BBitmap *bitmap, int pageHeight); + + // Is there a next line? + bool HasNextLine(); + // Rasterizes the next line and returns the line. + const void *RasterizeNextLine(); + + // Iterates over all lines. + void RasterizeBitmap(); + + // Returns the Halftone object specified in the constructor + Halftone *GetHalftone() { return fHalftone; } + // The bounds of the bitmap to be rasterized + RECT GetBounds() { return fBounds; } + // The width (in pixels) of the bounds passed to Rasterized() + int GetWidth() { return fWidth; } + // The height (in pixels) of the bounds passed to Rasterize() + int GetHeight() { return fHeight; } + // Returns the current x position + int GetX() { return fX; } + // Returns the current y position + int GetY() { return fY; } + + // The method is called for each line in the bitmap. + virtual const void *RasterizeLine(int x, int y, const ColorRGB32Little* source) = 0; + + // Returns the number of bytes to store widthInPixels pixels with BPP = bitsPerPixel + // and padBytes number of pad bytes. + static int RowBufferSize(int widthInPixels, int bitsPerPixel, int padBytes = 1) { + int sizeInBytes = (widthInPixels * bitsPerPixel + 7) / 8; + return padBytes * ((sizeInBytes + padBytes - 1) / padBytes); + } + +private: + Halftone *fHalftone; + + RECT fBounds; + int fWidth; + int fHeight; + int fX; + int fY; + + const uchar *fBits; + int fBPR; + int fIndex; +}; + + +#endif