PostScript学习:另一种缩写为PS的技术

1.前言

  PostScript是一种编程语言,直译为"后处理脚本"[相对印刷过程而言],学名为页面描述语言。更为详细的解释见维基百科,以及其翻译版百度百科

  值得一提的是,PostScript于1985年由Adobe推出,而Adobe的软件Photoshop 1.0版本于1990发布,两者的缩写均为PS。虽然就知名度而言,PhotoShop更为人所熟知,但是在Adobe的发家史中,PostScript扮演着非常重要的作用,时至今日PostScript的衍生技术PDF已经是一项ISO标准。

  老实说,关于PostScript的基础知识,大家看维基百科的介绍以及附录的四本书就够了,四本书分别是:PostScript语言参考PostScript语言教程与手册PostScript程序设计数学图表:几何与PostScript手册 。本文只是介绍PostScript的简单绘图知识。

  大多数人开始接触PostScript大概是因为LaTeX,参考如何在论文中画出漂亮的插图?中 地铁风 的回答。LaTeX中常用的矢量图格式是EPS[Encapsulated PostScript],不过对PDF格式的支持应该是最好的。大多数与LaTeX相关的绘图与渲染都是基于PostScript技术的,如PSTricksTikZ /PGFMetaPost以及AsymptoteTexample.net上有大量关于Tikz的例子Asymptote官网也有大量 asy的例子

2.简单例子

  在学习之前,你需要两个软件:GhostScriptSumatraPDF。GhostScript是PostScript的一个开源解释器;SumatraPDF是一个文档阅读器,默认支持PDF,结合GhostScript可以支持PostScript。

  HelloWorld的例子,保存到文本文件HelloWorld.ps, 用SumatraPDF打开:

 %!PS
 /Courier                     % name the desired font
 20 selectfont              % choose the size in points and establish 
                                  % the font as the current one
 72 500 moveto           % position the current point at 
                                  % coordinates 72, 500 (the origin is at the 
                                  % lower-left corner of the page)
 (Hello world!) show     % stroke the text in parentheses
 showpage                  % print all on the page

  下面给出C语言生成PostScript图案的一个简单例子:

 1 #include <math.h>
 2 #include <stdio.h>
 3 void init(FILE* fp)
 4 {
 5     int w=640,h=480;
 6     fputs("%!PS-Adobe-3.0 EPSF-3.0\n",fp);
 7     fprintf(fp,"%%%%BoundingBox: 0 0 %d %d\n",w,h);
 8     fputs("/rgb {setrgbcolor} def\n",fp);
 9     fputs("/np {newpath} def\n",fp);
10     fputs("/cp {closepath} def\n",fp);
11     fputs("/mt {moveto} def\n",fp);
12     fputs("/ll {lineto} def\n",fp);
13     fputs("/st {stroke} def\n",fp);
14     fputs("/lw {setlinewidth} def\n",fp);
15     fputs("/line {np mt ll st} def\n",fp);
16 }
17 void close(FILE* fp)
18 {
19     fputs("showpage\n%%EOF",fp);
20     fclose(fp);
21 }
22 void line(FILE* fp,float x[],float y[],int n)
23 {
24     fprintf(fp,"0 0 1 rgb\nnp\n%.3f %.3f mt\n",x[0],y[0]);
25     for(int i=1;i<n;i++){
26         fprintf(fp,"%.3f %.3f ll\n",x[i],y[i]);
27     }
28     fprintf(fp,"st\n");
29 }
30 #define N 628
31 int main()
32 {
33 
34     FILE* fp=fopen("main.ps","wb");
35     init(fp);
36     //
37     float x[N],y[N],t;
38     for(int i=0;i<N;i++){
39         t=-3.14+i/100.0;
40         x[i]=200*sin(3*t)*cos(t)+320;
41         y[i]=200*sin(3*t)*sin(t)+240;
42     }
43     line(fp,x,y,N);
44     //
45     close(fp);
46     return 0;
47 }
View Code

  如图所示,更多的例子可以看之前提到的四本书,三维绘图请看第四本数学图表:几何与PostScript手册

  

   另一个简单例子,可以作为一个练习,更多例子见我的GitHub:LearnPostScript

  

3.复杂一点的例子

  这个例子需要一点三维旋转矩阵的知识,代码仅作演示:

  1 #include <math.h>
  2 #include <time.h>
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #define Random rand()%255
  6 #define Length(x) (sizeof(x)/sizeof(x[0])/3)
  7 const float PI=3.1415926536;
  8 typedef float vector3[3];
  9 //三维点数组结构
 10 typedef struct {
 11     int length;
 12     float *x, *y, *z;
 13 }PointArray ;
 14 //
 15 //三维点初始化
 16 PointArray Array3d(int n)
 17 {
 18     PointArray r;
 19     r.length = n;
 20     r.x = (float*)malloc(n*sizeof(float));
 21     r.y = (float*)malloc(n*sizeof(float));
 22     r.z = (float*)malloc(n*sizeof(float));
 23     for (int i = 0; i < n; i++) {
 24         r.x[i] = r.y[i] = r.z[i] = 0.0;
 25     }
 26     return r;
 27 }
 28 //三维点通过数组赋值
 29 PointArray eval(float *a, int n)
 30 {
 31     PointArray r;
 32     r.length = n;
 33     r.x = (float*)malloc(n*sizeof(float));
 34     r.y = (float*)malloc(n*sizeof(float));
 35     r.z = (float*)malloc(n*sizeof(float));
 36     for (int i = 0; i < n; i++) {
 37         r.x[i] = a[3*i];
 38         r.y[i] = a[3*i + 1];
 39         r.z[i] = a[3*i + 2];
 40     }
 41     return r;
 42 }
 43 //输出三维点数组的数据
 44 void print(PointArray r)
 45 {
 46     for (int i = 0; i < r.length; i++) {
 47         printf("%f %f %f\n", r.x[i], r.y[i], r.z[i]);
 48     }
 49 }
 50 //
 51 void fileprint(FILE* fp,PointArray r)
 52 {
 53     for (int i = 0; i < r.length; i++) {
 54         fprintf(fp,"%f %f ", r.x[i], r.y[i], r.z[i]);
 55     }
 56     fprintf(fp," quad\n");
 57 }
 58 //
 59 //对三维点进行旋转
 60 void Rotate(PointArray pa, vector3 vec,float t)
 61 {
 62     float x,y,z,a,b,c;
 63     float base=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
 64     a=vec[0]/base,b=vec[1]/base,c=vec[2]/base;
 65     for (int i = 0; i < pa.length; i++) {
 66         x=pa.x[i],y=pa.y[i],z=pa.z[i];
 67         //
 68         pa.x[i]=(cos(t)+(1-cos(t))*a*a)*x+
 69                 ((1-cos(t))*a*b-sin(t)*c)*y+
 70                 ((1-cos(t))*a*c+sin(t)*b)*z;
 71         //
 72         pa.y[i]=((1-cos(t))*b*a+sin(t)*c)*x+
 73                 (cos(t)+(1-cos(t))*b*b)*y+
 74                 ((1-cos(t))*b*c-sin(t)*a)*z;
 75         //
 76         pa.z[i]=((1-cos(t))*c*a-sin(t)*b)*x+
 77                 ((1-cos(t))*c*b+sin(t)*a)*y+
 78                 (cos(t)+(1-cos(t))*c*c)*z;
 79     }
 80 }
 81 //
 82 void RotateX(PointArray pa,float t)
 83 {
 84     float x,y,z;
 85 
 86     for (int i = 0; i < pa.length; i++) {
 87         x=pa.x[i],y=pa.y[i],z=pa.z[i];
 88 
 89         pa.x[i]=x;
 90         //
 91         pa.y[i]=y*cos(t)-z*sin(t);
 92         //
 93         pa.z[i]=y*sin(t)+z*cos(t);
 94     }
 95 }
 96 //
 97 void RotateY(PointArray pa,float t)
 98 {
 99     float x,y,z;
100     for (int i = 0; i < pa.length; i++) {
101         x=pa.x[i],y=pa.y[i],z=pa.z[i];
102         //
103         pa.x[i]=z*sin(t)+x*cos(t);
104         pa.y[i]=y;
105         pa.z[i]=z*cos(t)-x*sin(t);
106     }
107 }
108 //
109 void RotateZ(PointArray pa,float t)
110 {
111     float x,y,z;
112     for (int i = 0; i < pa.length; i++) {
113         x=pa.x[i],y=pa.y[i],z=pa.z[i];
114         pa.x[i]=x*cos(t)-y*sin(t);
115         pa.y[i]=x*sin(t)+y*cos(t);
116         pa.z[i]=z;
117     }
118 }
119 //透视投影
120 void Perspective(PointArray pa,float ez,float n,float f)
121 {
122     float x,y,z;
123     for (int i = 0; i < pa.length; i++) {
124         x=pa.x[i],y=pa.y[i],z=pa.z[i];
125         pa.x[i]=(ez-z)/(n-f)*x;
126         pa.y[i]=(ez-z)/(n-f)*y;
127         pa.z[i]=z;
128     }
129 }
130 //
131 static float yrot=45;
132 //
133 inline float fun(float x,float y)
134 {
135     //Matlab Peaks Function
136     float z=3*(1-x)*(1-x)*exp(-x*x - (y+1)*(y+1))
137             - 10*(x/5 - x*x*x - y*y*y*y*y)*exp(-x*x-y*y)
138             - 1.0/3*exp(-(x+1)*(x+1) - y*y);
139     return z*10;
140 }
141 //
142 void display()
143 {
144     float a[12];
145     PointArray ptsa,ptsb;
146     float d=0.1,factor=50;
147     float x,y,z1,z2,z3,z4;
148     FILE* fp=fopen("main.ps","wb");
149     fprintf(fp,"%%!PS-Adobe-3.0 EPSF-3.0\n%%%%BoundingBox: -250 -250 250 250\n/rgb {setrgbcolor} def\n/np {newpath} def\n/cp {closepath} def\n/mt {moveto} def\n/rmt {rmoveto} def\n/ll {lineto} def\n/rl {rlineto} def\n/st {stroke} def\n/lw {setlinewidth} def\n/line {np mt ll st} def\n/quad {np mt ll ll ll cp st} def\n0 0 1 rgb\n0.2 lw\n");
150     for(x=-3; x<3; x+=d) {
151         for(y=-3; y<3; y+=d) {
152             z1=fun(x,y);
153             a[0]=x*factor,a[1]=z1,a[2]=y*factor;
154             z2=fun(x+d,y);
155             a[3]=(x+d)*factor,a[4]=z2,a[5]=y*factor;
156             z3=fun(x+d,y+d);
157             a[6]=(x+d)*factor,a[7]=z3,a[8]=(y+d)*factor;
158             z4=fun(x,y+d);
159             a[9]=x*factor,a[10]=z4,a[11]=(y+d)*factor;
160             //
161             ptsa=eval(a,Length(a));
162             RotateY(ptsa,yrot);
163             RotateX(ptsa,15*2*PI/360);
164             //ptsb=RotateZ(ptsb,6);
165             fileprint(fp,ptsa);
166         }
167     }
168     fprintf(fp,"\nshowpage\n%%%%EOF\n");
169     fclose(fp);
170     yrot+=0.1;
171 }
172 int main()
173 {
174     display();
175 }
View Code

  

4.结束语

  虽然越来越多的新技术涌现出来,但是它们都不是凭空产生的。PostScript作为一项古老的技术,对于文档的排版和印刷而言,依然是值得学习的。

  

 

posted @ 2017-01-16 20:24  星云的彼岸  阅读(9139)  评论(0编辑  收藏  举报