首页 > 编程问答 >Python 问题 如何创建在 PDF 中注册为剪切线的专色?

Python 问题 如何创建在 PDF 中注册为剪切线的专色?

时间:2024-08-01 05:52:59浏览次数:7  
标签:python svg

我正在开发一个项目,需要我在图像周围创建一条剪切线,但在任何 RIP 程序(例如 Versaworks 或 Flexi)上将其注册为实际剪切线时遇到困难。

我尝试了很多不同的方法python 库可以帮助解决这个问题,但我无法让它工作。我希望它像我们在 Illustrator 中所做的那样,创建一条名为 CutContour 的剪切线作为专色,但由于某种原因,它没有在导出时注册。

我尝试过枕头、元素树、inkscape、scribus,但没有效果.

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)

已修复 - 此代码将为在 Flexi 和 Versaworks 中注册的任何文件添加填充边框和剪切线。目前,您的项目目录中需要有一个名为 2.png 的文件,但您可以轻松地在此基础上进行构建。

import numpy as np
from PIL import Image, ImageDraw, ImageFilter
import cv2
import os
from reportlab.pdfgen import canvas
from reportlab.lib.colors import PCMYKColorSep
from reportlab.lib.utils import ImageReader


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 create_image_with_border(input_image_path, border_size, corner_radius):
    # Open the original image
    img = Image.open(input_image_path).convert("RGBA")

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

    # Remove pixels with opacity lower than 60%
    img_np[img_np[:, :, 3] < 153] = [0, 0, 0, 0]

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

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

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

    # Convert mask to PIL Image
    mask_img = Image.fromarray(mask)

    # Calculate new size with padding
    padding = max(border_size * 3, corner_radius * 2)
    new_size = (img_np.shape[1] + padding * 2, img_np.shape[0] + padding * 2)

    # Create a new image with extra space for the border
    img_with_border = Image.new('RGBA', new_size, (0, 0, 0, 0))

    # Create a mask for the contour
    contour_mask = Image.new('L', new_size, 0)
    paste_position = (padding, padding)
    contour_mask.paste(mask_img, paste_position)

    # Apply corner rounding
    contour_mask = contour_mask.filter(ImageFilter.GaussianBlur(radius=corner_radius / 2))
    contour_mask = contour_mask.point(lambda x: 255 if x > 128 else 0)

    # Create the contour border
    contour_border = contour_mask.filter(ImageFilter.GaussianBlur(radius=border_size / 2))
    contour_border = contour_border.point(lambda x: 255 if x > 0 else 0)

    # Create a white layer for the border
    white_layer = Image.new('RGBA', new_size, (255, 255, 255, 255))

    # Paste the white border behind the image
    img_with_border.paste(white_layer, (0, 0), contour_border)

    # Paste the original image on top
    img_with_border.paste(Image.fromarray(img_np), paste_position, Image.fromarray(mask))

    return img_with_border


def create_contour(image):
    # Convert image to numpy array
    img_np = np.array(image)

    # Create a binary mask
    mask = (img_np[:, :, 3] > 0).astype(np.uint8) * 255

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

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

    return outer_contour


def create_pdf_with_spot_color(image, contour, pdf_path, cutline_offset):
    # Get image dimensions
    img_width, img_height = image.size

    # Create a new PDF canvas
    c = canvas.Canvas(pdf_path, pagesize=(img_width + 2 * cutline_offset, img_height + 2 * cutline_offset))

    # Define the spot color for the cut contour
    cut_contour_spot = PCMYKColorSep(0.0, 100.0, 91.0, 0.0, spotName='CutContour', density=100)

    # Draw the image
    c.drawImage(ImageReader(image), cutline_offset, cutline_offset, img_width, img_height, mask='auto')

    # Set the spot color
    c.setStrokeColor(cut_contour_spot)

    # Draw the contour path
    c.setLineWidth(1)
    path = c.beginPath()

    # Start the path with a move to command
    path.moveTo(contour[0][0][0] + cutline_offset,
                (img_height + 2 * cutline_offset) - (contour[0][0][1] + cutline_offset))

    # Draw the contour path
    for point in contour[1:]:
        px, py = point[0]
        path.lineTo(px + cutline_offset,
                    (img_height + 2 * cutline_offset) - (py + cutline_offset))  # Adjust for coordinate system

    path.close()
    c.drawPath(path)

    # Save the PDF
    c.save()

    print(f"PDF with spot color cut contour created: {pdf_path}")


# Input image path
input_image_path = '2.png'

# Output PDF path
output_pdf_path = 'cut_contour_spot_color.pdf'

# Border size (pixels)
border_size = 12

# Corner radius (pixels)
corner_radius = 7

# Cutline offset (distance from border to cutline)
cutline_offset = 1

# Create image with rounded contour padding border
img_with_border = create_image_with_border(input_image_path, border_size, corner_radius)

# Create contour from image with border
contour = create_contour(img_with_border)

# Create the PDF with the spot color cut contour
create_pdf_with_spot_color(img_with_border, contour, output_pdf_path, cutline_offset)

print(f"PDF created: {os.path.abspath(output_pdf_path)}")

以下是如何使用 Python 在 PDF 中创建注册为专色的剪切线的解决方法:

1. 图像处理和轮廓检测

  • 使用 Pillow 或 OpenCV 加载的图像: 这些库非常适合图像处理任务。
  • 创建蒙版: 为的图像创建一个蒙版以隔离要创建剪切线的区域。可以根据颜色阈值、alpha 透明度或任何其他相关的标准来实现这一点。
  • 查找轮廓: 使用 OpenCV 的 cv2.findContours 函数检测蒙版图像中的轮廓。选择代表所需剪切线的适当轮廓(例如,外部轮廓)。

2. 生成 SVG 并使用专色

  • 安装 svgwrite: 我们将使用 svgwrite 库生成 SVG 文件。可以使用 pip install svgwrite 安装它。
  • 创建 SVG:
    • 创建一个新的 SVG 文档。
    • 为的图像添加一个 <image> 元素。
    • 创建一个新的 <path> 元素以表示剪切线。
      • <path> 元素的 d 属性设置为步骤 1 中提取的轮廓坐标。
      • <path> 元素的 stroke 属性设置为的专色。可以使用专色名称(如果的 RIP 软件支持)或 CMYK 值。例如,对于“CutContour”,可以使用 stroke="CutContour"
  • 保存 SVG 文件。

3. 将 SVG 转换为 PDF(使用 Inkscape)

  • 安装 Inkscape: 确保的系统上安装了 Inkscape。
  • 使用 subprocess 模块从 Python 运行 Inkscape 命令行:
    • 使用 inkscape --export-type=pdf your_file.svg 命令将 SVG 文件转换为 PDF。

代码示例:

import cv2
import numpy as np
from PIL import Image
import svgwrite
import subprocess

# 1. 图像处理和轮廓检测
image = cv2.imread("your_image.png", cv2.IMREAD_UNCHANGED)
# 创建蒙版(根据需要调整此步骤)
mask = image[:, :, 3] > 128
# 查找轮廓
contours, hierarchy = cv2.findContours(mask.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cut_contour = contours[0] # 假设想要外部轮廓

# 2. 生成 SVG 并使用专色
dwg = svgwrite.Drawing("output.svg", profile='tiny')
dwg.add(dwg.image("your_image.png", size=(image.shape[1], image.shape[0])))
path = dwg.path(d=f"M {' '.join(f'{p[0][0]},{p[0][1]}' for p in cut_contour)} Z", 
                fill="none", stroke="CutContour", stroke_width="1") # 使用 CutContour 专色
dwg.add(path)
dwg.save()

# 3. 将 SVG 转换为 PDF(使用 Inkscape)
subprocess.run(["inkscape", "--export-type=pdf", "output.svg"])

重要说明:

  • 此解决方法假设的 RIP 软件支持“CutContour”专色或可以指定其 CMYK 等效值。
  • 调整图像处理步骤以适合特定图像和所需剪切线的需要。
  • 可能需要调整 Inkscape 命令中的路径和文件名以匹配的系统设置。

此方法结合了不同的库和工具来实现想要的结果。请记住,在不同的 RIP 软件中,对专色和剪切线支持的实现可能会有所不同,因此可能需要进行一些实验和调整才能使其与的特定设置完美配合。

标签:python,svg
From: 78818116

相关文章

  • 使用Python时如何避免`setattr`(和`getattr`)?以及是否有必要避免
    如果我想向协议缓冲区中的字段添加一个在编译时未知的值,我目前正在做setattr我通常不喜欢使用setattr,因为它看起来不太安全。但是当我知道该对象是protobuf时,我认为这很好,因为我设置它的值必须是protobuf允许的类型。所以也许它并不是真的不安全?让我举......
  • Java sshtools 生成的 EDDSA 签名与 Python 的 pycryptome 生成的签名不匹配
    我有一个python库,它使用pycryptodomelibrary使用openssh格式的ED25519私钥使用Ed25519算法对数据进行签名。然后需要使用sshtools库和相应的公钥在Java应用程序中验证签名。但是签名验证失败。约束:从文件中读取私钥/公钥很重要。我无法......
  • Elastic python请求超时错误:池达到最大大小,不允许更多连接
    我正在使用Elasticsearchpython模块。我正在尝试像这样建立到服务器的连接es=Elasticsearch([config.endpoint],api_key=config.key,request_timeout=config.request_timeout)服务器连接,然后我尝试执行丰富策略。es.enr......
  • 使用 python 将 JSON 数据空值导入数据库。收到此错误 - 数据需要字符串或类似字节的
    我正在尝试使用python将JSON数据集导入到我的PostgreSQL数据库,但在尝试导入null值时会抛出错误。表的名称是Loan_info。我在python中尝试过此操作:-forfieldinloan_info:ifloan_info[field]in['Null','null',None]:......
  • Python 将脚本转换为 exe 并给出 PermissionError
    我有一个Python(Windows10)脚本,其功能之一是创建备份。这是函数:defcreate_backups(self,file:str,counter:int=None)->None:counter=counteror1res=self.re_obj.match(file)ifresisNoneorlen(res.groups())==0:back_file=......
  • conda update python 不会更新,但 conda update --all 会更新
    我正在尝试更新我的venv。这就是我看到的(base_test)>condaupdatepythonCollectingpackagemetadata(current_repodata.json):doneSolvingenvironment:done==>WARNING:Anewerversionofcondaexists.<==currentversion:4.10.3latestversion:24......
  • 如何使用 Selenium (python) 访问另一个影子根中影子根中的元素?
    我有以下代码和HTML结构(我不是这方面的专家)。我正在尝试抓取HTML代码末尾的96.00C元素,其路径是:Xpath://*[@id="_grid"]/set-class2/div2/text-binding//text()完整Xpath:/html/body/main/div/div3/div3/......
  • 在Python中,如何在一段时间内接受输入
    我正在尝试用Python制作一个蛇游戏,但不知道如何制作它,以便蛇在没有玩家输入的情况下继续移动,所以如果有人知道一个简单的方法来做到这一点,我需要在2秒后取消输入将不胜感激代码如下:importrandomimportsysplayerY=(1)playerX=(0)appleY=random.randint(1,10)appl......
  • 在Python中单步执行代码时是否可以引发异常
    当我在IDE(例如PyCharm)中单步执行代码时,我想转储函数的参数(以供以后使用,例如复制它)。计划的场景是在某处设置断点,然后引发异常(这不在我运行的代码中,这就是重点),并捕获它。代码应该如下所示:defexception_cathcher_decorator(func):try:returnfunc(*f_args,**f_k......
  • 解决python自动化操作异常处理的问题
    在python自动化领域,往往要用到pyautogui,pywin32等模块实现自动化操作。然而,这种自动化操作,本身具有一定的局限性,其中最主要的一个问题就是,一旦执行结果不按照脚本预设的来执行,往往会抛出异常,导致程序中断。解决这个问题,主要有这么几种思路:第一,每一次操作后分情况讨论。这种方......