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