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