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 这一对保存和还原图形状态的操作符

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

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

相关文章

OpenCV学习(4.15) 基于 GrabCut 算法的交互式前景提取

1. 目标 在这一章当中 我们将看到 GrabCut 算法来提取图像中的前景我们将为此创建一个交互式应用程序。 2. 理论 GrabCut 算法由英国剑桥微软研究院 Carsten Rother&#xff0c;Vladimir Kolmogorov和Andrew Blake发明&#xff0c;并在他们的论文“GrabCut”&#xff1a;使…

LLM之RAG实战(四十)| 使用LangChain SQL Agent和MySQL搭建多层RAG ChatBot

在传统的意义上&#xff0c;RAG 主要是从文档中检索用户想要的数据&#xff0c;从而提高大模型的能力&#xff0c;减少幻觉问题。今天&#xff0c;我们从另一个维度介绍RAG&#xff0c;RAG不从文档中获取数据&#xff0c;而是从MySQL数据库检索数据。我们可以使用LangChain SQL…

Vue40-vueComponent构造函数

一、组件的本质&#xff1a;VueComponent构造函数 组件的本质是&#xff1a;构造函数 二、每一次调用vue.extend&#xff0c;返回的事一个全新的 VueComponent VueComponent的源码如下&#xff1a; 三、组件中的this 组件中的this是VueComponent实例对象&#xff0c;结构和vm…

如果给电商系统颜值搞排名,我觉得淘宝千牛系统是天花板了。

淘宝的商家操作界面-千牛系统经过多年的迭代&#xff0c;无论从颜值上、功能上还是用户体验上都是行业天花板的存在&#xff0c;我截图软件上的一些图给大家分享下。

网络编程之XDP和TC

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

foxmai邮箱使用技巧图文板简单容易,服务器配置密钥配置

本人详解 作者&#xff1a;王文峰&#xff0c;参加过 CSDN 2020年度博客之星&#xff0c;《Java王大师王天师》 公众号&#xff1a;JAVA开发王大师&#xff0c;专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生&#xff0c;期待你的关注和支持&#xf…

手把手教你实现条纹结构光三维重建(2)——条纹解码

在第一讲中&#xff0c;我们讲到了条纹的生成&#xff0c;这一讲&#xff0c;我们将实现条纹的解码。我们这里的解码技术很简单&#xff0c;即高低频倍数解码&#xff0c;详细的论文可以参考&#xff1a;《Temporal phase unwrapping algorithms for fringe projection profilo…

基于 Transformer 的大语言模型

语言建模作为语言模型&#xff08;LMs&#xff09;的基本功能&#xff0c;涉及对单词序列的建模以及预测后续单词的分布。 近年来&#xff0c;研究人员发现&#xff0c;扩大语言模型的规模不仅增强了它们的语言建模能力&#xff0c;而且还产生了处理传统NLP任务之外更复杂任务…

4-字符串-11-反转字符串-LeetCode344

4-字符串-11-反转字符串-LeetCode344 LeetCode: 题目序号344 更多内容欢迎关注我&#xff08;持续更新中&#xff0c;欢迎Star✨&#xff09; Github&#xff1a;CodeZeng1998/Java-Developer-Work-Note 技术公众号&#xff1a;CodeZeng1998&#xff08;纯纯技术文&#xff0…

认识一些分布函数-Frechet分布及其应用

1. 何为Frechet分布 Frechet分布也称为极值分布(EVD)类型II,用于对数据集中的最大值进行建模。它是四种常用极值分布之一。另外三种是古贝尔分布、威布尔分布和广义极值分布(Gumbel Distribution, the Weibull Distribution and the Generalized Extreme Value Distributi…

亿达中国武汉园区入选“武汉市科技金融工作站”及“武汉市线下首贷服务站”

近日&#xff0c;武汉市2024科技金融早春行活动在深交所湖北资本市场培育基地举行。会上&#xff0c;第四批武汉市科技金融工作站试点单位名单及第五批武汉地区金融系统线下首贷服务站名单正式公布&#xff0c;武汉软件新城成功入选上述两个名单。 为缓解科技型企业融资难题&a…

vue2+echarts实现简易的2d地图效果

背景 公司的一个可视化数据大屏里面&#xff0c;有一个使用echarts实现的2d地图。不是我开发的&#xff0c;在此记录一下实现过程以及一些扩展解构。应该是从哪个航空航线图改动了一下&#xff0c;效果看起来还是可以的。 效果预览 版本 vue版本使用的是"^2.6.12"…

我要成为算法高手-双指针篇

目录 什么是双指针?问题1&#xff1a;移动零问题2&#xff1a;复写零问题3&#xff1a;快乐数问题4&#xff1a;盛最多水的容器问题5&#xff1a;有效三角形个数问题6&#xff1a;查找总价格和为目标值的两个商品(两数之和)问题7&#xff1a;三数之和问题8&#xff1a;四数之和…

私域流量新利器:大模型+智慧客服+知识智能多管齐下,效果倍增!

前言 随着互联网环境的发展&#xff0c;线上市场竞争日益激烈&#xff0c;越来越多的企业开始关注私域流量的运营和管理——将品牌的用户数据在品牌官网、微信公众号、APP等自有平台上进行管理和运营&#xff0c;通过与用户建立深入的关系和互动&#xff0c;提升用户黏性、增强…

LNMP搭建:Linux+Nginx+MySQL+PHP

关闭防火墙和核心防护&#xff0c;使用一台机器Node1搭建LNMP systemctl stop firewalld; setenforce 0 所需源码包&#xff1a;可以去官网下载 编译Nginx 创建/data&#xff0c;在/data/下放源码包 [rootNode1 ~]#:mkdir /data;cd /data 安装依赖包 [rootNode1 data]#:yum …

第一个SpringBoot程序

第一个SpringBoot程序 目录介绍 当我们创建了一个SpringBoot项目之后&#xff0c;会出现如下的目录结构 SpringBoot项⽬有两个主要的⽬录&#xff1a; src/main/java: Java源代码 src/main/resources:为静态资源或配置⽂件&#xff1a; /static&#xff1a;静态资源⽂件夹,⽐…

Spring Cloud Netflix 之 Ribbon

前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff1a;https://www.captainbed.cn/z ChatGPT体验地址 文章目录 前言前言1、负载均衡1.1、服务端负载均衡1.2、客户端负载均衡 2、Ribbon实现服务…

大模型企业落地:制造业可以选择的应用场景

前言 在当今制造业快速发展的背景下&#xff0c;设备稳定运行对于企业的发展至关重要。然而&#xff0c;传统的设备维修模式已无法满足现代企业的需求。为此&#xff0c;引入智能化、数字化的设备维修解决方案成为必然趋势。本文将探讨如何利用大模型技术&#xff0c;构建企业…

智慧工厂人员定位系统的影响与前景展望

随着科技的不断发展&#xff0c;智能制造正在迅速崛起&#xff0c;而智慧工厂人员定位系统作为其中的重要组成部分&#xff0c;正在改变传统制造业的面貌。这一系统通过利用物联网、室内定位等技术手段&#xff0c;能够实时准确地追踪和监控工厂内人员的位置。那么&#xff0c;…

数据采集项目2-业务数据同步

全量同步 每天都将业务数据库中的全部数据同步一份到数据仓库 全量同步采用DataX datax datax使用 执行 python /opt/module/datax/bin/datax.py /opt/module/datax/job/job.json 更多job.json配置文件在&#xff1a; 生成的DataX配置文件 java -jar datax-config-genera…