工程图PDF标题栏与目录生成器
生成PDF工程图,合并PDF文件,添加文字、图片与自定义标题栏,并生成目录。
PDF, 工程图, 标题栏, 浏览器程序
--by Captdam @ 2024-09-21 02:40 GMT edited[en] Here is the English version of this article
Also on GitHub: https://github.com/captdam/DrawingTitleblock
起因
我在工作中时常需要绘制机械施工图纸。虽然我所使用的SoldWorks与Fusion在建模上没有什么问题,但是它们对图纸的标题栏的支持却有限。
工作中我最早接触使用的CAD是SolidWorks。在制作工程图时,我首先选择一张空白的工程图模板,接下来再添加结构与零件。SolidWorks提供了一些可以插入标题栏的参数,例如当前页码、总页数、作者。但是,这里也有不少限制:
- 页码必须从1开始,但是我想要把封面页设置为第0页。
- 所有页的更新时间这个参数会都被设置为工程图文件的最后修改时间。我的习惯是每一页包含一个结构或零件,而那一页的修改时间最好可以显示那个结构或零件的修改时间。但是这不支持。
- 不能自动生成目录列表,必须手动制作,耗时耗力还容易出错。
之后公司为了节约成本换成了Fusion。Fusion在制图方面比SolidWorks更难用,除了上面这些问题以为,Fusion还:
- 更少的可选的参数。也没办法建立自定义参数。
第一次尝试
在网上冲浪寻找制作SolidWorks与Fusion的标题栏的方法后,我果断放弃了。与其花时间死磕,不如另辟蹊径自己造车。我决定写一个程序来帮我制作工程图的标题栏。
我在网上找到了一个可以帮我编辑PDF的JS库PDF-Lib,于是我就基于这个库写了一个Web app,我觉得Web app很合适,因为有这些优势:
- 基本任何有浏览器的电脑都能跑。如果一台电脑可以跑CAD,那跑这个程序基本也就无压力了。
- 使用HTML与CSS可以轻松写出GUI,而且我搞了这么久Web也对这些很熟了,开发起来很简单。
- 不需要服务器端,不需要上传,一切都在本地。对于工程图来说,保密性也很重要。
现在,我将让CAD生成不带标题栏的图纸(或者只包括零件比例)。我将使用我自己写的这个程序来添加标题栏制作最终的施工图。
作为第一次尝试,这个程序将执行这些步骤:
- 导入图纸文件PDF,两张图片(公司与客户的商标)和目录文件CSV。
- 为图纸文件的每一页添加标题栏。首先使用一些列的包含在这个程序里面的SVG绘图指令画出标题栏的框架。然后再从目录文件中读取每一页的信息,例如工程名、零件名、修改日期、作者,并写在特定位置(具体书写的位置则在程序代码中定义了)。接下来,特定位置添加商标图片。最后,插入一个+1计数器作为页码。
- 在文件开头插入一张空白页并添加标题栏与信息等。接下来,使用特定规则通过目录文件中信息生成目录列表。
下面展示了工程图原图、目录与带有标题栏的最终完成图:
第二次尝试
第一次尝试写出来的程序能够生成我想要的图纸,但是这个程序的设计和代码一点也不优雅,也有很多限制。
- 只支持固定的参数,并且参数的位置大小等都是写死在程序代码里面的。要添加或者修改参数规则的话就要改程序代码。
- 支持且只支持两张作为logo的图片。况且,我们每次都会有公司logo,但是每次使用这个程序还得重新选择插入这个图片,确实麻烦。并且,我们也希望在需要时能添加更多图片。
- 使用写死在程序代码里面的SVG生成标题栏框架,并且只支持一个标题栏。在这里,我最先的想法是使用SVG图片,但是PDF-Lib这个库没有原生支持。
- 只支持一个工程图文件。最好我们可以合并多张工程图,特别是我们需要引用外部工程图或是需要合并多张子项目图纸的时候。
我重写这个程序不仅是为了让这个程序更适用,也是为了解决Fusion的一些问题。
对于SolidWorks来说,图纸是独立于零件或结构的。在创建空白图纸后,我可以随便添加毫无关联的不同零件与结构到图纸中。但是对于Fusion,图纸是和顶层结构挂钩或零件的。我必须要选择一个顶层结构挂钩或零件作为图纸的主题来创建图纸。接下来,我只能在这张图纸中包含那个顶层结构的子结构或零件。这也导致了一些新问题:
- 修改一个零件就需要更新整个顶层结构,因为图纸之和顶层结构挂钩,而不是被修改的那个零件。这个更新顶层结构的过程就比较卡顿让人砸键盘了。不过这一点倒也有他的道理,毕竟这保证了工程模型的一致性,所以我并不反对这个问题。
- 当在图纸中添加新的子结构或零件时,Fusion实际上会把顶层结构重新插入图纸,然后再隐蔽选择的子结构或零件以外的其它部分。在更新图纸时我们就可以观察到这一点,有时我们会在子结构或零件的位置突然看到整个结构,这是因为Fusion钢更新完这个结构还没来得及隐藏其它部分。试想我们的设计有100个零件(这对大部分项目来说已经很少了)且我们的图纸会分别展示每个零件,SolidWorks将会展示结构(画100个零件)与100个零件,总共200次绘图;Fusion会展示101个结构(每个结构画100个零件)并隐藏其中100个结构的部分,也就是10100次绘图。
- 当向设计中添加新零件时,那个零件将会被添加到图纸中每一个零件的图中。这是因为Fusion的图纸中每一个零件都是隐藏了其它部分的结构,而新添加的零件默认没有被隐藏。
- 如果我们建立图纸文件时选择的顶层结构变成了子结构(例如我们最先设计了一个发动机,但是现在我们想要将发动机作为汽车的一部分),我们必须重新对新的顶层结构建立图纸文件,并且从头开始。此外,当我们使用久设计创建新设计时,就算我们复制了一个新的图纸文件,其内部还是指向九个设计的模型。只能重画,这导致复用设计很困难。
- 文件越大越慢。
- 免费版本的Fusion(个人版非商用)只能做单页的工程图。
因此,我们更倾向把设计拆分成小的结构或单独零件并分别建立工程图,然后再将它们合并起来生成最终工程图。
新的程序仍然使用CSV文件作为目录,但是将支持多个PDF图纸文件与任意数量的PNG、JPEG图片文件。
简单有利于规律。新的程序摒弃了参数与标题栏的概念。与其从目录文件中提取出参数并放置在提前设定好的地方,不如让目录文件来定义在哪些地方放置怎样的文字或图片。与其使用固定的标题栏,不如直接用一张包含了标题栏的线条框架与文字,且背景透明的PNG文件来代替。
确切来讲,新的程序已经脱离标题栏生成器的范畴,而是一个可以合并PDF并插入图片的通用PDF编辑器了。
我们在之前定义了一套关于参数位置的规则,但现在这套规则变成了可以在目录文件中自定义,这也造成了短板与问题:
- 参数在每一页都遵循相同的位置、颜色、大小等规则。而现在,我们会将同样的规则在每一页都重复定义,这导致目录文件体积膨胀。
现在的电脑硬盘管够。 - 之前是自动生成页码,现在要手动生成了。
可以用表格软件(Libre Calc、MS Excel)来生成。
目录文件格式
每一行都代表了一页图纸。
Type - 种类
每一行开头表示了当前页的种类,可以是特定图纸文件中的特定一页,也可以是特定尺寸的空白页。
@BLANK,width,height
@BLANK,17,11
如果第一栏是“@BLANK”,程序将会为此页创建一张空白的图纸,并使用接下来两栏的内容作为尺寸(单位:英寸)。在这个例子中,我们创建了一个17x11英寸(横向Tabloid)的空白页。
file,page,rotation
a.pdf,5,90
否则,程序将从图纸文件中复制出来特定一页。第一第二栏分别是源图纸的文件名与需要复制的页码(第一页是1),第三栏为旋转角度。在这个例子中,我们复制“a.pdf”的第5页并旋转90度。
提示:旋转角度只改变PDF文件的观测角度,并不会实际旋转/修改PDF。
之后可以是一个或多个项目,项目可以是:
提示:原点为左下角(旋转前)。
Text - 文字
使用‘T’作为文字开头,并附上x-y坐标、文字高度、行高(都是英寸为单位)、RGBA颜色(0.0到1.0)、旋转角度(度)参数和要打印的文字。另外,可以使用“\n”作为分行。
T,x,y,h,lh,r,g,b,a,rotate,'text\nand new line'
T,1,3,0.1,0.15,1,0,0,0.5,20,Some text
上面的例子将会在(x = 1, y = 3)的位置使用0.1寸字体与0.15寸行高的半透明红打印“Some text”。
Picture - 图片
使用‘P’作为图片开头,并附上x-y坐标、图片尺寸(都是英寸为单位)、旋转角度(度)参数和图片文件名。图片可以是PNG或JPEG格式,PNG可以是背景透明的。
P,x,y,w,h,rotate,filename
P,9,5,4,2,45,icon.png
上面的例子将会在(x = 9, y = 5)的位置使插入文件名为“icon.png”的图片。图片宽4英寸宽,高2英寸,并旋转45度。
Index - 目录
使用‘I’作为目录开头,并附与文字项目相同的参数和目录项目参数,其中ref_col
为将要包括的项目在目录文件中的列数(最左边为第一列,计数时包括空白的列),ref_rowStart
为目录的起始行(最上为第一行),ref_rowLen
为目录的长度。
I,x,y,h,lh,r,g,b,a,rotate,ref_col,ref_rowStart,ref_rowLen
I,1,10,0.1,0.15,0,0,0,1,0,5,2,20
上面的例子将会在(x = 1, y = 10)的位置使用0.1寸字体与0.15寸行高的黑色打印目录。目录将包含从第2行开始的20行中的第5列的内容。
Dummy - 伪项目
使用‘X’作为伪项目开头,这个特殊的项目可以让我们在接下来一栏中放入我们想要放在目录文件中但是却不希望放进最终成品图纸中的东西,例如注释。
X,whatever
X,TODO: update in next reversion
上面的例子就展示了一个在目录文件中留下注释的使用场景。
目录文件中的空白栏
目录文件中可以插入任意的空白栏来帮助排版(以及方便在表格软件中快速编辑),下面两个例子生成的效果是完全相同的。
@BLANK,17,11,T,1,3,0.1,0.15,1,0,0,0.5,20,Some text,,,T,1,3,0.1,0.15,1,0,0,0.5,20,More text
@BLANK,17,11,,,T,1,3,0.1,0.15,1,0,0,0.5,,,,20,Some text,T,1,3,0.1,0.15,1,0,0,0.5,20,More text
例子
下面将展示将2张工程图原图、一张PNG扫描件、一张JPEG照片合并为一份工程图并添加标题栏与目录。为了简便展示,这里将使用一个迷你版的标题栏而不是标准的标题栏。
源文件
目录
我们将图纸的第一页将作为目录页,我们将需要:
创建一张17x11的空白页。
@BLANK,17,11
插入标题栏。我们将带有alpha通道的背景透明的PNG文件插入到原点(0,0),并将图片大小设置为页面大小。
P,0,0,17,11,0,tb.png
在特定地方插入工程名、本页标题、页码、总页数、作者与版本号。
T,13,1.05,0.25,0.3,0,0,0,1,0,Naval Gun Model // Project name T,13,0.6,0.25,0.3,0,0,0,1,0,Index // Page title T,16,0.23,0.16,0.2,0,0,0,1,0,0 // Page number T,16.4,0.23,0.16,0.2,0,0,0,1,0,/ 6 // Page count T,13,0.23,0.16,0.2,0,0,0,1,0,Captdam // Author T,15.2,0.23,0.16,0.2,0,0,0,1,0,1 // Reversion
在本页(封面)顶部写上大号的工程名,插入目录的标题。
T,1,10,0.35,0.4,0,0,0,1,0,Naval Gun Model T,1,9.3,0.16,0.2,0,0,0,1,0,Title T,4,9.3,0.16,0.2,0,0,0,1,0,Page
从目录文件中提取信息生成目录。这里我们将生成两项目录:第33列的每页的标题、第44列的每页的页码。目录将从第2行(也就是第二页)开始,这样就可以跳过被作为目录的第一页(也就是当前页),持续6行。
I,1,9,0.16,0.2,0,0,0,1,0,33,2,6 I,4,9,0.16,0.2,0,0,0,1,0,44,2,6
我们将把图纸源文件“1.pdf”中的两页图纸作为最终工程图的第2页与第3页,把图纸源文件“2.pdf”中的两页图纸作为最终工程图的第5页与第6页。我们将需要:
导入特定文件中的特定页,这个例子将导入“1.pdf”的第1页,不进行任何旋转。
1.pdf,1,0
和目录页的第2到4步相同,插入标题栏与相关参数。
P,0,0,17,11,0,tb.png // Titleblack T,13,1.05,0.25,0.3,0,0,0,1,0,Naval Gun Model // Project name T,13,0.6,0.25,0.3,0,0,0,1,0,Side plates // Page title T,16,0.23,0.16,0.2,0,0,0,1,0,A1 // Page number T,16.4,0.23,0.16,0.2,0,0,0,1,0,/ 6 // Page count T,13,0.23,0.16,0.2,0,0,0,1,0,Captdam // Author T,15.2,0.23,0.16,0.2,0,0,0,1,0,0 // Reversion
在第4页,我们希望可以插入一张扫描文件“r1.png”作为参考图。因为这张图自带标题栏,我们就没必要为这一页添加我们自己的标题栏。我们将需要:
创建一张17x11的空白页。
@BLANK,17,11
虽然我们不需要标题栏相关的参数,但是我们仍然需要在目录文件中包含这些参数来生成目录。我们可以使用“X”伪项目来在目录文件中包含这些信息,但是这些信息在这里将不会被放入图纸中。
X,Naval Gun Model // Project name X,Model reference // Page title X,A3 // Page number X,/ 6 // Page count X,Joe Doe // Author X,As-is // Reversion
在原点(0,0)插入图片“r1.png”,尺寸与图纸尺寸相等,使这张扫描件的图片铺满当前页。
P,0,0,17,11,0,r1.png
用半透明的红色和一点角度打一个水印“Reference Design”表示这是参考图纸。
T,4.5,4,1,1.5,1,0,0,0.5,20,REFERENCE DESIGN
在最后一页,我们想要添加一张成品照片,这一页可以包含我们的标题栏。我们将需要:
创建一张17x11的空白页。
@BLANK,17,11
和目录页的第2到4步相同,插入标题栏与相关参数。
P,0,0,17,11,0,tb.png // Titleblack T,13,1.05,0.25,0.3,0,0,0,1,0,Naval Gun Model // Project name T,13,0.6,0.25,0.3,0,0,0,1,0,Product photo // Page title T,16,0.23,0.16,0.2,0,0,0,1,0,C1 // Page number T,16.4,0.23,0.16,0.2,0,0,0,1,0,/ 6 // Page count T,13,0.23,0.16,0.2,0,0,0,1,0,Captdam // Author T,15.2,0.23,0.16,0.2,0,0,0,1,0,0 // Reversion
在合适的地方以合适的尺寸插入照片“photo.jpg”。
P,2.5,1.5,12,9,0,photo.jpg
最终图纸
下面就是最后生成的PDF工程图: