xref: /haiku/src/add-ons/print/drivers/pcl6/PCL6.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
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 
12 
13 #include "DbgMsg.h"
14 #include "DeltaRowCompression.h"
15 #include "Halftone.h"
16 #include "JobData.h"
17 #include "PackBits.h"
18 #include "PCL6.h"
19 #include "PCL6Cap.h"
20 #include "PCL6Config.h"
21 #include "PrinterData.h"
22 #include "PCL6Rasterizer.h"
23 #include "UIDriver.h"
24 #include "ValidRect.h"
25 
26 #if (!__MWERKS__ || defined(MSIPL_USING_NAMESPACE))
27 using namespace std;
28 #else
29 #define std
30 #endif
31 
32 // DeltaRowStreamCompressor writes the delta row directly to the
33 // in the contructor specified stream.
34 class DeltaRowStreamCompressor : public AbstractDeltaRowCompressor
35 {
36 public:
37 	DeltaRowStreamCompressor(int rowSize, uchar initialSeed, PCL6Writer *writer)
38 		: AbstractDeltaRowCompressor(rowSize, initialSeed)
39 		, fWriter(writer)
40 	{
41 		// nothing to do
42 	}
43 
44 protected:
45 	void AppendByteToDeltaRow(uchar byte) {
46 		fWriter->Append(byte);
47 	}
48 
49 private:
50 	PCL6Writer *fWriter;
51 };
52 
53 
54 PCL6Driver::PCL6Driver(BMessage *msg, PrinterData *printer_data, const PrinterCap *printer_cap)
55 	: GraphicsDriver(msg, printer_data, printer_cap)
56 {
57 	fHalftone = NULL;
58 	fWriter = NULL;
59 }
60 
61 void PCL6Driver::write(const uint8 *data, uint32 size)
62 {
63 	writeSpoolData(data, size);
64 }
65 
66 bool PCL6Driver::startDoc()
67 {
68 	try {
69 		jobStart();
70 		fHalftone = new Halftone(getJobData()->getSurfaceType(), getJobData()->getGamma(), getJobData()->getInkDensity(), getJobData()->getDitherType());
71 		return true;
72 	}
73 	catch (TransportException &err) {
74 		return false;
75 	}
76 }
77 
78 bool PCL6Driver::endDoc(bool)
79 {
80 	try {
81 		if (fHalftone) {
82 			delete fHalftone;
83 		}
84 		jobEnd();
85 		return true;
86 	}
87 	catch (TransportException &err) {
88 		return false;
89 	}
90 }
91 
92 bool PCL6Driver::nextBand(BBitmap *bitmap, BPoint *offset)
93 {
94 	DBGMSG(("> nextBand\n"));
95 
96 	try {
97 		int y = (int)offset->y;
98 
99 		PCL6Rasterizer *rasterizer;
100 		if (useColorMode()) {
101 			#if COLOR_DEPTH == 8
102 				rasterizer = new ColorRGBRasterizer(fHalftone);
103 			#elif COLOR_DEPTH == 1
104 				rasterizer = new ColorRasterizer(fHalftone);
105 			#else
106 				#error COLOR_DEPTH must be either 1 or 8!
107 			#endif
108 		} else {
109 			rasterizer = new MonochromeRasterizer(fHalftone);
110 		}
111 		auto_ptr<Rasterizer> _rasterizer(rasterizer);
112 		bool valid = rasterizer->SetBitmap((int)offset->x, (int)offset->y, bitmap, getPageHeight());
113 
114 		if (valid) {
115 			rasterizer->InitializeBuffer();
116 
117 			// Use compressor to calculate delta row size
118 			DeltaRowCompressor *deltaRowCompressor = NULL;
119 			if (supportsDeltaRowCompression()) {
120 				deltaRowCompressor = new DeltaRowCompressor(rasterizer->GetOutRowSize(), 0);
121 				if (deltaRowCompressor->InitCheck() != B_OK) {
122 					delete deltaRowCompressor;
123 					return false;
124 				}
125 			}
126 			auto_ptr<DeltaRowCompressor> _deltaRowCompressor(deltaRowCompressor);
127 			int deltaRowSize = 0;
128 
129 			// remember position
130 			int xPage = rasterizer->GetX();
131 			int yPage = rasterizer->GetY();
132 
133 			while (rasterizer->HasNextLine()) {
134 				const uchar *rowBuffer = (uchar*)rasterizer->RasterizeNextLine();
135 
136 				if (deltaRowCompressor != NULL) {
137 					int size = deltaRowCompressor->CalculateSize(rowBuffer, true);
138 					deltaRowSize += size + 2; // two bytes for the row byte count
139 				}
140 			}
141 
142 			y = rasterizer->GetY();
143 
144 			uchar *outBuffer = rasterizer->GetOutBuffer();
145 			int outBufferSize = rasterizer->GetOutBufferSize();
146 			int outRowSize = rasterizer->GetOutRowSize();
147 			int width = rasterizer->GetWidth();
148 			int height = rasterizer->GetHeight();
149 			writeBitmap(outBuffer, outBufferSize, outRowSize, xPage, yPage, width, height, deltaRowSize);
150 		}
151 
152 		if (y >= getPageHeight()) {
153 			offset->x = -1.0;
154 			offset->y = -1.0;
155 		} else {
156 			offset->y += bitmap->Bounds().IntegerHeight()+1;
157 		}
158 
159 		return true;
160 	}
161 	catch (TransportException &err) {
162 		BAlert *alert = new BAlert("", err.what(), "OK");
163 		alert->Go();
164 		return false;
165 	}
166 }
167 
168 void PCL6Driver::writeBitmap(const uchar* buffer, int outSize, int rowSize, int x, int y, int width, int height, int deltaRowSize)
169 {
170 	// choose the best compression method
171 	PCL6Writer::Compression compressionMethod = PCL6Writer::kNoCompression;
172 	int dataSize = outSize;
173 
174 #if ENABLE_DELTA_ROW_COMPRESSION
175 	if (supportsDeltaRowCompression() && deltaRowSize < dataSize) {
176 		compressionMethod = PCL6Writer::kDeltaRowCompression;
177 		dataSize = deltaRowSize;
178 	}
179 #endif
180 
181 #if ENABLE_RLE_COMPRESSION
182 	if (supportsRLECompression()) {
183 		int rleSize = pack_bits_size(buffer, outSize);
184 		if (rleSize < dataSize) {
185 			compressionMethod = PCL6Writer::kRLECompression;
186 			dataSize = rleSize;
187 		}
188 	}
189 #endif
190 
191 	// write bitmap
192 	move(x, y);
193 
194 	startRasterGraphics(x, y, width, height, compressionMethod);
195 
196 	rasterGraphics(buffer, outSize, dataSize, rowSize, height, compressionMethod);
197 
198 	endRasterGraphics();
199 
200 #if DISPLAY_COMPRESSION_STATISTICS
201 	fprintf(stderr, "Out Size       %d %2.2f\n", (int)outSize, 100.0);
202 #if ENABLE_RLE_COMPRESSION
203 	fprintf(stderr, "RLE Size       %d %2.2f\n", (int)rleSize, 100.0 * rleSize / outSize);
204 #endif
205 #if ENABLE_DELTA_ROW_COMPRESSION
206 	fprintf(stderr, "Delta Row Size %d %2.2f\n", (int)deltaRowSize, 100.0 * deltaRowSize / outSize);
207 #endif
208 	fprintf(stderr, "Data Size      %d %2.2f\n", (int)dataSize, 100.0 * dataSize / outSize);
209 #endif
210 }
211 
212 
213 void PCL6Driver::jobStart()
214 {
215 	// PCL6 begin
216 	fWriter = new PCL6Writer(this);
217 	PCL6Writer::ProtocolClass pc = (PCL6Writer::ProtocolClass)getProtocolClass();
218 	fWriter->PJLHeader(pc, getJobData()->getXres(), "Copyright (c) 2003, 2004 Haiku");
219 	fWriter->BeginSession(getJobData()->getXres(), getJobData()->getYres(), PCL6Writer::kInch, PCL6Writer::kBackChAndErrPage);
220 	fWriter->OpenDataSource();
221 	fMediaSide = PCL6Writer::kFrontMediaSide;
222 }
223 
224 bool PCL6Driver::startPage(int)
225 {
226 	PCL6Writer::Orientation orientation = PCL6Writer::kPortrait;
227 	if (getJobData()->getOrientation() == JobData::kLandscape) {
228 		orientation = PCL6Writer::kLandscape;
229 	}
230 
231 	PCL6Writer::MediaSize mediaSize = PCL6Driver::mediaSize(getJobData()->getPaper());
232 	PCL6Writer::MediaSource mediaSource = PCL6Driver::mediaSource(getJobData()->getPaperSource());
233 	if (getJobData()->getPrintStyle() == JobData::kSimplex) {
234 		fWriter->BeginPage(orientation, mediaSize, mediaSource);
235 	} else if (getJobData()->getPrintStyle() == JobData::kDuplex) {
236 		fWriter->BeginPage(orientation, mediaSize, mediaSource,
237 			PCL6Writer::kDuplexHorizontalBinding, fMediaSide);
238 
239 		if (fMediaSide == PCL6Writer::kFrontMediaSide) {
240 			fMediaSide = PCL6Writer::kBackMediaSide;
241 		} else {
242 			fMediaSide = PCL6Writer::kFrontMediaSide;
243 		}
244 	} else {
245 		return false;
246 	}
247 
248 	// PageOrigin from Windows NT printer driver
249 	int x = 142 * getJobData()->getXres() / 600;
250 	int y = 100 * getJobData()->getYres() / 600;
251 	fWriter->SetPageOrigin(x, y);
252 	fWriter->SetColorSpace(useColorMode() ? PCL6Writer::kRGB : PCL6Writer::kGray);
253 	fWriter->SetPaintTxMode(PCL6Writer::kOpaque);
254 	fWriter->SetSourceTxMode(PCL6Writer::kOpaque);
255 	fWriter->SetROP(204);
256 	return true;
257 }
258 
259 void PCL6Driver::startRasterGraphics(int x, int y, int width, int height, PCL6Writer::Compression compressionMethod)
260 {
261 	PCL6Writer::ColorDepth colorDepth;
262 	if (useColorMode()) {
263 		#if COLOR_DEPTH == 8
264 			colorDepth = PCL6Writer::k8Bit;
265 		#elif COLOR_DEPTH == 1
266 			colorDepth = PCL6Writer::k1Bit;
267 		#else
268 			#error COLOR_DEPTH must be either 1 or 8!
269 		#endif
270 	} else {
271 		colorDepth = PCL6Writer::k1Bit;
272 	}
273 	fWriter->BeginImage(PCL6Writer::kDirectPixel, colorDepth, width, height, width, height);
274 	fWriter->ReadImage(compressionMethod, 0, height);
275 }
276 
277 void PCL6Driver::endRasterGraphics()
278 {
279 	fWriter->EndImage();
280 }
281 
282 void PCL6Driver::rasterGraphics(
283 	const uchar *buffer,
284 	int bufferSize,
285 	int dataSize,
286 	int rowSize,
287 	int height,
288 	int compressionMethod
289 )
290 {
291 	// write bitmap byte size
292 	fWriter->EmbeddedDataPrefix32(dataSize);
293 
294 	// write data
295 	if (compressionMethod == PCL6Writer::kRLECompression) {
296 		// use RLE compression
297 		uchar *outBuffer = new uchar[dataSize];
298 		pack_bits(outBuffer, buffer, bufferSize);
299 		fWriter->Append(outBuffer, dataSize);
300 		delete outBuffer;
301 		return;
302 	} else if (compressionMethod == PCL6Writer::kDeltaRowCompression) {
303 		// use delta row compression
304 		DeltaRowStreamCompressor compressor(rowSize, 0, fWriter);
305 		if (compressor.InitCheck() != B_OK) {
306 			return;
307 		}
308 
309 		const uint8* row = buffer;
310 		for (int i = 0; i < height; i ++) {
311 			// write row byte count
312 			int32 size = compressor.CalculateSize(row);
313 			fWriter->Append((uint16)size);
314 
315 			if (size > 0) {
316 				// write delta row
317 				compressor.Compress(row);
318 			}
319 
320 			row += rowSize;
321 		}
322 	} else {
323 		// write raw data
324 		fWriter->Append(buffer, bufferSize);
325 	}
326 }
327 
328 bool PCL6Driver::endPage(int)
329 {
330 	try {
331 		fWriter->EndPage(getJobData()->getCopies());
332 		return true;
333 	}
334 	catch (TransportException &err) {
335 		return false;
336 	}
337 }
338 
339 void PCL6Driver::jobEnd()
340 {
341 	fWriter->CloseDataSource();
342 	fWriter->EndSession();
343 	fWriter->PJLFooter();
344 	fWriter->Flush();
345 	delete fWriter;
346 	fWriter = NULL;
347 }
348 
349 void PCL6Driver::move(int x, int y)
350 {
351 	fWriter->SetCursor(x, y);
352 }
353 
354 bool
355 PCL6Driver::supportsRLECompression()
356 {
357 	return getJobData()->getColor() != JobData::kColorCompressionDisabled;
358 }
359 
360 bool
361 PCL6Driver::supportsDeltaRowCompression()
362 {
363 	return getProtocolClass() >= PCL6Writer::kProtocolClass2_1 &&
364 		getJobData()->getColor() != JobData::kColorCompressionDisabled;
365 }
366 
367 bool
368 PCL6Driver::useColorMode()
369 {
370 	return getJobData()->getColor() != JobData::kMonochrome;
371 }
372 
373 PCL6Writer::MediaSize PCL6Driver::mediaSize(JobData::Paper paper)
374 {
375 	switch (paper) {
376 		case JobData::kLetter:    return PCL6Writer::kLetterPaper;
377 		case JobData::kLegal:     return PCL6Writer::kLegalPaper;
378 		case JobData::kA4:        return PCL6Writer::kA4Paper;
379 		case JobData::kExecutive: return PCL6Writer::kExecPaper;
380 		case JobData::kLedger:    return PCL6Writer::kLedgerPaper;
381 		case JobData::kA3:        return PCL6Writer::kA3Paper;
382 		case JobData::kB5:        return PCL6Writer::kB5Paper;
383 		case JobData::kJapanesePostcard:
384                                   return PCL6Writer::kJPostcard;
385 		case JobData::kA5:        return PCL6Writer::kA5Paper;
386 		case JobData::kB4:        return PCL6Writer::kJB4Paper;
387 /*
388 		case : return PCL6Writer::kCOM10Envelope;
389 		case : return PCL6Writer::kMonarchEnvelope;
390 		case : return PCL6Writer::kC5Envelope;
391 		case : return PCL6Writer::kDLEnvelope;
392 		case : return PCL6Writer::kJB4Paper;
393 		case : return PCL6Writer::kJB5Paper;
394 		case : return PCL6Writer::kB5Envelope;
395 		case : return PCL6Writer::kJPostcard;
396 		case : return PCL6Writer::kJDoublePostcard;
397 		case : return PCL6Writer::kA5Paper;
398 		case : return PCL6Writer::kA6Paper;
399 		case : return PCL6Writer::kJB6Paper;
400 		case : return PCL6Writer::kJIS8KPaper;
401 		case : return PCL6Writer::kJIS16KPaper;
402 		case : return PCL6Writer::kJISExecPaper;
403 */
404 		default:
405 			return PCL6Writer::kLegalPaper;
406 	}
407 }
408 
409 PCL6Writer::MediaSource PCL6Driver::mediaSource(JobData::PaperSource source)
410 {
411 	switch (source) {
412 		case JobData::kAuto:       return PCL6Writer::kAutoSelect;
413 		case JobData::kCassette1:  return PCL6Writer::kDefaultSource;
414 		case JobData::kCassette2:  return PCL6Writer::kEnvelopeTray;
415 		case JobData::kLower:      return PCL6Writer::kLowerCassette;
416 		case JobData::kUpper:      return PCL6Writer::kUpperCassette;
417 		case JobData::kMiddle:     return PCL6Writer::kThirdCassette;
418 		case JobData::kManual:     return PCL6Writer::kManualFeed;
419 		case JobData::kCassette3:  return PCL6Writer::kMultiPurposeTray;
420 
421 		default:
422 			return PCL6Writer::kAutoSelect;
423 	}
424 }
425 
426