1 /* Copyright (C) 1997, 2000 artofcode LLC. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16
17 */
18
19 /* $Id: gdevhl7x.c,v 1.5.2.1.2.1 2003/01/17 00:49:00 giles Exp $ */
20 /*
21 * Brother HL 720 and 730 driver for Ghostscript
22 *
23 * Note: for the HL 760, use the HP driver.
24 *
25 * The original code was borrowed from the
26 * HP LaserJet/DeskJet driver for Ghostscript.
27 * The code specific to the Brother HL 720 was written by :
28 * Pierre-Olivier Gaillard (pierre.gaillard@hol.fr)
29 * Thanks to the documentation kindly provided by :
30 * Richard Thomas <RICHARDT@brother.co.uk>
31 *
32 * Removal of compression code on 1/17/00 by Ross Martin
33 * (ross@ross.interwrx.com, martin@walnut.eas.asu.edu)
34 * enables this driver to correctly print tiger.ps on a
35 * Brother MFC6550MC Fax Machine. Change to the Horizontal
36 * Offset fixes incorrect page alignment at 300dpi in
37 * Landscape mode with a2ps.
38 */
39 #include "gdevprn.h"
40 /* The following line is used though these printers are not PCL printers*/
41 /* This is because we want the paper size access function */
42 /* (The 720 is a simple GDI printer) */
43 #include "gdevpcl.h"
44
45 /*
46 * You may select a default resolution of 150 (for 730), 300, or
47 * 600 DPI in the makefile, or an actual resolution on
48 * the gs command line.
49 *
50 * If the preprocessor symbol A4 is defined, the default paper size is
51 * the European A4 size; otherwise it is the U.S. letter size (8.5"x11").
52 *
53 * You may find the following test page useful in determining the exact
54 * margin settings on your printer. It prints four big arrows which
55 * point exactly to the for corners of an A4 sized paper. Of course the
56 * arrows cannot appear in full on the paper, and they are truncated by
57 * the margins. The margins measured on the testpage must match those
58 * in gdevdjet.c. So the testpage indicates two facts: 1) the page is
59 * not printed in the right position 2) the page is truncated too much
60 * because the margins are wrong. Setting wrong margins in gdevdjet.c
61 * will also move the page, so both facts should be matched with the
62 * real world.
63
64 %!
65 newpath
66 0 0 moveto 144 72 lineto 72 144 lineto
67 closepath fill stroke 0 0 moveto 144 144 lineto stroke
68
69 595.27 841.88 moveto 451.27 769.88 lineto 523.27 697.88 lineto
70 closepath fill stroke 595.27 841.88 moveto 451.27 697.88 lineto stroke
71
72 0 841.88 moveto 144 769.88 lineto 72 697.88 lineto
73 closepath fill stroke 0 841.88 moveto 144 697.88 lineto stroke
74
75 595.27 0 moveto 451.27 72 lineto 523.27 144 lineto
76 closepath fill stroke 595.27 0 moveto 451.27 144 lineto stroke
77
78 /Helvetica findfont
79 14 scalefont setfont
80 100 600 moveto
81 (This is an A4 testpage. The arrows should point exactly to the) show
82 100 580 moveto
83 (corners and the margins should match those given in gdev*.c) show
84 showpage
85
86 */
87
88
89 /* Type definitions */
90 typedef struct {
91 short width; /* physical width of the paper */
92 short height; /* physical height of the paper */
93 } PaperFormat; /* Rep. of the charateristics of a sheet of paper */
94
95 typedef unsigned char Byte; /* Rep. of elementary data unit */
96
97
98
99 /*
100 * Definition of a Helper structure to handle a list of commands
101 */
102 typedef struct {
103 Byte * data;
104 short maxSize;
105 short current;
106
107 } ByteList;
108
109 /*
110 * Type for representing a summary of the previous lines
111 *
112 */
113
114 typedef struct {
115 short previousSize;
116 Byte previousData[1500]; /* Size bigger than any possible line */
117 short nbBlankLines;
118 short nbLinesSent;
119 short pageWidth;
120 short pageHeight;
121 short horizontalOffset;
122 short resolution;
123 } Summary;
124
125
126
127 /* Constants */
128
129 /* We need a boolean : true , we got it from gdevprn.h */
130
131 /* Other constants */
132 private const int DumpFinished = 0;
133 private const int DumpContinue = 1;
134 private const int HL7X0_LENGTH = 5; /* Length of a command to tell the size of the data to be sent to the printer*/
135 private void makeCommandsForSequence(Byte * pSource,
136 short length,
137 ByteList * pCommandList,
138 short offset,
139 Byte * pCommandCount,
140 short rest);
141
142 /* Auxiliary Functions */
143
144
145
146 private int dumpPage(gx_device_printer * pSource,
147 Byte * pLineTmp,
148 ByteList * pCommandList,
149 Summary * pSummary
150 );
151 private void initSummary(Summary * s,short pw, short ph, short resolution);
152
153 private void resetPreviousData(Summary * s);
154
155 private void makeFullLine( Byte * pCurrentLine,
156 Byte * pPreviousLine,
157 short lineWidth,
158 ByteList * commandsList,
159 short horizontalOffset
160 );
161
162
163
164 /*
165 * Initialize a list of Bytes structure
166 */
167 private void initByteList(ByteList *list, Byte *array, short maxSize,short initCurrent);
168 private void addByte(ByteList *list,Byte value );
169 private void addArray(ByteList *list, Byte *source, short nb);
170 private void addNBytes(ByteList * list, Byte value, short nb);
171 private Byte * currentPosition(ByteList * list);
172 private void addCodedNumber(ByteList * list, short number);
173 private int isThereEnoughRoom(ByteList * list, short biggest);
174 private short roomLeft(ByteList * list);
175 private void dumpToPrinter(ByteList * list,FILE * printStream);
176
177 /* Real Print function */
178
179 private int hl7x0_print_page(P5(gx_device_printer *, FILE *, int, int, ByteList *));
180
181
182
183
184
185
186 /* Define the default, maximum resolutions. */
187 #ifdef X_DPI
188 # define X_DPI2 X_DPI
189 #else
190 # define X_DPI 300
191 # define X_DPI2 600
192 #endif
193 #ifdef Y_DPI
194 # define Y_DPI2 Y_DPI
195 #else
196 # define Y_DPI 300
197 # define Y_DPI2 600
198 #endif
199
200
201 #define LETTER_WIDTH 5100
202 #define LEFT_MARGIN 30
203 /* The following table is not actually used.... */
204 private const PaperFormat tableOfFormats[] = {
205 /* 0 P LETTER */ { 2550, 3300 },
206 /* 1 P LEGAL */ { 2550, 4200 },
207 /* 2 P EXEC */ { 2175, 3150 },
208 /* 3 P A4(78) */ { 2480, 3507 },
209 /* 4 P B5 */ { 2078, 2953 },
210 /* 5 P A5 */ { 1754, 2480 },
211 /* 6 P MONARC */ { 1162, 2250 },
212 /* 7 P COM10 */ { 1237, 2850 },
213 /* 8 P DL */ { 1299, 2598 },
214 /* 9 P C5 */ { 1913, 2704 },
215 /* 10 P A4Long */ { 2480, 4783 },
216
217 /* 11 L LETTER */ { 3300, 2550 },
218 /* 12 L LEGAL */ { 4200, 2550 },
219 /* 13 L EXEC */ { 3150, 2175 },
220 /* 14 L A4 */ { 3507, 2480 },
221 /* 15 L B5 */ { 2952, 2078 },
222 /* 16 L A5 */ { 2480, 1754 },
223 /* 17 L MONARC */ { 2250, 1162 },
224 /* 18 L COM10 */ { 2850, 1237 },
225 /* 19 L DL */ { 2598, 1299 },
226 /* 20 L C5 */ { 2704, 1913 },
227 /* 21 L A4Long */ { 4783, 2480 }
228 };
229
230
231 /* Compute the maximum length of a compressed line */
MaxLineLength(short resolution)232 private short MaxLineLength(short resolution){
233 return (((156 * resolution / 150 ) * 5 )/4) + 8;
234 }
235
236
237 /* Margins are left, bottom, right, top. */
238 /* Quotation from original gdevdjet.c */
239 /* from Frans van Hoesel hoesel@rugr86.rug.nl. */
240 /* A4 has a left margin of 1/8 inch and at a printing width of
241 * 8 inch this give a right margin of 0.143. The 0.09 top margin is
242 * not the actual margin - which is 0.07 - but compensates for the
243 * inexact paperlength which is set to 117 10ths.
244 * Somebody should check for letter sized paper. I left it at 0.07".
245 */
246
247
248 /* The A4 margins are almost good */
249 /* The one for Letter are those of the gdevdjet.c file... */
250 #define HL7X0_MARGINS_A4 0.1, 0.15, 0.07, 0.05
251 #define HL7X0_MARGINS_LETTER 0.275, 0.20, 0.25, 0.07
252
253
254
255 /* We round up the LINE_SIZE to a multiple of a ulong for faster scanning. */
256 #define W sizeof(word)
257
258 /* Printer types */
259
260 #define HL720 0
261 #define HL730 0 /* No difference */
262
263
264
265
266 /* The device descriptors */
267 private dev_proc_open_device(hl7x0_open);
268 private dev_proc_close_device(hl7x0_close);
269 private dev_proc_print_page(hl720_print_page);
270 private dev_proc_print_page(hl730_print_page);
271
272
273
274 private const gx_device_procs prn_hl_procs =
275 prn_params_procs(hl7x0_open, gdev_prn_output_page, hl7x0_close,
276 gdev_prn_get_params, gdev_prn_put_params);
277
278
279 const gx_device_printer far_data gs_hl7x0_device =
280 prn_device(prn_hl_procs, "hl7x0",
281 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
282 X_DPI, Y_DPI,
283 0, 0, 0, 0, /* margins filled in by hl7x0_open */
284 1, hl720_print_page); /* The hl720 and hl730 can both use the same print method */
285
286
287
288 /* Open the printer, adjusting the margins if necessary. */
289
290 private int
hl7x0_open(gx_device * pdev)291 hl7x0_open(gx_device *pdev)
292 { /* Change the margins if necessary. */
293 static const float m_a4[4] = { HL7X0_MARGINS_A4 };
294 static const float m_letter[4] = { HL7X0_MARGINS_LETTER };
295 const float *m =
296 (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? m_a4 : m_letter);
297
298 gx_device_set_margins(pdev, m, true);
299 return gdev_prn_open(pdev);
300 }
301
302
303 /* The orders sent are those provided in the Brother DOS example */
304 private int
hl7x0_close(gx_device * pdev)305 hl7x0_close(gx_device *pdev)
306 {
307 gx_device_printer *const ppdev = (gx_device_printer *)pdev;
308 int code = gdev_prn_open_printer(pdev, 1);
309
310 if (code < 0)
311 return code;
312 fputs("@N@N@N@N@X", ppdev->file) ;
313 return gdev_prn_close_printer(pdev);
314 }
315
316 /* ------ Internal routines ------ */
317
318 /* The HL 720 can compress*/
319 private int
hl720_print_page(gx_device_printer * pdev,FILE * prn_stream)320 hl720_print_page(gx_device_printer *pdev, FILE *prn_stream)
321 {
322 Byte prefix[] ={
323 0x1B,'%','-','1','2','3','4','5','X'
324 ,'@','P','J','L',0x0A /* set PJL mode */
325 ,'@','P','J','L',' ','E','N','T','E','R',' '
326 ,'L','A','N','G','U','A','G','E'
327 ,' ','=',' ','H','B','P',0x0A /* set GDI Printer mode */
328 ,'@','L', 0x0
329 };
330 ByteList initCommand;
331 int x_dpi = pdev->x_pixels_per_inch;
332 initByteList(&initCommand,
333 prefix, /* Array */
334 sizeof(prefix), /* Total size */
335 sizeof(prefix) - 1); /* Leave one byte free since*/
336 /* we need to add the following order at the end */
337 addByte(&initCommand, (Byte) ((((600/x_dpi) >> 1) \
338 | (((600/x_dpi) >> 1) << 2))));
339 /* Put the value of the used resolution into the init string */
340
341 return hl7x0_print_page(pdev, prn_stream, HL720, 300,
342 &initCommand);
343 }
344 /* The HL 730 can compress */
345 private int
hl730_print_page(gx_device_printer * pdev,FILE * prn_stream)346 hl730_print_page(gx_device_printer *pdev, FILE *prn_stream)
347 { return hl720_print_page(pdev, prn_stream);
348 }
349
350 /* Send the page to the printer. For speed, compress each scan line, */
351 /* since computer-to-printer communication time is often a bottleneck. */
352 private int
hl7x0_print_page(gx_device_printer * pdev,FILE * printStream,int ptype,int dots_per_inch,ByteList * initCommand)353 hl7x0_print_page(gx_device_printer *pdev, FILE *printStream, int ptype,
354 int dots_per_inch, ByteList *initCommand)
355 {
356 /* UTILE*/
357 /* Command for a formFeed (we can't use strings because of the zeroes...)*/
358 Byte FormFeed[] = {'@','G',0x00,0x00,0x01,0xFF,'@','F'};
359 ByteList formFeedCommand;
360 /* Main characteristics of the page */
361 int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
362 int x_dpi = pdev->x_pixels_per_inch;
363 /* int y_dpi = pdev->y_pixels_per_inch; */
364 int num_rows = dev_print_scan_lines(pdev);
365 int result;
366 int sizeOfBuffer = MaxLineLength(x_dpi) + 30;
367 Byte * storage = (Byte *) gs_malloc(sizeOfBuffer + line_size,
368 1,
369 "hl7x0_print_page");
370 /* bool dup = pdev->Duplex; */
371 /* bool dupset = pdev->Duplex_set >= 0; */
372 Summary pageSummary;
373 ByteList commandsBuffer;
374 initSummary(&pageSummary,
375 line_size,
376 num_rows,
377 x_dpi);
378 if ( storage == 0 ) /* can't allocate working area */
379 return_error(gs_error_VMerror);
380 initByteList(&commandsBuffer, storage, sizeOfBuffer,0 );
381 /* PLUS A MOI */
382 if ( pdev->PageCount == 0 )
383 {
384 /* Put out init string before first page. */
385 dumpToPrinter(initCommand, printStream); /* send init to printer */
386
387 }
388
389 do {
390 result = dumpPage(pdev,
391 storage + sizeOfBuffer, /* The line buffer is after the dump buffer */
392 &commandsBuffer,
393 &pageSummary);
394 dumpToPrinter(&commandsBuffer,printStream);
395
396 } while (result == DumpContinue);
397
398
399 /* end raster graphics and eject page */
400 initByteList(&formFeedCommand,
401 FormFeed, /* Array */
402 sizeof(FormFeed), /* Size in bytes */
403 sizeof(FormFeed)); /* First free byte */
404 dumpToPrinter(&formFeedCommand, printStream);
405
406 /* free temporary storage */
407 gs_free((char *)storage, storage_size_words, 1, "hl7X0_print_page");
408
409 return 0; /* If we reach this line, it means there was no error */
410 }
411
412 /*
413 * Useful auxiliary declarations
414 *
415 */
416
417
stripTrailingBlanks(Byte * line,short length)418 private short stripTrailingBlanks(Byte * line, short length){
419 short positionOfFirstZero = length - 1;
420 while (positionOfFirstZero > 0) {
421 if (line[positionOfFirstZero] != 0) {
422 return positionOfFirstZero + 1;
423 }
424 positionOfFirstZero -- ;
425 }
426 return 0;
427 }
428
429 /*
430 * Changed the horizontalOffset function 1/17/00 Ross Martin.
431 * ross@ross.interwrx.com or martin@walnut.eas.asu.edu
432 *
433 * The equation used to muliply pixWidth by resolution/600
434 * also. This didn't work right at resolution 300; it caused
435 * landscape pages produced by a2ps to be half off the
436 * page, when they were not at 600dpi or on other
437 * devices. I'm not sure the equation below is exactly
438 * correct, but it now looks to be pretty close visually,
439 * and works correctly at 600dpi and 300dpi.
440 */
horizontalOffset(short pixWidth,short pixOffset,short resolution)441 private short horizontalOffset(short pixWidth,
442 short pixOffset,
443 short resolution){
444 return (((LETTER_WIDTH * resolution/600 - pixWidth) + pixOffset * 2) + 7) / 8;
445
446 }
447
448
449
450 /*
451 * First values in a Summary
452 */
initSummary(Summary * s,short pw,short ph,short resolution)453 private void initSummary(Summary * s,short pw, short ph, short resolution){
454 s->previousSize = -1 ;
455 s->nbBlankLines = 1;
456 s->nbLinesSent = 0;
457 s->pageWidth = pw; /* In Bytes */
458 s->pageHeight = ph;
459 s->horizontalOffset = horizontalOffset( pw * 8,LEFT_MARGIN, resolution) ;
460 s->resolution = resolution;
461 }
462
463 /*
464 * The previous line was blank, so we need to clean the corresponding array
465 */
resetPreviousData(Summary * s)466 private void resetPreviousData(Summary * s){
467 memset(s->previousData,0,s->pageWidth);
468 }
469
470
471 /*
472 * dumpPage :
473 *
474 */
dumpPage(gx_device_printer * pSource,Byte * pLineTmp,ByteList * pCommandList,Summary * pSummary)475 private int dumpPage(gx_device_printer * pSource,
476 Byte * pLineTmp,
477 ByteList * pCommandList,
478 Summary * pSummary
479 ){
480
481 /* Declarations */
482 Byte * pSaveCommandStart;
483 short lineNB;
484 short usefulLength;
485 short tmpLength;
486 /* Initializations */
487 /* Make room for size of commands buffer */
488 pSaveCommandStart = currentPosition(pCommandList);
489 addNBytes(pCommandList,0,HL7X0_LENGTH);
490 /* pSource += pSummary->nbLinesSent * pSummary->pageWidth;*/
491 /* Process all possible Lines */
492 for (lineNB = pSummary->nbLinesSent /*ERROR? + nbBlankLines */ ;
493 lineNB < pSummary->pageHeight ; lineNB ++ ) {
494 /* Fetch the line and put it into the buffer */
495 gdev_prn_copy_scan_lines(pSource,
496 lineNB,
497 pLineTmp,
498 pSummary->pageWidth);
499
500 usefulLength = stripTrailingBlanks(pLineTmp,pSummary->pageWidth);
501 if (usefulLength != 0) {
502
503 /* The line is not blank */
504 /* Get rid of the precedent blank lines */
505 if (pSummary->nbBlankLines != 0) {
506 if ( isThereEnoughRoom( pCommandList, pSummary->nbBlankLines ) ) {
507
508 addNBytes(pCommandList,0xff,pSummary->nbBlankLines);
509 pSummary->nbBlankLines = 0;
510
511 }
512 else {
513
514 short availableRoom = roomLeft(pCommandList);
515 addNBytes(pCommandList,0xff,availableRoom);
516 pSummary->nbBlankLines -= availableRoom;
517
518 break ; /* We have no more room */
519
520 }
521
522 resetPreviousData(pSummary); /* Make sure there are zeroes for the previous line */
523 pSummary->previousSize = 0; /* The previous line was empty */
524
525 }
526
527 /* Deal with the current line */
528 if (!isThereEnoughRoom(pCommandList,MaxLineLength(pSummary->resolution))){
529 break; /* We can process this line */
530 }
531
532 if (pSummary->previousSize > usefulLength){
533 tmpLength = pSummary->previousSize;
534 }
535 else {
536 tmpLength = usefulLength;
537 }
538
539 if (pSummary->previousSize == -1 ) {/* This is the first line */
540
541 Byte *save = currentPosition(pCommandList);
542 addByte(pCommandList,0); /* One byte for the number of commands */
543
544 makeCommandsForSequence(pLineTmp,
545 tmpLength,
546 pCommandList,
547 pSummary->horizontalOffset,
548 save,
549 0);
550 }
551 else { /*There is a previous line */
552
553 makeFullLine(pLineTmp,
554 pSummary->previousData,
555 tmpLength,
556 pCommandList,
557 pSummary->horizontalOffset);
558 }
559 /* The present line will soon be considered as "previous" */
560 pSummary->previousSize = tmpLength;
561 /* Update the data representing the line will soon be the "previous line" */
562 memcpy(pSummary->previousData,pLineTmp,tmpLength);
563
564 }
565 else { /* the current line is blank */
566 pSummary->nbBlankLines++;
567 }
568
569 /* And one more line */
570 pSummary->nbLinesSent ++;
571 }
572
573 if (pCommandList->current > HL7X0_LENGTH){
574 short size = pCommandList->current - HL7X0_LENGTH;
575 *(pSaveCommandStart++) = '@';
576 *(pSaveCommandStart++) = 'G';
577 *(pSaveCommandStart++) = (Byte) (size >> 16);
578 *(pSaveCommandStart++) = (Byte) (size >> 8);
579 *(pSaveCommandStart++) = (Byte) (size);
580 }
581 else { /* We only met blank lines and reached the end of the page */
582 pCommandList->current = 0;
583 }
584 if (lineNB == pSummary->pageHeight){
585 return DumpFinished;
586 }
587 else {
588 return DumpContinue;
589 }
590 }
591
592
593 /*
594 * makeFullLine :
595 * process an arbitrary line for which a former line is available
596 * The line will be split in sequences that are different from the
597 * corresponding ones of the previous line. These sequences will be processed
598 * by makeCommandsOfSequence.
599 */
600
601
602
makeFullLine(Byte * pCurrentLine,Byte * pPreviousLine,short lineWidth,ByteList * commandsList,short horizontalOffset)603 private void makeFullLine( Byte * pCurrentLine,
604 Byte * pPreviousLine,
605 short lineWidth,
606 ByteList * commandsList,
607 short horizontalOffset
608 ){
609 /* Declarations */
610 Byte *pPreviousTmp;
611 Byte *pCurrentTmp;
612 Byte *pNumberOfCommands;
613 int loopCounter;
614 short remainingWidth;
615 Byte *pStartOfSequence;
616 /*****************/
617 /* Special cases */
618 /*****************/
619
620 /* I believe this situation to be impossible */
621 if (lineWidth <= 0) {
622 addByte(commandsList,0xff);
623 return;
624 }
625
626 /*******************/
627 /* Initializations */
628 /*******************/
629
630 pNumberOfCommands = currentPosition(commandsList); /* Keep a pointer to the number of commands */
631 addByte(commandsList,0); /* At the moment there are 0 commands */
632
633 pPreviousTmp = pPreviousLine;
634 pCurrentTmp = pCurrentLine;
635
636 /* Build vector of differences with a Xor */
637
638 for (loopCounter = lineWidth ; 0 < loopCounter ; loopCounter -- )
639 *pPreviousTmp++ ^= *pCurrentTmp++;
640
641 /* Find sequences that are different from the corresponding (i.e. vertically aligned)
642 * one of the previous line. Make commands for them.
643 */
644
645 pStartOfSequence = pPreviousLine;
646 remainingWidth = lineWidth;
647
648 while (true) {
649
650 /*
651 * Disabled line-to-line compression, 1/17/00 Ross Martin
652 * ross@ross.interwrx.com and/or martin@walnut.eas.asu.edu
653 *
654 * The compression here causes problems printing tiger.ps.
655 * The problem is vertical streaks. The printer I'm printing
656 * to is a Brother MFC6550MC Fax Machine, which may be
657 * slightly different from the hl720 and hl730. Note that
658 * this fax machine does support HP LaserJet 2p emulation,
659 * but in order to enable it I believe one needs special
660 * setup from a DOS program included with the printer. Thus,
661 * the hl7x0 driver seems a better choice. In any case,
662 * on the MFC6550MC, some files print fine with compression
663 * turned on, but others such as tiger.ps print with streaks.
664 * disabling the compression fixes the problem, so I haven't
665 * looked any further at the cause. It may be that the
666 * compression is correct for the hl720 and hl730, and only
667 * different for the MFC6550MC, or it may be that tiger.ps
668 * won't print correctly with compression enabled on any
669 * of these. It may be that the problem is only with color
670 * and/or grayscale prints. YMMV. I don't think it likely
671 * that turning off compression will cause problems with
672 * other printers, except that they may possibly print slower.
673 */
674
675 #ifdef USE_POSSIBLY_FLAWED_COMPRESSION
676 /* Count and skip bytes that are not "new" */
677 while (true) {
678 if (remainingWidth == 0) /* There is nothing left to do */
679 {
680 return;
681 }
682 if (*pStartOfSequence != 0)
683 break;
684 pStartOfSequence ++;
685 horizontalOffset ++; /* the offset takes count of the bytes that are not "new" */
686 --remainingWidth;
687 }
688 #endif
689
690 pPreviousTmp = pStartOfSequence + 1; /* The sequence contains at least this byte */
691 --remainingWidth;
692
693 /* Find the end of the sequence of "new" bytes */
694
695 #ifdef USE_POSSIBLY_FLAWED_COMPRESSION
696 while (remainingWidth != 0 && *pPreviousTmp != 0) {
697 ++pPreviousTmp; /* Enlarge the sequence Of new bytes */
698 --remainingWidth;
699 }
700 #else
701 pPreviousTmp += remainingWidth;
702 remainingWidth = 0;
703 #endif
704
705 makeCommandsForSequence(pCurrentLine + (pStartOfSequence - pPreviousLine),
706 pPreviousTmp - pStartOfSequence,
707 commandsList,
708 horizontalOffset,
709 pNumberOfCommands,
710 remainingWidth);
711 if (*pNumberOfCommands == 0xfe /* If the number of commands has reached the maximum value */
712 || /* or */
713 remainingWidth == 0 ) /* There is nothing left to process */
714 {
715 return;
716 }
717
718 pStartOfSequence = pPreviousTmp + 1; /* We go on right after the sequence of "new" bytes */
719 horizontalOffset = 1;
720 --remainingWidth;
721 } /* End of While */
722
723
724
725
726 } /* End of makeFullLine */
727
728
729
730 /*
731 * Declarations of functions that are defined further in the file
732 */
733 private void makeSequenceWithoutRepeat(
734 Byte * pSequence,
735 short lengthOfSequence,
736 ByteList * pCommandList,
737 short offset );
738
739 private void makeSequenceWithRepeat(
740 Byte * pSequence,
741 short lengthOfSequence,
742 ByteList * pCommandList,
743 short offset );
744
745
746 /*
747 * makeCommandsForSequence :
748 * Process a sequence of new bytes (i.e. different from the ones on the former line)
749 */
750
makeCommandsForSequence(Byte * pSource,short length,ByteList * pCommandList,short offset,Byte * pNumberOfCommands,short rest)751 private void makeCommandsForSequence(Byte * pSource,
752 short length,
753 ByteList * pCommandList,
754 short offset,
755 Byte * pNumberOfCommands,
756 short rest) {
757 /* Declarations */
758 Byte * pStartOfSequence;
759 Byte * pEndOfSequence;
760 short remainingLength = length - 1;
761
762 pStartOfSequence = pSource;
763 pEndOfSequence = pStartOfSequence + 1;
764 /*
765 * Process the whole "new" Sequence that is divided into
766 * repetitive and non-repetitive sequences.
767 */
768 while (true) {
769
770 /* If we have already stored too many commands, make one last command with
771 * everything that is left in the line and return.
772 */
773 if (*pNumberOfCommands == 0xfd) {
774 makeSequenceWithoutRepeat(pStartOfSequence,
775 1 + remainingLength + rest,
776 pCommandList,
777 offset);
778 ++*pNumberOfCommands;
779 return;
780 }
781
782 /* Start with a sub-sequence without byte-repetition */
783 while (true) {
784 /* If we have completed the last subsequence */
785 if (remainingLength == 0) {
786 makeSequenceWithoutRepeat(pStartOfSequence,
787 pEndOfSequence - pStartOfSequence,
788 pCommandList,
789 offset);
790 ++*pNumberOfCommands;
791 return;
792 }
793 /* If we have discovered a repetition */
794 if (*pEndOfSequence == *(pEndOfSequence - 1)) {
795 break;
796 }
797 ++ pEndOfSequence; /* The subsequence is bigger*/
798 --remainingLength;
799 }
800 /* If this is a sequence without repetition */
801 if (pStartOfSequence != pEndOfSequence - 1) {
802 makeSequenceWithoutRepeat(pStartOfSequence,
803 (pEndOfSequence - 1) - pStartOfSequence,
804 pCommandList,
805 offset);
806 ++*pNumberOfCommands;
807 offset = 0;
808 pStartOfSequence = pEndOfSequence - 1;
809
810 /* If we have too many commands */
811 if (*pNumberOfCommands == 0xfd) {
812 makeSequenceWithoutRepeat(pStartOfSequence,
813 1 + remainingLength + rest,
814 pCommandList,
815 offset);
816 ++*pNumberOfCommands;
817 return;
818 }
819 } /* End If */
820
821 /*
822 * Process a subsequence that repeats the same byte
823 */
824 while (true) {
825 /* If there is nothing left to process */
826 if (remainingLength == 0) {
827 makeSequenceWithRepeat(pStartOfSequence,
828 pEndOfSequence - pStartOfSequence,
829 pCommandList,
830 offset);
831 ++*pNumberOfCommands;
832 return;
833 }
834 /* If we find a different byte */
835 if (*pEndOfSequence != *pStartOfSequence){
836 break;
837 }
838 ++pEndOfSequence; /* The subsequence is yet bigger */
839 --remainingLength;
840 } /* End of While */
841 makeSequenceWithRepeat(pStartOfSequence,
842 pEndOfSequence - pStartOfSequence,
843 pCommandList,
844 offset);
845 ++*pNumberOfCommands;
846 offset = 0; /* The relative offset between two subsequences is 0 */
847 pStartOfSequence = pEndOfSequence ++ ; /* we loop again from the end of this subsequence */
848 --remainingLength;
849
850 } /* End of While */
851
852 } /* End makeCommandsForSequence */
853
854
855
856
857
858
859
860
861 /*
862 * makeSequenceWithoutRepeat
863 */
makeSequenceWithoutRepeat(Byte * pSequence,short lengthOfSequence,ByteList * pCommandList,short offset)864 private void makeSequenceWithoutRepeat(
865 Byte * pSequence,
866 short lengthOfSequence,
867 ByteList * pCommandList,
868 short offset ){
869 /*
870 * Constant definitions
871 */
872 static const short MAX_OFFSET = 15;
873 static const short POSITION_OF_OFFSET = 3;
874 static const short MAX_LENGTH = 7;
875
876 Byte tmpFirstByte = 0;
877 Byte * pSaveFirstByte;
878 short reducedLength = lengthOfSequence - 1; /* Length is alway higher than 1
879 Therefore a reduced value is stored
880 */
881 /* Initialization */
882
883 pSaveFirstByte = currentPosition(pCommandList);
884 addByte( pCommandList, 0 /* Dummy value */);
885
886 /* Computations */
887
888 if (offset >= MAX_OFFSET) {
889 addCodedNumber(pCommandList,offset - MAX_OFFSET);
890 tmpFirstByte |= MAX_OFFSET << POSITION_OF_OFFSET;
891 }
892 else
893 tmpFirstByte |= offset << POSITION_OF_OFFSET;
894
895 if (reducedLength >= MAX_LENGTH) {
896 addCodedNumber(pCommandList,reducedLength - MAX_LENGTH);
897 tmpFirstByte |= MAX_LENGTH ;
898 }
899 else
900 tmpFirstByte |= reducedLength ;
901 /* Add a copy of the source sequence */
902
903 addArray(pCommandList, pSequence, lengthOfSequence);
904
905 /* Store the computed value of the first byte */
906
907 *pSaveFirstByte = tmpFirstByte;
908
909 return ;
910 } /* End of makeSequenceWithoutRepeat */
911
912
913
914 /*
915 * makeSequenceWithRepeat
916 */
makeSequenceWithRepeat(Byte * pSequence,short lengthOfSequence,ByteList * pCommandList,short offset)917 private void makeSequenceWithRepeat(
918 Byte * pSequence,
919 short lengthOfSequence,
920 ByteList * pCommandList,
921 short offset ){
922 /*
923 * Constant definitions
924 */
925 static const short MAX_OFFSET = 3;
926 static const short POSITION_OF_OFFSET = 5;
927 static const short MAX_LENGTH = 31;
928
929 Byte tmpFirstByte = 0x80;
930 Byte * pSaveFirstByte;
931 short reducedLength = lengthOfSequence - 2; /* Length is always higher than 2
932 Therefore a reduced value is stored
933 */
934 /* Initialization */
935
936 pSaveFirstByte = currentPosition(pCommandList);
937 addByte( pCommandList, 0 /* Dummy value */);
938
939 /* Computations */
940
941 if (offset >= MAX_OFFSET) {
942 addCodedNumber(pCommandList, offset - MAX_OFFSET);
943 tmpFirstByte |= MAX_OFFSET << POSITION_OF_OFFSET;
944 }
945 else
946 tmpFirstByte |= offset << POSITION_OF_OFFSET;
947
948 if (reducedLength >= MAX_LENGTH) {
949 addCodedNumber(pCommandList,reducedLength - MAX_LENGTH);
950 tmpFirstByte |= MAX_LENGTH ;
951 }
952 else
953 tmpFirstByte |= reducedLength ;
954 /* Add a copy the byte that is repeated throughout the sequence */
955
956 addByte(pCommandList, *pSequence );
957
958 /* Store the computed value of the first byte */
959
960 *pSaveFirstByte = tmpFirstByte;
961
962 return ;
963 } /* End of makeSequenceWithRepeat*/
964
965
966
967
968 /*
969 * Initialize a list of Bytes structure
970 */
initByteList(ByteList * list,Byte * array,short maxSize,short initCurrent)971 private void initByteList(ByteList *list, Byte *array, short maxSize, short initCurrent) {
972 list->current = initCurrent;
973 list->maxSize = maxSize;
974 list->data = array;
975 }
976
977 /*
978 * Add a Byte to a list of Bytes
979 */
addByte(ByteList * list,Byte value)980 private void addByte(ByteList *list,Byte value ) {
981 if (list->current < list->maxSize)
982 list->data[list->current++] = value;
983 else
984 errprintf("Could not add byte to command\n");
985 }
986
987
988 /*
989 * Add a copy of an array to a list of Bytes
990 */
991
addArray(ByteList * list,Byte * source,short nb)992 private void addArray(ByteList *list, Byte *source, short nb){
993 if (list->current <= list->maxSize - nb)
994 {
995 memcpy(list->data + list->current, source , (size_t) nb);
996 list->current += nb;
997 }
998 else
999 errprintf("Could not add byte array to command\n");
1000 }
1001
1002
1003 /*
1004 * Add N bytes to a list of Bytes
1005 */
1006
addNBytes(ByteList * list,Byte value,short nb)1007 private void addNBytes(ByteList * list, Byte value, short nb){
1008 int i;
1009 if (list->current <= list->maxSize - nb)
1010 {
1011 for (i = list->current ; i < (list->current + nb) ; i++)
1012 {
1013 list->data[i] = value;
1014 }
1015 list->current += nb;
1016 }
1017 else
1018 errprintf("Could not add %d bytes to command\n",nb);
1019 }
1020
1021 /*
1022 * Get pointer to the current byte
1023 */
currentPosition(ByteList * list)1024 private Byte * currentPosition(ByteList * list) {
1025 return &(list->data[list->current]);
1026 }
1027
1028 /*
1029 * add a number coded in the following way :
1030 * q bytes with 0xff value
1031 * 1 byte with r value
1032 * where q is the quotient of the number divided by 0xff and r is the
1033 * remainder.
1034 */
addCodedNumber(ByteList * list,short number)1035 private void addCodedNumber(ByteList * list, short number){
1036 short q = number / 0xff;
1037 short r = number % 0xff;
1038
1039 addNBytes(list, 0xff, q);
1040 addByte(list,r);
1041
1042 }
1043
1044 /*
1045 * See if there is enough room for a set of commands of size biggest
1046 *
1047 */
1048
isThereEnoughRoom(ByteList * list,short biggest)1049 private int isThereEnoughRoom(ByteList * list, short biggest){
1050 return ((list->maxSize-list->current) >= biggest);
1051 }
1052 /*
1053 * Tell how much room is left
1054 */
roomLeft(ByteList * list)1055 private short roomLeft(ByteList * list){
1056 return list->maxSize - list->current;
1057 }
1058 /*
1059 * Dump all commands to the printer and reset the structure
1060 *
1061 */
dumpToPrinter(ByteList * list,FILE * printStream)1062 private void dumpToPrinter(ByteList * list,FILE * printStream){
1063 short loopCounter;
1064 /* Actual dump */
1065 /* Please note that current is the first empty byte */
1066 for (loopCounter = 0; loopCounter < list->current; loopCounter++)
1067 {
1068 fputc(list->data[loopCounter],printStream);
1069 }
1070
1071 /* Reset of the ByteList */
1072 list->current = 0;
1073 }
1074