aboutsummaryrefslogtreecommitdiffstats
path: root/doc/expert/tex
blob: 5d4d3571d6c6f3d986a1de4e02cd3a5e146ffa23 (plain) (blame)
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
@Appendix
   @Title { Implementation of Textures }
   @Tag { tex }
@Begin
The following notes detail how PostScript patterns have been
used to produce textures.  See the PostScript Language
Reference Manual, second edition (PLRM), especially Section 4.9.
@PP
PostScript patterns are implemented as color spaces, whereas
from a logical point of view they are really separate entities
in the graphics state, independent of color (except that a
colored texture overrides any current color while it is in
effect).  To ensure that Lout's @@SetTexture and @@SetColour
symbols have this desired independence of each other, the
following operators are defined in the Lout prologue:
@CD @Tbl
    mv { 0.5vx }
    bfont { Italic }
    bformat { @StartHSpan @Cell i { ctr } A | @HSpan | @HSpan | @Cell D }
    aformat { @Cell i { right } @Code A | @Cell @Code B |
              @Cell mr { 1c } @Code "-" | @Cell D }
{
@Rowb
    ma { 0i }
    A { Lout-defined operator }
    D { What it replaces }
    rb { yes }
@Rowa
    A { num } 
    B { LoutSetGray }
    D { setgray }
@Rowa
    A { num num num } 
    B { LoutSetRGBColor }
    D { setrgbcolor }
@Rowa
    A { num num num } 
    B { LoutSetHSBColor }
    D { sethsbcolor }
@Rowa
    A { num num num num } 
    B { LoutSetCMYKColor }
    D { setcmykcolor }
@Rowa
    A { p } 
    B { LoutSetTexture }
    D { setpattern }
    rb { yes }
    mb { 0i }
}
These have similar signatures to the corresponding PostScript
operators shown, and the idea is to use the Lout-defined
versions where you would normally use the PostScript ones.
The first four set the color without disturbing any current
texture; the last sets the texture without disturbing
any current color.  Here @Code { p } may be the PostScript
{@Code null} object, meaning no texture i.e. normal filling,
or else it must be an instantiated pattern dictionary, as
returned by @Code { makepattern }.
@PP
There are three key data types used by this code:
@BulletList

@LI { A colorspace, denoted @Code { cs }, is a PostScript
colorspace array and may have one of the following values:
@DP @RID @Tbl
    mv { 0.6vx }
    aformat { @Cell @Code A | @Cell B }
{
@Rowa
    ma { 0i }
    A { "[ /DeviceGray ]" }
    B { The greyscale colorspace }
@Rowa
    A { "[ /DeviceRGB ]" }
    B { The RGB colorspace }
@Rowa
    A { "[ /DeviceCMYK ]" }
    B { The CMYK colorspace }
@Rowa
    A { "[ /Pattern ]" }
    B { A colored pattern }
@Rowa
    mb { 0i }
    A { "[ /Pattern /name ]" }
    B { An uncolored pattern; @Code "/name" may be
{@Code "/DeviceGray"}, {@Code "/DeviceRGB"}, or
{@Code "/DeviceCMYK"} }
}
}

@LI { A color, denoted c, is an array containing a PostScript
non-pattern color and thus may have one of the following values:
@ID @Tbl
    mv { 0.6vx }
    aformat { @Cell @Code A | @Cell B }
{
@Rowa
    ma { 0i }
    A { "[ grey ]" }
    B { A @Code "/DeviceGray" color }
@Rowa
    A { "[ red green blue ]" }
    B { A @Code "/DeviceRGB" color }
@Rowa
    A { "[ c m y k ]" }
    B { A @Code "/DeviceCMYK" color }
    mb { 0i }
}
We enclose colors in an array to make it easy for us to
deal with their varying length.  The array has to be unpacked
with @Code "aload" before calling {@Code setcolor}.
}

@LI { A pattern, denoted {@Code "p"}.  For us, a pattern is
either the PostScript null object, meaning to fill with solid
color, or else it is a dictionary as returned by
{@Code makepattern}.  When such a dictionary is installed in
the current graphics state, this code guarantees that it will
contain two extra entries:
@ID @Tbl
    mv { 0.6vx }
    aformat { @Cell @Code A | @Cell B }
{
@Rowa
    ma { 0i }
    A { "/UnderlyingColorSpace" }
    B { A @Code cs as defined above }
@Rowa
    A { "/UnderlyingColor" }
    B { A @Code c as defined above }
    mb { 0i }
}
We need these extra entries to make color independent of
texture:  without them we would lose the current color when
we set a texture.  Because of these variables we can't share
pattern dictionaries among graphics states.  We must copy them.
}

@EndList
This representation obeys the following invariant:
@BulletList

@LI {
All components of the PostScript graphics state related to
pattern and color have defined values (e.g. there is never a
situation where we set color space but not color).
}

@LI { 
If the PostScript graphics state contains a @Code "/Pattern"
colorspace, the pattern dictionary stored in the state has
@Code "/UnderlyingColorSpace" and @Code "/UnderlyingColor"
entries of types @Code cs and {@Code c}.
}

@LI {
If the graphics state contains an uncolored @Code "/Pattern"
colorspace, then the @Code "/UnderlyingColorSpace" and
@Code "/UnderlyingColor" entries of the pattern dictionary
stored in the state agree with the underlying color space
and color stored in the graphics state.
}

@EndList
And it has the following abstraction function:
@BulletList

@LI {
If the graphics state colorspace is {@Code "/Pattern"}, then
the abstract current texture is the pattern dictionary stored
in the graphics state color.  If the graphics state colorspace
is not {@Code "/Pattern"}, then the abstract current texture
is {@Code null}.
}

@LI {
If the graphics state colorspace is {@Code "/Pattern"}, then the
abstract colorspace and color are the values of
@Code "/UnderlyingColorSpace" and @Code "/UnderlyingColor"
in the pattern dictionary stored in the graphics state color.
If the graphics state colorspace is not {@Code "/Pattern"},
then the abstract current colorspace and color are as returned
by @Code "currentcolorspace" and {@Code "[ currentcolor ]"}.
}

@EndList
The following functions are private helpers for the public functions:
@IndentedList

@LI @OneRow -2px @Break @F @Verbatim @Begin
% Current pattern (may be null): - LoutCurrentP p
/LoutCurrentP
{                              %% -
  currentcolorspace            %% [ /name etc ]
  0 get /Pattern eq            %% bool
  {                            %% -   (have pattern)
    [ currentcolor ]           %% [ comp0 ... compn p ]
    dup length 1 sub get       %% p
  }
  {                            %% -   (no pattern)
    null                       %% null
  } ifelse                     %% p
} def
@End @Verbatim

@LI @OneRow -2px @Break @F @Verbatim @Begin
% Current color and color space: - LoutCurrentCCS c cs
/LoutCurrentCCS
{
  LoutCurrentP dup null eq     %% p bool
  {                            %% null
    pop [ currentcolor ]       %% c
    currentcolorspace          %% c cs
  }
  {                            %% p
    dup                        %% p p
    /UnderlyingColor get exch  %% c p
    /UnderlyingColorSpace get  %% c cs
  } ifelse                     %% c cs
} def
@End @Verbatim

@LI @OneRow -2px @Break @F @Verbatim @Begin
% Make c, cs, and p current: c cs p LoutSetCCSP -
/LoutSetCCSP
{                              %% c cs p
  dup null eq                  %% c cs p bool
  {                            %% c cs p    (null pattern)
    pop setcolorspace          %% c
    aload pop setcolor         %% -
  }
  {                            %% c cs p    (non-null pattern)
    % copy pattern dictionary
    12 dict copy               %% c cs p

    % record cs and c in p
    dup /UnderlyingColorSpace  %% c cs p p /UCS
    3 index put                %% c cs p
    dup /UnderlyingColor       %% c cs p p /UC
    4 index put                %% c cs p

    % do setcolorspace and setcolor
    dup /PaintType get 1 eq    %% c cs p bool
    {                          %% c cs p   (colored pattern)
      [/Pattern] setcolorspace %% c cs p
      setcolor                 %% c cs
      pop pop                  %% -
    }
    {                          %% c cs p   (uncolored pattern)
      [ /Pattern               %% c cs p [ /Pattern
      4 -1 roll                %% c p [ /Pattern cs
      ] setcolorspace          %% c p
      exch aload length 1 add  %% p comp1 ... compm m+1
      -1 roll                  %% comp1 ... compm p
      setcolor                 %% -
    } ifelse                   %% -
  } ifelse                     %% -
} def
@End @Verbatim

@EndList
With the helper functions it's now easy to derive the colour and
texture setting commands that we are offering to our end users.
When setting the color we pass it, plus the current pattern, to
{@Code "LoutSetCCSP"}; when setting the pattern we pass it, plus
the current color, to {@Code "LoutSetCCSP"}.  Note that there is
no {@Code "/DeviceHSB"}: @Code "hsb" is a variant of {@Code "rgb"}.
@IndentedList

@LI @OneRow -2px @Break @F @Verbatim @Begin
% num LoutSetGray -
/LoutSetGray
{
  [ 2 1 roll ]                 %% c
  [ /DeviceGray ]              %% c cs
  LoutCurrentP                 %% c cs p
  LoutSetCCSP                  %% -
} def
@End @Verbatim

@LI @OneRow -2px @Break @F @Verbatim @Begin
% r g b LoutSetRGBColor -
/LoutSetRGBColor
{                              %% r g b
  [ 4 1 roll ]                 %% c
  [ /DeviceRGB ]               %% c cs
  LoutCurrentP                 %% c cs p
  LoutSetCCSP                  %% -
} def
@End @Verbatim

@LI @OneRow -2px @Break @F @Verbatim @Begin
% h s b LoutSetHSBColor -
/LoutSetHSBColor
{                              %% h s b
  gsave sethsbcolor            %% -
  currentrgbcolor grestore     %% r g b
  LoutSetRGBColor              %% -
} def
@End @Verbatim

@LI @OneRow -2px @Break @F @Verbatim @Begin
% c m y k LoutSetRGBColor -
/LoutSetCMYKColor
{
  [ 5 1 roll ]                 %% c
  [ /DeviceCMYK ]              %% c cs
  LoutCurrentP                 %% c cs p
  LoutSetCCSP                  %% -
} def
@End @Verbatim

@LI @OneRow -2px @Break @F @Verbatim @Begin
% p LoutSetTexture -
/LoutSetTexture
{
  LoutCurrentCCS               %% p c cs
  3 -1 roll                    %% c cs p
  LoutSetCCSP                  %% -
} def
@End @Verbatim

@EndList
All we need now is some sample textures.  Textures are just pattern
dictionaries as returned by {@Code "makepattern"}.  Here is
a PostScript function that appears in the Lout prologue.  Its
function is to simplify the production of textures.  It first
takes six parameters to specify a transformation of the texture
used to build the matrix taken by {@Code makepattern}, then
five parameters that go into the pattern dictionary.
@IndentedList

@LI @OneRow -2px @Break @F @Verbatim @Begin
% <scale> <scalex> <scaley> <rotate> <hshift> <vshift>
% <pt> <bb> <xs> <ys> <pc> LoutMakeTexture p
/LoutMakeTexture
{                              %% s sx sy r h v pt bb xs ys pp
  12 dict begin                %% s sx sy r h v pt bb xs ys pp
  /PaintProc exch def          %% s sx sy r h v pt bb xs ys
  /YStep exch def              %% s sx sy r h v pt bb xs
  /XStep exch def              %% s sx sy r h v pt bb
  /BBox exch def               %% s sx sy r h v pt
  /PaintType exch def          %% s sx sy r h v
  /PatternType 1 def           %% s sx sy r h v
  /TilingType 1 def            %% s sx sy r h v
  currentdict end              %% s sx sy r h v p
  7 1 roll                     %% p s sx sy r h v
  matrix translate             %% p s sx sy r mat1
  5 1 roll                     %% p mat1 s sx sy r
  matrix rotate                %% p mat1 s sx sy mat2
  4 1 roll                     %% p mat1 mat2 s sx sy
  matrix scale                 %% p mat1 mat2 s mat3
  exch dup matrix scale        %% p mat1 mat2 mat3 mat4
  matrix concatmatrix          %% p mat1 mat2 mat34
  matrix concatmatrix          %% p mat1 mat234
  matrix concatmatrix          %% p mat1234
  /makepattern where
  {                            %% p mat123 dict
    pop makepattern            %% p
  }
  {                            %% p mat123
    pop pop null               %% null
  } ifelse                     %% p (may be null)
} def
@End @Verbatim

@EndList
For examples of textures using {@Code LoutMakeTexture}, consult
the standard include file {@Code coltex}.  There is only one
built-in texture, {@Code LoutTextureSolid}:
@IndentedList

@LI @OneRow -2px @Break @F @Verbatim @Begin
/LoutTextureSolid
{
  null
  LoutSetTexture
} def
@End @Verbatim

@RawEndList
@End @Appendix