Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
 
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
 
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 */
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 
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 
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
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
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 
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
 
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
 */
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
 */ 
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
 */
465
private void resetPreviousData(Summary * s){
466
 memset(s->previousData,0,s->pageWidth);
467
}
468
 
469
 
470
/*
471
 * dumpPage :
472
 *
473
 */
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
 
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
 
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
 */
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
 */
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
 */
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
 */
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
 
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
 
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
 */
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
 */
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
 
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
 */
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
 */
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
}