xref: /haiku/src/add-ons/print/drivers/pcl5/PCL5.cpp (revision 26d22ee8dc5db3cea88354d0536f5dd9950b6bcf)
1 /*
2  * PCL5.cpp
3  * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
4  * Copyright 2003 Michael Pfeiffer.
5  */
6 
7 
8 #include "PCL5.h"
9 
10 #include <vector>
11 
12 #include <Alert.h>
13 #include <Bitmap.h>
14 #include <File.h>
15 
16 #include "DbgMsg.h"
17 #include "Halftone.h"
18 #include "JobData.h"
19 #include "PackBits.h"
20 #include "PCL5Cap.h"
21 #include "PrinterData.h"
22 #include "UIDriver.h"
23 #include "ValidRect.h"
24 
25 
26 PCL5Driver::PCL5Driver(BMessage* message, PrinterData* printerData,
27 	const PrinterCap* printerCap)
28 	:
29 	GraphicsDriver(message, printerData, printerCap),
30 	fCompressionMethod(0),
31 	fHalftone(NULL)
32 {
33 }
34 
35 
36 bool
37 PCL5Driver::StartDocument()
38 {
39 	try {
40 		_JobStart();
41 		fHalftone = new Halftone(GetJobData()->GetSurfaceType(),
42 			GetJobData()->GetGamma(), GetJobData()->GetInkDensity(),
43 			GetJobData()->GetDitherType());
44 		return true;
45 	}
46 	catch (TransportException& err) {
47 		return false;
48 	}
49 }
50 
51 
52 bool
53 PCL5Driver::StartPage(int)
54 {
55 	return true;
56 }
57 
58 
59 bool
60 PCL5Driver::EndPage(int)
61 {
62 	try {
63 		WriteSpoolChar('\014');
64 		return true;
65 	}
66 	catch (TransportException& err) {
67 		return false;
68 	}
69 }
70 
71 
72 bool
73 PCL5Driver::EndDocument(bool)
74 {
75 	try {
76 		if (fHalftone != NULL) {
77 			delete fHalftone;
78 			fHalftone = NULL;
79 		}
80 		_JobEnd();
81 		return true;
82 	}
83 	catch (TransportException& err) {
84 		return false;
85 	}
86 }
87 
88 
89 bool
90 PCL5Driver::NextBand(BBitmap* bitmap, BPoint* offset)
91 {
92 	DBGMSG(("> nextBand\n"));
93 
94 	try {
95 		BRect bounds = bitmap->Bounds();
96 
97 		RECT rc;
98 		rc.left = (int)bounds.left;
99 		rc.top = (int)bounds.top;
100 		rc.right = (int)bounds.right;
101 		rc.bottom = (int)bounds.bottom;
102 
103 		int height = rc.bottom - rc.top + 1;
104 
105 		int x = (int)offset->x;
106 		int y = (int)offset->y;
107 
108 		int pageHeight = GetPageHeight();
109 
110 		if (y + height > pageHeight)
111 			height = pageHeight - y;
112 
113 		rc.bottom = height - 1;
114 
115 		DBGMSG(("height = %d\n", height));
116 		DBGMSG(("x = %d\n", x));
117 		DBGMSG(("y = %d\n", y));
118 
119 		if (get_valid_rect(bitmap, &rc)) {
120 
121 			DBGMSG(("validate rect = %d, %d, %d, %d\n",
122 				rc.left, rc.top, rc.right, rc.bottom));
123 
124 			x = rc.left;
125 			y += rc.top;
126 
127 			int width = rc.right - rc.left + 1;
128 			int widthByte = (width + 7) / 8;
129 				// byte boundary
130 			int height = rc.bottom - rc.top + 1;
131 			int in_size = widthByte;
132 			int out_size = (widthByte * 6 + 4) / 5;
133 			int delta = bitmap->BytesPerRow();
134 
135 			DBGMSG(("width = %d\n", width));
136 			DBGMSG(("widthByte = %d\n", widthByte));
137 			DBGMSG(("height = %d\n", height));
138 			DBGMSG(("in_size = %d\n", in_size));
139 			DBGMSG(("out_size = %d\n", out_size));
140 			DBGMSG(("delta = %d\n", delta));
141 			DBGMSG(("renderobj->Get_pixel_depth() = %d\n", fHalftone->GetPixelDepth()));
142 
143 			uchar* ptr = static_cast<uchar*>(bitmap->Bits())
144 						+ rc.top * delta
145 						+ (rc.left * fHalftone->GetPixelDepth()) / 8;
146 
147 			int compressionMethod;
148 			int compressedSize;
149 			const uchar* buffer;
150 
151 			std::vector<uchar> in_buffer(in_size);
152 			std::vector<uchar> out_buffer(out_size);
153 
154 			DBGMSG(("move\n"));
155 
156 			_Move(x, y);
157 			_StartRasterGraphics(width, height);
158 
159 			const bool color = GetJobData()->GetColor() == JobData::kColor;
160 			const int num_planes = color ? 3 : 1;
161 
162 			if (color) {
163 				fHalftone->SetPlanes(Halftone::kPlaneRGB1);
164 				fHalftone->SetBlackValue(Halftone::kLowValueMeansBlack);
165 			}
166 
167 			for (int i = rc.top; i <= rc.bottom; i++) {
168 
169 				for (int plane = 0; plane < num_planes; plane ++) {
170 
171 					fHalftone->Dither(&in_buffer[0], ptr, x, y, width);
172 
173 					compressedSize = pack_bits(&out_buffer[0], &in_buffer[0], in_size);
174 
175 					if (compressedSize + _BytesToEnterCompressionMethod(2)
176 						< in_size + _BytesToEnterCompressionMethod(0)) {
177 						compressionMethod = 2; // back bits
178 						buffer = &out_buffer[0];
179 					} else {
180 						compressionMethod = 0; // uncompressed
181 						buffer = &in_buffer[0];
182 						compressedSize = in_size;
183 					}
184 
185 					_RasterGraphics(
186 						compressionMethod,
187 						buffer,
188 						compressedSize,
189 						plane == num_planes - 1);
190 
191 				}
192 
193 				ptr  += delta;
194 				y++;
195 			}
196 
197 			_EndRasterGraphics();
198 
199 		} else
200 			DBGMSG(("band bitmap is clean.\n"));
201 
202 		if (y >= pageHeight) {
203 			offset->x = -1.0;
204 			offset->y = -1.0;
205 		} else
206 			offset->y += height;
207 
208 		DBGMSG(("< nextBand\n"));
209 		return true;
210 	}
211 	catch (TransportException& err) {
212 		BAlert* alert = new BAlert("", err.What(), "OK");
213 		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
214 		alert->Go();
215 		return false;
216 	}
217 }
218 
219 
220 void
221 PCL5Driver::_JobStart()
222 {
223 	const bool color = GetJobData()->GetColor() == JobData::kColor;
224 	// enter PCL5
225 	WriteSpoolString("\033%%-12345X@PJL ENTER LANGUAGE=PCL\n");
226 	// reset
227 	WriteSpoolString("\033E");
228 	// dpi
229 	WriteSpoolString("\033*t%dR", GetJobData()->GetXres());
230 	// unit of measure
231 	WriteSpoolString("\033&u%dD", GetJobData()->GetXres());
232 	// page size
233 	WriteSpoolString("\033&l0A");
234 	// page orientation
235 	WriteSpoolString("\033&l0O");
236 	if (color) {
237 		// 3 color planes (red, green, blue)
238 		WriteSpoolString("\033*r3U");
239 	}
240 	// raster presentation
241 	WriteSpoolString("\033*r0F");
242 	// top maring and perforation skip
243 	WriteSpoolString("\033&l0e0L");
244 	// clear horizontal margins
245 	WriteSpoolString("\0339");
246 	// number of copies
247 	// WriteSpoolString("\033&l%ldL", GetJobData()->GetCopies());
248 }
249 
250 
251 void
252 PCL5Driver::_StartRasterGraphics(int width, int height)
253 {
254 	// width
255 	WriteSpoolString("\033*r%dS", width);
256 	// height
257 	WriteSpoolString("\033*r%dT", height);
258 	// start raster graphics
259 	WriteSpoolString("\033*r1A");
260 	fCompressionMethod = -1;
261 }
262 
263 
264 void
265 PCL5Driver::_EndRasterGraphics()
266 {
267 	WriteSpoolString("\033*rB");
268 }
269 
270 
271 void
272 PCL5Driver::_RasterGraphics(int compressionMethod, const uchar* buffer,
273 	int size, bool lastPlane)
274 {
275 	if (fCompressionMethod != compressionMethod) {
276 		WriteSpoolString("\033*b%dM", compressionMethod);
277 		fCompressionMethod = compressionMethod;
278 	}
279 	WriteSpoolString("\033*b%d", size);
280 	if (lastPlane)
281 		WriteSpoolString("W");
282 	else
283 		WriteSpoolString("V");
284 
285 	WriteSpoolData(buffer, size);
286 }
287 
288 
289 void
290 PCL5Driver::_JobEnd()
291 {
292 	WriteSpoolString("\033&l1T");
293 	WriteSpoolString("\033E");
294 }
295 
296 
297 void
298 PCL5Driver::_Move(int x, int y)
299 {
300 	WriteSpoolString("\033*p%dx%dY", x, y + 75);
301 }
302 
303 
304 int
305 PCL5Driver::_BytesToEnterCompressionMethod(int compressionMethod)
306 {
307 	if (fCompressionMethod == compressionMethod)
308 		return 0;
309 	else
310 		return 5;
311 }
312