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