xref: /haiku/src/add-ons/print/drivers/pcl5/PCL5.cpp (revision 1c09002cbee8e797a0f8bbfc5678dfadd39ee1a7)
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 <memory>
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 			uchar* in_buffer  = new uchar[in_size];
152 			uchar* out_buffer = new uchar[out_size];
153 
154 			auto_ptr<uchar> _in_buffer (in_buffer);
155 			auto_ptr<uchar> _out_buffer(out_buffer);
156 
157 			DBGMSG(("move\n"));
158 
159 			_Move(x, y);
160 			_StartRasterGraphics(width, height);
161 
162 			const bool color = GetJobData()->GetColor() == JobData::kColor;
163 			const int num_planes = color ? 3 : 1;
164 
165 			if (color) {
166 				fHalftone->SetPlanes(Halftone::kPlaneRGB1);
167 				fHalftone->SetBlackValue(Halftone::kLowValueMeansBlack);
168 			}
169 
170 			for (int i = rc.top; i <= rc.bottom; i++) {
171 
172 				for (int plane = 0; plane < num_planes; plane ++) {
173 
174 					fHalftone->Dither(in_buffer, ptr, x, y, width);
175 
176 					compressedSize = pack_bits(out_buffer, in_buffer, in_size);
177 
178 					if (compressedSize + _BytesToEnterCompressionMethod(2)
179 						< in_size + _BytesToEnterCompressionMethod(0)) {
180 						compressionMethod = 2; // back bits
181 						buffer = out_buffer;
182 					} else {
183 						compressionMethod = 0; // uncompressed
184 						buffer = in_buffer;
185 						compressedSize = in_size;
186 					}
187 
188 					_RasterGraphics(
189 						compressionMethod,
190 						buffer,
191 						compressedSize,
192 						plane == num_planes - 1);
193 
194 				}
195 
196 				ptr  += delta;
197 				y++;
198 			}
199 
200 			_EndRasterGraphics();
201 
202 		} else
203 			DBGMSG(("band bitmap is clean.\n"));
204 
205 		if (y >= pageHeight) {
206 			offset->x = -1.0;
207 			offset->y = -1.0;
208 		} else
209 			offset->y += height;
210 
211 		DBGMSG(("< nextBand\n"));
212 		return true;
213 	}
214 	catch (TransportException& err) {
215 		BAlert* alert = new BAlert("", err.What(), "OK");
216 		alert->Go();
217 		return false;
218 	}
219 }
220 
221 
222 void
223 PCL5Driver::_JobStart()
224 {
225 	const bool color = GetJobData()->GetColor() == JobData::kColor;
226 	// enter PCL5
227 	WriteSpoolString("\033%%-12345X@PJL ENTER LANGUAGE=PCL\n");
228 	// reset
229 	WriteSpoolString("\033E");
230 	// dpi
231 	WriteSpoolString("\033*t%dR", GetJobData()->GetXres());
232 	// unit of measure
233 	WriteSpoolString("\033&u%dD", GetJobData()->GetXres());
234 	// page size
235 	WriteSpoolString("\033&l0A");
236 	// page orientation
237 	WriteSpoolString("\033&l0O");
238 	if (color) {
239 		// 3 color planes (red, green, blue)
240 		WriteSpoolString("\033*r3U");
241 	}
242 	// raster presentation
243 	WriteSpoolString("\033*r0F");
244 	// top maring and perforation skip
245 	WriteSpoolString("\033&l0e0L");
246 	// clear horizontal margins
247 	WriteSpoolString("\0339");
248 	// number of copies
249 	// WriteSpoolString("\033&l%ldL", GetJobData()->GetCopies());
250 }
251 
252 
253 void
254 PCL5Driver::_StartRasterGraphics(int width, int height)
255 {
256 	// width
257 	WriteSpoolString("\033*r%dS", width);
258 	// height
259 	WriteSpoolString("\033*r%dT", height);
260 	// start raster graphics
261 	WriteSpoolString("\033*r1A");
262 	fCompressionMethod = -1;
263 }
264 
265 
266 void
267 PCL5Driver::_EndRasterGraphics()
268 {
269 	WriteSpoolString("\033*rB");
270 }
271 
272 
273 void
274 PCL5Driver::_RasterGraphics(int compressionMethod, const uchar* buffer,
275 	int size, bool lastPlane)
276 {
277 	if (fCompressionMethod != compressionMethod) {
278 		WriteSpoolString("\033*b%dM", compressionMethod);
279 		fCompressionMethod = compressionMethod;
280 	}
281 	WriteSpoolString("\033*b%d", size);
282 	if (lastPlane)
283 		WriteSpoolString("W");
284 	else
285 		WriteSpoolString("V");
286 
287 	WriteSpoolData(buffer, size);
288 }
289 
290 
291 void
292 PCL5Driver::_JobEnd()
293 {
294 	WriteSpoolString("\033&l1T");
295 	WriteSpoolString("\033E");
296 }
297 
298 
299 void
300 PCL5Driver::_Move(int x, int y)
301 {
302 	WriteSpoolString("\033*p%dx%dY", x, y + 75);
303 }
304 
305 
306 int
307 PCL5Driver::_BytesToEnterCompressionMethod(int compressionMethod)
308 {
309 	if (fCompressionMethod == compressionMethod)
310 		return 0;
311 	else
312 		return 5;
313 }
314