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

news2024/11/29 11:44:44

之前我们了解了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 % 这个矩形是相对于 (400, 400) 这个点旋转了45°的矩形
endstream   % 流结束
endobj

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络安全从入门到精通(特别篇I):应急响应案例

蓝队应急响应实战 1. 应急响应1. 应急响应 获取当前WEB环境的组成架构(语言,数据库,中间件,系统等) 分析思路: 1、利用时间节点筛选日志行为 2、利用已知对漏洞进行特征筛选 3、利用后门查杀进行筛选日志行为 #内容点: 应急响应: 1、抗拒绝服务攻击防范应对指南 2、勒…

小分子水半幅宽检测 低氘水同位素氘检测 富氢水检测

小分子水半幅宽检测 低氘水同位素氘检测 富氢水检测 检测范围: 矿泉水等饮用水 检测概述 小分子团水活化性很强&#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…

Java面试题--JVM大厂篇之掌握JVM性能优化:选择合适的垃圾回收器

掌握JVM性能优化&#xff1a;选择合适的垃圾回收器 引言: ​  在Java开发中&#xff0c;性能优化往往是提高应用稳定性和用户体验的关键所在。而垃圾回收器的选择和优化&#xff0c;是JVM性能调优的核心环节。如何在众多垃圾回收器中选出适合自己应用需求的那一个&#xff1…

6581 太阳能电池板伏安特性测试仪

6581 太阳能电池板伏安特性测试仪 产品综述 6581太阳能电池板伏安特性测试仪主要用于太阳能电池板生产的最终测试&#xff0c;也可以作为层压前测试使用&#xff0c;能大大提高一次封装成品率。该测试仪适合于单晶、多晶、薄膜等多种电池组件&#xff0c;可进行I-V曲线、P-…

进口二手RS FSH4规格3.6G罗德与施瓦茨 FSH6参数

Rohde & Schwarz FSH4 的规格包括&#xff1a; 频率范围从 9 kHz 到 3.6 GHz 高灵敏度&#xff08;<-141dBm&#xff08;1Hz&#xff09;&#xff0c;或使用可选前置放大器<-161dBm&#xff08;1Hz&#xff09;&#xff09; 低测量不确定度&#xff08; 内部跟踪发生…

算法day31

第一题 542. 01 矩阵 本题本来求解的是每一个1到0的最短距离并返回到矩阵之中&#xff1b; 我们采用正难则反的思路&#xff0c;将其化解为每一个0到每一个1的最短距离&#xff0c;并通过矩阵来返回&#xff1b; 解法&#xff1a;多源bfs正难则反 步骤一&#xff1a; 定义一个…

僵尸网络相关

个人电脑被植入木马之后&#xff0c;就会主动的连接被黑客控制的这个C&C服务器&#xff0c;然后这个服务器就会给被植入木马的这个电脑发指令&#xff0c;让他探测在他的局域网内还有没有其他的电脑了&#xff0c;如果有那么就继续感染同局域网的其他病毒&#xff0c;黑客就…

基于单片机的无人监守点滴控制系统设计

摘要 &#xff1a; 在当代社会 &#xff0c; 点滴是一种常用的诊疗方法 。 为了减轻医护人员的压力 &#xff0c; 设计了一种基于单片机的无人监守点滴控制系统&#xff0c; 该系统共由 2 个板子组成 &#xff0c; 其中一个主控板子 &#xff0c; 一个检测板子 。 检测板与…

maven编译【-Dmaven.test.skip=true和-DskipTests=true的区别】

1、背景 我在执行maven编译时&#xff0c;遇到下面情况&#xff1a; 1、当执行命令为下面&#xff1a; mvn clean compile package install -Dmaven.wagon.http.ssl.insecuretrue -Dmaven.wagon.http.ssl.allowalltrue -Dmaven.wagon.http.ssl.ignore.validity.datestrue -Dra…

救命!挖到宝了,这本计算机书真的巨巨好看

一本适合大学生使用的计算机科学和编程学习指南&#xff0c;它通过丰富的内容和多样的学习形式&#xff0c;帮助学生建立坚实的计算机科学基础&#xff0c;并激发他们对计算机科学的兴趣。 这本书涵盖了多种类型的练习题&#xff0c;旨在帮助读者巩固理论知识并提高实际编程技能…

PostgreSQL下载地址

下载地址&#xff1a;PostgreSQL: File Browser

深入理解ReentrantLock

深入理解ReentrantLock 在Java并发编程中&#xff0c;锁&#xff08;Lock&#xff09;是控制多个线程对共享资源访问的重要工具。虽然Synchronized关键字是实现锁的常用方式&#xff0c;但它在功能上比较有限。ReentrantLock是java.util.concurrent.locks包中提供的一个更加灵…

Python基础教程(十九):网络编程

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

【吊打面试官系列-Mysql面试题】实践中如何优化 MySQL?

大家好&#xff0c;我是锋哥。今天分享关于 【实践中如何优化 MySQL&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 实践中如何优化 MySQL&#xff1f; 最好是按照以下顺序优化&#xff1a; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 1、SQL 语…

组件化框架 ARouter 完全解析(一)

一、路由认知 ARouter从命名即可知&#xff0c;这是一个路由框架。那么路由是个啥呢&#xff1f; 路由&#xff08;routing&#xff09;就是通过互联的网络把信息从源地址传输到目的地址的活动。-- 百科 可见 路由 是个动词&#xff0c;这是网络传输中的概念&#xff0c;完成路…

跨境电商测评、采购大额下单自养号需要解决哪些技术原理?

市场上有许多伪装工具&#xff0c;但大多数只是为了方便开发人员测试系统程序&#xff0c;它们并不能针对特定的电商平台进行伪装。每个电商平台都有其独特的风控机制&#xff0c;因此&#xff0c;我们需要从硬件环境的底层配合软件控制&#xff0c;以满足各平台的检测规则。 …

Spring boot 使用AbstractRoutingDataSource实现数据源动态切换

目录 一、AbstractRoutingDataSource 二、具体实现 1、pom.xml 2、新建UserMapper 3、在spring boot 启动类上添加扫描mapper注解 4、在配置文件 application.properties 中添加多个(我这里是两个)数据源的配置信息 5、集成动态数据源模块 5.1、新建注解 CurDataSource…

【复旦邱锡鹏教授《神经网络与深度学习公开课》笔记】梯度的反向传播算法

矩阵微积分&#xff08;Matrix Calculus&#xff09; 在开始之前&#xff0c;需要先了解矩阵微积分的一些计算规则。 首先&#xff0c;对于矩阵微积分的表示&#xff0c;通常由两种符号约定&#xff1a; 分母布局 标量关于向量的导数为列向量 向量关于标量的导数为行向量 N维…

C# Winform Datagridview查询项目实例

在项目中&#xff0c;我们经常要遇到查询和展示内容&#xff0c;常用的做法是通过文本框&#xff0c;时间控件&#xff0c;按键和datagridview查询和展示内容。下面是一个常见的综合实例&#xff0c;并支持Excel(csv)导入导出&#xff0c;表格列动态调整的功能。 实例代码链接&…