forked from Godzil/lpstyl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lpstyl.c
2090 lines (1800 loc) · 47.3 KB
/
lpstyl.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
lpstyl.c
version 0.9.9
Copyright (C) 1996-2000 Monroe Williams ([email protected])
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----
This is a printer driver for Apple StyleWriter printers. Here is the
known status of printers it supports:
- Color Stylewriter 2500:
Fully supported in 360x360dpi, B/W and Color.
- Color Stylewriter 2400:
Fully supported in 360x360dpi, B/W and Color.
- Color Stylewriter 2200:
Supposed to work as of 0.9.9 (I haven't seen it, though.)
- Color Stylewriter 1500:
Works in B/W and Color.
- StyleWriter III, StyleWriter 1200:
"Works peachy." -- Charles Broderick, [email protected]
- StyleWriter II:
Reported to work quite well.
- StyleWriter I:
Working again as of version 0.9.7.
- Other stylewriters?:
Give it a try. The code will treat any printer it doesn't
recognize like a SWII, so it just might work. (That's how
the SW2400 first worked, anyway.)
Future releases of this driver will have more documentation, including
some explanation of the control codes I have figured out. Stay tuned.
Any feedback should be directed to [email protected].
*/
/* Version history:
0.9.9:
- Fixed a problem with identifying the StyleWriter 2400 and 2500.
- Added changes from Paulo Abreu <[email protected]>
to support the StyleWriter 2200.
- Initial support for the Apple StyleWriter Ethertalk Adapter
(Apple part number M4877). This is a box which connects a
number of different models of StyleWriter directly to an
Ethernet network. This requires netatalk support on the
machine you're compiling on. It also required an
implementation of a subset of the ADSP protocol for the
Appletalk stack, which is in the file adsp.c. This device
looks very similar to the "Farallon EtherMac iPrint Adapter SL",
(it performs the same function and appears to use the same plastics),
and I'd like to find out if the Farallon device works the same.
0.9.8:
- Added changes from Takashi Oe <[email protected]> to
support the StyleWriter 1500.
- Made the code's entire concept of paper sizes and margins much
less confused.
- Added A4 paper support. (Finally.)
- Added a mechanism for specifying arbitrary paper sizes on
the command line. -W and -H (yes, capital letters) specify
the width and height of the paper in _pixels_. One pixel is
1/360 of an inch. In the normal case, these numbers should
match the dimensions of the input file. No validity checking
is done on the paper sizes thus received, and I'm sure one could
make things go rather badly by entering wildly inaccurate numbers.
Be nice.
- Improved out-of-paper handling. The code for all printer
types should now handle out-of-paper conditions by retrying.
0.9.7:
- Finally got hold of a StyleWriter I.
It didn't work.
It does now.
0.9.6:
- Incorporated new information about control codes from
Paul Mackerras <[email protected]> to make the
StyleWriter 2500 work.
- Improved out-of-paper handling on 2400/2500. (Instead of
retransmitting data, we now use another control code to make
the printer try again.) Thanks to Paul Mackerras for coming
up with the right control code.
- The driver is now aware of whether a color ink cartridge is
installed in the 2400/2500.
0.9.5:
- Finally, really fixed the finish-page code to wait for the
right thing. (Hooray for trial and error...)
- Figured out how long a microsecond was (duh...) and fixed the
various retry-loops to sleep for 0.1 second like I originally
intended.
- Now deals with the printer running out of paper by retrying
every 30 seconds until the problem goes away (or someone
puts a stop to it).
- No longer reset before every page. It's unnecessary. Now we
reset before the first page of the job, and after printing
is unpaused with SIGUSR1.
0.9.4:
- Now recognizes the SW1200/SW3, courtesy of Charles Broderick
- Uses non-blocking I/O to read from the printer.
0.9.3:
- Less confusing comments about the default margins.
- Now checks for what I think are error codes from the printer
and terminates on errors.
- Code that gets printer status is now less likely to hang.
- Disabled the expanded vertical print area on the SW2400 until
I can figure out why it's causing errors on some pages.
0.9.2:
- Generalized the printable area and margins constants so that they can
be set to different values after the printer is identified. The
SW2400 case in printerSetup now sets larger print area and smaller
margins to match what the 2400 can do. More printers will be added
as I get their specs.
- Added a flag -m to disable cropping for top and left margins.
Use this flag if you want to see the entire image file.
(Files rendered for a full 8.5"x11" page will be offset down and to
the right from where they should be on the page.)
0.9.1:
- Fixed a problem with waiting for the last part of a page to
print. The problem would cause the next page's reset to
happen too soon, chopping off the last part of the page.
0.9:
- Fully functional COLOR on a Color Stylewriter 2400!!!
- Added signal handlers for common kill signals that eject the
page and reset the printer.
- Two new input formats: 'bit' and 'bitcmyk'.
- Flags, flags, flags. Type 'lpstyl -?' to see usage.
- Now sets up the serial port properly (57600 baud, raw mode)
using termios.
- Uses a larger buffer size on Color StyleWriter 2400.
0.2.0d2:
- Fully functional in B&W on a Color StyleWriter 2400 and a
SWII
0.2.0d1:
- Changed a couple of things to make it work better (but still not
quite right) on a SWII.
- First try at using the printer's buffer more efficiently.
0.2.0d0:
- First attempt at direct StyleWriter II support, with help from
Jack Howarth <[email protected]>. This includes the
first attempt at compensating for what looks like a "scanline
differencing" algorithm the SWII uses, conditional on the
returned printer type.
- Included a modification suggested by Stefan Schmiedl
<[email protected]> -- reducing the maximum
amount of data that will be sent at once from 0x10000
to 0x4000. (Apparently, some more complex files caused
the printer's buffer to overflow.)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#ifdef ATALK
#include <netatalk/at.h>
#include <atalk/nbp.h>
#include "adsp.h"
#endif
/* Just a few prototypes... Yeah, I was raised on ANSI C. So sue me. */
void fixPageSizes(void);
int main(int argc, char **argv);
int printStdin(void);
size_t encodescanline(unsigned char *src, size_t srcLen, unsigned char *dst);
void sendEncodedData(unsigned char *buffer, size_t size);
void sendrect(long top, long left, long bottom, long right);
size_t inputRead(void *buffer, size_t size);
int inputGetc(void);
void inputPutback(int c);
void printerSetup(void);
size_t comm_printer_read(void *buffer, size_t size);
size_t comm_printer_write(void *buffer, size_t size);
size_t comm_printer_writestring(char *buffer);
void comm_printer_writeFFFx(char x);
int comm_printer_getc(void);
int comm_printer_getc_block(void);
void ejectAndReset(void);
void finishPage(void);
void waitNonBusy(int canHandlePaperOut);
void printerFlushInput(void);
void print_error(char *s);
void print_info(char *s);
void waitStatus(int stat, int canHandlePaperOut);
int getStatus(int which);
/***** Some relevant constants *****/
/* NOTE: To change these values on a per-printer basis, add a case
to the "Printer-specific setup" in printerSetup(). Copying
the SW2400 case is a good place to start.
*/
/* size of the printer's buffer */
long MAX_BUFFER = 0x00004000;
/* Default to letter-size paper, which is 8.5 x 11 inches @ 360dpi */
long PAGE_WIDTH = 3060;
long PAGE_HEIGHT = 3960;
long PRINT_WIDTH;
long PRINT_HEIGHT;
long TOP_MARGIN;
long BOTTOM_MARGIN;
long LEFT_MARGIN;
/* number of BYTES of each scanline to leave off the left. (pixels / 8) */
long LEFT_MARGIN_BYTES;
long PRINT_ROWBYTES;
#ifndef nil
#define nil ((void*)0)
#endif
/* Do we really care? */
int verbose = 0;
volatile int paused = 0;
char *ProcName;
void handler();
void cleanup();
void usage(void);
int readFileHeader(void);
size_t readFileScanline(char *bufK, char *bufC, char *bufM, char *bufY);
size_t appendEncode(size_t length, char *in, char *last, char *out);
/* Variables printStdin() needs which can also be set by arguments */
long height = -1, width = -1;
enum
{
FILE_PBMRAW,
FILE_BIT,
FILE_BITCMYK
};
int fileType = FILE_PBMRAW;
int fileIsColor = 0; /* Set to true in readFileHeader if the input
file contains color information. */
int canPrintColor = 0; /* set to true in printerSetup() if a color ink
cartridge is installed. */
int printQuality = 1; /* 0 = draft (not implemented yet), 1 = normal,
2 = high. */
size_t rowbytes;
enum
{
KIND_SW1,
KIND_SW2,
KIND_SW3,
KIND_SW1500,
KIND_SW2200,
KIND_SW2400,
KIND_SW2500,
KIND_SWUNKNOWN
};
int printerType;
int noMargins = 0;
int doReset = 1;
int bufferHelp = 0;
int atalk_connection = 0;
#ifdef ATALK
char *atalk_username = NULL;
struct adsp_socket s1, s2;
struct adsp_endp end1, end2;
int at_printer_open(char *name);
void at_printer_kill(void);
void at_printer_setstatus(char *status);
#endif
long USLEEP_TIME = 100000; /* 0.1 seconds for usleep() */
void fixPageSizes(void)
{
/* This routine assumes that the following are set up before it is called:
(these depend only on the paper size)
PAGE_WIDTH - width of the paper
PAGE_HEIGHT - height of the paper
(these depend only on the capabilities of the printer's hardware)
PRINT_WIDTH - width of the printer's imageable area
LEFT_MARGIN - printer's left margin
TOP_MARGIN - printer's top margin
BOTTOM_MARGIN - printer's bottom margin
All values are in pixels. There are 360 pixels per inch.
*/
/* the height of the printer's imageable area */
PRINT_HEIGHT = PAGE_HEIGHT - (TOP_MARGIN + BOTTOM_MARGIN + 1);
/* The number of imageable bytes in each scanline */
PRINT_ROWBYTES = (PRINT_WIDTH + 7) / 8;
/* The number of bytes to chop off the left of each scanline to make a left margin */
LEFT_MARGIN_BYTES = (LEFT_MARGIN + 7) / 8;
}
int main(int argc, char **argv)
{
int ch;
ProcName = argv[0];
#ifdef ATALK
atalk_username = getlogin();
#endif
/* Enable print pause */
signal(SIGUSR1, handler);
/* Make sure we eject the page if the driver is killed off. */
signal(SIGTERM, cleanup);
signal(SIGHUP, cleanup);
signal(SIGINT, cleanup);
/* Figure out the options */
while((ch = getopt(argc, argv, "a:t:f:h:w:H:W:q:p:u:v?mb")) != -1)
{
switch(ch)
{
case 'f': /* file to open as printer device */
{
int fd;
fd = open(optarg, O_RDWR, 0);
if(fd == -1)
{
perror("open");
exit(1);
}
else
{
dup2(fd, 1);
}
}
break;
case 'a': /* Printer is on an AppleTalk box. */
{
#ifdef ATALK
at_printer_open(optarg);
atalk_connection = 1;
#else
fprintf(stderr, "%s: AppleTalk support not compiled in.\n",
ProcName);
exit(1);
#endif
}
break;
case 'u': /* username for setting status of appletalk printer */
#ifdef ATALK
atalk_username = optarg;
#else
fprintf(stderr, "%s: AppleTalk support not compiled in.\n",
ProcName);
exit(1);
#endif
break;
case 't': /* file format */
if(strcmp(optarg, "pbmraw") == 0)
fileType = FILE_PBMRAW;
else if(strcmp(optarg, "bit") == 0)
fileType = FILE_BIT;
else if(strcmp(optarg, "bitcmyk") == 0)
fileType = FILE_BITCMYK;
else
usage();
break;
case 'p':
if(strcmp(optarg, "letter") == 0)
{
/* Print on U.S. Letter-size paper */
PAGE_WIDTH = 3060; /* 8.5" * 360dpi */
PAGE_HEIGHT = 3960; /* 11" * 360dpi */
}
else if(strcmp(optarg, "a4") == 0)
{
/* Print on A4 paper */
PAGE_WIDTH = 2975; /* about 8.27" * 360dpi */
PAGE_HEIGHT = 4210; /* about 11.69" * 360dpi */
}
else
{
usage();
}
break;
case 'H': /* paper height (in pixels) */
PAGE_HEIGHT = atoi(optarg);
break;
case 'W': /* paper width (in pixels) */
PAGE_WIDTH = atoi(optarg);
break;
case 'h': /* input file height (in pixels) */
height = atoi(optarg);
break;
case 'w': /* input file width (in pixels) */
width = atoi(optarg);
break;
case 'm':
/* don't crop margins */
noMargins = 1;
break;
case 'q': /* print quality (0, 1, or 2) */
printQuality = atoi(optarg);
break;
case 'v':
verbose++;
break;
case 'b':
bufferHelp = 1;
break;
case '?':
default:
usage();
break;
}
}
/* Set up some necessary terminal parameters */
if(!atalk_connection)
{
struct termios t;
tcgetattr(1, &t);
cfmakeraw(&t);
cfsetispeed(&t, B57600);
cfsetospeed(&t, B57600);
if(tcsetattr(1, TCSAFLUSH, &t) == -1)
{
perror("tcsetattr");
exit(1);
}
sleep(1);
}
fprintf(stderr, "%s: printing started, pid = %d.\n", ProcName, getpid());
/* I'd like to do something here so that the driver can be sending data
to the printer and working on the next chunk at the same time.
(On my SE/30, it seems to spend about half of its time doing each.)
Sooner or later, I'll figure out something with pipes or shared
memory or something. Not yet.
*/
if(bufferHelp)
{
#if 0
pipe();
dup2(fd, 1);
#endif
}
/* print some jobs */
while(printStdin() == 0)
{
doReset = 0;
if(paused)
{
fprintf(stderr, "%s: printing paused, you may mess with the printer now.\n", ProcName);
while(paused)
pause();
fprintf(stderr, "%s: printing resumed.\n", ProcName);
/* Reset the printer before the next page. Who knows what
they might have done to the poor thing?
*/
doReset = 1;
}
}
fprintf(stderr, "%s: printing finished, exiting.\n", ProcName);
#ifdef ATALK
if(atalk_connection)
{
at_printer_kill();
}
#endif
return(0);
}
void usage(void)
{
fprintf(stderr, "usage: lpstyl [-v] [-m] [-q printQuality] [-t pbmraw | bit | bitcmyk]\n");
fprintf(stderr, " [-f printer_device] [-p letter | a4]\n");
fprintf(stderr, " [-h inputHeight] [-w inputWidth]\n");
fprintf(stderr, " [-H paperHeight] [-W paperWidth]\n");
exit(1);
}
void handler()
{
paused = !paused;
if(paused)
fprintf(stderr, "%s: got SIGUSR1, printing will pause after the next page.\n", ProcName);
else
fprintf(stderr, "%s: got SIGUSR1, printing will resume at the next opportunity.\n", ProcName);
}
void cleanup()
{
fprintf(stderr, "%s: Caught a signal, resetting printer.\n", ProcName);
#if ATALK
if(atalk_connection)
{
at_printer_kill();
}
else
#endif
{
/* Reset the printer and eject the page. */
ejectAndReset();
}
fprintf(stderr, "%s: printing stopped, exiting.\n", ProcName);
exit(0);
}
int printStdin(void)
{
long lastRow, curRow;
long printwidth, printheight;
unsigned char *bufK, *lastK;
unsigned char *lastMark, *dataBuf, *curMark, *tempMark;
unsigned char *bufC = nil, *bufM = nil, *bufY = nil, *lastC = nil, *lastM = nil, *lastY = nil;
long result;
int retry;
result = readFileHeader();
if(result != 0)
return(result);
if(verbose)
{
fprintf(stderr, "%s: Got a valid header, input image is %dx%d.\n",
ProcName, (int)width, (int)height);
}
/* This may modify margins, etc. */
printerSetup();
/* start on the data */
rowbytes = (width + 7) >> 3;
printwidth = rowbytes - LEFT_MARGIN_BYTES;
if(printwidth > PRINT_ROWBYTES)
printwidth = PRINT_ROWBYTES;
printheight = height;
if(printheight > PRINT_HEIGHT + TOP_MARGIN)
printheight = PRINT_HEIGHT + TOP_MARGIN;
/* this buffer is intentionally too big. */
dataBuf = malloc(MAX_BUFFER * 2);
bufK = malloc(rowbytes + 8);
lastK = malloc(rowbytes + 8);
/* Check for malloc errors */
if((!bufK) || (!lastK) || (!dataBuf))
{
print_error("Couldn't allocate buffers");
return(-1);
}
else
{
print_info("Buffers have been allocated.");
}
if(fileIsColor && canPrintColor)
{
bufC = malloc(rowbytes + 8);
bufM = malloc(rowbytes + 8);
bufY = malloc(rowbytes + 8);
lastC = malloc(rowbytes + 8);
lastM = malloc(rowbytes + 8);
lastY = malloc(rowbytes + 8);
if((!bufC) || (!bufM) || (!bufY) || (!lastC) || (!lastM) || (!lastY))
{
print_error("Couldn't allocate color buffers");
return(-1);
}
else
{
print_info("Color buffers have been allocated.");
}
}
for(curRow = 0;curRow < TOP_MARGIN;curRow++)
{
/* read in a scanline and ignore it */
readFileScanline(nil, nil, nil, nil);
}
print_info("Skipped top margin.");
curMark = lastMark = dataBuf;
lastRow = curRow;
/* Make sure the "previous" line looks blank. */
memset(lastK, 0, rowbytes + 8);
if(lastC)
memset(lastC, 0, rowbytes + 8);
if(lastM)
memset(lastM, 0, rowbytes + 8);
if(lastY)
memset(lastY, 0, rowbytes + 8);
print_info("Encoding data...");
for(;;)
{
if(curRow < height)
{
/* read a scanline */
result = readFileScanline(bufK, bufC, bufM, bufY);
/* check for input problems */
if(result != rowbytes)
{
print_error("Error reading input file or pipe");
/* eject the page and reset the printer */
ejectAndReset();
return(-1);
}
}
else
{
/* fake it */
memset(bufK, 0, rowbytes);
}
curRow++;
/* encode the scanline */
switch(printerType)
{
case KIND_SW1:
/* encode the scanline into the buffer */
curMark += appendEncode(printwidth, bufK + LEFT_MARGIN_BYTES, nil, curMark);
break;
case KIND_SW1500:
case KIND_SW2200:
case KIND_SW2400:
case KIND_SW2500:
if(fileIsColor && canPrintColor)
{
curMark += appendEncode(printwidth, bufC + LEFT_MARGIN_BYTES, lastC + LEFT_MARGIN_BYTES, curMark);
curMark += appendEncode(printwidth, bufM + LEFT_MARGIN_BYTES, lastM + LEFT_MARGIN_BYTES, curMark);
curMark += appendEncode(printwidth, bufY + LEFT_MARGIN_BYTES, lastY + LEFT_MARGIN_BYTES, curMark);
}
/* FALLTHROUGH */
default:
curMark += appendEncode(printwidth, bufK + LEFT_MARGIN_BYTES, lastK + LEFT_MARGIN_BYTES, curMark);
break;
}
/* swap the buffers */
tempMark = lastK; lastK = bufK; bufK = tempMark;
if(fileIsColor && canPrintColor)
{
tempMark = lastC; lastC = bufC; bufC = tempMark;
tempMark = lastM; lastM = bufM; bufM = tempMark;
tempMark = lastY; lastY = bufY; bufY = tempMark;
}
/* if this chunk put us over the buffer limit... */
if((curMark - dataBuf >= MAX_BUFFER) || (curRow >= printheight))
{
if(curMark - dataBuf < MAX_BUFFER)
{
/* This is the last bit. */
lastMark = curMark;
curRow++;
}
/* wait for a not-busy status */
waitNonBusy(0);
do
{
retry = 0;
/* send the last batch of scanlines */
print_info("Ready to send a block of image data...");
sendrect(lastRow - TOP_MARGIN, 0,
(curRow-2) - TOP_MARGIN, PRINT_WIDTH);
sendEncodedData(dataBuf, (lastMark - dataBuf));
print_info("data sent.");
if(lastRow - TOP_MARGIN == 0)
{
/* This is the first part of the page. */
/* Wait long enough to make sure the printer knows if it's out of paper... */
waitNonBusy(1);
if(getStatus('2') == 4)
{
switch(printerType)
{
default:
/* the printer is out of paper. */
print_error("The printer is out of paper -- trying again in 30 seconds...");
ejectAndReset();
retry = 1;
sleep(30);
break;
case KIND_SW1500:
case KIND_SW2200:
case KIND_SW2400:
case KIND_SW2500:
do
{
print_error("The printer is out of paper -- trying to continue in 5 seconds...");
sleep(5);
comm_printer_writeFFFx('S');
}
while(getStatus('2') == 4);
break;
}
}
}
} while(retry);
if(lastMark != curMark)
{
/* Re-encode the last scanline */
print_info("Encoding data...");
curMark = dataBuf;
/* (no differencing) */
switch(printerType)
{
case KIND_SW1500:
case KIND_SW2200:
case KIND_SW2400:
case KIND_SW2500:
if(fileIsColor && canPrintColor)
{
curMark += appendEncode(printwidth, lastC + LEFT_MARGIN_BYTES, nil, curMark);
curMark += appendEncode(printwidth, lastM + LEFT_MARGIN_BYTES, nil, curMark);
curMark += appendEncode(printwidth, lastY + LEFT_MARGIN_BYTES, nil, curMark);
}
/* FALLTHROUGH */
default:
curMark += appendEncode(printwidth, lastK + LEFT_MARGIN_BYTES, nil, curMark);
lastRow = curRow-1;
break;
}
}
else
{
/* we're done with the page */
print_info("Done with page.");
break;
}
}
lastMark = curMark;
}
/* This was adjusted to do the last bit of the page -- adjust it back. */
curRow--;
print_info("Skipping bottom margin.");
/* skip any extra lines in the input file */
for(;curRow < height;curRow++)
{
/* read in a scanline and ignore it */
readFileScanline(nil, nil, nil, nil);
}
print_info("Skipped bottom margin.");
/* wait for a not-busy status */
waitNonBusy(0);
/* finish printing the page */
finishPage();
/* clean up buffers */
free(bufK);
free(dataBuf);
if(bufC) free(bufC);
if(bufM) free(bufM);
if(bufY) free(bufY);
if(lastC) free(lastC);
if(lastM) free(lastM);
if(lastY) free(lastY);
return(0);
}
int readFileHeader(void)
{
int c, i;
char smallBuf[32];
fileIsColor = 0;
switch(fileType)
{
case FILE_PBMRAW:
/* read the file header (including height and width) */
height = -1;
do
{
c = inputGetc();
switch(c)
{
case -1:
/* end of file -- we're done here. Note that this is not an error */
return(1);
break;
case '#':
/* comment line -- skip it */
while((c = inputGetc()) != 0x0A)
;
break;
case ' ': case '\n': case '\t':
/* random whitespace... just ignore it. */
break;
case 'P':
/* magic number */
if((c = inputGetc()) != '4')
{
/* bad magic number */
print_error("Bad magic number in input file");
return(-1);
}
/* there should be one whitespace character */
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
/* read width */
smallBuf[0] = c;
for(i=1;isdigit(c = inputGetc()) && (i < sizeof(smallBuf));i++)
smallBuf[i] = c;
if(!isspace(c))
{
print_error("Bad input file format");
}
smallBuf[i] = 0;
width = atoi(smallBuf);
/* read height */
for(i=0;isdigit(c = inputGetc()) && (i < sizeof(smallBuf));i++)
smallBuf[i] = c;
if(!isspace(c))
{
print_error("Bad input file format");
}
smallBuf[i] = 0;
height = atoi(smallBuf);
break;
default:
print_error("Bad header format in input file");
return(-1);
break;
}
}while(height == -1);
/* the header has been taken care of. The rest of the file is just image data. */
break;
case FILE_BITCMYK:
fileIsColor = 1;
print_info("Input file is in color.");
/* FALLTHROUGH */
case FILE_BIT:
/* These files have no header, but we can make sure we were given
a height and width...
*/
if((height == -1) || (width == -1))
{
fprintf(stderr, "%s: Width and height must be specified for 'bit' and 'bitcmyk' files.\n",
ProcName);
return(-1);
}
c = inputGetc();
if(c == -1)
{
/* We're done. Note that this is not an error. */
return(1);
}
else
{
inputPutback(c);
}
break;
}
return(0);
}
size_t readFileScanline(char *bufK, char *bufC, char *bufM, char *bufY)
{
static char *inputBuf = nil;
static size_t inputSize = 0;
size_t result = 0;
switch(fileType)
{
case FILE_PBMRAW:
case FILE_BIT:
/* These two are the same, after the header. */
if(bufK)
{
result = inputRead(bufK, rowbytes);
}
else
{
/* the black buffer is nil -- read into a dummy buffer. */
if(inputSize < rowbytes)
{
/* reallocate the buffer */
if(inputBuf)
free(inputBuf);
inputBuf = malloc(rowbytes);
inputSize = rowbytes;
}
result = inputRead(inputBuf, rowbytes);
}
break;
case FILE_BITCMYK:
{
size_t filerowbytes = ((width * 4) + 7) >> 3;
if(inputSize < filerowbytes)
{
/* reallocate the buffer */
if(inputBuf)
free(inputBuf);
inputBuf = malloc(filerowbytes);
inputSize = filerowbytes;
}
if(inputRead(inputBuf, filerowbytes) != filerowbytes)
{
result = 0;
return(result);
}
else
{
result = rowbytes;
}
if(!bufK)
{
/* skip the hard part. */
return(result);
}