我有 SVG 文档,在工作流程结束时通过 Ghostscript 将其转换为 PDF。现在我必须添加一个新功能。 我需要用 PDF 内容替换 SVG 中的某些元素。它不是 只需叠加,它就可以按比例旋转和缩放,例如下面的图像:
“示例”
我的问题是有什么办法可以用 Ghostscript 做到这一点吗?
目前我只是将其作为 SVG 图像元素的光栅化图像插入,但我需要将其作为矢量进行打印。
注意:我只需要从插入的 PDF 中取出第一页。
我知道有一个 pdftk 可以将一个 PDF 文件覆盖在另一个 PDF 文件上,但我无法用它缩放和旋转覆盖的 PDF 文档。
恐怕,由于 Ghostscript PDF 解释器最近为解决安全漏洞而进行了更改,此代码仅适用于 9.26 及以下版本。将来 PDF 解释器将会发生改变,并且会有更好的方法来实现这一点,但恐怕这是一个长期目标。目前,要使用此代码,您需要坚持使用旧版本。
执行此操作的 PostScript 程序如下:
%!PS
%%
%% This code is copied from pdf_main.ps, pdfshowpage_finish
%% sadly that routine always calls showpage, and we want that
%% to be under our control, so we have to duplicate the code
%% here. Not only that but it uses GS extensions which aren't
%% available outside of startup, so some things it simply can't
%% replicate. As a result some of the error handling is less
%% good.
%%
%% I plan to extend the PDF interpreter with two new
%% routines, pdfnoshowpage_finish and then have both
%% that and pdfshowpage_finish call pdfoptionalshowpage_finish
%% which will take a boolean determining whether to actually
%% call the showpage. At that time we'll alter this code.
%%
/draw_page_content { % <pagedict> pdfshowpage_finish -
save /PDFSave exch store
/PDFdictstackcount countdictstack store
/PDFexecstackcount count 2 sub store
(before exec) VMDEBUG
% set up color space substitution (this must be inside the page save)
pdfshowpage_setcspacesub
% Display the actual page contents.
8 dict begin
/BXlevel 0 def
/BMClevel 0 def
/OFFlevels 0 dict def
/BGDefault currentblackgeneration def
/UCRDefault currentundercolorremoval def
%****** DOESN'T HANDLE COLOR TRANSFER YET ******
/TRDefault currenttransfer def
matrix currentmatrix
2 dict
dictbeginpage setmatrix
/DefaultQstate qstate store
count 1 sub /pdfemptycount exch store
% If the page uses any transparency features, show it within
% a transparency group.
dup pageusestransparency dup /PDFusingtransparency exch def {
% Show the page within a PDF 1.4 device filter.
0 .pushpdf14devicefilter {
/DefaultQstate qstate store % device has changed -- reset DefaultQstate
% If the page has a Group, enclose contents in transparency group.
% (Adobe Tech Note 5407, sec 9.2)
dup /Group knownoget {
1 index /CropBox pget {
/CropBox exch
} {
1 index get_media_box pop /MediaBox exch
} ifelse
oforce_elems normrect_elems fix_empty_rect_elems 4 array astore .beginformgroup
showpagecontents
.endtransparencygroup
} {
showpagecontents
} ifelse
} stopped {
% abort the transparency device
.abortpdf14devicefilter
/DefaultQstate qstate store % device has changed -- reset DefaultQstate
stop
} if .poppdf14devicefilter
/DefaultQstate qstate store % device has changed -- reset DefaultQstate
} {
showpagecontents
} ifelse
.free_page_resources
% todo: mixing drawing ops outside the device filter could cause
% problems, for example with the pnga device.
end % scratch dict
% Some PDF files don't have matching q/Q (gsave/grestore) so we need
% to clean up any left over dicts from the dictstack
PDFdictstackcount //false
{ countdictstack 2 index le { exit } if
currentdict /n known not or
end
} loop
pop
count PDFexecstackcount sub { pop } repeat
Repaired % pass Repaired state around the restore
PDFSave restore
currentglobal pdfdict gcheck .setglobal
.setglobal
/Repaired exch def
} def
% And now, draw the page from the first PDF file
(d:/temp/SO/target.pdf) (r) file runpdfbegin
save
1 pdfgetpage
dup /Page exch store draw_page_content
restore
runpdfend
% and then the page from the second PDF file
(d:/temp/SO/source.pdf) (r) file runpdfbegin
save
1 pdfgetpage
dup /Page exch store
% Before drawing the second page, adjust the CTM so
% that the bottom left corner of the page is co-incident
% with the bottom left of the area we want to draw the
% page in
75 575 translate
% adjust the size of the output
0.11 0.11 scale
% and rotate it
-46 rotate
draw_page_content
restore
runpdfend
showpage
将其保存在一个文件中,命名为 test.ps,并适当调整 PostScript 程序中的路径。然后使用以下命令运行 Ghostscript:
gs -sDEVICE=pdfwrite -sOutputFile=out.pdf test.ps
,您将获得一个 PDF 文件,类似于我认为您想要的内容。显然,您还需要更改平移/缩放/旋转的数字。
我在这里发布了一个解决方案,支持剪切粘贴的 PDF 文件,以防将来有人需要它。我已向draw_page_content 添加了额外的参数来支持这一点。我发现“dict beginpage setmatrix”命令以某种方式覆盖了剪切路径,并且应该仅在该命令之后设置它。我不是 PostScript 专家,但至少这个解决方案是有效的。再次感谢 KenS 的帮助。
%!PS
%%
%% This code is copied from pdf_main.ps, pdfshowpage_finish
%% sadly that routine always calls showpage, and we want that
%% to be under our control, so we have to duplicate the code
%% here. Not only that but it uses GS extensions which aren't
%% available outside of startup, so some things it simply can't
%% replicate. As a result some of the error handling is less
%% good.
%%
%% I plan to extend the PDF interpreter with two new
%% routines, pdfnoshowpage_finish and then have both
%% that and pdfshowpage_finish call pdfoptionalshowpage_finish
%% which will take a boolean determining whether to actually
%% call the showpage. At that time we'll alter this code.
%%
/draw_page_content { % <pagedict> pdfshowpage_finish -
/clipx exch def /clipy exch def /clip_width exch def /clip_height exch def /should_clip exch def
save /PDFSave exch store
/PDFdictstackcount countdictstack store
/PDFexecstackcount count 2 sub store
(before exec) VMDEBUG
% set up color space substitution (this must be inside the page save)
pdfshowpage_setcspacesub
% Display the actual page contents.
8 dict begin
/BXlevel 0 def
/BMClevel 0 def
/OFFlevels 0 dict def
/BGDefault currentblackgeneration def
/UCRDefault currentundercolorremoval def
%****** DOESN'T HANDLE COLOR TRANSFER YET ******
/TRDefault currenttransfer def
matrix currentmatrix
2 dict
dictbeginpage setmatrix
% set clipping here
should_clip 0 gt
{
newpath clipx clipy moveto clipx clipy clip_height add lineto clipx clip_width add clipy clip_height add lineto clipx clip_width add clipy lineto closepath clip
}
{
}
ifelse
/DefaultQstate qstate store
count 1 sub /pdfemptycount exch store
% If the page uses any transparency features, show it within
% a transparency group.
dup pageusestransparency dup /PDFusingtransparency exch def {
% Show the page within a PDF 1.4 device filter.
0 .pushpdf14devicefilter {
/DefaultQstate qstate store % device has changed -- reset DefaultQstate
% If the page has a Group, enclose contents in transparency group.
% (Adobe Tech Note 5407, sec 9.2)
dup /Group knownoget {
1 index /CropBox pget {
/CropBox exch
} {
1 index get_media_box pop /MediaBox exch
} ifelse
oforce_elems normrect_elems fix_empty_rect_elems 4 array astore .beginformgroup
showpagecontents
.endtransparencygroup
} {
showpagecontents
} ifelse
} stopped {
% abort the transparency device
.abortpdf14devicefilter
/DefaultQstate qstate store % device has changed -- reset DefaultQstate
stop
} if .poppdf14devicefilter
/DefaultQstate qstate store % device has changed -- reset DefaultQstate
} {
showpagecontents
} ifelse
.free_page_resources
% todo: mixing drawing ops outside the device filter could cause
% problems, for example with the pnga device.
end % scratch dict
% Some PDF files don't have matching q/Q (gsave/grestore) so we need
% to clean up any left over dicts from the dictstack
PDFdictstackcount //false
{ countdictstack 2 index le { exit } if
currentdict /n known not or
end
} loop
pop
count PDFexecstackcount sub { pop } repeat
Repaired % pass Repaired state around the restore
PDFSave restore
currentglobal pdfdict gcheck .setglobal
.setglobal
/Repaired exch def
} bind def
% And now, draw the page from teh first PDF file
(/opt/files/main.pdf) (r) file runpdfbegin
save
1 pdfgetpage
dup /Page exch store 0 1125 1125 0 0 draw_page_content
restore
runpdfend
gsave
% and then the page from the next PDF file
(/opt/files/placement1.pdf) (r) file runpdfbegin
save
1 pdfgetpage
dup /Page exch store
% Before drawing the second page, adjust the CTM so
% that the bottom left corner of the page is co-incident
% with the bottom left of the area we want to draw the
% page in
120 120 translate
% and rotate it
25 rotate
% adjust the size of the output
0.7 0.7 scale
%let's skew file
[1 0 1.3 1 0 0] concat
% draw file and clip it
1 100 100 0 0 draw_page_content
restore
runpdfend
grestore
showpage