首页 > 其他分享 >PostScript学习心得

PostScript学习心得

时间:2024-05-27 14:00:42浏览次数:26  
标签:10 mm 学习心得 PostScript 指令 def exch

Table of Contents


网上有PostScript 的教程,并且还有参考手册,这里只是记录在学习该语言过程中的一些 心得体会。

学此语言主要是为了创建一个只带页码的 pdf,配合 pdftk 给输入 pdf 添加页码。当然, 加页码有其他手工方法,但我就是想找一个能够自动化的方式,考察之后选择使用 ps2pdf 和 PostScript 脚本的方式。关于使用 pdftk 修改 pdf 页码的方法可见上一篇文章。

学完之后,关于 PostScript 映像最深的是 "PostScript是面向堆栈的语言" 。这句话乍 一看也没什么,但在实践中才能领会其真义。

1. 语句表达是逆波兰式

"a * b" 在PostScript 表示成 " a b mul",非常便于操作数和操作符入栈。当然操作数和 操作符分别压入不同的栈,三个基本栈分别是操作数、操作符、字典。

2. 一些特别的符号

  • << k1 v1 k2 v2 … >> 表示字典
  • [ v1 v2 v3 … ] 表示数组
  • (abcde…) 表示字符串
  • { s1 s2 } 表示过程,也可表示数组,因为过程也是数组
  • % 表示注释
  • / 表示名字

3. 函数和过程可以看作 C 语言中的宏

PostScript 使用 def 来定义常量,也用其定义变量和过程," /fontsize 14 def " 定义 了一个名字是 fontsize 的常量。 " /tmpstr 6 string def " 定义了一个名字是 tmpstr 的变量, "/mm2inch { 72 mul 25.4 div } def " 定义了一个名字是 "mm2inch" 的函数。

函数的参数需要提前入栈,可以是上一步的结果自动入栈,也可以直接当作操作数写出来被 自动入栈。返回值同理,只要代码中的名字不是操作符或者前文定义的过程,就会被当作操 作数压入栈。

4. 执行脚本可以看作解析流的过程

换行并不重要,更多的是便于程序员阅读。解释器分析的脚本的过程中,大致是先将所有宏 (常量、函数)展开,然后是一个搜索操作符的过程,不是操作符的当作操作数压入栈,找 到的操作符需要参数的从栈中弹出,然后执行。

5. 栈平衡

写脚本的过程要非常关注栈平衡,否则执行结果就可能出问题。这里举例说明,下面定义了 一个函数,将一个数据传入,将数字对应的字符输出出来。PostScript 其实并不难,但在 写定个函数的过程中还是差点作出 PostScript 无法完成所需功能的判断而放弃学习。其中 注释了一个句子和正式使用句子有一些不同,搞明白其中道理基本上一通百通。

/num2glyph {
% 准备后面要用的临时变量,即将参数复制了几遍
    dup
    len -1 0 {
        pop
        dup
    } for len -1 0 {10 exch exp 2 -1 roll exch div floor cvi 10 mod glyphlist exch get glyphshow } for
%下面这句话值得研究
%len -1 0 { dup 10 exch exp exch 2 add -1 roll exch div floor cvi 10 mod } for 
} def 

注释的句子中求余数后未采取下一步动作,余数还在栈中, for 循环中下一步还要取之前 压入栈的数据,在使用 roll 指令时,第一个参数是通过 add 指令计算出来的,而正式使 用的句子中,由于求余后的数被后面的操作使用了,不存在于栈中,所以 for 循环中 roll 的每一个参数是固定值 2。

6. 调试

PostScript 是可以使用 gs 等可交互的解释器进行调试的,执行后指令后可以使用 stack 指令查看堆栈中的数据,从而判断指令参数等是否正确。

7. 中文字体

网上有贴子说要显示中文需要特殊字体并将文件存为 gb2312 编码。我是没有测试成功的, 最后阅读 PostScript 手册基本上肯定的一件事是,字体分成好几种,而我要使用的宋体是 不能使用 show 指令显示的,也无法使用 stringwidth 来计算显示字符串所需要的长度的。

我将宋体字体文件复制到与脚本一个文件夹,并在脚本中使用 "(simsun.ttc) 14 selectfont " 选择字体,同时 gs 命令要加参数 "-p", 这样就要以正常使用该字体了。

#这个句子可以将 input.ps 转换成 output.pdf
gs -P -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=output.pdf input.ps

关于使用 Unicode 编码,PostScript 不支持 " (我爱你) show " 或者 " (我爱你) glyphshow " 这种操作,原因是中文在脚本中的表示他并不了解,可以通过字符名称进行访 问,当然无法直接显示字符串。

所以,计算字符所占宽度,我也只是采用了取巧的方式,即在看不见的地方先记录所在位置, 然后将要输出的字符输出一遍,再查看当前位置,可计算出输出字符串所占长度。如果谁知 道更加优雅的方式,欢迎留言告知为谢。

8. 指令隐含的对栈的影响

一般情况,计算有结果的指令会将结果压入栈。

for 指令会在每一遍循环前将当前 index 压入栈。

stringwidth 和 currentpoint 计算结果是 wx 和 wy 两个数,均会压入栈。

拿不准的指令最好阅读手册去了解指令的参数和输出。

9. 示例程序

%!PS
/pagewidth_by_mm 210 def
/pageheight_by_mm 297 def
/left_margin_by_mm 28 def
/right_margin_by_mm  pagewidth_by_mm 26 sub def
/bottom_start_by_mm 24 def
/fontsize 14 def
/maxpagenum 20 def 

/mm2inch {
    72 mul 25.4 div
} def

/height_start {
    bottom_start_by_mm mm2inch
} def 

/pagewidth {
    pagewidth_by_mm mm2inch
} def

/pageheight {
    pageheight_by_mm mm2inch
} def

/left_start {
    left_margin_by_mm mm2inch
} def

/right_margin {
    right_margin_by_mm mm2inch
} def

<< /PageSize [pagewidth pageheight] >> setpagedevice
(simsun.ttc) fontsize selectfont
%/Helvetica 12 selectfont

/glyphlist [ /zero /one /two /three /four /five /six /seven /eight /nine ] def

/tmpstr {
    6 string
} def

/len {
    10 tmpstr cvrs length 1 sub
} def 

/glypharray {
    6 array
} def 

/num2glyph {
    dup
    len -1 0 {
        pop
        dup
    } for len -1 0 {10 exch exp 2 -1 roll exch div floor cvi 10 mod glyphlist exch get glyphshow } for
    %下面这句话值得研究
%len -1 0 { dup 10 exch exp exch 2 add -1 roll exch div floor cvi 10 mod } for 
} def 

/pstrlen {
    0 -50 moveto
    currentpoint
    pop
    exch
    /hyphenmonospace glyphshow
    num2glyph
    /hyphenmonospace glyphshow
    currentpoint
    pop
    exch
    sub
} def 

/mkpage {
    dup 
    dup
    2 mod 1 eq {
        pstrlen right_margin exch sub height_start moveto
    } {
        left_start height_start moveto
    } ifelse
    /hyphenmonospace glyphshow
    num2glyph
    /hyphenmonospace glyphshow
    showpage
} def

1 1 maxpagenum {
    mkpage 
} for 


本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议 进行许可。

标签:10,mm,学习心得,PostScript,指令,def,exch
From: https://www.cnblogs.com/bu-wu-zheng-ye/p/18215350

相关文章

  • 学习心得
    今天是从盒模型开始的学习,一直以来我最不理解的就是HTML的布局和排版,虽然也有过一些了解。但总感觉有些模糊,今天在学习的过程中逐渐搞清了关于盒模型里的一些排列,对于padding、border和margin到底是什么,以及在浏览器中的位置的具体显示,这些已经清楚了。对于位置上的判定目前大致......
  • 如何摆脱[自我/当下]而考虑到[别人/将来],从而主动为群体和将来行动 在学习通提交解
    培养同理心:尝试从他人的角度看待问题,理解他们的感受和需求。倾听他人:积极倾听并尊重他人的观点和意见,这有助于你更好地理解他们。拓宽视野:阅读、旅行和学习新事物可以帮助你了解不同的观点和文化。长期规划:设定长期目标,并考虑这些目标如何影响你的未来和他人。合作......
  • CSS-Grid网格布局学习心得
    CSS-grid属性:value(可选值):<'grid-template'>|<'grid-template-rows'>/[auto-flow&&dense?]<'grid-auto-columns'>?|[auto-flow&&dense?]<'grid-auto-rows'>/<'g......
  • 讨论 :银弹真的有用么? 在学习通提交解答的同时,可以同步发布在团队和个人博客上,作为
    银弹在项目管理和团队协作中是一种特殊的工具,其有效性和适用性取决于具体的团队和项目环境。这里是关于银弹的一些讨论点和考虑因素:优点:快速决策:当团队成员之间出现争执时,银弹可以帮助快速做出决策,避免争论持续下去,节省时间和精力。明确权威:银弹赋予特定角色(Dev/Test/PM)决策权,......
  • PostScript 是一种页面描述语言,最初由 Adobe 公司开发。它被设计用于描述页面的外观和
    PostScript的起源可以追溯到1982年,当时由Adobe公司的创始人之一约翰·沃诺克(JohnWarnock)和查尔斯·格什克(CharlesGeschke)共同开发。沃诺克和格什克当时都是在施乐帕克研究中心工作,他们在那里开始了对一种新的页面描述语言的研究和开发。当时的打印技术面临着一些挑战,......
  • Docker常用命令个人学习心得
    Docker的常用命令涵盖了容器的创建、管理、镜像的下载与推送等多个方面。1、镜像管理dockerps:列出所有正在运行的容器。dockerps-a:显示所有的容器,包括未运行的。dockertag[现有镜像名]:[现有标签][新镜像名]:[新标签]:为现有的镜像创建一个新的标签。dockerrmi[image......
  • HTML 学习心得
    前言超文本标记语言\(HyperTextMarkupLanguage\)简称\(HTML\),本质上是是一种用来结构化\(Web\)网页及其内容的标记语言。也算不上编程语言,是一种用于定义内容结构的标记语言,是由一堆堆的元素组成。正文下面才是正文啦\(HTML\)的代码一般是呈现下面的一种形式由白色......
  • C++算法学习心得八.动态规划算法(5)
    1.买卖股票的最佳时机(121题)题目描述:给定一个数组prices,它的第 i个元素 prices[i]表示一支给定股票第i天的价格。你只能选择某一天买入这只股票,并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取......
  • C++算法学习心得八.动态规划算法(4)
    1.零钱兑换(322题)题目描述:给定不同面额的硬币coins和一个总金额amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。你可以认为每种硬币的数量是无限的。示例 1:输入:coins=[1,2,5],amount=11输出:3解......
  • C++算法学习心得八.动态规划算法(3)
    1.最后一块石头的重量II(1049题)题目描述:有一堆石头,每块石头的重量都是正整数。每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x和 y,且 x<=y。那么粉碎的可能结果如下:如果 x==y,那么两块石头都会被完全粉碎;如果 x!=y,那么重量为 x 的......