Postscript: Drawing a Gradient
I'm learning Postscript I'm trying to create a method for that would draw a vertical gradient.
Here is my code:
%!PS-Adobe-3.0
%%%%%%%%%%%%%%%%%%%%%%%
% draw a RECTANGLE
/Rect {
/h exch def % height
/w exch def % width
w 0 rlineto
0 h rlineto
-1.0 w mul 0 rlineto
0 -1.0 h mul rlineto
} def
%%%%%%%%%%%%%%%%%%%%%%%
% draw a Gradient
/VGrad {
/h exch def % height
/w exch def % width
/c2 exch def %gray-end
/c1 exch def %gray-start
/index 0.0 def %loop-index
0 1 h { %loop over height
gsave
c2 c1 sub index h div mul c1 add setgray
w h index sub Rect
stroke
/index index 1.0 add def % index++
grestore
} for
} def
%%%%%%%%%%%%%%%%%%%%%%%
%test script
200 600 moveto
.1 .9 100 10 VGrad
showpage
But GS raises an error:
GPL Ghostscript 8.70 (2009-07-31)
Copyright (C) 2009 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Error: /undefinedresult in --div--
Operand stack:
0 1 2 3 4 5 0.8 5.0 0.0
Execution stack:
%interp_exit .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval-- --nostringval-- --nostringval-- false 1 %stopped_push 1862 1 3 %oparray_pop 1861 开发者_StackOverflow中文版1 3 %oparray_pop 1845 1 3 %oparray_pop 1739 1 3 %oparray_pop --nostringval-- %errorexec_pop .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval-- 6 1 10 --nostringval-- %for_pos_int_continue --nostringval--
Dictionary stack:
--dict:1150/1684(ro)(G)-- --dict:0/20(G)-- --dict:75/200(L)--
Current allocation mode is local
Current file position is 588
GPL Ghostscript GPL Ghostscript 8.708.70: : Unrecoverable error, exit code 1
Unrecoverable error, exit code 1
where am I wrong ?
Your program will execute faster by using clever stack manipulation and CTM effects.
This is not a smooth gradient like yours, but executes much faster, and the functions are computed as one-line statements (which I just like better, can't explain why).
Also it's nice to post with usage and maybe a sample page (easy to trim when you don't need it, but when you do need it...??!!) Anyway, here's your program rewritten my way, FWIW.
As I said, the output it not as pretty in its current form. But you can modify the gradient by changing the gray-transfer function using currenttransfer
and settransfer
and/or change the calculation of the boxes to a logorithmic scaling, change the range and velocity of the grays. These things should be easier to see in "tighter" code. The stack comments help you to "check your understanding" at the end of each line.
Edit: I couldn't stop playing with it! I've factored out the loop and teased out some more parameters.
Edit: One more expansion. And how about a pretty picture?
%!
/box { % x y w h
4 2 roll moveto % w h
1 index 0 rlineto % w h
0 exch rlineto % w
neg 0 rlineto %
closepath
} def
/poly { % n
0.5 0 moveto
{ ? rotate 0.5 0 lineto } % n proc
dup 0 360 4 index div put % n {360/n...}
repeat
closepath
} def
% num-slices shapeproc matrix grayproc agrad -
% repeatedly (fill shape, concat matrix, transform currentgray)
/agrad {
3 dict begin /gray exch def /mat exch def /shape exch def
({ //shape exec //mat concat currentgray //gray exec setgray })
token pop exch pop end bind repeat
} def
/shapes [
{ -0.5 -0.5 1 1 box fill } %box shape
{ 0 0 0.5 0 360 arc fill } %circle shape
{ 0 0 0.5 0 180 arc fill } %fan shape
{ 5 poly fill } %pentagon
{ 6 poly fill } %hexagon
] def
/mats [
{1 index 2 exch div 1 exch sub dup matrix scale } %pyramid matrix
{1 index 2 exch div 1 exch sub 1 matrix scale } %horizontal matrix
{1 index 2 exch div 1 exch sub 1 exch matrix scale } %vertical matrix
] def
% mat-no shape-no gray0 grayF n x y w h dograd -
/dograd {
gsave
4 2 roll translate % m sh g0 gF n w h
scale % m sh g0 gF n
3 1 roll % m sh n g0 gF
1 index sub 2 index div % m sh n g0 (gF-g0)/n
[ exch /add cvx ] cvx % m sh n g0 grayproc
3 1 roll setgray % m sh grayproc n
3 -1 roll shapes exch get % m gray n shape
4 -1 roll mats exch get exec % gray n shape mat
4 -1 roll %n shape matrix gray
agrad
grestore
} def
%mat shape g0 gF n x y w h
0 4 .7 .1 20 300 400 600 800 dograd
0 0 0 1 10 100 650 200 200 dograd
1 1 0 1 20 300 650 200 200 dograd
2 2 .5 1 30 500 650 200 200 dograd
0 3 1 0 40 100 400 200 200 dograd
1 4 1 .5 50 300 400 200 200 dograd
2 1 .5 0 60 500 400 200 200 dograd
0 2 .1 .9 10 100 150 200 200 dograd
1 3 .2 .8 20 300 150 200 200 dograd
2 4 .3 .7 30 500 150 200 200 dograd
showpage
Ok, I found the problem: It seems that index is a reserved word. Here is a functional version:
/box
{
4 dict begin
/height exch def
/width exch def
/y exch def
/x exch def
x y moveto
width 0 rlineto
0 height rlineto
width -1 mul 0 rlineto
0 height -1 mul rlineto
end
} bind def
/gradient
{
4 dict begin
/height exch def
/width exch def
/y exch def
/x exch def
/i 0 def
height 2 div /i exch def
0 1 height 2 div {
1 i height 2.0 div div sub setgray
newpath
x
y height 2 div i sub add
width
i 2 mul
box
closepath
fill
i 1 sub /i exch def
}for
newpath
0 setgray
0.4 setlinewidth
x y width height box
closepath
stroke
end
} bind def
I didn't try to understand your code fully. But the error message tries to tell you that you are dividing by zero (look at the top element of the remaining operand stack: "0").
Just by adding "1" to your h
variable (insert 1 add
after h
) makes your PostScript program run through the Ghostscript interpreter and let it draw something (though that may not look like you envisaged....).
精彩评论