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 // move origin from bottom left to top left 74 // and set margin 75 writeSpoolString("%f %f translate\n", leftMargin, getJobData()->getPaperRect().Height()-topMargin); 76 // y values increase from top to bottom 77 // units of measure is dpi 78 writeSpoolString("72 %d div 72 -%d div scale\n", getJobData()->getXres(), getJobData()->getYres()); 79 } 80 81 bool PSDriver::endDoc(bool) 82 { 83 try { 84 if (fHalftone) { 85 delete fHalftone; 86 } 87 jobEnd(); 88 return true; 89 } 90 catch (TransportException &err) { 91 return false; 92 } 93 } 94 95 inline uchar hex_digit(uchar value) 96 { 97 if (value <= 9) return '0'+value; 98 else return 'a'+(value-10); 99 } 100 101 bool PSDriver::nextBand(BBitmap *bitmap, BPoint *offset) 102 { 103 DBGMSG(("> nextBand\n")); 104 105 try { 106 BRect bounds = bitmap->Bounds(); 107 108 RECT rc; 109 rc.left = (int)bounds.left; 110 rc.top = (int)bounds.top; 111 rc.right = (int)bounds.right; 112 rc.bottom = (int)bounds.bottom; 113 114 int height = rc.bottom - rc.top + 1; 115 116 int x = (int)offset->x; 117 int y = (int)offset->y; 118 119 int page_height = getPageHeight(); 120 121 if (y + height > page_height) { 122 height = page_height - y; 123 } 124 125 rc.bottom = height - 1; 126 127 DBGMSG(("height = %d\n", height)); 128 DBGMSG(("x = %d\n", x)); 129 DBGMSG(("y = %d\n", y)); 130 131 if (get_valid_rect(bitmap, &rc)) { 132 133 DBGMSG(("validate rect = %d, %d, %d, %d\n", 134 rc.left, rc.top, rc.right, rc.bottom)); 135 136 x = rc.left; 137 y += rc.top; 138 139 bool color = getJobData()->getColor() == JobData::kColor; 140 int width = rc.right - rc.left + 1; 141 int widthByte = (width + 7) / 8; /* byte boundary */ 142 int height = rc.bottom - rc.top + 1; 143 int in_size = color ? width : widthByte; 144 int out_size = color ? width * 6: widthByte * 2; 145 int delta = bitmap->BytesPerRow(); 146 147 DBGMSG(("width = %d\n", width)); 148 DBGMSG(("widthByte = %d\n", widthByte)); 149 DBGMSG(("height = %d\n", height)); 150 DBGMSG(("out_size = %d\n", out_size)); 151 DBGMSG(("delta = %d\n", delta)); 152 DBGMSG(("renderobj->get_pixel_depth() = %d\n", fHalftone->getPixelDepth())); 153 154 uchar *ptr = (uchar *)bitmap->Bits() 155 + rc.top * delta 156 + (rc.left * fHalftone->getPixelDepth()) / 8; 157 158 int compression_method; 159 int compressed_size; 160 const uchar *buffer; 161 162 uchar *in_buffer = new uchar[in_size]; // gray values 163 uchar *out_buffer = new uchar[out_size]; // gray values in hexadecimal 164 165 auto_ptr<uchar> _in_buffer(in_buffer); 166 auto_ptr<uchar> _out_buffer(out_buffer); 167 168 DBGMSG(("move\n")); 169 170 int size = color ? width*3 : in_size; 171 startRasterGraphics(x, y, width, height, size); 172 173 for (int i = rc.top; i <= rc.bottom; i++) { 174 if (color) { 175 uchar* out = out_buffer; 176 uchar* in = ptr; 177 for (int w = width; w > 0; w --) { 178 *out++ = hex_digit((in[2]) >> 4); 179 *out++ = hex_digit((in[2]) & 15); 180 *out++ = hex_digit((in[1]) >> 4); 181 *out++ = hex_digit((in[1]) & 15); 182 *out++ = hex_digit((in[0]) >> 4); 183 *out++ = hex_digit((in[0]) & 15); 184 in += 4; 185 } 186 } else { 187 fHalftone->dither(in_buffer, ptr, x, y, width); 188 189 uchar* in = in_buffer; 190 uchar* out = out_buffer; 191 192 for (int w = in_size; w > 0; w --, in ++) { 193 *in = ~*in; // invert pixels 194 *out++ = hex_digit((*in) >> 4); 195 *out++ = hex_digit((*in) & 15); 196 } 197 } 198 199 { 200 compression_method = 0; // uncompressed 201 buffer = out_buffer; 202 compressed_size = out_size; 203 } 204 205 rasterGraphics( 206 compression_method, 207 buffer, 208 compressed_size); 209 210 ptr += delta; 211 y++; 212 } 213 214 endRasterGraphics(); 215 216 } else { 217 DBGMSG(("band bitmap is clean.\n")); 218 } 219 220 if (y >= page_height) { 221 offset->x = -1.0; 222 offset->y = -1.0; 223 } else { 224 offset->y += height; 225 } 226 227 228 DBGMSG(("< nextBand\n")); 229 return true; 230 } 231 catch (TransportException &err) { 232 BAlert *alert = new BAlert("", err.what(), "OK"); 233 alert->Go(); 234 return false; 235 } 236 } 237 238 void PSDriver::jobStart() 239 { 240 // PostScript header 241 writeSpoolString("%%!PS-Adobe-3.0\n"); 242 writeSpoolString("%%%%LanguageLevel: 1\n"); 243 writeSpoolString("%%%%Title: %s\n", getSpoolMetaData()->getDescription().c_str()); 244 writeSpoolString("%%%%Creator: %s\n", getSpoolMetaData()->getMimeType().c_str()); 245 writeSpoolString("%%%%CreationDate: %s", getSpoolMetaData()->getCreationTime().c_str()); 246 writeSpoolString("%%%%DocumentMedia: Plain %d %d white 0 ( )\n", getJobData()->getPaperRect().IntegerWidth(), getJobData()->getPaperRect().IntegerHeight()); 247 writeSpoolString("%%%%Pages: (atend)\n"); 248 writeSpoolString("%%%%EndComments\n"); 249 250 writeSpoolString("%%%%BeginDefaults\n"); 251 writeSpoolString("%%%%PageMedia: Plain\n"); 252 writeSpoolString("%%%%EndDefaults\n"); 253 } 254 255 void PSDriver::startRasterGraphics(int x, int y, int width, int height, int widthByte) 256 { 257 bool color = getJobData()->getColor() == JobData::kColor; 258 fCompressionMethod = -1; 259 writeSpoolString("gsave\n"); 260 writeSpoolString("/s %d string def\n", widthByte); 261 writeSpoolString("%d %d translate\n", x, y); 262 writeSpoolString("%d %d scale\n", width, height); 263 if (color) { 264 writeSpoolString("%d %d 8\n", width, height); // 8 bpp 265 } else { 266 writeSpoolString("%d %d 1\n", width, height); // 1 bpp 267 } 268 writeSpoolString("[%d 0 0 %d 0 0]\n", width, height); 269 writeSpoolString("{ currentfile s readhexstring pop }\n"); 270 if (color) { 271 writeSpoolString("false 3\n"); // single data source, 3 color components 272 writeSpoolString("colorimage\n"); 273 } else { 274 writeSpoolString("image\n\n"); 275 } 276 } 277 278 void PSDriver::endRasterGraphics() 279 { 280 writeSpoolString("grestore\n"); 281 } 282 283 void PSDriver::rasterGraphics( 284 int compression_method, 285 const uchar *buffer, 286 int size) 287 { 288 if (fCompressionMethod != compression_method) { 289 fCompressionMethod = compression_method; 290 } 291 writeSpoolData(buffer, size); 292 writeSpoolString("\n"); 293 } 294 295 void PSDriver::jobEnd() 296 { 297 writeSpoolString("%%%%Pages: %d\n", fPrintedPages); 298 writeSpoolString("%%%%EOF\n"); 299 } 300