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