xref: /haiku/src/add-ons/print/drivers/pcl5/PCL5.cpp (revision aa94570a34695672df9b47adda2257f75d8da880)
1 /*
2  * PCL5.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 "PCL5.h"
12 #include "UIDriver.h"
13 #include "JobData.h"
14 #include "PrinterData.h"
15 #include "PCL5Cap.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 PCL5Driver::PCL5Driver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap)
28 	: GraphicsDriver(msg, printer_data, printer_cap)
29 {
30 	fHalftone = NULL;
31 }
32 
33 bool PCL5Driver::startDoc()
34 {
35 	try {
36 		jobStart();
37 		fHalftone = new Halftone(getJobData()->getSurfaceType(), getJobData()->getGamma(), getJobData()->getInkDensity(), getJobData()->getDitherType());
38 		return true;
39 	}
40 	catch (TransportException &err) {
41 		return false;
42 	}
43 }
44 
45 bool PCL5Driver::startPage(int)
46 {
47 	return true;
48 }
49 
50 bool PCL5Driver::endPage(int)
51 {
52 	try {
53 		writeSpoolChar('\014');
54 		return true;
55 	}
56 	catch (TransportException &err) {
57 		return false;
58 	}
59 }
60 
61 bool PCL5Driver::endDoc(bool)
62 {
63 	try {
64 		if (fHalftone) {
65 			delete fHalftone;
66 		}
67 		jobEnd();
68 		return true;
69 	}
70 	catch (TransportException &err) {
71 		return false;
72 	}
73 }
74 
75 bool PCL5Driver::nextBand(BBitmap *bitmap, BPoint *offset)
76 {
77 	DBGMSG(("> nextBand\n"));
78 
79 	try {
80 		BRect bounds = bitmap->Bounds();
81 
82 		RECT rc;
83 		rc.left   = (int)bounds.left;
84 		rc.top    = (int)bounds.top;
85 		rc.right  = (int)bounds.right;
86 		rc.bottom = (int)bounds.bottom;
87 
88 		int height = rc.bottom - rc.top + 1;
89 
90 		int x = (int)offset->x;
91 		int y = (int)offset->y;
92 
93 		int page_height = getPageHeight();
94 
95 		if (y + height > page_height) {
96 			height = page_height - y;
97 		}
98 
99 		rc.bottom = height - 1;
100 
101 		DBGMSG(("height = %d\n", height));
102 		DBGMSG(("x = %d\n", x));
103 		DBGMSG(("y = %d\n", y));
104 
105 		if (get_valid_rect(bitmap, &rc)) {
106 
107 			DBGMSG(("validate rect = %d, %d, %d, %d\n",
108 				rc.left, rc.top, rc.right, rc.bottom));
109 
110 			x = rc.left;
111 			y += rc.top;
112 
113 			int width = rc.right - rc.left + 1;
114 			int widthByte = (width + 7) / 8;	/* byte boundary */
115 			int height    = rc.bottom - rc.top + 1;
116 			int in_size   = widthByte;
117 			int out_size  = (widthByte * 6 + 4) / 5;
118 			int delta     = bitmap->BytesPerRow();
119 
120 			DBGMSG(("width = %d\n", width));
121 			DBGMSG(("widthByte = %d\n", widthByte));
122 			DBGMSG(("height = %d\n", height));
123 			DBGMSG(("in_size = %d\n", in_size));
124 			DBGMSG(("out_size = %d\n", out_size));
125 			DBGMSG(("delta = %d\n", delta));
126 			DBGMSG(("renderobj->get_pixel_depth() = %d\n", fHalftone->getPixelDepth()));
127 
128 			uchar *ptr = (uchar *)bitmap->Bits()
129 						+ rc.top * delta
130 						+ (rc.left * fHalftone->getPixelDepth()) / 8;
131 
132 			int compression_method;
133 			int compressed_size;
134 			const uchar *buffer;
135 
136 			uchar *in_buffer  = new uchar[in_size];
137 			uchar *out_buffer = new uchar[out_size];
138 
139 			auto_ptr<uchar> _in_buffer (in_buffer);
140 			auto_ptr<uchar> _out_buffer(out_buffer);
141 
142 			DBGMSG(("move\n"));
143 
144 			move(x, y);
145 			startRasterGraphics(width, height);
146 
147 			const bool color = getJobData()->getColor() == JobData::kColor;
148 			const int num_planes = color ? 3 : 1;
149 
150 			if (color) {
151 				fHalftone->setPlanes(Halftone::kPlaneRGB1);
152 				fHalftone->setBlackValue(Halftone::kLowValueMeansBlack);
153 			}
154 
155 			for (int i = rc.top; i <= rc.bottom; i++) {
156 
157 				for (int plane = 0; plane < num_planes; plane ++) {
158 
159 					fHalftone->dither(in_buffer, ptr, x, y, width);
160 
161 					compressed_size = pack_bits(out_buffer, in_buffer, in_size);
162 
163 					if (compressed_size + bytesToEnterCompressionMethod(2) < in_size + bytesToEnterCompressionMethod(0)) {
164 						compression_method = 2; // back bits
165 						buffer = out_buffer;
166 					} else {
167 						compression_method = 0; // uncompressed
168 						buffer = in_buffer;
169 						compressed_size = in_size;
170 					}
171 
172 					rasterGraphics(
173 						compression_method,
174 						buffer,
175 						compressed_size,
176 						plane == num_planes - 1);
177 
178 				}
179 
180 				ptr  += delta;
181 				y++;
182 			}
183 
184 			endRasterGraphics();
185 
186 		} else {
187 			DBGMSG(("band bitmap is clean.\n"));
188 		}
189 
190 		if (y >= page_height) {
191 			offset->x = -1.0;
192 			offset->y = -1.0;
193 		} else {
194 			offset->y += height;
195 		}
196 
197 		DBGMSG(("< nextBand\n"));
198 		return true;
199 	}
200 	catch (TransportException &err) {
201 		BAlert *alert = new BAlert("", err.what(), "OK");
202 		alert->Go();
203 		return false;
204 	}
205 }
206 
207 void PCL5Driver::jobStart()
208 {
209 	const bool color = getJobData()->getColor() == JobData::kColor;
210 	// enter PCL5
211 	writeSpoolString("\033%%-12345X@PJL ENTER LANGUAGE=PCL\n");
212 	// reset
213 	writeSpoolString("\033E");
214 	// dpi
215 	writeSpoolString("\033*t%dR", getJobData()->getXres());
216 	// unit of measure
217 	writeSpoolString("\033&u%dD", getJobData()->getXres());
218 	// page size
219 	writeSpoolString("\033&l0A");
220 	// page orientation
221 	writeSpoolString("\033&l0O");
222 	if (color) {
223 		// 3 color planes (red, green, blue)
224 		writeSpoolString("\033*r3U");
225 	}
226 	// raster presentation
227 	writeSpoolString("\033*r0F");
228 	// top maring and perforation skip
229 	writeSpoolString("\033&l0e0L");
230 	// clear horizontal margins
231 	writeSpoolString("\0339");
232 	// number of copies
233 	// writeSpoolString("\033&l%ldL", getJobData()->getCopies());
234 }
235 
236 void PCL5Driver::startRasterGraphics(int width, int height)
237 {
238 	// width
239 	writeSpoolString("\033*r%dS", width);
240 	// height
241 	writeSpoolString("\033*r%dT", height);
242 	// start raster graphics
243 	writeSpoolString("\033*r1A");
244 	fCompressionMethod = -1;
245 }
246 
247 void PCL5Driver::endRasterGraphics()
248 {
249 	writeSpoolString("\033*rB");
250 }
251 
252 void PCL5Driver::rasterGraphics(
253 	int compression_method,
254 	const uchar *buffer,
255 	int size,
256 	bool lastPlane)
257 {
258 	if (fCompressionMethod != compression_method) {
259 		writeSpoolString("\033*b%dM", compression_method);
260 		fCompressionMethod = compression_method;
261 	}
262 	writeSpoolString("\033*b%d", size);
263 	if (lastPlane) {
264 		writeSpoolString("W");
265 	} else {
266 		writeSpoolString("V");
267 	}
268 	writeSpoolData(buffer, size);
269 }
270 
271 void PCL5Driver::jobEnd()
272 {
273 	writeSpoolString("\033&l1T");
274 	writeSpoolString("\033E");
275 }
276 
277 void PCL5Driver::move(int x, int y)
278 {
279 	writeSpoolString("\033*p%dx%dY", x, y+75);
280 }
281 
282 int PCL5Driver::bytesToEnterCompressionMethod(int compression_method)
283 {
284 	if (fCompressionMethod == compression_method) {
285 		return 0;
286 	} else {
287 		return 5;
288 	}
289 }
290 
291