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
|
% the postscript header we use for our qpsprinter in uncompressed and commented form.
% use the makepsheader perl script to generate a compressed version of this header
% you can then paste into qpsprinter.cpp
%
% some compression of the code is done by the makepsheader script, so we don't need to
% write too criptically here.
/d /def load def
/D {bind d} bind d
/d2 {dup dup} D
/B {0 d2} D
/W {255 d2} D
/ED {exch d} D
/D0 {0 ED} D
/LT {lineto} D
/MT {moveto} D
/S {stroke} D
/F {setfont} D
/SW {setlinewidth} D
/CP {closepath} D
/RL {rlineto} D
/NP {newpath} D
/CM {currentmatrix} D
/SM {setmatrix} D
/TR {translate} D
/SD {setdash} D
/SC {aload pop setrgbcolor} D
/CR {currentfile read pop} D
/i {index} D
/bs {bitshift} D
/scs {setcolorspace} D
/DB {dict dup begin} D
/DE {end d} D
/ie {ifelse} D
/sp {astore pop} D
% ENDUNCOMPRESSED: Warning: leave this line in.
% Everything before this line will be left untouched by the compression
/BSt 0 d % brush style
/LWi 1 d % line width
/PSt 1 d % pen style
/Cx 0 d % current x position
/Cy 0 d % current y position
/WFi false d % winding fill
/OMo false d % opaque mode (not transparent)
/BCol [ 1 1 1 ] d % brush color
/PCol [ 0 0 0 ] d % pen color
/BkCol [ 1 1 1 ] d % background color
/BDArr [ % Brush dense patterns
0.94
0.88
0.63
0.50
0.37
0.12
0.06
] d
/defM matrix d
/nS 0 d % number of saved painter states
% LArr for the Pen styles is defined in emitHeader because of scaling
% GPS: GetPenStyle
% Returns the line pattern (from pen style PSt).
%
% bool GPS pattern
% true : returns draw pattern
% false: returns fill pattern
/GPS {
PSt 1 ge PSt 5 le and % valid pen pattern?
{
{ LArr PSt 1 sub 2 mul get } % draw pattern
{ LArr PSt 2 mul 1 sub get } ifelse % opaque pattern
}
{ [] } ifelse % out of range => solid line
} D
% QS: QtStroke
% draw and fill current path
%
% - QS -
/QS { % stroke command
PSt 0 ne % != NO_PEN
{
gsave
LWi SW % set line width
true GPS 0 setdash S % draw line pattern
OMo PSt 1 ne and % opaque mode and not solid line?
{
BkCol SC
false GPS dup 0 get setdash S % fill in opaque pattern
} if
grestore
} if
} D
%% The following operations are used to read compressed data from the file
%% Until now this is only used for image compression
% read 28 bits and leave them on tos
%
% - r28 num
/r28 {
% skip past whitespace and read one character
{ currentfile read pop
dup 32 gt { exit } if
pop
} loop
% read three more
3 {
currentfile read pop
} repeat
% make an accumulator
0
% for each character, shift the accumulator and add in the character
4 {
7 bitshift exch
dup 128 gt { 84 sub } if 42 sub 127 and
add
} repeat
} D
/rA 0 d % accumulator
/rL 0 d % bits left
% takes number of bits, leaves number
%
% num rB num
/rB {
rL 0 eq {
% if we have nothing, let's get something
/rA r28 d
/rL 28 d
} if
dup rL gt {
% if we don't have enough, take what we have and get more
rA exch rL sub rL exch
/rA 0 d /rL 0 d
rB exch bitshift add
} {
% else take some of what we have
dup rA 16#fffffff 3 -1 roll bitshift not and exch
% ... and update rL and rA
dup rL exch sub /rL ED
neg rA exch bitshift /rA ED
} ifelse
} D
% uncompresses image data from currentfile until the string on the
% stack is full; leaves the string there.
% assumes that nothing could conceivably go wrong, ie. the compressed data has
% to be in the correct format and the length of the string has to be exactly right
% to hold the compressed data
%
% string uc string
%
%%% Warning: if you change the method here, change the table in qpsprinter.cpp:compress()!
/uc {
/rL 0 d
0
{ % string pos
dup 2 index length ge { exit } if
1 rB
1 eq { % compressed
3 rB % string pos bits
dup 3 ge {
1 add dup rB % string pos bits extra
1 index 5 ge {
1 index 6 ge {
1 index 7 ge {
1 index 8 ge {
128 add
} if
64 add
} if
32 add
} if
16 add
} if
3 add
exch pop
} if
3 add
% string pos length
exch 10 rB 1 add
% string length pos dist
{
dup 3 index lt {
dup
} {
2 index
} ifelse % string length pos dist length-this-time
4 index 3 index 3 index sub 2 index getinterval
5 index 4 index 3 -1 roll putinterval
dup 4 -1 roll add 3 1 roll
4 -1 roll exch sub
dup 0 eq { exit } if
3 1 roll
} loop % string pos dist length
pop pop
} { % uncompressed
3 rB 1 add
{
2 copy 8 rB put 1 add
} repeat
} ifelse
} loop
pop
} D
%% image drawing routines
/sl D0 % ### is this needed ?
% defines for QCI
/QCIgray D0 /QCIcolor D0 /QCIindex D0
% this method prints color images if colorimage is available, otherwise
% converts the string to a grayscale image and uses the reular postscript image
% operator for printing.
% Arguments are the same as for the image operator:
%
% width height bits/sample matrix datasrc QCI -
/QCI {
/colorimage where {
pop
false 3 colorimage
}{ % the hard way, based on PD code by John Walker <[email protected]>
exec /QCIcolor ED
/QCIgray QCIcolor length 3 idiv string d
0 1 QCIcolor length 3 idiv 1 sub
{ /QCIindex ED
/x QCIindex 3 mul d
QCIgray QCIindex
QCIcolor x get 0.30 mul
QCIcolor x 1 add get 0.59 mul
QCIcolor x 2 add get 0.11 mul
add add cvi
put
} for
QCIgray image
} ifelse
} D
% general image drawing routine, used from the postscript driver
%
% Draws images with and without mask with 1, 8 and 24(rgb) bits depth.
%
% width height matrix image 1|8|24 mask|false x y di
%
% width and height specify the width/height of the image,
% matrix a transformation matrix, image a procedure holding the image data
% (same for mask) and x/y an additional translation.
%
% ### should move the translation into the matrix!!!
/di
{
gsave
translate
1 index 1 eq { % bitmap
false eq { % no mask, draw solid background
pop
true 3 1 roll % width height false matrix image
4 index
4 index
false
4 index
4 index
imagemask
BkCol SC
imagemask
} {
pop
false 3 1 roll % width height false matrix image
imagemask
} ifelse
} {
dup false ne {
% have a mask, see if we can use it
/languagelevel where {
pop
languagelevel 3 ge
} { false } ifelse
} {
false
} ifelse
{
% languagelevel3, we can use image mask and dicts
% store the image mask
/ma exch d
% select colorspace according to 8|24 bit depth and set the decode array /dc
8 eq {
/dc [0 1] d
/DeviceGray
} {
/dc [0 1 0 1 0 1] d
/DeviceRGB
} ifelse
setcolorspace
% the image data
/im exch d
% transformation matrix
/mt exch d
% width and height
/h exch def
/w exch def
% the image dict
/id
7 dict dup begin
/ImageType 1 d
/Width w d
/Height h d
/ImageMatrix mt d
/DataSource im d
/BitsPerComponent 8 d
/Decode dc d
end d
% the mask dictionary
/md
7 dict dup begin
/ImageType 1 d
/Width w d
/Height h d
/ImageMatrix mt d
/DataSource ma d
/BitsPerComponent 1 d
/Decode [0 1] d
end d
% and the combined image dict
4 dict dup begin
/ImageType 3 d
/DataDict id d
/MaskDict md d
/InterleaveType 3 d
end
image
} {
pop % no mask or can't use it, get rid of it
8 % width height image 8|24 8 matrix
4 1 roll
8 eq { % grayscale
image
} { %color
QCI
} ifelse
} ifelse
} ifelse
grestore
} d
/BF { % brush fill
gsave
BSt 1 eq % solid brush?
{
BCol SC
WFi { fill } { eofill } ifelse
} if
BSt 2 ge BSt 8 le and % dense pattern?
{
BDArr BSt 2 sub get /sc ED
% the following line scales the brush color according to the pattern. the higher the pattern the lighter the color.
BCol
{
1. exch sub sc mul 1. exch sub
} forall
3 array astore
SC
WFi { fill } { eofill } ifelse
} if
BSt 9 ge BSt 14 le and % brush pattern?
{
WFi { clip } { eoclip } ifelse
defM SM
pathbbox % left upper right lower
3 index 3 index translate
4 2 roll % right lower left upper
3 2 roll % right left upper lower
exch % left right lower upper
sub /h ED
sub /w ED
OMo {
NP
0 0 MT
0 h RL
w 0 RL
0 h neg RL
CP
BkCol SC
fill
} if
BCol SC
0.3 SW
NP
BSt 9 eq BSt 11 eq or % horiz or cross pattern
{ 0 4 h
{ dup 0 exch MT w exch LT } for
} if
BSt 10 eq BSt 11 eq or % vert or cross pattern
{ 0 4 w
{ dup 0 MT h LT } for
} if
BSt 12 eq BSt 14 eq or % F-diag or diag cross
{ w h gt
{ 0 6 w h add
{ dup 0 MT h sub h LT } for
} { 0 6 w h add
{ dup 0 exch MT w sub w exch LT } for
} ifelse
} if
BSt 13 eq BSt 14 eq or % B-diag or diag cross
{ w h gt
{ 0 6 w h add
{ dup h MT h sub 0 LT } for
} { 0 6 w h add
{ dup w exch MT w sub 0 exch LT } for
} ifelse
} if
S
} if
BSt 24 eq % CustomPattern
{
} if
grestore
} D
% for arc
/mat matrix d
/ang1 D0 /ang2 D0
/w D0 /h D0
/x D0 /y D0
/ARC { % Generic ARC function [ X Y W H ang1 ang2 ]
/ang2 ED /ang1 ED /h ED /w ED /y ED /x ED
mat CM pop
x w 2 div add y h 2 div add TR
1 h w div neg scale
ang2 0 ge
{0 0 w 2 div ang1 ang1 ang2 add arc }
{0 0 w 2 div ang1 ang1 ang2 add arcn} ifelse
mat SM
} D
/C D0
/P { % PdcDrawPoint [x y]
NP
MT
0.5 0.5 rmoveto
0 -1 RL
-1 0 RL
0 1 RL
CP
fill
} D
/M { % PdcMoveTo [x y]
/Cy ED /Cx ED
} D
/L { % PdcLineTo [x y]
NP
Cx Cy MT
/Cy ED /Cx ED
Cx Cy LT
QS
} D
/DL { % PdcDrawLine [x1 y1 x0 y0]
NP
MT
LT
QS
} D
/HL { % PdcDrawLine [x1 y x0]
1 index DL
} D
/VL { % PdcDrawLine [x y1 y0]
2 index exch DL
} D
/R { % PdcDrawRect [x y w h]
/h ED /w ED /y ED /x ED
NP
x y MT
0 h RL
w 0 RL
0 h neg RL
CP
BF
QS
} D
/ACR { % add clip rect
/h ED /w ED /y ED /x ED
x y MT
0 h RL
w 0 RL
0 h neg RL
CP
} D
/xr D0 /yr D0
/rx D0 /ry D0 /rx2 D0 /ry2 D0
/RR { % PdcDrawRoundRect [x y w h xr yr]
/yr ED /xr ED /h ED /w ED /y ED /x ED
xr 0 le yr 0 le or
{x y w h R} % Do rect if one of rounding values is less than 0.
{xr 100 ge yr 100 ge or
{x y w h E} % Do ellipse if both rounding values are larger than 100
{
/rx xr w mul 200 div d
/ry yr h mul 200 div d
/rx2 rx 2 mul d
/ry2 ry 2 mul d
NP
x rx add y MT
x y rx2 ry2 180 -90
x y h add ry2 sub rx2 ry2 270 -90
x w add rx2 sub y h add ry2 sub rx2 ry2 0 -90
x w add rx2 sub y rx2 ry2 90 -90
ARC ARC ARC ARC
CP
BF
QS
} ifelse
} ifelse
} D
/E { % PdcDrawEllipse [x y w h]
/h ED /w ED /y ED /x ED
mat CM pop
x w 2 div add y h 2 div add translate
1 h w div scale
NP
0 0 w 2 div 0 360 arc
mat SM
BF
QS
} D
/A { % PdcDrawArc [x y w h ang1 ang2]
16 div exch 16 div exch
NP
ARC
QS
} D
/PIE { % PdcDrawPie [x y w h ang1 ang2]
/ang2 ED /ang1 ED /h ED /w ED /y ED /x ED
NP
x w 2 div add y h 2 div add MT
x y w h ang1 16 div ang2 16 div ARC
CP
BF
QS
} D
/CH { % PdcDrawChord [x y w h ang1 ang2]
16 div exch 16 div exch
NP
ARC
CP
BF
QS
} D
/BZ { % PdcDrawCubicBezier [4 points]
curveto
QS
} D
/CRGB { % Compute RGB [R G B] => R/255 G/255 B/255
255 div 3 1 roll
255 div 3 1 roll
255 div 3 1 roll
} D
/BC { % PdcSetBkColor [R G B]
CRGB
BkCol astore pop
} D
/BR { % PdcSetBrush [style R G B]
CRGB
BCol astore pop
/BSt ED
} D
/WB { % set white solid brush
1 W BR
} D
/NB { % set nobrush
0 B BR
} D
/PE { % PdcSetPen [style width R G B Cap Join]
setlinejoin setlinecap
CRGB
PCol astore pop
/LWi ED
/PSt ED
LWi 0 eq { 0.25 /LWi ED } if % ### 3.0 remove this line
PCol SC
} D
/P1 { % PdcSetPen [R G B]
1 0 5 2 roll 0 0 PE
} D
/ST { % SET TRANSFORM [matrix]
defM setmatrix
concat
} D
%% Font handling
% the next three commands are for defining fonts. The first one
% tries to find the most suitable printer font out of a fontlist.
% if encoding is false the default one will be used.
/MF { % newname encoding fontlist
% this function tries to find a suitable postscript font.
% We try quite hard not to get courier for a
% proportional font. The following takes an array of fonts.
% The algorithm will take the first font that
% gives a match (defined as not resulting in a courier font).
% each entry in the table is an array of the form [ /Fontname x-stretch slant ]
% x-strtch can be used to stretch/squeeze the font in x direction.
% This gives better results when eg substituting helvetica for arial
% slant is an optional slant. 0 is non slanted, 0.2 is a typical value for a syntetic oblique.
% encoding can be either an encoding vector of false if the default font encoding is requested.
true exch true exch % push a dummy on the stack,
{ % so the loop over the array will leave a font in any case when exiting.
exch pop exch pop % (dummy | oldfont) (dummy | fontdict) fontarray
dup 0 get dup findfont % get the fontname from the array and load it
dup /FontName get % see if the font exists
3 -1 roll eq { % see if fontname and the one provided are equal
exit
} if
} forall
exch % font fontarray
% newname encoding font fontarray defines a postscript font
dup
1 get /fxscale exch def % define scale, sland and encoding
2 get /fslant exch def
exch /fencoding exch def
[ fxscale 0 fslant 1 0 0 ] makefont % transform font accordingly
fencoding false eq { % check if we have an encoding and use it if available
} {
dup maxlength dict begin % copy font
{
1 index /FID ne % don't copy FID, as it's not allowed in PS Level 1
{def}{pop pop}ifelse
} forall
/Encoding fencoding def % replace encoding
currentdict
end
} ifelse
definefont pop
} D
% an embedded font. This is used for the base fonts of the composite font used later on.
/MFEmb { % newname encoding fontname
findfont dup length dict
begin
{
1 index /FID ne
{d}{pop pop}ifelse
} forall
/Encoding ED currentdict
end
definefont pop
} D
% DF: define font
% used to get a scaled version of an already loaded font
%
% newname pointsize fontmame DF -
/DF {
findfont
% get the fontsize on top of the stack and define font matrix
/fs 3 -1 roll d [ fs 0 0 fs -1 mul 0 0 ]
makefont
d
} D
/ty 0 d
/Y {
/ty ED
} D
/Tl { % draw underline/strikeout line: () w x y lw ->Tl-> () w x
gsave
setlinewidth
NP 1 index exch MT
1 index 0 rlineto stroke
grestore
} D
/XYT { % [string [x/y displacement array] width x]
ty MT % pops x
/xyshow where { % interpreter has xyshow
pop pop
xyshow
} { % use ashow
exch pop % string cwidth
1 index % string cwidth string
dup length 2 div exch % string cwidth length string !have to divide by 2 since we use unicode!
stringwidth pop % string cwidth length pwidth
3 -1 roll % string length pwidth cwidth
exch sub exch div % string extraperchar
exch 0 exch % extraperchar 0 string
ashow
} ifelse
} D
/AT {
ty MT % pops x
1 index % string cwidth string
dup length 2 div exch % string cwidth length string !have to divide by 2 since we use unicode!
stringwidth pop % string cwidth length pwidth
3 -1 roll % string length pwidth cwidth
exch sub exch div % string extraperchar
exch 0 exch % extraperchar 0 string
ashow
} D
%% start of page
/QI {
/C save d
pageinit
/Cx 0 d % reset current x position
/Cy 0 d % reset current y position
/OMo false d
} D
%% end of page
/QP { % show page
C restore
showpage
} D
% merges one key value pair into the page device dict
%
% key value SPD -
/SPD {
/setpagedevice where {
1 dict dup begin 3 1 roll def end
setpagedevice
} { pop pop } ifelse
} D
/SV { % Save painter state
BSt LWi PSt Cx Cy WFi OMo BCol PCol BkCol
/nS nS 1 add d
gsave
} D
/RS { % Restore painter state
nS 0 gt
{ grestore
/BkCol ED /PCol ED /BCol ED /OMo ED /WFi ED
/Cy ED /Cx ED /PSt ED /LWi ED /BSt ED
/nS nS 1 sub d
} if
} D
/CLSTART { % clipping start
/clipTmp matrix CM d % save current matrix
defM SM % Page default matrix
NP
} D
/CLEND { % clipping end
clip
NP
clipTmp SM % restore the current matrix
} D
/CLO { % clipping off
grestore % restore top of page state
gsave % save it back again
defM SM % set coordsys (defensive progr.)
} D
|