/* * PS.cpp * Copyright 1999-2000 Y.Takagi. All Rights Reserved. * Copyright 2003 Michael Pfeiffer. */ #include #include #include #include #include #include "PS.h" #include "UIDriver.h" #include "JobData.h" #include "PrinterData.h" #include "PSCap.h" #include "PackBits.h" #include "Halftone.h" #include "ValidRect.h" #include "DbgMsg.h" #if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE)) using namespace std; #else #define std #endif PSDriver::PSDriver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap) : GraphicsDriver(msg, printer_data, printer_cap) { fPrintedPages = 0; fHalftone = NULL; } bool PSDriver::startDoc() { try { jobStart(); fHalftone = new Halftone(getJobData()->getSurfaceType(), getJobData()->getGamma(), getJobData()->getInkDensity(), getJobData()->getDitherType()); return true; } catch (TransportException &err) { return false; } } bool PSDriver::startPage(int page) { page ++; writeSpoolString("%%%%Page: %d %d\n", page, page); writeSpoolString("gsave\n"); setupCTM(); return true; } bool PSDriver::endPage(int) { try { fPrintedPages ++; writeSpoolString("grestore\n"); writeSpoolString("showpage\n"); return true; } catch (TransportException &err) { return false; } } void PSDriver::setupCTM() { const float leftMargin = getJobData()->getPrintableRect().left; const float topMargin = getJobData()->getPrintableRect().top; // move origin from bottom left to top left // and set margin writeSpoolString("%f %f translate\n", leftMargin, getJobData()->getPaperRect().Height()-topMargin); // y values increase from top to bottom // units of measure is dpi writeSpoolString("72 %d div 72 -%d div scale\n", getJobData()->getXres(), getJobData()->getYres()); } bool PSDriver::endDoc(bool) { try { if (fHalftone) { delete fHalftone; } jobEnd(); return true; } catch (TransportException &err) { return false; } } inline uchar hex_digit(uchar value) { if (value <= 9) return '0'+value; else return 'a'+(value-10); } bool PSDriver::nextBand(BBitmap *bitmap, BPoint *offset) { DBGMSG(("> nextBand\n")); try { BRect bounds = bitmap->Bounds(); RECT rc; rc.left = (int)bounds.left; rc.top = (int)bounds.top; rc.right = (int)bounds.right; rc.bottom = (int)bounds.bottom; int height = rc.bottom - rc.top + 1; int x = (int)offset->x; int y = (int)offset->y; int page_height = getPageHeight(); if (y + height > page_height) { height = page_height - y; } rc.bottom = height - 1; DBGMSG(("height = %d\n", height)); DBGMSG(("x = %d\n", x)); DBGMSG(("y = %d\n", y)); if (get_valid_rect(bitmap, &rc)) { DBGMSG(("validate rect = %d, %d, %d, %d\n", rc.left, rc.top, rc.right, rc.bottom)); x = rc.left; y += rc.top; bool color = getJobData()->getColor() == JobData::kColor; int width = rc.right - rc.left + 1; int widthByte = (width + 7) / 8; /* byte boundary */ int height = rc.bottom - rc.top + 1; int in_size = color ? width : widthByte; int out_size = color ? width * 6: widthByte * 2; int delta = bitmap->BytesPerRow(); DBGMSG(("width = %d\n", width)); DBGMSG(("widthByte = %d\n", widthByte)); DBGMSG(("height = %d\n", height)); DBGMSG(("out_size = %d\n", out_size)); DBGMSG(("delta = %d\n", delta)); DBGMSG(("renderobj->get_pixel_depth() = %d\n", fHalftone->getPixelDepth())); uchar *ptr = (uchar *)bitmap->Bits() + rc.top * delta + (rc.left * fHalftone->getPixelDepth()) / 8; int compression_method; int compressed_size; const uchar *buffer; uchar *in_buffer = new uchar[in_size]; // gray values uchar *out_buffer = new uchar[out_size]; // gray values in hexadecimal auto_ptr _in_buffer(in_buffer); auto_ptr _out_buffer(out_buffer); DBGMSG(("move\n")); int size = color ? width*3 : in_size; startRasterGraphics(x, y, width, height, size); for (int i = rc.top; i <= rc.bottom; i++) { if (color) { uchar* out = out_buffer; uchar* in = ptr; for (int w = width; w > 0; w --) { *out++ = hex_digit((in[2]) >> 4); *out++ = hex_digit((in[2]) & 15); *out++ = hex_digit((in[1]) >> 4); *out++ = hex_digit((in[1]) & 15); *out++ = hex_digit((in[0]) >> 4); *out++ = hex_digit((in[0]) & 15); in += 4; } } else { fHalftone->dither(in_buffer, ptr, x, y, width); uchar* in = in_buffer; uchar* out = out_buffer; for (int w = in_size; w > 0; w --, in ++) { *in = ~*in; // invert pixels *out++ = hex_digit((*in) >> 4); *out++ = hex_digit((*in) & 15); } } { compression_method = 0; // uncompressed buffer = out_buffer; compressed_size = out_size; } rasterGraphics( compression_method, buffer, compressed_size); ptr += delta; y++; } endRasterGraphics(); } else { DBGMSG(("band bitmap is clean.\n")); } if (y >= page_height) { offset->x = -1.0; offset->y = -1.0; } else { offset->y += height; } DBGMSG(("< nextBand\n")); return true; } catch (TransportException &err) { BAlert *alert = new BAlert("", err.what(), "OK"); alert->Go(); return false; } } void PSDriver::jobStart() { // PostScript header writeSpoolString("%%!PS-Adobe-3.0\n"); writeSpoolString("%%%%LanguageLevel: 1\n"); writeSpoolString("%%%%Title: %s\n", getSpoolMetaData()->getDescription().c_str()); writeSpoolString("%%%%Creator: %s\n", getSpoolMetaData()->getMimeType().c_str()); writeSpoolString("%%%%CreationDate: %s", getSpoolMetaData()->getCreationTime().c_str()); writeSpoolString("%%%%DocumentMedia: Plain %d %d white 0 ( )\n", getJobData()->getPaperRect().IntegerWidth(), getJobData()->getPaperRect().IntegerHeight()); writeSpoolString("%%%%Pages: (atend)\n"); writeSpoolString("%%%%EndComments\n"); writeSpoolString("%%%%BeginDefaults\n"); writeSpoolString("%%%%PageMedia: Plain\n"); writeSpoolString("%%%%EndDefaults\n"); } void PSDriver::startRasterGraphics(int x, int y, int width, int height, int widthByte) { bool color = getJobData()->getColor() == JobData::kColor; fCompressionMethod = -1; writeSpoolString("gsave\n"); writeSpoolString("/s %d string def\n", widthByte); writeSpoolString("%d %d translate\n", x, y); writeSpoolString("%d %d scale\n", width, height); if (color) { writeSpoolString("%d %d 8\n", width, height); // 8 bpp } else { writeSpoolString("%d %d 1\n", width, height); // 1 bpp } writeSpoolString("[%d 0 0 %d 0 0]\n", width, height); writeSpoolString("{ currentfile s readhexstring pop }\n"); if (color) { writeSpoolString("false 3\n"); // single data source, 3 color components writeSpoolString("colorimage\n"); } else { writeSpoolString("image\n\n"); } } void PSDriver::endRasterGraphics() { writeSpoolString("grestore\n"); } void PSDriver::rasterGraphics( int compression_method, const uchar *buffer, int size) { if (fCompressionMethod != compression_method) { fCompressionMethod = compression_method; } writeSpoolData(buffer, size); writeSpoolString("\n"); } void PSDriver::jobEnd() { writeSpoolString("%%%%Pages: %d\n", fPrintedPages); writeSpoolString("%%%%EOF\n"); }