xref: /haiku/src/add-ons/print/drivers/postscript/PS.cpp (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
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