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