summaryrefslogtreecommitdiff
blob: 66d1db29e4940fde545bdf50c2f1510f6dea9635 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
/* Copyright (C) 2001-2020 Artifex Software, Inc.
   All Rights Reserved.

   This software is provided AS-IS with no warranty, either express or
   implied.

   This software is distributed under license and may not be copied,
   modified or distributed except as expressly authorized under the terms
   of the license contained in the file LICENSE in this distribution.

   Refer to licensing information at http://www.artifex.com or contact
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
   CA 94945, U.S.A., +1(415)492-9861, for further information.
*/

/*
 * Brother HL 720 and 730 driver for Ghostscript
 *
 * Note: for the HL 760, use the HP driver.
 *
 * The original code was borrowed from the
 * HP LaserJet/DeskJet driver for Ghostscript.
 * The code specific to the Brother HL 720 was written by :
 *       Pierre-Olivier Gaillard (pierre.gaillard@hol.fr)
 * Thanks to the documentation kindly provided by :
 *        Richard Thomas <RICHARDT@brother.co.uk>
 *
 * Removal of compression code on 1/17/00 by Ross Martin
 * (ross@ross.interwrx.com, martin@walnut.eas.asu.edu)
 * enables this driver to correctly print tiger.eps on a
 * Brother MFC6550MC Fax Machine.  Change to the Horizontal
 * Offset fixes incorrect page alignment at 300dpi in
 * Landscape mode with a2ps.
 */
#include "gdevprn.h"
/* The following line is used though these printers are not PCL printers*/
/* This is because we want the paper size access function */
/* (The 720 is a simple GDI printer) */
#include "gdevpcl.h"

/*
 * You may select a default resolution of  150 (for 730), 300, or
 * 600 DPI in the makefile, or an actual resolution on
 * the gs command line.
 *
 * If the preprocessor symbol A4 is defined, the default paper size is
 * the European A4 size; otherwise it is the U.S. letter size (8.5"x11").
 *
 * You may find the following test page useful in determining the exact
 * margin settings on your printer.  It prints four big arrows which
 * point exactly to the for corners of an A4 sized paper. Of course the
 * arrows cannot appear in full on the paper, and they are truncated by
 * the margins. The margins measured on the testpage must match those
 * in gdevdjet.c.  So the testpage indicates two facts: 1) the page is
 * not printed in the right position 2) the page is truncated too much
 * because the margins are wrong. Setting wrong margins in gdevdjet.c
 * will also move the page, so both facts should be matched with the
 * real world.

%!
        newpath
        0 0 moveto 144 72 lineto 72 144 lineto
        closepath fill stroke 0 0 moveto 144 144 lineto stroke

        595.27 841.88 moveto 451.27 769.88 lineto 523.27 697.88 lineto
        closepath fill stroke 595.27 841.88 moveto 451.27 697.88 lineto stroke

        0 841.88 moveto 144 769.88 lineto 72 697.88 lineto
        closepath fill stroke 0 841.88 moveto 144 697.88 lineto stroke

        595.27 0 moveto 451.27 72 lineto 523.27 144 lineto
        closepath fill stroke 595.27 0 moveto 451.27 144 lineto stroke

        /Helvetica findfont
        14 scalefont setfont
        100 600 moveto
        (This is an A4 testpage. The arrows should point exactly to the) show
        100 580 moveto
        (corners and the margins should match those given in gdev*.c) show
        showpage

 */

#define USE_POSSIBLY_FLAWED_COMPRESSION 1

/* Type definitions */
typedef struct {
  short width;                /* physical width of the paper */
  short height;               /* physical height of the paper */
}                 PaperFormat; /* Rep. of the charateristics of a sheet of paper */

typedef unsigned char Byte; /* Rep. of elementary data unit */

/*
 * Definition of a Helper structure to handle a list of commands
 */
typedef struct {
  Byte * data;
  short maxSize;
  short current;

} ByteList;

/*
 * Type for representing a summary of the previous lines
 *
 */

typedef struct {
  short  previousSize;
  Byte*  previousData;
  short  nbBlankLines;
  short  nbLinesSent;
  short  pageWidth;
  short  pageHeight;
  short  horizontalOffset;
  short  resolution;
} Summary;

/* Constants */

/* We need a boolean : true , we got it from gdevprn.h */

/* Other constants */
static const int DumpFinished = 0;
static const int DumpContinue = 1;
static const int HL7X0_LENGTH = 5; /* Length of a command to tell the size of the data to be sent to the printer*/
static void  makeCommandsForSequence(Byte     * pSource,
                                      short      length,
                                      ByteList * pCommandList,
                                      short      offset,
                                      Byte     * pCommandCount,
                                      short      rest);

/* Auxiliary Functions */

static int dumpPage(gx_device_printer * pSource,
                      Byte              * pLineTmp,
                      ByteList          * pCommandList,
                      Summary           * pSummary
                      );
static int initSummary(gx_device_printer* pdev, Summary * s,short pw, short ph, short resolution);

static void freeSummary(gx_device_printer* pdev, Summary * s);

static void resetPreviousData(Summary * s);

static void makeFullLine( Byte      * pCurrentLine,
                           Byte      * pPreviousLine,
                           short       lineWidth,
                           ByteList  * commandsList,
                           short       horizontalOffset
                           );

/*
 * Initialize a list of Bytes structure
 */
static void initByteList(ByteList *list, Byte *array, short maxSize,short initCurrent);
static void addByte(ByteList *list,Byte value );
static void addArray(ByteList *list, Byte *source, short nb);
static void addNBytes(ByteList * list, Byte value, short nb);
static Byte * currentPosition(ByteList * list);
static void addCodedNumber(ByteList * list, short number);
static int isThereEnoughRoom(ByteList * list, short biggest);
static short roomLeft(ByteList * list);
static void dumpToPrinter(ByteList * list,gp_file * printStream);

/* Real Print function */

static int hl7x0_print_page(gx_device_printer *, gp_file *, int, int, ByteList *);

/* Define the default, maximum resolutions. */
#ifdef X_DPI
#  define X_DPI2 X_DPI
#else
#  define X_DPI 300
#  define X_DPI2 600
#endif
#ifdef Y_DPI
#  define Y_DPI2 Y_DPI
#else
#  define Y_DPI 300
#  define Y_DPI2 600
#endif

#define LETTER_WIDTH 5100
#define LEFT_MARGIN  30
/* The following table is not actually used.... */
#if 0
static const PaperFormat tableOfFormats[] = {
    /*  0 P LETTER */ { 2550, 3300 },
    /*  1 P LEGAL  */ { 2550, 4200 },
    /*  2 P EXEC   */ { 2175, 3150 },
    /*  3 P A4(78) */ { 2480, 3507 },
    /*  4 P B5     */ { 2078, 2953 },
    /*  5 P A5     */ { 1754, 2480 },
    /*  6 P MONARC */ { 1162, 2250 },
    /*  7 P COM10  */ { 1237, 2850 },
    /*  8 P DL     */ { 1299, 2598 },
    /*  9 P C5     */ { 1913, 2704 },
    /* 10 P A4Long */ { 2480, 4783 },

    /* 11 L LETTER */ { 3300, 2550 },
    /* 12 L LEGAL  */ { 4200, 2550 },
    /* 13 L EXEC   */ { 3150, 2175 },
    /* 14 L A4     */ { 3507, 2480 },
    /* 15 L B5     */ { 2952, 2078 },
    /* 16 L A5     */ { 2480, 1754 },
    /* 17 L MONARC */ { 2250, 1162 },
    /* 18 L COM10  */ { 2850, 1237 },
    /* 19 L DL     */ { 2598, 1299 },
    /* 20 L C5     */ { 2704, 1913 },
    /* 21 L A4Long */ { 4783, 2480 }
};
#endif

/* Compute the maximum length of a compressed line */
static short MaxLineLength(short resolution){
return (((156 * resolution / 150 ) * 5 )/4) + 8;
}

/* Margins are left, bottom, right, top. */
/* Quotation from original gdevdjet.c */
/* from Frans van Hoesel hoesel@rugr86.rug.nl.  */
/* A4 has a left margin of 1/8 inch and at a printing width of
 * 8 inch this give a right margin of 0.143. The 0.09 top margin is
 * not the actual margin - which is 0.07 - but compensates for the
 * inexact paperlength which is set to 117 10ths.
 * Somebody should check for letter sized paper. I left it at 0.07".
 */

/* The A4 margins are almost good */
/* The one for Letter are those of the gdevdjet.c file... */
#define HL7X0_MARGINS_A4	0.1, 0.15, 0.07, 0.05
#define HL7X0_MARGINS_LETTER 0.275, 0.20, 0.25, 0.07

/* We round up the LINE_SIZE to a multiple of a ulong for faster scanning. */
#define W sizeof(word)

/* Printer types */

#define HL720    0
#define HL730    0 /* No difference */

/* The device descriptors */
static dev_proc_open_device(hl7x0_open);
static dev_proc_close_device(hl7x0_close);
static dev_proc_print_page(hl720_print_page);

/* Since the print_page doesn't alter the device, this device can print in the background */
static const gx_device_procs prn_hl_procs =
  prn_params_procs(hl7x0_open, gdev_prn_bg_output_page, hl7x0_close,
                   gdev_prn_get_params, gdev_prn_put_params);

const gx_device_printer far_data gs_hl7x0_device =
  prn_device(prn_hl_procs, "hl7x0",
        DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
        X_DPI, Y_DPI,
        0, 0, 0, 0,		/* margins filled in by hl7x0_open */
        1, hl720_print_page); /* The hl720 and hl730 can both use the same print method */

/* Open the printer, adjusting the margins if necessary. */

static int
hl7x0_open(gx_device *pdev)
{	/* Change the margins if necessary. */
        static const float m_a4[4] = { HL7X0_MARGINS_A4 };
        static const float m_letter[4] = { HL7X0_MARGINS_LETTER };
        const float *m =
          (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? m_a4 : m_letter);

        gx_device_set_margins(pdev, m, true);
        return gdev_prn_open(pdev);
}

/* The orders sent are those provided in the Brother DOS example */
static int
hl7x0_close(gx_device *pdev)
{
    gx_device_printer *const ppdev = (gx_device_printer *)pdev;
    int code = gdev_prn_open_printer(pdev, 1);

    if (code < 0)
        return code;
    gp_fputs("@N@N@N@N@X", ppdev->file) ;
    return gdev_prn_close_printer(pdev);
}

/* ------ Internal routines ------ */

/* The HL 720 can compress*/
static int
hl720_print_page(gx_device_printer *pdev, gp_file *prn_stream)
{
        Byte prefix[] ={
   0x1B,'%','-','1','2','3','4','5','X'
  ,'@','P','J','L',0x0A                         /* set PJL mode */
  ,'@','P','J','L',' ','E','N','T','E','R',' '
  ,'L','A','N','G','U','A','G','E'
  ,' ','=',' ','H','B','P',0x0A                 /* set GDI Printer mode */
  ,'@','L', 0x0
   };
        ByteList initCommand;
        int x_dpi = pdev->x_pixels_per_inch;
        initByteList(&initCommand,
                     prefix,         /* Array */
                     sizeof(prefix), /* Total size */
                     sizeof(prefix) - 1); /* Leave one byte free since*/
        /* we need to add the following order at the end */
        addByte(&initCommand, (Byte) ((((600/x_dpi) >> 1) \
                                                  | (((600/x_dpi) >> 1) << 2))));
        /* Put the value of the used resolution into the init string */

        return hl7x0_print_page(pdev, prn_stream, HL720, 300,
               &initCommand);
}

/* Send the page to the printer.  For speed, compress each scan line, */
/* since computer-to-printer communication time is often a bottleneck. */
static int
hl7x0_print_page(gx_device_printer *pdev, gp_file *printStream, int ptype,
  int dots_per_inch, ByteList *initCommand)
{
  int code;
        /* UTILE*/
  /* Command for a formFeed (we can't use strings because of the zeroes...)*/
  Byte FormFeed[] = {'@','G',0x00,0x00,0x01,0xFF,'@','F'};
  ByteList formFeedCommand;
  /* Main characteristics of the page */
  int line_size       = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
  int x_dpi = pdev->x_pixels_per_inch;
  /*  int y_dpi = pdev->y_pixels_per_inch; */
  int num_rows = dev_print_scan_lines(pdev);
  int result;
  int sizeOfBuffer   = MaxLineLength(x_dpi) + 30;
  Byte * storage      = (Byte *) gs_malloc(pdev->memory,
                                           sizeOfBuffer + line_size,
                                           1,
                                           "hl7x0_print_page");
        /*	bool dup = pdev->Duplex; */
        /* bool dupset = pdev->Duplex_set >= 0; */
        Summary pageSummary;
        ByteList commandsBuffer;
        if ( storage == 0 )	/* can't allocate working area */
                return_error(gs_error_VMerror);
        code = initSummary(pdev,
                    &pageSummary,
                    line_size,
                    num_rows,
                    x_dpi);
        if (code < 0) {
            gs_free(pdev->memory, (char *)storage, storage_size_words, 1, "hl7X0_print_page");
            return code;
        }
        initByteList(&commandsBuffer, storage, sizeOfBuffer,0 );
        /* PLUS A MOI */
        if ( pdev->PageCount == 0 )
          {
            /* Put out init string before first page. */
            dumpToPrinter(initCommand, printStream);		/* send init to printer */

        }

        do {
          result = dumpPage(pdev,
                            storage + sizeOfBuffer, /* The line buffer is after the dump buffer */
                            &commandsBuffer,
                            &pageSummary);
            if (result < 0)
                goto xit;
          dumpToPrinter(&commandsBuffer,printStream);

        } while (result == DumpContinue);	/* NB: at end  of page, result will be DumpFinished == 0 */

        /* end raster graphics and eject page */
        initByteList(&formFeedCommand,
                     FormFeed,          /* Array */
                     sizeof(FormFeed),  /* Size in bytes */
                     sizeof(FormFeed)); /* First free byte */
        dumpToPrinter(&formFeedCommand, printStream);

xit:
        /* free temporary storage */
        freeSummary(pdev, &pageSummary);
        gs_free(pdev->memory, (char *)storage, storage_size_words, 1, "hl7X0_print_page");

        return result; /* If we reach this line, it means there was no error */
}

/*
 * Useful auxiliary declarations
 *
 */

static short stripTrailingBlanks(Byte * line, short length){
  short positionOfFirstZero = length - 1;
  while (positionOfFirstZero > 0) {
    if (line[positionOfFirstZero] != 0) {
      return positionOfFirstZero + 1;
    }
    positionOfFirstZero -- ;
  }
  return 0;
}

/*
 * Changed the horizontalOffset function 1/17/00 Ross Martin.
 * ross@ross.interwrx.com or martin@walnut.eas.asu.edu
 *
 * The equation used to muliply pixWidth by resolution/600
 * also.  This didn't work right at resolution 300; it caused
 * landscape pages produced by a2ps to be half off the
 * page, when they were not at 600dpi or on other
 * devices.  I'm not sure the equation below is exactly
 * correct, but it now looks to be pretty close visually,
 * and works correctly at 600dpi and 300dpi.
 */
static short horizontalOffset(short pixWidth,
                              short pixOffset,
                              short resolution){
return (((LETTER_WIDTH * resolution/600 - pixWidth) + pixOffset * 2) + 7) / 8;

}

/*
 * First values in a Summary
 */
static int initSummary(gx_device_printer* pdev, Summary * s,short pw, short ph, short resolution){
  s->previousSize = -1 ;
  s->previousData = gs_malloc(pdev->memory, pw, 1, "initSummary");
  s->nbBlankLines = 1;
  s->nbLinesSent = 0;
  s->pageWidth = pw; /* In Bytes */
  s->pageHeight = ph;
  s->horizontalOffset = horizontalOffset( pw * 8,LEFT_MARGIN, resolution) ;
  s->resolution = resolution;
  if (!s->previousData) {
    return_error(gs_error_VMerror);
  }
  return 0;
}

static void freeSummary(gx_device_printer* pdev, Summary * s) {
  gs_free(pdev->memory, s->previousData, s->pageWidth, 1, "freeSummary");
}

/*
 * The previous line was blank, so we need to clean the corresponding array
 */
static void resetPreviousData(Summary * s){
 memset(s->previousData,0,s->pageWidth);
}

/*
 * dumpPage :
 *
 */
static int dumpPage(gx_device_printer * pSource,
                      Byte              * pLineTmp,
                      ByteList          * pCommandList,
                      Summary           * pSummary
                      ){

  /* Declarations */
  Byte * pSaveCommandStart;
  short  lineNB;
  short usefulLength;
  short tmpLength;
  int code = 0;

  /* Initializations */
  /* Make room for size of commands buffer */
  pSaveCommandStart = currentPosition(pCommandList);
  addNBytes(pCommandList,0,HL7X0_LENGTH);
  /* pSource += pSummary->nbLinesSent * pSummary->pageWidth;*/
  /* Process all possible Lines */
  for (lineNB = pSummary->nbLinesSent /*ERROR? + nbBlankLines */ ;
       lineNB < pSummary->pageHeight ; lineNB ++ ) {
    /* Fetch the line and put it into the buffer */
    code = gdev_prn_copy_scan_lines(pSource,
                             lineNB,
                             pLineTmp,
                             pSummary->pageWidth);
    if (code < 0)
        return code;

    usefulLength =  stripTrailingBlanks(pLineTmp,pSummary->pageWidth);
    if (usefulLength != 0) {

      /* The line is not blank */
      /* Get rid of the precedent blank lines */
      if (pSummary->nbBlankLines != 0) {
        if ( isThereEnoughRoom( pCommandList, pSummary->nbBlankLines )   ) {

          addNBytes(pCommandList,0xff,pSummary->nbBlankLines);
          pSummary->nbBlankLines = 0;

        }
        else {

          short availableRoom = roomLeft(pCommandList);
          addNBytes(pCommandList,0xff,availableRoom);
          pSummary->nbBlankLines -= availableRoom;

          break ; /* We have no more room */

        }

        resetPreviousData(pSummary); /* Make sure there are zeroes for the previous line */
        pSummary->previousSize = 0; /* The previous line was empty */

      }

      /* Deal with the current line */
      if (!isThereEnoughRoom(pCommandList,MaxLineLength(pSummary->resolution))){
        break; /* We can process this line */
      }

      if (pSummary->previousSize > usefulLength){
        tmpLength = pSummary->previousSize;
      }
      else {
        tmpLength = usefulLength;
      }

      if (pSummary->previousSize == -1 ) {/* This is the first line */

        Byte *save = currentPosition(pCommandList);
        addByte(pCommandList,0); /* One byte for the number of commands */

        makeCommandsForSequence(pLineTmp,
                                tmpLength,
                                pCommandList,
                                pSummary->horizontalOffset,
                                save,
                                0);
      }
      else { /*There is a previous line */

        makeFullLine(pLineTmp,
                     pSummary->previousData,
                     tmpLength,
                     pCommandList,
                     pSummary->horizontalOffset);
      }
      /* The present line will soon be considered as "previous" */
      pSummary->previousSize = tmpLength;
      /* Update the data representing the line will soon be the "previous line" */
      memcpy(pSummary->previousData,pLineTmp,tmpLength);

    }
    else { /* the current line is blank */
      pSummary->nbBlankLines++;
    }

  /* And one more line */
    pSummary->nbLinesSent ++;
  }

  if (pCommandList->current > HL7X0_LENGTH){
    short size = pCommandList->current - HL7X0_LENGTH;
    *(pSaveCommandStart++)  = '@';
    *(pSaveCommandStart++)  = 'G';
    *(pSaveCommandStart++)  = 0;                    /* was: (Byte) (size >> 16) as per hte spec, but shorts cannot exceed 16 bits! */
    *(pSaveCommandStart++)  = (Byte) (size >> 8);
    *(pSaveCommandStart++)  = (Byte) (size);
  }
  else {  /* We only met blank lines and reached the end of the page */
    pCommandList->current = 0;
  }
  if (lineNB == pSummary->pageHeight){
    return DumpFinished;
  }
  else {
    return DumpContinue;
  }
}

/*
 *  makeFullLine :
 *  process an arbitrary line for which a former line is available
 *  The line will be split in sequences that are different from the
 * corresponding ones of the previous line. These sequences will be processed
 * by makeCommandsOfSequence.
 */

static void makeFullLine( Byte      * pCurrentLine,
                           Byte      * pPreviousLine,
                           short       lineWidth,
                           ByteList  * commandsList,
                           short       horizontalOffset
                           ){
  /* Declarations */
  Byte *pPreviousTmp;
  Byte *pCurrentTmp;
  Byte *pNumberOfCommands;
  int loopCounter;
  short remainingWidth;
  Byte *pStartOfSequence;
  /*****************/
  /* Special cases */
  /*****************/

  /* I believe this situation to be impossible */
  if (lineWidth <= 0) {
    addByte(commandsList,0xff);
    return;
  }

  /*******************/
  /* Initializations */
  /*******************/

  pNumberOfCommands = currentPosition(commandsList); /* Keep a pointer to the number of commands */
  addByte(commandsList,0); /* At the moment there are 0 commands */

  pPreviousTmp = pPreviousLine;
  pCurrentTmp = pCurrentLine;

  /* Build vector of differences with a Xor */

  for (loopCounter = lineWidth ;  0 < loopCounter ; loopCounter -- )
    *pPreviousTmp++ ^= *pCurrentTmp++;

  /* Find sequences that are different from the corresponding (i.e. vertically aligned)
   * one of the previous line. Make commands for them.
   */

  pStartOfSequence = pPreviousLine;
  remainingWidth = lineWidth;

  while (true) {

    /*
     * Disabled line-to-line compression, 1/17/00 Ross Martin
     * ross@ross.interwrx.com and/or martin@walnut.eas.asu.edu
     *
     * The compression here causes problems printing tiger.eps.
     * The problem is vertical streaks.  The printer I'm printing
     * to is a Brother MFC6550MC Fax Machine, which may be
     * slightly different from the hl720 and hl730.  Note that
     * this fax machine does support HP LaserJet 2p emulation,
     * but in order to enable it I believe one needs special
     * setup from a DOS program included with the printer.  Thus,
     * the hl7x0 driver seems a better choice.  In any case,
     * on the MFC6550MC, some files print fine with compression
     * turned on, but others such as tiger.eps print with streaks.
     * disabling the compression fixes the problem, so I haven't
     * looked any further at the cause.  It may be that the
     * compression is correct for the hl720 and hl730, and only
     * different for the MFC6550MC, or it may be that tiger.eps
     * won't print correctly with compression enabled on any
     * of these.  It may be that the problem is only with color
     * and/or grayscale prints.  YMMV.  I don't think it likely
     * that turning off compression will cause problems with
     * other printers, except that they may possibly print slower.
     */

#ifdef USE_POSSIBLY_FLAWED_COMPRESSION
    /* Count and skip bytes that are not "new" */
    while (true) {
      if (remainingWidth == 0)  /* There is nothing left to do */
        {
          return;
        }
      if (*pStartOfSequence != 0)
        break;
      pStartOfSequence ++;
      horizontalOffset ++; /* the offset takes count of the bytes that are not "new" */
      --remainingWidth;
    }
#endif

    pPreviousTmp = pStartOfSequence + 1; /* The sequence contains at least this byte */
    --remainingWidth;

    /* Find the end of the sequence of "new" bytes */

#ifdef USE_POSSIBLY_FLAWED_COMPRESSION
    while (remainingWidth != 0 && *pPreviousTmp != 0) {
      ++pPreviousTmp; /* Enlarge the sequence Of new bytes */
      --remainingWidth;
    }
#else
   pPreviousTmp += remainingWidth;
   remainingWidth = 0;
#endif

    makeCommandsForSequence(pCurrentLine + (pStartOfSequence - pPreviousLine),
                             pPreviousTmp - pStartOfSequence,
                             commandsList,
                             horizontalOffset,
                             pNumberOfCommands,
                             remainingWidth);
    if (*pNumberOfCommands == 0xfe   /* If the number of commands has reached the maximum value */
        ||                           /* or */
        remainingWidth == 0 )        /* There is nothing left to process */
    {
      return;
    }

    pStartOfSequence = pPreviousTmp + 1; /* We go on right after the sequence of "new" bytes */
    horizontalOffset = 1;
    --remainingWidth;
  } /* End of While */

} /* End of makeFullLine */

/*
 *  Declarations of functions that are defined further in the file
 */
static void makeSequenceWithoutRepeat(
                                  Byte     * pSequence,
                                  short      lengthOfSequence,
                                  ByteList * pCommandList,
                                  short      offset             );

static void makeSequenceWithRepeat(
                                  Byte     * pSequence,
                                  short      lengthOfSequence,
                                  ByteList * pCommandList,
                                  short      offset             );

/*
 * makeCommandsForSequence :
 * Process a sequence of new bytes (i.e. different from the ones on the former line)
 */

static void makeCommandsForSequence(Byte     * pSource,
                                     short      length,
                                     ByteList * pCommandList,
                                     short      offset,
                                     Byte     * pNumberOfCommands,
                                     short      rest)         {
  /* Declarations */
  Byte * pStartOfSequence;
  Byte * pEndOfSequence;
  short  remainingLength = length - 1;

  pStartOfSequence = pSource;
  pEndOfSequence = pStartOfSequence + 1;
  /*
   * Process the whole "new" Sequence that is divided into
   * repetitive and non-repetitive sequences.
   */
  while (true) {

    /* If we have already stored too many commands, make one last command with
     * everything that is left in the line and return.
     */
    if (*pNumberOfCommands == 0xfd) {
      makeSequenceWithoutRepeat(pStartOfSequence,
                        1 + remainingLength + rest,
                        pCommandList,
                        offset);
      ++*pNumberOfCommands;
      return;
    }

    /* Start with a sub-sequence without byte-repetition */
    while (true) {
      /* If we have completed the last subsequence */
      if (remainingLength == 0) {
        makeSequenceWithoutRepeat(pStartOfSequence,
                     pEndOfSequence - pStartOfSequence,
                     pCommandList,
                     offset);
        ++*pNumberOfCommands;
        return;
      }
      /* If we have discovered a repetition */
      if (*pEndOfSequence == *(pEndOfSequence - 1)) {
        break;
      }
      ++ pEndOfSequence; /* The subsequence is bigger*/
      --remainingLength;
    }
    /* If this is a sequence without repetition */
    if (pStartOfSequence != pEndOfSequence - 1) {
      makeSequenceWithoutRepeat(pStartOfSequence,
                                (pEndOfSequence - 1) - pStartOfSequence,
                                pCommandList,
                                offset);
      ++*pNumberOfCommands;
      offset = 0;
      pStartOfSequence = pEndOfSequence - 1;

      /* If we have too many commands */
      if (*pNumberOfCommands == 0xfd) {
        makeSequenceWithoutRepeat(pStartOfSequence,
                                  1 + remainingLength + rest,
                                  pCommandList,
                                  offset);
        ++*pNumberOfCommands;
        return;
      }
    } /* End If */

    /*
     * Process a subsequence that repeats the same byte
     */
    while (true) {
      /* If there is nothing left to process */
      if (remainingLength == 0) {
        makeSequenceWithRepeat(pStartOfSequence,
                               pEndOfSequence - pStartOfSequence,
                               pCommandList,
                               offset);
        ++*pNumberOfCommands;
        return;
      }
      /* If we find a different byte */
      if (*pEndOfSequence != *pStartOfSequence){
        break;
      }
      ++pEndOfSequence; /* The subsequence is yet bigger */
      --remainingLength;
    } /* End of While */
      makeSequenceWithRepeat(pStartOfSequence,
                             pEndOfSequence - pStartOfSequence,
                             pCommandList,
                             offset);
      ++*pNumberOfCommands;
      offset = 0;   /* The relative offset between two subsequences is 0 */
      pStartOfSequence = pEndOfSequence ++ ; /* we loop again from the end of this subsequence */
      --remainingLength;

  } /* End of While */

} /* End makeCommandsForSequence */

/*
 * makeSequenceWithoutRepeat
 */
static void makeSequenceWithoutRepeat(
                                  Byte     * pSequence,
                                  short      lengthOfSequence,
                                  ByteList * pCommandList,
                                  short      offset             ){
  /*
   *   Constant definitions
   */
  static const short MAX_OFFSET         = 15;
  static const short POSITION_OF_OFFSET = 3;
  static const short MAX_LENGTH         =  7;

  Byte tmpFirstByte = 0;
  Byte * pSaveFirstByte;
  short reducedLength = lengthOfSequence - 1; /* Length is alway higher than 1
                                                 Therefore a reduced value is stored
                                                 */
  /* Initialization */

  pSaveFirstByte = currentPosition(pCommandList);
  addByte( pCommandList, 0 /* Dummy value */);

  /* Computations */

  if (offset >= MAX_OFFSET) {
    addCodedNumber(pCommandList,offset - MAX_OFFSET);
    tmpFirstByte |= MAX_OFFSET << POSITION_OF_OFFSET;
  }
  else
    tmpFirstByte |= offset << POSITION_OF_OFFSET;

  if (reducedLength >= MAX_LENGTH) {
    addCodedNumber(pCommandList,reducedLength - MAX_LENGTH);
    tmpFirstByte |= MAX_LENGTH ;
  }
  else
    tmpFirstByte |= reducedLength ;
  /* Add a copy of the source sequence */

  addArray(pCommandList, pSequence, lengthOfSequence);

  /* Store the computed value of the first byte */

  *pSaveFirstByte = tmpFirstByte;

  return ;
} /* End of makeSequenceWithoutRepeat */

/*
 * makeSequenceWithRepeat
 */
static void makeSequenceWithRepeat(
                                  Byte     * pSequence,
                                  short      lengthOfSequence,
                                  ByteList * pCommandList,
                                  short      offset             ){
  /*
   *   Constant definitions
   */
  static const short MAX_OFFSET         = 3;
  static const short POSITION_OF_OFFSET = 5;
  static const short MAX_LENGTH         =  31;

  Byte tmpFirstByte = 0x80;
  Byte * pSaveFirstByte;
  short reducedLength = lengthOfSequence - 2; /* Length is always higher than 2
                                                 Therefore a reduced value is stored
                                                 */
  /* Initialization */

  pSaveFirstByte = currentPosition(pCommandList);
  addByte( pCommandList, 0 /* Dummy value */);

  /* Computations */

  if (offset >= MAX_OFFSET) {
    addCodedNumber(pCommandList, offset - MAX_OFFSET);
    tmpFirstByte |= MAX_OFFSET << POSITION_OF_OFFSET;
  }
  else
    tmpFirstByte |= offset << POSITION_OF_OFFSET;

  if (reducedLength >= MAX_LENGTH) {
    addCodedNumber(pCommandList,reducedLength - MAX_LENGTH);
    tmpFirstByte |= MAX_LENGTH ;
  }
  else
    tmpFirstByte |= reducedLength ;
  /* Add a copy the byte that is repeated throughout the sequence */

  addByte(pCommandList, *pSequence );

  /* Store the computed value of the first byte */

  *pSaveFirstByte = tmpFirstByte;

  return ;
} /* End of makeSequenceWithRepeat*/

/*
 * Initialize a list of Bytes structure
 */
static void initByteList(ByteList *list, Byte *array, short maxSize, short initCurrent) {
  list->current = initCurrent;
  list->maxSize = maxSize;
  list->data = array;
}

/*
 * Add a Byte to a list of Bytes
 */
static void addByte(ByteList *list,Byte value ) {
 if (list->current < list->maxSize)
  list->data[list->current++] = value;
 else
   eprintf("Could not add byte to command\n");
}

/*
 * Add a copy of an array to a list of Bytes
 */

static void addArray(ByteList *list, Byte *source, short nb){
  if (list->current <= list->maxSize - nb)
  {
    memcpy(list->data + list->current, source , (size_t) nb);
    list->current += nb;
  }
  else
    eprintf("Could not add byte array to command\n");
}

/*
 * Add N bytes to a list of Bytes
 */

static void addNBytes(ByteList * list, Byte value, short nb){
  int i;
  if (list->current <= list->maxSize - nb)
  {
    for (i = list->current ; i < (list->current + nb) ; i++)
      {
        list->data[i] = value;
      }
    list->current += nb;
  }
  else
    eprintf1("Could not add %d bytes to command\n",nb);
}

/*
 * Get pointer to the current byte
 */
static Byte * currentPosition(ByteList * list) {
  return &(list->data[list->current]);
}

/*
 * add a number coded in the following way :
 * q bytes with 0xff value
 * 1 byte with r value
 * where q is the quotient of the number divided by 0xff and r is the
 * remainder.
 */
static void addCodedNumber(ByteList * list, short number){
 short q = number / 0xff;
 short r = number % 0xff;

 addNBytes(list, 0xff, q);
 addByte(list,r);

}

/*
 * See if there is enough room for a set of commands of size biggest
 *
 */

static int isThereEnoughRoom(ByteList * list, short biggest){
  return ((list->maxSize-list->current) >= biggest);
}
/*
 * Tell how much room is left
 */
static short roomLeft(ByteList * list){
  return list->maxSize - list->current;
}
/*
 * Dump all commands to the printer and reset the structure
 *
 */
static void dumpToPrinter(ByteList * list,gp_file * printStream){
  short loopCounter;
  /* Actual dump */
  /* Please note that current is the first empty byte */
  for (loopCounter = 0; loopCounter < list->current; loopCounter++)
    {
      gp_fputc(list->data[loopCounter],printStream);
    }

  /* Reset of the ByteList */
  list->current = 0;
}