xref: /haiku/src/add-ons/print/drivers/pcl6/PCL6.cpp (revision 9eb55bc1d104b8fda80898f8b25c94d8000c8255)
1 /*
2  * PCL6.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 "PCL6.h"
12 #include "UIDriver.h"
13 #include "JobData.h"
14 #include "PrinterData.h"
15 #include "PCL6Cap.h"
16 #include "PackBits.h"
17 #include "Halftone.h"
18 #include "ValidRect.h"
19 #include "DbgMsg.h"
20 
21 #if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE))
22 using namespace std;
23 #else
24 #define std
25 #endif
26 
27 PCL6Driver::PCL6Driver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap)
28 	: GraphicsDriver(msg, printer_data, printer_cap)
29 {
30 	fHalftone = NULL;
31 	fStream = NULL;
32 }
33 
34 void PCL6Driver::FlushOutBuffer(HP_StreamHandleType pStream, unsigned long cookie, HP_pUByte pOutBuffer, HP_SInt32 currentBufferLen)
35 {
36 	writeSpoolData(pOutBuffer, currentBufferLen);
37 }
38 
39 
40 bool PCL6Driver::startDoc()
41 {
42 	try {
43 		jobStart();
44 		fHalftone = new Halftone(getJobData()->getSurfaceType(), getJobData()->getGamma());
45 		return true;
46 	}
47 	catch (TransportException &err) {
48 		return false;
49 	}
50 }
51 
52 bool PCL6Driver::endDoc(bool)
53 {
54 	try {
55 		if (fHalftone) {
56 			delete fHalftone;
57 		}
58 		jobEnd();
59 		return true;
60 	}
61 	catch (TransportException &err) {
62 		return false;
63 	}
64 }
65 
66 bool PCL6Driver::nextBand(BBitmap *bitmap, BPoint *offset)
67 {
68 	DBGMSG(("> nextBand\n"));
69 
70 	try {
71 		BRect bounds = bitmap->Bounds();
72 
73 		RECT rc;
74 		rc.left   = (int)bounds.left;
75 		rc.top    = (int)bounds.top;
76 		rc.right  = (int)bounds.right;
77 		rc.bottom = (int)bounds.bottom;
78 
79 		int height = rc.bottom - rc.top + 1;
80 
81 		int x = (int)offset->x;
82 		int y = (int)offset->y;
83 
84 		int page_height = getPageHeight();
85 
86 		if (y + height > page_height) {
87 			height = page_height - y;
88 		}
89 
90 		rc.bottom = height - 1;
91 
92 		DBGMSG(("height = %d\n", height));
93 		DBGMSG(("x = %d\n", x));
94 		DBGMSG(("y = %d\n", y));
95 
96 		if (get_valid_rect(bitmap, &rc)) {
97 
98 			DBGMSG(("validate rect = %d, %d, %d, %d\n",
99 				rc.left, rc.top, rc.right, rc.bottom));
100 
101 			x = rc.left;
102 			y += rc.top;
103 
104 			bool color;
105 			int width;
106 			int widthByte;
107 			int padBytes;
108 			int out_row_length;
109 			int height;
110 			int out_size;
111 			int delta;
112 
113 			color = getJobData()->getColor() == JobData::kColor;
114 
115 			width = rc.right - rc.left + 1;
116 			height = rc.bottom - rc.top + 1;
117 			delta = bitmap->BytesPerRow();
118 
119 			if (color) {
120 				widthByte = 3 * width;
121 			} else {
122 				widthByte = (width + 7) / 8;	/* byte boundary */
123 			}
124 
125 			out_row_length = 4*((widthByte+3)/4);
126 			padBytes = out_row_length - widthByte; /* line length is a multiple of 4 bytes */
127 			out_size  = out_row_length * height;
128 
129 
130 			DBGMSG(("width = %d\n", width));
131 			DBGMSG(("widthByte = %d\n", widthByte));
132 			DBGMSG(("height = %d\n", height));
133 			DBGMSG(("out_size = %d\n", out_size));
134 			DBGMSG(("delta = %d\n", delta));
135 			DBGMSG(("renderobj->get_pixel_depth() = %d\n", fHalftone->getPixelDepth()));
136 
137 			uchar *ptr = (uchar *)bitmap->Bits()
138 						+ rc.top * delta
139 						+ (rc.left * fHalftone->getPixelDepth()) / 8;
140 
141 			int compression_method;
142 			int compressed_size;
143 			const uchar *buffer;
144 
145 			uchar *out_buffer = new uchar[out_size];
146 
147 			uchar *out_ptr = out_buffer;
148 
149 			auto_ptr<uchar> _out_buffer(out_buffer);
150 
151 			DBGMSG(("move\n"));
152 
153 			move(x, y);
154 			startRasterGraphics(x, y, width, height);
155 
156 			compression_method = 0; // uncompressed
157 			buffer = out_buffer;
158 			compressed_size = out_size;
159 
160 			// dither entire band into out_buffer
161 			for (int i = rc.top; i <= rc.bottom; i++) {
162 				uchar* out = out_ptr;
163 				if (color) {
164 					uchar* in = ptr;
165 					for (int w = width; w > 0; w --) {
166 						*out++ = in[2];
167 						*out++ = in[1];
168 						*out++ = in[0];
169 						in += 4;
170 					}
171 				} else {
172 					fHalftone->dither(out_ptr, ptr, x, y, width);
173 					// invert pixels
174 					for (int w = widthByte; w > 0; w --, out ++) {
175 						*out = ~*out;
176 					}
177 				}
178 				// pad with 0s
179 				for (int w = padBytes; w > 0; w --, out ++) {
180 					*out = 0;
181 				}
182 
183 				ptr  += delta;
184 				out_ptr += out_row_length;
185 				y++;
186 			}
187 
188 			rasterGraphics(
189 				compression_method,
190 				buffer,
191 				compressed_size);
192 
193 			endRasterGraphics();
194 
195 		} else {
196 			DBGMSG(("band bitmap is clean.\n"));
197 		}
198 
199 		if (y >= page_height) {
200 			offset->x = -1.0;
201 			offset->y = -1.0;
202 		} else {
203 			offset->y += height;
204 		}
205 
206 		DBGMSG(("< nextBand\n"));
207 		return true;
208 	}
209 	catch (TransportException &err) {
210 		BAlert *alert = new BAlert("", err.what(), "OK");
211 		alert->Go();
212 		return false;
213 	}
214 }
215 
216 void PCL6Driver::jobStart()
217 {
218 	// PJL header
219 	writeSpoolString("\033%%-12345X@PJL JOB\n"
220 					 "@PJL SET RESOLUTION=%d\n"
221 	                 "@PJL ENTER LANGUAGE=PCLXL\n"
222 	                 ") HP-PCL XL;1;1;"
223 	                 "Comment Copyright (c) 2003 OBOS\n",
224 	                 getJobData()->getXres());
225 	// PCL6 begin
226 	fStream = HP_NewStream(16 * 1024, this);
227 	HP_BeginSession_2(fStream, getJobData()->getXres(), getJobData()->getYres(), HP_eInch, HP_eBackChAndErrPage);
228 	HP_OpenDataSource_1(fStream, HP_eDefaultDataSource, HP_eBinaryLowByteFirst);
229 }
230 
231 bool PCL6Driver::startPage(int)
232 {
233 	// XXX orientation
234 	HP_BeginPage_3(fStream, HP_ePortraitOrientation, mediaSize(getJobData()->getPaper()), HP_eAutoSelect);
235 	// PageOrigin from Windows NT printer driver
236 	int x = 142 * getJobData()->getXres() / 600;
237 	int y = 100 * getJobData()->getYres() / 600;
238 	bool color = getJobData()->getColor() == JobData::kColor;
239 	HP_SetPageOrigin_1(fStream, x, y);
240 	HP_SetColorSpace_1(fStream, color ? HP_eRGB : HP_eGray);
241 	HP_SetPaintTxMode_1(fStream, HP_eOpaque);
242 	HP_SetSourceTxMode_1(fStream, HP_eOpaque);
243 	HP_SetROP_1(fStream, 204);
244 	return true;
245 }
246 
247 void PCL6Driver::startRasterGraphics(int x, int y, int width, int height)
248 {
249 	bool color = getJobData()->getColor() == JobData::kColor;
250 	fCompressionMethod = -1;
251 	HP_BeginImage_1(fStream, HP_eDirectPixel, color ? HP_e8Bit : HP_e1Bit, width, height, width, height);
252 	HP_ReadImage_1(fStream, 0, height, HP_eNoCompression);
253 }
254 
255 void PCL6Driver::endRasterGraphics()
256 {
257 	HP_EndImage_1(fStream);
258 }
259 
260 void PCL6Driver::rasterGraphics(
261 	int compression_method,
262 	const uchar *buffer,
263 	int size)
264 {
265 	if (fCompressionMethod != compression_method) {
266 		fCompressionMethod = compression_method;
267 	}
268 	HP_EmbeddedDataPrefix32(fStream, size);
269 	HP_RawUByteArray(fStream, (uchar*)buffer, size);
270 }
271 
272 bool PCL6Driver::endPage(int)
273 {
274 	try {
275 		HP_EndPage_2(fStream, getJobData()->getCopies());
276 		return true;
277 	}
278 	catch (TransportException &err) {
279 		return false;
280 	}
281 }
282 
283 void PCL6Driver::jobEnd()
284 {
285 	HP_CloseDataSource_1(fStream);
286 	HP_EndSession_1(fStream);
287 	HP_FinishStream(fStream);
288 	// PJL footer
289 	writeSpoolString("\033%%-12345X@PJL EOJ\n"
290 	                 "\033%%-12345X");
291 }
292 
293 void PCL6Driver::move(int x, int y)
294 {
295 	HP_SetCursor_1(fStream, x, y);
296 }
297 
298 HP_UByte PCL6Driver::mediaSize(JobData::Paper paper)
299 {
300 	switch (paper) {
301 		case JobData::kLetter: return HP_eLetterPaper;
302 		case JobData::kLegal: return HP_eLegalPaper;
303 		case JobData::kA4: return HP_eA4Paper;
304 		case JobData::kExecutive: return HP_eExecPaper;
305 		case JobData::kLedger: return HP_eLedgerPaper;
306 		case JobData::kA3: return HP_eA3Paper;
307 /*
308 		case : return HP_eCOM10Envelope;
309 		case : return HP_eMonarchEnvelope;
310 		case : return HP_eC5Envelope;
311 		case : return HP_eDLEnvelope;
312 		case : return HP_eJB4Paper;
313 		case : return HP_eJB5Paper;
314 		case : return HP_eB5Envelope;
315 		case : return HP_eB5Paper;
316 		case : return HP_eJPostcard;
317 		case : return HP_eJDoublePostcard;
318 		case : return HP_eA5Paper;
319 		case : return HP_eA6Paper;
320 		case : return HP_eJB6Paper;
321 		case : return HP_eJIS8KPaper;
322 		case : return HP_eJIS16KPaper;
323 		case : return HP_eJISExecPaper;
324 */
325 		default:
326 			return HP_eLegalPaper;
327 	}
328 }
329 
330