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->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 217 alert->Go(); 218 return false; 219 } 220 } 221 222 223 void 224 PCL5Driver::_JobStart() 225 { 226 const bool color = GetJobData()->GetColor() == JobData::kColor; 227 // enter PCL5 228 WriteSpoolString("\033%%-12345X@PJL ENTER LANGUAGE=PCL\n"); 229 // reset 230 WriteSpoolString("\033E"); 231 // dpi 232 WriteSpoolString("\033*t%dR", GetJobData()->GetXres()); 233 // unit of measure 234 WriteSpoolString("\033&u%dD", GetJobData()->GetXres()); 235 // page size 236 WriteSpoolString("\033&l0A"); 237 // page orientation 238 WriteSpoolString("\033&l0O"); 239 if (color) { 240 // 3 color planes (red, green, blue) 241 WriteSpoolString("\033*r3U"); 242 } 243 // raster presentation 244 WriteSpoolString("\033*r0F"); 245 // top maring and perforation skip 246 WriteSpoolString("\033&l0e0L"); 247 // clear horizontal margins 248 WriteSpoolString("\0339"); 249 // number of copies 250 // WriteSpoolString("\033&l%ldL", GetJobData()->GetCopies()); 251 } 252 253 254 void 255 PCL5Driver::_StartRasterGraphics(int width, int height) 256 { 257 // width 258 WriteSpoolString("\033*r%dS", width); 259 // height 260 WriteSpoolString("\033*r%dT", height); 261 // start raster graphics 262 WriteSpoolString("\033*r1A"); 263 fCompressionMethod = -1; 264 } 265 266 267 void 268 PCL5Driver::_EndRasterGraphics() 269 { 270 WriteSpoolString("\033*rB"); 271 } 272 273 274 void 275 PCL5Driver::_RasterGraphics(int compressionMethod, const uchar* buffer, 276 int size, bool lastPlane) 277 { 278 if (fCompressionMethod != compressionMethod) { 279 WriteSpoolString("\033*b%dM", compressionMethod); 280 fCompressionMethod = compressionMethod; 281 } 282 WriteSpoolString("\033*b%d", size); 283 if (lastPlane) 284 WriteSpoolString("W"); 285 else 286 WriteSpoolString("V"); 287 288 WriteSpoolData(buffer, size); 289 } 290 291 292 void 293 PCL5Driver::_JobEnd() 294 { 295 WriteSpoolString("\033&l1T"); 296 WriteSpoolString("\033E"); 297 } 298 299 300 void 301 PCL5Driver::_Move(int x, int y) 302 { 303 WriteSpoolString("\033*p%dx%dY", x, y + 75); 304 } 305 306 307 int 308 PCL5Driver::_BytesToEnterCompressionMethod(int compressionMethod) 309 { 310 if (fCompressionMethod == compressionMethod) 311 return 0; 312 else 313 return 5; 314 } 315