You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建可被RIP程序识别为切割线的PDF专色CutContour

解决RIP程序无法识别CutContour专色切割线的问题

我正在做一个给图像添加切割线的项目,但添加的切割线无法被Versaworks、Flexi这类RIP程序识别为有效切割线。尝试过Pillow、ElementTree、Inkscape、Scribus等工具,想实现类似Illustrator里的CutContour专色切割线,但导出后始终不被识别。以下是我最初尝试的代码:

import subprocess
import os
import xml.etree.ElementTree as ET
import cv2
import numpy as np
from PIL import Image

def convert_png_to_svg(input_image_path, output_svg_path):
    try:
        subprocess.run(['C:\\Program Files\\Inkscape\\bin\\inkscape.exe', input_image_path, '--export-type=svg', '--export-filename', output_svg_path], check=True)
        if os.path.exists(output_svg_path):
            print(f"SVG file created: {os.path.abspath(output_svg_path)}")
        else:
            print(f"Error: SVG file was not created: {output_svg_path}")
    except subprocess.CalledProcessError as e:
        print(f"Error running Inkscape: {e}")
    except FileNotFoundError:
        print("Inkscape not found. Make sure it's installed at the specified path.")

def remove_small_objects(mask, min_size):
    num_labels, labels, stats, _ = cv2.connectedComponentsWithStats(mask, connectivity=8)
    for i in range(1, num_labels):
        if stats[i, cv2.CC_STAT_AREA] < min_size:
            mask[labels == i] = 0
    return mask

def add_contour_to_svg(input_image_path, svg_path, output_svg_path, border_size, padding):
    # Open the original image
    img = Image.open(input_image_path).convert("RGBA")

    # Add initial padding to the original image
    padded_size = (img.width + 2 * padding, img.height + 2 * padding)
    padded_img = Image.new("RGBA", padded_size, (0, 0, 0, 0))
    padded_img.paste(img, (padding, padding))

    # Convert to numpy array
    img_np = np.array(padded_img)

    # Create an alpha mask
    alpha = img_np[:, :, 3]

    # Create a binary mask
    mask = (alpha > 0).astype(np.uint8) * 255

    # Remove small objects (smaller than 1px)
    mask = remove_small_objects(mask, 1)

    # Find contours using OpenCV
    contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # Find the outer contour
    outer_contour = max(contours, key=cv2.contourArea)

    # Create a new mask for the border
    border_mask = np.zeros_like(mask)

    # Draw the contour on the border mask with a thicker stroke
    cv2.drawContours(border_mask, [outer_contour], -1, 255, border_size)

    # Find the contours of the border mask
    border_contours, _ = cv2.findContours(border_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    border_contour = max(border_contours, key=cv2.contourArea)

    # Parse the SVG
    tree = ET.parse(svg_path)
    root = tree.getroot()
    ns = {'svg': 'http://www.w3.org/2000/svg'}

    # Create a new layer for the cut path
    layer = ET.SubElement(root, 'g', {
        'id': 'cut_layer',
        'inkscape:groupmode': 'layer',
        'inkscape:label': 'CutContour'
    })

    # Create the cut path
    path_data = 'M ' + ' '.join(f'{px},{py}' for px, py in [point[0] for point in border_contour]) + ' Z'
    ET.SubElement(layer, 'path', {
        'd': path_data,
        'fill': 'none',
        'stroke': '#EC008C',
        'stroke-width': str(border_size)
    })

    # Save the modified SVG
    tree.write(output_svg_path)
    print(f"Modified SVG with contour saved as: {output_svg_path}")

def export_svg_to_pdf(svg_path, output_pdf_path):
    try:
        subprocess.run(['C:\\Program Files\\Inkscape\\bin\\inkscape.exe', svg_path, '--export-type=pdf', '--export-filename', output_pdf_path], check=True)
        if os.path.exists(output_pdf_path):
            print(f"PDF file created: {os.path.abspath(output_pdf_path)}")
        else:
            print(f"Error: PDF file was not created: {output_pdf_path}")
    except subprocess.CalledProcessError as e:
        print(f"Error running Inkscape: {e}")
    except FileNotFoundError:
        print("Inkscape not found. Make sure it's installed at the specified path.")

# Input image path
input_image_path = '2.png'
# Output SVG paths
output_svg_path = '2_converted.svg'
modified_svg_path = '2_with_cut.svg'
# Output PDF path
output_pdf_path = '2_final.pdf'
# Border size (pixels)
border_size = 1
# Padding size (pixels)
padding = 10

# Step 1: Convert PNG to SVG using Inkscape
convert_png_to_svg(input_image_path, output_svg_path)

# Step 2: Add cut path and spot color to the SVG
add_contour_to_svg(input_image_path, output_svg_path, modified_svg_path, border_size, padding)

# Step 3: Export the modified SVG to PDF using Inkscape
export_svg_to_pdf(modified_svg_path, output_pdf_path)

问题根源与修改方案

原代码的核心问题是:仅给路径设置了RGB颜色,没有按照RIP程序的要求定义专色(Spot Color)。RIP程序识别CutContour需要明确的专色标识,而非普通的RGB描边。

以下是修改后的代码,重点调整了专色定义和导出参数:

import subprocess
import os
import xml.etree.ElementTree as ET
import cv2
import numpy as np
from PIL import Image

def convert_png_to_svg(input_image_path, output_svg_path):
    try:
        subprocess.run(['C:\\Program Files\\Inkscape\\bin\\inkscape.exe', input_image_path, '--export-type=svg', '--export-filename', output_svg_path, '--export-ignore-filters'], check=True)
        if os.path.exists(output_svg_path):
            print(f"SVG file created: {os.path.abspath(output_svg_path)}")
        else:
            print(f"Error: SVG file was not created: {output_svg_path}")
    except subprocess.CalledProcessError as e:
        print(f"Error running Inkscape: {e}")
    except FileNotFoundError:
        print("Inkscape not found. Make sure it's installed at the specified path.")

def remove_small_objects(mask, min_size):
    num_labels, labels, stats, _ = cv2.connectedComponentsWithStats(mask, connectivity=8)
    for i in range(1, num_labels):
        if stats[i, cv2.CC_STAT_AREA] < min_size:
            mask[labels == i] = 0
    return mask

def add_contour_to_svg(input_image_path, svg_path, output_svg_path, border_size, padding):
    # Open the original image
    img = Image.open(input_image_path).convert("RGBA")

    # Add initial padding to the original image
    padded_size = (img.width + 2 * padding, img.height + 2 * padding)
    padded_img = Image.new("RGBA", padded_size, (0, 0, 0, 0))
    padded_img.paste(img, (padding, padding))

    # Convert to numpy array
    img_np = np.array(padded_img)

    # Create an alpha mask
    alpha = img_np[:, :, 3]

    # Create a binary mask
    mask = (alpha > 0).astype(np.uint8) * 255

    # Remove small objects (smaller than 1px)
    mask = remove_small_objects(mask, 1)

    # Find contours using OpenCV
    contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # Find the outer contour
    outer_contour = max(contours, key=cv2.contourArea)

    # Create a new mask for the border
    border_mask = np.zeros_like(mask)

    # Draw the contour on the border mask with a thicker stroke
    cv2.drawContours(border_mask, [outer_contour], -1, 255, border_size)

    # Find the contours of the border mask
    border_contours, _ = cv2.findContours(border_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    border_contour = max(border_contours, key=cv2.contourArea)

    # Parse the SVG and handle namespaces properly
    tree = ET.parse(svg_path)
    root = tree.getroot()

    # Define namespaces explicitly to avoid parsing issues
    ET.register_namespace('', 'http://www.w3.org/2000/svg')
    ET.register_namespace('inkscape', 'http://www.inkscape.org/namespaces/inkscape')
    ET.register_namespace('xlink', 'http://www.w3.org/1999/xlink')

    # Add color profile definition for CutContour spot color
    # Insert at the beginning of the SVG root
    color_profile = ET.Element('{http://www.w3.org/2000/svg}color-profile', {
        'id': 'CutContour',
        'name': 'CutContour',
        'rendering-intent': 'absolute-colorimetric',
        'local': 'CutContour'
    })
    root.insert(0, color_profile)

    # Create a new layer for the cut path
    layer = ET.SubElement(root, '{http://www.w3.org/2000/svg}g', {
        'id': 'cut_layer',
        'inkscape:groupmode': 'layer',
        'inkscape:label': 'CutContour'
    })

    # Create the cut path using the spot color
    path_data = 'M ' + ' '.join(f'{px},{py}' for px, py in [point[0] for point in border_contour]) + ' Z'
    ET.SubElement(layer, '{http://www.w3.org/2000/svg}path', {
        'd': path_data,
        'fill': 'none',
        'stroke': 'url(#CutContour)',
        'stroke-width': str(border_size),
        'vector-effect': 'non-scaling-stroke'
    })

    # Save the modified SVG with proper namespace handling
    tree.write(output_svg_path, encoding='utf-8', xml_declaration=True)
    print(f"Modified SVG with CutContour spot color saved as: {output_svg_path}")

def export_svg_to_pdf(svg_path, output_pdf_path):
    try:
        # Add parameters to preserve spot colors during PDF export
        subprocess.run([
            'C:\\Program Files\\Inkscape\\bin\\inkscape.exe', 
            svg_path, 
            '--export-type=pdf', 
            '--export-filename', output_pdf_path,
            '--export-pdf-version=1.7',
            '--export-preserve-spot-colors',
            '--export-ignore-filters'
        ], check=True)
        if os.path.exists(output_pdf_path):
            print(f"PDF file with CutContour saved as: {os.path.abspath(output_pdf_path)}")
        else:
            print(f"Error: PDF file was not created: {output_pdf_path}")
    except subprocess.CalledProcessError as e:
        print(f"Error running Inkscape: {e}")
    except FileNotFoundError:
        print("Inkscape not found. Make sure it's installed at the specified path.")

# Input image path
input_image_path = '2.png'
# Output SVG paths
output_svg_path = '2_converted.svg'
modified_svg_path = '2_with_cut.svg'
# Output PDF path
output_pdf_path = '2_final.pdf'
# Border size (pixels)
border_size = 1
# Padding size (pixels)
padding = 10

# Step 1: Convert PNG to SVG using Inkscape
convert_png_to_svg(input_image_path, output_svg_path)

# Step 2: Add cut path and spot color to the SVG
add_contour_to_svg(input_image_path, output_svg_path, modified_svg_path, border_size, padding)

# Step 3: Export the modified SVG to PDF using Inkscape
export_svg_to_pdf(modified_svg_path, output_pdf_path)

关键修改说明

  • 专色定义:在SVG头部添加了color-profile元素,明确标识CutContour为专色,RIP程序能识别这个标识
  • 命名空间处理:注册了SVG、Inkscape的命名空间,避免ElementTree解析和保存时丢失属性
  • 路径引用专色:将路径的stroke设置为url(#CutContour),而非普通RGB值
  • 导出参数优化:Inkscape导出PDF时添加--export-preserve-spot-colors和--export-pdf-version=1.7参数,确保专色信息被保留在PDF中
  • 矢量效果设置:添加vector-effect: non-scaling-stroke,保证切割线宽度在缩放时保持一致

内容的提问来源于stack exchange,提问作者MagicMatt253

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 09:34:52