1Pamtris User Manual(0) Pamtris User Manual(0)
2
3
4
6 pamtris - triangle rasterizer featuring perspective-correct interpola‐
7 tion of generic vertex attributes and depth buffering
8
9
11 pamtris
12
13 -width=width
14
15 -height=height
16
17 { -num_attribs=attributes_per_vertex [ -tupletype=tupletype ] | -rgb |
18 -grayscale }
19
20 [ -maxval=maxval ]
21
22 All options can be abbreviated to their shortest unique prefix. You
23 may use two hyphens instead of one to designate an option. You may use
24 either white space or an equals sign between an option name and its
25 value.
26
27
29 This program is part of Netpbm(1).
30
31
32
33 pamtris can be used to draw a great variety of 2D and 3D graphics by
34 composing arbitrarily complex pictures out of separate triangles, tri‐
35 angle strips and triangle fans. The program reads instructions written
36 in a simple command script notation from Standard Input and outputs its
37 results as a (potentially multi-image) PAM stream on Standard Output.
38
39 For example, the following input
40
41
42 mode fan
43 attribs 0 128 0
44 vertex 0 0 1
45 attribs 0 0 128
46 vertex 200 0 1
47 attribs 50 20 103
48 vertex 190 61 1
49 attribs 100 40 78
50 vertex 161 117 1
51 attribs 150 60 53
52 vertex 117 161 1
53 attribs 200 80 28
54 vertex 61 190 1
55 attribs 250 100 3
56 vertex 0 200 1
57 print
58
59
60
61 produces this:
62
63 Example Pamtris output for fan mode
64
65
66 The input file gives triangle data by setting the appropriate drawing
67 mode, if necessary, and then providing a list of vertices. Each vertex
68 is also associated with a list of up to 20 "attributes," which are
69 integer values between 0 and a given maxval. In the most common usage,
70 you use pamtris to draw a visual image and a vertex has three
71 attributes, which are an RGB specification of a color. Such attribute
72 lists may be provided on a per-vertex basis.
73
74 Before images can be effectively written to Standard Output, pamtris
75 gradually rasterizes them on an internal frame buffer which consists of
76 an "image buffer" and a "depth buffer." The image buffer consists of a
77 sequence of height rows containing a sequence of width tuples. There is
78 one sample for each vertex attribute in every tuple plus an opacity
79 (alpha) sample. Each tuple in the image buffer is also associated with
80 an integer depth in the depth buffer, which determines whether subse‐
81 quent drawing operations affect that particular tuple or not. This pro‐
82 vides a way of depth-sorting graphical objects which is adequate for
83 many purposes in 2D and 3D computer graphics. One prominent shortcoming
84 of such an approach to depth-sorting, however, is that it does not
85 automatically work with objects which are intended to appear "translu‐
86 cent," therefore requiring more elaborate strategies to incorporate
87 said objects into pictures generated using this technique.
88
89 The opacity sample is the last sample of the tuple. pamtris manipu‐
90 lates opacity internally and for any tuple it is always either 0 or the
91 maxval. The program does not provide the user direct control over the
92 alpha image plane.
93
94 pamtris rasterizes triangles by approximating their visible area as a
95 collection of tuples at particular positions in the frame buffer, and
96 to each sample of every such tuple it assigns a value which is a per‐
97 spective-correct interpolation between the values of the corresponding
98 attribute for each vertex of the triangle. Whenever a tuple within the
99 area of the frame buffer is produced, it is written to the correspond‐
100 ing position in the frame buffer if and only if it passes a depth test.
101 This test works as follows: the depth value of every incoming tuple
102 (which is itself an interpolation between the Z-coordinates of the ver‐
103 tices of the corresponding triangle) is compared against the value in
104 the corresponding position in the depth buffer. If the depth value of
105 the incoming tuple equals or is smaller than the depth value already
106 present in said position in the depth buffer, the following happens.
107
108
109
110 · Every sample i, where 0 ≤ i < num_attribs, of the tuple in
111 the corresponding position in the image buffer is set to equal
112 the value of the respective sample of the incoming tuple; and
113 the alpha sample (the last one) is updated to the maxval;
114
115
116 · The depth value in the corresponding position in the depth buf‐
117 fer is updated to a depth value directly proportional to that of
118 the incoming tuple.
119
120
121 Otherwise, that particular tuple effects no change at all in the frame
122 buffer.
123
124 The frame buffer is initially set so that all samples in every tuple of
125 the image buffer contain the value 0, and all entries in the depth buf‐
126 fer contain the maximum permitted depth value.
127
128 The attributes' values, and therefore the samples in the output PAM
129 images, have no fixed interpretation ascribed to them (except for the
130 last image plane, which is deliberately supposed to represent tuple
131 opacity information); one may ascribe any suitable meaning to them,
132 such as that of colors, texture coordinates, surface normals, light
133 interaction characteristics, texture influence coefficients for multi-
134 texturing, etc.
135
136
137
139 Fan Mode
140 The following command generates the image from the fan mode example at
141 the top of the DESCRIPTION ⟨#description⟩ section. If the file
142 fan.tris contains that code, you could process it with:
143
144
145 $ pamtris -height=200 -width=200 -rgb <fan.tris >fan.pam
146
147
148
149 Strip Mode
150 The following is an example of strip mode:
151
152
153 mode strip
154 attribs 255 0 0 # red
155 vertex 0 200 1
156 vertex 50 0 1
157 attribs 0 0 0 # black
158 vertex 100 200 1
159 attribs 0 205 205 # cyan
160 vertex 150 0 1
161 attribs 0 0 255 # blue
162 vertex 200 200 1
163 vertex 250 0 1
164 print
165
166
167 Save the above code in a file named strip.tris (for instance) and
168 process it with:
169
170
171 $ pamtris -height=200 -width=200 -rgb <strip.tris >strip.pam
172
173
174 to yield:
175
176 Example Pamtris output for strip mode
177
178
179 Triangle Mode
180 The following is an example of triangle mode:
181
182
183 # yellow square
184 mode strip
185 attrib 155 155 0
186 vertex 50 50 100
187 vertex 50 200 100
188 vertex 200 50 100
189 vertex 200 200 100
190
191 # blue triangle
192 mode triangles
193 attrib 0 205 205
194 vertex 20 125 70
195 attrib 0 0 140
196 vertex 230 70 120 # Change "120" and see what happens
197 vertex 230 180 120 #
198 print
199
200
201 Save the above code in a file named pierce.tris (for instance) and
202 process it with:
203
204
205 $ pamtris -height=200 -width=200 -rgb <pierce.tris >pierce.pam
206
207
208 to yield:
209
210 Example Pamtris output for triangle mode
211
212
213
214 Meta-programming
215 The pamtris command language is much too rudimentary to be used
216 directly for any serious drawing; you will probably want to use a gen‐
217 eral purpose programming language to generate a temporary pamtris com‐
218 mand file.
219
220
221
222 For example, the following C program generates pamtris instructions to
223 produce a picture of NAMCO's Pac-Man. It generates dozens of vertex
224 commands tracing around the perimeter of a circle.
225
226 <img alt="Pac-Man" src="pamtris_pacman.png">
227
228
229 /* ------------------------------------
230 * width = 256
231 * height = 256
232 * num_attribs = 3
233 * tupletyple = RGB_ALPHA
234 * --------------------------------- */
235
236 #include <stdio.h>
237 #include <math.h>
238
239 #define PI 3.141592
240 #define PI2 (2.0 * PI)
241
242 #define WIDTH 256
243 #define HEIGHT WIDTH
244
245 int main(void)
246 {
247 int const center_x = 0.5 * WIDTH;
248 int const center_y = 0.5 * HEIGHT;
249
250 double const radius = 0.48 * WIDTH;
251
252 int const sectors = round(0.125 * PI * radius + 1);
253
254 puts("mode triangles");
255
256 printf("vertex %d %d 0\n", center_x, center_y);
257 printf("vertex %d %d 0\n", WIDTH, 0);
258 printf("vertex %d %d 0\n", WIDTH, HEIGHT);
259
260 puts("clear image");
261 puts("mode fan");
262 puts("attribs 255 255 0");
263 printf("vertex %d %d 1\n", center_x, center_y);
264 puts("attribs 255 128 0");
265
266 double const angle_step = PI2 / (sectors - 1);
267
268 unsigned int i;
269
270 for (i = 0; i < sectors; i++)
271 {
272 double const angle = angle_step * i;
273 int const x = round(cos(angle) * radius + center_x);
274 int const y = round(sin(angle) * radius + center_y);
275
276 printf("vertex %d %d 1\n", x, y);
277 }
278
279 puts("print");
280
281 return 0;
282 }
283
284 Below are two other examples which, although not as trivial, demon‐
285 strate what else can be feasibly obtained through this meta-programming
286 approach, especially when combining pamtris with other Netpbm programs
287 (Earth texture from nasa.gov
288 ⟨https://visibleearth.nasa.gov/view.php?id=73580⟩ ):
289
290 <img alt="Isometric Rainbow Waves" src="pamtris_isowaves.gif"> <img
291 alt="Rotating Earth" src="pamtris_earth.gif">
292
293
294
296 <dl compact="compact">
297
298 -width=width
299 Sets the width of the internal frame buffer and, by extension,
300 of the output PAM images, given in number of columns. This must
301 be an integer in the closed range [1, 8192].
302
303 This option is mandatory.
304
305
306 -height=height
307 This is the height of the internal frame buffer and, by exten‐
308 sion, of the output PAM images, given in number of rows. This
309 must be an integer in the closed range [1, 8192].
310
311 This option is mandatory.
312
313
314 -num_attribs=attributes_per_vertex
315 This is the number of attributes per vertex and, by extension,
316 the depth of the output PAM images, which is equal to this value
317 plus one (to accomodate the alpha plane). The argument must be
318 an integer in the closed range [1, 20].
319
320 The input instruction sequence may override this with a reset
321 command.
322
323 You must specify exactly one of -num_attribs, -rgb, and
324 -grayscale.
325
326
327
328 -tupletype=tupletype
329 This is the tuple type for the output PAM images. The argument
330 is a string which may be no longer than 255 characters.
331
332 The input instruction sequence may override this with a reset
333 command.
334
335 The default is an empty (null) string.
336
337 This option cannot be specified together with -rgb or
338 -grayscale.
339
340
341
342
343 -rgb This is a convenience option which simply serves as an alias for
344 -num_attribs=3 -tupletype=RGB_ALPHA. In other words, this option
345 is a quick way to specify that you are going to use pamtris to
346 draw RGB(_ALPHA) color images directly, and the three vertex
347 attributes are the red, green and blue levels of the color asso‐
348 ciated with the vertex, in that order.
349
350 The input instruction sequence may override this with a reset
351 command.
352
353 You must specify exactly one of -num_attribs, -rgb, and
354 -grayscale.
355
356 This option was new in Netpbm 10.85 (December 2018).
357
358
359 -grayscale
360 Another convenience option, similar to -rgb; except this one is
361 an alias for -num_attribs=1 -tupletype=GRAYSCALE_ALPHA. The one
362 vertex attribute is the gray level associated with the vertex.
363
364 The input instruction sequence may override this with a reset
365 command.
366
367 You must specify exactly one of -num_attribs, -rgb, and
368 -grayscale.
369
370 This option was new in Netpbm 10.85 (December 2018).
371
372
373 -maxval=maxval
374 Sets the maxval of the output PAM images, which is also the max‐
375 imum permitted value for each vertex attribute. This must be an
376 integer in the closed range [1, 65535].
377
378 The default value is 255.
379
380 The input instruction sequence may override this with a reset
381 command.
382
383
384
385
387 The input for pamtris consists of a sequence of text lines sent to it
388 through the Standard Input mechanism.
389
390 Empty lines or lines that contain only white space characters are
391 called blank lines and are ignored.
392
393 When a # occurs anywhere in a line, pamtris ignores it along with every
394 character after it. In other words, everything from the # until the end
395 of the line receives the same treatment as white space.
396
397 Lines which are not blank must contain a sequence of strings separated
398 by white space, called tokens. The first such token must be one of the
399 commands recognized by pamtris, and all further tokens are interpreted
400 as the arguments for that command, if it takes any. When an insuffi‐
401 cient number of arguments is provided for a command, the line is con‐
402 sidered invalid and is given the same treatment as a blank line. The
403 same happens when an out of range argument or one of a kind different
404 of what is expected is given (for example, when you give a string of
405 letters where a numerical value is expected), or when an unrecognized
406 command/argument is found. When a number of arguments greater than that
407 required for a particular command is provided, only the portion of the
408 line up to the last required argument is considered and any further
409 tokens are ignored.
410
411 pamtris is case-insensitive. That is, mode, MODE, mODe, etc. are all
412 treated the same way.
413
414 The commands recognized by pamtris are:
415
416
417 mode
418
419 attribs
420
421 vertex
422
423 print
424
425 clear
426
427 reset
428
429 quit
430
431
432 You may use a minimum unique abbreviation of a command name. You may
433 use an exclamation mark (!) in place of the print command name and an
434 asterisk (*) in place of clear.
435
436
437
438 The functions of the commands are as follows.
439
440
441
442 mode { triangles | strip | fan }
443
444 This makes pamtris enter a new drawing mode. The argument is a
445 word which specifies the mode to change to. Instead of a full
446 argument name, it is permissible to provide a minimum unique
447 abbreviation, which has the same effect. The drawing mode will
448 remain the same until the next mode command is given.
449
450 This command also resets the current vertex list, which is
451 (re)initialized to an empty state after the command is executed.
452 One may add new vertices to this list through successive invoca‐
453 tions of the vertex command (see below). You do not have to
454 worry about providing "too many" vertices, since the vertex list
455 is virtualized: pamtris maintains only the state pertaining to
456 three vertices at any one time. The current vertex list is ini‐
457 tially empty.
458
459 It is permissible to give pamtris a mode command which instructs
460 it to enter a drawing mode it is currently already in. One might
461 use this approach to reset the current vertex list without
462 changing the current drawing mode.
463
464 Regardless of the current drawing mode, a new triangle is imme‐
465 diately rasterized into the frame buffer as soon as the neces‐
466 sary vertices for it are provided through the current vertex
467 list.
468
469 In the following descriptions of each drawing mode, triangles'
470 and vertices' indices (ordinal numbers) are 0-based.
471
472 The triangles argument instructs pamtris to enter the "TRIAN‐
473 GLES" drawing mode. While in this mode, a series of separate
474 triangles is constructed. Every three vertices pushed into the
475 current vertex list specify a new triangle. Formally, this
476 means that every Nth triangle is specified by vertices 3 * N, 3
477 * N + 1, and 3 * N + 2. This is the default initial mode and is
478 therefore not required to be set explicitly before drawing any
479 triangles.
480
481 The strip argument instructs pamtris to enter the "STRIP" draw‐
482 ing mode. While in this mode, pamtris constructs a "triangle
483 strip." That is, the first three vertices pushed into the cur‐
484 rent vertex list specify the first triangle, and every new ver‐
485 tex pushed after that specifies, together with the previous two,
486 the next triangle. Formally, this means that every Nth triangle
487 is specified by vertices N, N + 1, and N + 2.
488
489 The fan argument instructs pamtris to enter the "FAN" drawing
490 mode. While in this mode, a so-called "triangle fan" is con‐
491 structed. That is, the first three vertices pushed into the
492 current vertex list specify the first triangle, and every new
493 vertex pushed after that specifies, together with the previous
494 vertex and the first one, the next triangle. Formally, this
495 means that every Nth triangle is specified by vertices 0, N + 1,
496 and N + 2.
497
498
499
500
501 attribs a<sub>0</sub> ... a<sub>num_attribs - 1</sub>
502
503 This updates the current attribute values list. This command
504 takes as arguments a sequence of num_attribs integers which rep‐
505 resent the values of the attributes to be associated with the
506 next vertex. This sequence of values is the just mentioned "cur‐
507 rent attribute values list."
508
509 Each ith argument, where 0 ≤ i < num_attribs, indicates
510 the value to be assigned to the ith attribute of the current
511 attribute values list. All arguments must be integer values in
512 the closed range [0, maxval]. If a number of arguments less
513 than the current value of num_attribs is given, the command is
514 considered invalid and is therefore ignored.
515
516 The current attribute values list remains unchanged until the
517 next valid attribs or reset command is given. The attribs com‐
518 mand allows one to change the values of each attribute individu‐
519 ally, while the reset command is not specifically designed for
520 that function, but it has the side effect of setting all values
521 in the current attribute values list to the maxval (see below).
522
523 All values in the current attribute values list are initially
524 set to the maxval.
525
526 <dt id="cmd_vertex">vertex x y z [w]
527
528 Adds a new vertex to the current vertex list (see the mode com‐
529 mand above), assigning the values of the arguments to its
530 respective coordinates, and the values in the current attribute
531 values list (see the attribs command above) to the respective
532 entries in the attribute list associated with the vertex.
533
534 x, y and z must be integer values in the closed range [-32767,
535 32767]. x and y represent, respectively, the column and row of
536 the tuple which corresponds to the location of the vertex. Such
537 values may correspond to tuples outside the limits of the frame
538 buffer. The origin of the coordinate system is at the top-left
539 tuple of the frame buffer. The X-axis goes from left to right,
540 and the Y-axis from top to bottom. A negative value for x indi‐
541 cates a column that many tuples to the left of the leftmost col‐
542 umn of the frame buffer. Likewise, a negative value for y indi‐
543 cates a row that many tuples above the uppermost row of the
544 frame buffer. Observe that those coordinates correspond directly
545 to a particular point in the coordinate system delineated above,
546 regardless of whether you are trying to draw an image which is
547 supposed to look as if viewed "in perspective" or not; pamtris
548 does not "warp" the coordinates you give in any way. Therefore,
549 if you want to draw images in perspective, you must compute val‐
550 ues for x and y already projected into pamtris' coordinate sys‐
551 tem yourself, using an external perspective projection method,
552 prior to giving them to the program.
553
554 The z parameter represents the Z-coordinate of the vertex,
555 which is used to compute depth values for tuples within the
556 areas of rasterized triangles. Intuitively, smaller values for z
557 mean "closer to the viewer," and larger ones mean "farther away
558 from the viewer" (but remember: as said above, the x and y coor‐
559 dinates are not warped in any way, which implies that they are
560 not affected by z; neither by the next parameter, for that mat‐
561 ter).
562
563 Optionally, you may provide a w parameter which represents a
564 "perspective correction factor" used to properly interpolate
565 vertex attributes across the area of the corresponding triangle.
566 This must be an integer value in the closed range [1, 1048575].
567 If you don't provide a value for it, the default value of 1 is
568 used (hence, if you want to nullify the effects of perspective
569 correction on a triangle so the output samples are computed as
570 if just linearly interpolated, simply do not provide a value for
571 w for any vertex of the triangle). If, however, you intend to
572 draw 3D geometry in perspective, you must provide an appropriate
573 value for this parameter, otherwise the output images might look
574 very wrong. w was new in Netpbm 10.85 (December 2018).
575
576 One way to compute w for a vertex in a image which is intended
577 to look as in perspective is as follows. First, consider the
578 typical model ⟨https://en.wikipedia.org/wiki/Viewing_frustum⟩
579 of the so-colled "viewing frustum" used to project vertices in
580 3D "world space" onto a planar "image space." The value of w for
581 a vertex is simply the <a id="vertex_note_link" href="#ver‐
582 tex_note">dot product*</a> between the 3D vector r and the 3D
583 unit vector n (i.e. the length of the orthogonal projection of r
584 on the line determined by n) in pixels; where r is the vector
585 which goes from the projection reference point (PRP, or "eye")
586 to the vertex, and n is a view-plane normal (VPN) of unit length
587 which points away from the PRP.
588
589 In case you are performing a mere multiplication of a 4D vector
590 with x, y, z and w components by a so-called perspective projec‐
591 tion 4x4 matrix in order to compute the projection of a vertex
592 onto the image plane, then you may supply for w a value which is
593 directly proportional to the absolute value of the w component
594 of the resulting vector.
595
596 [<a id="vertex_note" href="#vertex_note_link">*</a>]: For any
597 two 3D vectors a and b, with respective real scalar components
598 a<sub>x</sub>, a<sub>y</sub>, a<sub>z</sub> and b<sub>x</sub>,
599 b<sub>y</sub>, b<sub>z</sub>, the dot product between a and b is
600 simply a<sub>x</sub> * b<sub>x</sub> + a<sub>y</sub> *
601 b<sub>y</sub> + a<sub>z</sub> * b<sub>z</sub>.
602
603
604
605
606 print
607
608 This writes a PAM image to Standard Output whose raster is a
609 copy of the current contents of the image buffer. The values of
610 the WIDTH and HEIGHT fields are the same as the width and
611 height, respectively, of the frame buffer, which were given on
612 the command line during program invocation. The MAXVAL field is
613 equal to the current maxval; the DEPTH field is equal to the
614 current value of num_attribs + 1; and the TUPLTYPE field is
615 equal to the current tupletype.
616
617 This command has no effect upon the current drawing state. E. g.
618 it does not modify the current drawing mode, the current vertex
619 list, etc.
620
621 One may issue an arbitrary number of print commands at different
622 positions in the input instruction sequence to produce a multi-
623 image PAM stream.
624
625
626 clear [ image | depth ]
627
628 Clears the frame buffer. That is, all samples in the image buf‐
629 fer are once again set to 0, and all entries in the depth buffer
630 are once again set to the maximum permitted depth value.
631
632 Optionally, one may provide an argument to only clear either the
633 image buffer or the depth buffer individually, while leaving the
634 other intact. With the image argument, only the image buffer is
635 cleared; with the depth argument, only the depth buffer is
636 cleared. Instead of full argument names, one may provide a mini‐
637 mum unique abbreviation, which has the same effect. The single
638 character z is also accepted as an alias for depth.
639
640 Like the print command, this command has no effect upon the cur‐
641 rent drawing state either.
642
643
644
645 reset maxval num_attribs [tupletype]
646
647 This updates the current maxval and number of attributes per
648 vertex (num_attribs), resetting the <u>image</u> buffer with a
649 new maxval and number of samples per tuple while at it. The
650 parameter maxval must be an integer in the closed range [1,
651 65535], and num_attribs must be an integer in the closed range
652 [1, 20].
653
654 Optionally, after the second argument, one may provide a string
655 to be assigned to the current tupletype. The string goes from
656 the first character after the second argument which is not white
657 space and continues until (and including) the last character
658 before the end of the line which is not white space. If a new
659 tupletype is not provided, or the provided string is longer than
660 255 characters, the empty string is assigned to the current
661 tupletype.
662
663 The side effects of running this command are
664
665
666
667 ·
668
669 The new image buffer is completely cleared once the command is
670 executed.
671
672
673 ·
674
675 All values in the current attribute values list are set to the
676 new maxval.
677
678
679 ·
680
681 The current vertex list is reset.
682
683
684
685 However, it does not touch the depth buffer: it is left the same
686 way as it was found before the command. Also the drawing mode
687 remains the same (e. g. if pamtris was in FAN mode, it will con‐
688 tinue in that same mode, etc.).
689
690 If this command is given with an invalid value for maxval or
691 num_attribs, it is ignored and therefore none of the above side
692 effects apply, nor do the current maxval, num_attribs or tuple‐
693 type change at all.
694
695 It is permissible to give a value for maxval and num_attribs
696 equal to the current maxval and num_attribs, respectively,
697 although the above side effects will still apply even in such
698 cases.
699
700 Since this command deals with memory allocation, it may fail to
701 execute successfully. If that happens, no lines of input will be
702 read anymore and pamtris will be terminated as if the quit com‐
703 mand was given.
704
705 quit
706
707 This terminates pamtris. It will not read any more lines of
708 input after this command.
709
710
711
712
713
715 Texturing
716 It is possible to apply so-called "textures" to images produced with
717 pamtris by using a pair of vertex attributes as texture coordinates,
718 then using pamchannel(1) to select the appropriate channels in the out‐
719 put image(s), and finally processing the result through pamlookup(1),
720 providing the desired texture file as a "lookup table." If you are
721 drawing pictures in perspective, make sure to provide adequate values
722 for the w parameter to your vertex commands ( see above ⟨#cmd_vertex⟩ )
723 so that the resulting samples in the images produced by pamtris are
724 perspective-correct.
725
726 You might want to consider using pnmtile(1) to make textures which are
727 inteded to be "repeated" along triangle meshes.
728
729
730
731 Anti-aliased edges
732 pamtris performs no anti-aliasing on triangle edges by itself. How‐
733 ever, it is possible to obtain anti-aliased images through a "super-
734 sampling" approach: draw your image(s) at a size larger than the
735 desired final size, and then, when all post-processing is done, down-
736 scale the final image(s) to the desired size. Drawing images with twice
737 the desired width and height, then down-scaling them to the intended
738 size while disregarding gamma (i.e. what pamscale -linear does) often
739 produces good enough results.
740
741
742
744 pampick(1) pamchannel(1) pamstack(1) pamlookup(1) pamarith(1) pam‐
745 scale(1) pamdepth(1) pamexec(1) pam(1)
746
747
749 pamtris was originally written by Lucas Brunno Luna. The author is
750 grateful to Bryan Henderson for offering suggestions regarding usabil‐
751 ity.
752
753
755 pamtris was new in Netpbm 10.84 (September 2018).
756
758 This manual page was generated by the Netpbm tool 'makeman' from HTML
759 source. The master documentation is at
760
761 http://netpbm.sourceforge.net/doc/pamtris.html
762
763netpbm documentation 15 June 2019 Pamtris User Manual(0)