1
/* Copyright (C) 2001-2012 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied,
8
modified or distributed except as expressly authorized under the terms
9
of the license contained in the file LICENSE in this distribution.
11
Refer to licensing information at http://www.artifex.com or contact
12
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13
CA 94903, U.S.A., +1(415)492-9861, for further information.
16
/* Generic monochrome H-P DeskJet/LaserJet driver */
21
* Thanks for various improvements to:
22
* Jim Mayer (mayer@wrc.xerox.com)
23
* Jan-Mark Wams (jms@cs.vu.nl)
24
* Frans van Hoesel (hoesel@chem.rug.nl)
25
* George Cameron (g.cameron@biomed.abdn.ac.uk)
26
* Nick Duffek (nsd@bbc.com)
27
* Thanks for the FS-600 driver to:
28
* Peter Schildmann (peter.schildmann@etechnik.uni-rostock.de)
29
* Thanks for the LJIIID duplex capability to:
30
* PDP (Philip) Brown (phil@3soft-uk.com)
31
* Thanks for the OCE 9050 driver to:
32
* William Bader (wbader@EECS.Lehigh.Edu)
33
* Thanks for the LJ4D duplex capability to:
34
* Les Johnson <les@infolabs.com>
37
/* See gdevdljm.h for the definitions of the PCL_ features. */
39
/* The number of blank lines that make it worthwhile to reposition */
41
#define MIN_SKIP_LINES 7
43
/* We round up the LINE_SIZE to a multiple of a ulong for faster scanning. */
44
#define W sizeof(word)
46
/* Send a page to the printer. */
48
dljet_mono_print_page(gx_device_printer * pdev, FILE * prn_stream,
49
int dots_per_inch, int features, const char *page_init)
51
return dljet_mono_print_page_copies(pdev, prn_stream, 1, dots_per_inch,
52
features, page_init, page_init, false);
55
dljet_mono_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
56
int num_copies, int dots_per_inch, int features,
57
const char *odd_page_init, const char *even_page_init, bool tumble)
59
int line_size = gdev_mem_bytes_per_scan_line((gx_device *) pdev);
60
int line_size_words = (line_size + W - 1) / W;
61
uint storage_size_words = line_size_words * 8; /* data, out_row, out_row_alt, prev_row */
68
#define data ((byte *)data_words)
69
#define out_row ((byte *)out_row_words)
70
#define out_row_alt ((byte *)out_row_alt_words)
71
#define prev_row ((byte *)prev_row_words)
73
int x_dpi = (int)pdev->x_pixels_per_inch;
74
int y_dpi = (int)pdev->y_pixels_per_inch;
75
int y_dots_per_pixel = dots_per_inch / y_dpi;
76
int num_rows = dev_print_scan_lines(pdev);
80
static const char *const from2to3 = "\033*b3M";
81
static const char *const from3to2 = "\033*b2M";
82
int penalty_from2to3 = strlen(from2to3);
83
int penalty_from3to2 = strlen(from3to2);
84
int paper_size = gdev_pcl_paper_size((gx_device *) pdev);
86
bool dup = pdev->Duplex;
87
bool dupset = pdev->Duplex_set >= 0;
89
if (num_copies != 1 && !(features & PCL_CAN_PRINT_COPIES))
90
return gx_default_print_page_copies(pdev, prn_stream, num_copies);
92
(ulong *)gs_alloc_byte_array(pdev->memory, storage_size_words, W,
94
if (storage == 0) /* can't allocate working area */
95
return_error(gs_error_VMerror);
97
out_row_words = data_words + (line_size_words * 2);
98
out_row_alt_words = out_row_words + (line_size_words * 2);
99
prev_row_words = out_row_alt_words + (line_size_words * 2);
100
/* Clear temp storage */
101
memset(data, 0, storage_size_words * W);
103
/* Initialize printer. */
104
if (pdev->PageCount == 0) {
105
if (features & HACK__IS_A_LJET4PJL) {
106
fputs("\033%-12345X@PJL\r\n@PJL ENTER LANGUAGE = PCL\r\n",
109
fputs("\033E", prn_stream); /* reset printer */
110
/* If the printer supports it, set the paper size */
111
/* based on the actual requested size. */
112
if (features & PCL_CAN_SET_PAPER_SIZE) {
113
fprintf(prn_stream, "\033&l%dA", paper_size);
115
/* If printer can duplex, set duplex mode appropriately. */
116
if (features & PCL_HAS_DUPLEX) {
117
if (dupset && dup && !tumble)
118
fputs("\033&l1S", prn_stream);
119
else if (dupset && dup && tumble)
120
fputs("\033&l2S", prn_stream);
121
else if (dupset && !dup)
122
fputs("\033&l0S", prn_stream);
123
else /* default to duplex for this printer */
124
fputs("\033&l1S", prn_stream);
127
/* Put out per-page initialization. */
129
Modified by karsten@sengebusch.de
130
in duplex mode the sheet is alread in process, so there are some
131
commands which must not be sent to the printer for the 2nd page,
132
as this commands will cause the printer to eject the sheet with
133
only the 1st page printed. This commands are:
134
\033&l%dA (setting paper size)
135
\033&l%dH (setting paper tray)
136
in simplex mode we set this parameters for each page,
137
in duplex mode we set this parameters for each odd page
140
if ((features & PCL_HAS_DUPLEX) && dupset && dup) {
141
/* We are printing duplex, so change margins as needed */
142
if ((pdev->PageCount%2)==0) {
143
if (features & PCL_CAN_SET_PAPER_SIZE) {
144
fprintf(prn_stream, "\033&l%dA", paper_size);
146
fputs("\033&l0o0l0E", prn_stream);
147
fputs(odd_page_init, prn_stream);
149
fputs(even_page_init, prn_stream);
151
if (features & PCL_CAN_SET_PAPER_SIZE){
152
fprintf(prn_stream, "\033&l%dA", paper_size);
154
fputs("\033&l0o0l0E", prn_stream);
155
fputs(odd_page_init, prn_stream);
158
fprintf(prn_stream, "\033&l%dX", num_copies); /* # of copies */
160
/* End raster graphics, position cursor at top. */
161
fputs("\033*rB\033*p0x0Y", prn_stream);
163
/* The DeskJet and DeskJet Plus reset everything upon */
164
/* receiving \033*rB, so we must reinitialize graphics mode. */
165
if (features & PCL_END_GRAPHICS_DOES_RESET) {
166
fputs(odd_page_init, prn_stream); /* Assume this does the right thing */
167
fprintf(prn_stream, "\033&l%dX", num_copies); /* # of copies */
170
/* Set resolution. */
171
fprintf(prn_stream, "\033*t%dR", x_dpi);
173
/* Send each scan line in turn */
176
int num_blank_lines = 0;
177
word rmask = ~(word) 0 << (-pdev->width & (W * 8 - 1));
179
/* Transfer raster graphics. */
180
for (lnum = 0; lnum < num_rows; lnum++) {
181
register word *end_data =
182
data_words + line_size_words;
184
code = gdev_prn_copy_scan_lines(pdev, lnum,
185
(byte *) data, line_size);
188
/* Mask off 1-bits beyond the line width. */
189
end_data[-1] &= rmask;
190
/* Remove trailing 0s. */
191
while (end_data > data_words && end_data[-1] == 0)
193
if (end_data == data_words) { /* Blank line */
197
/* We've reached a non-blank line. */
198
/* Put out a spacing command if necessary. */
199
if (num_blank_lines == lnum) {
200
/* We're at the top of a page. */
201
if (features & PCL_ANY_SPACING) {
202
if (num_blank_lines > 0)
203
fprintf(prn_stream, "\033*p+%dY",
204
num_blank_lines * y_dots_per_pixel);
205
/* Start raster graphics. */
206
fputs("\033*r1A", prn_stream);
207
} else if (features & PCL_MODE_3_COMPRESSION) {
208
/* Start raster graphics. */
209
fputs("\033*r1A", prn_stream);
210
#if 1 /* don't waste paper */
211
if (num_blank_lines > 0)
212
fputs("\033*b0W", prn_stream);
215
for (; num_blank_lines; num_blank_lines--)
216
fputs("\033*b0W", prn_stream);
219
/* Start raster graphics. */
220
fputs("\033*r1A", prn_stream);
221
for (; num_blank_lines; num_blank_lines--)
222
fputs("\033*bW", prn_stream);
225
/* Skip blank lines if any */
226
else if (num_blank_lines != 0) {
228
* Moving down from current position causes head motion
229
* on the DeskJet, so if the number of lines is small,
230
* we're better off printing blanks.
233
* For Canon LBP4i and some others, <ESC>*b<n>Y doesn't
234
* properly clear the seed row if we are in compression mode
237
if ((num_blank_lines < MIN_SKIP_LINES && compression != 3) ||
238
!(features & PCL_ANY_SPACING)
241
(features & PCL_MODE_3_COMPRESSION) &&
242
!(features & PCL_ANY_SPACING);
244
if (mode_3ns && compression != 2) {
245
/* Switch to mode 2 */
246
fputs(from3to2, prn_stream);
249
if (features & PCL_MODE_3_COMPRESSION) {
250
/* Must clear the seed row. */
251
fputs("\033*b1Y", prn_stream);
255
for (; num_blank_lines; num_blank_lines--)
256
fputs("\033*b0W", prn_stream);
258
for (; num_blank_lines; num_blank_lines--)
259
fputs("\033*bW", prn_stream);
261
} else if (features & PCL3_SPACING) {
262
fprintf(prn_stream, "\033*p+%dY",
263
num_blank_lines * y_dots_per_pixel);
265
fprintf(prn_stream, "\033*b%dY",
268
/* Clear the seed row (only matters for */
269
/* mode 3 compression). */
270
memset(prev_row, 0, line_size);
274
/* Choose the best compression mode */
275
/* for this particular line. */
276
if (features & PCL_MODE_3_COMPRESSION) {
277
/* Compression modes 2 and 3 are both */
278
/* available. Try both and see which one */
279
/* produces the least output data. */
280
int count3 = gdev_pcl_mode3compress(line_size, data,
282
int count2 = gdev_pcl_mode2compress(data_words, end_data,
285
(compression == 3 ? 0 : penalty_from2to3);
287
(compression == 2 ? 0 : penalty_from3to2);
289
if (count3 + penalty3 < count2 + penalty2) {
290
if (compression != 3)
291
fputs(from2to3, prn_stream);
296
if (compression != 2)
297
fputs(from3to2, prn_stream);
299
out_data = out_row_alt;
302
} else if (features & PCL_MODE_2_COMPRESSION) {
304
out_count = gdev_pcl_mode2compress(data_words, end_data,
308
out_count = (byte *) end_data - data;
311
/* Transfer the data */
312
fprintf(prn_stream, "\033*b%dW", out_count);
313
fwrite(out_data, sizeof(byte), out_count,
318
/* end raster graphics and eject page */
319
fputs("\033*rB\f", prn_stream);
321
/* free temporary storage */
322
gs_free_object(pdev->memory, storage, "hpjet_print_page");