【问题标题】:Export SVG to PDF with groups/layers intact将 SVG 导出为 PDF,组/图层完好无损
【发布时间】:2021-10-18 12:29:32
【问题描述】:

我有一个如下所示的 SVG 对象:

每个内部 <g> 元素中都有 <path>s。

我想将此 SVG 导出为 PDF,以便组转换为图层 (OCG),如下所示:

<ThroughCut>
    <Path>
    <Path>
    <Path>
    <Path>
<Graphics>
    <Path>
    <Path>
    <Path>
    <Path>

然而,我为此尝试过的任何工具都将所有对象放在同一层中,并且基本上会丢弃有关组的信息。

首选 JavaScript 或 Python 解决方案,但在 UNIX 机器上从命令行执行的任何操作都可以。

【问题讨论】:

  • 由于 SVG 不支持 PDF 等可选内容组(也称为图层),因此 SVG 到 PDF 转换器没有理由将 标签转换为 PDF 中的 OCG。但是你的问题给了我一个关于我们产品未来功能的建议:)
  • @iPDFdev 这是个好消息!也看看我提出的这个问题,关于重新排列 PDF 中的图层。如果您的产品可以做到这一点,我肯定会使用它。 stackoverflow.com/questions/68802965/…

标签: javascript python pdf svg


【解决方案1】:

我通过在 Github 上关注 this PyMuPDF issue 解决了我的问题。

由于我可以控制输入 SVG,我设法通过将两个 SVG 解析为 PDF 并将它们组合到新文档的不同层中来解决问题。 这就是我正在做的事情

import fitz
from svglib.svglib import svg2rlg
from reportlab.graphics.renderPDF import drawToString

def svg_to_doc(path):
    """Using this function rather than `fitz`'  `convertToPDF` because the latter
    fills every shape with black for some reason.
    """
    drawing = svg2rlg(path)
    pdfbytes = drawToString(drawing)
    return fitz.open("pdf", pdfbytes)

# Create a new blank document
doc = fitz.open()
page = doc.new_page()

# Create "Layer1" and "Layer2" OCGs and get their `xref`s
xref_1 = doc.add_ocg('Layer1', on=True)
xref_2 = doc.add_ocg('Layer2', on=True)

# Load "layer_1" and "layer_2" svgs and convert to pdf
doc_1 = svg_to_doc("my_layer_1.svg")
doc_2 = svg_to_doc("my_layer_2.svg")

# Set the `page` dimensions. Note: for me it makes sense to set the bounding
# box of the output to the same as `doc_1`, because I know `doc_1` contains
# `doc_2`. If that were not the case, I would set `bb` to be a new
# `fits.Rect` object that contained both `doc_1` and `doc_2`.
bb = doc_1[0].rect
page.setMediaBox(bb)

# Put the docs in their respective OCGs
page.show_pdf_page(bb, doc_1, 0, oc=xref_1)
page.show_pdf_page(bb, doc_2, 0, oc=xref_2)

# Save
doc.save("output.pdf")

如果我在 Adob​​e Acrobat 中加载“output.pdf”,图层会显示。奇怪的是,Adobe Illustrator 并非如此(这里它们只是“剪辑组”)。无论如何,我相信这可以解决上述问题。

my_layer_1.svg

my_layer_2.svg

【讨论】:

    【解决方案2】:

    我的其他解决方案虽然正确,但无法生成与 Adob​​e 标准兼容的 PDF(例如,Illustrator 不会将 OCG 视为合法图层,但奇怪的是,Acrobat 会)。

    如果需要生成与 Adob​​e 标准兼容的 PDF,并且可以在 Illustrator 中正确加载,另一种选择是使用 Illustrator 脚本 API。

    这是一个脚本,可用于将加载的 SVG 文件转换为具有所需层结构的 PDF。

    /** Convert an open file in Illustrator to PDF, after removing the first layer.
     *  Useful for converting SVGs into PDFs, where it is desired that the first level
     *  `<g>` elements are converted to layers/OCGs in the exported PDF.
    */
    
    // Select export destination
    const destFolder = Folder.selectDialog( 'Select folder for PDF files.', '~' );
    
    // Get the PDF options to be used
    const options = getOptions();
    
    // The SVG should have a single `Layer1` top layer...
    const doc = app.activeDocument;
    if (doc.layers.length == 1) {
        
        // ... remove it
        removeFirstLayer(doc)
    
        // Create a file pointer for export...
        var targetFile = getTargetFile(doc.name, '.pdf', destFolder);
        
        // ... and save save `doc` in the file pointer.
        doc.saveAs(targetFile, options);
    }
    
    
    /* --------- */
    /* Utilities */
    /* --------- */
    
    function getOptions() {
        // Create PDFSaveOptions object
        var pdfSaveOpts = new PDFSaveOptions();
        
        // Set PDFSaveOptions properties (toggle these comment/uncomment)
        pdfSaveOpts.acrobatLayers = true;
        pdfSaveOpts.colorBars = true;
        pdfSaveOpts.colorCompression = CompressionQuality.AUTOMATICJPEGHIGH;
        pdfSaveOpts.compressArt = true; //default
        pdfSaveOpts.embedICCProfile = true;
        pdfSaveOpts.enablePlainText = true;
        pdfSaveOpts.generateThumbnails = true; // default
        pdfSaveOpts.optimization = true;
        pdfSaveOpts.pageInformation = true;
        // pdfSaveOpts.viewAfterSaving = true;
        
    
        return pdfSaveOpts;
    }
    
    function removeFirstLayer(doc) {
        // Get the layer to be removed
        var firstLayer = doc.layers[0];
        
        // Convert groups into new layers
        for (var i=firstLayer.groupItems.length-1; i>=0; i--) {
            var group = firstLayer.groupItems[i];
            var newLayer = firstLayer.layers.add();
            newLayer.name = group.name;
            for (var j=group.pageItems.length-1; j>=0; j--)
                group.pageItems[j].move(newLayer, ElementPlacement.PLACEATBEGINNING);
        }
        
        // Move new layers to the document and remove `firstLayer`
        for (var i=firstLayer.layers.length-1; i>=0; i--)
            firstLayer.layers[i].move(firstLayer.parent, ElementPlacement.PLACEATBEGINNING);
    
        firstLayer.remove();
    }
    
    function getTargetFile(docName, ext, destFolder) {
        var newName = "";
    
        // Add extension is none exists
        if (docName.indexOf('.') < 0)
            newName = docName + ext;
        else
            newName += docName.substring(0, docName.lastIndexOf('.')) + ext;
        
        // Create file pointer
        var myFile = new File(destFolder + '/' + newName);
        
        // Check that file permissions are granted
        if (myFile.open("w"))
            myFile.close();
        else
            throw new Error('Access is denied');
    
        return myFile;
    }
    
    1. 将脚本放入以.jsx 结尾的文件中,然后放入Illustrator 中的Scripts 文件夹中。我的地址是/Applications/Adobe Illustrator 2021/Presets/en_US/Scripts/svgToPDF.jsx

    2. 重启 Illustrator

    3. File > Scripts > svgToPDF 菜单项执行脚本。

    缺点

    • 插画需要花钱。
    • 您必须手动执行SVG -> PDF 转换。可以使用 AppleScript 实现自动化,但它确实不是您希望在服务器上运行的东西。

    【讨论】:

      猜你喜欢
      • 2017-06-28
      • 2018-10-18
      • 2015-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多