PostScript——学习postscrip
本文转载自:https://www.cnblogs.com/wurui1994/p/6290969.html
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技术的,如PSTricks、TikZ /PGF、MetaPost以及Asymptote。Texample.net上有大量关于Tikz的例子。Asymptote官网也有大量 asy的例子。
2.简单例子
在学习之前,你需要两个软件:GhostScript和SumatraPDF。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图案的一个简单例子:
#include <math.h> #include <stdio.h> void init(FILE* fp) { int w=640,h=480; fputs("%!PS-Adobe-3.0 EPSF-3.0\n",fp); fprintf(fp,"%%%%BoundingBox: 0 0 %d %d\n",w,h); fputs("/rgb {setrgbcolor} def\n",fp); fputs("/np {newpath} def\n",fp); fputs("/cp {closepath} def\n",fp); fputs("/mt {moveto} def\n",fp); fputs("/ll {lineto} def\n",fp); fputs("/st {stroke} def\n",fp); fputs("/lw {setlinewidth} def\n",fp); fputs("/line {np mt ll st} def\n",fp); } void close(FILE* fp) { fputs("showpage\n%%EOF",fp); fclose(fp); } void line(FILE* fp,float x[],float y[],int n) { fprintf(fp,"0 0 1 rgb\nnp\n%.3f %.3f mt\n",x[0],y[0]); for(int i=1;i<n;i++){ fprintf(fp,"%.3f %.3f ll\n",x[i],y[i]); } fprintf(fp,"st\n"); } #define N 628 int main() { FILE* fp=fopen("main.ps","wb"); init(fp); // float x[N],y[N],t; for(int i=0;i<N;i++){ t=-3.14+i/100.0; x[i]=200*sin(3*t)*cos(t)+320; y[i]=200*sin(3*t)*sin(t)+240; } line(fp,x,y,N); // close(fp); return 0; }
如图所示,更多的例子可以看之前提到的四本书,三维绘图请看第四本数学图表:几何与PostScript手册:
另一个简单例子,可以作为一个练习,更多例子见星云的彼岸的GitHub:LearnPostScript。
3.复杂一点的例子
这个例子需要一点三维旋转矩阵的知识,代码仅作演示:
#include <math.h> #include <time.h> #include <stdio.h> #include <stdlib.h> #define Random rand()%255 #define Length(x) (sizeof(x)/sizeof(x[0])/3) const float PI=3.1415926536; typedef float vector3[3]; //三维点数组结构 typedef struct { int length; float *x, *y, *z; }PointArray ; // //三维点初始化 PointArray Array3d(int n) { PointArray r; r.length = n; r.x = (float*)malloc(n*sizeof(float)); r.y = (float*)malloc(n*sizeof(float)); r.z = (float*)malloc(n*sizeof(float)); for (int i = 0; i < n; i++) { r.x[i] = r.y[i] = r.z[i] = 0.0; } return r; } //三维点通过数组赋值 PointArray eval(float *a, int n) { PointArray r; r.length = n; r.x = (float*)malloc(n*sizeof(float)); r.y = (float*)malloc(n*sizeof(float)); r.z = (float*)malloc(n*sizeof(float)); for (int i = 0; i < n; i++) { r.x[i] = a[3*i]; r.y[i] = a[3*i + 1]; r.z[i] = a[3*i + 2]; } return r; } //输出三维点数组的数据 void print(PointArray r) { for (int i = 0; i < r.length; i++) { printf("%f %f %f\n", r.x[i], r.y[i], r.z[i]); } } // void fileprint(FILE* fp,PointArray r) { for (int i = 0; i < r.length; i++) { fprintf(fp,"%f %f ", r.x[i], r.y[i], r.z[i]); } fprintf(fp," quad\n"); } // //对三维点进行旋转 void Rotate(PointArray pa, vector3 vec,float t) { float x,y,z,a,b,c; float base=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]); a=vec[0]/base,b=vec[1]/base,c=vec[2]/base; for (int i = 0; i < pa.length; i++) { x=pa.x[i],y=pa.y[i],z=pa.z[i]; // pa.x[i]=(cos(t)+(1-cos(t))*a*a)*x+ ((1-cos(t))*a*b-sin(t)*c)*y+ ((1-cos(t))*a*c+sin(t)*b)*z; // pa.y[i]=((1-cos(t))*b*a+sin(t)*c)*x+ (cos(t)+(1-cos(t))*b*b)*y+ ((1-cos(t))*b*c-sin(t)*a)*z; // pa.z[i]=((1-cos(t))*c*a-sin(t)*b)*x+ ((1-cos(t))*c*b+sin(t)*a)*y+ (cos(t)+(1-cos(t))*c*c)*z; } } // void RotateX(PointArray pa,float t) { float x,y,z; for (int i = 0; i < pa.length; i++) { x=pa.x[i],y=pa.y[i],z=pa.z[i]; pa.x[i]=x; // pa.y[i]=y*cos(t)-z*sin(t); // pa.z[i]=y*sin(t)+z*cos(t); } } // void RotateY(PointArray pa,float t) { float x,y,z; for (int i = 0; i < pa.length; i++) { x=pa.x[i],y=pa.y[i],z=pa.z[i]; // pa.x[i]=z*sin(t)+x*cos(t); pa.y[i]=y; pa.z[i]=z*cos(t)-x*sin(t); } } // void RotateZ(PointArray pa,float t) { float x,y,z; for (int i = 0; i < pa.length; i++) { x=pa.x[i],y=pa.y[i],z=pa.z[i]; pa.x[i]=x*cos(t)-y*sin(t); pa.y[i]=x*sin(t)+y*cos(t); pa.z[i]=z; } } //透视投影 void Perspective(PointArray pa,float ez,float n,float f) { float x,y,z; for (int i = 0; i < pa.length; i++) { x=pa.x[i],y=pa.y[i],z=pa.z[i]; pa.x[i]=(ez-z)/(n-f)*x; pa.y[i]=(ez-z)/(n-f)*y; pa.z[i]=z; } } // static float yrot=45; // inline float fun(float x,float y) { //Matlab Peaks Function float z=3*(1-x)*(1-x)*exp(-x*x - (y+1)*(y+1)) - 10*(x/5 - x*x*x - y*y*y*y*y)*exp(-x*x-y*y) - 1.0/3*exp(-(x+1)*(x+1) - y*y); return z*10; } // void display() { float a[12]; PointArray ptsa,ptsb; float d=0.1,factor=50; float x,y,z1,z2,z3,z4; FILE* fp=fopen("main.ps","wb"); 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"); for(x=-3; x<3; x+=d) { for(y=-3; y<3; y+=d) { z1=fun(x,y); a[0]=x*factor,a[1]=z1,a[2]=y*factor; z2=fun(x+d,y); a[3]=(x+d)*factor,a[4]=z2,a[5]=y*factor; z3=fun(x+d,y+d); a[6]=(x+d)*factor,a[7]=z3,a[8]=(y+d)*factor; z4=fun(x,y+d); a[9]=x*factor,a[10]=z4,a[11]=(y+d)*factor; // ptsa=eval(a,Length(a)); RotateY(ptsa,yrot); RotateX(ptsa,15*2*PI/360); //ptsb=RotateZ(ptsb,6); fileprint(fp,ptsa); } } fprintf(fp,"\nshowpage\n%%%%EOF\n"); fclose(fp); yrot+=0.1; } int main() { display(); }
4.结束语
虽然越来越多的新技术涌现出来,但是它们都不是凭空产生的。PostScript作为一项古老的技术,对于文档的排版和印刷而言,依然是值得学习的。