1 /* 2 * PS.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 <stdio.h> 12 #include "PS.h" 13 #include "UIDriver.h" 14 #include "JobData.h" 15 #include "PrinterData.h" 16 #include "PSCap.h" 17 #include "PackBits.h" 18 #include "Halftone.h" 19 #include "ValidRect.h" 20 #include "DbgMsg.h" 21 22 23 #if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) 24 using namespace std; 25 #else 26 #define std 27 #endif 28 29 PSDriver::PSDriver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap) 30 : GraphicsDriver(msg, printer_data, printer_cap) 31 { 32 fPrintedPages = 0; 33 fHalftone = NULL; 34 } 35 36 bool PSDriver::startDoc() 37 { 38 try { 39 jobStart(); 40 fHalftone = new Halftone(getJobData()->getSurfaceType(), getJobData()->getGamma(), getJobData()->getInkDensity(), getJobData()->getDitherType()); 41 return true; 42 } 43 catch (TransportException &err) { 44 return false; 45 } 46 } 47 48 bool PSDriver::startPage(int page) 49 { 50 page ++; 51 writeSpoolString("%%%%Page: %d %d\n", page, page); 52 writeSpoolString("gsave\n"); 53 setupCTM(); 54 return true; 55 } 56 57 bool PSDriver::endPage(int) 58 { 59 try { 60 fPrintedPages ++; 61 writeSpoolString("grestore\n"); 62 writeSpoolString("showpage\n"); 63 return true; 64 } 65 catch (TransportException &err) { 66 return false; 67 } 68 } 69 70 void PSDriver::setupCTM() { 71 const float leftMargin = getJobData()->getPrintableRect().left; 72 const float topMargin = getJobData()->getPrintableRect().top; 73 if (getJobData()->getOrientation() == JobData::kPortrait) { 74 // move origin from bottom left to top left 75 // and set margin 76 writeSpoolString("%f %f translate\n", leftMargin, getJobData()->getPaperRect().Height()-topMargin); 77 } else { 78 // landscape: 79 // move origin from bottom left to margin top and left 80 // and rotate page contents 81 writeSpoolString("%f %f translate\n", topMargin, leftMargin); 82 writeSpoolString("90 rotate\n"); 83 } 84 // y values increase from top to bottom 85 // units of measure is dpi 86 writeSpoolString("72 %d div 72 -%d div scale\n", getJobData()->getXres(), getJobData()->getYres()); 87 } 88 89 bool PSDriver::endDoc(bool) 90 { 91 try { 92 if (fHalftone) { 93 delete fHalftone; 94 } 95 jobEnd(); 96 return true; 97 } 98 catch (TransportException &err) { 99 return false; 100 } 101 } 102 103 inline uchar hex_digit(uchar value) 104 { 105 if (value <= 9) return '0'+value; 106 else return 'a'+(value-10); 107 } 108 109 bool PSDriver::nextBand(BBitmap *bitmap, BPoint *offset) 110 { 111 DBGMSG(("> nextBand\n")); 112 113 try { 114 BRect bounds = bitmap->Bounds(); 115 116 RECT rc; 117 rc.left = (int)bounds.left; 118 rc.top = (int)bounds.top; 119 rc.right = (int)bounds.right; 120 rc.bottom = (int)bounds.bottom; 121 122 int height = rc.bottom - rc.top + 1; 123 124 int x = (int)offset->x; 125 int y = (int)offset->y; 126 127 int page_height = getPageHeight(); 128 129 if (y + height > page_height) { 130 height = page_height - y; 131 } 132 133 rc.bottom = height - 1; 134 135 DBGMSG(("height = %d\n", height)); 136 DBGMSG(("x = %d\n", x)); 137 DBGMSG(("y = %d\n", y)); 138 139 if (get_valid_rect(bitmap, &rc)) { 140 141 DBGMSG(("validate rect = %d, %d, %d, %d\n", 142 rc.left, rc.top, rc.right, rc.bottom)); 143 144 x = rc.left; 145 y += rc.top; 146 147 bool color = getJobData()->getColor() == JobData::kColor; 148 int width = rc.right - rc.left + 1; 149 int widthByte = (width + 7) / 8; /* byte boundary */ 150 int height = rc.bottom - rc.top + 1; 151 int in_size = color ? width : widthByte; 152 int out_size = color ? width * 6: widthByte * 2; 153 int delta = bitmap->BytesPerRow(); 154 155 DBGMSG(("width = %d\n", width)); 156 DBGMSG(("widthByte = %d\n", widthByte)); 157 DBGMSG(("height = %d\n", height)); 158 DBGMSG(("out_size = %d\n", out_size)); 159 DBGMSG(("delta = %d\n", delta)); 160 DBGMSG(("renderobj->get_pixel_depth() = %d\n", fHalftone->getPixelDepth())); 161 162 uchar *ptr = (uchar *)bitmap->Bits() 163 + rc.top * delta 164 + (rc.left * fHalftone->getPixelDepth()) / 8; 165 166 int compression_method; 167 int compressed_size; 168 const uchar *buffer; 169 170 uchar *in_buffer = new uchar[in_size]; // gray values 171 uchar *out_buffer = new uchar[out_size]; // gray values in hexadecimal 172 173 auto_ptr<uchar> _in_buffer(in_buffer); 174 auto_ptr<uchar> _out_buffer(out_buffer); 175 176 DBGMSG(("move\n")); 177 178 int size = color ? width*3 : in_size; 179 startRasterGraphics(x, y, width, height, size); 180 181 for (int i = rc.top; i <= rc.bottom; i++) { 182 if (color) { 183 uchar* out = out_buffer; 184 uchar* in = ptr; 185 for (int w = width; w > 0; w --) { 186 *out++ = hex_digit((in[2]) >> 4); 187 *out++ = hex_digit((in[2]) & 15); 188 *out++ = hex_digit((in[1]) >> 4); 189 *out++ = hex_digit((in[1]) & 15); 190 *out++ = hex_digit((in[0]) >> 4); 191 *out++ = hex_digit((in[0]) & 15); 192 in += 4; 193 } 194 } else { 195 fHalftone->dither(in_buffer, ptr, x, y, width); 196 197 uchar* in = in_buffer; 198 uchar* out = out_buffer; 199 200 for (int w = in_size; w > 0; w --, in ++) { 201 *in = ~*in; // invert pixels 202 *out++ = hex_digit((*in) >> 4); 203 *out++ = hex_digit((*in) & 15); 204 } 205 } 206 207 { 208 compression_method = 0; // uncompressed 209 buffer = out_buffer; 210 compressed_size = out_size; 211 } 212 213 rasterGraphics( 214 compression_method, 215 buffer, 216 compressed_size); 217 218 ptr += delta; 219 y++; 220 } 221 222 endRasterGraphics(); 223 224 } else { 225 DBGMSG(("band bitmap is clean.\n")); 226 } 227 228 if (y >= page_height) { 229 offset->x = -1.0; 230 offset->y = -1.0; 231 } else { 232 offset->y += height; 233 } 234 235 236 DBGMSG(("< nextBand\n")); 237 return true; 238 } 239 catch (TransportException &err) { 240 BAlert *alert = new BAlert("", err.what(), "OK"); 241 alert->Go(); 242 return false; 243 } 244 } 245 246 void PSDriver::jobStart() 247 { 248 // PostScript header 249 writeSpoolString("%%!PS-Adobe-3.0\n"); 250 writeSpoolString("%%%%LanguageLevel: 1\n"); 251 writeSpoolString("%%%%Title: %s\n", getSpoolMetaData()->getDescription().c_str()); 252 writeSpoolString("%%%%Creator: %s\n", getSpoolMetaData()->getMimeType().c_str()); 253 writeSpoolString("%%%%CreationDate: %s", getSpoolMetaData()->getCreationTime().c_str()); 254 writeSpoolString("%%%%DocumentMedia: Plain %d %d white 0 ( )\n", getJobData()->getPaperRect().IntegerWidth(), getJobData()->getPaperRect().IntegerHeight()); 255 writeSpoolString("%%%%Pages: (atend)\n"); 256 writeSpoolString("%%%%EndComments\n"); 257 258 writeSpoolString("%%%%BeginDefaults\n"); 259 writeSpoolString("%%%%PageMedia: Plain\n"); 260 writeSpoolString("%%%%EndDefaults\n"); 261 } 262 263 void PSDriver::startRasterGraphics(int x, int y, int width, int height, int widthByte) 264 { 265 bool color = getJobData()->getColor() == JobData::kColor; 266 fCompressionMethod = -1; 267 writeSpoolString("gsave\n"); 268 writeSpoolString("/s %d string def\n", widthByte); 269 writeSpoolString("%d %d translate\n", x, y); 270 writeSpoolString("%d %d scale\n", width, height); 271 if (color) { 272 writeSpoolString("%d %d 8\n", width, height); // 8 bpp 273 } else { 274 writeSpoolString("%d %d 1\n", width, height); // 1 bpp 275 } 276 writeSpoolString("[%d 0 0 %d 0 0]\n", width, height); 277 writeSpoolString("{ currentfile s readhexstring pop }\n"); 278 if (color) { 279 writeSpoolString("false 3\n"); // single data source, 3 color components 280 writeSpoolString("colorimage\n"); 281 } else { 282 writeSpoolString("image\n\n"); 283 } 284 } 285 286 void PSDriver::endRasterGraphics() 287 { 288 writeSpoolString("grestore\n"); 289 } 290 291 void PSDriver::rasterGraphics( 292 int compression_method, 293 const uchar *buffer, 294 int size) 295 { 296 if (fCompressionMethod != compression_method) { 297 fCompressionMethod = compression_method; 298 } 299 writeSpoolData(buffer, size); 300 writeSpoolString("\n"); 301 } 302 303 void PSDriver::jobEnd() 304 { 305 writeSpoolString("%%%%Pages: %d\n", fPrintedPages); 306 writeSpoolString("%%%%EOF\n"); 307 } 308