1 /* 2 * PCL5.cpp 3 * Copyright 1999-2000 Y.Takagi. All Rights Reserved. 4 * Copyright 2003 Michael Pfeiffer. 5 */ 6 7 8 #include "PCL5.h" 9 10 #include <memory> 11 12 #include <Alert.h> 13 #include <Bitmap.h> 14 #include <File.h> 15 16 #include "DbgMsg.h" 17 #include "Halftone.h" 18 #include "JobData.h" 19 #include "PackBits.h" 20 #include "PCL5Cap.h" 21 #include "PrinterData.h" 22 #include "UIDriver.h" 23 #include "ValidRect.h" 24 25 26 PCL5Driver::PCL5Driver(BMessage* message, PrinterData* printerData, 27 const PrinterCap* printerCap) 28 : 29 GraphicsDriver(message, printerData, printerCap), 30 fCompressionMethod(0), 31 fHalftone(NULL) 32 { 33 } 34 35 36 bool 37 PCL5Driver::StartDocument() 38 { 39 try { 40 _JobStart(); 41 fHalftone = new Halftone(GetJobData()->GetSurfaceType(), 42 GetJobData()->GetGamma(), GetJobData()->GetInkDensity(), 43 GetJobData()->GetDitherType()); 44 return true; 45 } 46 catch (TransportException& err) { 47 return false; 48 } 49 } 50 51 52 bool 53 PCL5Driver::StartPage(int) 54 { 55 return true; 56 } 57 58 59 bool 60 PCL5Driver::EndPage(int) 61 { 62 try { 63 WriteSpoolChar('\014'); 64 return true; 65 } 66 catch (TransportException& err) { 67 return false; 68 } 69 } 70 71 72 bool 73 PCL5Driver::EndDocument(bool) 74 { 75 try { 76 if (fHalftone != NULL) { 77 delete fHalftone; 78 fHalftone = NULL; 79 } 80 _JobEnd(); 81 return true; 82 } 83 catch (TransportException& err) { 84 return false; 85 } 86 } 87 88 89 bool 90 PCL5Driver::NextBand(BBitmap* bitmap, BPoint* offset) 91 { 92 DBGMSG(("> nextBand\n")); 93 94 try { 95 BRect bounds = bitmap->Bounds(); 96 97 RECT rc; 98 rc.left = (int)bounds.left; 99 rc.top = (int)bounds.top; 100 rc.right = (int)bounds.right; 101 rc.bottom = (int)bounds.bottom; 102 103 int height = rc.bottom - rc.top + 1; 104 105 int x = (int)offset->x; 106 int y = (int)offset->y; 107 108 int pageHeight = GetPageHeight(); 109 110 if (y + height > pageHeight) 111 height = pageHeight - y; 112 113 rc.bottom = height - 1; 114 115 DBGMSG(("height = %d\n", height)); 116 DBGMSG(("x = %d\n", x)); 117 DBGMSG(("y = %d\n", y)); 118 119 if (get_valid_rect(bitmap, &rc)) { 120 121 DBGMSG(("validate rect = %d, %d, %d, %d\n", 122 rc.left, rc.top, rc.right, rc.bottom)); 123 124 x = rc.left; 125 y += rc.top; 126 127 int width = rc.right - rc.left + 1; 128 int widthByte = (width + 7) / 8; 129 // byte boundary 130 int height = rc.bottom - rc.top + 1; 131 int in_size = widthByte; 132 int out_size = (widthByte * 6 + 4) / 5; 133 int delta = bitmap->BytesPerRow(); 134 135 DBGMSG(("width = %d\n", width)); 136 DBGMSG(("widthByte = %d\n", widthByte)); 137 DBGMSG(("height = %d\n", height)); 138 DBGMSG(("in_size = %d\n", in_size)); 139 DBGMSG(("out_size = %d\n", out_size)); 140 DBGMSG(("delta = %d\n", delta)); 141 DBGMSG(("renderobj->Get_pixel_depth() = %d\n", fHalftone->GetPixelDepth())); 142 143 uchar* ptr = static_cast<uchar*>(bitmap->Bits()) 144 + rc.top * delta 145 + (rc.left * fHalftone->GetPixelDepth()) / 8; 146 147 int compressionMethod; 148 int compressedSize; 149 const uchar* buffer; 150 151 uchar* in_buffer = new uchar[in_size]; 152 uchar* out_buffer = new uchar[out_size]; 153 154 auto_ptr<uchar> _in_buffer (in_buffer); 155 auto_ptr<uchar> _out_buffer(out_buffer); 156 157 DBGMSG(("move\n")); 158 159 _Move(x, y); 160 _StartRasterGraphics(width, height); 161 162 const bool color = GetJobData()->GetColor() == JobData::kColor; 163 const int num_planes = color ? 3 : 1; 164 165 if (color) { 166 fHalftone->SetPlanes(Halftone::kPlaneRGB1); 167 fHalftone->SetBlackValue(Halftone::kLowValueMeansBlack); 168 } 169 170 for (int i = rc.top; i <= rc.bottom; i++) { 171 172 for (int plane = 0; plane < num_planes; plane ++) { 173 174 fHalftone->Dither(in_buffer, ptr, x, y, width); 175 176 compressedSize = pack_bits(out_buffer, in_buffer, in_size); 177 178 if (compressedSize + _BytesToEnterCompressionMethod(2) 179 < in_size + _BytesToEnterCompressionMethod(0)) { 180 compressionMethod = 2; // back bits 181 buffer = out_buffer; 182 } else { 183 compressionMethod = 0; // uncompressed 184 buffer = in_buffer; 185 compressedSize = in_size; 186 } 187 188 _RasterGraphics( 189 compressionMethod, 190 buffer, 191 compressedSize, 192 plane == num_planes - 1); 193 194 } 195 196 ptr += delta; 197 y++; 198 } 199 200 _EndRasterGraphics(); 201 202 } else 203 DBGMSG(("band bitmap is clean.\n")); 204 205 if (y >= pageHeight) { 206 offset->x = -1.0; 207 offset->y = -1.0; 208 } else 209 offset->y += height; 210 211 DBGMSG(("< nextBand\n")); 212 return true; 213 } 214 catch (TransportException& err) { 215 BAlert* alert = new BAlert("", err.What(), "OK"); 216 alert->Go(); 217 return false; 218 } 219 } 220 221 222 void 223 PCL5Driver::_JobStart() 224 { 225 const bool color = GetJobData()->GetColor() == JobData::kColor; 226 // enter PCL5 227 WriteSpoolString("\033%%-12345X@PJL ENTER LANGUAGE=PCL\n"); 228 // reset 229 WriteSpoolString("\033E"); 230 // dpi 231 WriteSpoolString("\033*t%dR", GetJobData()->GetXres()); 232 // unit of measure 233 WriteSpoolString("\033&u%dD", GetJobData()->GetXres()); 234 // page size 235 WriteSpoolString("\033&l0A"); 236 // page orientation 237 WriteSpoolString("\033&l0O"); 238 if (color) { 239 // 3 color planes (red, green, blue) 240 WriteSpoolString("\033*r3U"); 241 } 242 // raster presentation 243 WriteSpoolString("\033*r0F"); 244 // top maring and perforation skip 245 WriteSpoolString("\033&l0e0L"); 246 // clear horizontal margins 247 WriteSpoolString("\0339"); 248 // number of copies 249 // WriteSpoolString("\033&l%ldL", GetJobData()->GetCopies()); 250 } 251 252 253 void 254 PCL5Driver::_StartRasterGraphics(int width, int height) 255 { 256 // width 257 WriteSpoolString("\033*r%dS", width); 258 // height 259 WriteSpoolString("\033*r%dT", height); 260 // start raster graphics 261 WriteSpoolString("\033*r1A"); 262 fCompressionMethod = -1; 263 } 264 265 266 void 267 PCL5Driver::_EndRasterGraphics() 268 { 269 WriteSpoolString("\033*rB"); 270 } 271 272 273 void 274 PCL5Driver::_RasterGraphics(int compressionMethod, const uchar* buffer, 275 int size, bool lastPlane) 276 { 277 if (fCompressionMethod != compressionMethod) { 278 WriteSpoolString("\033*b%dM", compressionMethod); 279 fCompressionMethod = compressionMethod; 280 } 281 WriteSpoolString("\033*b%d", size); 282 if (lastPlane) 283 WriteSpoolString("W"); 284 else 285 WriteSpoolString("V"); 286 287 WriteSpoolData(buffer, size); 288 } 289 290 291 void 292 PCL5Driver::_JobEnd() 293 { 294 WriteSpoolString("\033&l1T"); 295 WriteSpoolString("\033E"); 296 } 297 298 299 void 300 PCL5Driver::_Move(int x, int y) 301 { 302 WriteSpoolString("\033*p%dx%dY", x, y + 75); 303 } 304 305 306 int 307 PCL5Driver::_BytesToEnterCompressionMethod(int compressionMethod) 308 { 309 if (fCompressionMethod == compressionMethod) 310 return 0; 311 else 312 return 5; 313 } 314