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 <vector> 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 std::vector<uchar> in_buffer(in_size); 152 std::vector<uchar> out_buffer(out_size); 153 154 DBGMSG(("move\n")); 155 156 _Move(x, y); 157 _StartRasterGraphics(width, height); 158 159 const bool color = GetJobData()->GetColor() == JobData::kColor; 160 const int num_planes = color ? 3 : 1; 161 162 if (color) { 163 fHalftone->SetPlanes(Halftone::kPlaneRGB1); 164 fHalftone->SetBlackValue(Halftone::kLowValueMeansBlack); 165 } 166 167 for (int i = rc.top; i <= rc.bottom; i++) { 168 169 for (int plane = 0; plane < num_planes; plane ++) { 170 171 fHalftone->Dither(&in_buffer[0], ptr, x, y, width); 172 173 compressedSize = pack_bits(&out_buffer[0], &in_buffer[0], in_size); 174 175 if (compressedSize + _BytesToEnterCompressionMethod(2) 176 < in_size + _BytesToEnterCompressionMethod(0)) { 177 compressionMethod = 2; // back bits 178 buffer = &out_buffer[0]; 179 } else { 180 compressionMethod = 0; // uncompressed 181 buffer = &in_buffer[0]; 182 compressedSize = in_size; 183 } 184 185 _RasterGraphics( 186 compressionMethod, 187 buffer, 188 compressedSize, 189 plane == num_planes - 1); 190 191 } 192 193 ptr += delta; 194 y++; 195 } 196 197 _EndRasterGraphics(); 198 199 } else 200 DBGMSG(("band bitmap is clean.\n")); 201 202 if (y >= pageHeight) { 203 offset->x = -1.0; 204 offset->y = -1.0; 205 } else 206 offset->y += height; 207 208 DBGMSG(("< nextBand\n")); 209 return true; 210 } 211 catch (TransportException& err) { 212 BAlert* alert = new BAlert("", err.What(), "OK"); 213 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 214 alert->Go(); 215 return false; 216 } 217 } 218 219 220 void 221 PCL5Driver::_JobStart() 222 { 223 const bool color = GetJobData()->GetColor() == JobData::kColor; 224 // enter PCL5 225 WriteSpoolString("\033%%-12345X@PJL ENTER LANGUAGE=PCL\n"); 226 // reset 227 WriteSpoolString("\033E"); 228 // dpi 229 WriteSpoolString("\033*t%dR", GetJobData()->GetXres()); 230 // unit of measure 231 WriteSpoolString("\033&u%dD", GetJobData()->GetXres()); 232 // page size 233 WriteSpoolString("\033&l0A"); 234 // page orientation 235 WriteSpoolString("\033&l0O"); 236 if (color) { 237 // 3 color planes (red, green, blue) 238 WriteSpoolString("\033*r3U"); 239 } 240 // raster presentation 241 WriteSpoolString("\033*r0F"); 242 // top maring and perforation skip 243 WriteSpoolString("\033&l0e0L"); 244 // clear horizontal margins 245 WriteSpoolString("\0339"); 246 // number of copies 247 // WriteSpoolString("\033&l%ldL", GetJobData()->GetCopies()); 248 } 249 250 251 void 252 PCL5Driver::_StartRasterGraphics(int width, int height) 253 { 254 // width 255 WriteSpoolString("\033*r%dS", width); 256 // height 257 WriteSpoolString("\033*r%dT", height); 258 // start raster graphics 259 WriteSpoolString("\033*r1A"); 260 fCompressionMethod = -1; 261 } 262 263 264 void 265 PCL5Driver::_EndRasterGraphics() 266 { 267 WriteSpoolString("\033*rB"); 268 } 269 270 271 void 272 PCL5Driver::_RasterGraphics(int compressionMethod, const uchar* buffer, 273 int size, bool lastPlane) 274 { 275 if (fCompressionMethod != compressionMethod) { 276 WriteSpoolString("\033*b%dM", compressionMethod); 277 fCompressionMethod = compressionMethod; 278 } 279 WriteSpoolString("\033*b%d", size); 280 if (lastPlane) 281 WriteSpoolString("W"); 282 else 283 WriteSpoolString("V"); 284 285 WriteSpoolData(buffer, size); 286 } 287 288 289 void 290 PCL5Driver::_JobEnd() 291 { 292 WriteSpoolString("\033&l1T"); 293 WriteSpoolString("\033E"); 294 } 295 296 297 void 298 PCL5Driver::_Move(int x, int y) 299 { 300 WriteSpoolString("\033*p%dx%dY", x, y + 75); 301 } 302 303 304 int 305 PCL5Driver::_BytesToEnterCompressionMethod(int compressionMethod) 306 { 307 if (fCompressionMethod == compressionMethod) 308 return 0; 309 else 310 return 5; 311 } 312