PDF标准详解(三)—— PDF坐标系统和坐标变换

之前我们了解了PDF文档的基本结构,并且展示了一个简单的hello world。这个hello world 虽然只在页面中显示一个hello world 文字,但是包含的内容却是不少。这次我们仍然以它为切入点,来了解PDF的坐标系统以及坐标变换的相关知识

图形学中二维图形变换

中学我们学习了平面直角坐标系,x轴沿着水平方向从左往右递增,Y轴沿着竖直方向,从下往上坐标递增。而PDF的坐标系与数学中的坐标系相同。但是PDF的坐标是有单位的,PDF的坐标单位为磅,一般来说他们与英寸等的转化关系为
1 磅 = 1/72 英寸
因为PDF需要做到设备无关,也是就是在不同的显示像素和打印机上,显示的长度都一致,所以这里不能采用像素做单位。但是我们可以通过相关的接口来将这个单位转化为像素。例如在Windows平台可以通过下列的代码来获取一英寸有多少像素

HDC hdc = GetDC(NULL);
short cxInch = GetDeviceCaps(hdc, LOGPIXELSX);
short cyInch = GetDeviceCaps(hdc, LOGPIXELSY);
ReleaseDC(NULL, hdc);

对于我的显示器来说,水平和竖直方向都是 1英寸=96像素

有了这些概念之后,我们来看一个例子,下面是在页面的(200, 200) 位置画一个 长宽都为100的正方形

3 0 obj % 页面内容流
<< >>
stream % 流的开始
200 200 100 100 re S
endstream % 流结束
endobj

之前说过,页面显示内容在页面流中,因此这里我们将内容放置到页面流对象中。前面的200 200 是矩形的起始位置。后面的100 100 分别是长和宽。re 代表我们要构建一个矩形,最后的S表示要显示这个图形。严格意义上来说,re 和S都是路径构造所使用的操作符。这里的矩形也不单单是一个图形,它是一个路径。关于他们的概念将在后面继续介绍。下面我们来介绍基本的2D图形变换

平移

平移

假设一个点原始坐标是(x1, x2),那么沿着x轴平移a,y轴平移b,那么平移之后点的坐标为 (x1 + a, x2 + b) ,转换成矩阵就是
[ x y 1 ] [ 1 0 0 0 1 0 a b 1 ] = [ x + a y + b 1 ] \begin{bmatrix} x & y & 1\end{bmatrix} \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ a & b & 1 \end{bmatrix} = \begin{bmatrix}x + a & y + b & 1\end{bmatrix} [xy1] 10a01b001 =[x+ay+b1]

旋转

旋转
利用中学的知识可以知道
x 1 = r ∗ c o s ( θ + ψ )   = r ∗ ( c o s θ ∗ c o s ψ − s i n θ ∗ s i n ψ )   = x ∗ c o s θ − y s i n θ x_1 = r * cos(\theta+\psi) \ = r*(cos\theta*cos\psi-sin\theta*sin\psi) \ = x*cos\theta-ysin\theta x1=rcos(θ+ψ) =r(cosθcosψsinθsinψ) =xcosθysinθ

同理,我们可以得到
y 1 = r ∗ s i n ( θ + ψ )   = r ∗ ( s i n θ ∗ c o s ψ + c o s θ ∗ s i n ψ )   = x ∗ s i n θ + y ∗ c o s θ y_1 = r * sin(\theta+\psi) \ = r * (sin\theta*cos\psi+cos\theta*sin\psi)\ = x*sin\theta+y*cos\theta y1=rsin(θ+ψ) =r(sinθcosψ+cosθsinψ) =xsinθ+ycosθ

转换成矩阵就是
[ x y 1 ] [ c o s θ s i n θ 0 − s i n θ c o s θ 0 0 0 1 ] = [ x ∗ c o s θ − y ∗ s i n θ x ∗ s i n θ + y ∗ c o s θ 1 ] \begin{bmatrix} x & y & 1\end{bmatrix} \begin{bmatrix} cos\theta & sin\theta & 0 \\ -sin\theta & cos\theta & 0 \\ 0 & 0 & 1 \end{bmatrix} = \begin{bmatrix}x*cos\theta - y*sin\theta & x*sin\theta+y*cos\theta & 1\end{bmatrix} [xy1] cosθsinθ0sinθcosθ0001 =[xcosθysinθxsinθ+ycosθ1]

缩放

缩放就是将坐标扩大或者缩小为原来的多少倍,我们可以很清楚的知道
x 1 = x ∗ a y 1 = y ∗ b x_1=x*a y_1=y*b x1=xay1=yb

这里的a和b都是缩放的系数
利用矩阵表示就是
[ x y 1 ] [ a 0 0 0 b 0 0 0 1 ] \begin{bmatrix} x & y & 1\end{bmatrix} \begin{bmatrix} a & 0 & 0 \\ 0 & b & 0 \\ 0 & 0 & 1\end{bmatrix} [xy1] a000b0001

pdf 矩阵变换

还有另外几种变换,这里就不一一列举了。现在我们知道二维图形的变换使用一个矩阵就能进行描述。所以PDF在变换图形的时候直接使用的是变换的矩阵。另外我们观察到对于二维变换来说,最后一列一直都是 0 0 1这三个数字。所以pdf中设置变换矩阵时忽略最后一列,仅仅保留前两列,采用6个数字
[ a b 0 c d 0 e f 1 ] \begin{bmatrix}a & b & 0 \\ c & d & 0 \\ e & f & 1\end{bmatrix} acebdf001

这个矩阵在PDF中表现为 a b c d e f。

回到我们之前hello的例子中,我们在 hello world 字符流开始的时候,给定了几个数字
1. 0. 0. 1. 50. 700. cm
各个数字之间采用空格隔开,这里数字后面跟的点表示它是一个浮点数。我们可以将这一列数字写成如下的矩阵
[ 1.0 0.0 0 0.0 1.0 0 50.0 700.0 1 ] \begin{bmatrix}1.0 & 0.0 & 0 \\ 0.0 & 1.0 & 0 \\ 50.0 & 700.0 & 1 \end{bmatrix} 1.00.050.00.01.0700.0001

这个矩阵我们叫做当前变换矩阵 (Current Transformation Matrix CTM),最后的cm表示使用该矩阵进行图形变换。它是current matrix 的缩写

所以上述这一串数值的意思就是将 hello world 这个字符串平移到页面坐标 (50, 700) 的位置

PDF 中控制图形变换的操作符

现在我们利用这个上述知识来做一个小练习。我们将一个长宽都为100 的矩形在 (200, 200) 位置逆时针旋转45°
绕任意点旋转,可以先将该点移动到坐标原点,然后按照坐标原点的进行旋转的公式进行计算,最后再将坐标点平移回原来的位置。这个过程产生3个变换矩阵

平移矩阵
[ 1 0 0 0 1 0 − C x − C y 1 ] \begin{bmatrix}1 & 0 & 0 \\ 0 & 1 & 0 \\ -C_x & -C_y & 1\end{bmatrix} 10Cx01Cy001

旋转矩阵
[ c o s θ s i n θ 0 − s i n θ c o s θ 0 0 0 1 ] \begin{bmatrix}cos\theta & sin\theta & 0 \\ -sin\theta & cos\theta & 0 \\ 0 & 0 & 1\end{bmatrix} cosθsinθ0sinθcosθ0001

平移矩阵
[ 1 0 0 0 1 0 C x C y 1 ] \begin{bmatrix}1 & 0 & 0 \\ 0 & 1 & 0 \\ C_x & C_y & 1\end{bmatrix} 10Cx01Cy001

我们将这三个矩阵相乘
[ 1 0 0 0 1 0 − C x − C y 1 ] ∗ [ c o s θ s i n θ 0 − s i n θ c o s θ 0 0 0 1 ] ∗ [ 1 0 0 0 1 0 C x C y 1 ] \begin{bmatrix}1 & 0 & 0 \\ 0 & 1 & 0 \\ -C_x & -C_y & 1\end{bmatrix} * \begin{bmatrix}cos\theta & sin\theta & 0 \\ -sin\theta & cos\theta & 0 \\ 0 & 0 & 1\end{bmatrix} * \begin{bmatrix}1 & 0 & 0 \\ 0 & 1 & 0 \\ C_x & C_y & 1\end{bmatrix} 10Cx01Cy001 cosθsinθ0sinθcosθ0001 10Cx01Cy001

最终得到这样一个矩阵
[ c o s θ s i n θ 0 − s i n θ c o s θ 0 C x − C x c o s θ + C y s i n θ C y − C x s i n θ − C y c o s θ 1 ] \begin{bmatrix}cos\theta & sin\theta & 0 \\ -sin\theta & cos\theta & 0 \\ C_x - C_xcos\theta+C_ysin\theta & C_y-C_xsin\theta-C_ycos\theta & 1\end{bmatrix} cosθsinθCxCxcosθ+CysinθsinθcosθCyCxsinθCycosθ001
因此这里可以这样写

3 0 obj     % 页面内容流
<< >>
stream      % 流的开始
200 200 100 100 re S %原始矩形
0.7 0.7 -0.7 0.7 200 -80 cm%进行坐标变换
200 200 100 100 re S %变换后的矩形
endstream   % 流结束
endobj

这样我们可以得到如下所示的图形
在这里插入图片描述
这个时候我们会发现,同样是(200, 200) 的位置,在变换前和变换后,得到不一样的图形,这就说明我们的坐标系统被改变了。不再是水平和竖直方向的x y轴了。如果我们想要它变回原来的位置该怎么办?

在GDI或者其他框架的图形编程中,在改变画笔、画刷等图形状态的时候,会首先保存原来的,然后更新,最后再还原。同样在PDF中,也存在有这样的保存和还原的操作符。我们使用q/Q这么一对操作符来完成保存和还原的操作。

我在原来的基础上,再加一个矩形,在(400, 400) 位置画一个长宽都是100的矩形

3 0 obj     % 页面内容流
<< >>
stream      % 流的开始
200 200 100 100 re S %原始矩形
0.7 0.7 -0.7 0.7 200 -80 cm%进行坐标变换
200 200 100 100 re S %变换后的矩形
400 400 100 100 re S % 这个矩形是相对于 (200, 200) 这个点旋转了45°的矩形
endstream   % 流结束
endobj

我们再采用q/Q这一对操作符来保存和还原图形状态

3 0 obj     % 页面内容流
<< >>
stream      % 流的开始
200 200 100 100 re S %原始矩形
q
0.7 0.7 -0.7 0.7 200 -80 cm%进行坐标变换
200 200 100 100 re S %变换后的矩形
Q
400 400 100 100 re S 
endstream   % 流结束
endobj

这个时候我们发现它已经在(400, 400) 这个位置画了一个矩形。没有任何的图形变换

PDF中将图形状态保存成一个栈结构,每次执行q就是将当前图形状态进行入栈,使用Q将之前保存在栈顶的图形状态进行出栈,并还原成当前图形状态。一般来说q/Q必须成对出现。
好了,本节到这里就结束了。本节主要介绍了图形变换矩阵以及PDF中变换矩阵的操作符cm以及q/Q 这一对保存和还原图形状态的操作符

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/710823.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

利用Cesium和JS实现地点点聚合功能

引言 在实现基于地图的业务场景时&#xff0c;当地图上需要展示过多的标记点时&#xff0c;大量的分散点会使地图上显得杂乱无章&#xff0c;导致标记点对地图上的其他重要信息造成遮挡和混淆&#xff0c;降低地图整体的可读性。 标记点的聚合就很好的解决了这些痛点的同时&a…

线性规划问题——单纯形算法

第一步&#xff1a;化“约束标准型” 在每个等式约束中至少有一个变量的系数为正&#xff0c;且这个变量只在该约束中出现。在每个约束方程中选择一个这样的变量称为基本变量。 剩下变量称为非基本变量。 一个简单的栗子 上图是一个约束标准型线性规划的例子。 等式1&#x…

几款让你怦然心动的神奇工具——搜嗖工具箱

alteredqualia AlteredQualia 脑洞爆炸器网站&#xff0c;不得不说这是一个神奇的网站&#xff0c;在这个网站上你可以实现不可思议的各种操作&#xff0c;让我们对网站有了新的认知&#xff0c;因为它告诉你不是所有有趣的网站都那么花哨&#xff0c;有些网站看着外形平淡无奇…

AI实践与学习5-AI解题场景RAG应用预研demo

背景 AI解题场景现状&#xff0c;教研测评文档&#xff1a;xxx 解题正确率仍需进一步提高&#xff0c;提示词优化方案基本无力o目前配置的易错题CoT示例支持的长度有限&#xff0c;后续题量大的时候配置具有局限性。某些英语翻译题型BAD CASE反映大模型的输出格式不太符合要求…

设置sqlserver management的字体大小

在用sqlserver management的时候&#xff0c;总感觉怪怪的&#xff0c;然后发现是字体太小的原因。 1&#xff09;设置一下字体&#xff0c;工具--选项&#xff1a; 2&#xff09;环境--字体和颜色--显示其设置&#xff08;环境&#xff09; 3&#xff09;选择微软雅黑&#xf…

在Kubernetes中部署Elasticsearch高可用集群详细教程

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

btrace:binder_transaction+eBPF+Golang实现通用的Android APP动态行为追踪工具

一、简介&#xff1a; 在进行Android恶意APP检测时&#xff0c;需要进行自动化的行为分析&#xff0c;一般至少包括行为采集和行为分析两个模块。其中&#xff0c;行为分析有基于规则、基于机器学习、基于深度学习甚至基于大模型的方案&#xff0c;各有各的优缺点&#xff0c;不…

Photoshop中颜色与色调的调整

Photoshop中颜色与色调的调整 Photoshop中的颜色模式RGB模式灰度模式位图模式索引模式CMYK模式Lab模式 Photoshop中的颜色/色调调整命令颜色/色调调整命令的分类亮度/对比度调整命令色阶命令曲线命令曝光度命令自然饱和度命令色相/饱和度命令色彩平衡命令照片滤镜调整命令通道混…

一篇文章教你学会公众号IP写作(新手小白必备)

最近在带大家玩公众号 IP 写作&#xff0c;很多新手小白常问的问题&#xff0c; 1 什么是IP写作&#xff1f; “IP写作&#xff0c;简单来说&#xff0c;就是通过在公众号上持续写出有价值的文章&#xff0c;来建立个人影响力。 让读者了解你、信任你、找你付费。实现高价值、强…

MySQL之优化服务器设置(二)

优化服务器设置 InnoDB事务日志(包含:Redo log 重做日志和Undo log回滚日志) 了解清楚"把日志缓冲写到日中文件"和"把日志刷新到持久化存储"之间的不同是很重要的。在大部分操作系统中&#xff0c;把缓冲写到日志只是简单地把数据从InnoDB的内存缓冲转移…

MySQL中的正排/倒排索引和DoubleWriteBuffer

正排/倒排索引 正排索引 文档1&#xff1a;词条A&#xff0c;词条B&#xff0c;词条C 文档2&#xff1a;词条A&#xff0c;词条D 文档3&#xff1a;词条B&#xff0c;词条C&#xff0c;词条E正排表是以文档的ID为关键字&#xff0c;表中记录文档中的每个字的位置信息&#xff…

人事信息管理系统(Java+MySQL)

一、项目背景 在现代企业中&#xff0c;管理大量员工的工作信息、薪资、请假、离职等事务是一项非常繁琐和复杂的任务。传统的手工管理方式不仅效率低下&#xff0c;而且容易出错。为了提高人事管理的效率&#xff0c;减少人工操作带来的错误&#xff0c;企业迫切需要一个高效…

怎样收集企业名单?

收集企业名单的方法按照不同维度有不同的方式&#xff0c; 通过人工一个个收集&#xff0c;通过技术手段收集&#xff0c;通过第三方进行购买。 按照来源渠道&#xff0c;可以分为官方和非官方网站&#xff0c;官方的有公示系统&#xff0c;年报等。此外一些相对于官方的平台…

论文阅读笔记:DepGraph: Towards Any Structural Pruning

论文阅读笔记&#xff1a;DepGraph: Towards Any Structural Pruning 1 背景2 创新点3 方法4 模块4.1 分组4.2 依赖图4.3 网络分解4.4 依赖建模4.4 组级剪枝 5 效果 论文&#xff1a;https://arxiv.org/pdf/2301.12900 代码&#xff1a;https://github.com/VainF/Torch-Prunin…

Anaconda环境安装失败的解决方案

链接步骤的补充。 为了运行marlib&#xff0c;需要一个全新的Anaconda环境。但是&#xff0c;不想把文件安装在C盘&#xff0c;会造成空间不足。于是试着在.condarc文件里面改动了路径&#xff0c;具体如图。 上图中&#xff0c;在defaults前面添加了D盘的路径作为安装路径。 …

docker环境中配置phpstorm php xdebug调试工具

本文介绍通过docker compose的使用方式 第一步&#xff1a;在php镜像中安装phpxdebug扩展&#xff0c;比如php7.4对应的是xdebug3.1.6 第二步&#xff1a;设置项目中的docker-compose.yml docker-compose 增加开启xdebug的环境变量,host.docker.internal是宿主机的地址&#…

错题记录(小测)

单选 错题1 错题2 错题3 代码题 反转链表 链表的回文结构

java第二十三课 —— 继承

面向对象的三大特征 继承 继承可以解决代码复用&#xff0c;让我们的编程更加靠近人类思维&#xff0c;当多个类存在相同的属性&#xff08;变量&#xff09;和方法时&#xff0c;可以从这些类中抽象出父类&#xff0c;在父类中定义这些相同的属性和方法&#xff0c;所有的子…

利用flask + pymysql监测数据同步中的数据是否完整

一、背景 最近项目搞重构&#xff0c;将原有的系统拆分成了多个子系统。但是有数据表需要在不同系统中数据&#xff0c;同时为了解决项目性能最了一个很简单的方案&#xff0c;就是公共数据存在每个系统之中。 二、分析 分析这些表&#xff0c;这些表相比源数据表&#xff0c;表…

网络编程之XDP和TC

一、TC之于XDP 在前面分析过XDP&#xff0c;今天简单分析一下与其相关的TC&#xff0c;即traffic control,流量控制。在分析XDP时知道其只能用于ingress方向触发&#xff0c;而TC却可以在两个方向即ingress和egress方向触发。也可以简单理解成它可以同时钩住进出两个方向的数据…