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