1/*
2 * Lips4.cpp
3 * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
4 */
5
6
7#include "Lips4Cap.h"
8
9#include <vector>
10
11#include <Alert.h>
12#include <Bitmap.h>
13#include <File.h>
14
15#include "DbgMsg.h"
16#include "Halftone.h"
17#include "JobData.h"
18#include "Lips4.h"
19#include "PackBits.h"
20#include "PrinterData.h"
21#include "ValidRect.h"
22
23
24LIPS4Driver::LIPS4Driver(BMessage* message, PrinterData* printerData,
25	const PrinterCap* printerCap)
26	:
27	GraphicsDriver(message, printerData, printerCap),
28	fHalftone(NULL)
29{
30}
31
32
33bool
34LIPS4Driver::StartDocument()
35{
36	try {
37		_BeginTextMode();
38		_JobStart();
39		_ColorModeDeclaration();
40		_SoftReset();
41		_SizeUnitMode();
42		_SelectSizeUnit();
43		_PaperFeedMode();
44		_SelectPageFormat();
45		_DisableAutoFF();
46		_SetNumberOfCopies();
47		_SidePrintingControl();
48		_SetBindingMargin();
49		fHalftone = new Halftone(GetJobData()->GetSurfaceType(),
50			GetJobData()->GetGamma(), GetJobData()->GetInkDensity(),
51			GetJobData()->GetDitherType());
52		return true;
53	}
54	catch (TransportException& err) {
55		return false;
56	}
57}
58
59
60bool
61LIPS4Driver::StartPage(int)
62{
63	try {
64		fCurrentX = 0;
65		fCurrentY = 0;
66		_MemorizedPosition();
67		return true;
68	}
69	catch (TransportException& err) {
70		return false;
71	}
72}
73
74
75bool
76LIPS4Driver::EndPage(int)
77{
78	try {
79		_FormFeed();
80		return true;
81	}
82	catch (TransportException& err) {
83		return false;
84	}
85}
86
87
88bool
89LIPS4Driver::EndDocument(bool)
90{
91	try {
92		if (fHalftone)
93			delete fHalftone;
94
95		_JobEnd();
96		return true;
97	}
98	catch (TransportException& err) {
99		return false;
100	}
101}
102
103
104bool
105LIPS4Driver::NextBand(BBitmap* bitmap, BPoint* offset)
106{
107	DBGMSG(("> nextBand\n"));
108
109	try {
110
111		if (bitmap == NULL) {
112			uchar dummy[1];
113			dummy[0] =  '\0';
114			_RasterGraphics(1, 1, 1, 0, dummy);
115			DBGMSG(("< next_band\n"));
116			return true;
117		}
118
119		BRect bounds = bitmap->Bounds();
120
121		RECT rc;
122		rc.left = (int)bounds.left;
123		rc.top = (int)bounds.top;
124		rc.right = (int)bounds.right;
125		rc.bottom = (int)bounds.bottom;
126
127		int height = rc.bottom - rc.top + 1;
128
129		int x = (int)offset->x;
130		int y = (int)offset->y;
131
132		int page_height = GetPageHeight();
133
134		if (y + height > page_height)
135			height = page_height - y;
136
137		rc.bottom = height - 1;
138
139		DBGMSG(("height = %d\n", height));
140		DBGMSG(("x = %d\n", x));
141		DBGMSG(("y = %d\n", y));
142
143		if (get_valid_rect(bitmap, &rc)) {
144
145			DBGMSG(("validate rect = %d, %d, %d, %d\n",
146				rc.left, rc.top, rc.right, rc.bottom));
147
148			x = rc.left;
149			y += rc.top;
150
151			int width = rc.right - rc.left + 1;
152			int widthByte = (width + 7) / 8;
153			int height = rc.bottom - rc.top + 1;
154			int in_size = widthByte * height;
155			int out_size = (in_size * 6 + 4) / 5;
156			int delta = bitmap->BytesPerRow();
157
158			DBGMSG(("width = %d\n", width));
159			DBGMSG(("widthByte = %d\n", widthByte));
160			DBGMSG(("height = %d\n", height));
161			DBGMSG(("in_size = %d\n", in_size));
162			DBGMSG(("out_size = %d\n", out_size));
163			DBGMSG(("delta = %d\n", delta));
164			DBGMSG(("fHalftone_engine->Get_pixel_depth() = %d\n",
165				fHalftone->GetPixelDepth()));
166
167			uchar* ptr = static_cast<uchar*>(bitmap->Bits())
168						+ rc.top * delta
169						+ (rc.left * fHalftone->GetPixelDepth()) / 8;
170
171			int compression_method;
172			int compressed_size;
173			const uchar* buffer;
174
175			std::vector<uchar> in_buffer(in_size);
176			std::vector<uchar> out_buffer(out_size);
177
178			uchar* ptr2 = &in_buffer[0];
179
180			DBGMSG(("move\n"));
181
182			_Move(x, y);
183
184			for (int i = rc.top; i <= rc.bottom; i++) {
185				fHalftone->Dither(ptr2, ptr, x, y, width);
186				ptr  += delta;
187				ptr2 += widthByte;
188				y++;
189			}
190
191			DBGMSG(("PackBits\n"));
192
193			compressed_size = pack_bits(&out_buffer[0], &in_buffer[0], in_size);
194
195			if (compressed_size < in_size) {
196				compression_method = 11;
197				buffer = &out_buffer[0];
198			} else if (compressed_size > out_size) {
199				BAlert* alert = new BAlert("memory overrun!!!", "warning", "OK");
200				alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
201				alert->Go();
202				return false;
203			} else {
204				compression_method = 0;
205				buffer = &in_buffer[0];
206				compressed_size = in_size;
207			}
208
209			DBGMSG(("compressed_size = %d\n", compressed_size));
210			DBGMSG(("widthByte = %d\n", widthByte));
211			DBGMSG(("height = %d\n", height));
212			DBGMSG(("compression_method = %d\n", compression_method));
213
214			_RasterGraphics(
215				compressed_size,	// size,
216				widthByte,			// widthByte
217				height,				// height,
218				compression_method,
219				buffer);
220
221		} else
222			DBGMSG(("band bitmap is clean.\n"));
223
224		if (y >= page_height) {
225			offset->x = -1.0;
226			offset->y = -1.0;
227		} else
228			offset->y += height;
229
230		DBGMSG(("< nextBand\n"));
231		return true;
232	}
233	catch (TransportException& err) {
234		BAlert* alert = new BAlert("", err.What(), "OK");
235		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
236		alert->Go();
237		return false;
238	}
239}
240
241
242void
243LIPS4Driver::_BeginTextMode()
244{
245	WriteSpoolString("\033%%@");
246}
247
248
249void
250LIPS4Driver::_JobStart()
251{
252	WriteSpoolString("\033P41;%d;1J\033\\", GetJobData()->GetXres());
253}
254
255
256void
257LIPS4Driver::_ColorModeDeclaration()
258{
259//	if (color)
260//		WriteSpoolString("\033[1\"p");
261//	else
262		WriteSpoolString("\033[0\"p");
263}
264
265
266void
267LIPS4Driver::_SoftReset()
268{
269	WriteSpoolString("\033<");
270}
271
272
273void
274LIPS4Driver::_SizeUnitMode()
275{
276	WriteSpoolString("\033[11h");
277}
278
279
280void
281LIPS4Driver::_SelectSizeUnit()
282{
283	WriteSpoolString("\033[?7;%d I", GetJobData()->GetXres());
284}
285
286
287void
288LIPS4Driver::_PaperFeedMode()
289{
290	// 0 auto
291	// --------------
292	// 1 MP tray
293	// 2 lower
294	// 3 lupper
295	// --------------
296	// 10 MP tray
297	// 11 casette 1
298	// 12 casette 2
299	// 13 casette 3
300	// 14 casette 4
301	// 15 casette 5
302	// 16 casette 6
303	// 17 casette 7
304
305	int i;
306
307	switch (GetJobData()->GetPaperSource()) {
308		case JobData::kManual:
309			i = 10;
310			break;
311		case JobData::kUpper:
312			i = 11;
313			break;
314		case JobData::kMiddle:
315			i = 12;
316			break;
317		case JobData::kLower:
318			i = 13;
319			break;
320		case JobData::kAuto:
321		default:
322			i = 0;
323			break;
324	}
325
326	WriteSpoolString("\033[%dq", i);
327}
328
329
330void
331LIPS4Driver::_SelectPageFormat()
332{
333	int i;
334
335	switch (GetJobData()->GetPaper()) {
336		case JobData::kA3:
337			i = 12;
338			break;
339
340		case JobData::kA4:
341			i = 14;
342			break;
343
344		case JobData::kA5:
345			i = 16;
346			break;
347
348		case JobData::kJapanesePostcard:
349			i = 18;
350			break;
351
352		case JobData::kB4:
353			i = 24;
354			break;
355
356		case JobData::kB5:
357			i = 26;
358			break;
359
360		case JobData::kLetter:
361			i = 30;
362			break;
363
364		case JobData::kLegal:
365			i = 32;
366			break;
367
368		case JobData::kExecutive:
369			i = 40;
370			break;
371
372		case JobData::kJEnvYou4:
373			i = 50;
374			break;
375
376		case JobData::kUser:
377			i = 90;
378			break;
379
380		default:
381			i = 0;
382			break;
383	}
384
385	if (JobData::kLandscape == GetJobData()->GetOrientation())
386		i++;
387
388	WriteSpoolString("\033[%d;;p", i);
389}
390
391
392void
393LIPS4Driver::_DisableAutoFF()
394{
395	WriteSpoolString("\033[?2h");
396}
397
398
399void
400LIPS4Driver::_SetNumberOfCopies()
401{
402	WriteSpoolString("\033[%ldv", GetJobData()->GetCopies());
403}
404
405
406void
407LIPS4Driver::_SidePrintingControl()
408{
409	if (GetJobData()->GetPrintStyle() == JobData::kSimplex)
410		WriteSpoolString("\033[0#x");
411	else
412		WriteSpoolString("\033[2;0#x");
413}
414
415
416void
417LIPS4Driver::_SetBindingMargin()
418{
419	if (GetJobData()->GetPrintStyle() == JobData::kDuplex) {
420		int i;
421//		switch (job_data()->binding_location()) {
422//		case kLongEdgeLeft:
423			i = 0;
424//			break;
425//		case kLongEdgeRight:
426//			i = 1;
427//			break;
428//		case kShortEdgeTop:
429//			i = 2;
430//			break;
431//		case kShortEdgeBottom:
432//			i = 3;
433//			break;
434//		}
435		WriteSpoolString("\033[%d;0#w", i);
436	}
437}
438
439
440void
441LIPS4Driver::_MemorizedPosition()
442{
443	WriteSpoolString("\033[0;1;0x");
444}
445
446
447void
448LIPS4Driver::_MoveAbsoluteHorizontal(int x)
449{
450	WriteSpoolString("\033[%ld`", x);
451}
452
453
454void
455LIPS4Driver::_CarriageReturn()
456{
457	WriteSpoolChar('\x0d');
458}
459
460
461void
462LIPS4Driver::_MoveDown(int dy)
463{
464	WriteSpoolString("\033[%lde", dy);
465}
466
467
468void
469LIPS4Driver::_RasterGraphics(int compression_size, int widthbyte, int height,
470	int compression_method, const uchar* buffer)
471{
472// 0  RAW
473// 10 RLE
474// 11 packbits
475
476	WriteSpoolString(
477		"\033[%ld;%ld;%d;%ld;%ld.r",
478		compression_size,
479		widthbyte,
480		GetJobData()->GetXres(),
481		compression_method,
482		height);
483
484	WriteSpoolData(buffer, compression_size);
485}
486
487
488void
489LIPS4Driver::_FormFeed()
490{
491	WriteSpoolChar('\014');
492}
493
494
495void
496LIPS4Driver::_JobEnd()
497{
498	WriteSpoolString("\033P0J\033\\");
499}
500
501
502void
503LIPS4Driver::_Move(int x, int y)
504{
505	if (fCurrentX != x) {
506		if (x) {
507			_MoveAbsoluteHorizontal(x);
508		} else {
509			_CarriageReturn();
510		}
511		fCurrentX = x;
512	}
513	if (fCurrentY != y) {
514		int dy = y - fCurrentY;
515		_MoveDown(dy);
516		fCurrentY = y;
517	}
518}
519