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